some example code of SPI with DMA for Kinetics.

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

some example code of SPI with DMA for Kinetics.

2,980 Views
albertmartin
Contributor II

Hellow:

My problem is to implement a SPI master driver. Also I need to send this port many bytes (9600 bytes).

I implemented it on MK60FN1M0VMD12  by Keil environment and Processor Expert.

I can send it using a SPI by interruptions, but I would like to be able to use DMA.

This can not be done using the Processor Expert.

In addition I have seen that it is not possible to send bytes directly to the "PUSHR", because we must also complete "command information" for each byte.

Are there examples code to send a full buffer by DMA?

Is it possible without copying byte by byte with the command information?

Remember, we need to send a lot bytes continuously.

thank you!

0 Kudos
3 Replies

1,441 Views
egoodii
Senior Contributor III

It is at best 'very difficult' to 'cheat' on this expansion of TX SPI DMA buffer to 32-bits.  I just define the buffer that way, and make the buffer-filler 'know' to only work into the lower byte or half-word.  One place I used this was in a small monochrome-graphics display buffer that updates the actual display periodically with a DMA block-write.  You might also look into:

Using SPI/DMA on the K60.

0 Kudos

1,441 Views
albertmartin
Contributor II

I can create this code for DMA SPI:

//##############################################################

// * Start Tranfer Buffer to SPI.

//##############################################################

uint32_t DMA_DISP_Start_Transfer (uint32_t * Source, uint16_t Size)

{

   uint32_t u32ErrorStatus = 1;

   u32ErrorStatus = DMA0->INT; // CHECK COMPLETE LAST.

   SIM->SCGC6 |= SIM_SCGC6_DMAMUX0_MASK;    // Enable clock to DMA mux

   SIM->SCGC7 |= SIM_SCGC7_DMA_MASK;      // Enable clock to DMA

   DMA0->ERR |= (uint32_t) DMA_CHANEL_SPI_MASK; // Remove ERROR flags. // 0x0001

   DMA0->CEEI = (uint8_t) 0x00U; // Clear Disp Error Interrupt Register

   DMA0->CERQ = (uint8_t) 0x00U; // Clear Disp Request Register

   DMA0->CINT = (uint8_t) 0x00U;  // Clear Disp Interrupt Requests

   DMA0->CERR = (uint8_t) 0x00U; // Clear Disp Error Indicators

   // DMAMUX DMA_CHANEL_SPI

   DMAMUX0->CHCFG[DMA_CHANEL_SPI] = 0;     // reset DMAMUX0

   // for Chanel show: "Table 3-26. DMA request sources - MUX 0"  

   DMAMUX0->CHCFG[DMA_CHANEL_SPI] = DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(17); // Triger // 17: SPI0 Transmit

   DMA0->CERQ |= DMA_CERQ_CERQ(DMA_CHANEL_SPI); //to clear a given bit in the ERQ to disable the DMA request for a given channel

   DMA0->TCD[DMA_CHANEL_SPI].SADDR = (uint32_t) Source;

   DMA0->TCD[DMA_CHANEL_SPI].CSR &= (uint16_t) (~(uint16_t) (DMA_CSR_DONE_MASK)); // /* Clear DMA transfer done status flag. */

   DMA0->TCD[DMA_CHANEL_SPI].ATTR = DMA_ATTR_SSIZE(2) | DMA_ATTR_DSIZE(2); // 32-bit source and destiny

   DMA0->TCD[DMA_CHANEL_SPI].SOFF = 4;  //4 byte(32 bytes) offset between each source element

   DMA0->TCD[DMA_CHANEL_SPI].DOFF = 0;  //0 byte offset between each destination element

   DMA0->TCD[DMA_CHANEL_SPI].NBYTES_MLNO = 0x04; /* Transfer 4 bytes per transaction */

   DMA0->TCD[DMA_CHANEL_SPI].SLAST = 0x00;/* set last_sga to point to the TCD struct to be loaded at the end of the major loop */ // CHECK // AM

   DMA0->TCD[DMA_CHANEL_SPI].DADDR = (uint32_t) &(SPI0->PUSHR);

  

   DMA0->TCD[DMA_CHANEL_SPI].CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(Size); /* No link channel to channel, Size transaction */

   DMA0->TCD[DMA_CHANEL_SPI].BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(Size); /* No link channel to channel, Size transaction */

   DMA0->TCD[DMA_CHANEL_SPI].DLAST_SGA = 0x00; /* No adjustment to destination address */ //OR -0x0A

   DMA0->TCD[DMA_CHANEL_SPI].CSR = DMA_CSR_DREQ_MASK; // No link, //One transfer only./* Clear control status register. *///DisableAfterRequest

   // Interrupt.

   /* Transfer compete interrupt vector(s) priority setting */

   /* NVICIP0: PRI0=0xF0 */

   NVIC->IP[(uint32_t) DMA0_DMA16_IRQn] = (uint8_t) 0xF0; // LOW PRIORITY.

   /* NVICISER0: SETENA|=1 */

   NVIC_EnableIRQ(DMA0_DMA16_IRQn);  // Set DMA ISRs

   // Enable Complete Tranfer on DMA.

   DMA0->TCD[DMA_CHANEL_SPI].CSR |= DMA_CSR_INTHALF_MASK; // Complete Tranfer.

   // end Iterrupt.

   DMA0->ERQ = DMA_ERQ_ERQ0_MASK; // Start !!!!

   DMA0->SSRT = (uint8_t) DMA_SSRT_SSRT(DMA_CHANEL_SPI); // Start !!!!

   return (u32ErrorStatus);

}

//##############################################################

It is important to conmfigure SPI for Request to DMA.:

   SPI0->RSER |= SPI_RSER_TFFF_DIRS_MASK | SPI_RSER_TFFF_RE_MASK; // DMA

I hope you find it useful.

Alberto Martin.

0 Kudos

1,441 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Abert,

I'd highly recommend you to refer to this document about the SPI operation integrates with DMA.

And please review this doc through the link as below.

使用DMA降低SPI通信过程中内核负荷 Reduce core work load with DMA Module during SPI communication

Hope it helps.
Have a great day,
Ping

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos