stefanrueger / urboot

Small AVR bootloader using urprotocol
GNU General Public License v3.0
55 stars 8 forks source link

To support mega0 AVR and Tiny0/1/2 AVR, similar to optiboot_x #1

Open mcuee opened 1 year ago

mcuee commented 1 year ago

I am not so sure how difficult it is to add the support of mega0 AVR and Tiny0/1/2 AVR, similar to optiboot_x.

Stretch goal will be to add the support of AVR DA/DB/DD part, similar to optiboot_dx.

Ref: optiboot_dx is too diffierent to be included in optiboot (optiboot_x is integrated into optiboot).

stefanrueger commented 1 year ago

My understanding is that optiboot_dx doesn't work. I'd be interested in handling XMEGA parts (They have a huge bootloader section that I think could be made available for ordinary applications) and perhaps extend to the parts that optiboot_x can handle.

Immediate priority though is to deal well with classic parts and release a reference implementation (current code is pre-release).

mcuee commented 1 year ago

My understanding is that optiboot_dx doesn't work

optibootdx works well with avrdude on AVR DA/DB parts based on testing on the 128KB Flash parts. I believe it should also work for 64KB and less Flash parts (pending conformation.

optiboot_dx does not work yet for AVR DD parts.

mcuee commented 1 year ago

I'd be interested in handling XMEGA parts (They have a huge bootloader section that I think could be made available for ordinary applications) and perhaps extend to the parts that optiboot_x can handle.

I have not seen any STK500v1 implementation for XMEGA parts yet. I believe the most popular bootloaders for XMEGA parts is using AVR109 protocol (xboot or CATERINA). urboot for xmega will be interesting.

xboot: https://github.com/alexforencich/xboot (AVR109)

stk500v2 or CATERINA (USB version of AVR109). https://github.com/XMegaForArduino/arduino/blob/master/bootloaders/xmega/xmegaBOOT.c

Collection of bootloader for AVRs.

SpenceKonde commented 1 year ago

Dx and non-Dx modern AVRs use fundamentally different methods to write the flash.

On non-Dx, you fill a page buffer and then execute page-erase-write command.

On Dx, you have to have erased the pages, and have NVMCMD set to FLWR but then just load low and high byte of word into R0 and R1, have the Z pointer pointing to where you want to write and execute SPM or SPM Z+. (You can also use the mapping and normal st instructions, but this looked like it would take more flash, is twice as slow (takes same time to write a byte as a word) and doesn't work correctly on the AVR128DA due to an erratum. Erasing pages is done by selecting an FLPER NVMCMD, setting the Z pointer to point to the page being erased,

All modern AVRs also have the following differences: They all have hardware bootloader support. They have three memory sections, which are located in this order in the flash:

Code executing from APPDATA cannot write to any NVM, not even EEPROM. Code executing from APPCODE can write to EEPROM and APPDATA Code executing from BOOTCODE can write to EEPROM, APPDATA, and APPCODE. Nothing except UPDI can write to BOOTCODE section. A bootloader can never update or overwrite itself. If the bootloader section size is 0, the entire flash is BOOTCODE. It is not specified in the datasheet what can write to USERROW - likely everything except APPDATA. Future parts will also contain a "BOOTROW", generally of the same size as the USERROW. The function of this section has yet to be made clear. Code executing from the bootloader section can set the BOOTRP bit, which takes effect when execution crosses to the application section. Setting this bit will cause all data in the boot section to read as 0x0000 (nop). This includes instruction fetch, so if it has been set you can't call into the bootloader to write to APPCODE - all that it'll see there are nop's. There is also an APPCODEWP and APPDATAWP bit, when set, they prevent writes to the specified section. All of these bits (along with FLMAPLOCK) are protected by CCP, and once set, can be cleared only by a reset.

Bootloaders start at 0x0000, not near the end of the flash.

On Dx, a write for the purposes of protection only counts the SPM or ST that writes or erases flash. (you can stage everything, then call a 2 word routine in the boot section consisting of SPM, RET, and write the flash like that). On other modern AVRs, both filling the page buffer and committing the page buffer must be carried out from the appropriate section.

Like all AVRs, it is essential that the reset cause flags be checked AND CLEARED, because you need to be able to detect a "dirty reset" where execution has reached the bootloader, but no reset has occurred. As the peripherals are in an unknown state, the only safe thing to do is a software reset at that point. That was always true, but optiboot never did this, foolishly expecting the user code to do so. Your chances of going up to a roulette table, betting on 00, and then winning twice in a row are probably better than the chance that a randomly selected Arduino sketch would check or clear the reset flags, or that the author of the code even knew that such flags exist.

However on modern AVRs it's much more important to force reset after a dirty reset: 1) The clock speed if using internal oscillator is set during initialization of the sketch, bootloader assumes it is the POR internal clock speed. 2) One of the ways you end up at 0x0000 without a reset is a BAD_ISR - the implementation of this handler, provided by avr-libc, just jumps to 0x0000. But you got there because of an INTERRUPT. So CPUINT.STATUS has LVL0EX or LVL1EX set still. So no matter what you do after this, you can't reenable interrupts without either a reset (which also restores peripherals to known states), or manipulating the top of the stack register so you can execute a RETI to convince the interrupt controller that it's not in an interrupt anymore. That's why my modern AVR cores always (either in bootloader or at the very start of initialization, in .init3 if not using bootloader) check reset flags, trigger SW reset if they're zero, and otherwise clear them and stash the old value in GPIOR0/GPR0 (my cores #define aliases of GPIORn and GPR_GPRn

stefanrueger commented 1 year ago

@SpenceKonde Thanks for a thorough overview espec with regards to the pitfalls.

The urboot project originated in 2016, but I only recently published it (following a New-Year resolution to give back to the open-source community).

I was hoping that not much needs changing in the bootloader for newer parts over and above changing the way flash/eeprom is written (or read) but may have underestimated some of the sublte differences you pointed out. Anyway, my plan was to first see whether/how urboot bootloaders are accepted along with avrdude -c urclock and the urprotocol before expanding to non-classic parts.

SpenceKonde commented 1 year ago

IIRC (it's been a while since I looked at the details of the classic AVR bootloader write process, modern-non-dx probably isn't too hard of a port. You always start up at ~3.33 or ~2.66 MHz, (16/6 or 20/6), which is plenty fast enough for reading from the serial port - because of the fractional baud rate generator, the baud rate calculation error that plagued AVR in the past is gone - so you only have to consider two speeds, and there are no dead-zones between the divisors. You specify the time between the 8 or 16 samples in 64ths of a system clock with the caveat that it must be not less than 64. None of that garbage where 12 MHz chips receive one baud rate more reliably and 16 MHz ones like a different, lower baud rate if you're sticking to "standard" baud rates, and none of this UART crystal nonsense. 57600 and 115200 are some awful baud rates to hit on classic AVRs with a power-of-two-MHz system clock aren't they? Somewhere I wrote up how you could have 4 classic AVRs all running at 115200 baud (or what you think is 115200 baud, with every member of the quarrelsome quartet being able to talk to at least one other device, but none of them successfully able to talk to all three other devices plus a serial adapter. It was after I had to explain to someone on a github issue that no, those classic AVRs running at 8 MHz were not actually operating at 115200 baud, and are only able to talk to eachother, and that no it doesn't matter that they all have a crystal this isn't clock error it's baud error (apparently he had, for years, had a number of classic AVRs running at 8 MHz and what he thought was 115200 baud (no, it's 111111 baud), and complained that his new tiny 3216 couldn't talk to them and it had to be a problem with my core. Initially he didn't belive me, but he stopped posting when I suggested he could prove this was working by trying to listen in with a serial adapter and noticing that it didn't work (of course it didn't, they're talking at 111111 baud and it's trying to talk at 115108 baud, ie. it's actually able to do what you tell it.

It's a whole new world in terms of the UART (and for basically no increased effort. The USART baud rate generator is just better way the hell better; we don't even use U2X mode unlesss it's needed to reach the target speed - even really close to the top, you do better by not using U2X and getting the wider error tolerance, vs classic AVR where you basically need it on for any relevant baud rate. IIRC flash writing isnt much different to set up, and changed less than you might think. And for non-DX/future EX. everything is accessible in the same address space (fully mapped flash). DX is definitely more of a challenge.

mcuee commented 1 year ago

DX is definitely more of a challenge.

So much so that @WestfW mentioned below.

stefanrueger commented 1 year ago

Thanks for the heads up re USART.

| 57600 and 115200 are some awful baud rates to hit on classic AVRs with a power-of-two-MHz system clock aren't they?

When compiled urboot.c warns of baud quantisation errors in excess of 2.5%. The precompiled urboot bootloaders use software IO instead of the USART when the latter has unacceptable quantisation errors. SWIO has less quantisiation error for classic parts at the expense of code space.

stefanrueger commented 1 year ago

| Dx and non-Dx modern AVRs use fundamentally different methods to write the flash

@SpenceKonde What is a good way for a C preprocessor to distinguish between Dx and non-Dx modern AVRs? Obvs, there is the tedious listing of #if defined(__AVR_AVR16DD14__) || defined(...), but is there a better way to do this?

I have come up with

#if defined(FUSE_BOOTEND)    // Non-Dx/Ex modern AVR, BOOTCODE is multiple of 256
...
#elif defined(FUSE_BOOTSIZE) // Dx or Ex modern AVR, BOOTCODE is multiple of 512
...
#endif

Any intell on Ex parts and how they need to be differently treated from Dx parts?

SpenceKonde commented 1 year ago

__AVR_ARCH__ >= 100 for modern AVRs.

103 indicates a part with fully mapped flash, like a mega0 or a modern tiny. The practical upper limit is 48k of flash as they did on the mega0, with the progmem offset of 0x4000 leaving 3/4ths of the address space as mapped flash, and thus 16k to fit the ram and the special function registers. 102 indicates a part with 64k flash, hence the flash cannot all be mapped as it would entirely fill 16-bit address space - instead only half (32k) of it is mapped (by default, the upper half), but addresses still fit in 16 bits. If these have a RAMPZ register (the 64k DA/DB do, while the 64k DDs don't have it. 32k DA/DB parts don't have a RAMPZ in the headers) it is vestigial and not used. I don't think RAMPZ does anything if the parts have it, and while it's in the headers there may not be any corresponding register in the silicon, so it would be an unwritable locations that always reads as 0x00 like most of it's neighbors in the upper 32 bytes of the I/O space. It's unclear what it would do if it is physically present; I've never tried writing to it. It probably "should" remain 0x00 regardless of attempts to write to it, since the unused bits of RAMPZ are supposed to always read as 0, and that's the only kind, 104 indicates a part with 128k flash, making any location word addressable with a 16-bit address but not necessarily byte addressable, and the memory mapping can map 1/4th of the flash (again, by default this is the last 32k). So the first half of flash can be accessed with LPM, PROGMEM, and so on, and the last 1/4th can be accessed with normal load operations, while the cursed ground between 64k and 96k is accessible only with ELPM, and the RAMPZ register is needed.

The EA-series looks like it was "forked" from the Dx-series before those parts got any of the big architectural enhancements. They have the same 16/20 selectable base clock instead of the nice directly selectable clock speed, the flash is written and erased by page, and available information thus far suggests that they behave essentially the same as the tinys. There is one big difference at least, though - WWR functionality, so you may have to poll a status register to know when you can start writing the next page. The details of that implementation haven't been released. But what is clear is that the self programming of the EA and EB will have more in common with the tinyavrs and megaavr 0-series.

stefanrueger commented 1 year ago

Blimey - that's a maze!

My gcc-avr v12.2.0 does not know Dx parts (nor Ex parts). For all the others I get when filtered to __AVR_ARCH__ >= 100:

$ grep __AVR_ARCH__ gcc-12.2.0-defs/*.pre| awk '{if($3 >= 100) print; }' 
gcc-12.2.0-defs/atmega1608.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/atmega1609.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/atmega3208.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/atmega3209.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/atmega4808.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/atmega4809.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/atmega808.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/atmega809.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny10.pre:#define __AVR_ARCH__ 100
gcc-12.2.0-defs/attiny1604.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny1606.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny1607.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny1614.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny1616.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny1617.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny202.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny204.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny20.pre:#define __AVR_ARCH__ 100
gcc-12.2.0-defs/attiny212.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny214.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny3214.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny3216.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny3217.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny402.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny404.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny406.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny40.pre:#define __AVR_ARCH__ 100
gcc-12.2.0-defs/attiny412.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny414.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny416.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny417.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny4.pre:#define __AVR_ARCH__ 100
gcc-12.2.0-defs/attiny5.pre:#define __AVR_ARCH__ 100
gcc-12.2.0-defs/attiny804.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny806.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny807.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny814.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny816.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny817.pre:#define __AVR_ARCH__ 103
gcc-12.2.0-defs/attiny9.pre:#define __AVR_ARCH__ 100
gcc-12.2.0-defs/atxmega128a1.pre:#define __AVR_ARCH__ 107
gcc-12.2.0-defs/atxmega128a1u.pre:#define __AVR_ARCH__ 107
gcc-12.2.0-defs/atxmega128a3.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega128a3u.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega128a4u.pre:#define __AVR_ARCH__ 107
gcc-12.2.0-defs/atxmega128b1.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega128b3.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega128c3.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega128d3.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega128d4.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega16a4.pre:#define __AVR_ARCH__ 102
gcc-12.2.0-defs/atxmega16a4u.pre:#define __AVR_ARCH__ 102
gcc-12.2.0-defs/atxmega16c4.pre:#define __AVR_ARCH__ 102
gcc-12.2.0-defs/atxmega16d4.pre:#define __AVR_ARCH__ 102
gcc-12.2.0-defs/atxmega16e5.pre:#define __AVR_ARCH__ 102
gcc-12.2.0-defs/atxmega192a3.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega192a3u.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega192c3.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega192d3.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega256a3b.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega256a3bu.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega256a3.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega256a3u.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega256c3.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega256d3.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega32a4.pre:#define __AVR_ARCH__ 102
gcc-12.2.0-defs/atxmega32a4u.pre:#define __AVR_ARCH__ 102
gcc-12.2.0-defs/atxmega32c3.pre:#define __AVR_ARCH__ 102
gcc-12.2.0-defs/atxmega32c4.pre:#define __AVR_ARCH__ 102
gcc-12.2.0-defs/atxmega32d3.pre:#define __AVR_ARCH__ 102
gcc-12.2.0-defs/atxmega32d4.pre:#define __AVR_ARCH__ 102
gcc-12.2.0-defs/atxmega32e5.pre:#define __AVR_ARCH__ 102
gcc-12.2.0-defs/atxmega384c3.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega384d3.pre:#define __AVR_ARCH__ 106
gcc-12.2.0-defs/atxmega64a1.pre:#define __AVR_ARCH__ 105
gcc-12.2.0-defs/atxmega64a1u.pre:#define __AVR_ARCH__ 105
gcc-12.2.0-defs/atxmega64a3.pre:#define __AVR_ARCH__ 104
gcc-12.2.0-defs/atxmega64a3u.pre:#define __AVR_ARCH__ 104
gcc-12.2.0-defs/atxmega64a4u.pre:#define __AVR_ARCH__ 104
gcc-12.2.0-defs/atxmega64b1.pre:#define __AVR_ARCH__ 104
gcc-12.2.0-defs/atxmega64b3.pre:#define __AVR_ARCH__ 104
gcc-12.2.0-defs/atxmega64c3.pre:#define __AVR_ARCH__ 104
gcc-12.2.0-defs/atxmega64d3.pre:#define __AVR_ARCH__ 104
gcc-12.2.0-defs/atxmega64d4.pre:#define __AVR_ARCH__ 104
gcc-12.2.0-defs/atxmega8e5.pre:#define __AVR_ARCH__ 102

Didn't spot any 101.

SpenceKonde commented 1 year ago

You're using old atpacks.

The TPI interface ones (the AVRrc devices - they've also got only r16-r31, and the instruction timing is different, and direct addressed load/store is a 16-bit opcode with 128-bit address space because the memory on those things is fucking tiny) are not particularly old either - their specs are crap because they're sold for the price of dirt and have to fit in a tiny package.

The 102, 104, arch codes were used for the xmega parts too, yeah. These parts have much in common with xmega. Metaphorically, throughout the development process, they were rummaging around in a junkyard full of old xmega and classic AVR's, looking for parts and subsystems that they could adapt - you can see that many of the peripherals are obviously derived from either xmega or classic AVR versions - though to their credit they did generally streamline what they reused; The xmegas were fiendishly complicated.

As for why they used higher architecture versions for some parts than was necessary, I think was just from how Atmel was systematically less consistant. Technically they don't set the size of the flash, but rather are associated with maximums, so that's legal.

For all Dx and Ex with 32k flash or less, it's 103, for all Dx and Ex with 64k it's 102, and for all Dx with 128k it's 104. A future 256k part would probably be 106. I don't think 101 ever saw the light of day. 105 and 107 I think are related to those parts supporting large external memories.

stefanrueger commented 1 year ago

OK, I am now using Microchip.AVR-Dx_DFP.2.3.272.atpack and Microchip.AVR-Ex_DFP.2.2.56.atpack and copy their specs-* files into my own directory device-specs-dx then I do the following in bash

touch pre.c # empty file
for ds in device-specs-dx/*; do 
   echo $ds $(avr-gcc -specs=device-specs-dx/specs-avr64da48 -Os -E -dD  pre.c | grep __AVR_ARCH__)
done

device-specs-dx/specs-avr128da28 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr128da32 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr128da48 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr128da64 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr128db28 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr128db32 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr128db48 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr128db64 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr16dd14 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr16dd20 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr16dd28 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr16dd32 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr32da28 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr32da32 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr32da48 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr32db28 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr32db32 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr32db48 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr32dd14 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr32dd20 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr32dd28 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr32dd32 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr64da28 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr64da32 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr64da48 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr64da64 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr64db28 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr64db32 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr64db48 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr64db64 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr64dd14 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr64dd20 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr64dd28 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr64dd32 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr64ea28 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr64ea32 #define __AVR_ARCH__ 102
device-specs-dx/specs-avr64ea48 #define __AVR_ARCH__ 102

avr-gcc --version
avr-gcc (GCC) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

So, looks like Dx and Ex get an __AVR_ARCH__ of 102.

BTW, this Arch-Linux installation is relatively recent and it misses all Dx or Ex specs files. Thats why I had to copy them over from atpacks. I installed avr-gcc using

pacman --noconfirm --needed -Syu wget avr-gcc avr-binutils gcc-libs libmpc avr-libc
stefanrueger commented 1 year ago

And that leaves the business of distinguishing xmega devices from Dx/Ex in the C pre-processor. There are plenty of macros/register names etc that will differ. There are even some differences in the __AVR_xyz macros that are defined at start (w/o considering any header files):

avr-gcc -specs=device-specs-dx/specs-avr64da48 -Os -E -dD  pre.c | grep __AVR_ >/tmp/1
avr-gcc -mmcu=atxmega32c3 -Os -E -dD  pre.c | grep __AVR_ | diff - /tmp/1
13c13,14
< #define __AVR_ISA_RMW__ 1
---
> #define __AVR_ERRATA_SKIP__ 1
> #define __AVR_ERRATA_SKIP_JMP_CALL__ 1
15,16c16,18
< #define __AVR_ATxmega32C3__ 1
< #define __AVR_DEVICE_NAME__ atxmega32c3
---
> #define __AVR_AVR64DA48__ 1
> #define __AVR_DEVICE_NAME__ avr64da48
> #define __AVR_DEV_LIB_NAME__ avr64da48

I wonder whether these are really trustworthy. Does the modern AVR64DA48 really suffer from the age-old __AVR_ERRATA_SKIP__?!?

mcuee commented 1 year ago

@stefanrueger

One easy way to get a working compiler is to get the one from @SpenceKonde.

For Linux x86_64 https://spencekondetoolchains.s3.amazonaws.com/avr-gcc-7.3.0-atmel3.6.1-azduino6-x86_64-pc-linux-gnu.tar.bz2

Ref: https://github.com/SpenceKonde/DxCore/blob/master/megaavr/bootloaders/optiboot_dx/README.md