1
\$\begingroup\$

I have an stm32f429-disco configured for USART (Tx and Rx).Communicating with an asynchronous device. The receive data length is not known before hand. It generally varies from 2 bytes to 28 bytes. Hence i have configured the USART_IT_IDLE (idle line detection). DMA is responsible for performing the peripheral-to-memory transfer upon each USART_Rx request (which is per byte). I am not using internal usart fifo. IDLE line interrupt handler is responsible for disabling the dma and hence setting the DMA_FLAG_TCIFx flag. The DMA ISR then copies the data from thew usart buffer to another buffer where data processing is done.

The device i communicate with expects a '\r' to be sent continuously until it acknowledges synchronization by sending a "OK" command. The job of the communication task is to parse the buffer and check if "OK" has been received. I am using freertos with stm32f4 standard peripheral library. Following is the code.

    #define RXBUFFERSIZE  64
    #define PARSESIZE     128

    char aRxBuffer[RXBUFFERSIZE];
    char parsebuffer[PARSESIZE]; 
    volatile size_t writes,write_length;

    static int BufferCmp(char* pBuffer1,char* pBuffer2,size_t   pBufferLength)
    {
       while(pBufferLength--)
        {
          if(*pBuffer1 != *pBuffer2)
             {

                return -1;
              }
          pBuffer1++;
          pBuffer2++;
         }
        return 0;
       }


    static void* BufferSearch(char* bf1,size_t size,char* bf2,size_t length)
      {
        const unsigned char* haystack=(const unsigned char*)bf1;
        const unsigned char* needle=(const unsigned char*)bf2;

        if(length==0)
           return 0;
        while(length <= size)
          {
             if(!BufferCmp(haystack,needle,length))
                 return (void*) haystack;
             haystack++;
             size--;
           }
        return NULL;
      }


    void DMA1_Stream1_IRQHandler(void)
    {
      volatile size_t len,copyindex;
      uint8_t* ptr;

      if(DMA1->LISR & DMA_FLAG_TCIF1)
         DMA1->LIFCR = DMA_FLAG_TCIF1;

      len = (uint32_t)RXBUFFERSIZE - DMA1_Stream1->NDTR;
      copyindex=(uint32_t)PARSESIZE - writes;

      if(copyindex > len)
         copyindex=len;
      else if(copyindex < len)
      {
         writes=0;
         copyindex=len;
       }

       ptr=aRxBuffer;
       memcpy(&parsebuffer[writes],ptr,len);

       writes+=copyindex;
       write_length += len;
       len-=copyindex;
       ptr+=copyindex;

       BaseType_t xHigherPriorityTaskWoken;

       xHigherPriorityTaskWoken=pdFALSE;

       xSemaphoreGiveFromISR(parse,&xHigherPriorityTaskWoken);

       DMA1->LIFCR=DMA_FLAG_DMEIF1 | DMA_FLAG_FEIF1 | DMA_FLAG_TEIF1 | DMA_FLAG_TCIF1 | DMA_FLAG_HTIF1;
       DMA1_Stream1->M0AR=(uint32_t)aRxBuffer;
       DMA1_Stream1->NDTR=(uint32_t)RXBUFFERSIZE;
       DMA1_Stream1->CR |= DMA_SxCR_EN;



       portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
      }

    void vTask_parse(void* pvParameters)
      {
        const TickType_t MaxBlock =pdMS_TO_TICKS(20);
        char comm[2]={'O','K'};
        for(;;)
          {
             //GPIOG->ODR ^= GPIO_Pin_13;
            if(xSemaphoreTake(parse,MaxBlock)==pdPASS)
               {

                  if(!synced)
                     {
                       __disable_irq();
                    if(!BufferSearch(&parsebuffer[0],PARSESIZE,comm,2))
                       {
                         Putc_ax('\r');
                         //GPIOG->ODR ^= GPIO_Pin_13;
                        }
                       else
                        {
                          Puts_term("Synced\r\n"); //Message to the terminal USART
                          synced=1;
                          GPIOG->ODR ^= GPIO_Pin_13;
                         }
                       __enable_irq();
                      }
                   }
                }
            }

And following is the main code. vTask2 only prints the contents of the buffer to the terminal. I've checked the contents of the buffer by printing them and they do contain "OK". For some reason my code is unable to find the pattern. I've tried manually initialising the buffer with random values and placed "OK" at certain places. The BufferCmp and BufferSearch seems to do its job.

Main:

     int main()
     {
       parse=xSemaphoreCreateBinary();
       GPIO_Config();
       synced=0;
       USART6_Config(); //Initializes the Terminal usart
       USART3DMA_Config();

       xTaskCreate(vTask_parse,"parse",256,NULL,1,NULL);
       xTaskCreate(vTask2,"vTask2",100,NULL,1,NULL);

       vTaskStartScheduler();

       for(;;);
      }

I dont understand what the issue is, DMA and USART seem to be working fine. I have even checked target devices bit pattern on a scope and found no issues. The BufferSearch function has an execution time of 44-46.8 usecs. And the USART baud is 9600 bps.There is no sign of data corruption as well. Since the printing task prints the correct data.

Any suggestions or troubleshooting ideas would be greatly appreciated.

P.S: The freertos works fine, no hardfaults or memmanage faults. The printing task gets scheduled regularly with no timing issues.

Edit: The USART and DMA config function.

     void USART3DMA_Config()
{
   USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);


   GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
   GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
   GPIO_InitStructure.GPIO_Speed=GPIO_Fast_Speed;
   GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
   GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;

   GPIO_PinAFConfig(GPIOB,GPIO_PinSource10,GPIO_AF_USART3);
   GPIO_PinAFConfig(GPIOB,GPIO_PinSource11,GPIO_AF_USART3);

   GPIO_Init(GPIOB, &GPIO_InitStructure);

   GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11;
   GPIO_Init(GPIOB, &GPIO_InitStructure);

    //USART_OverSampling8Cmd(USART1, ENABLE);

   USART_InitStructure.USART_BaudRate=9600;
   USART_InitStructure.USART_WordLength=USART_WordLength_8b;
   USART_InitStructure.USART_StopBits=USART_StopBits_1;
   USART_InitStructure.USART_Parity=USART_Parity_Even;
   USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
   USART_InitStructure.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;

   NVIC_InitStructure.NVIC_IRQChannel=USART3_IRQn;
   NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
   //NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;

   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

   NVIC_Init(&NVIC_InitStructure);


   USART_Init(USART3, &USART_InitStructure);


   USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);

   DMA_StructInit(&DMA_InitStructure);

   DMA_InitStructure.DMA_Channel=DMA_Channel_4;
   DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&USART3->DR;
   DMA_InitStructure.DMA_Memory0BaseAddr=(uint32_t)aRxBuffer;
   DMA_InitStructure.DMA_BufferSize=(uint32_t)RXBUFFERSIZE;
   DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
   DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
   DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
   DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
   DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;
   DMA_InitStructure.DMA_Priority=DMA_Priority_High;
   DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;
   DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralToMemory;
   DMA_InitStructure.DMA_FIFOThreshold=DMA_FIFOThreshold_3QuartersFull;
   DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;
   DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;

   NVIC_InitStructure.NVIC_IRQChannel=DMA1_Stream1_IRQn;
   NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY;
   //NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
   NVIC_Init(&NVIC_InitStructure);

   DMA_Init(DMA1_Stream1,&DMA_InitStructure);
   DMA_ITConfig(DMA1_Stream1,DMA_IT_TC,ENABLE);
   DMA_Cmd(DMA1_Stream1,ENABLE);
   USART_DMACmd(USART3,USART_DMAReq_Rx,ENABLE);
   USART_Cmd(USART3,ENABLE);
}

USART IRQ handler:

void USART3_IRQHandler(void)
{
  if(USART_GetITStatus(USART3,USART_IT_IDLE))
  {
    volatile uint32_t dummy;
    dummy=USART3->SR;
    dummmy=USART3->DR;

    DMA1_Stream1->CR &= ~DMA_SxCR_EN;
  }
}
\$\endgroup\$
  • \$\begingroup\$ Some variables and macros need expanding: writes; PARSESIZE; RXBUFFERSIZE. Can you post the USART and DMA config functions? Also, have you watched the code execute in a debugger? \$\endgroup\$ – pgvoorhees Dec 13 '17 at 15:09
  • \$\begingroup\$ sorry i forgot to add that earlier on. I have run it several times through gdb, couldn't see any problems in the flow of execution as well. Although the behaviour of the target device that i'm communicating with changes when debugging since the microcontroller stops sending the '\r' command, the device stops responding with "OK". Which is what the parsing task is supposed to be looking for. \$\endgroup\$ – Asusrog Dec 13 '17 at 16:44
  • \$\begingroup\$ Yah, that's fair enough. Can we see those config functions? \$\endgroup\$ – pgvoorhees Dec 13 '17 at 16:46
  • \$\begingroup\$ added the config functions \$\endgroup\$ – Asusrog Dec 13 '17 at 16:48
  • \$\begingroup\$ And can you post the UART interrupt handler? \$\endgroup\$ – pgvoorhees Dec 13 '17 at 18:33
1
\$\begingroup\$

Yes i'm absolutely certain that the interrupts are firing the way they should. I hooked up a scope to all the interrupts and usart lines to confirm that. Stepping through gdb i've realised that the values are wrong. When i'm sure that the buffer[x] contains a 'W' at that place and the putc_term function prints it out as such as well. The character's bit pattern as reported by gdb is '11010111' while it should have been '01010111' according to Ascii standard.

The Target device has been sending 7-bit data and i paid no attention to how i was storing it locally. I added the following edit to the memcpy function and now it works.

void  *memcpy(volatile void *dest, const volatile void *src, size_t count)
{
        volatile char *in_src = (volatile char*)src;
  volatile char *in_dest = (volatile char*)dest;

  while(count--)
    *in_dest++ = (*in_src++) &0x7f; // turned off the MSB in 8-bit char
  return dest;
}

@pgvoorhees: Thank you very much for your help :D

\$\endgroup\$
  • \$\begingroup\$ Well, that'd would do it. Congrats, stomping stubborn bugs is rewarding \$\endgroup\$ – pgvoorhees Dec 15 '17 at 3:35
  • \$\begingroup\$ @pgvoorhees: haha yeah. \$\endgroup\$ – Asusrog Dec 15 '17 at 8:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.