Hey everyone,
I am trying to write code that will read in an continuous audio signal from channel A0. Then have a A/D conversion of the audio signal store the digitized results in the DMA then send the digital values from the audio signal out through serial using the RS-232 port. Right now my terminal is reading only the lower byte of the ADC12MEM0 register. I noticed that the UCA0TXBUF can only send out on 1 byte at a time. Therefore, I am wondering how to send out both bytes while still utilizing the DMA to setup my buffer. Below is my code so far any help would be appreciated.
# include <msp430xG46x.h>volatile unsigned int ADCSample;void main(void){WDTCTL = WDTPW+WDTHOLD; // Stop watchdogP5DIR |= 0x02;P5OUT |= 0x02;// Initialization of ADC12//P6SEL |= 0x01; // Enable A/D channel A0ADC12CTL0 &= ~ENC; // Disable ConversionsADC12CTL0 = ADC12ON + SHS_1 + REFON + REF2_5V + MSC; // turn on ADC12, set samp timeADC12CTL1 = SHP+CONSEQ_2; // Use sampling timerADC12MCTL0 = SREF_1+INCH_0; // Vr+=VeREF+ (external)//ADC12IFG = 0;//Timer ATACCR0 = 1500; // Delay to allow Ref to settleTACCR1 = 1470;//TACCTL0 |= CCIE; // Compare-mode interrupt.TACCTL1 = OUTMOD_7;TACTL = TASSEL_1 + MC_1 + TACLR; // TACLK = ACLK, Up mode.//__bis_SR_register(LPM3_bits + GIE); // Wait for delay, Enable interruptsADC12CTL0 |= ENC; // Enable conversions// Initialization of Rs-232//FLL_CTL0 |= XCAP14PF; // Configure load capsdo{IFG1 &= ~OFIFG; // Clear OSCFault flag//_delay_cycles(50000); // Time for flag to set}while ((IFG1 & OFIFG)); // OSCFault flag still set?P2SEL |= 0x30; // P2.4,5 = USCI_A0 RXD/TXDUCA0CTL1 |= UCSSEL_1; // CLK = ACLKUCA0BR0 = 0x03; // 32k/9600 - 13.65UCA0BR1 = 0x00; //UCA0MCTL = 0x06; // ModulationUCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**IE2 |= UCA0TXIE + UCA0RXIE; // enable RXD and TXD interrupt;// Initialize DMADMACTL0 = DMA0TSEL_6; // ADC12IF setDMACTL1 = DMAONFETCH;__data16_write_addr((unsigned short) &DMA0SA, (unsigned long) &ADC12MEM0); // Source block address__data16_write_addr((unsigned short) &DMA0DA, (unsigned long) &UCA0TXBUF); // Destination single addressDMA0SZ = 0x00002; // Set DMA Block size ADCSample sizeDMA0CTL = DMADT_4 + DMADSTINCR_3 + DMAIE + DMADSTBYTE + DMASRCBYTE; // Repeat single, inc dst, interruptsDMA0CTL |= DMAEN;ADC12CTL0 |= ADC12SC;//Serial Loopwhile(1){ADCSample = ADC12MEM0;//UCA0TXBUF = ADCSample >> 8;//while(!(IFG2 & UCA0TXIFG))//{//__delay_cycles(1000);// wait for first transmit//}//UCA0TXBUF = ADCSample;__bis_SR_register(LPM0_bits + GIE);}}
Unfortunately, there is no 'clean' direct way to send a 16 bit value to an 8 bit destination.If the DMA is triggered by the ADC, then you can of course transfer two bytes to a one-byte destination as a block transfer. (incrementing source address, static destination address. However, the transfer wouldn't be synchronized to TXIFG bit.
With some exact timing calculations, it is still possible. It is necessary that
The trick is that on teh conversion ready trigger, teh DMA starts moving two bytes from ADC12MEMx to TXBUF. This takes 2 MCLK cycles for the first and 2 MCLK cycle sfor the second transfer. If the USCI is idle. the first byte is written to TXBUF. Since DMA is done with MCLK, the USCI will receive a clock pulse and move the first byte from TXBUF to output while the DMA is moving the second byte to TXBUF.
If MCLK is higher than the baudrate (or maybe higher than baudrate*baudrate divider - the users guide doesn't tell about the exact timings), the first byte will still sit in TXBUF when the second one arrives. Bad.
Th eothe rway woul dbe to trigger the DMA by the TXIFG bit in repeated block mode. THen each tiem the TXBUF is free for the next bye, first and secodn byte of ADC12MEM will be moved in - whether a new conversion is ready or not. In this case you'll get a constant stream of data with the last conversion result - updated as soon as the next conversion is done.
Well, maybe suitable for an oscilloscope application.
_____________________________________Before posting bug reports or ask for help, do at least quick scan over this article. It applies to any kind of problem reporting. On any forum. And/or look here.If you cannot discuss your problem in the public, feel free to start a private conversation: click on my name and then 'start conversation'. But please do so only if you really cannot do it in a public thread, as I usually read all threads. And I prefer to answer where others can profit from it (or contribute to it) too.