Z-STACK之cc2530串口驱动详解下

本文详细介绍了Z-STACK中串口驱动的DMA方式,讲解了如何初始化串口DMA,包括设置DMA配置描述符,以及如何在`HalUARTInitDMA`和`HalUARTOpenDMA`函数中配置波特率和中断处理。文中还探讨了DMA在TX和RX上的不同设置,如传输模式和触发源,并分析了`HalUARTWriteDMA`和`HalUARTPollDMA`函数的工作流程,讨论了DMA中断处理和数据传输的细节。
摘要由CSDN通过智能技术生成

         在http://blog.csdn.net/crystal736/article/details/8541443中已经讲了Z-STACK中串口驱动的ISR方式,本文介绍串口驱动的另一种方式DMA,实际上Z-STACK中就是采用的这种方式,看hal_board_cfg.h文件中如下代码

 #if HAL_UART

// Always prefer to use DMA over ISR.
#if HAL_DMA
#ifndef HAL_UART_DMA
#if (defined ZAPP_P1) || (defined ZTOOL_P1)
#define HAL_UART_DMA  1
#elif (defined ZAPP_P2) || (defined ZTOOL_P2)
#define HAL_UART_DMA  2
#else
#define HAL_UART_DMA  1
#endif
#endif
#define HAL_UART_ISR  0
#else
#ifndef HAL_UART_ISR
#if (defined ZAPP_P1) || (defined ZTOOL_P1)
#define HAL_UART_ISR  1
#elif (defined ZAPP_P2) || (defined ZTOOL_P2)
#define HAL_UART_ISR  2
#else
#define HAL_UART_ISR  1
#endif
#endif
#define HAL_UART_DMA  0
#endif


// Used to set P2 priority - USART0 over USART1 if both are defined.
#if ((HAL_UART_DMA == 1) || (HAL_UART_ISR == 1))
#define HAL_UART_PRIPO             0x00
#else
#define HAL_UART_PRIPO             0x40
#endif


#else
#define HAL_UART_DMA  0
#define HAL_UART_ISR  0
#endif


可以看出z-stack中串口驱动使用的是DMA方式。上篇文章讲了DMA具体工作方式及原理,这里就说说串口是如何使用DMA的。先看驱动源文件_hal_uart_dma.c

先看一下串口DMA方式中很重要的一个结构体uartDMACfg_t

typedef struct
{
  uint16 rxBuf[HAL_UART_DMA_RX_MAX];
#if HAL_UART_DMA_RX_MAX < 256
  uint8 rxHead;
  uint8 rxTail;
#else
  uint16 rxHead;
  uint16 rxTail;
#endif
  uint8 rxTick;
  uint8 rxShdw;


  uint8 txBuf[2][HAL_UART_DMA_TX_MAX];
#if HAL_UART_DMA_TX_MAX < 256
  uint8 txIdx[2];
#else
  uint16 txIdx[2];
#endif
  volatile uint8 txSel;
  uint8 txMT;
  uint8 txTick;           // 1-character time in 32kHz ticks according to baud rate,
                          // to be used in calculating time lapse since DMA ISR
                          // to allow delay margin before start firing DMA, so that
                          // DMA does not overwrite UART DBUF of previous packet
  
  volatile uint8 txShdw;  // Sleep Timer LSB shadow.
  volatile uint8 txShdwValid; // TX shadow value is valid
  uint8 txDMAPending;     // UART TX DMA is pending


  halUARTCBack_t uartCB;
} uartDMACfg_t;

跟uartISRCfg_t有很多相同之处,如rxTick、rxShdw。这里txBuf定义成二维数组,以增加缓冲区长度容纳更多的数据,其他的成员在讲具体函数时会提到。先看DMA串口驱动的初始化函数

static void HalUARTInitDMA(void)
{
  halDMADesc_t *ch;


  P2DIR &= ~P2DIR_PRIPO;
  P2DIR |= HAL_UART_PRIPO;


#if (HAL_UART_DMA == 1)
  PERCFG &= ~HAL_UART_PERCFG_BIT;    // Set UART0 I/O to Alt. 1 location on P0.
#else
  PERCFG |= HAL_UART_PERCFG_BIT;     // Set UART1 I/O to Alt. 2 location on P1.
#endif
  PxSEL  |= UxRX_TX;                 // Enable Tx and Rx peripheral functions on pins.
  ADCCFG &= ~UxRX_TX;                // Make sure ADC doesnt use this.
  UxCSR = CSR_MODE;                  // Mode is UART Mode.
  UxUCR = UCR_FLUSH;                 // Flush it.


  // Setup Tx by DMA.
  ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_TX );


  // The start address of the destination.
  HAL_DMA_SET_DEST( ch, DMA_UDBUF );


  // Using the length field to determine how many bytes to transfer.
  HAL_DMA_SET_VLEN( ch, HAL_DMA_VLEN_USE_LEN );


  // One byte is transferred each time.
  HAL_DMA_SET_WORD_SIZE( ch, HAL_DMA_WORDSIZE_BYTE );


  // The bytes are transferred 1-by-1 on Tx Complete trigger.
  HAL_DMA_SET_TRIG_MODE( ch, HAL_DMA_TMODE_SINGLE );
  HAL_DMA_SET_TRIG_SRC( ch, DMATRIG_TX );


  // The source address is incremented by 1 byte after each transfer.
  HAL_DMA_SET_SRC_INC( ch, HAL_DMA_SRCINC_1 );


  // The destination address is constant - the Tx Data Buffer.
  HAL_DMA_SET_DST_INC( ch, HAL_DMA_DSTINC_0 );


  // The DMA Tx done is serviced by ISR in order to maintain full thruput.
  HAL_DMA_SET_IRQ( ch, HAL_DMA_IRQMASK_ENABLE );


  // Xfer all 8 bits of a byte xfer.
  HAL_DMA_SET_M8( ch, HAL_DMA_M8_USE_8_BITS );


  // DMA has highest priority for memory access.
  HAL_DMA_SET_PRIORITY( ch, HAL_DMA_PRI_HIGH );


  // Setup Rx by DMA.
  ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_RX );


  // The start address of the source.
  HAL_DMA_SET_SOURCE( ch, DMA_UDBUF );


  // Using the length field to determine how many bytes to transfer.
  HAL_DMA_SET_VLEN( ch, HAL_DMA_VLEN_USE_LEN );


  /* The trick is to cfg DMA to xfer 2 bytes for every 1 byte of Rx.
   * The byte after the Rx Data Buffer is the Baud Cfg Register,
   * which always has a known value. So init Rx buffer to inverse of that

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值