compiler
Compiling requires a compiler that knows the CPU. In the previous post I just cheated and used a mostly compatible CPU.
My Debian comes default with gcc 4.7.3 which does not support the new atxmega*e5 CPU's yet. Luckily someone already packaged the gcc 4.8.1 compiler source, so it was just a matter of recompiling Debian's gcc-avr package against the gcc 4.8.1 source package. If you don't feel like that using the atxmega*D4 as cpu type during compilation is doable.
avr-libc
Besides the compiler, avr-libc also needs to be adapted. It is avr-libc that provides the io description headers for the CPU's. There is no avr-libc for linux yet that does this. Luckily Atmel's AVR Studio product also uses gcc internally, and they already support the atxmega*e5 CPU's.
I took the files iox8e5.h, iox16e5.h and iox32e5.h from avr studio and copied these to /usr/lib/avr/include/avr/ .
Also /usr/lib/avr/include/avr/io.h needs to be updated to add the new CPU's:
--- io.h.old 2013-08-10 09:51:40.963241968 +0200 +++ io.h 2013-08-10 13:29:12.682545107 +0200 @@ -382,12 +382,6 @@ # include <avr/iox32a4.h> #elif defined (__AVR_ATxmega32D4__) # include <avr/iox32d4.h> +#elif defined (__AVR_ATxmega8E5__) +# include <avr/iox8e5.h> +#elif defined (__AVR_ATxmega16E5__) +# include <avr/iox16e5.h> +#elif defined (__AVR_ATxmega32E5__) +# include <pavr/iox32e5.h> #elif defined (__AVR_ATxmega64A1__) # include <avr/iox64a1.h> #elif defined (__AVR_ATxmega64A1U__)
With those two in place, compilation works :)
Example
- switch to the internal 32Mhz oscillator
- configure an USART on ports D6 and D7 at 9600 baud and run a simple echo follower
- blink a LED on port A0
// (c) 2013 Joost Yervante Damad <joost@damad.be> // License: GPL3 #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> static void usart_write(uint8_t data) { USARTD0.DATA = data; if(!(USARTD0.STATUS & USART_DREIF_bm)) { while(!(USARTD0.STATUS & USART_TXCIF_bm)); // wait for TX complete } USARTD0.STATUS |= USART_TXCIF_bm; // clear TX interrupt flag } static inline void init_oscillator() { // enable 32Mhz internal oscillator OSC.CTRL |= OSC_RC32MEN_bm; // wait for it to be stable while (!(OSC.STATUS & OSC_RC32MRDY_bm)); // tell the processor we want to change a protected register CCP=CCP_IOREG_gc; // and start using the 32Mhz oscillator CLK.CTRL=CLK_SCLKSEL_RC32M_gc; // disable the default 2Mhz oscillator OSC.CTRL&=(~OSC_RC2MEN_bm); // enable 32kHz calibrated internal oscillator OSC.CTRL|= OSC_RC32KEN_bm; while (!(OSC.STATUS & OSC_RC32KRDY_bm)); // set bit to 0 to indicate we use the internal 32kHz // callibrated oscillator as auto-calibration source // for our 32Mhz oscillator OSC.DFLLCTRL = OSC_RC32MCREF_RC32K_gc; // enable auto-calibration for the 32Mhz oscillator DFLLRC32M.CTRL |= DFLL_ENABLE_bm; } static inline void init_usart() { // enable clock out on port PC7 PORTCFG.CLKOUT = (PORTCFG.CLKOUT & ~PORTCFG_CLKOUTSEL_gm) | PORTCFG_CLKOUT_PC7_gc; // set PC7 as output PORTC.DIRSET = PIN7_bm; // set PD7 as output for TX0 PORTD.DIRSET = PIN7_bm; PORTD.OUTSET = PIN7_bm; // remap USARTD0 to PD[7-4] PORTD.REMAP |= PORT_USART0_bm; // set baud rate 9600: BSEL=12, BSCALE=4 // as found in table in // Atmel-42005-8-and-16-bit-AVR-Microcontrollers-XMEGA-E_Manual.pdf USARTD0.BAUDCTRLA = 12; // BSEL USARTD0.BAUDCTRLB = 4 << USART_BSCALE_gp; // BSCALE // disable 2X USARTD0.CTRLB = USARTD0.CTRLB & ~USART_CLK2X_bm; // enable RX and TX USARTD0.CTRLB = USARTD0.CTRLB | USART_RXEN_bm | USART_TXEN_bm; // enable async UART 8N1 USARTD0.CTRLC = USART_CMODE_ASYNCHRONOUS_gc | USART_PMODE_DISABLED_gc | USART_CHSIZE_8BIT_gc; USARTD0.CTRLC &= ~USART_SBMODE_bm; USARTD0.CTRLD = 0; // No LUT // set interrupt level for RX USARTD0.CTRLA = (USARTD0.CTRLA & ~USART_RXCINTLVL_gm) | USART_RXCINTLVL_LO_gc; } static inline void init_interrupts() { // Enable PMIC interrupt level low PMIC.CTRL |= PMIC_LOLVLEX_bm; // enable interrupts sei(); } static volatile uint8_t echo_char = 42; int main( void ) { init_oscillator(); // enable clock out on port PC7 PORTCFG.CLKOUT = (PORTCFG.CLKOUT & ~PORTCFG_CLKOUTSEL_gm) | PORTCFG_CLKOUT_PC7_gc; // set PC7 as output PORTC.DIRSET = PIN7_bm; init_usart(); init_interrupts(); // set PA0 as output PORTA.DIRSET = PIN0_bm; // blink LED on PA0 with 1 second on, 1 second off // write echo_char on USART on D7; defaults to 42(*) while (1) { usart_write(echo_char); PORTA.OUTSET = PIN0_bm; _delay_ms( 1000 ); usart_write(echo_char); PORTA.OUTCLR = PIN0_bm; _delay_ms( 1000 ); } } // USART RX receive interrupt handler ISR(USARTD0_RXC_vect) { echo_char = USARTD0.DATA; }
Code
I have some extra atxmega32e5 breakout boards available. You can find them in my tindie store.
breakout on a breadboard with USB-serial adapter |
In addition, the eagle schematic and board files are available on github as well.
More fun
I'm still exploring this nice little microcontroller. Be sure to check back later on my blog for new adventures!
No comments:
Post a Comment