Simple USART not working on xmega32a4u [solved]

Go To Last Post
23 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm stuck getting a trivial USART test program working on a xmega32A4U.

Trying to debug it with some connected LEDs renders the problem even more confusing. The following code is supposed to write 'Hello World' at 9600 baud via USARTD0 (pin D3). It works only partially with the following symptoms:

- If the line with 'light LED 0' is commented I get an infinite amount of the character 'H'. LED1 never lights (the printf call never returns).
- If the line with 'light LED 0' is active, the LED0 lights, but I get no output at all. Nothing, nada.

I'm using the AVR toolchain provided by Atmel (Release 3.4.0.663).

Here the compilation steps:

avr-gcc -g -DF_CPU=2000000 -Wall -Os -mmcu=atxmega32a4u    -c -o serial-out.o serial-out.c
avr-gcc -g -DF_CPU=2000000 -Wall -Os -mmcu=atxmega32a4u  -Wl,-Map,serial-out.map -o serial-out.elf serial-out.o 
avr-objcopy -j .text -j .data -O ihex serial-out.elf serial-out.hex
avrdude -q -p x32a4 -F -c dragon_pdi -P usb -U flash:w:serial-out.hex

Here the program:

#include 
#include 
#include 

static int uart_putchar(char c, FILE *stream);
static void uart_init (void);

static FILE mystdout = FDEV_SETUP_STREAM (uart_putchar, NULL, _FDEV_SETUP_WRITE);

int main (void)
{
    uart_init();
    stdout = &mystdout;

    PORTC.DIR = 0xFF;   // port C

    while (1)
//      PORTC.OUTSET = PIN0_bm; // light LED 0
        printf("Hello, world!\n");
        PORTC.OUTSET = PIN1_bm; // light LED 1
}


static int uart_putchar (char c, FILE *stream) {
    if (c == '\n')
        uart_putchar('\r', stream);

    // Wait for the transmit buffer to be empty
    while ( !( USARTD0.STATUS & USART_DREIF_bm) );

    // Put our character into the transmit buffer
    USARTD0.DATA = c;

    return 0;
}

// Init USART.  Transmit only (we're not receiving anything)
// We use USARTD0, transmit pin on PC3.
// Want 9600 baud. Have a 2 MHz clock. BSCALE = 0
// BSEL = ( 2000000 / (2^0 * 16*9600)) -1 = 12
// Fbaud = 2000000 / (2^0 * 16 * (12+1))  = 9615 bits/sec
static void uart_init (void) {
    // Set the TxD pin high - set PORTC DIR register bit 3 to 1
    PORTD.OUTSET = PIN3_bm;

    // Set the TxD pin as an output - set PORTC OUT register bit 3 to 1
    PORTD.DIRSET = PIN3_bm;

    // Set baud rate & frame format
    USARTD0.BAUDCTRLB = 0;                      // BSCALE = 0 as well
    USARTD0.BAUDCTRLA = 12;

    // Set mode of operation
    USARTD0.CTRLA = 0;                          // no interrupts please
    USARTD0.CTRLC = 0x03;                       // async, no parity, 8 bit data, 1 stop bit

    // Enable transmitter only
    USARTD0.CTRLB = USART_TXEN_bm;
}

Edit: This is essentially a code snippet copied from the Web. But simple enough that it should just work,

Markus

Last Edited: Wed. Aug 1, 2012 - 08:32 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't know why turning on an LED would prevent the USART from working...unless you have power problems.

The code looks like it should work. As a test, you could try replacing USART_DREIF_bm with USART_TXCIF_bm in the uart_putchar's while() loop.

Gamu The Killer Narwhal
Portland, OR, US
_________________
Atmel Studio 6.2
Windows 8.1 Pro
Xplained boards mostly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Would curly braces after the while(1) help?
This isn't Python, you know! :wink:

Nigel Batten
www.batsocks.co.uk

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Adding curly braces around the loop helps in part. It explains case 2), where I have no output. But for case 1) it is till the same: I get a endless loop of 'H' characters (1st character of the string, actually) and the printf never returns.
The loop looks now (and should have been looking) like this:

while (1) {
        PORTC.OUTSET = PIN0_bm; // light LED 0
        printf("Hello, world!\n");
        PORTC.OUTSET = PIN1_bm; // light LED 1
    }

As Output I get this:

HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not sure how printf is implemented on avr, but maybe you should try creating your own function to output streams, something like

 int sendString(char *string, FILE *stream){
  while(*(string) != "\0")
    usart_putchar(*(string++), stream);

  return 0;
}

Alberto

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Markus,

The code works fine on my XMega32A4U:

Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!

I'm also using:

avr-gcc (AVR_8_bit_GNU_Toolchain_3.4.0_663) 4.6.2

For reference (and it's unlikely to help), here's the compile command (spat out from my 'normal' makefile - I don't pretend to understand it all)

avr-gcc -c -mmcu=atxmega32a4 -I. -gdwarf-2 -DF_CPU=2000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=./main.lst  -std=gnu99 -MMD -MP -MF .dep/main.o.d main.c -o main.o

and here's the linker command...

avr-gcc -mmcu=atxmega32a4 -I. -gdwarf-2 -DF_CPU=2000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=main.o  -std=gnu99 -MMD -MP -MF .dep/main.elf.d main.o --output main.elf -Wl,-Map=main.map,--cref     -lm

As shown above, I compiled it for the XMega32A4, but it also works when compiled for the XMega32A4U (which makes the code slightly larger).

Nigel Batten
www.batsocks.co.uk

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

algrizz wrote:
Not sure how printf is implemented on avr, but maybe you should try creating your own function to output streams, something like

 int sendString(char *string, FILE *stream){
  while(*(string) != "\0")
    usart_putchar(*(string++), stream);

  return 0;
}


I've tried is with your sendString instead of the printf. Same result, it prints 'HHHHHHHHHHHH'. I did have a similar routine on my own before with that same result. Then I went to search for examples on the net.

I've modified your code as follows, the LED does not light !

int sendString(char *string, FILE *stream){
    while(*(string) != "\0") {
        uart_putchar(*(string++), stream);
        PORTC.OUTSET = PIN2_bm; // light LED 2
    }

    return 0;
}

Next step: Try with compiler parameters...

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tried your code on a 128a1 (changed to USARTE0, since I have a FTDI-chip connected to that). It worked both with your command lines (changed to 128a1) and the commands I happened to have in my Makefile.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've attached my testcases. Can someone try the hex files ?

It is using the UARTD0 (Port D3, pin 23) at 9600 baud.

Attachment(s): 

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The code works.

I've just loaded serial-out.hex-printf onto a 32a4u and it works without any problems. A nice list of hello worlds.

I used

avrdude -px32a4 -Pusb -cavrisp2 -e -U flash:w:serial-out.hex-printf

and it squirts nicely into my PC via a SparkFun 3.3v FTDI USB adapter.

So if it's not the code... what is it?! Decoupling caps? Rubbish terminal software? Programming failure?

Nigel Batten
www.batsocks.co.uk

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just reinstalled avr-gcc-4.5.1 (the debian package from the wrightflyer site). There is one difference: Now both printf and sendString generate just 'H' characters.

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

condemned wrote:
The code works.

I've just loaded serial-out.hex-printf onto a 32a4u and it works without any problems. A nice list of hello worlds.

I used

avrdude -px32a4 -Pusb -cavrisp2 -e -U flash:w:serial-out.hex-printf

and it squirts nicely into my PC via a SparkFun 3.3v FTDI USB adapter.

So if it's not the code... what is it?! Decoupling caps? Rubbish terminal software? Programming failure?

OK, So I have to verify the hardware. My x32a4u (QFP44) is had-soldered on a breakout board. On the board I do wire Vcc and Gnd together on the two available rails and there is a 100n decoupling cap.

I supply is with power via breadboard 3.3V supply, this supply gets its power from a USB power supply.

I can imagine that something causes a reset (brownout) and the 'H's come from the boot/reset loop.

Thanks for the help !

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The other version (serial-out.hex-sendstring) didn't work, however. The compilation warning was the hint...

Changing the code in sendString from

while(*(string) != "\0") {

to

while(*(string) != '\0') {

makes it work just fine.

Summary
Both versions of code now work fine.
The sendString version needed a tweak.

Each pair of power pins needs decoupling as close to the pins as possible.

Nigel Batten
www.batsocks.co.uk

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I did measure all pins, there is no short between any of them. Vcc and Gnd is connected the respective pins, too. I've measured Vcc at 2.28V. I've measured the noise on Vcc, I have impulses 50mV peak, with a 0.25us period. I suspect they are artifact of the default 2Mhz clock.

However in another test (the venerable led blinky), I make all ports blink and I have PA5 PA6 and PC6 wo do not blinks. All other ports do blink (and a initialize and blink the all pins at once).

Also the chip programs just fine.

Is my chip faulty ?

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you added a decoupling cap to each pair of power pins? Near the pins?
Is the measured 2.28v coming from the 3.3v supply you mentioned earlier? If so, that seems very, very low.
Do you have any brown-out fuses programmed? (note that the brown-out voltages are different between the original and U variants of the chips)

Nigel Batten
www.batsocks.co.uk

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I seem to be very prone to typos. The voltage was 3.28 Volt (2.28 was a type). Much better !

In the meantime I've removed the chip and soldered another one in place. Hot air gun to the rescue !

This has solved the blink problem, I suppose the pins were not soldered well enough. This time I used a bit of solder pasta and hot air.

Blocking condensators: There is one on the protoboard. The protoboard has two power rails and all four power pins are connect there with short and quite think wires.

I have not touched the brownout/fuses at all.

Here the setup:

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So there's just one decoupling cap on the whole board :shock:

If you've got any more 100nF caps, you could try plugging one into the sockets for each pair of power pins. Whilst not ideal, it might help.

AVR1012 wrote:
Decoupling capacitor should be placed close to the device for each supply pin pair in the signal group, low ESR caps should be used for better decoupling

For reference, I worry if my decoupling caps are farther away than this:

p.s. I love the idea of solder pasta :wink:

Nigel Batten
www.batsocks.co.uk

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

On the PCB I've designed I have a decoupling cap close to each pin. But I don't think this is that a big deal on a prototype for sending hello world out the UART. I'd complain about noise on my ADC and similar things, fine. But here I have only a micro, completely on its own.

However, I've added now an additional 330n ceramic and a 10u electrolytic. The noise on the power rails is now down to <10mV peak-to-peak.

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Did another test: Added a delay at the start. And added an additional blink there. The LED is now blinking due to a reset loop.

Added the hex here, could you test it ?

Here is sends a single mangled character out on pin23 and blinks o n pin10.

Attachment(s): 

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The following code snipped does work. The problem seems to be related subroutine calls. Do I thrash my stack ? How can I verify ?

int main (void) {
    char *s;
    uart_init();
    stdout = &mystdout;

    PORTC.DIR = 0xFF;   // port C

    _delay_ms(500); 
    PORTC.OUTCLR = PIN0_bm;     // light LED 0
    _delay_ms(500); 
    while (1) {
        s = hello;

        PORTC.OUTSET = PIN0_bm; // light LED 0
        while (*(s)!='\0') {
            while ( !( USARTD0.STATUS & USART_DREIF_bm) );
            USARTD0.DATA = *(s++);
        }
        _delay_ms(100);
        PORTC.OUTSET = PIN2_bm; // light LED 1
    }
}

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Markus,

The .hex works just fine. A continuous stream of

Hello, world!
Hello, world!
Hello, world!
Hello, world!

Pins c0, c1 and C2 are high. I couldn't see any pulses on them.

Nigel Batten
www.batsocks.co.uk

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Nigel,

It blinks only on reset. It blinks on mine, therefore I have a reset (when calling the sendString routine).
If I integrate the putchar and sendstring into main, then it works, see the last test.

Findings:
- The same binary/hex file runs differently on your atxmega32A4U and on mine. Works on yours, resets on mine.
-> This lets me suspect a hardware problem, causing the reset.

- If I eliminate subroutine calls (everything in main), then it works on mine too.
-> This lets me suspect a software problem (stack overrun), causing the reset.

Confused.

Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

After a week away from home (with no AVR) and installing Studio 6 in desperation in a VM I found the problem. It was related to stack and subroutine calls and it was hardware. The actual devices I have are xmega16a4u and not xmega32a4u.

What helped mislead me was that avrdude does not know about the -U variety. So I overwrote the signature check with -F, believing that avrdude complains about the signature because of the -U variety.

Markus