2015年11月3日 星期二

ZigBee TI CC2530 程式筆記-UART 程式流程 hal_uart.c hal_uart.h _hal_uart_dma.c

1.HalUARTRead和HalUARTWrite程式碼寫在hal_uart.c內,程式如下:

---------------------------------------程式分隔--------------------------------------------------
uint16 HalUARTRead(uint8 port, uint8 *buf, uint16 len)
{
  (void)port;
  (void)buf;
  (void)len;

#if (HAL_UART_DMA == 1)
  if (port == HAL_UART_PORT_0)  return HalUARTReadDMA(buf, len);
#endif
#if (HAL_UART_DMA == 2)
  if (port == HAL_UART_PORT_1)  return HalUARTReadDMA(buf, len);
#endif
#if (HAL_UART_ISR == 1)
  if (port == HAL_UART_PORT_0)  return HalUARTReadISR(buf, len);
#endif
#if (HAL_UART_ISR == 2)
  if (port == HAL_UART_PORT_1)  return HalUARTReadISR(buf, len);
#endif

#if HAL_UART_USB
  return HalUARTRx(buf, len);
#else
  return 0;
#endif
}
---------------------------------------程式分隔--------------------------------------------------
uint16 HalUARTWrite(uint8 port, uint8 *buf, uint16 len)
{
  (void)port;
  (void)buf;
  (void)len;

#if (HAL_UART_DMA == 1)
  if (port == HAL_UART_PORT_0)  return HalUARTWriteDMA(buf, len);
#endif
#if (HAL_UART_DMA == 2)
  if (port == HAL_UART_PORT_1)  return HalUARTWriteDMA(buf, len);
#endif
#if (HAL_UART_ISR == 1)
  if (port == HAL_UART_PORT_0)  return HalUARTWriteISR(buf, len);
#endif
#if (HAL_UART_ISR == 2)
  if (port == HAL_UART_PORT_1)  return HalUARTWriteISR(buf, len);
#endif

#if HAL_UART_USB
  HalUARTTx(buf, len);
  return len;
#else
  return 0;
#endif
}
port基本上使用的是HAL_UART_PORT_0,所以會進入到HalUARTReadDMA和HalUARTWriteDMA。

---------------------------------------我是分隔線--------------------------------------------------

2.HalUARTReadDMA和HalUARTWriteDMA程式碼寫在_hal_uart_dma.c內,程式如下:

---------------------------------------程式分隔--------------------------------------------------

static uint16 HalUARTWriteDMA(uint8 *buf, uint16 len)
{
  uint16 cnt;
  halIntState_t his;
  uint8 txSel;
  txIdx_t txIdx;

  // Enforce all or none.
  if ((len + dmaCfg.txIdx[dmaCfg.txSel]) > HAL_UART_DMA_TX_MAX)
  {
    return 0;
  }
//注意一下HAL_UART_DMA_TX_MAX,預設為256,所以一次資料量最大不能超過256,否則沒辦法給UART資料。

  HAL_ENTER_CRITICAL_SECTION(his);
  txSel = dmaCfg.txSel;
  txIdx = dmaCfg.txIdx[txSel];
  HAL_EXIT_CRITICAL_SECTION(his);

  for (cnt = 0; cnt < len; cnt++)
  {
    dmaCfg.txBuf[txSel][txIdx++] = buf[cnt];
  }
//將要寫入的資料存近dmaCfg.txBuf,這是TI寫好的,別亂改。

  HAL_ENTER_CRITICAL_SECTION(his);
  if (txSel != dmaCfg.txSel)
  {
    HAL_EXIT_CRITICAL_SECTION(his);
    txSel = dmaCfg.txSel;
    txIdx = dmaCfg.txIdx[txSel];

    for (cnt = 0; cnt < len; cnt++)
    {
      dmaCfg.txBuf[txSel][txIdx++] = buf[cnt];
    }
    HAL_ENTER_CRITICAL_SECTION(his);
  }

  dmaCfg.txIdx[txSel] = txIdx;

  if (dmaCfg.txIdx[(txSel ^ 1)] == 0)
  {
    // TX DMA is expected to be fired
    dmaCfg.txDMAPending = TRUE;//TRUE表示有資料要送入UART,才會驅動到控制UART的程式碼。
  }
  HAL_EXIT_CRITICAL_SECTION(his);

  dmaCfg.txDMAPending = TRUE;
  這行是我自己加入的,因為會進入到HalUARTWriteDMA表示一定有資料,何必像上面一樣再次判斷。
 return cnt;
}

---------------------------------------程式分隔--------------------------------------------------

static uint16 HalUARTReadDMA(uint8 *buf, uint16 len)
{
  uint16 cnt;

  for (cnt = 0; cnt < len; cnt++)
  {
    if (!HAL_UART_DMA_NEW_RX_BYTE(dmaCfg.rxHead))
    {
      break;
    }
    *buf++ = HAL_UART_DMA_GET_RX_BYTE(dmaCfg.rxHead);
    HAL_UART_DMA_CLR_RX_BYTE(dmaCfg.rxHead);
//#if HAL_UART_DMA_RX_MAX == 256
//    (dmaCfg.rxHead)++;
//#else
    if (++(dmaCfg.rxHead) >= HAL_UART_DMA_RX_MAX)
    {
      dmaCfg.rxHead = 0;
    }
//#endif
  }
  PxOUT &= ~HAL_UART_Px_RTS;  // Re-enable the flow on any read.
//基本上就是將讀到的資料,寫入到你指定的buf。
//黃色的註解,是我個人會修改成使用
//if (++(dmaCfg.rxHead) >= HAL_UART_DMA_RX_MAX)
//    {
//      dmaCfg.rxHead = 0;
//    }這段進行計算,我個人認為讀的時候比較順。
  return cnt;
}

---------------------------------------我是分隔線--------------------------------------------------

3.HalUARTReadDMA和HalUARTWriteDMA並沒有寫入UART,只是寫入到TI指定的buf,實際上寫入的function是static void HalUARTPollDMA(void)。程式如下:

---------------------------------------程式分隔--------------------------------------------------

static void HalUARTPollDMA(void)
{
  uint16 cnt = 0;
  uint8 evt = 0;

  if (HAL_UART_DMA_NEW_RX_BYTE(dmaCfg.rxHead))
  {
    rxIdx_t tail = findTail();

    // If the DMA has transferred in more Rx bytes, reset the Rx idle timer.
    if (dmaCfg.rxTail != tail)
    {
      dmaCfg.rxTail = tail;

      // Re-sync the shadow on any 1st byte(s) received.
      if (dmaCfg.rxTick == 0)
      {
        dmaCfg.rxShdw = ST0;
      }
      dmaCfg.rxTick = HAL_UART_DMA_IDLE;
    }
    else if (dmaCfg.rxTick)
    {
      // Use the LSB of the sleep timer (ST0 must be read first anyway).
      uint8 decr = ST0 - dmaCfg.rxShdw;

      if (dmaCfg.rxTick > decr)
      {
        dmaCfg.rxTick -= decr;
        dmaCfg.rxShdw = ST0;
      }
      else
      {
        dmaCfg.rxTick = 0;
      }
    }
    cnt = HalUARTRxAvailDMA();
  }
  else
  {
    dmaCfg.rxTick = 0;
  }

  if ((cnt >= HAL_UART_DMA_FULL)||(cnt > 10))
  {
    evt = HAL_UART_RX_FULL;
  }
  else if (cnt >= HAL_UART_DMA_HIGH)
  {
    evt = HAL_UART_RX_ABOUT_FULL;
    PxOUT |= HAL_UART_Px_RTS;  // Disable Rx flow.
  }
  else if (cnt && !dmaCfg.rxTick)
  {
    evt = HAL_UART_RX_TIMEOUT;
  }
//這個if可以觀察到,UART事件處理是在這邊決定的。

/************************************************************/
/****************上面是Read,下面是Wirte。*******************/
/************************************************************/

  if (dmaCfg.txMT)
  {
    dmaCfg.txMT = FALSE;
    evt |= HAL_UART_TX_EMPTY;
  }

  if (dmaCfg.txShdwValid)
  {
    uint8 decr = ST0;
    decr -= dmaCfg.txShdw;
    if (decr > dmaCfg.txTick)
    {
      // No protection for txShdwValid is required
      // because while the shadow was valid, DMA ISR cannot be triggered
      // to cause concurrent access to this variable.
      dmaCfg.txShdwValid = FALSE;
    }
  }
 // dmaCfg.txShdwValid = FALSE;
  if (dmaCfg.txDMAPending && !dmaCfg.txShdwValid)
  {
    //以下就是寫入UART程式碼
    // UART TX DMA is expected to be fired and enough time has lapsed since last DMA ISR
    // to know that DBUF can be overwritten
    halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_DMA_CH_TX);
    halIntState_t intState;

    // Clear the DMA pending flag
    dmaCfg.txDMAPending = FALSE;
 
    HAL_DMA_SET_SOURCE(ch, dmaCfg.txBuf[dmaCfg.txSel]);
    HAL_DMA_SET_LEN(ch, dmaCfg.txIdx[dmaCfg.txSel]);
    dmaCfg.txSel ^= 1;
    HAL_ENTER_CRITICAL_SECTION(intState);
    HAL_DMA_ARM_CH(HAL_DMA_CH_TX);
    do
    {
      asm("NOP");
    } while (!HAL_DMA_CH_ARMED(HAL_DMA_CH_TX));
    HAL_DMA_CLEAR_IRQ(HAL_DMA_CH_TX);
    HAL_DMA_MAN_TRIGGER(HAL_DMA_CH_TX);
    HAL_EXIT_CRITICAL_SECTION(intState);
  }
  else
  {
    halIntState_t his;

    HAL_ENTER_CRITICAL_SECTION(his);
    if ((dmaCfg.txIdx[dmaCfg.txSel] != 0) && !HAL_DMA_CH_ARMED(HAL_DMA_CH_TX)
                                          && !HAL_DMA_CHECK_IRQ(HAL_DMA_CH_TX))
    {
      HAL_EXIT_CRITICAL_SECTION(his);
      HalUARTIsrDMA();
    }
    else
    {
      HAL_EXIT_CRITICAL_SECTION(his);
    }
  }

  if (evt && (dmaCfg.uartCB != NULL))
  {
    dmaCfg.uartCB(HAL_UART_DMA-1, evt);
  }
}

沒有留言:

張貼留言