最近在学习M61使用时候,没有找到SPI多机通讯相关的小白教程,刚好需要用到就和大家分享以下吧
前提
- 不知道什么是spi参考timo这篇帖子嵌入式通信协议-SPI
- 查手册发现M61SU 只有一个SPI ,可自由配置为主模式或者从模式。
目标
- 实现stm32与M61通过spi 实现双机/多机(一主多从)通信
- STM32(从机) 实时进行adc采集,通过spi发送给M61(主机)
这里没有给出adc 实时采集代码,说一下原理,利用DMA设置双缓冲区,当ADC采集满一个缓冲区,切换到另一个缓冲区存放数据,此时CPU处于空闲,来进行SPI的数据发送。
代码及说明
- 导入相关库
#include "bflb_mtimer.h"
#include "board.h"
#include "bflb_spi.h"
#include "bflb_gpio.h"
- 定义收发缓冲区
uint16_t tx_buff[3] = {0};
uint16_t rx_buff[3] = {0}; //数据宽度自定义我用到无符号16位了
- 声明初始化
struct bflb_device_s *spi0;//声明结构体指针spi0
struct bflb_device_s *gpio; //声明结构体指针gpio
int main(void){
board_init(); //开发板初始化
board_spi0_gpio_init(); //spi0默认的gpio初始化
// io12 -- cs
// io13 -- clk
// io18 -- miso
// io19 -- mosi
struct bflb_spi_config_s spi_cfg ={
.freq = 100000,
.role =SPI_ROLE_MASTER, // m61作为主机模式
.mode = SPI_MODE3, // 模式3 相位和极性都为1
.data_width = SPI_DATA_WIDTH_16BIT, //数据宽度我用16位
.bit_order = SPI_BIT_MSB, // 位顺序
.byte_order = SPI_BYTE_MSB, // 字节序
.tx_fifo_threshold = 0,
.rx_fifo_threshold = 0,
};
spi0 = bflb_device_get_by_name("spi0");
bflb_spi_init(spi0,&spi_cfg); // 初始化spi0
//bflb_spi_feature_control(spi0,SPI_CMD_SET_DATA_WIDTH,SPI_DATA_WIDTH_16BIT);
// 下面这些都都可以不要,说明一下还要初始化gpio干嘛,由于我不知道STM32在DMA采集切换有空闲时间,所以让stm32选一个gpio作为标志位,通知M61可以进行片选
gpio = bflb_device_get_by_name("gpio");// gpio10 输入模式 获取电平状态
bflb_gpio_init(gpio, GPIO_PIN_10, GPIO_INPUT | GPIO_PULLUP);
bflb_gpio_set(gpio,GPIO_PIN_10); // 设置为高电平
}
- 片选用串口打印数据
while(1){
// 1. 判断从机是否可以片选 【定义GPIO为低电平可选】
// 2. 片选,发送数据,接收数据
// 3. 打印数据到串口
if(!bflb_gpio_read(gpio, GPIO_PIN_10)){
// bflb_gpio_reset(gpio, GPIO_PIN_12); // 片选(双机通讯可以不用手动设置/取消片选)
for(uint8_t i=0;i<3;i++){
//这里可能会有人有疑惑,DMA才采集三个数据,速度很快的,CPU刚调度完就结束了,会不会没有时间将数据发送出来,事实上我的STM32ADC采集的缓冲区非常大的,我只是把最大值给发出来,这里三个数就是用了三个通道的找出最大值给发过来的。
rx_buff[i] = bflb_spi_poll_send(spi0,tx_buff[i]); //数据交换
}
// bflb_gpio_set(gpio, GPIO_PIN_12); //取消片选
printf(":%d,%d,%d\r\n",rx_buff[0],rx_buff[1],rx_buff[2]); //打印出ADC 采集的数据
}
else{
//printf("wait");
}
}
}
-
代码
效果
|