精读OSAL --SPI方式串行通信(_hal_uart_spi.c)

来源:互联网 发布:nba2k online球星数据 编辑:程序博客网 时间:2024/05/22 12:13

SPI种方式是可以在DMA的方式上同时共享缓冲区,来节省内存.

spiRxBuf = dmaCfg.rxBuf;

piRxDat = dmaCfg.txBuf;

 spiTxPkt[SPI_MAX_PKT_LEN]

spiRxDat = dmaCfg.txBuf[0];//这个最难懂,其实就当是缓冲区就好子.解包后的数据放在这,让读函数来读.
spiTxPkt = dmaCfg.txBuf[1];

 

一帧的结构:

SOF     //开始标志,EF

LEN     //长度

DATA     //数据,长度是上面LEN定义

FCS       //检验字

rxBuf 是接收正个帧,解出数据放RxDat中.

 

读函数很简单,就是从RxDat中读多少数据,这时砂说了.

写函数有两种实现方法,一种是有发送队列,另一种是无发送队列.

先按帧要求填数据.

无发送队列就是配置好DMA通道,然后ARM就行了.

而有发送队列,看注释:

/************************************************************************************************** * @fn          HalUARTWriteSPI * * @brief       Transmit data bytes as a SPI packet. * * input parameters * * @param       buf - pointer to the memory of the data bytes to send. * @param       len - the length of the data bytes to send. * * output parameters * * None. * * @return      Zero for any error; otherwise, 'len'. */static spiLen_t HalUARTWriteSPI(uint8 *buf, spiLen_t len){  if (spiTxLen != 0)//spiTxLen在这是标志是否有数据正在DMA中发送,它在完成中断里清零.#if HAL_SPI_QUEUED_TX    uint8 *txMsg = osal_msg_allocate(len);    if (txMsg != NULL)    {      (void)memcpy(txMsg, buf, len);      osal_msg_enqueue(&spiTxQ, txMsg);      return len;    }#endifreturn 0;  }//之后就打包数据ARM就行了.  if (len > SPI_MAX_DAT_LEN)  {    len = SPI_MAX_DAT_LEN;  }  spiTxLen = len;#if HAL_SPI_QUEUED_TX  spiTxMT = FALSE;#endif  spiTxPkt[SPI_LEN_IDX] = len;  (void)memcpy(spiTxPkt + SPI_DAT_IDX, buf, len);  spiCalcFcs(spiTxPkt);  spiTxPkt[SPI_SOF_IDX] = SPI_SOF;  halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_SPI_CH_TX);  HAL_DMA_SET_LEN(ch, SPI_PKT_LEN(spiTxPkt));#if defined HAL_SPI_MASTER#if HAL_SPI_WAKEUP  /* A Full-Duplex Slave will keep SRDY active low if it has Tx ready; otherwise it will toggle its   * SRDY with every falling edge of MRDY. So if SRDY is high and the wait after writing each byte   * is not long enough, the master may loop here, infinitely out of sync with the toggling SRDY.   * Thus in a threaded OS, it would be advisable to send one zero and yield for 1-msec or more, or   * be able to receive and check here for the SRDY ISR.   */  spiRdyIsr = 0;  while (!SPI_RDY_IN() && (spiRdyIsr == 0))  {    SPI_CLOCK_RX(1);    for (uint16 cnt = 0; cnt < 512; cnt++)    {      if (SPI_RDY_IN() || (spiRdyIsr != 0))      {        break;      }    }  }#endif  SPI_SET_CSn_OUT();  HAL_DMA_ARM_CH(HAL_SPI_CH_TX);  asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");  asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");  HAL_DMA_MAN_TRIGGER(HAL_SPI_CH_TX);#elif !defined HAL_SPI_MASTER  HAL_DMA_ARM_CH(HAL_SPI_CH_TX);  asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");  asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");  SPI_SET_RDY_OUT();#endif  return len;}
/************************************************************************************************** * @fn          HalUART_DMAIsrSPI * * @brief       Handle the Tx done DMA ISR. * * input parameters * * None. * * output parameters * * None. * * @return      None. */void HalUART_DMAIsrSPI(void){#if !defined HAL_SPI_MASTER  if (!SPI_RDY_IN())#endif  {    SPI_CLR_RDY_OUT();  }  spiTxLen = 0;//这里清零了,注意.!! 这后就判断是否还有队列要发送,再调用写函数.#if HAL_SPI_QUEUED_TX  if (spiTxQ != NULL)  {    uint8 *txMsg = osal_msg_dequeue(&spiTxQ);    (void)HalUARTWriteSPI(txMsg, OSAL_MSG_LEN(txMsg));    (void)osal_msg_deallocate(txMsg);  }  else  {    spiTxMT = TRUE;  }#else  spiCB((HAL_UART_SPI - 1), HAL_UART_TX_EMPTY);#endif}


接收都在POLL里处理,主要调用了static void spiParseRx(void);

spiRxBug 是用来扫描整个缓冲区. spiRxIdx是用来指明帧数据解释到哪里.

/************************************************************************************************** * @fn          spiParseRx * * @brief       Parse all available bytes from the spiRxBuf[]; parse Rx data into the spiRxDat[]. * * input parameters * * None. * * output parameters * * None. * * @return      None. */static void spiParseRx(void){  while (1)  {    if (!SPI_NEW_RX_BYTE(spiRxIdx))//spiRxIdx指向的数据是旧数据则,循环扫描spiRxBug.#if defined HAL_SPI_MASTER      if (SPI_RDY_IN() && (spiTxLen == 0))      {        SPI_CLOCK_RX(1);        continue;      }#endif      if (SPI_NEW_RX_BYTE(spiRxBug))//如果找到数据       {        while (!SPI_NEW_RX_BYTE(spiRxIdx))        {          SPI_LEN_T_INCR(spiRxIdx);        }        spiRxBug = spiRxIdx;        continue;      }      SPI_LEN_T_INCR(spiRxBug);//如果空则一直循环       break;    }//这里开始解帧: uint8 ch = SPI_GET_RX_BYTE(spiRxIdx);    SPI_CLR_RX_BYTE(spiRxIdx);    SPI_LEN_T_INCR(spiRxIdx);    switch (spiRxSte)    {    case spiRxSteSOF:      if (ch == SPI_SOF)      {        spiRxSte = spiRxSteLen;        // At this point, the master has effected the protocol for ensuring that the SPI slave is        // awake, so set the spiRxLen to non-zero to prevent the slave from re-entering sleep until        // the entire packet is received - even if the master interrupts the sending of the packet        // by de-asserting/re-asserting MRDY one or more times.        spiRxLen = 1;      }      break;    case spiRxSteLen:      if ((ch == 0) || (ch > SPI_MAX_DAT_LEN))      {        spiRxSte = spiRxSteSOF;        spiRxLen = 0;      }      else      {        spiRxFcs = spiRxLen = ch;        spiRxTemp = spiRxTail;        spiRxCnt = 0;        spiRxSte = spiRxSteData;#if defined HAL_SPI_MASTER        SPI_CLOCK_RX(ch + 1);  // Clock out the SPI Frame Data bytes and FCS.#endif      }      break;    case spiRxSteData:      spiRxFcs ^= ch;      spiRxDat[spiRxTemp] = ch;      SPI_LEN_T_INCR(spiRxTemp);      if (++spiRxCnt == spiRxLen)      {        spiRxSte = spiRxSteFcs;      }      break;    case spiRxSteFcs:      spiRxSte = spiRxSteSOF;      if (ch == spiRxFcs)      {        spiRxTail = spiRxTemp;      }      spiRxCnt = spiRxLen = 0;      break;    default:      HAL_ASSERT(0);      break;    }  }}


 


 

原创粉丝点击