DSP28335的硬件SPI使用(无FIFO)总结


前言

这两天折腾了一个旋变器解算模块的使用,类似于这种器件一般都是使用通信的方式写入芯片对应的寄存器的数据从而初始化芯片或得到可编程的结果;反之,我们也需要读取其模块、芯片内部经过解算得到的存储内容在SPI的SCLK引导下传输到DSP的硬件SPI内的接收寄存器中。

问题的提出

对于硬件SPI的使用从成功启动的角度来看并不麻烦,麻烦的是以下几点:

  1. 如何在接收到自己想到的数据之后就停止接收,并进行相关处理;
  2. 如何写入自己想要的长度的数据,例如寄存器是八位的地址,但我一次性只能写入16位的,可以达到自己想要的目的吗?
  3. 是否需要使用接收中断或者发送中断,该如何使用?

问题的解决

对于这三个问题,我在这次的小项目实践中都有了一定程度的理解。首先讲一下这个项目对于SPI的写入读取要求:写入需要一个八位地址和一个八位数据,首先写入一个地址,至少间隔几微秒后可以写入该地址对应寄存器的数据,达到可编程的目的。写入的时候需要在SCLK的上升沿写入;读取的时候读取到的数据一共有24位,可以分成3个8位读取,另外读取的时候需要在下降沿读取。
实质上28335的SPI功能与其他处理器类似,但有点不同的就是它有个FIFO操作。这里不得不提的就是,FIFO功能实质上是对标注年SPI模式的覆盖,FIFO的功能里包括了SPI的功能,但相反的,你使用了FIFO的功能后SPI的一些功能就会被限制或者是无效。FIFO的优势就是它具有发送和接收缓冲器,一个缓冲器最多可以放16个字。其FIFO功能的状态位,比如TXFFINT、RXFFOVFCLR等都是针对它的发送和接收缓冲器所设定的,这就形成了一个问题,比如我想接收一个字节后或者发送一个字节后,发送和接收功能就暂停,这在FIFO模式下是无法做到的,因为FIFO的缓冲器最少最少是一个字,即16位。那么针对我们这个小项目的功能他就显然不满足了。因为我的项目中在发送一个地址的字节后需要等待几微秒,再发送一个数据字节,但是FIFO的发送缓冲器最少的存储大小为一个字,所以FIFO会等待发送缓冲器里放入了地址和数据两个字节后开始连续发送,这就会造成从机无法识别的后果。所以在经过考虑之后,我选择使用DSP28335的标准SPI功能。
在进行SPI初始化的过程中,最主要的就是SPICCR(进行软件复位和移位时钟极性选择)和SPICTL(控制数据发送、中断产生、SCLK相位、以及主从模式)两个寄存器的初始化,另外还需要进行初始化的寄存器就是SPIBBR,这个寄存器就是一个波特率选择的寄存器,使用上并没有问题。值得一提的是SPICCR的低四位的功能非常重要,称为字符长度控制位,这四位就决定了在标准SPI模式下,一次性发送和接收数据的位数,这里我选择的就是8位,这样每次我写入一个8位数据后就会自动发送给从机,然后SPI的时钟线就会置高暂停发送。
在初始化之后,我们要进行的就是SPI数据什么时候发送完,以及什么时候接收完,因为只有完成了发送和接收,CPU才能做其他的事情,否则时钟线就会被迫暂停,因为数据还没发完,CPU就去做其他事情了。所以在选择好了字符长度控制位为8位后,我还需要等它发送完,SPI的时钟线才能正常置高。这里就需要用到另一个寄存器,也就是SPISTS,该寄存器是一个状态寄存器,其中的第6位标志位,也就是SPI INT FLAG,就可以用来完成我们刚所需要的操作,这是一个只读标志位,别看它叫中断标志位,但它跟我们所理解的中断并不是一回事,无论是否开启SPI中断,它在已完成发送最后一位和接受最后一位的操作后都会硬件置1,除了一种情况,就是你开启了FIFO模式后,该标志位就不会变化了。清除这个标志位的操作,手册上都有,我就不说了。另外需要指出的一点是,该标志位在发送或者接收最后一位刚刚开始就会置1,如果你马上干其他事儿,那么在SCLK的最后一个脉冲就会被削成尖波,那样的话,最后一位数据可能会发送或者接收失败。所以一般在后面加一个延时操作,具体发送的代码示例如下:

    SpiaRegs.SPITXBUF=a;
    while(!SpiaRegs.SPISTS.SPI INT FLAG){}
    Delay_US(8);

那么我们有没有必要开启SPI的中断来发送和读取数据呢?我的回答是没有的,至少对于这个项目是没有的。如果开启了中断,那么我们在发送一个数据或者接收一个数据之后都会进入一次中断,实质上对于CPU的损耗是很大的,并且将接收到的数据的处理放在程序串行结构之中也没有过多的影响,整体结构清晰美观,不会产生过多的跳跃阅读的情况。

说在最后

对于这个项目,其实使用模拟SPI更加方便,直接用IO口模拟SCLK的时序,在上升沿的时候将输出引脚的状态改变以模拟数据发送,在下降沿的时候读取输入引脚的高低电平状态以模拟数据输入。只不过发送和接收的时候速度慢一些,但对于这个项目来说,传送的数据并不多,且都是8位的,足够了!

dsp28335是一款数字信号处理器,它具有硬SPI(串行外设接口)功能,可以用于与其他设备进行通信。SPI是一种同步串行通信协议,它使用四根线(SCLK、MISO、MOSI、SS)来实现设备之间的数据传输。 以下是使用dsp28335硬件SPI进行通信的步骤[^2]: 1. 配置SPI控制寄存器:设置SPI的工作模式、数据位长度、时钟极性和相位等参数。 2. 配置GPIO引脚:将SPI的引脚与dsp28335的GPIO引脚相连。 3. 启用SPI:使能SPI模块。 4. 发送数据:将要发送的数据写入SPI发送缓冲区。 5. 等待传输完成:等待SPI传输完成。 6. 接收数据:从SPI接收缓冲区读取接收到的数据。 下面是一个使用dsp28335硬件SPI发送和接收数据的示例代码: ```c #include "DSP2833x_Device.h" #include "DSP2833x_Examples.h" void InitSPI(void) { // 配置SPI控制寄存器 SpiaRegs.SPICCR.bit.SPISWRESET = 0; // 关闭SPI模块 SpiaRegs.SPICCR.bit.CLKPOLARITY = 0; // 时钟极性为低电平 SpiaRegs.SPICCR.bit.SPICHAR = 7; // 数据位长度为8位 SpiaRegs.SPICTL.bit.MASTER_SLAVE = 1; // 主模式 SpiaRegs.SPICTL.bit.TALK = 1; // 允许发送和接收数据 SpiaRegs.SPICTL.bit.CLK_PHASE = 0; // 时钟相位为第一个边沿 SpiaRegs.SPICTL.bit.OVERRUNINTENA = 0; // 禁止溢出中断 SpiaRegs.SPICTL.bit.SPIINTENA = 0; // 禁止SPI中断 SpiaRegs.SPIBRR.bit.SPI_BIT_RATE = 255; // 设置SPI时钟频率 // 配置GPIO引脚 GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 3; // 将GPIO18配置SPI的SIMO引脚 GpioCtrlRegs.GPAMUX2.bit.GPIO19 = 3; // 将GPIO19配置SPI的SOMI引脚 GpioCtrlRegs.GPAMUX2.bit.GPIO20 = 3; // 将GPIO20配置SPI的CLK引脚 GpioCtrlRegs.GPAMUX2.bit.GPIO21 = 3; // 将GPIO配置SPI的STE引脚 // 启用SPI SpiaRegs.SPICCR.bit.SPISWRESET = 1; // 打开SPI模块 } void SendAndReceiveSPI(void) { Uint16 sendData = 0xABCD; Uint16 receiveData; // 发送 SpiaRegs.SPITXBUF = sendData; // 等待传输完成 while (SpiaRegs.SPISTS.bit_FLAG != 1); // 接收数据 receiveData = SpiaRegs.SPIRXBUF; } ```
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LEODWL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值