HI,
I have TWRK60F120MUM tower board. I try to use DMA for SPI master transfer. It doesn't start DMA. Here is code:
LDD_TDeviceData* SM1_Init(LDD_TUserData *UserDataPtr)
{
SM1_TDeviceDataPtr DeviceDataPrv;
DeviceDataPrv = (SM1_TDeviceData *)_mem_alloc_system((_mem_size)sizeof(SM1_TDeviceData));
DeviceDataPrv->UserData = UserDataPtr; /* Store the RTOS device structure */
/* Interrupt vector(s) allocation */
DeviceDataPrv->TxCommand = 0x80010000U; /* Initialization of current Tx command */
DeviceDataPrv->ErrFlag = 0x00U; /* Clear error flags */
/* Clear the receive counters and pointer */
DeviceDataPrv->InpRecvDataNum = 0x00U; /* Clear the counter of received characters */
DeviceDataPrv->InpDataNumReq = 0x00U; /* Clear the counter of characters to receive by ReceiveBlock() */
DeviceDataPrv->InpDataPtr = NULL; /* Clear the buffer pointer for received characters */
/* Clear the transmit counters and pointer */
DeviceDataPrv->OutSentDataNum = 0x00U; /* Clear the counter of sent characters */
DeviceDataPrv->OutDataNumReq = 0x00U; /* Clear the counter of characters to be send by SendBlock() */
DeviceDataPrv->OutDataPtr = NULL; /* Clear the buffer pointer for data to be transmitted */
/* SIM_SCGC6: DSPI1=1 */
SIM_SCGC6 |= SIM_SCGC6_DSPI1_MASK;
/* Interrupt vector(s) priority setting */
/* NVICIP27: PRI27=0x80 */
NVICIP27 = NVIC_IP_PRI27(0x80);
/* NVICISER0: SETENA|=0x08000000 */
NVICISER0 |= NVIC_ISER_SETENA(0x08000000);
//PINS configuration ...
/* SPI1_MCR: MSTR=0,CONT_SCKE=0,DCONF=0,FRZ=0,MTFE=0,PCSSE=0,ROOE=1,??=0,??=0,PCSIS=1,DOZE=0,MDIS=0,DIS_TXF=0,DIS_RXF=0,CLR_TXF=0,CLR_RXF=0,SMPL_PT=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,HALT=1 */
SPI1_MCR = SPI_MCR_DCONF(0x00) |
SPI_MCR_ROOE_MASK |
SPI_MCR_PCSIS(0x01) |
SPI_MCR_SMPL_PT(0x00) |
SPI_MCR_HALT_MASK; /* Set Configuration register */
/* SPI1_MCR: MSTR=1,CONT_SCKE=0,DCONF=0,FRZ=0,MTFE=0,PCSSE=0,ROOE=1,??=0,??=0,PCSIS=1,DOZE=0,MDIS=0,DIS_TXF=1,DIS_RXF=1,CLR_TXF=1,CLR_RXF=1,SMPL_PT=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,HALT=1 */
SPI1_MCR = SPI_MCR_MSTR_MASK |
SPI_MCR_DCONF(0x00) |
SPI_MCR_ROOE_MASK |
SPI_MCR_PCSIS(0x01) |
//SPI_MCR_DIS_TXF_MASK |
//SPI_MCR_DIS_RXF_MASK |
SPI_MCR_CLR_TXF_MASK |
SPI_MCR_CLR_RXF_MASK |
SPI_MCR_SMPL_PT(0x00) |
SPI_MCR_HALT_MASK; /* Set Configuration register */
/* SPI1_CTAR0: DBR=1,FMSZ=7,CPOL=0,CPHA=1,LSBFE=0,PCSSCK=3,PASC=3,PDT=3,PBR=3,CSSCK=0,ASC=0,DT=0,BR=1 */
SPI1_CTAR0 = SPI_CTAR_DBR_MASK |
SPI_CTAR_FMSZ(0x07) |
SPI_CTAR_CPHA_MASK |
SPI_CTAR_PCSSCK(0x03) |
SPI_CTAR_PASC(0x03) |
SPI_CTAR_PDT(0x03) |
SPI_CTAR_PBR(0x03) |
SPI_CTAR_CSSCK(0x00) |
SPI_CTAR_ASC(0x00) |
SPI_CTAR_DT(0x00) |
SPI_CTAR_BR(0x01); /* Set Clock and Transfer Attributes register */
/* SPI1_SR: TCF=1,TXRXS=0,??=0,EOQF=1,TFUF=1,??=0,TFFF=1,??=0,??=0,??=0,??=1,??=0,RFOF=1,??=0,RFDF=1,??=0,TXCTR=0,TXNXTPTR=0,RXCTR=0,POPNXTPTR=0 */
SPI1_SR = SPI_SR_TCF_MASK |
SPI_SR_EOQF_MASK |
SPI_SR_TFUF_MASK |
SPI_SR_TFFF_MASK |
SPI_SR_RFOF_MASK |
SPI_SR_RFDF_MASK |
SPI_SR_TXCTR(0x00) |
SPI_SR_TXNXTPTR(0x00) |
SPI_SR_RXCTR(0x00) |
SPI_SR_POPNXTPTR(0x00) |
0x00200000U; /* Clear flags */
/* SPI1_RSER: TCF_RE=0,??=0,??=0,EOQF_RE=0,TFUF_RE=0,??=0,TFFF_RE=0,TFFF_DIRS=0,??=0,??=0,??=0,??=0,RFOF_RE=0,??=0,RFDF_RE=1,RFDF_DIRS=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0 */
_int_disable();
SPI1_RSER &= ~SPI_RSER_TFFF_RE_MASK;
SPI1_RSER |= SPI_RSER_TFFF_DIRS_MASK;
//Enable receive interrupt`
//SPI1_RSER &= ~SPI_RSER_RFDF_RE_MASK;
//SPI1_RSER &= ~SPI_RSER_RFDF_DIRS_MASK;
_int_enable();
SM1_SetClockConfiguration(DeviceDataPrv, Cpu_GetClockConfiguration()); /* Set Initial according speed CPU mode */
/* Registration of the device structure */
PE_LDD_RegisterDeviceStructure(PE_LDD_COMPONENT_SM1_ID,DeviceDataPrv);
return ((LDD_TDeviceData *)DeviceDataPrv); /* Return pointer to the data data structure */
}
LDD_TDeviceData* DMACH2_Init(LDD_TUserData *UserDataPtr)
{
// enable DMA and DMAMUX clock
SIM_SCGC6 |= SIM_SCGC6_DMAMUX0_MASK;
SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;
//////////////////////////////////////////
ChnInit2 = DMACH2_ChInit; //Initialize local copy of init. structure
// source configuration: Source will need to be updated in write to global buffer
ChnInit2.TCD.DMA_TCD_SADDR_Reg = DMA_SADDR_SADDR(UserDataPtr); //empty needs to be set: needwork
ChnInit2.TCD.DMA_TCD_SOFF_Reg = 4; //Source address increment: 4 bytes increment needed
ChnInit2.TCD.DMA_TCD_SLAST_Reg = 0; //Source address reload after major loop finishes: no reload needed
ChnInit2.TCD.DMA_TCD_ATTR_Reg = DMA_ATTR_SSIZE(2) | DMA_ATTR_DSIZE(2);//SSIZE and DSIZE are 2 SMOD is 0
// destination configuration
ChnInit2.TCD.DMA_TCD_DADDR_Reg = (uint32_t)&(SPI1_PUSHR);
ChnInit2.TCD.DMA_TCD_DOFF_Reg = 0;
ChnInit2.TCD.DMA_TCD_DLASTSGA_Reg = 0; //in Bytes : reload after major loop finishes
//Loop interation numbers
// set CITER and BITER to maximum value
ChnInit2.TCD.DMA_TCD_BITER_Reg = DMA_BITER_ELINKNO_BITER (1); //Number of DWORDs of Tx Buffer
ChnInit2.TCD.DMA_TCD_CITER_Reg = DMA_CITER_ELINKNO_CITER (1); //Number of DWORDs of Tx Buffer
ChnInit2.TCD.DMA_TCD_NBYTES_Reg = 4; //4 bytes in minor loop
// enable auto close request
ChnInit2.TCD.DMA_TCD_CSR_Reg = 0; //disale ELINK
ChnInit2.TCD.DMA_TCD_CSR_Reg |= DMA_CSR_DREQ_MASK;
ChnDevDataPtr = DMA1_InitChannel(DevDataPtr, (DMA1_TChnInit *)(void *)&ChnInit2, UserDataPtr);
return (ChnDevDataPtr);
}
uint8_t Spi1_Trigger(void) {
SPI1_MCR |= SPI_MCR_CLR_RXF_MASK | // clear rx FIFO
SPI_MCR_CLR_TXF_MASK ; // clear tx FIFO
DMA_TCD2_BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(1);
DMA_TCD2_CITER_ELINKNO = DMA_TCD2_BITER_ELINKNO;
DMA_ERQ |= DMA_ERQ_ERQ2_MASK; // DMA will respond to SPI SPI tx (TFFF) requests
//SPI1_RSER |= SPI_RSER_RFDF_RE_MASK; //enable the tx fifo fill interrupt for DMA use
SPI1_RSER |= SPI_RSER_TFFF_RE_MASK; //enable the tx fifo fill interrupt for DMA use
SPI1_MCR &= ~SPI_MCR_HALT_MASK; // halt disable
return ERROR_OK;
}
Code Sequence:
1. SM1_Init () is called to initalize SPI Master (SPI1)
2. Setup DMA for SPI1 by calling DMACH2_INIT()
DMA channel 2 (Static channel )
3. Call Spi1_Trigger() to start transfer.
nothing happens.
Can you help me review the code and point out what is missing?
Thank you
David Zhou
HI,
DMA is working, it transfers the bytes as specified.
But only one thing needs your help:
Both DMA TX complete and DMA RX complete interrupts are not called. Here is the setup for the interupts:
1. PE generated code: Interrupt is enabled for both DMA channels (SPI1_TX DMA request, and SPI1 RX DMA request)
2. in DMA controller PE generated code: DMACH2 for RX and DMACH3 for TX : both interrupts are registered:
DevDataPtr->SavedISRSettings_DMA1_INT_DMA2_DMA18_TransferComplete_ISR.isrData = _int_get_isr_data(LDD_ivIndex_INT_DMA2_DMA18);
DevDataPtr->SavedISRSettings_DMA1_INT_DMA2_DMA18_TransferComplete_ISR.isrFunction = _int_install_isr(LDD_ivIndex_INT_DMA2_DMA18, DMA1_INT_DMA2_DMA18_TransferComplete_ISR, DevDataPtr);
/* Transfer complete interrupt vector(INT_DMA3_DMA19) allocation */
/* {MQX RTOS Adapter} Save old and set new interrupt vector (function handler and ISR parameter) */
/* Note: Exception handler for interrupt is not saved, because it is not modified */
DevDataPtr->SavedISRSettings_DMA1_INT_DMA3_DMA19_TransferComplete_ISR.isrData = _int_get_isr_data(LDD_ivIndex_INT_DMA3_DMA19);
DevDataPtr->SavedISRSettings_DMA1_INT_DMA3_DMA19_TransferComplete_ISR.isrFunction = _int_install_isr(LDD_ivIndex_INT_DMA3_DMA19, DMA1_INT_DMA3_DMA19_TransferComplete_ISR, DevDataPtr);
3. DMA Mux has interrupt ISR initialized: (for both DMACH2 and DMACH3)
/* DMAMUX initial settings */
(DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(0x12)), /* DMA multiplexor configuration register initial value 'SPI1_Receive_DMA_Request' */
{ /* Events initial setting */
&DMACH2_OnComplete, /* OnComplete callback address */
&DMACH2_OnError /* OnComplete callback address */
}
4. DMA_CSR_INTMAJOR_MASK are set for both TCD.DMA_TCD_CSR_Reg
5. DMAs are started
DMA_ERQ |= DMA_ERQ_ERQ2_MASK; | // DMA will respond to SPI SPI Rx (RDRF) requests | ||
DMA_ERQ |= DMA_ERQ_ERQ3_MASK; | // DMA will respond to SPI SPI tx (TFFF) requests |
SPI1_MCR &= ~SPI_MCR_HALT_MASK;
6. 5 bytes to TX and to RX:
DMA_TCD2_BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(5);
DMA_TCD2_CITER_ELINKNO = DMA_TCD2_BITER_ELINKNO;
DMA_TCD3_BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(5);
MA_TCD3_CITER_ELINKNO = DMA_TCD3_BITER_ELINKNO;
7. Operation completed (Tx-ed OK and RX-ed OK)
BUT both callback functions are not called
void DMACH3_OnComplete(LDD_TUserData *UserDataPtr) {
gdwSpiCmdSent++;
}
void DMACH2_OnComplete(LDD_TUserData *UserDataPtr) {
gdwSpiCmdReceived++;
}
What is still missing?
Thank you,
David Zhou
This is working now. Please close this tick for me.
Thank you,
David Zhou