AnsweredAssumed Answered

S32K144 DMA modulo

Question asked by arkadyosh on Nov 12, 2019
Latest reply on Nov 21, 2019 by arkadyosh

Hello,
I have problem with DMA and FTM. I used this combination to catch data from FTM registers to struct when signal on input pin changed(falling and rising edge). From time to time, very rarely, I have situation when I get interrupt from DMA but no data inside struct which is destination of DMA transfer. I cant't find scenario to reproduce it in release, but in debug mode with connected JLink when I pause the code, when signal on input pin is still changing, and resume it, problem arrives. DMA destination configured with modulo option. When I used configuration without circular buffer(modulo for destination) I can stop and pause code as many times as I want and this never happened.

Below some sample code. Any solution where is the problem?

 

#define CHANNELS_NO (8)

#define DMA_EDGE_MAX_COUNT (4)

 

typedef struct
{

struct
{
uint32_t cnsc;
uint32_t cnv;
}values[DMA_EDGE_MAX_COUNT ];
}str_data_ctrl;

 

volatile str_data_ctrl data_ctrl[CHANNELS_NO] __attribute__((aligned(32)));

 

void test_Init(void)
{

PORTC->PCR[15] &= ~PORT_PCR_MUX_MASK;
PORTC->PCR[15] |= PORT_PCR_MUX(2); // FTM1 CH3

 

// DMA configuration

DMAMUX->CHCFG[2] = 0;
DMAMUX->CHCFG[2] |= DMAMUX_CHCFG_SOURCE(EDMA_REQ_FTM1_CHANNEL_3);

DMAMUX->CHCFG[2] |= DMAMUX_CHCFG_ENBL_MASK;


DMA->TCD[2].SADDR = DMA_TCD_SADDR_SADDR(&(FTM1->CONTROLS[3].CnSC));
DMA->TCD[2].SOFF = DMA_TCD_SOFF_SOFF(1); // Src addr add x byte after transfer
DMA->TCD[2].ATTR = DMA_TCD_ATTR_SMOD(0) | // Src modulo feature not used
DMA_TCD_ATTR_SSIZE(0) | // Src read 8bit
DMA_TCD_ATTR_DMOD(5) | // Dest modulo feature not used
DMA_TCD_ATTR_DSIZE(0); // Dest 8bit
DMA->TCD[2].NBYTES.MLNO = DMA_TCD_NBYTES_MLNO_NBYTES(8); // Transfer N byte /minor loop
DMA->TCD[2].SLAST = DMA_TCD_SLAST_SLAST(-8); // Src addr change after major loop
DMA->TCD[2].DADDR = DMA_TCD_DADDR_DADDR(&data_ctrl[2].values[0].cnsc);// Dest.
DMA->TCD[2].DOFF = DMA_TCD_DOFF_DOFF(1); // dest adr offset after transfer
DMA->TCD[2].CITER.ELINKNO = DMA_TCD_CITER_ELINKNO_CITER(1) | // n minor loop iterations
DMA_TCD_CITER_ELINKNO_ELINK(0); // No minor loop chan link
DMA->TCD[2].DLASTSGA = DMA_TCD_DLASTSGA_DLASTSGA(0); // dest chg after major loop
DMA->TCD[2].CSR = DMA_TCD_CSR_START(0) | // Clear START status flag
DMA_TCD_CSR_INTMAJOR(1) | // IRQ after major loop
DMA_TCD_CSR_INTHALF(0) | // No IRQ after 1/2 major loop
DMA_TCD_CSR_DREQ(0) | // Disable chan after major loop
DMA_TCD_CSR_ESG(0) | // Disable Scatter Gather
DMA_TCD_CSR_MAJORELINK(0) | // No major loop chan link
DMA_TCD_CSR_ACTIVE(0) | // Clear ACTIVE status flag
DMA_TCD_CSR_DONE(0) | // Clear DONE status flag
DMA_TCD_CSR_MAJORLINKCH(0) | // Chan # if major loop ch link
DMA_TCD_CSR_BWC(0); // No eDMA stalls after R/W

DMA->TCD[2].BITER.ELINKNO = DMA_TCD_BITER_ELINKNO_BITER(1) | // Initial iteration count
DMA_TCD_BITER_ELINKNO_ELINK(0); // No minor loop chan link

DMA->SERQ = DMA_SERQ_SERQ(2); // start dma
DMA->SEEI = DMA_SEEI_SEEI(2); // enable error interrupt for channel

 

INT_SYS_ClearPending(DMA0_IRQn + 2);
INT_SYS_EnableIRQ(DMA0_IRQn + 2);

 

// TIMER configuration

FTM1->MODE |= FTM_MODE_WPDIS_MASK; // disable wr protect

FTM1->MODE &= ~FTM_MODE_FTMEN_MASK; // disable FTM

FTM1->SYNC |= FTM_SYNC_SYNCHOM_MASK; // mask channels outputs

FTM1->MOD = 0xFFFF;

FTM1->CNTIN = 0;

FTM1->CONTROLS[3].CnSC = FTM_CnSC_CHIE(1) | // channel interrupt enable FTM_CnSC_DMA_MASK | // DMA FTM_CnSC_MSB(0) | // mode select

FTM_CnSC_MSA(0) | // mode select

FTM_CnSC_ELSB(1) | // edge/level select

FTM_CnSC_ELSA(1);// edge/level select

 

FTM1->CONTROLS[3].CnV = 0;

FTM1->CNT = 0;

 

FTM1->SYNC &= ~FTM_SYNC_SYNCHOM_MASK; // mask channels outputs
FTM1->MODE |= FTM_MODE_FTMEN_MASK | FTM_MODE_FAULTM(2) | FTM_MODE_FAULTIE_MASK;
FTM1->SC = FTM_SC_TOIE(1) | // overflow interrupt enable
FTM_SC_PS(3); // prescaler = 8
FTM1->SC |= FTM_SC_CLKS(3);

 

INT_SYS_ClearPending(FTM1_Fault_IRQn);
INT_SYS_EnableIRQ(FTM1_Fault_IRQn);

 

INT_SYS_ClearPending(FTM1_Ch2_Ch3_IRQn);

INT_SYS_EnableIRQ(FTM1_Ch2_Ch3_IRQn);

 

}

 

void DMA2_IRQHandler(void)
{
DMA->CINT = DMA_CINT_CINT(2); // clear int.

int cnsc_cnt = 0;
int cnt = 0;
while(cnt < DMA_EDGE_MAX_COUNT )
{
if( data_ctrl[2].values[cnt].cnsc > 0)
{
cnsc_cnt++;
if( (data_ctrl[2].values[cnt].cnsc & FTM_CnSC_CHIS_MASK) != FTM_CnSC_CHIS_MASK) // falling edge
{
// do something
}
else // rising edge
{
// do something
}
}
data_ctrl[2].values[cnt].cnsc = 0;
data_ctrl[2].values[cnt].cnv = 0;
cnt++;
}

if(cnsc_cnt == 0)
PIN_TOGGLE; // this should never happen
}

Outcomes