我按照这个问题/教程STM32 SPI LL DMA Transmit使用DMA实现我自己的SPI TransmitReceive版本。
我的代码到目前为止运行良好,它基于低级驱动程序在 SPI 上发送/接收。
什么不起作用:当传输完成时,我想有一个中断,但无论我到目前为止尝试过什么:中断根本没有触发。
SPI 初始化一次:
// Note: called only once because the address of the peripheral does never change
// Configure RX
// LL_DMA_ConfigAddresses(DMA, DMA Channel, Source Addr, Dest Addr, Direction)
LL_DMA_ConfigAddresses(
DMA1,
LL_DMA_CHANNEL_2,
LL_SPI_DMA_GetRegAddr(SPI1),
(uint32_t)RXdata,
LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2));
// Configure Tx
LL_DMA_ConfigAddresses(
DMA1,
LL_DMA_CHANNEL_3,
(uint32_t)TXdata,
LL_SPI_DMA_GetRegAddr(SPI1),
LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_3));
通过此代码重复启动传输:
// set RX
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_2, (uint32_t)pRXdata);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, BufSz);
LL_SPI_EnableDMAReq_RX(SPI1);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_2);
LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_2);
// set TX
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_3, (uint32_t)pTXdata);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_3, BufSz);
LL_SPI_EnableDMAReq_TX(SPI1);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_3);
// Start SPI
LL_SPI_Enable(SPI1);
中断(传输完成和传输错误)“绑定”到 RX DMA 通道 - 就像 HAL 一样。
在(自动生成的)dma.c 文件中启用中断:
void MX_DMA_Init(void) {
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel2_IRQn interrupt configuration */
NVIC_SetPriority(DMA1_Channel2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),4, 0));
NVIC_EnableIRQ(DMA1_Channel2_IRQn);
/* DMA1_Channel3_IRQn interrupt configuration */
NVIC_SetPriority(DMA1_Channel3_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0));
NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}
CubeMX 中启用了 DMA 通道 2 和 3 的中断,我可以在中断向量表中找到这些函数。一般来说,中断是活动的,因为我可以看到 SysTic 中断触发。我还有一个定时器,它通过中断触发 SPI 传输。
void DMA1_Channel2_IRQHandler(void) 和 void DMA1_Channel3_IRQHandler(void) 存在于“stm32XXyyzzz_it.c”中。我向 DMA 通道 2 ISR 添加了一个计数器变量用于调试,该变量保持为 0 => ISR 从未被调用。
问题:我需要做什么才能使 DMA(通道 2)传输完成中断正常工作?
我找到了解决方案:问题不是 DMA 的设置,而是我只是在程序流程的早期禁用 DMA。 DMA 从未到达传输末尾,因此它不会触发“传输完成”IRQ。
上述代码有效且有效。我希望它能帮助其他人使用低级驱动程序实现自己的 SPI 功能。