ZAPP回调函数出现BUG后的一点体会(同时使用两个串口方法)
/***************************************************************************************************
* @fn MT_UartProcessZAppData
*
* @brief | SOP | CMD | Data Length | FSC |
* | 1 | 2 | 1 | 1 |
*
* Parses the data and determine either is SPI or just simply serial data
* then send the data to correct place (MT or APP)
*
* @param port - UART port
* event - Event that causes the callback
*
*
* @return None
***************************************************************************************************/
void MT_UartProcessZAppData ( uint8 port, uint8 event )
{
osal_event_hdr_t *msg_ptr;
uint16 length = 0;
uint16 rxBufLen = Hal_UART_RxBufLen(port /*MT_UART_DEFAULT_PORT*/);//获得缓冲区数据长度
/*
If maxZAppBufferLength is 0 or larger than current length
the entire length of the current buffer is returned.//如果串口缓冲区中的长度为0并且小于最大长度,则返回实际长度
*/
if ((MT_UartMaxZAppBufLen != 0) && (MT_UartMaxZAppBufLen <= rxBufLen))//如果最大长度不为0,并且实际长度大于最大长度
{
length = MT_UartMaxZAppBufLen;//返回最大长度
}
else
{
length = rxBufLen;//其它情况下为实际获得的长度
}
/* Verify events */
if (event == HAL_UART_TX_FULL) //串口 1 发送缓冲区溢出
{
// Do something when TX if full
return;
}
if (event & ( HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT))
{
if ( 0x08 /*App_TaskID*/ )// 这里我直接写上某个任务的TASK_ID,因为我程序同时使用了两个串口,定义了ZTOOL_P1和ZAPP 和MT_TASK
{
/*
If Application is ready to receive and there is something
in the Rx buffer then send it up
*/
if ((MT_UartZAppRxStatus == MT_UART_ZAPP_RX_READY ) && (length != 0))//串口允许接收并且实际长度不为0
{
/* Disable App flow control until it processes the current data 关闭串口直到处理数据完成 */
MT_UartAppFlowControl (MT_UART_ZAPP_RX_NOT_READY);
msg_ptr = (osal_event_hdr_t *)osal_msg_allocate( length + sizeof(osal_event_hdr_t) );
if ( msg_ptr )
{
msg_ptr->event = SPI_INCOMING_ZAPP_DATA;
msg_ptr->status = length; /* 2 more bytes are added, 1 for CMD type, other for length */
/* Read the data of Rx buffer */
HalUARTRead( port /*MT_UART_DEFAULT_PORT*/, (uint8 *)(msg_ptr + 1), length );//将缓冲区数据装入消息体中
/* Send the raw data to application...or where ever */
osal_msg_send( 0x08 /*App_TaskID*/, (uint8 *)msg_ptr );
P1_0 = P1_0;//便于调试
}
}
}
}
}
有个现象跟大家分享一下:我同时使用了两个串口,协议栈版本为ZStack-2007-2..4.0。因为由串口0与我自己写的上位机程序通信,其它格式可以完全按照TI规定的来。所以串口0可以用回调函数void MT_UartProcessZToolData ( uint8 port, uint8 event ),而且采用DMA方式。但串口1是来是另外一个CC2530(两个处理器都在同一板子上,这里我将含有我自己程序叫主处理器,另外一个叫从处理器),其内部的程序不是我的。所以格式自己没有办法规定。因此,串口1的回调函数我只能用这里列出的void MT_UartProcessZToolData ( uint8 port, uint8 event ),而且采用中断方式。后来在用串口助手调试的过程中,(因为现在另外一个CC2530没有焊,用串口调试助手代替向主处理器发送任意十六进制数据)。问题由此产生了 ,我对串口1进来的数据直接到任务号为8任务处理。其处理方式为将数据立即通过串口0发送至上位机(这里的上位机不是调试助手,是LINUX下自己写的,串口0发送数据至上位的机的格式为固定长度32字节)。现象是:当我通过调试发送任意长度的十六进制数据时,回调函数调用的次数为发送数据的个数。而且通过串口0发送出来的数据是经过几次发送的。并且发出来的数据不会超过永远小或者等于4个十六进制数(也就是我通过调试助手发过的前4个,而且数据也没错,只是个数永远小4个)。
这里有两个现象值得注意:
1)串口1每接收一个字节就会调用一次回调函数,这样就不能打包成一条完整的消息。我认为是系统轮循1ms太快了。
2)数据接收不会超过4个。也不知道是什么原因
3)在LINUX发送的数据都能顺利到达串口调试助手。
不知道大家有没有遇到过这样的问题,也请高手能帮我我看看,可能是什么原因。
只能发四个字节的问不太清楚是怎么回事;一个字节中断一次的情况应该和中断服务程序的实现方式有关,每接收一个字节产生一个接收事件,就会出现你说的情况。
我用zstack 2.5.0发现串行口驱动有不小问题,有可能2.4.0也有同样的问题。
那请问一下版主. 是否可以实现为两个串口都使用 dma 方式呢?
中断服务程序根本就非常简单,每次仅仅是将UXDBUF中的一个字节的数据,写入接收缓冲区中。同时维护缓冲区的完整性。问题应该不在中断函数,而是在回调函数中,因为用户只会跟缓冲区打交道。仔细分析一下MT_UartProcessZAppData中的uint16 rxBufLen = Hal_UART_RxBufLen(0x01),由现象可知道,每次调用回调函数时缓冲区中都只有一个字节存在,而回调函数是由系统轮循来调用的。由此可以说明每次中断后系统就刚好开始调用回调函数。至于永远只有4个字节的问题,我试过了,其它的字节已经被回调函数处理了,只是没有发送到应用层相关的任务中。不知道是不是在调用4次回调函数后,系统就做别的事情去了。即使是这样,字节也应该还在,跑哪去了呢
DMA方式肯定也是可以用的,但要改动的地方比较多。因为协议栈中默认只用了DMA3和4两个通道。还有三个通道可用。但是需要改动预编译和增加DMA通道的初始化。而且最后也只能采用第二个回调函数。DMA所做的事情与中断是一样的,也是完成缓冲区与串口寄存器间的数据搬移。感觉没有多大区别,关键应该在回调函数MT_UartProcessZAppData,如果它也能像MT_UartProcessZToolData一样在接收指定字节长度后才发送消息应该就没有问题了。目前我正在尝试修改回调函数,如果接收的每条消息第一个字节为消息长度也许就很好办了。希望有过经历的兄弟也出点建议!
遇到同样的困惑!
丢失字节的问题可能和串口的使用方式有关,uart接收到的数据有三种处理方式,znp协议,ztool协议和app自定义协议,前两种有格式要求,接收处理会去掉帧头帧尾的字符。
我很长一段时间没有碰过zigbee相关的东西,前面说中断有问题的说法可能不确切,记不清那些代码。
UART相关的问题记得一些:如果同时进行接收和发送,有一定概率丢失某事件(具体接收事件还是发送事件记不清了),可以分析这几个事件的产生和处理方式了解,这个问题进行大量数据传输时发现的;串行口DMA实际上达不到DMA的效果,由于不知道什么时候DMA结束,每一次DMA都要检查一下,效率和ISR方式一样,并且DMA多用了一个填充字节,占了比ISR方式多的内存;zstack默认的实现方式,两个中行口只能配置成一个ISR和一个DMA方式,两个都是ISR或者都是DMA得大改驱动代码。
另一个非常严重的问题,不是UART驱动问题,很可能会影响到UART功能:OSAL的事件处理机制问题,如果在短时间内产生大量事件,由于OSAL没有事件队例,部分事件会丢失,如果丢失的事件涉及堆的回收操作,导致这些内存块永远无法回收,最终内存泄漏完崩溃或者出来越界,这种情况uart也会工作不正常,当时发现这个问题时,是先看到uart不正常才发现的。
我当时接触的zstack版本是2.5.0,上面提到的uart问题都存在,当然也发现了很多和uart不相关的问题,2.4.0估计问题更多,玩zstack的朋友最好更新到最新版本试一试。
这位兄弟分析得很透彻。我的程序由串口1接收的数据经过打包发送至应用层任务,然后通过串口0发送出去。出现在两个问题:1)由串口0出来的数据不超过4个字节。 2)所有由串口1接收的数据都已经过回调函数MT_UartProcessZAppData处理,而且是每次处理一个字节,但四个字节以后的数据却没有到达应用层任务。3)用串口调试助手向串口1发送数据,当进行一段时间后,所有的数据都收不到,原以为是串口1接收缓冲区溢出,但后来粗略计算一下,不是这个原因。至于事件丢失问题,这次受教了,应该是有可能的。问题还未解决,期待进一步讨论!