SPI Communication with TI ADC and ATMEGA32U4 - Page 1
Forum section: electronics / projects

author: Rymanvw
author_rank: Newbie
timestamp: March 04, 2013, 09:59:42 pm
content: Hey guys,I have been working on talking to this TI ADC for about a week now and I am stumped. I have a TI ADS1212 with a 2.5 MHz crystal (Datasheethttp://www.ti.com/lit/ds/symlink/ads1212.pdf) and a ATMEGA32U4 with a 16 MHz crystal(Datasheethttp://www.atmel.com/Images/doc7766.pdf).The wiring diagram I am basically follow is found on pg 32 Figure 31 in the ADS1212 datasheet, (DSYNC is HIGH).I have been able to communicate with the chip but I think my timing is all off. I have tried to follow the flowchart on pg 28 Figure 26 and the timing diagram on pg 25 figure 19 with TABLE XV on page 23.I have never configured another chip like this before and I am not exactly sure what I am doing wrong.The ADS1212 is writing to the 32U4 and I am able to read it on my serial terminal but the values are all 255. Once or twice I have gotten values the do correspond with actual voltage across the two analog inputs but it was only for the first 1 or 2 reads (I have not been able to replicate that again).I have hooked up my fluke 123 and the SCLK line is a sign wave?! I have used other chips that haven't been used and they act the same way. Here is my code.Code:/*LUFA LibraryCopyright (C) Dean Camera, 2013.dean  fourwalledcubicle  com[url=http://www.lufa-lib.org]www.lufa-lib.org*//*Copyright 2013 Dean Camera (dean  fourwalledcubicle  com)Permission to use, copy, modify, distribute, and sell thissoftware and its documentation for any purpose is hereby grantedwithout fee, provided that the above copyright notice appear inall copies and that both that the copyright notice and thispermission notice and warranty disclaimer appear in supportingdocumentation, and that the name of the author not be used inadvertising or publicity pertaining to distribution of thesoftware without specific, written prior permission.The author disclaims all warranties with regard to thissoftware, including all implied warranties of merchantabilityand fitness. In no event shall the author be liable for anyspecial, indirect or consequential damages or any damageswhatsoever resulting from loss of use, data or profits, whetherin an action of contract, negligence or other tortuous action,arising out of or in connection with the use or performance ofthis software.*//** \file** Main source file for the VirtualSerial demo. This file contains the main tasks of* the demo and is responsible for the initial application hardware configuration.*/#include <avr/io.h>#include "VirtualSerial.h"#define SCKPB1#define MOSIPB2#define MISOPB3#define MODEPD4#define DRDYPD5#define SSPD6/** LUFA CDC Class driver interface configuration and state information. This structure is* passed to all CDC Class driver functions, so that multiple instances of the same class* within a device can be differentiated from one another.*/USB_ClassInfo_CDC_Device_t VirtualSerial_CDC_Interface ={.Config ={.ControlInterfaceNumber = 0,.DataINEndpoint ={.Address = CDC_TX_EPADDR,.Size = CDC_TXRX_EPSIZE,.Banks = 1,},.DataOUTEndpoint ={.Address = CDC_RX_EPADDR,.Size = CDC_TXRX_EPSIZE,.Banks = 1,},.NotificationEndpoint ={.Address = CDC_NOTIFICATION_EPADDR,.Size = CDC_NOTIFICATION_EPSIZE,.Banks = 1,},},};/** Standard file stream for the CDC interface when set up, so that the virtual CDC COM port can be* used like any regular character stream in the C APIs*/static FILE USBSerialStream;volatile char buffer;void Initialize_SPI_MODE(uint8_t SPIMODE){if (SPIMODE == 1){// Set MOSI-PB2 and SCK-PB1 as outputs, all others input //DDRB = (1 << MOSI) | (1 << SCK);// Enable SPI, Master, set clock rate fosc/128 //SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);fprintf(&USBSerialStream, "SPI Initialized - Master Mode\n");CDC_Device_USBTask(&VirtualSerial_CDC_Interface);USB_USBTask();}if (SPIMODE == 0){// Set MISO-PB3 as output and SCK as input, all others input //DDRB = (1 << MISO) | (0 << MOSI) | (0 << SCK);// Enable SPI, set to Slave, set clock rate fosc/128 //SPCR = (1 << SPE) | (0 << MSTR) | (1 << SPR1) | (1 << SPR0);fprintf(&USBSerialStream, "SPI Initialized - Slave Mode\n");CDC_Device_USBTask(&VirtualSerial_CDC_Interface);USB_USBTask();}}void SPI_Transmit(unsigned char cData){// Start transmission //SPDR = cData;// Wait for transmission complete //while(!(SPSR & (1 << SPIF)));SPSR = (0 << SPIF);}char SPI_Receive(void){// Wait for reception complete //while(!(SPSR & (1 << SPIF)));// Return Data Register //return SPDR;}void chipSelect(uint8_t STATE){if (STATE == 1){PORTD |= (1 << SS); // SET CHIP SELECT TO HIGH}if (STATE == 0){PORTD &= ~(1 << SS); // SET CHIP SELECT TO LOW}}void ADC_Mode(uint8_t ADCMODE)//void ADC_Mode(char ADCMODE){if (ADCMODE == 1) // MASTER MODE ////if (ADCMODE == "Master") // MASTER MODE //{PORTD |= (1 << MODE); // SET ADC MODE TO MASTERchipSelect(1); // SET CHIP SELECT TO HIGH}if (ADCMODE == 0) // SLAVE MODE ////if (ADCMODE == "Slave") // SLAVE MODE //{PORTD &= ~(1 << MODE); // SET ADC MODE TO SLAVEchipSelect(0); // SET CHIP SELECT TO LOW}}/** Main program entry point. This routine contains the overall program flow, including initial* setup of all components and the main program loop.*/int main(void){unsigned long ADS1212_Read; // HOLDS 4 BYTE ADS1212 ADC OUTPUT 4TH BYTE IS BLANKuint8_t ADS_bytes = {0b00000000, 0b00000000, 0b00000000, 0b00000000};// ATMega32U4 Pin Configuration// SET AS OUTPUT SS | SET AS INPUT DRDY | SET AS OUTPUT MODEDDRD = (1 << DDD6) | (0 << DDD5) | (1 << DDD4);/* FOR DEBUGGING PURPOSES */// SET PIN31/PC6 AS INPUTDDRC = (0 << DDC6);/* FOR DEBUGGING PURPOSES */Initialize_SPI_MODE(1); // INITIALIZE SPI INTERFACE MODE (1 MASTER OR 0 SLAVE)ADC_Mode(0); // SELECT ADS1212 MODE (1 MASTER OR 0 SLAVE)chipSelect(1);/* Initialization */SetupHardware(); // Initialize USB Hardware/* Create a regular character stream for the interface so that it can be used with the stdio.h functions */CDC_Device_CreateStream(&VirtualSerial_CDC_Interface, &USBSerialStream);GlobalInterruptEnable();fprintf(&USBSerialStream, "USB Hardware Initialized Successfully\n");CDC_Device_USBTask(&VirtualSerial_CDC_Interface);USB_USBTask();while(1){if (PINC & (1 << PC6)){fprintf(&USBSerialStream, "Make PC6 LOW to run ADC\n");CDC_Device_USBTask(&VirtualSerial_CDC_Interface);USB_USBTask();_delay_ms(1000);}else{// _delay_ms(250); // 250ms power on delaywhile((PIND & _BV(DRDY)) == 0){/* WAIT 1200ns SEE FIGURE 16 PG.24 AND TABLE XV. */_delay_loop_2(5);chipSelect(0);_delay_loop_2(18);/* INSTRUCTION REGISTER */SPI_Transmit(0b01100100); // INSTRUCTION REGISTER GIVEN WRITE COMMAND TO WRITE FOUR BYTES TO COMMAND REGISTER./* WAIT 5200ns SEE FIGURE 16 PG.24 AND TABLE XV. */_delay_loop_2(21);/* COMMAND REGISTER */SPI_Transmit(0b01100010); // SET DATA FORMAT TO OFFSET BINARY & USE SDOUT FOR OUTPUT/* WAIT 5200ns SEE FIGURE 16 PG.24 AND TABLE XV. */_delay_loop_2(21);SPI_Transmit(0b00000000); // NORMAL MODE, GAIN OF PGA TO 1, USE CHANNEL 1/* WAIT 5200ns SEE FIGURE 16 PG.24 AND TABLE XV. */_delay_loop_2(21);SPI_Transmit(0b00100011); // SET TURBO MODE TO 2 AND DATA RATE TO 10 Hz/* WAIT 5200ns SEE FIGURE 16 PG.24 AND TABLE XV. */_delay_loop_2(21);SPI_Transmit(0b00001100); // SET DATA RATE TO 10 Hz/* WAIT 3200ns SEE FIGURE 16 PG.24 AND TABLE XV. */_delay_loop_2(13);S: while((PIND & _BV(DRDY)) == 0) // WAIT TILL DRDY(bar) BECOMES 1{// NOW READ DATA FROM DATA OUTPUT REGISTERL:while((PIND & _BV(DRDY)) == 0){chipSelect(1);_delay_loop_2(35);chipSelect(0);_delay_loop_2(18);SPI_Transmit(0b11000000); // INSTRUCTION REGISTER IS WRITTEN TO READ 3 BYTES OF DATA FROM DOR(DATA OUTPUT REGISTER )}for(uint8_t i = 0 ; i <= 2 ; i++){SPI_Transmit(0b00000000); // SEND DUMMY DATA ON MOSI LINEwhile(SPSR & (1 << SPIF)) // WAIT TILL SPIF FLAG OF ATMEGA32U4 IS SET{ADS_bytes = SPI_Receive(); // READ RECEIVED DATA FROM SPI DATA REGISTER}}fprintf(&USBSerialStream, "BYTE0 = %d BYTE1 = %d BYTE2 = %d BYTE3 = %d\n", ADS_bytes, ADS_bytes, ADS_bytes, ADS_bytes);ADS1212_Read = *(unsigned long*)ADS_bytes; // COMBINES ALL 4 BYTES OF ADS_bytesfprintf(&USBSerialStream, "ADS1212 READ = %ld\n", ADS1212_Read);uint8_t bytesWritten = fwrite(ADS1212_Read, 1, 3, &USBSerialStream); //fprintf(&USBSerialStream, "\nBytes Written with fwrite = %d\n", bytesWritten);// LUFA USB functions necessary for USB/virtual serial communication to work //CDC_Device_USBTask(&VirtualSerial_CDC_Interface);USB_USBTask();_delay_ms(1000);goto L;}_delay_loop_2(3);goto S;}}}}/** Configures the board hardware and chip peripherals for the demo's functionality. */void SetupHardware(void){/* Disable watchdog if enabled by bootloader/fuses */MCUSR &= ~(1 << WDRF);wdt_disable();/* Disable clock division */clock_prescale_set(clock_div_1);/* Hardware Initialization */USB_Init();}/** Event handler for the library USB Connection event. */void EVENT_USB_Device_Connect(void){LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);}/** Event handler for the library USB Disconnection event. */void EVENT_USB_Device_Disconnect(void){LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);}/** Event handler for the library USB Configuration Changed event. */void EVENT_USB_Device_ConfigurationChanged(void){bool ConfigSuccess = true;ConfigSuccess &= CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface);LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);}/** Event handler for the library USB Control Request reception event. */void EVENT_USB_Device_ControlRequest(void){CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface);}Please any help would be very much appreciated.

author: TerminalJack505
author_rank: Super Contributor
timestamp: March 05, 2013, 01:39:47 am
content: The fact that you have a sine wave when you should have a square wave is a big red flag. That can't be right.

author: Rymanvw
author_rank: Newbie
timestamp: March 05, 2013, 04:09:41 am
content: Yeah, that was a big red flag. Im just a little burnt out and need to step back for a second. I also don't understand why it was working some times? Thanks I will look into it.

author: ve7xen
author_rank: Super Contributor
timestamp: March 05, 2013, 05:20:18 am
content: Quote from: Rymanvw on March 05, 2013, 04:09:41 amAre you sure you weren't just getting bogus data from floating inputs or something like that?

author: CarlG
author_rank: Regular Contributor
timestamp: March 05, 2013, 09:51:55 am
content: Have you checked all connections with the Fluke meter? (that you have the levels/signals you expect?How have you verified the oscillator circuit?What mode are you running in, i.e. have you set the GPIO controlling MODE high or low? Have you set the MCU in the corresponding mode?Does the 255 data correspond to the data stream as measured with the Fluke?What frequency is the sine wave on SCLK?

author: Rymanvw
author_rank: Newbie
timestamp: March 05, 2013, 03:42:57 pm
content: The frequency of the sine wave is about 10.4 MHz, but it fluctuates +-0.2 MHz.I also checked across the crystal and it is 60 Hz fluctuating. Nothing seems to be working. I've swapped the crystal same result. I also checked continuity on all pins on the ADS1212 and bread board and the MOSI MISO SCK lines and they are good. Here are some pictures.The Red and white lines coming into the rail on the left are from a wall wart 5.2v. The caps and resistors match the ones found in figure 31 page 32. The crystal is 2.5MHz. I am using a Sparkfun ATMEGA32U4 Breakout Board, Here is a linkhttps://www.sparkfun.com/products/11117photo storageThis is the reading from the SCLK lines in the picture.pic uploadThe chip programs fine every time. Not sure what is wrong. Thanks let me know if any more detail are needed.-Ryman

author: TerminalJack505
author_rank: Super Contributor
timestamp: March 05, 2013, 04:00:27 pm
content: I don't see your images but are you sure your scope isn't locking onto some other fundamental frequency? Have you tried setting the timebase manually? If I remember correctly, according to your code SCK should be just 150kHz or so.

author: CarlG
author_rank: Regular Contributor
timestamp: March 05, 2013, 07:53:10 pm
content: Quote from: Rymanvw on March 05, 2013, 03:42:57 pmThat's obviously weird unless I got the wrong datasheet. Isn't 16 MHz max main clock frequency for the MCU (or even just 8MHz if the internal calibrated osc is used)? I haven't read the manual in detail but my guess is that max SCLK is 1/4 (or less) of the main clock. So there's no way you can have SCLK=10 MHz.QuoteIf you used the Fluke for that measurement it's useless. The capacitive load from the leads/probes will change the frequency or stop the oscillator.Instead, set the ADC as master by pulling the MODE pin of the ADC high (disconnect the MCU if necessary), measure its SCLK and derive the oscillator frequency from that. Make 100% sure that you're using the load capacitance recommened by the crystal manufacturer. Do NOT rely on the ADS1212 datasheet typical load caps for the oscillator.My suggestion is: just get rid of the oscillator, set up an MCU GPIO to generate something like 0.5-2 MHz and feed it to the XIN of the ADC, and adjust the MCU SPI parameters accordingly.(If you really want to try to measure the crystal frequency, you can try with a small cap (1-2 pF) at XOUT and connect the probe to the other end of the cap. Measure relative to GND, not across the crystal.)