Search code examples
cembeddedavravr-gccusart

Sending mutiple characters using USART1 on an atmega4809 results in 0xFF to be send


Solution:

Turns out it did not have anything to do with the USART. The problem was in the Makefile. I reused a Makefile I have been using for atmega328p and atmega2560 for a long time. But this Makefile does not include the .rodata section when converting the elf to hex file. I guess this section is never used for the "older" atmega parts. After including the .rodata section in the hex file everything worked as expected for the atmega4809.

Makefile part before:

$(OUT).hex: $(OUT).elf
    rm -f $(OUT).hex $(OUT).eep.hex
    $(OBJCOPY) -j .text -j .data -O ihex $(OUT).elf $(OUT).hex
    $(SIZE) $(OUT).hex

Makefile part after:

$(OUT).hex: $(OUT).elf
    rm -f $(OUT).hex $(OUT).eep.hex
    $(OBJCOPY) -j .text -j .data -j .rodata -O ihex $(OUT).elf $(OUT).hex
    $(SIZE) $(OUT).hex

Original question:

The following code results in:

enter image description here

#include <avr/io.h>

#define BAUDRATE 115200
#define BAUD_REG (F_CPU  * 64UL) / (16UL * BAUDRATE) 

void usart_init(USART_t * usart) {
  // Sets up usart
  usart->BAUD = BAUD_REG;
  usart->CTRLB = (1 << USART_TXEN_bp) | (1 << USART_RXEN_bp);
}

void usart_write(USART_t * usart, char c) {
    // Wait TX ready
    while (!(usart->STATUS & USART_DREIF_bm)) {;;}
    // Send character
    usart->TXDATAL = c;
}

int main(void)
{
  // Setup 16 MHz clock internal clock
  CCP = 0xD8;
  CLKCTRL_MCLKCTRLB = 0;

  // Setup uart1
  // Set alternate pin mux for uart1 to PC4 and PC5
  PORTMUX.USARTROUTEA |= PORTMUX_USART1_0_bm;
  // Set TX pin output
  VPORTC.DIR |= PIN4_bm;
  // Setup USART1
  usart_init(&USART1);

  // String to send
  char st[] = "Hello world!";
  // Pointer to iterate of characters
  char * st_ptr = st;

  // Send char -> works fine
  usart_write(&USART1, 'a');

  // Send string -> sends garbage
  while (*st_ptr) {
    usart_write(&USART1, *st_ptr++);
  }

  // Send another char -> works fine
  usart_write(&USART1, 'b');

  while (1) {;;}
}

I would expect "aHello world!b".

Writing single characters always works fine. When writing strings, the first character is fine the remaining characters result in 0xFF.

  • I've tried different baudrates (all same result).

  • Different compilers (The microchip toolchain, manually build gcc).

  • Adding a delay after sending each character. (same result).

What am I missing here?

Update: I changed to sending code to:

  // Send char -> works fine
  usart_write(&USART1, 'a');

  // String to send
  const char* st = "Hello world!";
  uint8_t i;
  for (i=0; i<8; i++) {
    char s = st[i];
    usart_write(&USART1, s);
  }

  // Send another char -> works fine
  usart_write(&USART1, 'b');

No difference unfortunately: a��������b

Update 2, progress:

  // Send char -> works fine
  usart_write(&USART1, 'a');

  // String to send
  const char* st = "Hello world!";
  usart_write(&USART1, st[0]);
  usart_write(&USART1, st[1]);
  usart_write(&USART1, st[2]);
  usart_write(&USART1, st[3]);
  usart_write(&USART1, st[4]);

  // Send another char -> works fine
  usart_write(&USART1, 'b');

Results in: aHellob

update 3:

  // Send char -> works fine
  usart_write(&USART1, 'a');

  // String to send
  const char* st = "UUUUUUUU";

  uint8_t i;
  for (i=0; i<8; i++) {
    char s = st[i];
    usart_write(&USART1, s);
  }

  usart_write(&USART1, st[0]);
  usart_write(&USART1, st[1]);
  usart_write(&USART1, st[2]);
  usart_write(&USART1, st[3]);
  usart_write(&USART1, st[4]);

  // Send another char -> works fine
  usart_write(&USART1, 'b');

No luck: a��������UUUUUb

Update 4 (delay added):

  // Send char -> works fine
  usart_write(&USART1, 'a');

  // String to send
  const char* st = "Hello world!";

  uint8_t i;
  for (i=0; i<8; i++) {
    char s = st[i];
    usart_write(&USART1, s);
    _delay_ms(10);
  }

  usart_write(&USART1, st[0]);
  usart_write(&USART1, st[1]);
  usart_write(&USART1, st[2]);
  usart_write(&USART1, st[3]);
  usart_write(&USART1, st[4]);

  // Send another char -> works fine
  usart_write(&USART1, 'b');

No luck: a��������Hellob

update 5: Found: hello world example Where the following code is used:

void USART1_sendChar(char c)
{
    while (!(USART1.STATUS & USART_DREIF_bm))
    {
        ;
    }        
    USART1.TXDATAL = c;
}

void USART1_sendString(char *str)
{
    for(size_t i = 0; i < strlen(str); i++)
    {
        USART1_sendChar(str[i]);
    }
}

Seems very similar

Update 6: Changed clock to 20MHz internal oscillator Disabled compiler optimizations, makefile snip:

# parent directory of the toolchain, device pack, and pyupdi directories
AVR_BASE_DIR      := /home/paul/workspace/atmega4809
#AVR_TOOLCHAIN_DIR := $(AVR_BASE_DIR)/avr8-gnu-toolchain-$(HOST_OS)_$(HOST_ARCH)
AVR_TOOLCHAIN_DIR := /usr
AVR_DFP_DIR       := $(lastword $(sort $(wildcard $(AVR_BASE_DIR)/Atmel.ATmega_DFP*)))

#CFLAGS_COMMON = -O2 -B $(AVR_DFP_DIR)/gcc/dev/$(DEVICE) -I $(AVR_DFP_DIR)/include -Wall -DF_CPU=$(F_CPU) -mmcu=$(DEVICE) -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -fdata-sections -ffunction-sections --param=min-pagesize=0 -mrelax -MMD -MP -Wa,-adhlns=$(OUT).lst
CFLAGS_COMMON = -O0 -B $(AVR_DFP_DIR)/gcc/dev/$(DEVICE) -I $(AVR_DFP_DIR)/include -Wall -DF_CPU=$(F_CPU) -mmcu=$(DEVICE) --param=min-pagesize=0 -mrelax -MMD -MP -Wa,-adhlns=$(OUT).lst
  // Send char -> works fine
  usart_write(&USART1, 'a');

  // String to send
  const char* st = "Hello world!";

  uint8_t i;
  for (i=0; i<8; i++) {
    char s = st[i];
    usart_write(&USART1, s);
  }

  usart_write(&USART1, st[0]);
  usart_write(&USART1, st[1]);
  usart_write(&USART1, st[2]);
  usart_write(&USART1, st[3]);
  usart_write(&USART1, st[4]);

  // Send another char -> works fine
  usart_write(&USART1, 'b');

Now every char from string "st" fails : a�������������b

Turning compiler optimizations back on:

CFLAGS_COMMON = -O2 -B $(AVR_DFP_DIR)/gcc/dev/$(DEVICE) -I $(AVR_DFP_DIR)/include -Wall -DF_CPU=$(F_CPU) -mmcu=$(DEVICE) -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -fdata-sections -ffunction-sections --param=min-pagesize=0 -mrelax -MMD -MP -Wa,-adhlns=$(OUT).lst

Some chars are working again:

a��������Hellob

Update 7:

  const char st[] = "Hello world!";

results in: a��������He���b

  const char * st = "Hello world!";

results in: a��������Hellob

update 8: Switched to usart2: Same result

Update 9: Its the initialization of the array:

 // String to send
  char st[8];
  st[0] = 'H';
  st[1] = 'e';
  st[2] = 'l';
  st[3] = 'l';
  st[4] = 'o';
  st[5] = ' ';
  st[6] = 'w';
  st[7] = 'o';

  // Send char -> works fine
  usart_write(&USART2, 'a');

  uint8_t i;
  for (i=0; i<8; i++) {
    char s = st[i];
    usart_write(&USART2, s);
  }

  usart_write(&USART2, st[0]);
  usart_write(&USART2, st[1]);
  usart_write(&USART2, st[2]);
  usart_write(&USART2, st[3]);
  usart_write(&USART2, st[4]);

  // Send another char -> works fine
  usart_write(&USART2, 'b');

Result: aHello woHellob


Solution

  • Here is disassembly blink.hex file from the link in comments

    Disassembly of section .sec1:
    
    00000000 <.sec1>:
       0:   4f c0           rjmp    .+158           ;  0xa0
       2:   00 00           nop
       4:   55 c0           rjmp    .+170           ;  0xb0
       6:   00 00           nop
       8:   53 c0           rjmp    .+166           ;  0xb0
       a:   00 00           nop
       c:   51 c0           rjmp    .+162           ;  0xb0
       e:   00 00           nop
      10:   4f c0           rjmp    .+158           ;  0xb0
      12:   00 00           nop
      14:   4d c0           rjmp    .+154           ;  0xb0
      16:   00 00           nop
      18:   4b c0           rjmp    .+150           ;  0xb0
      1a:   00 00           nop
      1c:   49 c0           rjmp    .+146           ;  0xb0
      1e:   00 00           nop
      20:   47 c0           rjmp    .+142           ;  0xb0
      22:   00 00           nop
      24:   45 c0           rjmp    .+138           ;  0xb0
      26:   00 00           nop
      28:   43 c0           rjmp    .+134           ;  0xb0
      2a:   00 00           nop
      2c:   41 c0           rjmp    .+130           ;  0xb0
      2e:   00 00           nop
      30:   3f c0           rjmp    .+126           ;  0xb0
      32:   00 00           nop
      34:   3d c0           rjmp    .+122           ;  0xb0
      36:   00 00           nop
      38:   3b c0           rjmp    .+118           ;  0xb0
      3a:   00 00           nop
      3c:   39 c0           rjmp    .+114           ;  0xb0
      3e:   00 00           nop
      40:   37 c0           rjmp    .+110           ;  0xb0
      42:   00 00           nop
      44:   35 c0           rjmp    .+106           ;  0xb0
      46:   00 00           nop
      48:   33 c0           rjmp    .+102           ;  0xb0
      4a:   00 00           nop
      4c:   31 c0           rjmp    .+98            ;  0xb0
      4e:   00 00           nop
      50:   2f c0           rjmp    .+94            ;  0xb0
      52:   00 00           nop
      54:   2d c0           rjmp    .+90            ;  0xb0
      56:   00 00           nop
      58:   2b c0           rjmp    .+86            ;  0xb0
      5a:   00 00           nop
      5c:   29 c0           rjmp    .+82            ;  0xb0
      5e:   00 00           nop
      60:   27 c0           rjmp    .+78            ;  0xb0
      62:   00 00           nop
      64:   25 c0           rjmp    .+74            ;  0xb0
      66:   00 00           nop
      68:   23 c0           rjmp    .+70            ;  0xb0
      6a:   00 00           nop
      6c:   21 c0           rjmp    .+66            ;  0xb0
      6e:   00 00           nop
      70:   1f c0           rjmp    .+62            ;  0xb0
      72:   00 00           nop
      74:   1d c0           rjmp    .+58            ;  0xb0
      76:   00 00           nop
      78:   1b c0           rjmp    .+54            ;  0xb0
      7a:   00 00           nop
      7c:   19 c0           rjmp    .+50            ;  0xb0
      7e:   00 00           nop
      80:   17 c0           rjmp    .+46            ;  0xb0
      82:   00 00           nop
      84:   15 c0           rjmp    .+42            ;  0xb0
      86:   00 00           nop
      88:   13 c0           rjmp    .+38            ;  0xb0
      8a:   00 00           nop
      8c:   11 c0           rjmp    .+34            ;  0xb0
      8e:   00 00           nop
      90:   0f c0           rjmp    .+30            ;  0xb0
      92:   00 00           nop
      94:   0d c0           rjmp    .+26            ;  0xb0
      96:   00 00           nop
      98:   0b c0           rjmp    .+22            ;  0xb0
      9a:   00 00           nop
      9c:   09 c0           rjmp    .+18            ;  0xb0
      9e:   00 00           nop
      a0:   11 24           eor     r1, r1
      a2:   1f be           out     0x3f, r1        ; 63
      a4:   cf ef           ldi     r28, 0xFF       ; 255
      a6:   cd bf           out     0x3d, r28       ; 61
      a8:   df e3           ldi     r29, 0x3F       ; 63
      aa:   de bf           out     0x3e, r29       ; 62
      ac:   02 d0           rcall   .+4             ;  0xb2
      ae:   3d c0           rjmp    .+122           ;  0x12a
      b0:   a7 cf           rjmp    .-178           ;  0x0
      b2:   cd b7           in      r28, 0x3d       ; 61
      b4:   de b7           in      r29, 0x3e       ; 62
      b6:   2d 97           sbiw    r28, 0x0d       ; 13
      b8:   cd bf           out     0x3d, r28       ; 61
      ba:   de bf           out     0x3e, r29       ; 62
      bc:   88 ed           ldi     r24, 0xD8       ; 216
      be:   84 bf           out     0x34, r24       ; 52
      c0:   10 92 61 00     sts     0x0061, r1      ;  0x800061
      c4:   80 91 e2 05     lds     r24, 0x05E2     ;  0x8005e2
      c8:   84 60           ori     r24, 0x04       ; 4
      ca:   80 93 e2 05     sts     0x05E2, r24     ;  0x8005e2
      ce:   44 9a           sbi     0x08, 4 ; 8
      d0:   86 eb           ldi     r24, 0xB6       ; 182
      d2:   92 e0           ldi     r25, 0x02       ; 2
      d4:   80 93 28 08     sts     0x0828, r24     ;  0x800828
      d8:   90 93 29 08     sts     0x0829, r25     ;  0x800829
      dc:   80 ec           ldi     r24, 0xC0       ; 192
      de:   80 93 26 08     sts     0x0826, r24     ;  0x800826
      e2:   8d e0           ldi     r24, 0x0D       ; 13
      e4:   ee e2           ldi     r30, 0x2E       ; 46
      e6:   f1 e4           ldi     r31, 0x41       ; 65
      e8:   de 01           movw    r26, r28
      ea:   11 96           adiw    r26, 0x01       ; 1
      ec:   01 90           ld      r0, Z+
      ee:   0d 92           st      X+, r0
      f0:   8a 95           dec     r24
      f2:   e1 f7           brne    .-8             ;  0xec
      f4:   80 91 24 08     lds     r24, 0x0824     ;  0x800824
      f8:   85 ff           sbrs    r24, 5
      fa:   fc cf           rjmp    .-8             ;  0xf4
      fc:   81 e6           ldi     r24, 0x61       ; 97
      fe:   80 93 22 08     sts     0x0822, r24     ;  0x800822
     102:   fe 01           movw    r30, r28
     104:   32 96           adiw    r30, 0x02       ; 2
     106:   98 e4           ldi     r25, 0x48       ; 72
     108:   80 91 24 08     lds     r24, 0x0824     ;  0x800824
     10c:   85 ff           sbrs    r24, 5
     10e:   fc cf           rjmp    .-8             ;  0x108
     110:   90 93 22 08     sts     0x0822, r25     ;  0x800822
     114:   91 91           ld      r25, Z+
     116:   91 11           cpse    r25, r1
     118:   f7 cf           rjmp    .-18            ;  0x108
     11a:   80 91 24 08     lds     r24, 0x0824     ;  0x800824
     11e:   85 ff           sbrs    r24, 5
     120:   fc cf           rjmp    .-8             ;  0x11a
     122:   82 e6           ldi     r24, 0x62       ; 98
     124:   80 93 22 08     sts     0x0822, r24     ;  0x800822
     128:   ff cf           rjmp    .-2             ;  0x128
     12a:   f8 94           cli
     12c:   ff cf           rjmp    .-2             ;  0x12c
    

    This part is interesting

    char st[] = "Hello world!";
      e2:   8d e0           ldi     r24, 0x0D       ; R24 = 13 (string length)
      e4:   ee e2           ldi     r30, 0x2E       ; R31:R30 (Z) = 0x412E
                                                    ; data address about 0x4000 is mapped progmem. 
                                                    ; So Z point to address 0x012E in your code 
      e6:   f1 e4           ldi     r31, 0x41       
      e8:   de 01           movw    r26, r28        ;R29:R28 (Y) is pointer to actual stack pointer
      ea:   11 96           adiw    r26, 0x01       ;R27:R26 (X) is now pointer to st
    
    loop:
      ec:   01 90           ld      r0, Z+
      ee:   0d 92           st      X+, r0
      f0:   8a 95           dec     r24
      f2:   e1 f7           brne    .-8             ;  0xec (loop) this loop copy 13 bytes 
                                                    ;from PROMEM to SRAM to created array on the stack
    

    But as can you see at address 0x12E in hex file is nothing. Its mean here is 0xFF value what is unprogrammed value for the flash.

    In my compiled version with AVR studio is here 13 byte of your string. And in simulator all work OK.

    Conclusion You have some problem with linking or converting to hex file.

    Edit: I check also blink.elf and rodata is here

    Disassembly of section .rodata:
    
    0000412e <_end-0x7fe6d2>:
        412e:   48 65           ori r20, 0x58   ; 88
        4130:   6c 6c           ori r22, 0xCC   ; 204
        4132:   6f 20           and r6, r15
        4134:   77 6f           ori r23, 0xF7   ; 247
        4136:   72 6c           ori r23, 0xC2   ; 194
        4138:   64 21           and r22, r4
        ...
    

    So it's mean that problem is in conversion to hex file. My AVR studio do this by

    avr-objcopy.exe" -O ihex -R .eeprom -R .fuse -R .lock -R .signature -R .user_signatures  "GccApplication1.elf" "GccApplication1.hex"
    

    Check your cmd. And in your hex file you must find text as last 13 bytes like my hex file. Line :0D01D40048656C6C6F20776F726C642100C1

    :100000000C9450000C945A000C945A000C945A0012
    :100010000C945A000C945A000C945A000C945A00F8
    :100020000C945A000C945A000C945A000C945A00E8
    :100030000C945A000C945A000C945A000C945A00D8
    :100040000C945A000C945A000C945A000C945A00C8
    :100050000C945A000C945A000C945A000C945A00B8
    :100060000C945A000C945A000C945A000C945A00A8
    :100070000C945A000C945A000C945A000C945A0098
    :100080000C945A000C945A000C945A000C945A0088
    :100090000C945A000C945A000C945A000C945A0078
    :1000A00011241FBECFEFCDBFDFE3DEBF0E9495005E
    :1000B0000C94E8000C940000CF93DF9300D0CDB7F0
    :1000C000DEB789839A8389819A812BE232E0FC0131
    :1000D0002087318789819A8120ECFC0126830000EA
    :1000E0000F900F90DF91CF910895CF93DF9300D0C1
    :1000F0001F92CDB7DEB789839A836B830000898115
    :100100009A81FC018481882F90E080729927892B45
    :10011000B1F389819A812B81FC012283000023960F
    :10012000CDBFDEBFDF91CF910895CF93DF93CDB7E1
    :10013000DEB72F97CDBFDEBF84E390E028EDFC0152
    :10014000208381E690E0FC01108280EE95E020EEB5
    :1001500035E0F90122812460FC01228388E090E0EF
    :1001600028E030E0F90120812061FC01208380E259
    :1001700098E00E945C008DE0E4EDF1E4DE0113966E
    :1001800001900D928A95E1F7CE01039689839A83B7
    :1001900061E680E298E00E9475000EC089819A8134
    :1001A0009C012F5F3F4F29833A83FC018081682F98
    :1001B00080E298E00E94750089819A81FC0180812B
    :1001C000882361F762E680E298E00E947500FFCF25
    :0401D000F894FFCFD1
    :0D01D40048656C6C6F20776F726C642100C1
    :00000001FF