BSP修改与SPI配置
首先在board/Kconfig里面加入SPI配置
menuconfig BSP_USING_SPI
bool "Enable SPI BUS"
select RT_USING_SPI
default n
if BSP_USING_SPI
menuconfig BSP_USING_SPI0
bool "Enable SPI0 BUS"
default n
menuconfig BSP_USING_SPI3
bool "Enable SPI3 BUS"
default n
if BSP_USING_SPI3
config BSP_USING_SPI3_SAMPLE
bool "Enable SPI3 BUS Sample"
default n
endif
menuconfig BSP_USING_SPI6
bool "Enable SPI6 BUS"
default n
endif
然后在menuconfig开启即可,但是需要修改一下drv_spi.c的引脚
引脚修改成EVK上对应的引脚即可,我这里用的是Arduino接口上的SPI,也是官方例程使用的SPI。
配置与应用代码如下所示。
/*
* Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2024-05-22 LZero first version */
#include <rtthread.h>
#include <rtdevice.h>
#include "ADIS16467-2.h"
#include "drv_gpio.h"
#include "drv_spi.h"
#include "rtdbg.h"
#define DBG_LVL DBG_
#define LED_PIN GET_PIN(16, 1)
#define LED2_PIN GET_PIN(16,2)
rt_thread_t IMU_thread;
ADIS16467_T adi_imu = {0};
void SPIRTTEST() {
rt_pin_mode(GET_PIN(10, 3), PIN_MODE_OUTPUT);
rt_kprintf("IMU Thread Start!\n");
struct rt_spi_configuration imu_config = {
.data_width=16,
.mode=RT_SPI_MASTER | RT_SPI_MODE_3 | RT_SPI_MSB,
.max_hz=1000000
};
struct rt_spi_device* imu_device = (struct rt_spi_device*)rt_malloc(sizeof(struct rt_spi_device));
rt_spi_bus_attach_device_cspin(imu,"spi61","spi6",GET_PIN(10,3),RT_NULL);
struct rt_spi_device *imu = (struct rt_spi_device *) rt_device_find("spi61");
if (!imu) {
rt_kprintf("imu not found\n");
} else {
rt_kprintf("imu found\n");
}
rt_spi_configure(imu, &imu_config);
adi_imu.spi_device = imu;
ADIS16467_Init(&adi_imu);
ADIS16467_Check(&adi_imu);
ADIS16467_imuInfo(&adi_imu);
rt_kprintf("IMU ProdID : %X", adi_imu.ProdId);
rt_pin_mode(LED2_PIN, PIN_MODE_OUTPUT);
while (1) {
rt_pin_write(LED2_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED2_PIN, PIN_LOW);
rt_thread_mdelay(500);
}
}
int main(void) {
spitest = rt_thread_create("spitest", SPIRTTEST, RT_NULL,
RT_MAIN_THREAD_STACK_SIZE, 20, 20);
rt_thread_startup(spitest);
rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
rt_kprintf("Hello World!\n");
for (;;) {
rt_pin_write(LED_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED_PIN, PIN_LOW);
rt_thread_mdelay(500);
}
}
实际使用
原计划使用SPI驱动ADIS16467-2,这是一个ADI的精密陀螺仪,在STM32上已经有完整实现,计划在本次实践中使用XMC7200嵌入RTT官方BSP,但是始终无法驱动起来。sendandsend函数逻分显示是正确的,但是
RTT BSP传输波形,不知道为什么会在后面有BA0,发送的是E880。
波形分析
使用ST官方HAL库,ADIS16467可正常运行,驱动链接:GitHub - WwWangGuan/ADIS16467-2: ADIS16467-2的STM32驱动程序
该函数使用的寄存器如图所示
正确的读取数据如下图所示
下图为逻分捕捉波形(rangeModel读取)
即正常波形为:Master发送5E00,从机回答07
接下来是写寄存器
此函数的目的是为了在开机时重启陀螺仪(写值0x1000 0000/0x80h)
那么如何写一个寄存器呢?datasheet这么说
也就是说 对于每一个16位的数据,写寄存器之前先将最高位置1,然后加上寄存器地址到高八位,低八位是你要写的数据
来看看逻辑分析仪的波形
函数实现是这个样子
也明显,分成三步:
- 地址先或一个0x80h(0x1000 0000),因为要写寄存器。
- 地址左移8位,”或“上你的数据
- 开始通信。
RTThread SPI设备驱动框架测试
上来就没绷住
换用rt_spi_transfer,能发出去了,但是收不到
跟ST的HAL相比,设备驱动框架无论是transfer,send还是send_and_receive都比HAL慢的多
上面有四帧数据,能看出来吗
感觉是API调的不对,再换。
void ADIS16467_Init(ADIS16467_T *imu) {
// ADI_Write_Reg(imu, GLOB_CMD_REG, 0x80); //software reset
// ADI_Write_Reg(imu, GLOB_CMD_REG + 1, 0x80);
uint16_t send[2] = {((GLOB_CMD_REG | 0x80) << 8) | 0x80, (((GLOB_CMD_REG + 1) | 0x80) << 8) | 0x80};
uint16_t receive[2] = {0};
rt_spi_send_then_recv(imu->spi_device, send, 2, receive, 2);
imu->K_G = 40;
imu->KG_Reciprocal = (float) (1 / imu->K_G);
rt_thread_mdelay(2000); // wait for reboot
}
这么写之后的波形是这样的,孩子怪可怜的
对比HAL的波形
void ADIS16467_Init(ADIS16467_T *imu) {
uint16_t send[2] = {((GLOB_CMD_REG | 0x80) << 8) | 0x80, (((GLOB_CMD_REG + 1) | 0x80) << 8) | 0x80};
uint16_t receive[2] = {0};
HAL_SPI_TransmitReceive(imu->hspi, (uint8_t *) send, (uint8_t *) receive, 2, 0xFFFF);
imu->K_G = 40;
imu->KG_Reciprocal = (float) (1 / imu->K_G);
HAL_Delay(4000); // wait for reboot
}
波形这个样子
能看出来RTT跟HAL的处理方式截然不同,RTT是,我先把TX的东西发完,再收两个
但是只有这么写,波形才对,读出来的数据也是正确的
void ADIS16467_Init(ADIS16467_T *imu) {
ADI_Write_Reg(imu, GLOB_CMD_REG, 0x80); //software reset
ADI_Write_Reg(imu, GLOB_CMD_REG + 1, 0x80);
imu->K_G = 40;
imu->KG_Reciprocal = (float) (1 / imu->K_G);
HAL_Delay(4000); // wait for reboot
}
int8_t ADI_Write_Reg(ADIS16467_T *imu, uint8_t addr, uint8_t value) {
addr |= 0x80; //写数据的掩码
uint16_t Tx_tmp = (addr << 8) | value;
ADI_flame_TandR(imu, Tx_tmp);
return 0;
}
uint16_t ADI_flame_TandR(ADIS16467_T *imu, uint16_t trans) {
HAL_GPIO_WritePin(imu->GPIOx, imu->GPIO_PIN, 0);
uint16_t result = 0;
static HAL_StatusTypeDef state;
state = HAL_SPI_TransmitReceive(imu->hspi, (uint8_t *) &trans, (uint8_t *) &result, 1, 0xFFFF);
if (state != HAL_OK) {
while (1);
} HAL_GPIO_WritePin(imu->GPIOx, imu->GPIO_PIN, 1);
sb_delay(500);
return result;
}
就是发一次,停一下再发一次。
使用rt_transfer
uint16_t ADI_flame_TandR(ADIS16467_T *imu, uint16_t trans) {
// HAL_GPIO_WritePin(imu->GPIOx, imu->GPIO_PIN, 0);
uint16_t result = 0;
// static HAL_StatusTypeDef state;
// state = HAL_SPI_TransmitReceive(imu->hspi, (uint8_t *) &trans, (uint8_t *) &result, 1, 0xFFFF);
// if (state != HAL_OK) {
// while (1);
// }
// HAL_GPIO_WritePin(imu->GPIOx, imu->GPIO_PIN, 1);
// rt_spi_send_then_recv(imu->spi_device, &trans, 1, &result, 1);
rt_spi_transfer(imu->spi_device, &trans, &result, 1);
return result;
}
还是慢,两次transfer时间相差15ms
HAL对比,函数使用HAL_SPI_TransmitReceive,两次传输时间相差39$\mu s$,怪离谱的。
尝试提升线程优先级?
int main(void) {
spitest = rt_thread_create("spitest", SPIRTTEST, RT_NULL,
4096, 20, 20);
rt_thread_startup(spitest);
/* set LED2 pin mode to output */
rt_pin_mode(LED2_PIN, PIN_MODE_OUTPUT);
while (1) {
rt_pin_write(LED2_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED2_PIN, PIN_LOW);
rt_thread_mdelay(500);
}}
priority改成10?试了,没用,这真的慢。
换用rt_spi_transfer_message,有效
uint16_t ADI_flame_TandR(ADIS16467_T *imu, uint16_t trans) {
// HAL_GPIO_WritePin(imu->GPIOx, imu->GPIO_PIN, 0);
uint16_t result;
struct rt_spi_message msg1,msg2;
msg1.send_buf = &trans;
msg1.recv_buf = &result;
msg1.length = 1;
msg1.cs_take = 1;
msg1.cs_release = 1;
msg1.next = RT_NULL;
rt_spi_transfer_message(imu->spi_device,&msg1);
// rt_spi_transfer(imu->spi_device,&trans,&result,2);
// sb_delay(200); return result;
}
读取成功
接下来console输出加速度和角速度值(rt_krpintf输出浮点数需要安装全功能软件包),但是debug下是好使的
串口输出结果
EVK板载QSPI Flash
换用QSPI,更换逻分之后再尝试
原理图如图所示,型号为S25FL512SAGMFMR10,英飞凌自己家的,参数挺好
引脚映射在下图
使用SPI0/SPI3模式
支持SFDP,这下好办了,可以直接使用RTT的SFUD
Kconfig文件修改
添加以下内容
scons重新生成cmakelist之后提示
尝试 pkgs -Update,发现无效
尝试在menucongfig中启用对应软件包,该软件包对此报错无效,且在HAL中无法找到此文件
问题:有对应的头文件,但是其实现却在drv_flash.c中,疑似官方错误,英飞凌的官方包也没有这个东西,在cmakelist中删除文件后能通过编译,但是AC6编译未能通过。