Hi,
My code is somehow not working.
What I want is, I have an array (adcDataCollected[3][512]) that ADC conversion data is written via DMA. When DMA interrupt occurs, I would like to change address of DMA destination, so previous ADC data will not be lost.
While changing DMA destination address inside the interrupt, it always writes to a different place.
CRC data shows data is written like:
Writes to adcDataCollected [1] (should be 0), [0] (should be 1), [1] (should be 2), [2] (should be 0), [0] (should be 2), ...
Sometimes it goes like
Writes to adcDataCollected [2] (should be 0), [0] (should be 1), [1] (should be 2), [2] (should be 0), [0] (should be 2), ...
I checked DMA0DA address and even though it is the correct address, data is written to another address in the array.
Can anyone figure out what I'm doing wrong?
Thank you in advance,
#include <msp430.h>
#include "lcd/lcd.h"
// ADC data timer, which is used to collect data in 1 second
const unsigned int adcDatatimer = (unsigned int)((unsigned long)1048576 / (unsigned long)256);
// Data Collected from ADC
volatile int adcDataCollected[3][512] = {0};
// Counter of data collected from ADC
unsigned int adcDataCollectedCounter = 0;
// DMA Interrupt Handler
#pragma vector=DMA_VECTOR
__interrupt void _dmaInterruptHandler(void)
{
switch(__even_in_range(DMAIV,16))
{
case 0: break;
case 2: // DMA0IFG = DMA Channel 0
// Stop conversion
ADC12CTL0 &= ~ADC12ENC;
adcDataCollectedCounter++;
if (adcDataCollectedCounter >= 3)
adcDataCollectedCounter -= 3;
__data16_write_addr((unsigned short)&DMA0DA, (unsigned long)adcDataCollected[adcDataCollectedCounter]);
// Start conversion again
ADC12CTL0 |= ADC12ENC;
__low_power_mode_off_on_exit();
break;
case 4: break; // DMA1IFG = DMA Channel 1
case 6: break; // DMA2IFG = DMA Channel 2
case 8: break; // DMA3IFG = DMA Channel 3
case 10: break; // DMA4IFG = DMA Channel 4
case 12: break; // DMA5IFG = DMA Channel 5
case 14: break; // DMA6IFG = DMA Channel 6
case 16: break; // DMA7IFG = DMA Channel 7
default: break;
}
}
void updateLCD(int a, int b, int c, int d)
{
lcdBufferClear(0);
lcdBufferPrintString(0, "A", 0, eLcdPage1);
lcdBufferPrintString(0, " : ", 50, eLcdPage1);
lcdBufferPrintInt(0, a, 70, eLcdPage1);
lcdBufferPrintString(0, "B", 0, eLcdPage3);
lcdBufferPrintString(0, " : ", 50, eLcdPage3);
lcdBufferPrintInt(0, b, 70, eLcdPage3);
lcdBufferPrintString(0, "C", 0, eLcdPage5);
lcdBufferPrintString(0, " : ", 50, eLcdPage5);
lcdBufferPrintInt(0, c, 70, eLcdPage5);
lcdBufferPrintString(0, "D", 0, eLcdPage7);
lcdBufferPrintString(0, " : ", 50, eLcdPage7);
lcdBufferPrintInt(0, d, 70, eLcdPage7);
lcdSendBuffer(0);
}
unsigned short getCRC(unsigned char* buffer, unsigned int length)
{
// Loop variable
unsigned long i = 0;
// CRC
unsigned short crc = 0;
// Temp buffer
unsigned char* pBuffer = buffer;
for (i = length; i; i--, pBuffer++)
{
crc += *pBuffer;
}
return crc;
}
int main(void)
{
unsigned short crcs[4] = {0};
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
// Disable global interrupts
__disable_interrupt();
lcdInit();
// ******************************
// ADC init
// Select P6.4
P6SEL |= BIT4;
// P6.4 input
P6DIR &= ~BIT4;
//Setup Timer B0
TB0CCR0 = adcDatatimer;
TB0CCR1 = adcDatatimer >> 1;
// Set/Reset Mode
TB0CCTL1 = OUTMOD_3;
// SMCLK, Up mode
TB0CTL = TBSSEL__SMCLK + MC__UP + TBCLR;
// Turn on ADC12, Sampling time, set multiple sample conversion
ADC12CTL0 = ADC12ON | ADC12SHT0_2 | ADC12MSC;
// Use sampling timer, set mode Repeat-single-channel
ADC12CTL1 = ADC12SHS_3 | ADC12CONSEQ_2 | ADC12SSEL_3 | ADC12DIV_0;
// Vr+=Avcc and Vr-=AVss
// Select channel 4
ADC12MCTL0 = ADC12SREF_0 | ADC12INCH_4;
// Write dis
DMACTL4 = DMARMWDIS;
// Set trigger register channel
DMACTL0 = DMA0TSEL__ADC12IFG;
// Set control register options
DMA0CTL = DMADT_4 | DMADSTINCR_3 | DMASRCINCR_0;
// Enable DMA and interrupt on specified channel
DMA0CTL &= ~DMAIFG;
DMA0CTL |= DMAEN + DMAIE;
DMA0SZ = 512;
__data16_write_addr((unsigned short)&DMA0SA, (unsigned long)&ADC12MEM0);
__data16_write_addr((unsigned short)&DMA0DA, (unsigned long)adcDataCollected);
// Enable conversions
ADC12CTL0 |= ADC12ENC;
// Enter LPM3, enable interrupts
__enable_interrupt();
// Super loop
while (1)
{
// Low power mode
// __low_power_mode_3();
crcs[0] = adcDataCollectedCounter;
crcs[1] = getCRC((unsigned char*)adcDataCollected[0], 1024);
crcs[2] = getCRC((unsigned char*)adcDataCollected[1], 1024);
crcs[3] = getCRC((unsigned char*)adcDataCollected[2], 1024);
updateLCD(crcs[0], crcs[1], crcs[2], crcs[3]);
}
return 0;
}
int _system_pre_init()
{
// Stop watchdog timer (prevent timeout reset)
WDTCTL = WDTPW | WDTHOLD;
return 1;
}