一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

協(xié)議中UART的兩種模式

 lyncan 2011-10-22

協(xié)議棧中UART有兩種模式:
1、中斷
2、DMA

對(duì)于這兩種模式具體運(yùn)用在哪一步,糾結(jié)了很久.通過(guò)UART配置結(jié)構(gòu):
typedef struct
{
  uint8 *rxBuf;
  uint8 rxHead;
  uint8 rxTail;
  uint8 rxMax;
  uint8 rxCnt;
  uint8 rxTick;
  uint8 rxHigh;

  uint8 *txBuf;
#if HAL_UART_BIG_TX_BUF
  uint16 txHead;
  uint16 txTail;
  uint16 txMax;
  uint16 txCnt;
#else
  uint8 txHead;
  uint8 txTail;
  uint8 txMax;
  uint8 txCnt;
#endif
  uint8 txTick;

  uint8 flag;

  halUARTCBack_t rxCB;
} uartCfg_t;

可以看到協(xié)議棧為串口收發(fā)分別配置了一塊內(nèi)存空間rxBuf和txBuf,具體在HalUARTOpen()里配置.
而中斷與DMA這兩種模式具體就運(yùn)用于 數(shù)據(jù)在串口緩存U0_1DBUF與rxBuf/txBuf之間傳送 的過(guò)程.

串口接收DMA模式:(data) —> U0DBUF —(DMA)—> rxBuf —> HalUARTRead()讀取rxBuf數(shù)據(jù)進(jìn)行處理
串口接收中斷模式:(data) —> U0DBUF —(中斷)—> rxBuf —> HalUARTRead()讀取rxBuf數(shù)據(jù)進(jìn)行處理


串口發(fā)送DMA模式:(data) <— U0DBUF <—(DMA)— txBuf
串口發(fā)送中斷模式:(data) <— U0DBUF <—(中斷)— txBuf

協(xié)議中UART的兩種模式 - 小峰 - happy~我覺(jué)得這樣理解好像還有問(wèn)題,本身對(duì)DMA不了解,網(wǎng)上又幾乎查不到關(guān)于協(xié)議棧有關(guān)UART_DMA模式具體

流程資料,卡在這里很久,所以打算建立個(gè)大概印象就跳出來(lái),以后再看.協(xié)議中UART的兩種模式 - 小峰 - happy~

 

先記錄下中斷模式吧~
###########################################################################

###########################################################################
1、中斷模式(UART接收)

當(dāng)1寫入U(xiǎn)xCSR.RE位時(shí),在UART上數(shù)據(jù)接收就開(kāi)始了.然后UART會(huì)在輸入引腳RXDx中尋找有效起始位,并且設(shè)置UxCSR.ACTIVE位為1.當(dāng)檢測(cè)出有效起始位時(shí),收到的字節(jié)就傳入接收寄存器,UxCSR.RX_BUTE位設(shè)置為1.該操作完成時(shí),產(chǎn)生接收中斷。通過(guò)寄存器UxBUF提供收到的數(shù)據(jù)字節(jié)。當(dāng)UxBUF讀出時(shí),UxCSR.RX_BUTE位由硬件清零.當(dāng)產(chǎn)生中斷時(shí),自然進(jìn)入中斷程序,看下UART0接收中斷函數(shù):

 ***************************************
#if HAL_UART_0_ENABLE
HAL_ISR_FUNCTION( halUart0RxIsr, URX0_VECTOR )
{
  cfg0->rxBuf[cfg0->rxHead] = U0DBUF;

  if ( cfg0->rxHead == cfg0->rxMax )
  {
    cfg0->rxHead = 0;
  }
  else
  {
    cfg0->rxHead++;
  }
}
#endif

/**************************************

中斷函數(shù)完成了把U0DBUF里一字節(jié)的數(shù)據(jù)傳送到rxBuf[ ]存儲(chǔ)空間去.這里rxHead是指向rxBuf[ ]的指針,看單詞像是指在數(shù)組的頭,其實(shí)應(yīng)理解為rxBuf[ ]接收數(shù)據(jù)的個(gè)數(shù)(以字節(jié)為單位).rxMax是rxBuf[ ]可以存儲(chǔ)最大字節(jié)數(shù),為128.而后面當(dāng)用HalUARTRead()來(lái)讀取rxBuf[ ]時(shí),rxTail應(yīng)理解為rxBuf[]轉(zhuǎn)移出去數(shù)據(jù)的個(gè)數(shù)(同樣以字節(jié)為單位).那數(shù)據(jù)傳送到rxBuf[ ]存儲(chǔ)空間去后呢?先看下pollISR()

 *****************************************************************************/
//大概每200ms調(diào)用pollISR()函數(shù).當(dāng)串口UxDBUF接收到一字節(jié)數(shù)據(jù)產(chǎn)生中斷,在中斷
//程序中把UxDBUF中數(shù)據(jù)傳送到rxbuf[ ]中(這有個(gè)坎要跨過(guò)來(lái),pollISR()200ms才被調(diào)用一次,而不是每次
中斷后都調(diào)用一次,如果串口接收的是大的數(shù)據(jù)包,則200ms內(nèi)rxbuf[ ]已經(jīng)接收了約48字節(jié)(這個(gè)后面分析),中斷了48次??.當(dāng)然如果串口沒(méi)有接收到數(shù)據(jù),也就是說(shuō)沒(méi)有發(fā)生串口接收中斷,cfg應(yīng)為是為空的,則cnt=0).此后pollISR()進(jìn)行輪詢,主要是重置超時(shí)時(shí)間和計(jì)算rxbuf[ ]還有多少數(shù)據(jù)沒(méi)有讀走(即cnt).然后再跳回到HalUARTPoll()函數(shù)進(jìn)行下一步處理.
static void pollISR( uartCfg_t *cfg )
{
  uint8 cnt = UART_RX_AVAIL( cfg );
//計(jì)算rxBuf[]中還有多少數(shù)據(jù)沒(méi)有讀出(以字節(jié)為單位)

  if ( !(cfg->flag & UART_CFG_RXF) ) //UART_CFG_RXF:Rx flow is disabled.rx流控制未關(guān)閉
  {
    // If anything received, reset the Rx idle timer.
    //如果又有新的數(shù)據(jù)接收到,則重置超時(shí)時(shí)間
    if ( cfg->rxCnt != cnt )
    {
      cfg->rxTick = HAL_UART_RX_IDLE;
      cfg->rxCnt = cnt;
    }

    /* It is necessary to stop Rx flow in advance of a full Rx buffer because
     * bytes can keep coming while sending H/W fifo flushes.
     */
     //當(dāng)接收數(shù)據(jù)超過(guò)安全界限的時(shí)候,通過(guò)硬件流控制停止接收數(shù)據(jù)
    if ( cfg->rxCnt >= (cfg->rxMax - SAFE_RX_MIN) )
    {
      RX_STOP_FLOW( cfg );
    }
  }
}
#endif

/******************************************************************************
pollISR()函數(shù)主要就是設(shè)置rxTick和rxCnt,發(fā)生接收中斷并且接收中斷函數(shù)處理完后,這些參數(shù)都會(huì)改變.
pollISR()執(zhí)行完成后就跳回到HalUARTPoll()中.
看下 HalUARTPoll()

/**************************************
void HalUARTPoll( void )
{
#if ( HAL_UART_0_ENABLE | HAL_UART_1_ENABLE )
  static uint8 tickShdw;
  uartCfg_t *cfg;
  uint8 tick;

//---------以下設(shè)置cfg
#if HAL_UART_0_ENABLE
  if ( cfg0 ) 
//當(dāng)串口接收到數(shù)據(jù)時(shí),在中斷函數(shù)或DMA程序中會(huì)改變cfg0值,如果沒(méi)有接收到數(shù)據(jù),cfg0

為空.
  {
    cfg = cfg0;
  }
#endif
//---------
#if HAL_UART_1_ENABLE
  if ( cfg1 )
  {
    cfg = cfg1;//同上
  }
#endif
//---------
 
  // Use the LSB of the sleep timer (ST0 must be read first anyway).
  //睡眠定時(shí)器.ST0為睡眠定時(shí)器計(jì)數(shù)值的低8位

  tick = ST0 - tickShdw;
  tickShdw = ST0;

  do
  {
    //------------------------發(fā)送超時(shí)時(shí)間
    if ( cfg->txTick > tick )
    {
      cfg->txTick -= tick;
    }
    else
    {
      cfg->txTick = 0;
    }
    //------------------------接收超時(shí)時(shí)間
    if ( cfg->rxTick > tick )
    {
      cfg->rxTick -= tick;
    }
    else
    {
      cfg->rxTick = 0;
    }
    //------------------------
#if HAL_UART_ISR
#if HAL_UART_DMA
    if ( cfg->flag & UART_CFG_DMA )
    {                            
      pollDMA( cfg ); //pollDMA( cfg )
    }
    else
#endif
      {
      pollISR( cfg );  //pollISR( cfg ) 
      }
#elif HAL_UART_DMA  
    pollDMA( cfg );
#endif

    /* The following logic makes continuous callbacks on any eligible flag(合法標(biāo)志)
     * until the condition corresponding to the flag is rectified.
     * So even if new data is not received, continuous callbacks are made.
     */
      if ( cfg->rxHead != cfg->rxTail ) //初始化時(shí)rxHead=rxTail=0,不相等,rxbuf[ ]中有數(shù)據(jù)
      {
      uint8 evt;

      if ( cfg->rxHead >= (cfg->rxMax - SAFE_RX_MIN) )
      {
        evt = HAL_UART_RX_FULL; //rxBuf接收[ ]滿,則觸發(fā)事件
      }
      else if ( cfg->rxHigh && (cfg->rxHead >= cfg->rxHigh) )
      {
        evt = HAL_UART_RX_ABOUT_FULL; //rxBuf[ ]接收到預(yù)設(shè)值(默認(rèn)80字節(jié)),則觸發(fā)事件
    }
      else if ( cfg->rxTick == 0 )
    {
        evt = HAL_UART_RX_TIMEOUT;  //RX接收事件超時(shí),則觸發(fā)事件
    }
    else
    {
        evt = 0;
    }

    if ( evt && cfg->rxCB )  //有事件并且有回調(diào)函數(shù)
    {
        cfg->rxCB( ((cfg->flag & UART_CFG_U1F)!=0), evt );  //調(diào)用回調(diào)函數(shù)處理這些事件
    }
    }

  ………………

  } while ( TRUE );
#else
  return;
#endif
}

/**************************************
可以看到,初始化時(shí)rxHead=rxTail=0,如果發(fā)生接收中斷,在中斷服務(wù)函數(shù)中把UxDBUF中的數(shù)據(jù)傳送到
rxbuf[ ]中(這一步也可以在DMA服務(wù)程序中完成),則rxHead與rxTail值不等(rxHead是rxBuf[ ]接收數(shù)據(jù)的個(gè)數(shù),rxTail是rxBuf[ ]轉(zhuǎn)移出去數(shù)據(jù)個(gè)數(shù)),再根據(jù)兩值的差值,判斷具體事件evt,最后再調(diào)用回調(diào)函數(shù):cfg->rxCB();回調(diào)函數(shù)在哪?回調(diào)函數(shù) cfg->rxCB( ((cfg->flag & UART_CFG_U1F)!=0), evt ),在cfg中有halUARTCBack_t rxCB;則肯定有個(gè)地方配置cfg這個(gè)結(jié)構(gòu)體,這個(gè)地方是HalUARTOpen( uint8 port, halUARTCfg_t *config );在這個(gè)函數(shù)中可以看到,結(jié)構(gòu)體config的內(nèi)容一項(xiàng)項(xiàng)賦給了結(jié)構(gòu)體cfg,其中包括cfg->rxCB = config->callBackFunc;那肯定有個(gè)地方配置config這個(gè)結(jié)構(gòu)體,這個(gè)地方是SPIMgr_Init (),這個(gè)函數(shù)有一句HalUARTOpen (SPI_MGR_DEFAULT_PORT, &uartConfig),*config與&uartConfig是同一halUARTCfg_t類型結(jié)構(gòu)體,而且SPIMgr_Init ()函數(shù)中對(duì)uartConfig進(jìn)行了定義,如下:

  /* UART Configuration */
  uartConfig.configured           = TRUE;
  uartConfig.baudRate             = SPI_MGR_DEFAULT_BAUDRATE;
  uartConfig.flowControl          = 0;//SPI_MGR_DEFAULT_OVERFLOW;
  uartConfig.flowControlThreshold = SPI_MGR_DEFAULT_THRESHOLD;
  uartConfig.rx.maxBufSize        = SPI_MGR_DEFAULT_MAX_RX_BUFF;
  uartConfig.tx.maxBufSize        = SPI_MGR_DEFAULT_MAX_TX_BUFF;
  uartConfig.idleTimeout          = SPI_MGR_DEFAULT_IDLE_TIMEOUT;
  uartConfig.intEnable            = TRUE;
#if defined (ZTOOL_P1) || defined (ZTOOL_P2)
  uartConfig.callBackFunc         = SPIMgr_ProcessZToolData;  //回調(diào)函數(shù)
#elif defined (ZAPP_P1) || defined (ZAPP_P2)
  uartConfig.callBackFunc         = SPIMgr_ProcessZAppData;  //回調(diào)函數(shù)
#else
  uartConfig.callBackFunc         = NULL;
#endif


來(lái)看下SPIMgr_ProcessZToolData ( uint8 port, uint8 event )
/*****************************************************
 * @fn      SPIMgr_ProcessZToolRxData
 *
 * @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   pBuffer  - pointer to the buffer that contains the data
 *          length   - length of the buffer
 *
 *
 * @return  None
 
void SPIMgr_ProcessZToolData ( uint8 port, uint8 event )
{
  uint8  ch;

  /* Verify events */
  if (event == HAL_UART_TX_FULL)
  {
    // Do something when TX if full
    return;
  }

  if (event & (HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT))
  {
    while (Hal_UART_RxBufLen(SPI_MGR_DEFAULT_PORT)) //RxBuf[ ]中字節(jié)數(shù),即有數(shù)據(jù)
    {
      HalUARTRead (SPI_MGR_DEFAULT_PORT, &ch, 1); //每次讀取1字節(jié)到ch所指空間
                                                                                              //接下來(lái)對(duì)所讀字節(jié)的state進(jìn)行判斷
      switch (state) //state 參見(jiàn)上面宏定義/* State values for ZTool protocal */
      {
        case SOP_STATE:
          if (ch == SOP_VALUE)  //SOP_VALUE=0x02
            state = CMD_STATE1;
          break;

        case CMD_STATE1:
          CMD_Token[0] = ch;
          state = CMD_STATE2;
          break;

        case CMD_STATE2:
          CMD_Token[1] = ch;
          state = LEN_STATE;
          break;

        case LEN_STATE:
          LEN_Token = ch;
          if (ch == 0)
            state = FCS_STATE;
          else
            state = DATA_STATE;
  //state = DATA_STATE=0x04

          tempDataLen = 0;

          /* Allocate memory for the data */
          SPI_Msg = (mtOSALSerialData_t *)osal_msg_allocate( sizeof ( mtOSALSerialData_t ) +

2+1+LEN_Token );

          if (SPI_Msg)  //構(gòu)造消息:把SOP字節(jié)和FCS字節(jié)去掉,剩下2字節(jié)的CMD和1字節(jié)的Data
          {
            /* Fill up what we can */
            SPI_Msg->hdr.event = CMD_SERIAL_MSG;  //CMD_SERIAL_MSG
            SPI_Msg->msg = (uint8*)(SPI_Msg+1);
            SPI_Msg->msg[0] = CMD_Token[0];
            SPI_Msg->msg[1] = CMD_Token[1];
            SPI_Msg->msg[2] = LEN_Token;
          }
          else
          {
            state = SOP_STATE;
            return;
          }

          break;

        case DATA_STATE:
            SPI_Msg->msg[3 + tempDataLen++] = ch;
            if ( tempDataLen == LEN_Token )
              state = FCS_STATE;
          break;

        case FCS_STATE:  //幀校驗(yàn)序列(FCS),則判斷是接收數(shù)據(jù)是否正確

          FSC_Token = ch;

          /* Make sure it's correct */
          if ((SPIMgr_CalcFCS ((uint8*)&SPI_Msg->msg[0], 2 + 1 + LEN_Token) == FSC_Token))
          {
            osal_msg_send( MT_TaskID, (byte *)SPI_Msg ); 
//接收數(shù)據(jù)正確則發(fā)送系統(tǒng)信息觸發(fā)MT層任

務(wù).事件為CMD_SERIAL_MSG
          }
          else
          {
            /* deallocate the msg */
            osal_msg_deallocate ( (uint8 *)SPI_Msg);
          }

          /* Reset the state, send or discard the buffers at this point */
          state = SOP_STATE;

         break;

        default:
         break;
      }


    }
  }
}
#endif*********************************************************
(這個(gè)函數(shù)只是總體上了解了下)
回調(diào)函數(shù)SPIMgr_ProcessZToolData()對(duì)rxbuf[]中的每一字節(jié)數(shù)據(jù)進(jìn)行分析,并且構(gòu)造一個(gè)發(fā)往系統(tǒng)的消息
包(具體事件為SPI_Msg->hdr.event = CMD_SERIAL_MSG)然后調(diào)用osal_msg_send( MT_TaskID, (byte *)SPI_Msg )給系統(tǒng)發(fā)送消息,而下面肯定又會(huì)調(diào)用osal_set_event()來(lái)設(shè)置任務(wù)事件發(fā)生標(biāo)志,最后調(diào)用MT層的事件處理函數(shù),下面來(lái)看下MT層的事件處理函數(shù):
/**********************************************************
 * @fn      MT_ProcessEvent
 *
 * @brief
 *
 *   MonitorTest Task Event Processor.  This task is put into the
 *   task table.
 *
 * @param   byte task_id - task ID of the MT Task
 * @param   UINT16 events - event(s) for the MT Task
 *
 * @return  void
 */
UINT16 MT_ProcessEvent( byte task_id, UINT16 events )
{
  uint8 *msg_ptr;

   ………………

  if ( events & SYS_EVENT_MSG )
  {
    while ( (msg_ptr = osal_msg_receive( MT_TaskID )) )
    {
      MT_ProcessCommand( (mtOSALSerialData_t *)msg_ptr );
    }
   ………………
/*********************************************************************
可以看到它調(diào)用了MT_ProcessCommand( (mtOSALSerialData_t *)msg_ptr )來(lái)進(jìn)行下一步的操作,來(lái)看下
MT_ProcessCommand()這個(gè)函數(shù):

/*********************************************************************
 * @fn      MT_ProcessCommand *
 * @brief

 *
 *   Process Event Messages.
 *
 * @param   byte *msg - pointer to event message
 *
 * @return
 */
void MT_ProcessCommand( mtOSALSerialData_t *msg )
{
   ……………………
#if defined (ZTOOL_P1) || defined (ZTOOL_P2)
    case CMD_SERIAL_MSG:
      MT_ProcessSerialCommand( msg->msg );
      break;
   ……………………
}

/*********************************************************************
通過(guò)上面的MT_ProcessCommand(),再根據(jù)先前SPI_Msg->hdr.event = CMD_SERIAL_MSG,可以得到它調(diào)用
MT_ProcessSerialCommand( msg->msg )這個(gè)函數(shù),而MT_ProcessSerialCommand()函數(shù)根據(jù)參數(shù)cmd來(lái)選擇命令,包括讀RAM,寫RAM等等很多命令指令來(lái)對(duì)接收到的數(shù)據(jù)進(jìn)行下一步操作(先不鉆了……),對(duì)于這個(gè)cmd,cmd = BUILD_UINT16( msg[1], msg[0] ),SPIMgr_ProcessZToolData()對(duì)msg[1], msg[0]進(jìn)行了配置:
            SPI_Msg->msg[0] = CMD_Token[0];
            SPI_Msg->msg[1] = CMD_Token[1];
而CMD_Token[0]與CMD_Token[1]的值又與SPIMgr_ProcessZToolData()中的參數(shù)ch密切相關(guān),對(duì)于這個(gè)ch具體
的定義,只是看到個(gè)uint8  ch;,沒(méi)看到具體初始化為什么值.個(gè)人在想,是不是通過(guò)對(duì)參數(shù)ch的自由設(shè)定來(lái)選擇串口命令cmd,通過(guò)cmd來(lái)實(shí)現(xiàn)對(duì)數(shù)據(jù)的不同處理……【現(xiàn)在發(fā)現(xiàn)這個(gè)應(yīng)該是跟ZTOOL有關(guān),晴天那天說(shuō)ZTOOL上面可以發(fā)送不同命令的】
迷糊中!~協(xié)議中UART的兩種模式 - 小峰 - happy~~糾結(jié)中!~協(xié)議中UART的兩種模式 - 小峰 - happy~

上面分析了UART中斷模式下,從接收到數(shù)據(jù)進(jìn)入中斷函數(shù),把數(shù)據(jù)寫入rxbuf[ ],200ms調(diào)用一次pollISR()輪詢,跳回到HalUARTPoll()進(jìn)行數(shù)據(jù)處理……………….那這個(gè)具體輪詢時(shí)間rxTick約為200ms是怎么得出來(lái)的?借用《Z-STACK問(wèn)題之串口結(jié)構(gòu)uartCfg_t亂說(shuō)》這篇文章的分析:
************
 cfg->rxTick = HAL_UART_RX_IDLE
 #define HAL_UART_RX_IDLE  (6 * RX_MSECS_TO_TICKS)
#define RX_MSECS_TO_TICKS  33 (// The timeout tick is at 32-kHz, so multiply msecs by 33.)

(這個(gè)超時(shí)計(jì)數(shù)采用的是睡眠定時(shí)器,32KHZ時(shí)鐘,一個(gè)微秒計(jì)數(shù)約33次)
因此cfg->rxTick=198,即大約200ms調(diào)用一次pollISR();
論證 #define SAFE_RX_MIN  48  // bytes - max expected per poll @ 115.2k
因?yàn)镃C2430串口波特率為38400bps下,一個(gè)字節(jié)需要時(shí)間約為:4.16ms(這里……這?),那么198/4.16等于
47.6(198ms是中斷處理數(shù)據(jù)的間隔,這期間串口是不斷接收數(shù)據(jù),那在這期間能接收到多少數(shù)據(jù)呢?為47.6字節(jié),因此要保證至少48字節(jié)的存儲(chǔ)空間),約為48.所以這也就是上面定義這個(gè)48的原因。因?yàn)?cfg->rxTick定義了多久處理一次串口緩存區(qū),而為了保證串口緩沖區(qū)不被新的數(shù)據(jù)覆蓋,那么在這個(gè)間隔期間就必須保證大于48字節(jié)存儲(chǔ)空間空閑。
*************
hal_uart.c有這段話:
/* Need to leave enough of the Rx buffer free to handle the incoming bytes
 * after asserting flow control, but before the transmitter has obeyed it.
 * At the max expected baud rate of 115.2k, 16 bytes will only take ~1.3 msecs,
 * but at the min expected baud rate of 38.4k, they could take ~4.2 msecs.
 * SAFE_RX_MIN and DMA_RX_DLY must both be consistent according to
 * the min & max expected baud rate.
 */

我算了半天也算不出上面幾個(gè)數(shù)來(lái)……悲?。∠冗@樣吧……
對(duì)于串口里面的幾個(gè)參數(shù),后面直接轉(zhuǎn)載《Z-STACK問(wèn)題之串口結(jié)構(gòu)uartCfg_t亂說(shuō)》文章好了.
********************************************************
UART接收數(shù)據(jù)中斷模式流程:(純屬個(gè)人理解,還有很多地方不清楚!協(xié)議中UART的兩種模式 - 小峰 - happy~)
(1)
ZMain.c調(diào)用HalDriverInit(),HalDriverInit調(diào)用HalUARTInit()初始化串口驅(qū)動(dòng)程序任務(wù)初始化函數(shù),MT_TaskInit()調(diào)用SPIMgr_Init()初始化串口配置
(2)
串口接收到數(shù)據(jù)產(chǎn)生中斷,進(jìn)入接收中斷服務(wù)程序,把串口緩存UxDBUF中的數(shù)據(jù)傳送到rxbuf[]中去.UxDBUF
只能存放1字節(jié),rxbuf[]能存放128字節(jié),但要空出48字節(jié)作為安全區(qū),因此接收數(shù)據(jù)達(dá)到80字節(jié)時(shí)作為一個(gè)臨界值rxHigh,可以觸發(fā)事件HAL_UART_RX_ABOUT_FUL.
(3)

系統(tǒng)主循環(huán)函數(shù)進(jìn)入HalUARTPoll()輪詢串口,大約每200ms調(diào)用一次pollISR(),然后跳回HalUARTPoll()對(duì)rxbuf[]中的數(shù)據(jù)進(jìn)行處理——>調(diào)用回調(diào)函數(shù)SPIMgr_ProcessZToolData()分析rxbuf[]中每一字節(jié),構(gòu)造發(fā)往系統(tǒng)的消息——>調(diào)用osal_msg_send( MT_TaskID, (byte *)SPI_Msg )發(fā)送消息——>觸發(fā)MT任務(wù)事件,調(diào)用MT任務(wù)事件處理函數(shù) MT_ProcessEvent()——>調(diào)用MT_ProcessCommand(),根據(jù)msg->hdr.event——>調(diào)用MT_ProcessSerialCommand(),根據(jù)參數(shù)cmd來(lái)進(jìn)行最終處理.
********************************************************
UART發(fā)送數(shù)據(jù)中斷模式暫時(shí)不分析了,一頭霧水……

############################################(下面小段于2010.5.25更新)

對(duì)于串口的回調(diào)函數(shù),SPIMgr_Init()中配置了兩個(gè):

#if defined (ZTOOL_P1) || defined (ZTOOL_P2)
  uartConfig.callBackFunc         = SPIMgr_ProcessZToolData;  //回調(diào)函數(shù)
#elif defined (ZAPP_P1) || defined (ZAPP_P2)
  uartConfig.callBackFunc         = SPIMgr_ProcessZAppData;  //回調(diào)函數(shù)
#else
  uartConfig.callBackFunc         = NULL;

有什么區(qū)別呢?在《Zigbee技術(shù)規(guī)范與協(xié)議棧分析》這篇文章中看到過(guò)一段話:
    作為協(xié)調(diào)器,如果程序使用了串口調(diào)試助手,則DMA將上位機(jī)的數(shù)據(jù)按照一個(gè)字節(jié)波特率加一個(gè)字節(jié)數(shù)據(jù)的形式組裝到cfg->rxBuf中供其他函數(shù)調(diào)用,并且通過(guò)回調(diào)函數(shù)SPIMgr_ProcessZToolData ( uint8 port, uint8 event )將任務(wù)的ID和強(qiáng)制事件發(fā)送到任務(wù)列表中,供主循環(huán)處理函數(shù)掃描;作為終端節(jié)點(diǎn)和路由設(shè)備,無(wú)法使用串口調(diào)試助手,則通過(guò)回調(diào)函數(shù) SPIMgr_ProcessZAppData ( uint8 port, uint8 event ) 將任務(wù)的ID和強(qiáng)制事件發(fā)送到任務(wù)列表中。當(dāng)掃描至參數(shù)events=1,則進(jìn)入相應(yīng)層的處理程序進(jìn)行任務(wù)ID和events的約定比對(duì),完成相應(yīng)的功能。
根據(jù)這段話個(gè)人在想:ZTOOL上可以發(fā)命令數(shù)據(jù)到ZC??,協(xié)調(diào)器調(diào)用SPIMgr_ProcessZToolData()進(jìn)行處理,那ZR和ED的串口接收到數(shù)據(jù)(怎么接收?)調(diào)用SPIMgr_ProcessZAppData(),SPIMgr_ProcessZAppData()最終會(huì)調(diào)用osal_msg_send():
/**************************************
void SPIMgr_ProcessZAppData ( uint8 port, uint8 event )
{

     …………
        if ( msg_ptr )
        {
          msg_ptr->event = SPI_INCOMING_ZAPP_DATA;//SPI_INCOMING_ZAPP_DATA
          msg_ptr->status = length;

          /* Read the data of Rx buffer *///Rx buffer是讀到上面為msg_ptr 分配的空間去的
          HalUARTRead( SPI_MGR_DEFAULT_PORT, (uint8 *)(msg_ptr + 1), length );

          /* Send the raw data to application...or where ever */
          osal_msg_send( App_TaskID, (uint8 *)msg_ptr );
        }
     …………
}
/**************************************

至于把串口接收到的數(shù)據(jù)傳送到哪里去,這就跟App_TaskID有關(guān),而App_TaskID是通過(guò)下面這個(gè)函數(shù)來(lái)定義的:

/**************************************
 * @fn      MT_SerialRegisterTaskID
 *
 * @brief
 *
 *   This function registers the taskID of the application so it knows
 *   where to send the messages whent they come in.
 *
 * @param   void
 *
 * @return  void
 **************************************
void SPIMgr_RegisterTaskID( byte taskID )
{
  App_TaskID = taskID;
}

/*************************************
可以看到,如果想把串口接收到的數(shù)據(jù)送到應(yīng)用層任務(wù)(比如SampleApp)中,那這里應(yīng)該注冊(cè)SPIMgr_RegisterTaskID( SampleApp_TaskID ).這樣就可以觸發(fā)應(yīng)用層任務(wù)(SampleApp)的事件(SPI_INCOMING_ZAPP_DATA),在事件處理函數(shù)中添加一個(gè)對(duì)事件SPI_INCOMING_ZAPP_DATA進(jìn)行處理的程序就可以.
但是,我好像看到協(xié)調(diào)器設(shè)備的預(yù)編譯里都是ZTOOL_P1,終端和路由功能的設(shè)備的預(yù)編譯為XZTOOL_P1,沒(méi)有編譯ZAPP_P1ZAPP_P2,也就是沒(méi)有回調(diào)函數(shù),是不是就不能進(jìn)行串口傳輸了?
那如果我在終端和路由節(jié)點(diǎn)上面編譯ZTOOL_P1是否可行??
那如果我在協(xié)調(diào)器上編譯ZAPP_P1,再在應(yīng)用任務(wù)事件處理函數(shù)中添加相應(yīng)SPI_INCOMING_ZAPP_DATA事件的處理程序,串口接收的數(shù)據(jù)是否可以順利傳送到應(yīng)用層??
——等有了實(shí)驗(yàn)套件,我再驗(yàn)證下!

個(gè)人在想,協(xié)調(diào)器串口接收的數(shù)據(jù)送到應(yīng)用層任務(wù)中的方法有
(1)通過(guò)默認(rèn)的SPIMgr_ProcessZToolData()處理函數(shù)把數(shù)據(jù)發(fā)送到應(yīng)用層供應(yīng)用層使用(這點(diǎn)只是猜測(cè),還沒(méi)找著,畢竟MT_ProcessSerialCommand()函數(shù)這么多命令)
(2)通過(guò)SPIMgr_RegisterTaskID()注冊(cè)相應(yīng)TaskID,再通過(guò)SPIMgr_ProcessZAppData()處理函數(shù)把數(shù)據(jù)發(fā)送到相應(yīng)任務(wù)中供其使用(也只是猜測(cè),沒(méi)有驗(yàn)證)
(3)通過(guò)串口讀寫函數(shù)HalUARTRead()和HalUARTWrite(),這兩個(gè)函數(shù)可以在應(yīng)用層中直接調(diào)用來(lái)讀取串口接收到的數(shù)據(jù)以及通過(guò)串口發(fā)送數(shù)據(jù)。

HalUARTRead( uint8 port, uint8 *buf, uint16 len )//從rxbuf[ ]讀取len長(zhǎng)度的數(shù)據(jù)到*buf所指空間
HalUARTWrite( uint8 port, uint8 *buf, uint16 len )//把len長(zhǎng)度的數(shù)據(jù)從*buf所指空間發(fā)送到txbuf[ ]

  以上問(wèn)題見(jiàn)《協(xié)議棧中串口的兩種回調(diào)函數(shù)》記錄。。。。。。。。                                          
純屬個(gè)人想法,有待驗(yàn)證!

###########################################################################

###########################################################################

2、DMA模式(UART接收)

hal_board_cfg.h中有這段話:

/* The preferred method of implementation is by DMA for faster buad rate
   * support. Customer may prefer to use the DMA channels for something else,
   * in which case USART can be driven by ISR. Also, if the 2nd USART is to be
   * used, this module does not currently support using 2 more DMA channels for
   * it, so it must use ISR.
   */

對(duì)于USART操作,波特率高的情況下推薦使用DMA驅(qū)動(dòng)模式.用戶可能習(xí)慣把DMA應(yīng)用在其它地方,這種情況下可
以用中斷模式.同樣,如果第二個(gè)USART也被使用了,由于USART模塊不能在同一時(shí)間支持兩條以上DMA通道,因此這個(gè)時(shí)候必須使用中斷來(lái)驅(qū)動(dòng).


********************
DMA:
允許不同速度的硬件裝置來(lái)溝通,而不需要依于CPU 的大量中斷負(fù)載。否則,CPU需要從來(lái)源把每一片段的資
料復(fù)制到暫存器,然后把他們?cè)俅螌懟氐叫碌牡胤健T谶@個(gè)時(shí)間中,CPU 對(duì)于其他的工作來(lái)說(shuō)就無(wú)法使用。DMA傳輸方式無(wú)需CPU直接控制傳輸,也沒(méi)有中斷處理方式那樣保留現(xiàn)場(chǎng)和恢復(fù)現(xiàn)場(chǎng)的過(guò)程,通過(guò)硬件為RAM與I/O設(shè)備開(kāi)辟一條直接傳送數(shù)據(jù)的通路,使CPU的效率大為提高。
********************
typedef struct {
  uint8 srcAddrH;
  uint8 srcAddrL;
  uint8 dstAddrH;
  uint8 dstAddrL;
  uint8 xferLenV;
  uint8 xferLenL;
  uint8 ctrlA;
  uint8 ctrlB;
} halDMADesc_t; //DMA描述符結(jié)構(gòu)體

每一個(gè)通道都有相應(yīng)的描述符.DMA傳送首先要進(jìn)行DMA參數(shù)配置,需要配置以下參數(shù):
(1)源地址:DMA信道要讀的數(shù)據(jù)的首地址
(2)目標(biāo)地址:DMA信道從源地址讀出的要寫數(shù)據(jù)的首地址.目標(biāo)地址要可寫
(3)傳送長(zhǎng)度
(4)可變長(zhǎng)度(VLEN)設(shè)置
(5)優(yōu)先級(jí)別
(6)觸發(fā)事件
(7)源地址和目標(biāo)地址增量
(8)DMA傳送模式
(9)字節(jié)傳送或字傳送
(10)中斷屏蔽
(11)設(shè)置M8模式

CC2430中DMA有5條通道,UART默認(rèn)的是哪個(gè)通道呢?
********************
HalUARTInit()中初始化為:
  // Setup Tx by DMA.
  ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_TX );
  // Setup Rx by DMA.
 
ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_RX );

#define HAL_DMA_GET_DESC1234( a )     (dmaCh1234+((a)-1))

// Used by DMA macros to shift 1 to create a mask for DMA registers.
#define HAL_DMA_CH_TX    3  //協(xié)議棧默認(rèn)的用于UART發(fā)送的DMA通道 映射后為DMA通道2
#define HAL_DMA_CH_RX    4  //協(xié)議棧默認(rèn)的用于UART接收的DMA通道 映射后為DMA通道3

********************
對(duì)這兩條分別用于發(fā)送與接收的DMA通道的配置是如何的?
********************
在HalUARTInit()中初始化為:
#if HAL_UART_DMA

//---------------------配置發(fā)送為DMA模式;數(shù)據(jù)從內(nèi)存空間傳送到DMA_UDBUF???
  /*選擇DMA通道*/
  // Setup Tx by DMA.

  ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_TX );
//協(xié)議棧默認(rèn)的用于UART發(fā)送的DMA通道映射后為DMA通道2

  /*配置ch->dstAddrH/L*/
  // The start address of the destination.目的地的起始地址
  HAL_DMA_SET_DEST( ch, DMA_UDBUF ); //DMA_UDBUF為目的地,通過(guò)這個(gè)函數(shù)把DMA_UDBUF地址的高8位
                                                                         //賦給ch->dstAddrH,低8位賦給ch->dstAddrL
  /*配置ch->xferLenV*/
  // Using the length field to determine how many bytes to transfer.
  HAL_DMA_SET_VLEN( ch, HAL_DMA_VLEN_USE_LEN );
//HAL_DMA_VLEN_USE_LEN=0x00 //配置VLEN域使用LEN字段

 

  /*配置ch->ctrlA(通過(guò)多次配置ctrlA的每一位,同理包括ctrlB)*/
  // One byte is transferred each time. //初始化為一次傳輸一字節(jié)
  HAL_DMA_SET_WORD_SIZE( ch, HAL_DMA_WORDSIZE_BYTE );

 

  /*配置ch->ctrlA*/
  // The bytes are transferred 1-by-1 on Tx Complete trigger. //一次觸發(fā)只傳輸一個(gè)字節(jié),觸發(fā)源為UART0 TX完成
  HAL_DMA_SET_TRIG_MODE( ch, HAL_DMA_TMODE_SINGLE );
  HAL_DMA_SET_TRIG_SRC( ch, DMATRIG_TX );

 

  /*配置ch->ctrlB*/
  // The source address is decremented by 1 byte after each transfer.每次傳送后源地址減1
  HAL_DMA_SET_SRC_INC( ch, HAL_DMA_SRCINC_1 );

 

  /*配置ch->ctrlB*/
  // The destination address is constant - the Tx Data Buffer.目的地址不變,始終為Tx Data Buffer
  HAL_DMA_SET_DST_INC( ch, HAL_DMA_DSTINC_0 );

 

  /*配置ch->ctrlB*/
  // The DMA is to be polled and shall not issue an IRQ upon completion.傳送完成后不傳送中斷請(qǐng)求
  HAL_DMA_SET_IRQ( ch, HAL_DMA_IRQMASK_DISABLE );

 

  /*配置ch->ctrlB*/
  // Xfer all 8 bits of a byte xfer. 8位一字節(jié)
  HAL_DMA_SET_M8( ch, HAL_DMA_M8_USE_8_BITS );

 

  /*配置ch->ctrlB*/
  // DMA Tx has shared priority for memory access - every other one. 高優(yōu)先級(jí)
  HAL_DMA_SET_PRIORITY( ch, HAL_DMA_PRI_HIGH );


 
//---------------------配置接收為DMA模式:數(shù)據(jù)從DMA_UDBUF傳送到內(nèi)存空間???
  // Setup Rx by DMA.
  ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_RX );//

協(xié)議棧默認(rèn)的用于UART接收的DMA通道 映射后為DMA通道3

 

  // The start address of the source. 發(fā)源地起始地址
  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
   * known value. DMA word xfer will flip the bytes, so every valid Rx byte
   * in the Rx buffer will be preceded by a DMA_PAD char equal to the
   * Baud Cfg Register value.
   */
 
HAL_DMA_SET_WORD_SIZE( ch, HAL_DMA_WORDSIZE_WORD );

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

  // The source address is constant - the Rx Data Buffer.
  HAL_DMA_SET_SRC_INC( ch, HAL_DMA_SRCINC_0 );

  // The destination address is incremented by 1 word after each transfer.
  HAL_DMA_SET_DST_INC( ch, HAL_DMA_DSTINC_1 );

  // The DMA is to be polled and shall not issue an IRQ upon completion.
  HAL_DMA_SET_IRQ( ch, HAL_DMA_IRQMASK_DISABLE );

  // 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 );
#endif
********************
對(duì)于發(fā)送,觸發(fā)事件為HAL_DMA_TRIG_UTX1/0 :USART1/0 TX complete UART中數(shù)據(jù)發(fā)送完成就觸發(fā)DMA從內(nèi)存空間txbuf[ ]傳送數(shù)據(jù)到串口??
對(duì)于接收,觸發(fā)事件為HAL_DMA_TRIG_URX1/0:USART1/0 RX complete UART中數(shù)據(jù)接收完成就觸發(fā)DMA把數(shù)據(jù)從串口緩存?zhèn)魉偷絻?nèi)存空間rxbuf[ ]??
——我不敢確定!
事實(shí)上這一步所完成的任務(wù)和中斷服務(wù)程序完成的任務(wù)是一樣的,發(fā)送中斷服務(wù)函數(shù):把數(shù)據(jù)從txbuf[]傳送到串口UDBUF;接收中斷服務(wù)函數(shù):把數(shù)據(jù)從UDBUF傳送到rxbuf[ ];

UART接收數(shù)據(jù)DMA模式流程:(純屬個(gè)人理解,還有很多地方不清楚!協(xié)議中UART的兩種模式 - 小峰 - happy~)
(1)
ZMain.c調(diào)用HalDriverInit(),HalDriverInit調(diào)用HalDmaInit()初始化DMA通道01234的地址:

    halDMADesc_t dmaCh0;     
    halDMADesc_t dmaCh1234[4];
    HAL_DMA_SET_ADDR_DESC0( &dmaCh0 );
    HAL_DMA_SET_ADDR_DESC1234( dmaCh1234 );

(2)
HalUARTInit()函數(shù)中對(duì)通道2和3進(jìn)行配置.
(3)
系統(tǒng)主循環(huán)函數(shù)進(jìn)入HalUARTPoll()輪詢串口,大約每200ms調(diào)用一次 pollDMA()???,然后跳回HalUARTPoll()對(duì)rxbuf[]中的數(shù)據(jù)進(jìn)行處理——>調(diào)用回調(diào)函數(shù)SPIMgr_ProcessZToolData()分析rxbuf[]中每一字節(jié),構(gòu)造發(fā)往系統(tǒng)的消息——>調(diào)用osal_msg_send( MT_TaskID, (byte *)SPI_Msg )發(fā)送消息——>觸發(fā)MT任務(wù)事件,調(diào)用MT任務(wù)事件處理函數(shù) MT_ProcessEvent()——>調(diào)用MT_ProcessCommand(),根據(jù)msg->hdr.event——>調(diào)用MT_ProcessSerialCommand(),根據(jù)參數(shù)cmd來(lái)進(jìn)行最終處理.

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    日本一区二区三区久久娇喘| 开心激情网 激情五月天| 欧美熟妇一区二区在线| 国产av熟女一区二区三区蜜桃 | 高清在线精品一区二区| 少妇熟女精品一区二区三区| 不卡中文字幕在线免费看| 国产综合一区二区三区av| 国产一区二区三中文字幕| 精品国产品国语在线不卡| 日韩免费成人福利在线| 欧美亚洲另类久久久精品| 国产精品欧美一区二区三区不卡 | 欧美日韩综合综合久久久| 麻豆国产精品一区二区| 九七人妻一区二区三区| 久久中文字人妻熟女小妇| 欧美三级大黄片免费看| 国产小青蛙全集免费看| 中日韩免费一区二区三区| 黑鬼糟蹋少妇资源在线观看| 狠狠做五月深爱婷婷综合| 日本午夜一本久久久综合| 九九热精彩视频在线免费| 国产欧美日本在线播放| 在线欧美精品二区三区| 欧美精品在线播放一区二区| 黄片在线免费看日韩欧美| 国产精品免费不卡视频| 制服丝袜美腿美女一区二区| 亚洲高清中文字幕一区二三区 | 久久精品亚洲欧美日韩| 精品香蕉一区二区在线| 色无极东京热男人的天堂| 欧美视频在线观看一区| 天海翼高清二区三区在线| 亚洲专区中文字幕在线| 青青操日老女人的穴穴| 国产精品午夜福利免费阅读| 亚洲人午夜精品射精日韩 | 久一视频这里只有精品|