This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430FR5989-EP: Reproduce errata DMA7

Part Number: MSP430FR5989-EP
Other Parts Discussed in Thread: MSP430FR5989

Hi,

I am trying to reproduce the error described in errata DMA7 of MSP430FR5989 microcontroller, which states that a if a DMA request starts executing during the time when a module register containing an interrupt flags is accessed with a read-modify-write instruction, a newly arriving interrupt from the same module can get lost.

What I have done so far is the following:

__root const UCHAR DmaSrcData[] = {
	0x02, 0x00
};
void main( void )
{
	InitializeHardware(); // initialize ports, clocks, pmm, etc.	
	
	// -------------- INIT TA1 ----------------------
	
	TA1CTL = TASSEL__ACLK
	         | ID__1
	         | MC__UP
	         | TACLR;

	TA1CCTL0 = !CAP	
		       | OUTMOD_0
		       | !CCIE;	

	TA1EX0 = TAIDEX_0;	/* divider /1 */

	// -------------- END INIT TA1 -------------------
	
	
	// -------------- INIT TB0 -----------------------
	TB0CTL = TBSSEL__ACLK
	         | ID__1
	         | MC__CONTINUOUS
	         | TBCLGRP_0
	         | CNTL_0
	         | TBCLR;

	TB0CCTL0 = !CAP	
	           | OUTMOD_0	
	           | CLLD_0
	           | !CCIE;

	TB0EX0 = TBIDEX_0;

	// -------------- END INIT TB0 -------------------
	

	// -------------- INIT DMA -----------------------
	// DMA is triggered by TA1CCR0 every 250ms. 
	// Source data has two values (0x02 and 0x00) used to alternate the destination port output value (P4.1)
	
	DMA1CTL_bit.DMAEN = false;

	DMACTL4_bit.DMARMWDIS = true;			

	DMACTL0 = ( DMACTL0 & ~DMA1TSEL_31 )
	          | DMA1TSEL__TA1CCR0;			

	DMA1CTL |= DMADT2							// Repeated single transfer
	           |  !DMADSTINCR0 | !DMADSTINCR1	// Destination address is not incremented
	           |  DMASRCINCR0 | DMASRCINCR1		// Source address is incremented
	           |  DMASRCBYTE
	           |  DMADSTBYTE
	           |  !DMALEVEL	
	           |  !DMAIFG
	           |  !DMAIE
	           |  !DMAABORT	
	           |  !DMAREQ;

	DMA1SA = ( void * )&DmaSrcData[0];
	DMA1DA = ( void * )&P4OUT;	
	DMA1SZ = 2;
	
	// -------------- END INIT DMA -----------------------	
	
	
	TA1CCTL0_bit.CCIFG = false;

	TB0CCR0 = TB0R + 2;	
	TB0CCTL0_bit.CCIFG = false;
	while ( !TB0CCTL0_bit.CCIFG ){
	}	
	
	// DMA trigger timer and TB0.0 synchronization
	TA0CTL |= TACLR;	// clears DMA timer counter
	TB0CCR0 += 8192 - 1; // 8192 ticks = 250ms. A tick is sutracted to start clearing the TB0CCTL0 30us before the DMA request
	TB0CCTL0_bit.CCIFG = false;
	
	// DMA is triggered every 250ms
	TA1CCR0 = 8192; // 8192 ticks = 250ms
	DMA1CTL_bit.DMAEN = true;	// starts DMA
	
	for (;;) {
		while ( !TB0CCTL0_bit.CCIFG ){
		}
		TB0CCR0 += 8192 + 1;
		P3OUT = 0x80;	// trace P3.7
		
		// Continuously clears the TB0CCTL0 interruption flag from 30 us before the dma trigger to about 30us after.
		// The idea of this is to perform a read-modify-write operation on a register containing 
		// an interruption flag at the same moment that the DMA is triggered.
		TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false;
		TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false;
		TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false;
		TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false;
		TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false;
		TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false;
		TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false;
		TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false;
		TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false;
		TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false;
		TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false;
		TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false;
		TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false;
		TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false;
		TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false; TB0CCTL0_bit.CCIFG = false;
		P3OUT = 0x00;	// trace P3.7
	}
}

The idea of this test is to trigger a DMA every 250ms (see Image1) and continuously perform read-modify-write operations (in this case, clear the TB0CCTL0 interrupt flag) from 30us before the DMA trigger until about 30us after the trigger to make sure there is a DMA request at the same time that the register is accessed. A trace is set before starting read-modify-write operations and cleared at the end of this process (see images 1 and 2). If, at any time, the trace period is about 2 seconds instead of 250ms, this would mean that an interrupt flag has been missed.

In the following images, CH1 (orange) is the trace signal (P3.7) and CH2 (blue) is the DMA destination port (P4.1).

Image 1: 

  

Image 2:

Read-modify-write operations are started 30us before the DMA trigger and stopped 30us after it.

I've left the code running for about 1 day now with no luck, which makes me think I might not be meeting the conditions of the errata.

Is this test correct? If not, what else could I try to replicate the errata?

Thanks. 

  • Hi,

    It is recommend to use either of the following ways to avoid the problem.

    • Use a read of Interrupt Vector registers to clear interrupt flags and do not use read-modify-write instruction. 
    • Disable all DMA channels during read-modify-write instruction of specific module registers containing interrupts flags while these interrupts are activated.

    Why are you trying to reproduce the errata? I didn't find any additional instructions to reproduce the problem, because it seems that stating certain conditions is enough.

  • Hi,

    Thanks for your reply.

    The idea to reproduce the errata is to prove that a bug that we are having is due to that, so we can rule out the other theories.

    Do you think that the test that I described is enough to meet the conditions of the errata?

  • Hi,

    Did you try to test more time point? For example, Read-modify-write operations are started 40us before the DMA trigger and stopped 20us after it.

    I am afraid I don't have any more good suggestions.

  • Hi,

    Yes, I have tried changing the time at which Read-modify-write operations are started. I have also tried using all DMA channels and timers to increase the probability of happening, but I still got nothing.

    The problem with this errata is that it makes it impossible for us to use the DMAs since none of the workarounds described are possible in our case. 

  • I've left the new test device running for several days where all three DMA channels are used which are triggered by a SMCLK timer and nothing has changed. 

    I'm sure that I have met the conditions of the errata probably thousands of times now and not one interruption flag has been lost. There must be another condition not described in the errata that I'm not meeting.

**Attention** This is a public forum