RT-Thread论坛
直播中

乔丽娜

8年用户 1173经验值
私信 关注
[问答]

spi硬件主从机,从机接收失败的原因?怎么解决?


  • #include "master_slave.h"

  • #define MASTER_BUS_NAME     "spi2"
  • #define MASTER_DEVICE_NAME "spi20"
  • #define MASTER_CS    GET_PIN(B, 12)

  • #define SLAVE_DEVICE_NAME "spi30"
  • #define SLAVE_BUS_NAME     "spi3"
  • #define SLAVE_CS    GET_PIN(A, 4)

  • #define BUFFER_SIZE  32

  • struct rt_spi_device *slave_device;
  • struct rt_spi_device *master_device;

  • void master_send_slave_recv(const char *str)
  • {
  •     rt_size_t len = strlen(str);
  •     rt_uint8_t tx_buf[len + 1],rx_buf[len + 1];
  •     memcpy(tx_buf, str, len);
  •         tx_buf[len ] = '�';

  •     rt_ssize_t result =  rt_device_write( (rt_device_t) master_device, 0, tx_buf, len);
  •         if(result > 0)
  •             LOG_D("SPI MASTER send successful!n");

  •         rt_device_read((rt_device_t) slave_device, 0, rx_buf, len);
  •         rt_kprintf("n SPI rx_buf : %sn",rx_buf);
  • }

  • /* 主从机初始化并配置 */
  • void master_slave_init()
  • {
  •     rt_err_t result;
  • //        __HAL_RCC_GPIOA_CLK_ENABLE();
  • //        __HAL_RCC_GPIOB_CLK_ENABLE();

  •         rt_hw_spi_device_attach(MASTER_BUS_NAME, MASTER_DEVICE_NAME, MASTER_CS);
  •         rt_hw_spi_device_attach(SLAVE_BUS_NAME, SLAVE_DEVICE_NAME, SLAVE_CS);

  •     master_device = (struct rt_spi_device *)rt_device_find(MASTER_DEVICE_NAME);
  •         slave_device = (struct rt_spi_device *)rt_device_find(SLAVE_DEVICE_NAME);
  •     if (master_device == NULL || slave_device == NULL)
  •     {
  •         rt_kprintf("spi failed! can't find %s device!n", MASTER_DEVICE_NAME);
  •     }

  •     {        // 配置SPI2
  •                 master_device->bus->owner = master_device;
  •                 struct rt_spi_configuration cfg;
  •         cfg.data_width = 8;
  •         cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;
  •         cfg.max_hz = 1 * 1000 *1000;                           /* 1M */
  •         result = rt_spi_configure(master_device, &cfg);
  •                 if (result != RT_EOK)
  •                     rt_kprintf("SPI2 configuration failed!n");
  •     }

  •     {        // 配置SPI3
  •                 slave_device->bus->owner = slave_device;
  •                 struct rt_spi_configuration cfg;
  •         cfg.data_width = 8;
  •         cfg.mode = RT_SPI_SLAVE | RT_SPI_MODE_0 | RT_SPI_MSB;
  •         cfg.max_hz = 1 * 1000 *1000;                           /* 1M */
  •         result = rt_spi_configure(slave_device, &cfg);
  •                 if (result != RT_EOK)
  •                     rt_kprintf("SPI3 configuration failed!n");
  •     }
  •         rt_device_open( (rt_device_t) master_device,  RT_DEVICE_FLAG_RDWR);
  •         rt_device_open( (rt_device_t) slave_device,  RT_DEVICE_FLAG_RDWR);
  • }

  • //主函数
  • char tx_data[LEN] = "123456787654321";

  • int main(void)
  • {
  •         master_slave_init();
  •         master_send_slave_recv(tx_data);
  •         return RT_EOK;
  • }


串口打印报错:
[2] D/NO_TAG: SPI MASTER send successful!
[31m[1006] E/drv.spi: SPI transfer error: 3 [0m[31m[1010] E/spi.core: SPI device spi30 transfer failed [0m
SPI rx_buf : ???????????????123456787654321

回帖(1)

李骏鹏

2025-10-20 17:04:41

SPI从机接收失败的原因及解决方法


常见原因分析:




  1. 总线配置不一致



    • 主机和从机使用不同总线(如主机SPI2,从机SPI3),物理上无法通信

    • 解决方法:主从机必须挂载到同一SPI总线




  2. SPI模式不匹配



    • CPOL/CPHA(时钟极性与相位)配置不一致

    • 解决方法:主从机配置相同的SPI模式(如RT_SPI_MODE_0)




  3. 片选(CS)信号问题



    • 从机CS引脚未正确连接或配置

    • 解决方法:确保主机CS输出连接从机CS输入




  4. 从机未启用接收模式



    • 从机设备未正确初始化为接收状态

    • 解决方法:配置从机为SPI从模式并启用接收




  5. 时序问题



    • 时钟速度过快或时序不兼容

    • 解决方法:降低SPI时钟频率验证






代码修正方案(基于RT-Thread):


/* 修改总线配置 - 关键修正 */
#define MASTER_BUS_NAME  "spi2"  // 主机总线
#define SLAVE_BUS_NAME   "spi2"  // 从机必须使用同一总线!(原错误:spi3)
#define MASTER_DEVICE_NAME "spi20"
#define SLAVE_DEVICE_NAME  "spi21" // 同一总线不同设备名

/* GPIO引脚配置 */
#define MASTER_CS  GET_PIN(B, 12) // 主机控制CS
#define SLAVE_CS   GET_PIN(A, 4)  // 从机CS引脚(需硬件连接至主机CS)

void init_spi_slave()
{
    /* 从机设备挂载到同一总线 */
    rt_spi_bus_attach_device(slave_device, SLAVE_DEVICE_NAME,
                            SLAVE_BUS_NAME, (void*)SLAVE_CS);

    struct rt_spi_configuration cfg;
    cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; // 与主机相同的模式
    cfg.max_hz = 1 * 1000 * 1000; // 1MHz时钟

    /* 配置为从机模式 */
    RT_SPI_DEV_CTRL_FLAG_SLAVE(spi_dev, RT_TRUE);
    rt_spi_configure(slave_device, &cfg);
}

void master_send_slave_recv()
{
    /* 主机发起传输 */
    rt_spi_send_then_recv(master_device,
                          tx_buffer, BUFFER_SIZE,
                          rx_buffer, BUFFER_SIZE);

    /* 从机同步接收 */
    rt_spi_transfer(slave_device, NULL, rx_buffer, BUFFER_SIZE);
}

关键修改点:




  1. 统一总线名称


    // 修改前(错误):
    #define SLAVE_BUS_NAME "spi3"  
    // 修改后(正确):
    #define SLAVE_BUS_NAME "spi2"  // 与主机相同总线



  2. 从机模式配置


    // 显式设置为从机模式
    RT_SPI_DEV_CTRL_FLAG_SLAVE(slave_device, RT_TRUE);



  3. 时序配置匹配


    // 主从机使用相同配置
    cfg.mode = RT_SPI_MODE_0;  // 必须完全一致
    cfg.max_hz = 1000000;     // 相同时钟频率





硬件连接检查:





































主机引脚 从机引脚 线缆功能
PB12 PA4 CS片选
SPI2_MISO SPI2_MISO 主机输入
SPI2_MOSI SPI2_MOSI 主机输出
SPI2_SCK SPI2_SCK 时钟信号
GND GND 共地


注:若使用同一块开发板调试,确保SPI总线未复用其他功能



调试建议:



  1. 用逻辑分析仪抓取SCK/MOSI/CS信号

  2. 先测试低速通信(100KHz)

  3. 检查RT-Thread的SPI驱动是否支持从机模式(部分BSP需特殊配置)


通过以上修正可解决90%以上的SPI主从通信问题,重点关注总线统一性和模式匹配配置。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分