工具与软件:
各位专家、您好!
我必须通过 SPI + DMA 将 MSPM0G3507与 FRAM (MB85RS256B)开发通信。 FRAM 数据表的第9页包含文本"..."RISED CS 将终止写入命令。 但是、如果在 CS 上升之前继续发送每8位写入数据、则可以继续以自动地址递增进行写入。
我能够在没有 DMA 的情况下向 FRAM 写入单个值或从 FRAM 读取单个值。
我开始使用示例 spi_controller_repeed_fifo_dma_interrupts_LP_MSPM0G3507_nortos_ticlang、唯一的更改是:SPI 时钟、SPI 引脚和设置3线 SPI (使用 GPIO 控制 CS)。 我停止所有 DMA 配置。
引用布鲁斯·麦肯尼的话、我知道"SPI 本质上是全双工的--对于你传输的每一个字节、你都会收到一个;而在这种情况下、如果你想要接收一个字节、你必须发送一个字节。 我们指的是"仅传输"和"仅接收"交易、但这些交易仅意味着另一端对数据不感兴趣。"
我的应用程序将需要写和读取大量的数据,但目前我正在用30个样本进行测试(婴儿步骤)。 因此、我将我的代码分为两部分:
第1)部分)将数据写入 FRAM:我调整了 gTxPacket 以纳入操作码(WREN 和写入)、起始地址和需要写入的数据。 此外、gTxPacket 采用单字节格式(uint8_t)。
我对来自 RXFIFO 及其回收站的数据不感兴趣。
写入部分看起来可以、我有一个在传输开始时计数为1的计时器。 我在示波器上检查了 CS、CLK 和 PICO。 CLK 很难看出、CS 在低电平时持续~16us、我知道在没有 DMA 的情况下写入16位需要~6.6us。
第2部分)从 FRAM 读取数据:我调整了 gTxDummy、以合并操作码(读取)、起始地址和需要写入的虚拟数据、从而生成时钟。 此外、gTxDummy 采用一字节格式(uint8_t)。
读取部分看起来不正常。 我对来自 RXFIFO 的数据非常感兴趣,但当我检查我的 gRxPacket 时,它在每个位置都有255 (0xFF)(我在 main ()的开头清除它)。 它应具有与 gTxPacket 相同的内容。
void SPI_send(void)
{
// Part 1: writing data to FRAM
/*
* Configure DMA source, destination and size to transfer data from
* gTxPacket to TXDATA. The DMA transfer will start when TX interrupt is
* set, which it should already be set (which indicates that the SPI is
* ready to transfer) so the DMA will begin this transfer when the channel
* is enabled.
*/
DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t) &gTxPacket[0]);
DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t)(&SPI_0_INST->TXDATA));
DL_DMA_setTransferSize(
DMA, DMA_CH0_CHAN_ID, sizeof(gTxPacket) / sizeof(gTxPacket[0]));
/*
* Configure DMA source, destination and size from RXDATA to gRxPacket.
* The DMA transfer will start when the RX interrupt is set, which happens
* when the device receives data.
*/
DL_DMA_setSrcAddr(DMA, DMA_CH1_CHAN_ID, (uint32_t)(&SPI_0_INST->RXDATA));
DL_DMA_setDestAddr(DMA, DMA_CH1_CHAN_ID, (uint32_t) &gRxPacket[0]);
DL_DMA_setTransferSize(DMA, DMA_CH1_CHAN_ID, ARRAY_SIZE);
DL_GPIO_clearPins(GPIO_PORT, GPIO_CS_SPI_PIN);
/*
* The SPI TX interrupt is already set, indicating the SPI is ready to
* transmit data, so enabling the DMA will start the transfer
*/
DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID);
DL_DMA_enableChannel(DMA, DMA_CH1_CHAN_ID);
/*
* Wait in SLEEP mode until SPI_PACKET_SIZE bytes have been transferred
* from gTxPacket to the SPI TXFIFO, and the DMA interrupt is triggered
*/
while (false == isDMATXDataTransferred) {
__WFE();
}
/*
* Wait until the SPI has transmitted all the data and the TXFIFO
* is empty
*/
while (false == isSPIDataTransmitted) {
__WFE();
}
/*
* Wait in SLEEP mode until SPI_PACKET_SIZE bytes have been transferred
* from SPI TXFIFO to gRxPacket, and the DMA interrupt is triggered
*/
while (false == isDMARXDataTransferred) {
__WFE();
}
/*
* Optional SW breakpoint to check results.
* If this example is used with the
* spi_peripheral_repeated_fifo_dma_interrupts example,
* the expected data that will be received in gRxPacket is
* {'x', 0x2, 0x3, 0x4}, where 'x' starts at 0x0 and
* should increment every time the Peripheral example
* sends a new data packet.
*/
// __BKPT(0);
isSPIDataTransmitted = false;
isDMATXDataTransferred = false;
isDMARXDataTransferred = false;
DL_GPIO_setPins(GPIO_PORT, GPIO_CS_SPI_PIN);
// Part 2: reading data from FRAM
// Sugestion from Chris e2e.ti.com/.../mspm0g3507-cant-get-spi-to-automatically-clock-in-receive-data-in-dma-mode
/*
* Configure DMA source, destination and size to transfer data from
* tx_pbuf to TXDATA. The DMA transfer will start when TX interrupt is
* set, which it should already be set (which indicates that the SPI is
* ready to transfer) so the DMA will begin this transfer when the channel
* is enabled.
*/
DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t) &gTxDummy[0]);
DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t)(&SPI_0_INST->TXDATA));
DL_DMA_setTransferSize(
DMA, DMA_CH0_CHAN_ID, sizeof(gTxDummy) / sizeof(gTxDummy[0]));
NVIC_EnableIRQ(SPI_0_INST_INT_IRQN);
// enable chip select
DL_GPIO_setPins(GPIO_PORT, GPIO_CS_SPI_PIN);
/*
* The SPI TX interrupt is already set, indicating the SPI is ready to
* transmit data, so enabling the DMA will start the transfer
*/
DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID);
/*
* Wait in SLEEP mode until SPI_PACKET_SIZE bytes have been transferred
* from tx_pbuf to the SPI TXFIFO, and the DMA interrupt is triggered
*/
while (false == isDMATXDataTransferred) {
__WFE();
}
/*
* Wait until the SPI has transmitted all the data and the TXFIFO
* is empty
*/
while (false == isSPIDataTransmitted) {
__WFE();
}
// dummy read clears spi data waiting interrupt caused by spi tx
DL_SPI_receiveData8(SPI_0_INST);
/*
* Configure DMA source, destination and size from RXDATA to rx_pbuf.
* The DMA transfer will start when the RX interrupt is set, which happens
* when the device receives data.
*/
DL_DMA_setSrcAddr(DMA, DMA_CH1_CHAN_ID, (uint32_t)(&SPI_0_INST->RXDATA));
DL_DMA_setDestAddr(DMA, DMA_CH1_CHAN_ID, (uint32_t) &gRxPacket[0]);
DL_DMA_setTransferSize(DMA, DMA_CH1_CHAN_ID, ARRAY_SIZE);
DL_DMA_enableChannel(DMA, DMA_CH1_CHAN_ID);
/*
* Wait in SLEEP mode until SPI_PACKET_SIZE bytes have been transferred
* from SPI TXFIFO to rx_pbuf, and the DMA interrupt is triggered
*/
/*while ((false == gDMARXDataTransferred) && (ARRAY_SIZE > 0)) {
// generates sclks until ARRAY_SIZE requested number of bytes have been read
DL_SPI_transmitData8(SPI_0_INST, 0x00);
}*/
}
void SPI_0_INST_IRQHandler(void)
{
switch (DL_SPI_getPendingInterrupt(SPI_0_INST)) {
case DL_SPI_IIDX_DMA_DONE_TX:
/* DMA is done transferring data from gTxPacket to TXFIFO */
isDMATXDataTransferred = true;
break;
case DL_SPI_IIDX_TX_EMPTY:
/* SPI is done transmitting data and TXFIFO is empty */
isSPIDataTransmitted = true;
break;
case DL_SPI_IIDX_DMA_DONE_RX:
/* DMA is done transferring data from RXFIFO to gRxPacket*/
isDMARXDataTransferred = true;
default:
break;
}
}
我查看了此处的其他文章(e2e.ti.com/.../mspm0g3507-cant-get-spi-to-automatically-clock-in-receive-data-in-dma-mode)。 我实施了它,但解决方案克里斯善意地建议也不工作。
我还检查了:
e2e.ti.com/.../mspm0g3507-dma-enabled-spi-communication-with-ads8684a
e2e.ti.com/.../mspm0g3507-spi-dma-receive-abnormal
e2e.ti.com/.../ads1258-ep-using-dma-with-ads1258
请,有人可以给我任何建议或建议,以修复我的阅读部分代码?
谢谢!
Andrea

