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