This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CMSIS DSP continuous Data Processing and transmitting with TM4C129x MCU

Expert 1350 points

Replies: 46

Views: 6107

Hi all,


Iam using TM4C1294XL launchpad and Iam trying to implement low pass filter function of CMSIS DSP Library.

I'am facing an issue of sending the filter output continuously via UART to another TM4C129x MCU which is running the TFT. I'am able to implement the filter but the data is being sent block by block to the other MCU due to which I'am getting unexpected results.

Iam using timer to trigger the ADC @ sampling rate of 256Hz.

Input signal is sine wave with varying frequency between10-50Hz and the cutoff frequency is 30Hz.


Below is the while(1) loop of my code for reading ADC & sending filter data.I've also attached the screen shot of the data plotting on TFT using Graphics library. It can be seen that the sine wave is not continuous.

Kindly help me to sort this issue

float32_t p[256];

#define TEST_LENGTH_SAMPLES  256

#define BLOCK_SIZE           128

#define NUM_TAPS              29

static float32_t firStateF32[BLOCK_SIZE + NUM_TAPS - 1];

float32_t testOutput[TEST_LENGTH_SAMPLES];

float32_t inputsamples[TEST_LENGTH_SAMPLES];


 arm_fir_instance_f32 S;


 float32_t  *inputF32, *outputF32;

uint32_t blockSize = BLOCK_SIZE;
uint32_t numBlocks = TEST_LENGTH_SAMPLES/BLOCK_SIZE;

void Timer0IntHandler(void)
{

    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
 
    ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_TIMER, 0);
 
}

int main(void)
{



    FPULazyStackingEnable();

    FPUEnable();

    uint32_t ui32Period;


    uint32_t  l=0;


     int32_t CH1DATA ;

    inputF32 = &inputsamples[0];

    outputF32 = &testOutput[0];



    ui32SysClkFreq= SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000);


 ********************ALL INITIALIZATION CODE OMITTED TO BE SPECIFIC TO THE ISSUE*********

        while(1)
        {
      
            ADCIntClear(ADC0_BASE, 1);


            while(!ADCIntStatus(ADC0_BASE, 1, false))
            {
            }
        ADCSequenceDataGet(ADC0_BASE, 1, ui32ADC0Value);

        if(l==256)
        {
            
            l=0;

            arm_fir_init_f32(&S, NUM_TAPS, (float32_t *)&firCoeffs32[0], &firStateF32[0], blockSize);

            for(i=0; i < numBlocks; i++)
            {
                arm_fir_f32(&S, inputF32 + (i * blockSize), outputF32 + (i * blockSize), blockSize);

            }


        }


        p[l] = (float32_t)ui32ADC0Value[0];
        p[l] = p[l] - (float32_t)0x0810;

        inputsamples[l]= p[l];


                                                                                UARTCharPutNonBlocking(UART6_BASE,'a'); //  To tell the other MCU to start plotting the incoming data.

                                                                                CH1DATA= (int32_t)testOutput[l]+ (int32_t)0x0810;


                                                                                al = CH1DATA & 0xF00;
                                                                                al = al>>8;
                                                                                ah = CH1DATA & 0xFF;


                                                                                UARTCharPutNonBlocking(UART6_BASE,ah);
                                                                                UARTCharPutNonBlocking(UART6_BASE,al);

                                                                            l=l+1;

        }

}

 

46 Replies

  • In reply to Sumit Mourya:

    Hello Sumit

    At 256Hz, you do not need to stop the Timer. The use if TransferSet function and channel enable is sufficient. As for the UART still not working as expected, I would suggest checking what it is transmitting v/s what it is expected to transmit.

    Regards,

    Amit Ashara

  • In reply to Amit Ashara:

    Hi Amit,

    Firstly , I do not need to disable & Enable timer in the ADCInt Handler for sampling rate of 256HZ?
    The DMASrc Buffer are not updating if i only do TransferSet API in ADCInt handler!!!Where should i need to reinitalize the DMA transfre if not in ADCInt handler?? Is it so complex to use DMA for ADC??

    Iam really not able to get into the core of the issue!!! I'am using such a low sampling rate because i need to capture biomedical signals like EEG, ECG , EMG etc.
  • In reply to Sumit Mourya:

    Hello Sumit,

    Yes, you do not need to disable and enable the timer if the continuous capture is expected.

    Secondly uDMAChannelTransferSet and uDMAChannelEnable both are needed to re-initialize the Ping or Pong control structures (also shown in TIDM-TM4C129POEAUDIO reference design software file audiocontro.c)

    It is not complex but without having the correct software structure it can be complicated.

    Now if the buffers show the data then they are being captured. The idea that you have floating point computation and requirement to send them in specific notation is complicating. If you look at the example of TIDM-TM4C129POEAUDIO I am doing the same with 48KHz sampling, audio compression and decompression while handling Ethernet traffic and LCD display, without having any issues.

    First things first, get the software working with ADC and DMA. Do not add the UART or floating point processing yet. Add a GPIO toggle every time the interrupt handler is invoked for ADC due to DMA stop and see the periodicity of the same. Once you can correct the same, then we get on with non-blocking transmission.

    Regards,

    Amit Ashara

  • In reply to Amit Ashara:

    OK, let me do it step by step since I really need to accomplish this task

    I'll follow your guidance. First I'll need to get the ADC to work with DMA with the below code

    I need to capture 4 different type of signals , so Iam using sample sequencer 1 for ADC0.

    With the below code i should get continuous transfer in ping & pong buffer?

    #pragma DATA_ALIGN(pui8DMAControlTable, 1024)

    uint8_t pui8DMAControlTable[1024];

    #define MEM_BUFFER_SIZE 1024

    static uint16_t g_ui16SrcBufA[MEM_BUFFER_SIZE];

    static uint16_t g_ui16SrcBufB[MEM_BUFFER_SIZE];

    void uDMAErrorHandler(void)

    {

       uint32_t ui32Status;

       ui32Status = uDMAErrorStatusGet(); // Check for uDMA error bit

       if(ui32Status) // If there is a uDMA error

       {

           uDMAErrorStatusClear(); //Clear the error status

       }

    }

    void ADCseq1Handler(void)

    {

    uint32_t ui32Status = ADCIntStatus(ADC0_BASE, 1 , false);

    uint32_t ui32Mode;

    ADCIntClear(ADC0_BASE, 1);

    ADCIntClearEx(ADC0_BASE, ADC_INT_DMA_SS1);

    ui32Mode = uDMAChannelModeGet(UDMA_CH15_ADC0_1 | UDMA_PRI_SELECT);

    if(ui32Mode == UDMA_MODE_STOP )

      {

          uDMAChannelTransferSet(UDMA_CH15_ADC0_1 | UDMA_PRI_SELECT,

                                     UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO1), g_ui16SrcBufA, MEM_BUFFER_SIZE);

      }

    ui32Mode = uDMAChannelModeGet(UDMA_CH15_ADC0_1 | UDMA_ALT_SELECT);

      if(ui32Mode == UDMA_MODE_STOP  )

      {

          uDMAChannelTransferSet(UDMA_CH15_ADC0_1 | UDMA_ALT_SELECT,

                                      UDMA_MODE_PINGPONG,

                                      (void *)(ADC0_BASE + ADC_O_SSFIFO1),

    g_ui16SrcBufB, MEM_BUFFER_SIZE);

      }

      uDMAChannelEnable(UDMA_CH15_ADC0_1);

    }

    void Timer0IntHandler(void)

    {

       TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

       ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_TIMER, 0);

    }

    int main(void)

    {

       FPULazyStackingEnable();

       FPUEnable();

       uint32_t ui32Period;

       uint32_t  l=0;

        int32_t CH1DATA ;

       inputF32 = &inputsamples[0];

       outputF32 = &testOutput[0];

       ui32SysClkFreq= SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000);

    /******* DMA INITIALIZATION***********/

    SysCtlPeripheralDisable(SYSCTL_PERIPH_UDMA);

    SysCtlPeripheralReset(SYSCTL_PERIPH_UDMA);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);

    while(!(SysCtlPeripheralReady(SYSCTL_PERIPH_UDMA)));

    IntEnable(INT_UDMAERR);

    uDMAEnable();

    uDMAControlBaseSet(pui8DMAControlTable);

    /******* ADC INITIALIZATION***********/

    SysCtlPeripheralDisable(SYSCTL_PERIPH_ADC0);

    SysCtlPeripheralReset(SYSCTL_PERIPH_ADC0);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

    while(!(SysCtlPeripheralReady(SYSCTL_PERIPH_ADC0)));

    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 24);

    ADCReferenceSet(ADC0_BASE,ADC_REF_INT);

    // ui32Config = ADCClockConfigGet(ADC0_BASE, &ui32ClockDiv);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

    while(!(SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOE)));

    GPIOPinTypeADC(GPIO_PORTE_BASE,GPIO_PIN_3|GPIO_PIN_2|GPIO_PIN_1|GPIO_PIN_0);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

    while(!(SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB)));

    GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_3);

    ADCSequenceDisable(ADC0_BASE, 1);

    ADCSequenceStepConfigure(ADC0_BASE,1,0,ADC_CTL_CH0);

    ADCSequenceStepConfigure(ADC0_BASE,1,1,ADC_CTL_CH1);

    ADCSequenceStepConfigure(ADC0_BASE,1,2,ADC_CTL_CH2);

    ADCSequenceStepConfigure(ADC0_BASE,1,3,ADC_CTL_CH3|ADC_CTL_IE|ADC_CTL_END);

    ADCSequenceEnable(ADC0_BASE, 1);

    ADCSequenceDMAEnable(ADC0_BASE, 1);

       uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC0,

                                       UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);

       uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT,

                                UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 |

                                  UDMA_ARB_4);

       uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT,

                               UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 |

                               UDMA_ARB_4);

       uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT,

                                     UDMA_MODE_PINGPONG,

                                     (void *)(ADC0_BASE + ADC_O_SSFIFO0),

     g_ui16SrcBufA, MEM_BUFFER_SIZE);

       uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT,

                                   UDMA_MODE_PINGPONG,

                                   (void *)(ADC0_BASE + ADC_O_SSFIFO0),

    g_ui16SrcBufB, MEM_BUFFER_SIZE);

       uDMAChannelEnable(UDMA_CHANNEL_ADC0);

       ADCIntEnableEx(ADC0_BASE, ADC_INT_DMA_SS1);

       IntEnable(INT_ADC0SS1);

       SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);

        TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);

        ui32Period = 120000000/256;

        TimerLoadSet(TIMER0_BASE, TIMER_A, ui32Period-1);

        TimerControlTrigger(TIMER0_BASE, TIMER_A, true);

        TimerEnable(TIMER0_BASE, TIMER_A);

           while(1)

           {

           }

    }

  • In reply to Sumit Mourya:

    Sorry My mistake,

    It should be (ADC0_BASE + ADC_O_SSFIFO1) instead of SSFIFO0 in the main function. was a copy paste error
  • In reply to Sumit Mourya:

    Hello Sumit,

    Yes. That is correct. Do make sure to toggle a GPIO every time the interrupt handler is invoked. This will tell you if the periodicity is being maintained.

    Regards,

    Amit Ashara

  • In reply to Amit Ashara:

    Hello Amit,

    Ok, I toggled the GPIO in the interrupt handler and got the below timings

    Time between each toggle is 3.920ms with the 255Hz freq(this must be because my sampling rate is 256Hz).

    The PIng & Pong buffers are getting also getting updated !!! Things seem to start working :) .

    what should be my next step?
  • In reply to Sumit Mourya:

    Hello Sumit,

    Now the next step would be to set a flags when Ping or Pong buffers are completed. Use this flag to perform the floating point conversion. BTW, do you need to convert the data for transmission?

    Regards,

    Amit Ashara

  • In reply to Amit Ashara:

    Hello Amit,

    So I should use two flags, suppose I name them PingBufferAvailable & PongBufferAvailable.

    When I check the ping buffer completion , I'll set the PingBufferAvailable flag to true. Similarly inside the If condition of Pong buffer completion I'll set the PongBufferAvailable.

    Then in while(1) loop I should check for true conditions of both the flags and convert & copy the data.Since My DMA memory buffer size is 1024 ( because i need to capture 4 different channel data)

    While(1)
    {

    if (PingBufferAvailable == true)
    {
    k=0;
    for(l=0;l<=255;l++)
    {
    CH1ADC[l] = (float32_t)g_ui16SrcBufA[k] - float32_t(0x0810);// first channel data
    CH2ADC[l] = (float32_t)g_ui16SrcBufA[k+1] - float32_t(0x0810); // second channel data
    CH3ADC[l] = (float32_t)g_ui16SrcBufA[k+2] - float32_t(0x0810);// third channel data
    CH4ADC[l] = (float32_t)g_ui16SrcBufA[k+3] - float32_t(0x0810);// fourth channel data
    k=k+4;

    }

    if (PongBufferAvailable == true)
    {
    k=0;
    for(l=0;l<=255;l++)
    {
    CH1ADC[l] = (float32_t)g_ui16SrcBufA[k] - float32_t(0x0810);// first channel data
    CH2ADC[l] = (float32_t)g_ui16SrcBufA[k+1] - float32_t(0x0810); // second channel data
    CH3ADC[l] = (float32_t)g_ui16SrcBufA[k+2] - float32_t(0x0810);// third channel data
    CH4ADC[l] = (float32_t)g_ui16SrcBufA[k+3] - float32_t(0x0810);// fourth channel data

    k=k+4;
    }

    ********************PERFORM THE FILTER**********

    }

    Am i correct for the above code??

    Secondly, Yes i need to break the data into 8 bits so that it can be transferred via UART. I can do that using the below code

    testOutput[l] is the filter output . originally it is 32 bit floating point, I've converted into 32 bit signed integer and then broke it into two 8 bit variables ah & al.

    I'am adding and subtracting a constant value of 0x0810 because the ADC is unipolar, so instead of adding an additional clipping circuit in my hardware, I've added and subtracted a constant value.


    CH1DATA= (int32_t)testOutput[l]+ (int32_t)0x0810;


    al = CH1DATA & 0xF00;
    al = al>>8;
    ah = CH1DATA & 0xFF;


    UARTCharPut(UART6_BASE,ah);
    UARTCharPut(UART6_BASE,al);
  • In reply to Sumit Mourya:

    Oops........ in Pongbuffer flag check i'll copy g_ui16SrcBufB AND not g_ui16SrcBufA.
    copy paste error

    if (PongBufferAvailable == true)
    {
    k=0;
    for(l=0;l<=255;l++)
    {
    CH1ADC[l] = (float32_t)g_ui16SrcBufB[k] - float32_t(0x0810);// first channel data
    CH2ADC[l] = (float32_t)g_ui16SrcBufB[k+1] - float32_t(0x0810); // second channel data
    CH3ADC[l] = (float32_t)g_ui16SrcBufB[k+2] - float32_t(0x0810);// third channel data
    CH4ADC[l] = (float32_t)g_ui16SrcBufB[k+3] - float32_t(0x0810);// fourth channel data

    k=k+4;
    }

This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.