单片机/MCU论坛
直播中

尤立虔

9年用户 1068经验值
擅长:控制/MCU
私信 关注
[问答]

如何使用 SPI 全双工在两个 5LP MPU 之间连接 RAM?

我需要将两个 5LP MPU 连接在一起以镜像两个 5LP MPU 内的 RAM。
我认为这将是 DMA 的一个功能,但我不确定如何实现该功能。
我的主 SPI 单元将向从属 MPU 发送一个数据块并将其存储在相同的内存位置中,从而将数据位置与数据进行镜像。
我想我在 I2C 部分读过一个允许这种类型传输的 API,但我不确定在哪里找到它。
我在 DMA 传输方面一直没有成功。

回帖(1)

李猛

2025-7-22 17:42:09

要将两个 MPU(如 STM32F5/L5 系列)通过 SPI 全双工模式连接以实现 RAM 镜像,需结合 SPI 和 DMA 技术。以下是步骤和代码示例:




1. 硬件连接



  • 主 MPU (SPI Master) ↔ 从 MPU (SPI Slave):

    • MOSI (主出从入)MOSI

    • MISO (主入从出)MISO

    • SCK (时钟)SCK

    • CS (片选)CS (主控手动拉低/拉高)





2. 主 MPU 配置(发送数据)


SPI 初始化


// 启用 SPI 时钟和 DMA 时钟
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;

// SPI 配置为全双工主模式
SPI_HandleTypeDef hspi;
hspi.Instance = SPI1;
hspi.Init.Mode = SPI_MODE_MASTER;
hspi.Init.Direction = SPI_DIRECTION_2LINES;
hspi.Init.DataSize = SPI_DATASIZE_8BIT;
hspi.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; // 根据需求调整
HAL_SPI_Init(&hspi);

DMA 配置(发送数据块)


// 源地址:待发送的 RAM 区域
// 目标地址:SPI 数据寄存器
uint8_t *source_addr = (uint8_t*)0x20000000; // 示例 RAM 地址
uint32_t data_size = 1024; // 传输字节数

DMA_HandleTypeDef hdma_tx;
hdma_tx.Instance = DMA2_Stream3;
hdma_tx.Init.Channel = DMA_CHANNEL_3;
hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_tx.Init.Mode = DMA_NORMAL; // 非循环模式
HAL_DMA_Init(&hdma_tx);

__HAL_LINKDMA(&hspi, hdmatx, hdma_tx);

// 启动 SPI DMA 传输
HAL_SPI_Transmit_DMA(&hspi, source_addr, data_size);



3. 从 MPU 配置(接收并写入 RAM)


SPI 初始化


// 从 MPU 配置为 SPI 从模式
SPI_HandleTypeDef hspi_slave;
hspi_slave.Instance = SPI2;
hspi_slave.Init.Mode = SPI_MODE_SLAVE;
hspi_slave.Init.Direction = SPI_DIRECTION_2LINES;
hspi_slave.Init.DataSize = SPI_DATASIZE_8BIT;
hspi_slave.Init.CLKPolarity = SPI_POLARITY_LOW; // 与主设备一致
hspi_slave.Init.CLKPhase = SPI_PHASE_1EDGE;
HAL_SPI_Init(&hspi_slave);

DMA 配置(接收数据到指定 RAM)


// 目标地址:镜像 RAM 区域
uint8_t *mirror_addr = (uint8_t*)0x20000000; // 与主设备相同地址
uint32_t data_size = 1024;

DMA_HandleTypeDef hdma_rx;
hdma_rx.Instance = DMA1_Stream0;
hdma_rx.Init.Channel = DMA_CHANNEL_0;
hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_rx.Init.Mode = DMA_NORMAL;
HAL_DMA_Init(&hdma_rx);

__HAL_LINKDMA(&hspi_slave, hdmarx, hdma_rx);

// 启动 SPI DMA 接收(从设备被动接收)
HAL_SPI_Receive_DMA(&hspi_slave, mirror_addr, data_size);



4. 传输流程



  1. 启动从设备 DMA

    • 从设备提前调用 HAL_SPI_Receive_DMA() 等待数据。


  2. 主设备发起传输

    • 拉低 CS 引脚(片选)。

    • 调用 HAL_SPI_Transmit_DMA() 发送数据。


  3. 数据传输

    • DMA 自动将主设备 RAM 数据通过 SPI 发送。

    • 从设备 SPI 接收数据,DMA 自动写入其 RAM。


  4. 传输完成

    • 主/从设备通过 DMA 完成中断(或轮询标志位)通知结束。

    • 主设备拉高 CS 引脚。





5. 关键注意事项



  • 时钟同步:主从设备 SPI 时钟配置(极性/相位)必须一致。

  • 内存地址:确保主/从设备的镜像 RAM 地址在各自系统中有效。

  • DMA 通道:根据具体 MPU 型号选择未冲突的 DMA 流(Stream)和通道(Channel)。

  • 数据对齐MemDataAlignment 需与数据宽度匹配(如 8/16 位)。

  • 中断处理

    • 实现 HAL_SPI_TxCpltCallback()(主)和 HAL_SPI_RxCpltCallback()(从)处理完成事件。


  • 全双工优化

    • 若需要主从双向同步,使用 HAL_SPI_TransmitReceive_DMA() 同时收发数据。





6. I2C 替代方案(不推荐)


虽然 I2C 支持多主模式,但半双工特性和较低速度不适合 RAM 镜像:


// I2C 示例(主设备写入从设备 RAM)
HAL_I2C_Mem_Write(&hi2c, SLAVE_ADDR, MEM_ADDR, I2C_MEMADD_SIZE_16BIT, data, size, 100);


  • 缺点:需指定从设备地址和内存地址,且速度通常低于 SPI DMA。




通过以上步骤,SPI 全双工 + DMA 能高效实现两个 MPU 之间的 RAM 数据镜像。确保硬件连接正确,并参考 MPU 的数据手册调整 SPI/DMA 寄存器配置。

举报

更多回帖

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