Core SPM programmer: request for comments #940
Replies: 18 comments 18 replies
-
From PR #936:
This is not wrong. Below the two scenarios on the back of an SSD packet. Upon 'chip erase', do nothing, but when programming a page, first erase it:
Upon 'chip erase', loop over all application flash pages, and erase them:
So we are looking at approximately 22-44 bytes vs 4 bytes. One question is whether this difference is big: it can make 10% of the bootloader size and, in many cases, risks pushing the bootloader size over a page boundary. And we are not even talking about reading the actual fuse byte that tells us whether chip erase implies EEPROM erase, and if needed erase that too. Another is whether the second scenario is really needed. In my world there is nothing wrong with the first scenario. The unused flash may look messy from previous use, but the suggested SPM programmer could emulate the chip erase by looping in avrdude (plenty o' RAM there) to clear the flash (slower, but that's the trade-off to save flash for every application). And the user calls the shots by using I like keeping flash for the application. But I am also partial to bootloaders: I like them for rapid prototyping. And testing. And EEPROM r/w. And for providing a |
Beta Was this translation helpful? Give feedback.
-
I was thinking that for an explicit SPM programmer implementation, it might be possible to offload a "chip erase emulation" (erase everything except the bootloader) into AVRDUDE - but then, only the bootloader knows the size of what constitutes "application flash", and least on small devices where it cannot be deduced by the fuses (which btw. is currently not possible anyway as AVRDUDE has no knowledge about the meaning of each fuse bit in each controller). So, for an SPM programmer protocol, it would be essential to provide a method where AVRDUDE can query the size of the application section. |
Beta Was this translation helpful? Give feedback.
-
Btw., I tend to transfer this into the discussion area. Objections? |
Beta Was this translation helpful? Give feedback.
-
Great Idea
Correct. There are plenty of possibilities of doing so. The way I see it is that we have freedom to determine a) what SPM programmers can and cannot do (ie, how they should behave); b) how they communicate with the host; c) what avrdude promises to provide and what it promises to not request (to avoid code in the bootloader that ignores requests). The best outcome for this exercise is something that helps bootloader writers to write efficient bootloaders. As an example, I have a prototype implementation of the following idea: the bootloader keeps a six-byte table at FLASHEND with
During handshake the bootloader lets know which part it sits on. Avrdude knows where FLASHEND of the part is and requests the six bytes below FLASHEND from the bootloader using the normal buffer flash read. So, that flash read routine doubles up for this info exchange at no extra cost for the bootloader. At the time I had not thought about bootloaders that do not wish to implement flash read. |
Beta Was this translation helpful? Give feedback.
-
Several options exist with minimal code footprint in the bootloader
Method 2 can lead to a proliferation of SPM programmers in Other query methods/protocols exist but I don't see how they can be implemented without spending more than one byte bootloader code. The same set of methods could be used for SPM programmers communicating
Backward compatibility: Existing bootloaders, eg, served by From a practical point of view, an implementation of a generic SPM programmer could (try to) figure out whether it talks to a bootloader with a specific protocol. For example, -c arduino and optiboot use the STK500 communication protocol to talk to each other about the tasks at hand. If the generic SPM programmer sees responses compatible with the STK500 communication protocol, it could indeed restrict itself to that protocol and implement the ideas developed here as far as possible. Would require Method 2 or 3 for communicating bootloader size when needed. |
Beta Was this translation helpful? Give feedback.
-
From Issue #944 If the SPM programmer realises that the bootloader does not implement flash read it would be good if it was able to tell |
Beta Was this translation helpful? Give feedback.
-
Memory granularity. AVRDUDE reads/writes/verifies the whole memory only (with the exception of specific, hardcoded named subsections of flash in the case of There is utility in being able to do so at a smaller granularity. Use examples:
This is relatively easy to implement for SPM programmers because bootloaders have the super power of SPM page erase. The SPM programmer in AVRDUDE can therefore implement sub-page writes through a page read, modify and page write cycle. Again, at no extra code footprint to the bootloader. The "small memory granularity" idea is simple. A backward compatible extension of the current AVRDUDE usage syntax is simple (eg, as indicated above). I do realise that the current codebase does not lend itself readily to a simple implementation, though. Essentially, this would require a remodelling of AVRDUDE's understanding of memory with consequences for how Being able to write small subsections of flash is (relatively) easy for any AVRDUDE programmer that has explicit page erase or implicit page erase in paged writes at their disposal. Small-granularity read/writes/verifies is an idea that transcends SPM programmers, though: it is also possible for AVRDUDE to effect this for any of its programmers. In the worst case, flash writes of a small section would involve a chip read (including EEPROM), modify, chip erase and write. (This is what a user would have to do manually otherwise). |
Beta Was this translation helpful? Give feedback.
-
Metadata. One of the benefits of a bootloader is that it can, and often does, export a function However, the compiled application usually has no knowledge how large it is. An application that wishes to utilise AVRDUDE not only knows the code size but also can easily write it to a location in flash that the application can access. A natural place is just below the bootloader. Generalising this idea, AVRDUDE can (optionally, driven by the user) drop the last-modified date and name of the input file just below the bootloader, too. The idea of an optional metadata section just below the bootloader only costs one byte flash expressing which pieces of metadata are available and where they reside. Of course, users can, and always could, assemble their ultimate flash image outside AVRDUDE, and just use AVRDUDE to upload the entire image. However, this requires mastery of tools that manipulate code sections, patch the vector table (for a vector bootloader), merge code sections, tables, metadata, the bootloader itself etc. AVRDUDE offering to write a few pertinent meta-data on its own accord would give the "ordinary" user new functionality. Optional, so backward compatible. |
Beta Was this translation helpful? Give feedback.
-
Summarising, I suggest implementing an SPM programmer that
I suggest not exporting higher-granularity memory r/w through |
Beta Was this translation helpful? Give feedback.
-
Mandate When the user asks a file to be programmed without chip erase, I don't see a mandate to alter bytes outside the segment(s) that the input file defines, so suggest read(s) if needed (and possible) to pad page, then modify the page, followed by an atomic erase and write page. In fairness, more often than not the users won't care what's outside the to be uploaded file (but how can I be sure?), so the read would be unnecessary and just cost time. Can be solved by ...
|
Beta Was this translation helpful? Give feedback.
-
AVRDUDE terminal SPM programmers give a poor experience when combined with AVRDUDE's
Therefore you currently get no joy when doing, eg,
I solved this in my
BTW, this also goes some way to address the memory granularity access mentioned earlier. Above allows bootloader users to extract quickly certain sections of the EEPROM/flash, eg, to obtain a board id that the project stored somewhere. Given that bootloaders are often connected with a slow-ish serial connection, that solution is pretty slow for larger memory dumps through the overhead of address loads for each byte. Here, an explicit programmer characterisation The other aspect is keeping a bootloader alive in terminal mode. That can be achieved by changing Summarising, with an explicit characterisation of an AVRDUDE programmer as |
Beta Was this translation helpful? Give feedback.
-
@stefanrueger Can you share your urclock bootlader? Thanks. I can not get optiboot to work with EEPROM under avrdude. |
Beta Was this translation helpful? Give feedback.
-
Chip erase in the bootloader I have now implemented (compile-time optional) chip erase in my bootloaders, which turns out to cost between 18 and 58 bytes code. For roughly every other bootloader this pushes its size over a page boundary. Instead of implementing chip erase in the bootloader for these, the new SPM programmer under discussion will erase flash during upload (except the bootloader). This is not far from my earlier estimate but I
Here a 512-byte optiboot drop-in bootloader atmega328p.hex with chip erase and EEPROM r/w that works with
The table below shows for individual bootloaders the number of extra code bytes, and the number of extra bytes owing to crossing page boundaries, the actual size of the bootloader, the effective space needed considering page size, and what the bootloader can do:
|
Beta Was this translation helpful? Give feedback.
-
Terminal mode (cont'd) @mariusgreuel Windows questions below I have now added terminal support for bootloaders in my draft urclock programmer and
This is now a real joy to use!
My solution for periodic "keep alive" calls to the bootloader uses callbacks in the readline() library. Unfortunately, the readline() code in
How is that functionality available in Windows? Cheers |
Beta Was this translation helpful? Give feedback.
-
Urprotocol proposal Comments welcome [edited 2022-06-26 to reflect discussions]. Explicit communication between an uploader/downloader program ("the programmer") and the bootloader is driven by the programmer, which sends command sequences to the bootloader and evaluates its return sequence. A command sequence starts by a command byte, followed by its parameters, followed by an end-of-parameter byte Although the
As Parameters. Paged EEPROM/flash read/write commands need the address followed by the length of the memory block, possibly followed by n=length bytes to be written. The address is always a byte address in big endian; it is 16-bit for MCUs that have up to 65536 bytes flash and 24-bit for MCUs with larger flash. Zero-length reads or writes are not supported by the protocol. If the flash page size is 256 or less, then the length parameter is sent as one byte (where 0 means 256 bytes). Otherwise the length parameter is sent as two bytes big endian (where 0 means 65536). Note, however, that the only valid length for the write flash page command is the MCU flash page size. The other three paged access commands can request any length between 1 and 256, and 1 and 65536, respectively. The programmer must always meet the following constraints: the EEPROM write length must not exceed the MCU flash page size; each address block must be fully within the range of EEPROM or flash on the device. It is best practice that the programmer generally sends page-aligned addresses for paged writes and page erases as some parts require even addresses for this. Whilst the sizes of the address and length parameters may differ between bootloaders, for a particular bootloader incarnation both the address and length are always given in the same way. This means that the EEPROM address on an MCU with a large flash will be a 24-bit address despite a small EEPROM. The length parameter must always be specified, even though the write flash page command only allows one valid length, and the page erase command does not need a length at all. This is to simplify the bootloader effort to decode the programmer's command sequences. The following commands are known
Error handling. It is generally considered an error if the programmer asks for non-implemented functionality, as it knows after synchronisation how the bootloader is configured. Hence, the bootloader WDT should reset on request of an optional, not implemented command. Typically, the bootloader would need to save the payload of EEPROM/flash writes to SRAM; for security reasons the bootloader should trigger a WDT reset if an illegitimate length of a paged write could overwrite the stack (eg, a request for writing 256 bytes EEPROM on a part with only 256 bytes SRAM). A protocol error detected by the bootloader (failure to match UR_EOP) should lead to a WDT reset. Protocol errors detected by the programmer (not matching UR_INSYNC or UR_OK) should lead to a termination of programming attempts. Frame errors in serial communication should also lead to a WDT reset or termination of programming, respectively. The bootloader should protect itself from being overwritten through own page writes and page erases. Implicit communication of further bootloader properties such as the bootloader size happens through a small table located at the top of flash. Normally, the programmer can read this table after establishing the MCU id, and therefore the part for which the bootloader was compiled and the location of top flash. The 6-byte table contains (top to bottom)
If the bootloader does implement flash read, the user needs to supply any necessary parameters on the command line. Backward compatibility mode. When urprotocol after synchronisation with the bootloader settles on Limitations. Urprotocol has only provisions for reading EEPROM and flash, for writing EEPROM and for writing flash other than the bootloader area. In particular, urprotocol has no provisions for reading other memories such as the signature (other than in backward compatibility mode), calibration bytes, locks or fuses, and neither for writing lock bytes. The protocol does not consider sub-page flash writes, which are shifted to the programmer. If the bootloader's flash write does not look like NOR programming and if the bootloader does not provide flash read, then sub-page modifications simply cannot be done. Installing a bootloader has security implications as it provides a means to modify flash thus weakening the Harvard architecture of AVR microprocessors. Even bootloader implementations that are hardened against prohibited address and length parameters have, out of necessity, somewhere a code sequence that manipulates flash memory. A flawed application might still give an attacker a way to call these code sequences, so be warned here be dragons. |
Beta Was this translation helpful? Give feedback.
-
Neat idea! I hadn't thought of that. I would first try and see whether AVRDUDE could provide automated baud rate detection: one place, one algorithm, a gazillion more resources than AVRs. My overriding mantra here is "Do as much as possible in the programmer and as little as you can get away with in the bootloader". I don't know what is involved in doing that, and if possible whether a portable solution could be found. An AVRDUDE solution would benefit a slew of other use cases. Failing that, it's eminently possible to add automated baud rate detection to the urboot bootloader in a similar way as it will have been added in the optiboot fork. I would implement this as a "neat-to-have" compile-time option. You will be aware of limitations of trimming the baud rate registers of AVR USARTs, though: at the high end of baud rate divided by F_CPU, the granularity available for matching the PC baud rate is not great. For example, an 8 MHz AVR finds it hard to match 115200 baud with the UART. Actually, for that combo I need to use software bit toggling instead in the urboot bootloader. |
Beta Was this translation helpful? Give feedback.
-
Should urprotocol cater for other memories than flash/EEPROM?
The protocol could (actually relatively easily) be extended to provide a means of reading other memories; I thought about this but didn't see a lot of benefit or use cases to justify implementation. I am happy to be convinced otherwise.
No, urboot bootloaders know exactly which MCU they have been compiled for and pass a unique MCU id on to the programmer. My ideal user scenario is: if the user does not specify the -p flag, there are no checks, and the MCU passed on by the bootloader is used; if the user specifies an MCU, a check happens just like it has been the case all along: AVRDUDE requests the signature bytes from the urclock programmer that looks up the signature bytes of the exact part that the urboot bootloader has indicated (without bothering the bootloader). As you'll probably know, bootloaders such as optiboot don't actually read the signature bytes from the device, instead they send the SIGNATURE_0..2 avr-libc compile-time constants for the MCU to the programmer. Using signature bytes for id-ing the device does not work universally, as AVRDUDE and avr-gcc don't necessarily have the same signature bytes for the same devices, as signature bytes are not unique for the device, and as they not even determine the flash memory size or the flash page size of the device.
Same here! Happens easily when you have a number of boards with different MCUs connected to the PC :-O |
Beta Was this translation helpful? Give feedback.
-
Vector bootloaders
Sure, if you can use HW-supported boot sections, go for it. Urclock/urboot support ordinary HW supported bootloading. Vector bootloaders are SW-supported bootloaders. Their benefit is generality and size granularity:
Fun fact: I only set the fuse bits when the bootloader size for an MCU happens to be a HW-supported size. The newer AVR8X devices are much better in that respect, though, as they support any number of 256-byte pages for bootloaders, and I suspect there is no benefit for vector bootloaders for these, indeed. Yes, what I call a vector bootloader really is the same idea as optiboot's virtual boot partitions:
The urclock/urboot implementation is radically different from optiboot's: The latter patches programs on upload in the bootloader itself, which costs some 110 bytes of AVR flash memory, and is therefore likely to cut corners. Last time I looked at the optiboot code, eg, it missed to check whether the to-be-uploaded sketch was already patched for vector bootloaders (arises when you want to upload a previously downloaded .hex image that would already have been patched during upload). In contrast, an urboot vector bootloader shifts the patching to the external programmer, which can spend a lot more resources on making sure it just works.
Yes, I noticed the same when I tried that a few years back. I suspect the optiboot code isn't (wasn't?) watertight.
Yes, it can, but no, it won't. It can because as soon as an incident destroys the reset vector the bootloader stops working (same incident-category as accidentally zapping the bootloader itself). It won't because |
Beta Was this translation helpful? Give feedback.
-
This is to start a discussion on avrdude support for bootloaders (ie, SPM programmers).
I propose modelling SPM programmers along existing bootloaders and along the capabilities of the SPM/LPM opcode and EEPROM access (or, in newer parts, along the capabilities of the NVM Controller). This to complement avrdude's modelling of SPI programming, PDI, UPDI, HVPP, JTAG, Debugwire etc.
Some of the peculiarities of SPM programmers: they
RAMPZ
andZ
are set to byte addresses for the SPM and LPM opcodes)In essence, SPM programmers allow a higher abstraction level than other modes of programming: the vagaries of the actual to be programmed part are mostly addressed in the bootloader, though avrdude benefits from knowing what the highest flash address is, the flash page size and a few parameters that depend on the bootloader but not on the part (for example, which memories the bootloader can read/write and at which granularity, whether the bootloader is a vector bootloader, which interrupt is used for that, how big the bootloader is so avrdude does not overwrite it etc).
One popular current avrdude SPM programmer is
arduino
, which is used for uploading/downloading applications and EEPROM contents via a bootloader on the part. It builds upon the STK500 protocol that models external programming and behaves as if the bootloader was an external programming device. Essentially, for all intents and purposes, thearduino
programmer is an STK500 programmer one minor, but important, difference being that it plucks the DTR line with a view to issue reset on the connected part, so it runs the bootloader code.In theory, a bootloader could emulate an STK500 external programmer, but in practice they don't necessarily do this.
I can see the following clear disadvantages of this bootloader-as-an-STK500 approach:
avrdude -c arduino
So, I suggest writing a generic core SPM programmer (I am happy to do so, and have experience in doing so), which supports the following minimum capability of a bootloader
and zero or more of the following
Optiboot is an example of a bootloader that supports flash read/write as above, with some optiboot renderings also supporting EEPROM r/w (it's a compile-time option). The core SPM programmer would emulate the EEPROM erase and/or flash erase writing 0xff to flash/EEPROM as a slower alternative if the bootloader does not provide this functionality.
I suggest using by and large the syntax of STK500 communications with small changes to the protocol to support 2/3-byte addresses and to support the bootloader telling
avrdude
early on which part it is and which subset of the 5 optional capabilities the bootloader has implemented. I suggest using two bytes for this, so this scheme can afford 11 bits for 2048 different parts; currentlyavrdude
knows 313 parts (one of which AVR32), avr-libc 293 parts and Microchip's ATDF files know 323 AVR8 parts. The union of these three sources amounts to 374 parts though some of the older/smaller parts are clearly not suitable for bootloader programming at all (no RAM or no SPM).The remaining parameters (application vector number for vector bootloaders, size of bootloader) can come from a few table bytes at the end of the bootloader, or failing that, from extended
-x
command line options.For all this to work,
avrdude
's proposed core SPM programmer might need/benefit from.conf
(default off for backward compatibility)OK, that's the long of it. Comments appreciated.
Beta Was this translation helpful? Give feedback.
All reactions