Hello,
I'm working on a small test program testing ADC sampling on the MSP4F2618.
The intended program flow is that Timer B periodically triggers the ADC12 module to sample A2 and A3. When conversion of this sequence finishes, the DMA module transfers both samples into a double buffer in RAM. The user guide, example code, and two threads below have gotten me most of the way there.
The unwanted behavior I'm encountering is that the DMA transfer overwrites the destination every time, so only the first two slots of the buffer are used. The DMA interrupt is triggered at the end of each block transfer. The needed behavior is that the buffer is filled (two values per Timer B trigger) over time and then triggers an interrupt.
I believe that the problem is in how I'm defining the block size. I currently have it set to 2 words as I only want to transfer the ADC12MEM0 and ADC12MEM1 values each trigger. But because the DMA interrupt triggers and the destination address resets at the end of each block transfer I'm not getting the desired behavior. I've tried increasing the block size to 4 and 8, but that hasn't seemed to work. I know I could change the DMA0DA at the end of each transfer in the interrupt, but I really want to avoid interrupts where possible to reduce power consumption and simplify the execution paths.
Many thanks for any help.
{
WDTCTL = WDTPW+WDTHOLD; // Stop watchdog timer
P6SEL = BIT2 + BIT3; // Enable A/D channel inputs
/* Power external ICs */
P2DIR = BIT0; P2OUT = BIT0;
P5DIR = BIT5; P5OUT = BIT5;
P6DIR = BIT4; P6OUT = BIT4;
/* Configure TimerB to produce the triggers for the ADC */
TBCTL = TBSSEL_1 | MC_1 | TBCLR; // Use ACLK, count up, reset counter and direction
TBCCR0 = 4096; // Init TBCCR0 w/ sample period
TBCCR1 = 4036; // Trigger for ADC12 Sample Conversion
TBCCTL1 = OUTMOD_7; // Reset OUT1 on EQU1, set on EQU0
/* Configure ADC for repeated sampling of A2 and A3 */
ADC12CTL0 = ADC12ON | MSC | SHT0_8; // Turn on ADC12, extend sampling time
ADC12CTL1 = SHS_3 | CONSEQ_3 | ADC12SSEL_1; // Use ACLK timer, repeated sequence
ADC12MCTL0 = SREF_2 | INCH_2; // ref+=VeREF+, channel = A2
ADC12MCTL1 = SREF_2 | INCH_3 | EOS; // ref+=VeREF+, channel = A3
ADC12IFG = 0;
ADC12CTL0 |= ENC; // Enable conversions
DMACTL0 = DMA0TSEL_6; // ADC12IFGx triggers DMA0
DMA0SA = ADC12MEM0_; // Source address
DMA0DA = (unsigned short) &ADMAresults[0]; // Destination address
DMA0SZ = 2; // Transfer 2 16 bit words per trigger
DMA0CTL = DMADT_5 | DMADSTINCR_3 | DMASRCINCR_3 | DMAEN | DMAIE; // Repeated block transfer, increment dest addr, enable DMA & interrupt
_BIS_SR(GIE); // Enable interrupts
/* Spin forever, ideally would be in lowest power mode possible */
while(1);
}
#pragma vector=DMA_VECTOR
__interrupt void DMA0_ISR (void)
{
switch(__even_in_range(DMAIV,16))
{
case 0: break; // No interrupt
case 2: // DMA0IFG
_NOP();
break;
case 4: break; // DMA1IFG
case 6: break; // DMA2IFG
case 8: break; // Reserved
case 10: break; // Reserved
case 12: break; // Reserved
case 14: break; // Reserved
case 16: break; // Reserved
default: break;
}
}