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.

Why does DMA record wrong value?

Other Parts Discussed in Thread: MSP430FG4618

Hi, i'm trying record data to flash mem. using DMA but every time it records wrong value. I mean, i have RESLO = 0x031A but dma records to flash 0xAEE4 value. What can be the problem? I'm looking this a whole day but i couldn't solve this problem. I wish someone help me. (using msp430fg4618 exp board)

Thanks.

 

void main(void){

  WDTCTL = WDTPW + WDTHOLD;
 
  volatile unsigned int i;

  WDTCTL = WDTPW +WDTHOLD;                  // Stop WDT
  FLL_CTL0 |= XCAP14PF;                     // Configure load caps

  do
  {
  IFG1 &= ~OFIFG;                           // Clear OSCFault flag
  for (i = 0x47FF; i > 0; i--);             // Time for flag to set
  }
  while ((IFG1 & OFIFG)); 

  RESLO = 0x031A;
 
  TBCTL = TBSSEL_2;                         // Use SMCLK as Timer_B source
  TBR = 0;
  TBCCR0 = 100;
  TBCCR2 = 50;
  TBCCTL2 = OUTMOD_7;

  DMACTL0 = DMA0TSEL_2;
  DMA0SA = (unsigned int)RESLO;
  DMA0DA = 0x9c00;
  DMA0SZ = 0x0001;                       // 1-word transfer
  DMA0CTL = DMAEN + DMAIE;
 
  FCTL2 = FWKEY + FSSEL1 + FN1;             // SMCLK/3 = ~333kHz
  FCTL3 = FWKEY;                            // Unlock Flash memory for write
  FCTL1 = FWKEY + WRT;                      // Enable Flash write for recording
 
  TBCTL |= MC0;
  __bis_SR_register(LPM0_bits + GIE);
  __disable_interrupt();
 
  FCTL1 = FWKEY;                            // Disable Flash write
  FCTL3 = FWKEY + LOCK;                     // Lock Flash memory
 
  TBCTL = 0;

}

#pragma vector=DMA_VECTOR
__interrupt void DMA_ISR(void)
{
  DMA0CTL &= ~DMAIFG;
  __bic_SR_register_on_exit(LPM0_bits);
}

  • First, you should add a_NOP() right after entering LPM0. The pipelined structure of the MSP code execution causes the next instruction to be read while the previous is executed, so the __sisable_interrupt is already in the queue when going into LPM.

    Also, you do not erase the segment you're writing to before writing. You cn only write '0' bits into flash. If the flash memory cell already contains a '0', you cannot set it back to '1' unless you erase the whole flash segment (512 bytes).

    Also, you clock the DMA using the timerB, but... Does the delay cover the necessary write times for flash? Also, while flash is being written, NO IRQs may take place. It will fetch a wrong address from the (unavailable) flash interrupt vector table. So you code won't work, can't work. The concept of it violates the flash writing specs.
    You must disable IRQs while writing to flash, start the DMA transfer, then busy-wait for the DMA transfer to be completed (check for the DMAIFG bit), then disable flash writing and THEN you can enable IRQs again. No LPM allowed in between (anyway it doesn't make sense to save 100µA while flashing sucks 5mA).

    Also, unless you need it for a different purpose, your setup of TB doesn't make sense. The DMA is triggered by the TBCCR2 CCIFG bit, so the OUTMOD is don't care. Each time TB counts to 50, it will trigger the DMA. So the first trigger happens after 50*SMCLK, all subsequent triggers happen 101 ticks later (TBCCR0+1 is the period, not TBCCR0). Also, you cannot be sure that the first trigger (which ends your LPM) isn't done before the flash controller is ready for writing. Too many reace conditions in the code. Even if it might work. Stop TB and then start if after everything else is ready.

    Oh, and I think it is a bit overkill for a single byte, but I gess this was planned to be changed later when the single write works :)

**Attention** This is a public forum