FireBLE

FireBLE 是一个面向于打造智能生活的开源平台,以BLE(Bluetooth Low Energy)技术为核心,拥有超低的功耗、不俗的处理能力和广泛的应用场合,专注于更智能、高效率的工作模式,让生活在科技中更安全、方便、快捷。也许您一个不经意的想法与FireBLE擦出的火花,会在这片原野上燎出火焰,甚至燃烧整个世界。

SPI 驱动

更新时间:2017-08-08 阅读:2935

前言

SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线。

  1. SDO – 主设备数据输出,从设备数据输入;
  2. SDI – 主设备数据输入,从设备数据输出;
  3. SCLK – 时钟信号,由主设备产生;
  4. CS – 从设备使能信号,由主设备控制

其中SDO/SDI/SCLK三根线实现了全双工的通信,虽然简单高效了很多,但是由于器件的寻址只有一个CS片选脚来指定,当连接多台SPI设备时,会显得比较麻烦。

SCLK提供时钟脉冲,SDI,SDO则基于此脉冲完成数据传输。数据输出通过 SDO线,数据在时钟上升沿/下降沿时改变,在紧接着的下降沿/上升沿被读取。完成一位数据传输,输入也使用同样原理。这样,在至少8次时钟的改变(上沿和下沿为一次),就可以完成8位数据的传输。

初始化

一般裸驱开发过程为系统初始化-->GPIO配置-->各驱动模块初始化-->主循环实现功能。第一步系统初始化是每一个例程所必须的,初始化的过程也是相同的,所以只需调用系统初始化接口即可。

下面的三个部分都是需要我们根据自己的需求自行实现,在上一小节我们已经学习了如何配置GPIO,接下来就是各个模块的初始化。本例程只介绍SPI的初始化。

初始化函数

SPI初始化的函数原型为:

void spi_init(QN_SPI_TypeDef * SPI, uint32_t bitrate, enum SPI_BUFFER_WIDTH width, enum SPI_MODE mode)

传入参数:

  1. SPI通道
  2. SPI波特率
  3. SPI传输数据宽度
  4. SPI工作模式

初始化示例

spi_init(QN_SPI1, SPI_BITRATE(200000), SPI_8BIT, SPI_MASTER_MOD);

SPI通道

QN9021中只含有SPI1通道,所以第一个参数必须为QN_SPI1。

SPI波特率

SPI 波特率范围在 62500~4000000 之间。在宏定义中可看到波特率设定的方法。

/// SPI bit rate algorithm
#define SPI_BITRATE(x)                  ((__USART_CLK/(2*(x)) - 1) << SPI_POS_CLK_DIV_MASTER)

宏定义中,x 影响到的是 SPI_POS_CLK_DIV_MASTER 的值,根据名称,这个值应该是一个分频系数.

追踪 SPI_POS_CLK_DIV_MASTER ,发现 SPI_POS_CLK_DIV_MASTER 的宏定义为16。

#define SPI_POS_CLK_DIV_MASTER                      16

很明显 (__USART_CLK/(2*(x)) - 1) 这个值应该是要写入某个寄存器,在寻址相关寄存器的掩码中发现如下介绍。

/* SPI REGISTER MASK */
// CR0
#define SPI_MASK_BITRATE                    0x003F0000   /* 21 - 16 */

原来寄存器的16位到21位存放的就是分频系数。在回到之前的宏定义,假设 __USART_CLK/(2*(x)) - 1 = div ,那么可发现其实就是对 __USART_CLK 的 2*(div+1)倍分频。 div 去取值范围为 0~63 ,查得 __USART_CLK 为 8MHz 的频率,故波特率取值为 62.5KHz~4Mhz , x 的单位为 Hz 。

#define CLK_8M                    (8000000UL)         /*!< Clock is 8MHz */
#define __USART_CLK                                     CLK_8M           /*!< UART and SPI clock frequency */

SPI读写

接下来程序初始化了rxbuffer,作为数据收发缓存使用。

for (j = 0; j < 40; j++) {
    rxbuffer[j] = 0;
    buffer[j] = j;
}

设置写入标志位,然后向SPI总线上写入buffer数组中的前4个字节数据,完成写入后清除标志位。

//Write 4byte data
    tx_flag = 1;
//    spi_write(QN_SPI0, buffer, 4, led_blink_right);
    spi_write(QN_SPI1, buffer, 4, led_blink_right);
    while(tx_flag);

设置读取标志位,从SPI总线上读取4个字节然后存入rxbuffer数组中,完成后清除标志位。

//Read 4byte data
    rx_flag = 1;
//    spi_read(QN_SPI0,  rxbuffer, 4, led_blink_left);
    spi_read(QN_SPI1,  rxbuffer, 4, led_blink_left);
    while(rx_flag);