SPI Master - DMA Transfer

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

SPI Master - DMA Transfer

1,227 Views
davidzhou
Contributor V

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

0 Kudos
2 Replies

470 Views
davidzhou
Contributor V

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

0 Kudos

470 Views
davidzhou
Contributor V

This is working now. Please close this tick for me.

Thank you,

David Zhou

0 Kudos