Hi, all...
I'm having some trouble with an SPI interface on the Mega32, which I'm
using to communicate with a TI TLV2543 ADC. I'm programming the micro in
C using avr-gcc.
Here's my problem... using the SPI transmit code more or less straight
from the Mega32 datasheet:
SPDR = (channel<<4)|(ADCSetup);
while(!(SPSR & (1<<SPIF)));
my code keeps getting stuck in an infinite loop at that while()
statement, but only on the 30th iteration or so (the micro loops through
the ADC code indefinitely). The first 29ish times through the code,
everything works perfectly. Am I missing something with how to handle
the SPIF flag? I RTFM'd and all that, and it says that SPIF is set and
reset automatically based on the SPI state and when SPDR is read.
I've included all of my code at the end of this email, but here are some
of the more relevant parts:
SPI setup:
// Set MOSI and SCK output, all others input
DDRB = (1<<PB5)|(1<<PB7);
// Enable SPI, Master, set clock rate fck/128
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0);
The ADC code is contained in the function ADCRead(), as shown in the
code below.
Am I making some classic n00b mistake here? Any advice or pointers are
welcome.
Thanks!
- Robert
/***************************************************************************
* main.c
* Fuel Cell Demonstrator Aircraft Data Acquisition System Controller
* ------------------------------------------------------------------------
* Main controller code for FCDA DAQ system.
* Author: Robert Ussery <robert.ussery@gatech.edu>
* Copyright 2006
* Revised 03-06-2006
***************************************************************************/
#include <inttypes.h>
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
/***************************************************************************
*
--------------------------------Constants--------------------------------
***************************************************************************/
#define clock 8000000 //Clock speed in Hertz
#define baud 51 //RS232 Baud definition for 9600bps and 8Mhz
#define ADCSetup 0b0100 //Selects 16bit, MSB first, unipolar
//operation for the ADC
/***************************************************************************
* --------------------------Pin/Port
Definitions---------------------------
***************************************************************************/
// When making any changes to these, also make sure to change
directions in
// the initialize() function.
//EEPROM Pins
#define EEPWP PB0 //EEPROM Write Protect
#define EEPPort PORTB //EEPROM Port Register
#define EEPPIN PINB //EEPROM Pin Register
//ADC Pins
#define ADCCS PD3 //ADC Chip Select
#define ADCEOC PD6 //ADC End of Conversion pin
#define ADCPORT PORTD //ADC Port register
#define ADCPIN PIND //ADC Pin register
/***************************************************************************
*
----------------------------------Macros---------------------------------
***************************************************************************/
//Macro for ASM "sei" global interrupt enable and "cli" global interrupt
//disable
#define sei() __asm__ __volatile__ ("sei" ::)
#define cli() __asm__ __volatile__ ("cli" ::)
#define nop() __asm__ __volatile__ ("nop" ::)
/***************************************************************************
* -----------------Function prototypes and global
variables----------------
***************************************************************************/
void initialize(void);
void transmit(unsigned char data);
unsigned char receive(void);
double ADCRead(unsigned int channel);
/***************************************************************************
* -------------------------------Functions--------------------------------
***************************************************************************/
int main(void){
double data;
int datatemp;
char output;
initialize();
transmit(0x0C); //Form Feed
while(1){
//Read and transmit channel 1 *************************************
data = ADCRead(0);
transmit(0x0A); //Line Feed
transmit(0x0D); //carriage return
//transmit low nibble
datatemp = (int)(data / 0x10);
if(datatemp<=9) output = datatemp|0x30;
else output = (datatemp-9)|0x40;
transmit(output);
//transmit high nibble
datatemp = (int)((char)data % 0x10);
if(datatemp<=9) output = datatemp|0x30;
else output = (datatemp-9)|0x40;
transmit(output);
//Read and transmit channel 2 *************************************
data = ADCRead(1);
transmit(0x0A); //Line Feed
transmit(0x0D); //carriage return
//transmit low nibble
datatemp = (int)(data / 0x10);
if(datatemp<=9) output = datatemp|0x30;
else output = (datatemp-9)|0x40;
transmit(output);
//transmit high nibble
datatemp = (int)((char)data % 0x10);
if(datatemp<=9) output = datatemp|0x30;
else output = (datatemp-9)|0x40;
transmit(output);
//Read and transmit channel 3 *************************************
data = ADCRead(2);
transmit(0x0A); //Line Feed
transmit(0x0D); //carriage return
//transmit low nibble
datatemp = (int)(data / 0x10);
if(datatemp<=9) output = datatemp|0x30;
else output = (datatemp-9)|0x40;
transmit(output);
//transmit high nibble
datatemp = (int)((char)data % 0x10);
if(datatemp<=9) output = datatemp|0x30;
else output = (datatemp-9)|0x40;
transmit(output);
//*****************************************************************
}
}// End function Main
/**************************************************************************
* initialize() sets pin directions and enables peripherals on the
* microcontroller
**************************************************************************/
void initialize(void){
//--------------------PORT Setup--------------------
DDRD = (1<<ADCCS);
//----------------RS-232 USART Setup----------------
// Set baud rate
UBRRH = (unsigned char)(baud>>8);
UBRRL = (unsigned char)baud;
// Enable receiver and transmitter
UCSRB = (1<<RXEN)|(1<<TXEN);
// Set frame format: 8data, 2stop bit
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
//------------------ADC/SPI Setup-------------------
ADCPORT = (1<<ADCCS); //Disable ADC
// Set MOSI and SCK output, all others input
DDRB = (1<<PB5)|(1<<PB7);
// Enable SPI, Master, set clock rate fck/128
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0);
//Globally enable enterrupts
sei();
//Initialize ADC by performing a conversion and ignoring the result
//ADCRead(1);
}// End function initialize
/**************************************************************************
* transmit() outputs a character on the RS-232 data bus
**************************************************************************/
void transmit(unsigned char data){
// Wait for empty transmit buffer
while ( !( UCSRA & (1<<UDRE)) );
// Put data into buffer, sends the data
UDR = data;
}//End function transmit
/**************************************************************************
* receive() receives a byte from the RS-232 data bus.
**************************************************************************/
unsigned char receive(void){
// Wait for data to be received
while ( !(UCSRA & (1<<RXC)) );
// Get and return received data from buffer
return UDR;
}//End function receive
/**************************************************************************
* ADCRead() reads the value of the selected channel on the external ADC.
* Accepts a channel number from 0-10.
**************************************************************************/
double ADCRead(unsigned int channel){
double data;
//Set Chip Select Low
ADCPORT = ADCPIN^(1<<ADCCS);
//Send ADC channel select and setup byte
SPDR = (channel<<4)|(ADCSetup);
transmit('d');//DEBUG***************************************************************
while(!(SPSR & (1<<SPIF))); //Wait for transmission to complete
//Wait for EOC
char EOC = 0;
transmit('e');//DEBUG***************************************************************
transmit('e');//DEBUG***************************************************************
while(!EOC){
EOC = (ADCPIN & (1<<ADCEOC)); //Wait for ADCEOC to go high
}
transmit('b');//DEBUG***************************************************************
//Receive 16 bit value
while(!(SPSR & (1<<SPIF))); // Wait for Reception to complete
data = SPDR;
transmit('u');//DEBUG***************************************************************
/*while(!(SPSR & (1<<SPIF))); // Wait for Reception to complete
transmit('g');//DEBUG***************************************************************
data += (SPDR<<8);*/
//Set Chip Select High
ADCPORT = ADCPIN|(1<<ADCCS);
transmit('g');//DEBUG***************************************************************
return data;
}Message
SPI Interface freezeup on Mega32
2006-03-25 by Robert Ussery
Attachments
- No local attachments were found for this message.