1 实现 ADS 1256 采集芯片在 RT-Thread 上的应用 2 了解 SPI 挂载的方式
在中断 ISR 中调用 SPI 发送数据相关函数,导致 assertion 报错。Function[rt_mutex_take] shall not be used in ISR,assertion failed at function:rt_mutex_take, line number:656 RT-Thread SPI 和 I2C 数据收发相关函数会调用 rt_mutex_take(),此函数不能再中断函数中使用
官方外设精品文章链接
SPI:
1 串行外设接口总线(SPI)最早由Motorola首先提出的全双工三线同步串行外围接口(SCK, MISO 主入从出, MOSI 主出从入) 2 采用 主从模式 支持一对多 3 通过 CS 片选脚来确定工作对象(大多是 CS 片选脚都是拉低有效,在RTOS 中如果是拉高有效需要另外设置)
设置 SPI 参数(需要查看器件数据手册确定)
1 时钟速率 2 数据数据格式 (MSB 高位在前) / (LSB 低位在前) 3 时钟极性 CPOL 和 时钟相位 CPHA(CubeMX 中的 1边沿 / 2边沿就是对应数字 0 / 1
参考 SPI 参考原网址 CPOL=0,CPHA=0:此时空闲态时,SCLK处于低电平,数据采样是在第1个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在上升沿,数据发送是在下降沿。 CPOL=0,CPHA=1:此时空闲态时,SCLK处于低电平,数据发送是在第1个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在下降沿,数据发送是在上升沿。 CPOL=1,CPHA=0:此时空闲态时,SCLK处于高电平,数据采集是在第1个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采集是在下降沿,数据发送是在上升沿。 CPOL=1,CPHA=1:此时空闲态时,SCLK处于高电平,数据发送是在第1个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采集是在上升沿,数据发送是在下降沿
1 挂载 SPI (默认在 SPI 总线会自动注册, 只需在 env 中集合 STM32CubeMX 配置即可 2 自定义消息 3 使用官方封住好的接口 4 总线使用和片选设定 5 配置
非 STM32 使用 rt_spi_bus_attach_device() 需求启动总线但是没有具体实验不再深入说明 STM32 使用 rt_hw_spi_device_attach()
__HAL_RCC_GPIOB_CLK_ENABLE(); //对应 GPIOB rt_hw_spi_device_attach("spi1", "spi10", GPIOB, GPIO_PIN_14); // GPIOB 和 GPIO_PIN_14 是用来说明 CS 所在 IO 引脚 B14 脚 //特别说明 GPIO_PIN_14 与 PIN 中引脚使用方式略微不同的 //GPIO_PIN_0 ~ GPIO_PIN_15 //假设现在 CS =》 PA4 ----> GPIOA, GPIO_PIN_4 即可 //"spi1" 总线名词 //"spi10" 是指 spi1 下的第一个设备,具体请查看官方文档 //"spi11" 是指 spi1 下的第二个设备关键点: 1 第一个消息块必须使能(cs_take = 1) CS脚 和 最后一个消息块必须释放(cs_release = 1) CS 脚 2 8bit视为 1 个字节, 16bit 视为 2 个字节 3 假设有 5 个 8bit 数据接收, length = 5 4 不在一个消息块上同时收发,发和收需要分成 2 个或者使用 官方包装好的(官方自动会在使用前后使能和释放)
struct rt_spi_message msg1, msg2, msg3; msg1.send_buf = &w25x_read_id; msg1.recv_buf = RT_NULL; msg1.length = 1; msg1.cs_take = 1; msg1.cs_release = 0; msg1.next = &msg2; msg2.send_buf = &w25x_xxx; msg2.recv_buf = RT_NULL; msg2.length = 1; msg2.cs_take = 0; msg2.cs_release = 0; msg2.next = RT_NULL; msg3.send_buf = RT_NULL; msg3.recv_buf = id; msg3.length = 5; msg3.cs_take = 0; msg3.cs_release = 1; msg3.next = RT_NULL; rt_spi_transfer_message(spi_dev_w25q, &msg1);只说明一个 rt_spi_send_then_recv 其特点就是 也是利用 上面的消息块分装的,但是使用前后会 自动使能和释放片选
1 避免被不同线程打断 SPI 传输需要,先对 SPI 获取使用权 rt_spi_take_bus() / 使用完成之后释放 rt_spi_release_bus() 2 不同从设备使用同一 SPI 需要指定对应片选引脚有效 rt_spi_take() / 使用完成之后释放 rt_spi_release() 3 新增信息内容 rt_spi_transfer_message()
特别说明:
1 具体 SPI 频率是根据自动选取 系统时钟 / 分频 满足要求的一个 (stm32f407 假设 1.92 最大 84M / 64 = 1.3125 M/s 这将是设定的实际频率)