XMC7200EEVK-SPI


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,然后加上寄存器地址到高八位,低八位是你要写的数据
来看看逻辑分析仪的波形

函数实现是这个样子

也明显,分成三步:

  1. 地址先或一个0x80h(0x1000 0000),因为要写寄存器。
  2. 地址左移8位,”或“上你的数据
  3. 开始通信。

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编译未能通过。


文章作者: Harry Zhang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Harry Zhang !
  目录