大家好
我最近在使用 SPI DMA 进行多传感器通信时遇到了一个问题,SPI 事务返回 -EIO 或数据损坏。深入研究驱动程序后,我发现 DMA 模式下,spi_nxp_lpspi 在每次传输开始时启用两个 LPSPI DMA 请求使能位,但在结束时只禁用其中一个。无论两个 DMA 通道中哪个先完成,都会在不清除自身 DER 位的情况下完成 SPI 上下文,因此每次传输都会将一个请求使能泄漏到下一个请求中。
在 drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi_dma.c 中,transceive_dma() (:346) 中这两个位同时被启用:
if (channel == dma_data->dma_tx.channel) {
spi_mcux_issue_TCR(spi_dev);
dma_data->state = LPSPI_TRANSFER_STATE_TX_DONE;
base->DER &= ~LPSPI_DER_TDDE_MASK;
} else {
dma_data->state = LPSPI_TRANSFER_STATE_RX_DONE;
base->DER &= ~LPSPI_DER_RDDE_MASK;
}在 lpspi_dma_callback() 中,第一个完成的通道会清除它自己的位(:249–:253):
if (channel == dma_data->dma_tx.channel) {
spi_mcux_issue_TCR(spi_dev);
dma_data->state = LPSPI_TRANSFER_STATE_TX_DONE;
base->DER &= ~LPSPI_DER_TDDE_MASK;
} else {
dma_data->state = LPSPI_TRANSFER_STATE_RX_DONE;
base->DER &= ~LPSPI_DER_RDDE_MASK;
}如果我清除这两个位,所有交易似乎都能顺利完成,没有任何警告。以下是我使用的补丁。
@@ lpspi_dma_callback()
case LPSPI_TRANSFER_STATE_TX_DONE:
case LPSPI_TRANSFER_STATE_RX_DONE:
dma_data->state = LPSPI_TRANSFER_STATE_RX_TX_DONE;
/* TX and RX both done here. */
+ base->DER &= ~(LPSPI_DER_TDDE_MASK | LPSPI_DER_RDDE_MASK);
spi_context_complete(ctx, spi_dev, 0);
spi_context_cs_control(ctx, false);
break;
@@
error:
+ base->DER &= ~(LPSPI_DER_TDDE_MASK | LPSPI_DER_RDDE_MASK);
LOG_ERR("DMA callback error with channel %d.", channel);
spi_context_complete(ctx, spi_dev, ret);
spi_context_cs_control(ctx, false);附件是我使用的测试应用程序。该应用程序内置了上述解决方案。
我的问题是,驱动程序为什么只清除一个比特位,而不是两个比特位都清除?