精读OSAL --DMA方式串行通信(_hal_uart_dma.c)
来源:互联网 发布:sqlserver 添加注释 编辑:程序博客网 时间:2024/06/06 12:34
跳过初始化的内容.
先讲接收操作:
DMA方式的具体操作可以查看DMA的相关内容.
这里有意思的是缓冲区算法的实现,和中断方式还是有些区别.
|BAUD|DXBUF|
|..........|............|
|..........|............|
|..........|............|
|..........|............|
|..........|............|
|..........|............|
|..........|............|
Tail--> |..........|............|
|..........|............|
|..........|............|
|..........|............|
|..........|............|<--Head
|..........|............|
读函数里只对Head操作,每读一字节就上移一字节,清BAUD,读到tail就停止了.
那么为啥要记录波特率呢?我想了好久也没明白.在DMA里会具体说.
代码不上了.
这里说Tail怎么变化,其实Tail指明的就是数据尾在哪里.
来自串口的数据通过DMA直接传到Tail所指的内容.不过因为
DMA所以Tail不能递增.那么Tail什么时候改呢?
是在每个OSAL的循环里:HalUARTPollDMA()里 ,调用HalUARTRxAvailDMA()里.
那么怎么知道数据写到哪呢?这就是为什么要存BAUD的原因.
算法里取反存起来作为没数据的标记,当DMA传输时,直接将BAUD和DxBUF一起
传过来存起来,于是BAUD就变成正常的BAUD值,而不是取反值.
然后POLL里就查找那个还是反的BAUD就是没数据.Tail就改到前一个..
都在HalUARTRxAvailDMA().
到这读操作完成了,下面是DMA的写..
里面有说写操作推荐 用 中断 方式,这和上篇没区别就不提了.
这里说DMA方式:
|SEL=0|SEL=1|
|IDX=n |IDX=m|
|...........|...........|
|...........|...........|
|...........|...........|
|...........|...........|
(IDX=n)-->|...........|...........|
|...........|...........|
|...........|...........|<--(IDX=m)
|...........|...........|
|...........|...........|
|...........|...........|
|...........|...........|
|...........|...........|
|...........|...........|
|...........|...........|
算法理角了也很简单,IDX是记录侍发数据长度,发送完一列就清IDX,同时改SEL指向另一列..
不过看代码还是有点难..所以来注释:
static void HalUARTArmTxDMA(void){ halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_DMA_CH_TX); HAL_DMA_SET_SOURCE(ch, dmaCfg.txBuf[dmaCfg.txSel]); HAL_DMA_SET_LEN(ch, dmaCfg.txIdx[dmaCfg.txSel]); dmaCfg.txSel ^= 1; //注意这里取反了txSEL. dmaCfg.txTrig = 1; HAL_DMA_ARM_CH(HAL_DMA_CH_TX); HalUARTPollTxTrigDMA(); if (DMA_PM) { HAL_UART_DMA_SET_RDY_OUT(); }}
每次调用完,SEL都改成另一个.这是要注意.
static void HalUARTPollTxTrigDMA(void) //这个也是在POLL里调用.
{ if ((UxCSR & CSR_TX_BYTE) == 0) // If no TXBUF to shift register transfer, then TXBUF may be MT. { if ((dmaCfg.txTick == 0) || ((uint8)(ST0 - dmaCfg.txTick) > HAL_UART_TX_TICK_MIN)) { dmaCfg.txTick = 0; if (dmaCfg.txTrig && HAL_DMA_CH_ARMED(HAL_DMA_CH_TX)) //这里判断是否要人工触发DMA传输 { HAL_DMA_MAN_TRIGGER(HAL_DMA_CH_TX); } dmaCfg.txTrig = 0; } } else { UxCSR = (CSR_MODE | CSR_RE); // Clear the CSR_TX_BYTE flag. dmaCfg.txTick = ST0; if (dmaCfg.txTick == 0) // Reserve zero to signify that the minimum delay has been met. { dmaCfg.txTick = 0xFF; } }}
void HalUART_DMAIsrDMA(void){ if (dmaCfg.txIdx[dmaCfg.txSel]) //这里判断是否还有数据要传输{ // If there is more Tx data ready to go, re-arm the DMA immediately on it. HalUARTArmTxDMA(); // Indicate that the Tx buffer just finished is now free (re-arming did a ^= toggle of txSel). dmaCfg.txIdx[dmaCfg.txSel] = 0;//因为这前ARM的时候,SEL取反了, //刚刚完成DMA才进中断,在上面ARM中SEL又取反了,那么 //此列已发送所有数据,IDX清零. } else { dmaCfg.txIdx[(dmaCfg.txSel ^ 1)] = 0; // Indicate that the Tx buffer just finished is now free.// 当前没数据,因为没有再ARM,所以要取反清零.// Clear the CSR_TX_BYTE flag & start the txTick to allow the possibility of an immediate// manual trigger from the next Write(), if it occurs more than one character time later. HalUARTPollTxTrigDMA(); } dmaCfg.txMT = TRUE; // Notify CB that at least one Tx buffer is now free to use.}
static uint16 HalUARTWriteDMA(uint8 *buf, uint16 len){ txIdx_t txIdx; uint8 txSel; halIntState_t his; HAL_ENTER_CRITICAL_SECTION(his); txSel = dmaCfg.txSel; txIdx = dmaCfg.txIdx[txSel]; HAL_EXIT_CRITICAL_SECTION(his); // Enforce all or none. if ((len + txIdx) > HAL_UART_DMA_TX_MAX) { return 0; } (void)memcpy(&(dmaCfg.txBuf[txSel][txIdx]), buf, len); HAL_ENTER_CRITICAL_SECTION(his); /* If an ongoing DMA Tx finished while this buffer was being *appended*, then another DMA Tx * will have already been started on this buffer, but it did not include the bytes just appended. * Therefore these bytes have to be re-copied to the start of the new working buffer. */ if (txSel != dmaCfg.txSel)//这里是判断这个过程是否有中断发生,如果有SEL不同,要重要整理过数据. { HAL_EXIT_CRITICAL_SECTION(his); txSel ^= 1; (void)memcpy(&(dmaCfg.txBuf[txSel][0]), buf, len); HAL_ENTER_CRITICAL_SECTION(his); dmaCfg.txIdx[txSel] = len; } else { dmaCfg.txIdx[txSel] = txIdx + len; } // If there is no ongoing DMA Tx, then the channel must be armed here. if (dmaCfg.txIdx[(txSel ^ 1)] == 0) { HAL_EXIT_CRITICAL_SECTION(his); HalUARTArmTxDMA(); } else { dmaCfg.txMT = FALSE; HAL_EXIT_CRITICAL_SECTION(his); } return len;}
到此对DMA的UART就没什么疑问了.
- 精读OSAL --DMA方式串行通信(_hal_uart_dma.c)
- 精读OSAL --中断方式串行通信(_hal_uart_isr.c)
- 精读OSAL --SPI方式串行通信(_hal_uart_spi.c)
- 精读OSAL --时钟及休眠(hal_sleep.c)
- 精读OSAL --按键的执行流程(hal_key.c onboard.c)
- 并行串行通信方式图解
- 串行通信程序(C#)
- 精读OSAL --回调函数的理解
- 精读OSAL --我的SPI驱动
- 串行通信接口RS-232C
- 串行通信
- 串行通信
- 串行通信
- 串行通信
- 串行通信
- 串行通信
- 串行通信
- 串行通信
- 视图索引的机制
- socket和tcp/ip
- 向任意应用程序(包括后台的)发送任意按键消息
- frame,iframe,frameset用法和区别
- 大数据处理技术 - 基于Hadoop的实战培训
- 精读OSAL --DMA方式串行通信(_hal_uart_dma.c)
- linux下socket通信,server和client简单例子(三)
- 三层架构之初识庐山真面目
- 如何开机自动运行某个程序?
- 软文写作之如何利用情绪化
- iOS开发资源:几个类似Path 2.0侧滑菜单的效果实现
- js出现“Access is denied to PIE.htc”
- 多继承同名覆盖
- 利用BitmapCutter实现截取图片功能MVC3