使用STM32进行SPI的DMA时出现无效数据

3
我会尽力为您翻译IT技术相关内容。以下是需要翻译的文本:

我正在使用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);

我尝试推送SPI传输,以便在DMA传输开始之前在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

EDIT 2: 在读取过程中,第一个字节和最后一个字节读取的是0而不是0xff。以下是传输开始和结束的截图。 Start End 为了澄清,我使用正常的SPI指令发送读命令,然后我配置DMA以针对特定数据长度并启动传输(其中SCLK是连续的部分)。Flash是空的(已验证),这意味着所有内容都在0xFF处。数据缓冲区只是在第一个和最后一个字节得到了0...

如果你直接设置硬件而不使用STLib这种垃圾,那么看起来会容易得多。然而,我怀疑你在最后一次或最后两次传输仍在进行时就过早地禁用了SS。请等待“!BUSY”。 - too honest for this site
在DMA初始化之前启用CS,DMA irqHandler在检查transferComplete标志后禁用它。不过,我不知道你所说的STLib是什么。 - Tiwi13
然而,如果SS不是问题的关键点,你必须提供更多信息;例如,使用调试器或MSO查看实际上正在发生什么。 - too honest for this site
作为一般提示:请检查设备勘误表。有关STM系列的DMA和可能的SPI方面存在一些问题。 - too honest for this site
这是一个16k字节的读取。字节0和字节0x3fff是错误的。就是这样。 - Tiwi13
显示剩余5条评论
1个回答

2
我怀疑你在SPI已经开始传输时才启用SS,而在帧结束时过早地禁用它,这时仍有位被移位。对于开始,首先启用SPI,然后启动DMA。对于结束,请等待DMA完成(如果DMA速度太慢以至于无法持续提供SPI,则SPI的!BUSY将无法工作)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接