Other Parts Discussed in Thread: MSP430FR5739, ADS7866
Hi,
I'm a student and I'm trying to get two of your products to talk to each other effectively and I'm having a lot of trouble with it. I'm attempting to read voltage values from your ADS7866 ADC to a MSP430FR5739 which is installed in the development kit. I've set the eUSCI A0 to SPI mode and I've tried reading the values out manually and by using DMA to implement the transfer. I can get something partially intelligible without using DMA to complete the transfer, however I'm not getting the resolution that I would expect from the device, which says to me that the data isn't getting transferred correctly. When I use DMA, I can read data from the device that makes sense roughly half of the time - but again with poor resolution. In either case, I'm not convinced that the data I read out of the ADC is actually valid.
There is very little information online or anywhere else on using DMA to access the eUSCI peripherals, so I've muddled some code together from the sources I could find. I am wondering if there's something I'm doing wrong, or if there is a way to make the read from the ADC more reliable. My code for the DMA read of the ADC over SPI (4-pin) is below. The clock generated by the eUSCI is ~1MHz:
Initialization function for the eUSCI to read the ADC:
/**********************************************************************************
* This function initializes the eUSCI for SPI mode to communicate with the
* external ADC.
* It is configured for 4-pin SPI mode with an active low control signal
* and is clocked off of the ACLK at a rate of ACLK/2. Only the Rx, control signal
* and clock pins are enabled since the ADC does not accept data input
**********************************************************************************/
void Init_ADC(){
UCA0CTLW0 |= UCSWRST; // **Put state machine in reset**
//Initialize pins
P1SEL1 |= BIT5 + BIT4; //Pin 1.4 -> UCA0STE, Pin 1.5 -> UCA0CLK
P2SEL1 |= BIT1+BIT0; //Pin 2.1 -> UCA0RXD, Pin 2.0 -> UCA0TXD... don't need to activate it
//and don't need to connect it to anything
UCA0CTLW0 |= UCMST+UCSYNC+UCMSB+UCCKPL // 8-bit SPI master
+UCMODE_2+UCSTEM+UCCKPH; // 4-pin SPI with UCxSTE active low
// Clock polarity high, MSB
UCA0CTLW0 |= UCSSEL_1; // ACLK (2MHz)
UCA0BR0 = 0x02; // /2 (clock div)
UCA0BR1 = 0; //
UCA0MCTLW = 0; // No modulation
UCA0CTLW0 &= ~UCSWRST; // **Initialize USCI state machine**
//Initialize DMA module for transfer from USCI to RAM (channels 1 and 0)
//DMA channel 1 = Block transfer, don't increment source or destination addresses, Level trigger (don't get that), Both source and destination are byte sized
DMA1CTL = DMADT_1+DMASRCINCR_0+DMADSTINCR_0 + DMALEVEL + DMADSTBYTE+ DMASRCBYTE; //DMALEVEL +;// + DMAEN; // Single Transfer, no increment
//DMA channel triggers - software for channel 1, eUSCI Rx buffer for channel 0
DMACTL0 = DMA0TSEL__UCA0RXIFG + DMA1TSEL__DMAREQ;
//DMA channel 0 = Block transfer, don't increment source address, increment destination address, level trigger, both source and destination are byte sized
DMA0CTL = DMADT_1+DMASRCINCR_0+DMADSTINCR_3 + DMALEVEL + DMASRCBYTE + DMADSTBYTE;// DMALEVEL +;// + DMAEN; // Single Transfer, no increment
DMA0SA = &UCA0RXBUF; // Channel 0 source = eUSCI receive buffer
DMA0SZ = 2; // Transfer 16 bits using DMA
// Setup DMA1 // Transfer 2 bytes on DMA0
DMA1SZ = 2; // Transfer 2 bytes on DMA1
DMA1SA = &TxData; //Source address is variable containing dummy data to send
DMA1DA = &UCA0TXBUF; // DMA channel 1 Destination is eUSCI transmit buffer
}
The read function is here:
/*********************************************************************************
* This function reads from the ADC over the eUSCI SPI interface. The function
* returns the data read by the ADC
* input: select -Selects which input to read from
* 1: Input Voltage
* 2: Input Current
* 3: Output Voltage
********************************************************************************/
int Read_ADC(int select){
int reading = 0;
DMA0DA = &reading; //DMA channel 0 destination is address of variable "reading"
//Use the external MUX to decide which input to use
switch(select){
case ADC_VIN:
P1OUT &= ~BIT2;
P1OUT |= BIT1;
break;
case ADC_IIN:
P1OUT &= ~BIT1;
P1OUT |= BIT2;
break;
case ADC_VOUT:
P1OUT |= BIT1 + BIT2;
break;
default:
P1OUT |= ~(BIT1 + BIT2);
break;
}
__delay_cycles(20); // Delay before reading from ADC ~ .001s at 2 MHz to allow for mux to switch
DMA0CTL |= DMAEN; // Enable DMA0
DMA1CTL |= DMAEN+DMAREQ; // Enable DMA1 and start transfer
__delay_cycles(30); // this delay is here because it seems necessary to allow time for the DMA to populate the memory
//with the received data
P1OUT |= ~(BIT1 + BIT2); //disconnect everything from ADC
return reading;
}
This is how the ADC_Read function is called:
Vinread = (unsigned long)Read_ADC(ADC_VIN);
where ADC_VIN is a #defined constant.
Thank you in advance for any help you are able to provide on this matter.
-Chris Hack