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!
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:
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.
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!
-----------------------------------------------------------------------------------------------------------------------