工具与软件:
各位专家、您好!
我必须通过 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