《Zstack串口的DMA模式简介.docx》由会员分享,可在线阅读,更多相关《Zstack串口的DMA模式简介.docx(6页珍藏版)》请在三一办公上搜索。
1、Zstack串口的DMA模式简介协议栈串口的DMA模式 以下修改皆基于ZStack-CC2530-2.3.0-1.4.0版本: 1. 串口的初始化 根据底板的引脚分配,我们用的是串口的UART0的Alt2方式。需要修改的地方: (1) 将option里预编译选项,ZTOOL_P1改成ZTOOL_P2,使#define HAL_UART_DMA 2为真。 (2) _hal_uart_dma.c的HalUARTInitDMA函数是对UART引脚以及寄存器的操作,修改如下: 在HAL_UART_DMA = 2情况下的 /#define HAL_UART_Px_RTS 0x20 / Periphera
2、l I/O Select for RTS. /#define HAL_UART_Px_CTS 0x10 / Peripheral I/O Select for CTS. /屏蔽上两句,是因为该底板没有分配RTS和CTS的引脚 #define HAL_UART_PERCFG_BIT 0x01 / USART0 on P1, Alt-2; so set this bit. /这里是将串口设置为UART0的Alt2方式 #define HAL_UART_Px_RX_TX 0x30 / Peripheral I/O Select for Rx/Tx. /此处设置RX,TX引脚为P1_4,P1_5 (3
3、) 在osal_init_system里osalInitTasks下MT_TaskInit的MT_UartInit,是对串口的配置 但要将uartConfig.flowControl = MT_UART_DEFAULT_OVERFLOW;改为 uartConfig.flowControl = FALSE;协议栈默认的流控制是TRUE。 2. 串口的事件处理 /系统主循环 void osal_start_system( void ) Hal_ProcessPoll; / 串口与定时器轮询函数 /定时器与串口轮询函数 void Hal_ProcessPoll . #if (defined HAL_
4、UART) & (HAL_UART = TRUE) HalUARTPoll; #endif /串口轮询函数 void HalUARTPoll( void ) #if HAL_UART_DMA HalUARTPollDMA;/根据DMA的方式选择DMA的轮询方式 #endif /DMA串口轮询函数 static void HalUARTPollDMA(void) /以上是检查rxbuf里是否有数据写入,并对uartDMACfg_t dmaCfg结构体赋值 if (evt & (dmaCfg.uartCB != NULL) dmaCfg.uartCB(HAL_UART_DMA-1, evt); /
5、执行回调函数 注:回调函数dmaCfg.uartCB的初始化在HalUARTOpenDMA的第一句代码: dmaCfg.uartCB = config -callBackFunc; 而halUARTCfg_t uartConfig结构体的初始化在MT包里的MT_UART.c的MT_UartInit 中 1)typedef struct bool configured; uint8 baudRate; bool flowControl; uint16 flowControlThreshold; uint8 idleTimeout; halUARTBufControl_t rx; halUARTB
6、ufControl_t tx; bool intEnable; uint32 rxChRvdTime; halUARTCBack_t callBackFunc; halUARTCfg_t; 该结构体是UART的配置结构体,设置UART的波特率,流控制,回调函数等等。 Z-stack带有一个MT包,用来方便测试的,上述结构体的初始化便在MT_UartInit 中。 2) typedef struct uint16 rxBufHAL_UART_DMA_RX_MAX; #if HAL_UART_DMA_RX_MAX 256 uint8 rxHead; uint8 rxTail; #else uint
7、16 rxHead; uint16 rxTail; #endif uint8 rxTick; uint8 rxShdw; uint8 txBuf2HAL_UART_DMA_TX_MAX; #if HAL_UART_DMA_TX_MAX 256 uint8 txIdx2; #else uint16 txIdx2; #endif volatile uint8 txSel; uint8 txMT; uint8 txTick; volatile uint8 txShdw; / Sleep Timer LSB shadow. volatile uint8 txShdwValid; / TX shadow
8、 value is valid uint8 txDMAPending; / UART TX DMA is pending halUARTCBack_t uartCB; uartDMACfg_t; 该结构体是协议栈为串口收发分别分配的内存rxbuf和txbuf,已经写入读取操作时的一些方式,如1 by 1读取,定义了多久处理一次串口缓存区等等。 回到执行回调函数这一步,回调函数的初始化在MT_UartInit : #if defined (ZTOOL_P1) | defined (ZTOOL_P2) /uartConfig.callBackFunc = MT_UartProcessZToolDa
9、ta; uartConfig.callBackFunc = rxCB; #elif defined (ZAPP_P1) | defined (ZAPP_P2) uartConfig.callBackFunc = MT_UartProcessZAppData; #else uartConfig.callBackFunc = NULL; #endif 在这里根据预编译的宏ZTOOL_Px和ZAPP_Px来选择回调函数,在这里我们定义的是ZTOOL_P2,并且使用自己定义的回调函数rxCB。自定义的rxCB如下: void rxCB (uint8 port,uint8 event) uint8 rx
10、len; /接收数据长度 uint8* databuf; /接收数据指针 rxlen=Hal_UART_RxBufLen(HAL_UART_PORT_1); /接收缓冲区数据长度,字节为单位 if (rxlen)/当有数据接收时,执行下面程序,没有此条语句时,会无限写数据到串口 HalUARTRead (MT_UART_DEFAULT_PORT, databuf, rxlen); /读接收缓冲区数据到内存databuf+3 HalUARTWrite ( MT_UART_DEFAULT_PORT, databuf, rxlen+1 );/将接收的数据又发回去,告诉自己数据接收到了 功能是轮询过程
11、中,HalUARTRead接收串口调试助手发送的8 byte数据,然后用HalUARTWrite回显到串口调试助手。 3. 串口DMA模式数据收发过程 main函数调用HalDriverInit,HalDriverInit调用HalDmaInit初始化DMA通道01234的地址。然后调用HalUARTInit,在HAL_UART_DMA=TRUE的情况下,接着调用HalUARTInitDMA对引脚,UART0还是UART1,UART寄存器根据功能初始化,然后是对通道2和3的分配: / Setup Tx by DMA. ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_
12、TX ); HAL_DMA_SET_DEST( ch, DMA_UDBUF ); / Setup Rx by DMA. ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_RX ); 这里是对UART的DMA配置,协议栈默认的用于UART接收的DMA通道,映射后为DMA通道3;协议栈默认的用于UART接收的DMA通道,映射后为DMA通道2。 这是协议栈为串口收发分别配置了一块内存空间rxBuf和txBuf,具体在HalUARTInitDMA和HalUARTOpen里配置. (1)串口发送DMA模式:(data) U0DBUF U0DBUF (DMA) rxBuf (内存
13、) HalUARTRead读取rxBuf数据进行处理。 特别要注意的地方,HAL_DMA_SET_DEST( ch, DMA_UDBUF );这里是给HAL_DMA_CH_TX对应的DMA通道3的目的地址设置为DMA_UDBUF,而 #if (HAL_UART_DMA = 2)/原来这行是#if (HAL_UART_DMA = 1) #define DMATRIG_RX HAL_DMA_TRIG_URX0 #define DMATRIG_TX HAL_DMA_TRIG_UTX0 #define DMA_UDBUF HAL_DMA_U0DBUF #define DMA_PAD U0BAUD #e
14、lse #define DMATRIG_RX HAL_DMA_TRIG_URX1 #define DMATRIG_TX HAL_DMA_TRIG_UTX1 #define DMA_UDBUF HAL_DMA_U1DBUF #define DMA_PAD U1BAUD #endif “go to definition of HAL_DMA_U0DBUF” #else /* CC2530 */ #define HAL_DMA_U0DBUF 0x70C1 #define HAL_DMA_U1DBUF 0x70F9 #endif 在手册上U0DBUF的地址为0xC1,从字面上也可以看出这个宏代表的是U0DBUF。原来HAL_UART_DMA = 2的情况下对应的是HAL_DMA_U1DBUF,DMA通道对应的是U1DBUF了,这里才是我之前苦恼的地方,修改了初始化,注意到了流控制,但是串口调试工具显示为00。 就写到这,串口的修改,很多地方借鉴了小峰和其他一些不知名的前辈的文章。谢谢各位!