Problema desconocido al analizar un búfer usart fifo

1

Tengo un stm32f429-disco configurado para USART (Tx y Rx). Comunicación con un dispositivo asíncrono. La longitud de los datos recibidos no se conoce de antemano. Generalmente varía de 2 bytes a 28 bytes. Por lo tanto, he configurado el USART_IT_IDLE (detección de línea inactiva). DMA es responsable de realizar la transferencia de periféricos a memoria en cada solicitud USART_Rx (que es por byte). No estoy usando usart fifo interno. El manejador de interrupción de línea IDLE es responsable de deshabilitar el dma y, por lo tanto, de configurar el indicador DMA_FLAG_TCIFx. El ISR de DMA luego copia los datos del búfer de usw a otro búfer donde se realiza el procesamiento de los datos.

El dispositivo con el que me comunico espera que se envíe un '\ r' continuamente hasta que confirme la sincronización mediante el envío de un comando "OK". El trabajo de la tarea de comunicación es analizar el búfer y verificar si se ha recibido "OK". Estoy usando freertos con la biblioteca periférica estándar stm32f4. El siguiente es el código.

    #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();
                      }
                   }
                }
            }

Y el siguiente es el código principal. vTask2 solo imprime el contenido del búfer en el terminal. He comprobado el contenido del búfer imprimiéndolos y contienen "OK". Por alguna razón mi código no puede encontrar el patrón. He intentado inicializar manualmente el búfer con valores aleatorios y colocar "OK" en ciertos lugares. El BufferCmp y el BufferSearch parecen hacer su trabajo.

Principal:

     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(;;);
      }

No entiendo cuál es el problema, DMA y USART parecen estar funcionando bien. Incluso he comprobado el patrón de bits de los dispositivos de destino en un alcance y no he encontrado ningún problema. La función BufferSearch tiene un tiempo de ejecución de 44-46.8 usecs. Y la velocidad de USART es de 9600 bps. Tampoco hay signos de corrupción de datos. Dado que la tarea de impresión imprime los datos correctos.

Cualquier sugerencia o idea de solución de problemas sería muy apreciada.

P.S: Los freertos funcionan bien, no hay fallas o fallos de memmanage. La tarea de impresión se programa regularmente sin problemas de tiempo.

Editar: La función de configuración USART y DMA.

     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);
}

Controlador IRQ USART:

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;
  }
}
    
pregunta Asusrog

1 respuesta

1

Sí, estoy absolutamente seguro de que las interrupciones se activan como deberían. Conecté un alcance a todas las interrupciones y usamos líneas para confirmarlo. Al pasar por gdb, me he dado cuenta de que los valores son incorrectos. Cuando estoy seguro de que el búfer [x] contiene una 'W' en ese lugar y la función putc_term lo imprime como tal también. El patrón de bits del carácter según lo informado por gdb es '11010111', mientras que debería haber sido '01010111' según el estándar Ascii.

El dispositivo de destino ha estado enviando datos de 7 bits y no presté atención a cómo lo estaba almacenando localmente. Agregué la siguiente edición a la función memcpy y ahora funciona.

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: Muchas gracias por su ayuda: D

    
respondido por el Asusrog

Lea otras preguntas en las etiquetas