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:
#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
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