You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在LibreComputer RK3328(Renegade)上编写CPP程序实现SPI通信?

实现LibreComputer Renegade与STM32F4的SPI通信方案

一、解决Renegade上的SPI启用问题

Linux系统下无需直接操作寄存器,通过系统工具和设备树配置启用SPI:

  • 启用SPI硬件overlay:编辑/boot/uEnv.txt,添加/修改overlay_prefix=rockchip,再追加overlays=spi0(使用SPI1则写spi1),重启系统后用ls /dev/spidev*确认设备节点(如/dev/spidev0.0)是否存在。
  • 排查设备树冲突:若节点未出现,用dtc -I fs /proc/device-tree查看SPI节点状态,确认对应引脚未被其他外设占用。

二、基于spidev的CPP CLI程序实现

利用Linux用户空间驱动spidev实现SPI读写,无需编写内核驱动:

1. SPI操作封装类

#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <cstdint>
#include <stdexcept>

class SPI {
private:
    int fd;
    const char* device;
    uint8_t mode;
    uint32_t speed;
    uint8_t bits;

public:
    SPI(const char* dev, uint8_t m, uint32_t s, uint8_t b) 
        : device(dev), mode(m), speed(s), bits(b) {
        fd = open(device, O_RDWR);
        if (fd < 0) throw std::runtime_error("Failed to open SPI device");
        
        if (ioctl(fd, SPI_IOC_WR_MODE, &mode) < 0) { close(fd); throw std::runtime_error("Failed to set SPI mode"); }
        if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) { close(fd); throw std::runtime_error("Failed to set SPI speed"); }
        if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0) { close(fd); throw std::runtime_error("Failed to set bits per word"); }
    }

    ~SPI() { if (fd >= 0) close(fd); }

    int transfer(uint8_t* tx_buf, uint8_t* rx_buf, size_t len) {
        struct spi_ioc_transfer tr = {
            .tx_buf = (unsigned long)tx_buf,
            .rx_buf = (unsigned long)rx_buf,
            .len = len,
            .speed_hz = speed,
            .bits_per_word = bits,
        };
        return ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
    }
};

2. CLI控制逻辑

解析命令行参数,实现运动指令发送、状态读取功能:

#include <iostream>
#include <cstring>

int main(int argc, char* argv[]) {
    if (argc < 2) {
        std::cout << "Usage: " << argv[0] << " <cmd> [params]\n";
        std::cout << "Cmds:\n  move <x> <y> <z> - Send inverse kinematics results to STM32\n  status - Read status from STM32\n";
        return 1;
    }

    try {
        SPI spi("/dev/spidev0.0", SPI_MODE_0, 1000000, 8); // 匹配STM32的SPI模式、速率、位宽

        if (strcmp(argv[1], "move") == 0) {
            if (argc != 5) { std::cout << "Move requires x, y, z params\n"; return 1; }
            // 打包逆运动学计算后的指令帧(示例格式)
            uint8_t tx_buf[5] = {0x01, 
                                static_cast<uint8_t>(atoi(argv[2]) & 0xFF),
                                static_cast<uint8_t>(atoi(argv[3]) & 0xFF),
                                static_cast<uint8_t>(atoi(argv[4]) & 0xFF),
                                0x00}; // 可选校验位
            uint8_t rx_buf[5] = {0};
            spi.transfer(tx_buf, rx_buf, 5);
            rx_buf[0] == 0x0A ? std::cout << "Move command sent successfully\n" : std::cout << "Move failed, response: " << static_cast<int>(rx_buf[0]) << "\n";
        } else if (strcmp(argv[1], "status") == 0) {
            uint8_t tx_buf[1] = {0x02}; // 读取状态指令
            uint8_t rx_buf[4] = {0}; // 状态帧:位置、报错码等
            spi.transfer(tx_buf, rx_buf, 4);
            std::cout << "Status: pos=" << static_cast<int>(rx_buf[0]) << ", error=" << static_cast<int>(rx_buf[1]) << "\n";
        } else {
            std::cout << "Unknown command\n";
            return 1;
        }
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << "\n";
        return 1;
    }

    return 0;
}

3. 编译与运行

编译命令:

g++ -o spi_controller spi_controller.cpp

运行前赋予权限:将用户加入spi组(sudo usermod -aG spi $USER,重启生效),或直接用sudo ./spi_controller执行。

三、STM32F4端SPI通信要点

  • 配置SPI为从机模式,模式、速率、位宽与Renegade端完全匹配(如SPI_MODE_0)。
  • 配置对应GPIO为SPI功能,硬件片选NSS设为输入下拉模式。
  • 实现SPI中断接收:收到指令帧后解析并执行步进电机控制,完成后返回状态帧。
  • 定义固定通信协议:比如帧头+指令类型+数据+校验位,避免通信丢包或误解析。

四、调试排障

  • 用逻辑分析仪检查SCK、MOSI引脚信号是否正常输出。
  • 先测试单向通信:Renegade发送固定数据,STM32接收后打印,确认物理连接无误。
  • 降低SPI速率(如先100kHz)排查信号失真问题。
  • 用dmesg | grep spi查看内核日志,确认SPI驱动加载状态。

内容的提问来源于stack exchange,提问作者PlushyCascade82

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 05:25:30