多亏了另一个用户的帮助,我实现了一个简单的循环缓冲区来读取一些UART数据,进行一些小处理,然后在另一个UART上传输.根据用户与外部设备的一些交互,我会收到10-20个6字节的数据包流.我有一个已知的SOF,它是两个值之一,四个数据字节,然后是一个EOF字节.前XX个分组始终具有第一个SOF值,而最后一个分组始终具有另一个已知SOF值.问题是,当我获得第二个SOF值时,IRQ不会再次命中.因此,我错过了状态机中的EOF字节,循环缓冲区指针不会递增,因此不会传输最后一个包.正确的最终包被加载到循环缓冲区中(我不存储EOF字节),但是因为我的头和尾索引相等(因为我不会在最后一个字节上进入CASE STATE_WAIT_EOF状态,这将增加头缓冲区),头索引不会递增,包也不会被处理/传输.
下面是IRQ处理程序中的状态机:
void USART2_IRQHandler(void)
{
uint8_t Curr_Byte = *RX_Touch_Data;
switch(Pkt_State)
{
case STATE_WAIT_SOF:
{
Data_Indx = 0;
if(( Curr_Byte == TD_PKT) || ( Curr_Byte == LO_PKT ))
{
Msg_Buff[Buff_Head_Indx].RX_Data[Data_Indx] = Curr_Byte;
++Data_Indx;
Pkt_State = STATE_RX_DATA;
}
}
break;
case STATE_RX_DATA:
{
Msg_Buff[Buff_Head_Indx].RX_Data[Data_Indx] = Curr_Byte;
++Data_Indx;
if( Data_Indx == DATA_SIZE )
{
Pkt_State = STATE_WAIT_EOF;
if (Msg_Buff[Buff_Head_Indx].RX_Data[0] == LO_PKT)
{
LO_Pkt = TRUE; //Set flag indicating got full data buff of last pkt
}
}
}
break;
case STATE_WAIT_EOF:
{
if(LO_Pkt == TRUE)
{
DataFull = TRUE; //Set breakpoint here, never hits
}
if( Curr_Byte == EOF_PKT )
{
uint8_t New_Buff_Head_Indx = ( Buff_Head_Indx + 1 ) % NUM_MESSAGES;
if( New_Buff_Head_Indx != Buff_Tail_Indx)
{
Buff_Head_Indx = New_Buff_Head_Indx;
}
else
{
//No space; msg will be lost
}
}
Pkt_State = STATE_WAIT_SOF;
}
break;
default:
break;
}
HAL_UART_IRQHandler(&huart2); //Let HAL clean up flags
HAL_UART_Receive_IT( &huart2, RX_Touch_Data, 1 ); //Get next byte
}
当然,我还会在进入主While循环之前调用一次HAL_UART_RECEIVE_IT函数来启动该过程.
该设备发送的最后一个数据包没有任何"特殊"之处.如果我可以强制设备只发送一种类型的包,我会发现同样的情况:最终的包仍然不会被发送(不幸的是,我不能这样做).另外,请注意,如果我通过新的用户交互触发新的数据包突发,则第一个突发的最后一个数据包将被"强制"输出(这是有意义的,因为Head索引增加了).因此,我可以有10个用户交互与10个数据包突发,一切都会很好,除了最后一个,它将错过最后一个数据包.
有人看到我错过了什么吗?我希望我的解释是有道理的.
编辑:只是为了测试,我将循环缓冲区大小扩大到了10倍,这是我预期的10次猝发.只是为了消除任何环绕式索引问题的可能性.没有变化.
我暂时实现了一个"补丁",在该补丁中我不会在最后一个包中查找EOF字节.这是有效的,但充其量只是一种黑客攻击,我想知道为什么没有这个它就不能工作.
EDIT2:
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart,
uint8_t *pData, uint16_t Size)
{
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Set Reception type to Standard reception */
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
if (!(IS_LPUART_INSTANCE(huart->Instance)))
{
/* Check that USART RTOEN bit is set */
if (READ_BIT(huart->Instance->CR2, USART_CR2_RTOEN) != 0U)
{
/* Enable the UART Receiver Timeout Interrupt */
ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_RTOIE);
}
}
return (UART_Start_Receive_IT(huart, pData, Size));
}
else
{
return HAL_BUSY;
}
}
我已经在HAL_BUSY和HAL_ERROR条件上设置了标志,它们永远不会命中.
唯一其他可能相关的代码是判断尾部索引以查找可用数据包:
if( Buff_Head_Indx != Buff_Tail_Indx )
//There are available packets to send
{
Result = Process_Touch_Data();
Buff_Tail_Indx = ( Buff_Tail_Indx + 1) % NUM_MESSAGES;
}