Hi,
My goal is to setup a DAC to output a value with a known, consistent update rate.
I'm trying to use the Config Tools, Peripherals tool to setup a SPI transmit via DMA on a Periodic Interrupt Timer (PIT).
So far I've figured out:
const lpspi_master_config_t LPSPI4_config = {
.baudRate = 500000UL,
.bitsPerFrame = 16UL,
.cpol = kLPSPI_ClockPolarityActiveHigh,
.cpha = kLPSPI_ClockPhaseFirstEdge,
.direction = kLPSPI_MsbFirst,
.pcsToSckDelayInNanoSec = 1000UL,
.lastSckToPcsDelayInNanoSec = 1000UL,
.betweenTransferDelayInNanoSec = 1000UL,
.whichPcs = kLPSPI_Pcs0,
.pcsActiveHighOrLow = kLPSPI_PcsActiveLow,
.pinCfg = kLPSPI_SdiInSdoOut,
.dataOutConfig = kLpspiDataOutRetained
};
edma_handle_t LPSPI4_RX_Handle;
edma_handle_t LPSPI4_TX_Handle;
lpspi_master_edma_handle_t LPSPI4_handle;
static void LPSPI4_init(void) {
LPSPI_MasterInit(LPSPI4_PERIPHERAL, &LPSPI4_config, LPSPI4_CLOCK_FREQ);
/* Set the source kDmaRequestMuxLPSPI4Rx request in the DMAMUX */
DMAMUX_SetSource(LPSPI4_RX_DMAMUX_BASEADDR, LPSPI4_RX_DMA_CHANNEL, LPSPI4_RX_DMA_REQUEST);
/* Enable the channel 3 in the DMAMUX */
DMAMUX_EnableChannel(LPSPI4_RX_DMAMUX_BASEADDR, LPSPI4_RX_DMA_CHANNEL);
/* Set the source kDmaRequestMuxLPSPI4Tx request in the DMAMUX */
DMAMUX_SetSource(LPSPI4_TX_DMAMUX_BASEADDR, LPSPI4_TX_DMA_CHANNEL, LPSPI4_TX_DMA_REQUEST);
/* Set the DMA channel 2 periodic trigger */
DMAMUX_EnablePeriodTrigger(LPSPI4_TX_DMAMUX_BASEADDR, LPSPI4_TX_DMA_CHANNEL);
/* Enable the channel 2 in the DMAMUX */
DMAMUX_EnableChannel(LPSPI4_TX_DMAMUX_BASEADDR, LPSPI4_TX_DMA_CHANNEL);
/* Create the eDMA LPSPI4_RX_Handle handle */
EDMA_CreateHandle(&LPSPI4_RX_Handle, LPSPI4_RX_DMA_BASEADDR, LPSPI4_RX_DMA_CHANNEL);
/* Create the eDMA LPSPI4_TX_Handle handle */
EDMA_CreateHandle(&LPSPI4_TX_Handle, LPSPI4_TX_DMA_BASEADDR, LPSPI4_TX_DMA_CHANNEL);
LPSPI_MasterTransferCreateHandleEDMA(LPSPI4_PERIPHERAL, &LPSPI4_handle, LPSPI4_MasterUserCallback, NULL, &LPSPI4_RX_Handle, &LPSPI4_TX_Handle);
LPSPI_MasterTransferEDMA(EXAMPLE_LPSPI_MASTER_BASEADDR, &g_m_edma_handle, &masterXfer);
My question is, do I use LPSPI_Master_transferEDMA() or a similar function somewhere to initiate the transfers that should be triggered by the PIT interrupt? If so, where does that function get placed (for example, does it belong in a PIT interrupt handler?) Or is one of the pointers setup in peripherals.c already intended to point to the transfer data?
iMXRT1060
已解决! 转到解答。
Hi @Miguel04
I have this now working as expected.
My question is, do I use LPSPI_Master_transferEDMA()or a similar function somewhere to initiate the transfers that should be triggered by the PIT interrupt? If so, where does that function get placed (for example, does it belong in a PIT interrupt handler?) Or is one of the pointers setup in peripherals.c already intended to point to the transfer data?
So, the answer is yes, use LPSPI_Master_transferEDMA() in the application code. With the PIT peripheral configured, and the SPI peripheral set to Periodic Trigger Enable, the data will begin transferring when the PIT is started with PIT_StartTimer(). Once started, the SPI packets will be transmitted with the CS asserting at the rate specified in the PIT configuration. This all seems to work without any interrupt service routine code.
The problem I was encountering was:
lpspi_transfer_t masterXfer;
masterXfer.configFlags = kLPSPI_Pcs0;
and it seems it should have been:
masterXfer.configFlags = kLPSPI_MasterPcs0;
Hi @Miguel04
I have this now working as expected.
My question is, do I use LPSPI_Master_transferEDMA()or a similar function somewhere to initiate the transfers that should be triggered by the PIT interrupt? If so, where does that function get placed (for example, does it belong in a PIT interrupt handler?) Or is one of the pointers setup in peripherals.c already intended to point to the transfer data?
So, the answer is yes, use LPSPI_Master_transferEDMA() in the application code. With the PIT peripheral configured, and the SPI peripheral set to Periodic Trigger Enable, the data will begin transferring when the PIT is started with PIT_StartTimer(). Once started, the SPI packets will be transmitted with the CS asserting at the rate specified in the PIT configuration. This all seems to work without any interrupt service routine code.
The problem I was encountering was:
lpspi_transfer_t masterXfer;
masterXfer.configFlags = kLPSPI_Pcs0;
and it seems it should have been:
masterXfer.configFlags = kLPSPI_MasterPcs0;
Hi @matt0x000C
Yes you can call the LPSPI_Master_transferEDMA() function on the PIT interrupt handler or you can use a boolean variable that is toggled when the PIT interrupt happens and then call LPSPI_Master_transferEDMA().
My recommendation are:
Let me know if you have another question.
Best Regards, Miguel.
Hi, thanks for getting back to me!
Ok, so if I use a boolean set by the PIT interrupt handler, I have something like this:
if (PIT_GetStatusFlags(PIT, kPIT_Chnl_0) == kPIT_TimerFlag) // if the interrupt triggered...
{
DAC_Load_Pin_Toggle();
// Send the next DAC value to its register over SPI
isTransferCompleted = false;
LPSPI_MasterTransferEDMA(LPSPI4_PERIPHERAL, &LPSPI4_handle, &masterXfer);
PIT_ClearStatusFlags(PIT, kPIT_Chnl_0, kPIT_TimerFlag); // clear the interrupt flag
// Wait until transfer completed
while (!isTransferCompleted)
{
}
}
The problem with this method is the time from when the DAC_Load_Toggle() to when the SPI transfer initiates is about 100us. So, if I want to set a GPIO bit and send 16bits via SPI, it seems I will be limited to a 100us update rate (unless I'm doing something wrong?).
Looking at this forum post it seems like there is a way to just link the DMA to the SPI output via the PIT without processor intervention, but I can't seem to get this method to work.
Hi @matt0x000C
I'll look into this and let you know what I found, meanwhile if you can share with me more details of what you did and why you think you are missing would help. Also I found this other posts that could help you.
Best Regards, Miguel.