Using the ADC and outputting the data to the USART:In this section we will set up the ADC of the microcontroller to do a simple single conversion and then send the value to the USART (after converting it to an Ascii character string).Initialising the ADC: If you have run through the previous sections in this AVR-32 blog, you should be feeling more confident with accessing the various registers and functions of the 32-bit microcontrollers. So we can launch straight in with the initialisation of the ADC:The code itself is fairly self explanatory. The ADC section of the data sheet gives more information about the registers used. It’s worth noting the reset values of the various registers (typically zero), and what functions are set up by default as a result. This allows only the bare minimum of register changes to be set. A couple of notes regarding the auto-complete function, which tend to cause a few compiling errors if not spotted:•Be very aware that something like: AVR32_ADCIFA_INNSEL00_CNV0is actually adefined valuewhere as: AVR32_ADCIFA.INPSEL00.cnv0 refers to a section of a register.•Similarly: AVR32_ADCIFA.innsel00 refers to the wholevalue of theregister(and is expected to be followed by =[value];where as: AVR32_ADCIFA.INNSEL00 refers to part of a register(and is expected to be followed by which part you wish to address e.g. .cnv0)Converting a number to a string of characters:One useful routine to have around is for converting a number to a string of Ascii characters that can easily be viewed on something like RealTerm com-port viewer (after sending over the USART). To avoid complicating the routine with pointers, the variables ADC and Sign are made public in the initial part of the code. Full ADC to character string code:The code shown below combines the above sections with the previously introduced code. The 10-bit ADC value from differential inputs on pins PA4 and PA19 and continuously sent as a character string. The main routine: •Signals for the start of a new ADC conversion, and then waits for it to complete. •Copies the value to a variable and sends this to be converted into a character string. •This is then sent over the USART before resetting the ADC end of sequence flag. A couple of notes on the code:AVR studio in its many guises often has issues with returning actual values from variables in debugging mode. In this case the variable ADC_Value could be stated as an integer however when debugging it always has the value of zero. Forcing the variable to be a volatile solves this problem, and the value can be check. However it was found that the value would not be updated properly if the code was interrupted each ADC cycle, only if the code was allowed to proceeded and then paused after some interval. The subroutine Send_Serial could use a simple loop to send each character of the string to the USART. However from experience with AVR-8 microcontrollers, this can sometimes lead to loss of data as the loop takes too much controller processing time and the synchronisation of the serial data is lost. “Carriage return” and “line feed” characters are added to the end of the data. This formats the data nicely in the com-port viewer, returning placing the cursor to the start of the next line.
voidInitialise_ADC(void){// Initialise the ADC// Active Pins PA4(ADCIN0+) and PA19(ADCIN8-) GPIO= 4 & 19 (port 0) function A// Set up the GPIO registersAVR32_GPIO.port[0].gperc=1<<4;// Set to peripheral modeAVR32_GPIO.port[0].gperc=1<<19;// Set to peripheral modeAVR32_GPIO.port[0].puerc=1<<4;// Clear pull-upAVR32_GPIO.port[0].puerc=1<<19;// Clear pull-up// Set PMR2,PMR1,PMR0 to 000 -AAVR32_GPIO.port[0].pmr0c=1<<4;AVR32_GPIO.port[0].pmr1c=1<<4;AVR32_GPIO.port[0].pmr2c=1<<4;// select function A for the mux GPIO register see page 468AVR32_GPIO.port[0].pmr0c=1<<19;AVR32_GPIO.port[0].pmr1c=1<<19;AVR32_GPIO.port[0].pmr2c=1<<19;// select function A for the mux GPIO register see page 468//…………..AVR32_ADCIFA.CFG.adcen=0;// Ensure ADC is disabled before settingAVR32_ADCIFA.CFG.shd=1;// No sample and hold (no gain control)AVR32_ADCIFA.CFG.rs=1;// Use 0.6xVDDANA as reference voltageAVR32_ADCIFA.CFG.ssmq=1;// Single sequence modeAVR32_ADCIFA.SEQCFG0.cnvnb=0;// Do 1 conversion onlyAVR32_ADCIFA.SEQCFG0.sres=1;// 10 bit accuracyAVR32_ADCIFA.ckdiv=3;// Set the clock divide by to 3 to get from 8MHz to <1.5MHzAVR32_ADCIFA.INPSEL00.cnv0=0;// Set Positive pin to ADCIN0AVR32_ADCIFA.INNSEL00.cnv0=0;// Set Negative pin to ADCIN8 (see page 1147)AVR32_ADCIFA.CFG.adcen=1;// Enable ADC}
voidInt_To_Ascii(intX){// Converts a signed integer number into an Ascii arrayunsignedintY,Th,T,U,H;Sign=’+’;Y=X;if(X<0){Y=(!X+1);// Effectively ‘two’s complement – converts to an unsigned value plus signSign=’-‘;}Th=Y/1000;// Calculate the whole number of Thousands, Hundreds, Tens and UnitsH=Y/100-Th*10;T=Y/10-Th*100-H*10;U=Y–T*10-H*100-Th*1000;ADC[0]=U+48;// Add 48 to the Value to convert it to the correct character and allocate to arrayADC[1]=T+48;ADC[2]=H+48;ADC[3]=Th+48;}
#include<avr32/io.h>voidInitialise_USART(void);voidInitialise_ADC(void);voidInt_To_Ascii(intX);voidSend_Serial(void);unsignedlongi,j;volatileADC_Value;// Defaults to integer but will not return a value in debug mode if not set to volatile.// Note also value does not update in debug mode, program must be run and stopped to see any changeunsignedcharSign,ADC[3];// Variables used to hold the Ascii string for the ADC Valueintmain(void){Initialise_USART();Initialise_ADC();while(1){AVR32_ADCIFA.CR.soc0=1;// Start sequence 0 conversionwhile(!(AVR32_ADCIFA.SR.seos0&0b1)){;// wait here until sequence is completed see page 1124}ADC_Value=AVR32_ADCIFA.resx[0];Int_To_Ascii(ADC_Value);// Convert the number to an Ascii StringSend_Serial();// Send the characters over the serial coms.AVR32_ADCIFA.SCR.seos0=1;// Clear the end of sequence flag}}//=========================================================================voidInitialise_USART(void){// Initialise the USART for serial comms// For 384OO baud CD is 13 @ 8MHz 20 @12 MHz// TX is on USART0 PC16 – GPIO 80 = port 2 pin 16unsignedcharCalibrationValue;// Initialise 8MHZ system clockCalibrationValue=AVR32_SCIF.RCCR8.calib;// Store 8MHz Calibration valueAVR32_SCIF.unlock=((AVR32_SCIF_UNLOCK_KEY_VALUE<<AVR32_SCIF_UNLOCK_KEY_OFFSET)|AVR32_SCIF_RCCR8);// Unlock the register to allow a change to be madeAVR32_SCIF.rccr8=((1<<AVR32_SCIF_RCCR8_RCOSC8_EN_OFFSET)|CalibrationValue);// Enable 8MHZ clock with original calibrationAVR32_PM.unlock=((AVR32_PM_UNLOCK_KEY_VALUE<<AVR32_PM_UNLOCK_KEY_OFFSET)|AVR32_PM_MCCTRL_MCSEL_OFFSET);// Unlock the PM register to allow a change of clock sourceAVR32_PM.mcctrl=AVR32_PM_MCCTRL_MCSEL_RCOSC8;// Select internal 8MHz main clock (see p 60)// Set up the GPIO registers – Peripheral interface D withAVR32_GPIO.port[2].gperc=1<<16;// Set to peripheral mode (clear bit)// Set PMR2,PMR1,PMR0 to 011 -D for the mux GPIO register see page 468AVR32_GPIO.port[2].pmr0s=1<<16;// SetAVR32_GPIO.port[2].pmr1s=1<<16;// SetAVR32_GPIO.port[2].pmr2c=1<<16;// Clear// Program USART0 (all bits set to 0 on reset)AVR32_USART0.MR.usart_mode.par=0b100;// No ParityAVR32_USART0.MR.usart_mode.chrl=0b11;// 8 Data BitsAVR32_USART0.BRGR.cd=13;// Set Baud Rate to 38400 @ 8MHzAVR32_USART0.CR.usart_mode.txen=1;// Activate transmitter}//=========================================================================voidInitialise_ADC(void){// Initialise the ADC// Active Pins PA4(ADCIN0+) and PA19(ADCIN8-) GPIO= 4 & 19 (port 0) function A// Set up the GPIO registersAVR32_GPIO.port[0].gperc=1<<4;// Set to peripheral modeAVR32_GPIO.port[0].gperc=1<<19;// Set to peripheral modeAVR32_GPIO.port[0].puerc=1<<4;// Clear pull-upAVR32_GPIO.port[0].puerc=1<<19;// Clear pull-up// Set PMR2,PMR1,PMR0 to 000 -AAVR32_GPIO.port[0].pmr0c=1<<4;AVR32_GPIO.port[0].pmr1c=1<<4;AVR32_GPIO.port[0].pmr2c=1<<4;// select function A for the mux GPIO register see page 468AVR32_GPIO.port[0].pmr0c=1<<19;AVR32_GPIO.port[0].pmr1c=1<<19;AVR32_GPIO.port[0].pmr2c=1<<19;// select function A for the mux GPIO register see page 468//…………..// Program ADC Note values use the underscore… addresses use the .AVR32_ADCIFA.CFG.adcen=0;// Ensure ADC is disabled before settingAVR32_ADCIFA.CFG.shd=1;// No sample and hold (no gain control)AVR32_ADCIFA.CFG.rs=1;// Use 0.6xVDDANA as reference voltageAVR32_ADCIFA.CFG.ssmq=1;// Single sequence modeAVR32_ADCIFA.SEQCFG0.cnvnb=0;// Do 1 conversion onlyAVR32_ADCIFA.SEQCFG0.sres=1;// 10 bit accuracyAVR32_ADCIFA.ckdiv=3;// Set the clock divide by to 3 to get from 8MHz to <1.5MHzAVR32_ADCIFA.INPSEL00.cnv0=0;// Set Positive pin to ADCIN0AVR32_ADCIFA.INNSEL00.cnv0=0;// Set Negative pin to ADCIN8 (see page 1147)AVR32_ADCIFA.CFG.adcen=1;// Enable ADC}//=========================================================================voidInt_To_Ascii(intX){// Converts a signed integer number into an ascii arrayunsignedintY,Th,T,U,H;Sign=’+’;Y=X;if(X<0){Y=X*-1;// Effectively ‘two’s complement – converts to an unsigned value plus signSign=’-‘;}Th=Y/1000;// Calculate the whole number of Thousands, Hundreds, Tens and UnitsH=Y/100-Th*10;T=Y/10-Th*100-H*10;U=Y–T*10-H*100-Th*1000;ADC[0]=U+48;// Add 48 to the Value to convert it to the correct character and allocate to arrayADC[1]=T+48;ADC[2]=H+48;ADC[3]=Th+48;}//=========================================================================voidSend_Serial(void){// Sends ADC numbers over the serial interface// Note a loop is not used as this can sometimes cause delays in program executionAVR32_USART0.THR.txchr=Sign;// Send characterwhile(!(AVR32_USART0.CSR.usart_mode.txrdy&0b1)){;// wait here until buffer empties}AVR32_USART0.THR.txchr=ADC[3];// Send characterwhile(!(AVR32_USART0.CSR.usart_mode.txrdy&0b1)){;// wait here until buffer empties}AVR32_USART0.THR.txchr=ADC[2];// Send characterwhile(!(AVR32_USART0.CSR.usart_mode.txrdy&0b1)){;// wait here until buffer empties}AVR32_USART0.THR.txchr=ADC[1];// Send characterwhile(!(AVR32_USART0.CSR.usart_mode.txrdy&0b1)){;// wait here until buffer empties}AVR32_USART0.THR.txchr=ADC[0];// Send characterwhile(!(AVR32_USART0.CSR.usart_mode.txrdy&0b1)){;// wait here until buffer empties}AVR32_USART0.THR.txchr=13;// Send carriage returnwhile(!(AVR32_USART0.CSR.usart_mode.txrdy&0b1)){;// wait here until buffer empties}AVR32_USART0.THR.txchr=10;// Send line feedwhile(!(AVR32_USART0.CSR.usart_mode.txrdy&0b1)){;// wait here until buffer empties}}//=========================================================================