Author Topic: Compiling Optiboot bootloader for ATmega32M1  (Read 2443 times)

0 Members and 1 Guest are viewing this topic.

Offline HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1471
  • Country: gb
Compiling Optiboot bootloader for ATmega32M1
« on: February 15, 2019, 03:41:58 pm »
I have been trying to compile the Optiboot bootloader for the ATmega32M1 using Atmel Studio 7, but without success. :( I'm doing this because Optiboot doesn't support the ATmega32M1 out of the box.

First off, I copied one set of the included Atmel Studio solution/project files (for the Xplained328P board), and renamed as appropriate - including hand-editing the solution file so it references the correct project file. Then I opened the solution in AS7 (where it wanted to convert from v6.2 to v7 format) and changed the target microcontroller to the ATmega32M1.

Then I set about making any necessary changes to the project files. Initially, I had found this GitHub pull request, but soon realised that I don't actually need to make any of its C code changes - it appears that patch is 2 years old, and since then Optiboot has included support for LIN-based UARTs (like the '32M1 has). All I think I need to do is add my own makefile target, like the patch does within Makefile.custom.

I have ended up with the following addition to Makefile.custom. I didn't really follow exactly what the patch had done, but rather followed what other things in the main Makefile did.

Code: [Select]
#
# ATmega32M1
#
HELPTEXT += "target atmega32m1      - ATmega32M1 (32pin, 32k)\n"
atmega32m1: TARGET = atmega32m1
atmega32m1: MCU_TARGET = atmega32m1
atmega32m1: CFLAGS += $(COMMON_OPTIONS)
atmega32m1: AVR_FREQ ?= 8000000L
ifndef BIGBOOT
atmega32m1: LDSECTIONS = -Wl,--section-start=.text=0x3f00 -Wl,--section-start=.version=0x3ffc
else
atmega32m1: LDSECTIONS = -Wl,--section-start=.text=0x3e00 -Wl,--section-start=.version=0x3ffc
endif
atmega32m1: $(PROGRAM)_atmega32m1.hex
atmega32m1: $(PROGRAM)_atmega32m1.lst

atmega32m1_isp: atmega32m1
atmega32m1_isp: TARGET = atmega32m1
atmega32m1_isp: MCU_TARGET = atmega32m1
ifndef BIGBOOT
# 512 byte (256 word) boot size, SPIEN
atmega32m1_isp: HFUSE ?= DE
else
# 1024 byte (512 word) boot size, SPIEN
atmega32m1_isp: HFUSE ?= DC
endif
# Clock source / startup time EXTXOSC_8MHZ_XX_1KCK_14CK_0MS
atmega32m1_isp: LFUSE ?= EE
# Brown-out level 4v3
atmega32m1_isp: EFUSE ?= FC
atmega32m1_isp: isp

I then changed the build command line within project properties to "AVR_FREQ=8000000L LED=B0 atmega32m1", so it calls the correct make target.

However, when I build, it fails with an error: "section .version loaded at [00003ffc,00003ffd] overlaps section .text loaded at [00003f00,000040df]". (There is also one about the 'baudcheck' recipe failing, but I don't think that's of any concern, as baudcheck.c only appears to be a shell script masquerading as a C file in order to get the preprocessor to substitute in #define values.)

I'm confused, as I cross-checked the section addresses with bootloader flash section ranges specified in the datasheet, and as far as I can see I believe I have the appropriate values. For 256 word size, it specifies 0x3F00-0x3FFF, and for 512 words 0x3E00-0x3FFF. But, I obviously have the wrong values here. If I check the LDSECTIONS value in the main Makefile for another chip, for example the ATmega328P, they are:

Code: [Select]
ifndef BIGBOOT
atmega328: LDSECTIONS  = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
else
# bigboot version is 1k long; starts earlier
atmega328: LDSECTIONS  = -Wl,--section-start=.text=0x7c00 -Wl,--section-start=.version=0x7ffe
endif

But these addresses don't match the values in the datasheet. They appear to be offset by double the datasheet value? :-//

What am I supposed to be specifying here for the section start addresses?
 

Offline HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1471
  • Country: gb
Re: Compiling Optiboot bootloader for ATmega32M1
« Reply #1 on: February 15, 2019, 04:56:37 pm »
Ah, I realised my mistake with the section addresses. It is even covered in the Optiboot Wiki. :palm:

The addresses the linker is expecting are byte addresses, whereas the addresses in the datasheet are word addresses. Of course, the datasheet doesn't explicitly mention that, only infers it by the presence of the boot flash size total values in words. I do indeed just need to double the datasheet figures (16-bit/2-byte word size).

So I have the following now for my LDSECTIONS values:

Code: [Select]
ifndef BIGBOOT
atmega32m1: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
else
atmega32m1: LDSECTIONS = -Wl,--section-start=.text=0x7c00 -Wl,--section-start=.version=0x7ffe
endif

It compiles successfully now! I get my nice 512 byte .hex file output. Of course, now I need to find out if the bootloader actually works... ;D
 
The following users thanked this post: elecdonia

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 3238
  • Country: gb
Re: Compiling Optiboot bootloader for ATmega32M1
« Reply #2 on: February 15, 2019, 05:35:30 pm »
I got bitten by something similar in an early version of avr-gcc (3.4.3).  I had a bunch of function pointers at fixed addresses which were defined as the byte address and after upgrading to a newer version they no longer worked and had to be defined as word addresses.
 

Offline HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1471
  • Country: gb
Re: Compiling Optiboot bootloader for ATmega32M1
« Reply #3 on: February 15, 2019, 06:20:05 pm »
Can report the version of Optiboot I compiled works just great. :)

My device has a USB-to-UART bridge on board, and I am now able to successfully read and write the flash via its serial COM port using the avrdude utility; of course, I have to trigger the bootloader by manually pressing a reset button I have temporarily attached to the MCU reset line (via ISP header), but not a big deal. My firmware for that device also works great as-is without any modifications.

As I have flash memory to spare, I think I may re-compile Optiboot in 'big' mode (1k size) so I can have EEPROM read/write capability too.

One thing I am disappointed about, however, is that I was hoping I would be able to use Atmel Studio to do programming using its STK500 support, but I don't appear to be able to. :( I can add an STK500 target by specifying the COM port in question, but I can't get it to communicate from the programming dialog. Perhaps because I'm using a non-standard baud rate (57,600)? I'm not sure how it's supposed to work. :-//
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: Compiling Optiboot bootloader for ATmega32M1
« Reply #4 on: February 16, 2019, 10:34:27 am »
Quote
I was hoping I would be able to use Atmel Studio to do programming using its STK500 support, but I don't appear to be able to.
Optiboot uses a very limited subset of STK500 in order to fit in the allocated 512 bytes), so it's not surprising that AS (expecting an actual STK500 that has ~8k of program space running the firmware) won't talk to it.
This is somewhat documented here: https://github.com/Optiboot/optiboot/wiki/HowOptibootWorks

Quote
I ... soon realised that I don't actually need to make any of its C code changes  ... All I think I need to do is add my own makefile target, like the patch does within Makefile.custom.
I am quite pleased that it worked out this way for you!  LIN UART support is a relatively recent addition, based on code provided by Spence Konde ("Dr Azzy"), who did the ATtinyCore
« Last Edit: February 16, 2019, 10:39:27 am by westfw »
 

Offline HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1471
  • Country: gb
Re: Compiling Optiboot bootloader for ATmega32M1
« Reply #5 on: February 16, 2019, 01:36:09 pm »
Optiboot uses a very limited subset of STK500 in order to fit in the allocated 512 bytes), so it's not surprising that AS (expecting an actual STK500 that has ~8k of program space running the firmware) won't talk to it.

So it just a case that AS is sending commands that Optiboot doesn't handle? Do you happen to know what AS tries to do?

I have flash memory to spare (about 3K), so I could go with a more fully-featured bootloader if that would work with AS. Had a quick look and found one on GitHub, but unsurprisingly it doesn't support LIN-based UARTs. :(

I have a question about compiling Optiboot with SUPPORT_EEPROM: does that push the size above 512 bytes?

Because, if it does, how will that result in the correct section start addresses being set by the makefiles? As far as I can see, only BIGBOOT does that.

Also, I was pondering an idea about changing the way the bootloader is started. As standard, it only runs when an external reset occurs. Would it be possible to modify things to have bootloader entry controlled by a hardware jumper/switch? That is, it would instead check the state of a given GPIO pin.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: Compiling Optiboot bootloader for ATmega32M1
« Reply #6 on: February 17, 2019, 06:47:55 am »
Sigh.  I has a long a detailed reply going, but apparently I forgot to hit "post"...

Quote
Do you happen to know what AS tries to do?
No.  It may require STK500v2; AS commonly wants to upgrade your programmer firmware before it will use the device :-(

Quote
I have flash memory to spare (about 3K), so I could go with a more fully-featured bootloader if that would work with AS. Had a quick look and found one on GitHub, but unsurprisingly it doesn't support LIN-based UARTs. :(
Surely it wouldn't be that hard to add the LIN UART support to some other bootloader?   A non-STK500 bootloader may be a better choice.  (STK500 is very much a programmer communications protocol.)

Quote
I have a question about compiling Optiboot with SUPPORT_EEPROM: does that push the size above 512 bytes?
Yes.  But you could do, say:make atmega328 SUPPORT_EEPROM=1 NO_APP_SPM=1 LED_START_FLASHES=0 LED_START_ON=1
Quote
Because, if it does, how will that result in the correct section start addresses being set by the makefiles? As far as I can see, only BIGBOOT does that.
Manual adjustment.  Note that chips with "boot section" support have very "quantized"  bootloader sizes.  BIGBOOT is the next size up from 512bytes.

Quote
[the bootloader] only runs when an external reset occurs. Would it be possible to modify things to have bootloader entry controlled by a hardware jumper/switch? That is, it would instead check the state of a given GPIO pin.
Instead of RESET would require application support.  Instead of "wait a bit for serial traffic" is a pretty common bootloader feature, and should be pretty easy to add.
 
The following users thanked this post: elecdonia

Offline HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1471
  • Country: gb
Re: Compiling Optiboot bootloader for ATmega32M1
« Reply #7 on: February 17, 2019, 06:50:14 pm »
No.  It may require STK500v2; AS commonly wants to upgrade your programmer firmware before it will use the device :-(

I was curious, so I attached my logic analyser to the serial RX/TX. It would appear that Atmel Studio is indeed trying to talk to it with the STK500 v2 protocol, and also at 115200 baud. At least, it matches the message format as described in AVR068. I would guess the single message it repeats several times every few seconds is the 'sign on' command.

Surely it wouldn't be that hard to add the LIN UART support to some other bootloader?   A non-STK500 bootloader may be a better choice.  (STK500 is very much a programmer communications protocol.)

Now I know that AS7 is trying to speak STK500v2 protocol, I have been looking at Peter Fleury's bootloader. It says it requires 512 words (1 KB), which I can accommodate, and doesn't look too hard to modify to support a LIN-based UART. It's behaviour is also to only enter the bootloader according to the state of an IO pin, which is nice. I might have a play with that if I have time.

Thanks very much for your help, Bill. :-+
 

Offline HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1471
  • Country: gb
Re: Compiling Optiboot bootloader for ATmega32M1
« Reply #8 on: February 17, 2019, 07:04:20 pm »
Oh, I forgot one other thing I was going to ask: is there a way to read the Optiboot version number from the main application code?

The version number is written to the .version section, for which the convention appears to be (although I guess it depends on the actual LDSECTIONS values specified in the makefile) to place it in the last two bytes of the boot flash, right? And that is at the very end of the entire flash. So, just read that location using the pgmspace.h functions? Something like this, perhaps:

Code: [Select]
uint8_t optiboot_ver_minor = pgm_read_byte((uint8_t *)(FLASHEND - 1));
uint8_t optiboot_ver_major = pgm_read_byte((uint8_t *)FLASHEND);
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: Compiling Optiboot bootloader for ATmega32M1
« Reply #9 on: February 18, 2019, 03:01:18 am »
Quote
is there a way to read the Optiboot version number from the main application code?
Code: [Select]
uint8_t optiboot_ver_minor = pgm_read_byte((uint8_t *)(FLASHEND - 1));
uint8_t optiboot_ver_major = pgm_read_byte((uint8_t *)FLASHEND);
Yes, that should work, unless the boot section has been protected against being read by the application.The optiboot makefiles explicitly allow this (lock bits = 0x2F), but the Arduino default is NOT to allow it (0x0F)
See also: https://github.com/WestfW/fusebytes/blob/master/fusebytes.ino#L699
 
The following users thanked this post: elecdonia

Offline HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1471
  • Country: gb
Re: Compiling Optiboot bootloader for ATmega32M1
« Reply #10 on: February 18, 2019, 07:44:15 pm »
Thought I would post back here with the results of my experimentation with Peter Fleury's STK500v2-compatible bootloader. Not really on-topic any more, as the subject matter is no longer Optiboot, but I still thought it may be informative.

There are a number of modifications I ended up making to the bootloader code:

- Added support for LIN-based UARTs. It wasn't quite as straight-forward as I had hoped, and involved re-jigging of some of the existing code that handles other types of UARTs, but the changes are still quite straightforward.
- The LED indicator stuff was hard-coded to active-low, so I added an option to make the polarity configurable (I needed active-high).
- I had to change the device signature string from "AVRISP_2" to "STK500_2".

One thing I realised while changing the UART configuration code was that because my device is running at only 8 MHz, I can't get a proper 115.2Kbaud out of it with the common 8/16 bit-sampling timing that is fixed (toggle-able by the 'U2X' flag) in other UARTs. However, because the ATmegaXXM1 series actually has a configurable bit timing (anywhere from 8 to 63), I can if I set it to an uncommon value. So rather than complicate the code, I just for now hard-coded it to 23 (and prescaler of 2), which gets me within 1% of 115.2K. In the long run I'll plan to switch to a 12 MHz crystal on this board, though, so I can get bang on 115.2K at 8/16 timing. :)

So, I now have a bootloader that satisfies my criteria of working with both avrdude and Atmel Studio 7!

Incidentally, that is the reason why I had to change the signature string - AS7 didn't handle it being "AVRISP_2", for whatever reason. But avrdude doesn't seem to care either way when telling it you have an 'stk500v2' programmer.

Also, one odd thing I have noticed - that may or may not be of concern - is the behaviour when reading flash memory of avrdude versus AS7. I noticed that the size of the read data from avrdude was not the full 32KB. :scared: Comparing in a hex editor, it appears as though when reading with avrdude, it stops at the end of the bootloader, rather than at the end of flash. The discrepancy in size comes about because the bootloader does not occupy the full 1024 bytes (only 940). The un-read bytes are just 0xFF emptiness, so don't really matter at the end of the day. But I've no idea what's causing this. From reading the code and the protocol documentation, it appears the programming application specifies the number of bytes to read. So why does avrdude specify a reduced value? :-//

As the bootloader is GPL, I'll probably put my changes on GitHub at some point.
 
The following users thanked this post: meshtron

Offline oPossum

  • Super Contributor
  • ***
  • Posts: 1415
  • Country: us
  • Very dangerous - may attack at any time
Re: Compiling Optiboot bootloader for ATmega32M1
« Reply #11 on: February 18, 2019, 08:08:47 pm »
Comparing in a hex editor, it appears as though when reading with avrdude, it stops at the end of the bootloader, rather than at the end of flash. The discrepancy in size comes about because the bootloader does not occupy the full 1024 bytes (only 940). The un-read bytes are just 0xFF emptiness, so don't really matter at the end of the day. But I've no idea what's causing this.

It is common for hex files to omit strings of 0xFF. This may be just at the end or throughout the file. A device programmer will typically clear it's buffer to 0xFF before loading the hex file.
 

Offline HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1471
  • Country: gb
Re: Compiling Optiboot bootloader for ATmega32M1
« Reply #12 on: February 18, 2019, 09:10:30 pm »
It is common for hex files to omit strings of 0xFF. This may be just at the end or throughout the file.

Ah, that makes sense.

I went looking to see where this avrdude behaviour is documented, and was puzzled not to find any mention of it. Until I then did some Googling and hit upon a PDF version of the manual on some random site, which contained this sentence:

Quote
When reading any kind of flash memory area (including the various sub-areas in Xmega devices),  the resulting output file will be truncated to not contain trailing 0xFF bytes which indicate unprogrammed (erased) memory.

WTF? That paragraph doesn't appear in the docs on the avrdude website! Oh, wait... according to the footer on each page, that version was generated in 2013. |O

Checking the SVN repo reveals that the current version's man page sources do indeed contain the aforementioned paragraph. Gee, it would be nice if the win32 distribution of avrdude by default included a copy of the man page, so I don't have to rely upon some old-arse version on the website or remember to download the docs separately. ::) :--
« Last Edit: February 18, 2019, 09:14:40 pm by HwAoRrDk »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf