精读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; } }}
- 精读OSAL --SPI方式串行通信(_hal_uart_spi.c)
- 精读OSAL --中断方式串行通信(_hal_uart_isr.c)
- 精读OSAL --DMA方式串行通信(_hal_uart_dma.c)
- 精读OSAL --我的SPI驱动
- 精读OSAL --时钟及休眠(hal_sleep.c)
- 精读OSAL --我的SPI驱动的失败
- STC89C52MCU--串行通信接口SPI
- 精读OSAL --按键的执行流程(hal_key.c onboard.c)
- 串行通信入门:uart、i2c、spi
- SPI通信方式总结
- 并行串行通信方式图解
- 串行通信程序(C#)
- 精读OSAL --回调函数的理解
- 常用串行通信对比(SPI、I2C、UART)
- 串行通信接口RS-232C
- DWM1000DISCOVERY SPI通信方式的选择
- I2C、SPI、USRT、USRAT通信方式对比
- I2C、SPI、USRT、USRAT通信方式对比
- 虚拟机Ubuntu 12.04 LTS上搭建DHCP服务器流程
- Oracle跟踪文件
- 数据结构实验 单链表
- API读取写入 ini文件内容的方法函数详解
- poj 1961 Period
- 精读OSAL --SPI方式串行通信(_hal_uart_spi.c)
- SSH集成出现空指针,很简单的代码,求助!
- C# Flowplayer(视频播放器)如何操作,使视频的时间进度不可操作
- hdu 2209 翻纸牌游戏 (状态bfs解)
- vmware环境下在linux中创建dns服务器
- error while loading shared libraries: libcudart.so.3: wrong ELF class: ELFCLASS32 的解决
- 主机端USB编程注意事项
- datagridview 手动添加列和行
- vmware环境下在linux中创建ftp服务器