Getting PIT to trigger SPI DMA transmit to a DAC (i.mxrt 1060)

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

Getting PIT to trigger SPI DMA transmit to a DAC (i.mxrt 1060)

ソリューションへジャンプ
1,134件の閲覧回数
matt0x000C
Contributor II

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:

  1. Using the config tools Peripherals tool, I have my LPSPI channel configured, my DMA channel configured, and a PIT configured. It generates a nice peripherals.c for me: 

 

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);​

 

  • I've looked at the lpspi_edma_b2b_transfer_master SDK example, and from that I see 

 

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 

 

ラベル(1)
0 件の賞賛
返信
1 解決策
972件の閲覧回数
matt0x000C
Contributor II

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;

 

元の投稿で解決策を見る

タグ(5)
0 件の賞賛
返信
4 返答(返信)
973件の閲覧回数
matt0x000C
Contributor II

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;

 

タグ(5)
0 件の賞賛
返信
1,111件の閲覧回数
Miguel04
NXP TechSupport
NXP TechSupport

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:

  1. To avoid any configuration issues, use the SDK drivers and configuration.
  2. Test indiviudally every peripheral to find pissible errors easier and then do your tests with all the project together.

Let me know if you have another question.

Best Regards, Miguel.

 

0 件の賞賛
返信
1,087件の閲覧回数
matt0x000C
Contributor II

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.

0 件の賞賛
返信
1,053件の閲覧回数
Miguel04
NXP TechSupport
NXP TechSupport

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.

AN4639

Post1

Post2

Post3

Best Regards, Miguel.

0 件の賞賛
返信