Compiling Optiboot bootloader for ATmega32M1 - Page 1
Forum section: electronics / general

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 15, 2019, 03:41:58 pm
content: 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 foundthis 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:## ATmega32M1#HELPTEXT += "target atmega32m1 - ATmega32M1 (32pin, 32k)\n"atmega32m1: TARGET = atmega32m1atmega32m1: MCU_TARGET = atmega32m1atmega32m1: CFLAGS += $(COMMON_OPTIONS)atmega32m1: AVR_FREQ ?= 8000000Lifndef BIGBOOTatmega32m1: LDSECTIONS = -Wl,--section-start=.text=0x3f00 -Wl,--section-start=.version=0x3ffcelseatmega32m1: LDSECTIONS = -Wl,--section-start=.text=0x3e00 -Wl,--section-start=.version=0x3ffcendifatmega32m1: $(PROGRAM)_atmega32m1.hexatmega32m1: $(PROGRAM)_atmega32m1.lstatmega32m1_isp: atmega32m1atmega32m1_isp: TARGET = atmega32m1atmega32m1_isp: MCU_TARGET = atmega32m1ifndef BIGBOOT# 512 byte (256 word) boot size, SPIENatmega32m1_isp: HFUSE ?= DEelse# 1024 byte (512 word) boot size, SPIENatmega32m1_isp: HFUSE ?= DCendif# Clock source / startup time EXTXOSC_8MHZ_XX_1KCK_14CK_0MSatmega32m1_isp: LFUSE ?= EE# Brown-out level 4v3atmega32m1_isp: EFUSE ?= FCatmega32m1_isp: ispI 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 theLDSECTIONSvalue in the main Makefile for another chip, for example the ATmega328P, they are:Code:ifndef BIGBOOTatmega328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffeelse# bigboot version is 1k long; starts earlieratmega328: LDSECTIONS = -Wl,--section-start=.text=0x7c00 -Wl,--section-start=.version=0x7ffeendifBut 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?

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 15, 2019, 04:56:37 pm
content: Ah, I realised my mistake with the section addresses. It is even covered in theOptiboot Wiki.The addresses the linker is expecting arebyteaddresses, whereas the addresses in the datasheet arewordaddresses. 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 myLDSECTIONSvalues:Code:ifndef BIGBOOTatmega32m1: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffeelseatmega32m1: LDSECTIONS = -Wl,--section-start=.text=0x7c00 -Wl,--section-start=.version=0x7ffeendifIt 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...

author: mikerj
author_rank: Super Contributor
timestamp: February 15, 2019, 05:35:30 pm
content: 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.

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 15, 2019, 06:20:05 pm
content: 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.

author: westfw
author_rank: Super Contributor
timestamp: February 16, 2019, 10:34:27 am
content: QuoteOptiboot 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/HowOptibootWorksQuoteI 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 theATtinyCore

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 16, 2019, 01:36:09 pm
content: Quote from: westfw on February 16, 2019, 10:34:27 amSo 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.

author: westfw
author_rank: Super Contributor
timestamp: February 17, 2019, 06:47:55 am
content: Sigh. I has a long a detailed reply going, but apparently I forgot to hit "post"...QuoteNo. It may require STK500v2; AS commonly wants to upgrade your programmer firmware before it will use the device :-(QuoteSurely 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 aprogrammercommunications protocol.)QuoteYes. But you could do, say:make atmega328 SUPPORT_EEPROM=1 NO_APP_SPM=1 LED_START_FLASHES=0 LED_START_ON=1QuoteManual adjustment. Note that chips with "boot section" support have very "quantized" bootloader sizes. BIGBOOT is the next size up from 512bytes.QuoteInstead 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.

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 17, 2019, 06:50:14 pm
content: Quote from: westfw on February 17, 2019, 06:47:55 amI 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.Quote from: westfw on February 17, 2019, 06:47:55 amNow I know that AS7 is trying to speak STK500v2 protocol, I have been looking atPeter 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.

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 17, 2019, 07:04:20 pm
content: 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.versionsection, for which the convention appears to be (although I guess it depends on the actualLDSECTIONSvalues 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 thepgmspace.hfunctions? Something like this, perhaps:Code:uint8_t optiboot_ver_minor = pgm_read_byte((uint8_t *)(FLASHEND - 1));uint8_t optiboot_ver_major = pgm_read_byte((uint8_t *)FLASHEND);

author: westfw
author_rank: Super Contributor
timestamp: February 18, 2019, 03:01:18 am
content: QuoteYes, 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

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 18, 2019, 07:44:15 pm
content: 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), Icanif 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 avrdudeandAtmel 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 wasnotthe full 32KB.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'treallymatter 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.

author: oPossum
author_rank: Super Contributor
timestamp: February 18, 2019, 08:08:47 pm
content: Quote from: HwAoRrDk on February 18, 2019, 07:44:15 pmIt 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.

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 18, 2019, 09:10:30 pm
content: Quote from: oPossum on February 18, 2019, 08:08:47 pmAh, 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:QuoteWTF? That paragraph doesn't appear in the docs on theavrdude website! Oh, wait... according to the footer on each page, that version was generated in2013.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.