【问题标题】:Invalid data when using DMA for SPI with STM32将 DMA 用于 STM32 的 SPI 时数据无效
【发布时间】:2015-09-17 11:12:33
【问题描述】:

我正在使用 DMA 来管理一些带有外部闪存的 SPI 传输。检索到的第一个和最后一个数据字节无效。我可以忍受最后一个字节无效(但仍然想知道为什么),但不是第一个字节。

这是 DMA 初始化

// Deinitialize DMA Streams 
DMA_DeInit(DMA_TX_STREAM);
DMA_DeInit(DMA_RX_STREAM);

// Initialize buffer size
DMA_InitStructure.DMA_BufferSize = *nbData;
// Rest of Init
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable ;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single ;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

DMA_InitStructure.DMA_PeripheralBaseAddr = (Uint32)&(SPIx->DR);
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;

// Configure Tx DMA 
DMA_InitStructure.DMA_Channel = DMA_TX_CHANNEL;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_Memory0BaseAddr = (Uint32) data;
DMA_Init(DMA_TX_STREAM, &DMA_InitStructure);

// Configure Rx DMA 
DMA_InitStructure.DMA_Channel = DMA_RX_CHANNEL;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) data;
DMA_Init(DMA_RX_STREAM, &DMA_InitStructure);

DMA_ITConfig(DMA_RX_STREAM, DMA_IT_TC, ENABLE);

// Enable the DMA Stream IRQ Channel
NVIC_InitStructure.NVIC_IRQChannel = DMA_RX_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

// Enable DMA Streams
DMA_Cmd(DMA_RX_STREAM, ENABLE);
DMA_Cmd(DMA_TX_STREAM, ENABLE);

// Enable DMA SPI request
SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Rx, ENABLE);
SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Tx, ENABLE);

我尝试在 DMA 传输开始之前推动 SPI 传输以在 SPIx->DR 中添加一些内容,但没有成功

while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPIx, (Uint16)0x00);

为什么会发生这种情况,您建议如何解决?

编辑:这是使用的定义

#define SPIx                            SPI2
#define DMA_RX_STREAM                   DMA1_Stream3
#define DMA_RX_CHANNEL                  DMA_Channel_0
#define DMA_RX_IRQ                      DMA1_Stream3_IRQn
#define DMA_IT_TCIF_RX                  DMA_IT_TCIF3
#define DMA_TX_STREAM                   DMA1_Stream4
#define DMA_TX_CHANNEL                  DMA_Channel_0
#define DMA_TX_IRQ                      DMA1_Stream4_IRQn
#define DMA_IT_TCIF_TX                  DMA_IT_TCIF4

编辑 2:第一个和最后一个字节读取 0 而不是 0xff。这是传输的开始和结束。

为了澄清,我使用普通的 SPI 指令来发送读取命令,然后我将 DMA 配置为特定的数据长度并开始传输(SCLK 连续的部分)。 Flash 是空的(已验证),这意味着一切都在 0xFF。数据缓冲区的第一个字节和最后一个字节都为 0...

【问题讨论】:

  • 如果您只是直接设置硬件而没有中间的这个 STLib 废话,会容易得多(看看您在做什么)。但是,我怀疑,您太早禁用 SS,而最后或最后两次转移仍在进行中。等待!BUSY
  • CS 在 DMA 初始化之前启用,并且 DMA irqHandler 在检查 transferComplete 标志后禁用它。不知道你说的 STLib 废话是什么意思......
  • ST提供的库。不直接设置硬件没有任何好处。那东西只会增加臃肿,可能导致奇怪的行为。如果不是这样,它至少会通过在此处进行一些设置、在此处进行一些设置等来混淆实际代码。
  • 但是,如果 SS 不是重点,您必须提供更多信息;例如使用调试器或 MSO 来查看实际发生的情况。
  • 添加了逻辑分析仪的图像。

标签: c stm32 spi dma


【解决方案1】:

我怀疑,当 SPI 已经开始传输时,您启用 SS 为时已晚。并在帧结束时过早禁用它,而仍有位被移位。

首先,首先启用 SPI,然后启动 DMA。最后,等到 DMA 完成(如果 DMA 太慢而无法连续馈送 SPI,则 SPI !BUSY 将不起作用)。

【讨论】:

    猜你喜欢
    • 2017-04-14
    • 1970-01-01
    • 2019-05-28
    • 2019-02-21
    • 2022-01-02
    • 2012-11-20
    • 2019-03-17
    • 2021-08-17
    • 2019-04-06
    相关资源
    最近更新 更多