Code hangs in DMA interrupt for UART receive

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

Code hangs in DMA interrupt for UART receive

1,526 Views
s32k146_ige
Contributor IV

I am using DMA for UART receive interrupt. I have configured DMA as per example code provided to me from NXP team. The code has one issue, sometimes the code continuously loops in DMA interrupt. The uart interrupt is configured for IDLE timeout.

Following is code provided and just modified for UART1,

void DMA_init(void)
{
 /* This is an initialization place holder for:   											*/
 /* 1. Enabling DMA MUX clock PCC_PCCn[PCC_DMAMUX_INDEX] (not needed when START bit used) 	*/
 /* 2. Enabling desired channels by setting ERQ bit (not needed when START bit used) 		*/

      PCC->PCCn[PCC_DMAMUX_INDEX] |= PCC_PCCn_CGC_MASK;    // CGC=1: Clock enabled for DMAMUX0

	  DMAMUX->CHCFG[DMA_CHANNEL_LPUART0_RX] &= ~ DMAMUX_CHCFG_ENBL(1);         // Disabling the DMA channel
	  DMAMUX->CHCFG[DMA_CHANNEL_LPUART0_RX] |= DMAMUX_CHCFG_SOURCE(4);         // LPUART1 RX is the source of the DMA0 channel
	  DMAMUX->CHCFG[DMA_CHANNEL_LPUART0_RX] |= DMAMUX_CHCFG_ENBL(1);           // Enabling the DMA channel

	  DMA->ERQ |= 1;//Enable Channel 0.

//	  DMAMUX->CHCFG[1] &= ~ DMAMUX_CHCFG_ENBL(1);         // Disabling the DMA channel
//	  DMAMUX->CHCFG[1] |= DMAMUX_CHCFG_SOURCE(3);        // LPUART0 TX is the source of the DMA0 channel
//	  DMAMUX->CHCFG[1] |= DMAMUX_CHCFG_ENBL(1);           // Enabling the DMA channel
}

void DMA_TCD_init(void)
{
	/*!
	 * TCD0: Transfers string to a single memory location
	 * ===================================================
	 */
  DMA->TCD[DMA_CHANNEL_LPUART0_RX].SADDR        = DMA_TCD_SADDR_SADDR((uint32_t volatile) &LPUART1->DATA); /* Source Address. */
  DMA->TCD[DMA_CHANNEL_LPUART0_RX].SOFF         = DMA_TCD_SOFF_SOFF(0);   /* Src. addr add 0 byte after Transfers   */
  DMA->TCD[DMA_CHANNEL_LPUART0_RX].ATTR         = DMA_TCD_ATTR_SMOD(0)  | /* Src. modulo feature not used */
                                                  DMA_TCD_ATTR_SSIZE(0) | /* Src. read 2**0 =1 byte per transfer */
                                                  DMA_TCD_ATTR_DMOD(0)  | /* Dest. modulo feature not used */
                                                  DMA_TCD_ATTR_DSIZE(0);  /* Dest. write 2**0 =1 byte per trans. */

  DMA->TCD[DMA_CHANNEL_LPUART0_RX].NBYTES.MLNO  = DMA_TCD_NBYTES_MLNO_NBYTES(1); /* Transfer 1 byte /minor loop */
  DMA->TCD[DMA_CHANNEL_LPUART0_RX].SLAST        = DMA_TCD_SLAST_SLAST(0); 		/* Src addr change after major loop */

  DMA->TCD[DMA_CHANNEL_LPUART0_RX].DADDR        = DMA_TCD_DADDR_DADDR(pRxBuff);	/* Destination Address. */
  DMA->TCD[DMA_CHANNEL_LPUART0_RX].DOFF         = DMA_TCD_DOFF_DOFF(1);     			/* Dest adr offset 1 byte after transfer */
  DMA->TCD[DMA_CHANNEL_LPUART0_RX].CITER.ELINKNO= DMA_TCD_CITER_ELINKNO_CITER(MAX_BYTE_PER_TRANSFER) | 	/*  minor loop iterations */
		  	  	  	                              DMA_TCD_CITER_ELINKNO_ELINK(0);   	/* No minor loop chan link */

  DMA->TCD[DMA_CHANNEL_LPUART0_RX].DLASTSGA     = DMA_TCD_DLASTSGA_DLASTSGA(0); /* No dest chg after major loop */
  DMA->TCD[DMA_CHANNEL_LPUART0_RX].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(1)        |  /* 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[DMA_CHANNEL_LPUART0_RX].BITER.ELINKNO= DMA_TCD_BITER_ELINKNO_BITER(MAX_BYTE_PER_TRANSFER) |  /* Initial iteration count */
                                                  DMA_TCD_BITER_ELINKNO_ELINK(0);    /* No minor loop chan link */
}

 

#define MAX_BYTE_PER_TRANSFER 512, i tried increasing this to 768

Max data that is receive on UART is 427 bytes.

UART int handler

void uart1_irqHandler()
{
	uint8_t lu8Data = 0;
	LPUART_Type * base = LPUARTx[1];
	if (base->STAT & LPUART_STAT_RDRF_MASK)
	{
          // receive data from uart if dma is disabled
        	lu8Data = base->DATA;	// type cast to 8 bit data
              callback_uart1_rx(lu8Data , 1);
        }
// idle timeout
	if (base->STAT & LPUART_STAT_IDLE_MASK)
	{
		base->STAT |= LPUART_STAT_IDLE_MASK;		//clear the Idle flag.
		g_number_of_bytes_Received = MAX_BYTE_PER_TRANSFER - DMA->TCD[DMA_CHANNEL_LPUART0_RX].CITER.ELINKNO;//calculate the total received data.
               callback_uart1_rx(pRxBuff, g_number_of_bytes_Received );

		/* reset the DMA for LPUART reception*/
		DMA->TCD[DMA_CHANNEL_LPUART0_RX].CITER.ELINKNO = DMA_TCD_CITER_ELINKNO_CITER(MAX_BYTE_PER_TRANSFER) | 	/*  minor loop iterations */
				  	  	  	                            DMA_TCD_CITER_ELINKNO_ELINK(0);   	/* No minor loop chan link */
		DMA->TCD[DMA_CHANNEL_LPUART0_RX].DADDR         = DMA_TCD_DADDR_DADDR(pRxBuff);	/* Destination Address. */

        }
}

 If any help is provided for diagnosing this behavior that would be much helpful

Labels (1)
Tags (3)
0 Kudos
Reply
5 Replies

1,369 Views
s32k146_ige
Contributor IV

Dear @Robin_Shen

We have zeroed on problem cause, After much of debugging and analysis we are concluding that FTM Timer is causing issue, when ever we disable FTM timer and its interrupt we dont get issue, Code doesnt hang in DMA interrupt.

 

#define INTERRUPT_PRIORITY_LEVEL_ADC_TIMER 3

// FTM timer for 500us
ftm_state_t ftmStateStruct;

/* Initialize Flex Timer instance as simple timer */
FTM_DRV_Init(INST_FLEXTIMER_MC1, &flexTimer_mc1_InitConfig, &ftmStateStruct);

/* Install handler for the Timer overflow interrupt and enable it */
INT_SYS_InstallHandler(FTM0_Ovf_Reload_IRQn, &ftmTimerISR, (isr_t*) 0U);
INT_SYS_EnableIRQ(FTM0_Ovf_Reload_IRQn);
INT_SYS_SetPriority(FTM0_Ovf_Reload_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + INTERRUPT_PRIORITY_LEVEL_ADC_TIMER);

/* Setup the counter to trigger an interrupt every 500us*/
FTM_DRV_InitCounter(INST_FLEXTIMER_MC1, &flexTimer_mc1_TimerConfig);
/* Start the counter */
FTM_DRV_CounterStart(INST_FLEXTIMER_MC1);

 

Is there a way to resolve this ? it will be helpful if you can guide us to resolve this

0 Kudos
Reply

1,349 Views
s32k146_ige
Contributor IV

@Robin_Shen  I also think that either uart interrupt is no getting triggered and hence the dma isr is getting triggered as you say the buffer is overflown.

Tags (2)
0 Kudos
Reply

1,294 Views
Robin_Shen
NXP TechSupport
NXP TechSupport

Have you tried lowering the priority of other interrupts?

0 Kudos
Reply

1,501 Views
Robin_Shen
NXP TechSupport
NXP TechSupport

Hi

Does the unmodified project work normally?

The DMA0_IRQHandler mentioned that: in a idea situation, the DMA interrupt should never be entered. If the DMA interrupt entered, it means the received data exceeded the maxim rx buffer

Many of the codes you posted still include LPUART0. Will this problem also occur if you just replace LPUART0 to LPUART1?


Best Regards,
Robin

0 Kudos
Reply

1,484 Views
s32k146_ige
Contributor IV

the following are the uart0 variables that i feel it should not affect the working,

#define DMA_CHANNEL_LPUART0_RX 0
DMAMUX_CHCFG_SOURCE(4) is right value as i have check in excel from s32k146

4lpuartReceive DMA Requestlpuart1
5lpuartTransmit DMA Requestlpuart1


it just macro that is used to indicate DMA channel

i have increased this macro to #define MAX_BYTE_PER_TRANSFER 1024

and it still goes in DMA interrupt, and the sending slave device doesnt send more than 427 bytes in single frame, and interval between 2 frame is 5ms.

0 Kudos
Reply