【WCH蓝牙系列芯片】-基于CH582开发板—SPI发送数据,每个字节间延时大的问题

-------------------------------------------------------------------------------------------------------------------------------------

在使用SPI接口发送数据时,当SPI主机使用过程中,连续发送多个数据时,会发现每个数据之间会产生一个时钟的间隙。两帧数据之间时间间隔都是几乎不变的,这样有时导致SPI接口收发数据产生时序错误,导致SPI通信失败。
因此,针对这个问题,这里采用沁恒微电子的CH582芯片,利用CH582的EVT中SPI例程对这个问题进行说明和优化。
一、在例程中,先写一个通过 SPI 接口发送 16 位数据的函数。发送单个数据是采取SPI0_MasterSendByte库函数进行编写。

void spi_write_test(uint16_t data)
{
    GPIOA_ResetBits(GPIO_Pin_12);  //片选信号拉低

    SPI0_MasterSendByte(data>>8);  //向 SPI0 接口发送数据的高字节。使用 >> 操作符将数据右移 8 位,以获取高 8 位数据。
    SPI0_MasterSendByte(data>>0);  //向 SPI0 接口发送数据的低字节。使用 >> 操作符将数据右移 0 位,以获取低 8 位数据。

    GPIOA_SetBits(GPIO_Pin_12);  //片选信号拉高
}

首先,将片选信号置低以选中 SPI 设备,然后依次发送数据的高和低字节,最后将片选信号置高以结束SPI。

二、然后再写一个通过 SPI 接口发送 16 位数据的函数,是使用FIFO连续发送多字节的思路进行编写。

 

void spi_write_test2(uint16_t data)//通过 FIFO方式 的SPI接口发送 16 位数据
{
    GPIOA_ResetBits(GPIO_Pin_12);     //片选信号拉低

    R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;   // 设置数据方向为输出

    while(!(R8_SPI0_INT_FLAG & RB_SPI_FREE));  // 等待FIFO中的数据全部发送完成
    R16_SPI0_TOTAL_CNT = 2;    //设置 SPI0 的数据传输总字节数为 2,表示需要发送 2 个字节。
    R8_SPI0_FIFO = data>>8;   //将数据的高字节写入 SPI0 的 FIFO 寄存器
    R8_SPI0_FIFO = data>>0;   //将数据的低字节写入 SPI0 的 FIFO 寄存器
    while(!(R8_SPI0_INT_FLAG & RB_SPI_FREE));   // 等待FIFO中的数据全部发送完成

    GPIOA_SetBits(GPIO_Pin_12);   //片选信号拉高
}

 

与前面的函数相比,使用了FIFO连续发送多字节底层寄存器的方式进行操作,而不是直接调用库函数。其中包括了通过控制寄存器、FIFO 寄存器和中断标志寄存器来进行 SPI 数据发送和等待的操作。
  1. 先是将片选信号置低以选中 SPI 设备;
  2. 然后设置数据方向为输出,即主设备向从设备发送数据;
  3. 之后先判断FIFO中的数据是否全部发送完成;
  4. 设置 SPI0 的数据传输总字节数为 2,表示需要发送 2 个字节
  5. 将数据的高字节写入 SPI0 的 FIFO 寄存器
  6. 将数据的低字节写入 SPI0 的 FIFO 寄存器
  7. 再次判断FIFO中的数据是否全部发送完成
  8. 最后片选信号置高以结束SPI

将这个两个程序放在while中一直运行,一直发送数据,发送数据0X1234。

    while(1)
    {
        spi_write_test(0x1234);
        DelayUs(100);
        spi_write_test2(0x1234);
        DelayMs(1);
    }

 

通过逻辑分析仪进行数据SPI采集,
    如图1,是采用SPI0_MasterSendByte库函数进行编写的SPI发送数据,可以很明显的看出两个数据之间的存在一定的时间间隔,大约在2.4225uS左右。

    如图2,是采用FIFO连续发送多个字节底层寄存器的方式,进行编写的SPI发送数据。

发现这样的方式发送数据,每个数据之间虽然还是存在一个时间间隔,但是只有97.5nS的时间间隔,相较于前一种SPI发送数据的方式,每个数据之间的延时就不会很长,不太影响数据发送的过程。

 

三、在此基础上,将上述两个函数都在放在RAM中进行运行。采用__HIGH_CODE的方式,只针对__HIGH_CODE下面定义的一个函数,这样函数是放在RAM中工作,运行速度会快一些。
__HIGH_CODE修饰下的速度和主频一致,普通位置的是在flash中运行,运行速度在20MHz左右。

#include "CH58x_common.h"

void DebugInit(void)
{
    GPIOA_SetBits(GPIO_Pin_9);
    GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);
    GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA);
    UART1_DefInit();
}

//通过 SPI 接口发送 16 位数据
__HIGH_CODE
void spi_write_test(uint16_t data)
{
    GPIOA_ResetBits(GPIO_Pin_12);  //片选信号拉低

    SPI0_MasterSendByte(data>>8);  //向 SPI0 接口发送数据的高字节。使用 >> 操作符将数据右移 8 位,以获取高 8 位数据。
    SPI0_MasterSendByte(data>>0);  //向 SPI0 接口发送数据的低字节。使用 >> 操作符将数据右移 0 位,以获取低 8 位数据。

    GPIOA_SetBits(GPIO_Pin_12);  //片选信号拉高
}


__HIGH_CODE
void spi_write_test2(uint16_t data)//通过 FIFO方式 的SPI接口发送 16 位数据
{
    GPIOA_ResetBits(GPIO_Pin_12);     //片选信号拉低

    R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;   // 设置数据方向为输出
    while(!(R8_SPI0_INT_FLAG & RB_SPI_FREE));  // 等待FIFO中的数据全部发送完成
    R16_SPI0_TOTAL_CNT = 2;    //设置 SPI0 的数据传输总字节数为 2,表示需要发送 2 个字节。
    R8_SPI0_FIFO = data>>8;   //将数据的高字节写入 SPI0 的 FIFO 寄存器
    R8_SPI0_FIFO = data>>0;   //将数据的低字节写入 SPI0 的 FIFO 寄存器
    while(!(R8_SPI0_INT_FLAG & RB_SPI_FREE));   // 等待FIFO中的数据全部发送完成

    GPIOA_SetBits(GPIO_Pin_12);   //片选信号拉高
}

int main()
{
    SetSysClock(CLK_SOURCE_PLL_40MHz);
    /* 配置串口调试 */
    DebugInit();
    PRINT("Start @ChipID=%02X\n", R8_CHIP_ID);
/* 主机模式 *//* SPI 0 */ GPIOA_SetBits(GPIO_Pin_12); GPIOA_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14, GPIO_ModeOut_PP_5mA); SPI0_MasterDefInit(); while(1) { spi_write_test(0x1234); DelayUs(100); spi_write_test2(0x1234); DelayMs(1); }

通过逻辑分析仪采集SPI数据,观察一下。
    如图3,采用SPI0_MasterSendByte库函数的方式,发现两个数据的时间间隔明显减少,

只有1.9975uS.相比于之前没有加__HIGH_CODE之前,有一定的改善。

    如图4,采用FIFO连续发送多个字节底层寄存器的方式,发现两个数据的时间间隔只有95nS.也有一定的改善。

    所以经过测试,当使用SPI发送数据时候,最好还是采用FIFO连续发送多个字节加上__HIGH_CODE,放在RAM中进行运行,这样能让发送的每个数据之间的时间间隔不至于过大,延时过长,导致在使用SPI发送数据过程中出现错误。

posted on 2023-11-09 16:33  凡仕  阅读(562)  评论(0编辑  收藏  举报