Following on from my previous post (http://e2e.ti.com/forums/t/8586.aspx) I have now modified my example to repeatedly transfer an array of data to consecutive sections of FLASH, except it doesn't work.
The code is:
#include "msp430xG46x.h"
#define MEM_START 0x10000UL
#define MEM_END (MEM_START + 10 * 0x20)
void main(void)
{
unsigned short inData[16];
volatile unsigned int i, j;
unsigned long dataPos = MEM_START;
unsigned long FarPtr = MEM_START;
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
FLL_CTL0 |= XCAP14PF; // Configure xtal load capacitance
// LFXT1 startup delay
do
{
IFG1 &= ~OFIFG; // Clear OSCFault flag
for (i = 0x47FF; i > 0; i--); // Time for flag to set
}
while (IFG1 & OFIFG); // OSCFault flag still set?
__disable_interrupt(); // Disable interrupts
// create some dummy data
for (i = 0; i < 16; i++)
{
inData[i] = i + 1;
}
// Setup and erase Flash memory
FCTL2 = FWKEY + FSSEL1 + FN1; // SMCLK/3 = ~333kHz
FCTL3 = FWKEY; // Unlock Flash memory for write
do
{
FCTL1 = FWKEY + ERASE;
__data20_write_char(FarPtr, 0x00); // Dummy write to erase segment
FarPtr += 0x0200; // Point to next segment
} while (FarPtr < MEM_END);
// Setup Timer_B for DMA to FLASH
TBCTL = TBSSEL_2; // Use SMCLK as Timer_B source
TBR = 0;
TBCCR0 = 100; // Initialize TBCCR0
TBCCR1 = 50; // Initialize TBCCR1
TBCCTL1 = OUTMOD_7; // Reset OUT1 on EQU1, set on EQU0
for (i = 0; i < 10; i++)
{
// set up DMA
__data16_write_addr((unsigned short)&DMA0SA, (unsigned int)inData);
// Start block address
__data16_write_addr((unsigned short)&DMA0DA, dataPos);
// Destination block address
DMA0SZ = 0x0010; // Block size
DMA0CTL = DMADT_0 + DMASRCINCR_3 + DMADSTINCR_3 + DMAEN + DMAIE;
// single xfer, inc s & d,
// enable DMA & interrupt
DMACTL0 = DMA0TSEL_8; // TBCCR0 triggers DMA0
FCTL1 = FWKEY + WRT; // Enable Flash write for copying
TBCTL |= MC0; // Start Timer_B in UP mode
// (counts up to TBCL0)
// Activate LPM during DMA transfer, wake-up when finished
__bis_SR_register(LPM0_bits + GIE); // Enable interrupts, enter LPM0
__disable_interrupt(); // Disable interrupts
TBCTL &= ~MC0; // Disable Timer_B
FCTL1 = FWKEY; // Disable Flash write
dataPos += 0x20;
for (j = 0; j < 16; j++)
{
inData[j] += 16;
}
}
// Deactivate Flash memory write access
FCTL3 = FWKEY + LOCK; // Lock Flash memory
}
//------------------------------------------------------------------------------
// DMA interrupt handler
//------------------------------------------------------------------------------
#pragma vector=DMA_VECTOR
__interrupt void DMA_ISR(void)
{
DMA0CTL &= ~DMAIFG; // Clear DMA0 interrupt flag
__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 on reti
}
//------------------------------------------------------------------------------
In this example I've added code to repeat the transfer, moving the destination memory location by 32 (0x20) bytes each time. Again, the RAM to RAM transfer using Timer B works fine, but the RAM to FLASH version only transfers one data set then stops in low power mode as if an interrupt is never fired (the RAM to RAM version fires interrupts without any problem).
Any ideas anyone? Obviously something to do with FLASH memory, but I don't know what.
Thanks!
Derek