Martin's corner on the web

2boots bootloader on the uIoT: Serial + MMC bootloader in 2Kb

The 2boots bootloader is a lovely bootloader, developed by Thomas Seiler that is

  • Just 2kb of flash, fits into normal 2kb bootblock of most atmega chips
  • Serial (stk500v1) bootloader, compatible with avrdude and Arduino IDE
  • Additional MMC bootloader, can read directly a intel .hex format file from an MMC/SD

What is appealing here is the ability to upload firmware without a programmer, simply by inserting a SD card with the .HEX file and performing a reset. That is a nice feature to have when having to remotely update the firmware – imagine that you have multiple nodes at clients in many locations: they can upgrade firmware quite easily now.

I (and many others) have previously tried to get it working, but couldn’t; we ended up using another bootloader that is SD card only (and .bin, not .hex compatible) and 4Kb.. I shared my experience here and here. Clearly 2boots is better..if only it was working. After failing to get it run, I have abandoned the project until recently I noticed some activity in Thomas’ github repository. There seems to be some fixes introduced and I decided to give it a new try. It didn’t work again, so I took a deeper look. It seems that he had another branch (new-makefile) in the repository that was having quite a bunch of changes, I tested it too and noticed that there is improvement: it did update the firmware from SD card, but only after a successful serial upload..odd? After couple days of debugging and testing, it turns out that there is a logical problem in the stk500v1.c file – it performs a WDT reset after timing out on serial, therefore the MMC upload procedure was never called unless preceded by a successful serial sketch upload.. duh. I fixed that by using a “break;” instead of performing watch-dog reset and Voila – it worked!

I tried it on my uIoT gateway with SD shield on and it works nicely. Quite nice feature to have. I have added it to my collection of bootloaders for the uIoT on github.

39 thoughts on “2boots bootloader on the uIoT: Serial + MMC bootloader in 2Kb

  1. Scott Wanner

    Tried using the code you have put on github but I cannot see what to tell it to use digital pin 10 as the CS pin. I’m trying to us a standalone arduino with an SD Card Module that has the CS pin at 10. Any help would be great.

    1. Martin Harizanov Post author

      Scott,
      you have to adjust the Makefile, for the uIoT it has these lines

      board-arduino: FCPUS = 6250000L
      board-arduino: MCUS = atmega328p
      board-arduino: MMC_CSS = PC1

      while for a “normal” arduino you need

      board-arduino: FCPUS = 16000000L
      board-arduino: MCUS = atmega328p
      board-arduino: MMC_CSS = PB2 //digital 10

      then build and burn

  2. Jonny Flowers

    Hi,
    I would love some help to get this ported over onto the arduino Mega. Specifically running at 3.3V and MHz

    1. Martin Post author

      That should be fairly easy; I guess changing the SD CS and LED pins + using appropriate fuses should do it.
      I don’t have a Mega, neitither the time to help further than this 😉

  3. Pingback: Re-vamping my Daikin Internet Air-conditioner controller | Martin's corner on the web

  4. Jens

    I am going to try your bootloader at the Arduiono Ethernet board but I am also very interested in using on the new Due board with and Ethernet shield (which has the SD socket). Is this possible or is it something completely different?

  5. Thomas

    Hey Martin, this looks very good.
    I have tried out your code, compiled it and flashed it. But then i can’t contact the arduino over the serial interface any more. I’m using a Arduino Uno and normaly it should work when i understand the 2boot description right. Do you have any ideas?

    Thank, Thomas

    1. Martin Post author

      Few things to watch out:
      1) mind the FCPU and set it to whatever frequency you run
      2) mind the SD card select pin
      3) upload baud rate is 19200, update this in your boards.txt

      1. Rodot

        Hi there !
        I managed to compile you code, but when I try to upload a program using arduino I get
        avrdude: stk500_recv(): programmer is not responding
        I’ve set the FCPU to 16000000L in the make file, and baud rate to 19200 in boards.txt. Even with the nommc it doesnt works. I also tried to upload with the arduino and the stk500v1 protocol (by editing boards.txt)
        When I try to upload, the RX and TX leds blinks the following pattern once :
        RX TX RX RX
        It means that I’ve got a answer from the µcontroller, but avrdude doesn’t seem to take it into account as it says “not responding”.

        It’s really important for me to get 2boots working for my project. It’s a portable gaming device based on arduino, and thank to 2boots it would be able to switch between games without a computer.

        Thank you for reading, I hope you have any idea what the problem could be :/

        1. Rodot

          …I forgot to say, I’m running on an atmega328p @16Mhz, and I use a FT232L for the USB port. It works like a charm with uno and duemilanove bootloader.

        2. Martin Post author

          Can you share the compile flags, I have lost mine too, so these will be for the history/future visitors.

          My boards.txt has the upload protocol set to stk500v1 too, here is what is working for me: (I have 12.5Mhz MCU, ignore that part)

          ##############################################################
          2buiot.name=Simon K. Micro Web Server @ 12.5Mhz /19200 2Boots
          2buiot.upload.protocol=stk500
          2buiot.upload.maximum_size=30720
          2buiot.upload.speed=19200
          2buiot.bootloader.low_fuses=0xE0
          2buiot.bootloader.high_fuses=0xDD
          2buiot.bootloader.extended_fuses=0x05
          2buiot.bootloader.path=atmega
          2buiot.bootloader.file=uiot.hex
          2buiot.bootloader.unlock_bits=0x3F
          2buiot.bootloader.lock_bits=0x0F
          2buiot.build.mcu=atmega328p
          2buiot.build.f_cpu=12500000L
          2buiot.build.core=arduino
          2buiot.build.variant=standard

          1. Rodot

            I use the compile flags from your github :

            OPTIMIZE = -Os -funsigned-char -fno-split-wide-types -fno-inline-small-functions -mcall-prologues -ffunction-sections -fdata-sections -ffreestanding -fno-jump-tables -fno-tree-scev-cprop -fno-split-wide-types

            When I compile it does a 2006B text size.

            I’m going to try to upload that again, I’ll post my progress here.

  6. Jens

    It appears from the Readme file that you are making it on a Linux machine, and I am having big problems getting it to make on a Win7 PC. It starts processing the Makefile but it has problems with mkdir, cut and awk. I wonder if you have a simpler Makefile that would work on Windows.

      1. Jens

        I am still struggling with the build on Linux and wonder if you could upload hex files for all boards? In particular I need it for the Arduino Ethernet board, which I think should be:

        2boots-arduino-atmega328p-16000000L-PD4.hex

        This is not included.

        Thanks….

  7. Jason

    Hi Martin,

    Thanks for the great post and details! I’d like to use this bootloader with a custom board I’m working on but had a question regarding the reset. My current board design doesn’t include a reset button with it, so users simply reset by taking the power plug out and plugging it back in.

    Do you see any reason that loading new sketches with 2boots won’t work with such board design? Do I need to add a reset button to get this working?

    My assumption is that taking the power out and back in will give identical result as a reset button and therefore just placing the power back in with the new hex file placed in the SD card slot should work just fine.

    Would love to get your thoughts and experience with this.

    Thanks!

    -J-

    1. Martin Post author

      It does work, my uIoT project also doesn’t have a reset pin and a power cycle does the trick.
      Cheers,
      Martin

  8. Jason

    Hi Martin,

    After a long night (and partially morning..) I managed to build it on my Windows machine. But I’m suspecting I might be heading to a new problem. After completing the build, make reports the result size of 2070 bytes.

    According to the original readme file, the bootloader shouldn’t exceed 2Kb. I tried to see if I can find anything in the src I can just remove – but I doubt there is any spare code in there.

    What is the size you’re getting? Do you believe this will indeed cause a problem?

    Thanks again!

    1. Jason

      Actually thinking about it some more – since I’m preparing my own custom boards I can probably remove the entire eeprom check section – and just place my fixed board name in the code. Do you see any reason this change won’t work?

      I assume such change will free enough space.

    2. Martin Post author

      I remember running into the same issue, I fiddled with the OPTIMIZE flags line in the MakeFile and eventually got it to less than 2048 bytes.
      I compiled this on a Raspberry Pi by the way.

      Using hardcoded sketch name will definitely save you few bytes

      1. Jason

        Yup – changed the code to a fixed name and I’m down to 2044, seems like this might work!

        Now making changes in the Arduino IDE and will try to burn the new bootloader shortly for some testing. Thanks for the help!

      2. Rodot

        Hi !
        I’m also trying to compile 2boots for a custom board, and I get a 2190 bytes hex… what did you do with the optimization flags ? Could you share which one you used ? Tanks !

  9. Nick

    Hi Martin,

    Well done reworking this bootloader. I downloaded your version a month or so ago but didn’t have any luck getting it working at the time. I have recently had some time to look into why.

    I didn’t require the serial upload capability in my application so I removed that which left plenty of room to add debug output. I found that my cards were all failing init(). I was confident the FAT16 formatting was ok. The cards I have to play with are limited to Verbatim and Transcend brands – don’t know if this is a factor.

    I ended up increasing the timeouts of a few loops in the code and now the bootloader works perfectly and reliably for all my SD cards. This is on genuine Arduino boards, a freetronics “EtherTen” board, and a custom 328P-based application-specific board I have made.

    For interest (or anyone else having similar issues), these are the parts where I modified the timeouts –

    – MMC_CMD0_RETRY
    – send_cmd() (“wait for response” loop)
    – mmc_init() (“reset MMC”)
    – wait_start_byte()

      1. Nick

        No problem! Also perhaps worth mentioning I added a timeout to the “while(send_cmd() != 0)” loop at the end of mmc_init(). There is a comment there wondering if it could become an endless loop, and I found this is exactly what happened if I had a FAT32 [4GB only tested] card in when the chip was reset. My custom board is used in a datalogging application so this is a pretty likely scenario for me, and having the bootloader hang is not exactly ideal! 😉

        1. Ip

          Hello nick, what values did you take for the timeouts and how exactly did you solve the fat32 problem?
          (would you consider uploading the code, i’m not that good at bootloaders?)

          1. Ip

            I have doubled the values of i and the CMD0, however, some cards still aren’t working. (What am i doing wrong here?)

  10. Jani Sakki

    Is it possible make a programme that can change the name of the sketches so that you can choose what sketch you want to use?

  11. Ip

    Hello,-
    I’ve managed to get out some more bytes 🙂
    now i’m waiting to put in nick’s changes to be more reliable

    however, there’s still a problem: it keeps flashing the hex from sd on every reset; i think martin, you said that this isn’t good and that it should be taken care of.

    i also tried to let mmc first check if there’s a file called 0, in order to let it flash (and letting the Hex file stay on sd card), but to no avail…

  12. Michael

    Hello Martin,

    I finally managed to write the bootloader to my atmega 328p (with some help of a friend to compile it) and ran into the next problem. what format the file on the sd card must have? what must i do with the .ino file to make the thing work.

    Thanks in advance for your answer, Michael

  13. Michael

    Hello Martin,

    thank you for the quick answer.

    I found the .hex of the blink example and put it on the card, but unfortunately the code wouldnt load 🙁
    I wanted to name the ardoino but didn’t get a connection to the board via serial connection.

    I just get the error message avrdude: stk500_getsync(): not in sync: resp=0x00

    I tried to write back the original bootloader but got an error message again.

    I hope you can help,

    Michael

    Error log for uploading NameBoardSketch

    Binäre Sketchgröße: 2.326 Bytes (von einem Maximum von 30.720 Bytes)
    C:\Programme\Dev\Arduino\hardware/tools/avr/bin/avrdude -CC:\Programme\Dev\Arduino\hardware/tools/avr/etc/avrdude.conf -v -v -v -v -patmega328p -carduino -P\\.\COM7 -b57600 -D -Uflash:w:C:\DOKUME~1\VONBAR~1\LOKALE~1\Temp\build3319578670752978141.tmp\NameBoardSketch.cpp.hex:i

    avrdude: Version 5.11, compiled on Sep 2 2011 at 19:38:36
    Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
    Copyright (c) 2007-2009 Joerg Wunsch

    System wide configuration file is “C:\Programme\Dev\Arduino\hardware/tools/avr/etc/avrdude.conf”

    Using Port : \\.\COM7
    Using Programmer : arduino
    Overriding Baud Rate : 57600
    avrdude: Send: 0 [30] [20]
    avrdude: Send: 0 [30] [20]
    avrdude: Send: 0 [30] [20]
    avrdude: Recv:
    avrdude: stk500_getsync(): not in sync: resp=0x00

    avrdude done. Thank you.

    Command lines for avrdude to write original bootloader

    avrdude -p m328p -P com7 -c stk500v1 -b 19200 -F -v -v -e -Ulock:w:0x3F:m -Uefuse:w:0x00:m -Uhfuse:w:0xdd:m -Ulfuse:w:0xff:m

    avrdude -p m328p -P com7 -c stk500v1 -b 19200 -F -v -v -e -U flash:w:ATmegaBOOT_168_atmega328.hex

    Error log from avrdude to write original bootloader

    Using Port : com7
    Using Programmer : stk500v1
    Overriding Baud Rate : 19200
    AVR Part : ATMEGA328P
    Chip Erase delay : 9000 us
    PAGEL : PD7
    BS2 : PC2
    RESET disposition : dedicated
    RETRY pulse : SCK
    serial program mode : yes
    parallel program mode : yes
    Timeout : 200
    StabDelay : 100
    CmdexeDelay : 25
    SyncLoops : 32
    ByteDelay : 0
    PollIndex : 3
    PollValue : 0x53
    Memory Detail :

    Block Poll Page
    Polled
    Memory Type Mode Delay Size Indx Paged Size Size #Pages MinW Max
    W ReadBack
    ———– —- —– —– —- —— —— —- —— —– —
    — ———
    eeprom 65 5 4 0 no 1024 4 0 3600 36
    00 0xff 0xff
    flash 65 6 128 0 yes 32768 128 256 4500 45
    00 0xff 0xff
    lfuse 0 0 0 0 no 1 0 0 4500 45
    00 0x00 0x00
    hfuse 0 0 0 0 no 1 0 0 4500 45
    00 0x00 0x00
    efuse 0 0 0 0 no 1 0 0 4500 45
    00 0x00 0x00
    lock 0 0 0 0 no 1 0 0 4500 45
    00 0x00 0x00
    calibration 0 0 0 0 no 1 0 0 0
    0 0x00 0x00
    signature 0 0 0 0 no 3 0 0 0
    0 0x00 0x00

    Programmer Type : STK500
    Description : Atmel STK500 Version 1.x firmware
    Hardware Version: 2
    Firmware Version: 1.18
    Topcard : Unknown
    Vtarget : 0.0 V
    Varef : 0.0 V
    Oscillator : Off
    SCK period : 0.1 us

    avrdude: AVR device initialized and ready to accept instructions

    Reading | ################################################## | 100% 0.08s

    avrdude: Device signature = 0x000000
    avrdude: Yikes! Invalid device signature.
    avrdude: Expected signature for ATMEGA328P is 1E 95 0F
    avrdude: safemode: lfuse reads as 0
    avrdude: safemode: hfuse reads as 0
    avrdude: safemode: efuse reads as 0
    avrdude: erasing chip
    avrdude: reading input file “0x3F”
    avrdude: writing lock (1 bytes):

    Writing | | 0% 0.00s ***faile
    d;
    Writing | ################################################## | 100% 0.17s

    avrdude: 1 bytes of lock written
    avrdude: verifying lock memory against 0x3F:
    avrdude: load data lock data from input file 0x3F:
    avrdude: input file 0x3F contains 1 bytes
    avrdude: reading on-chip lock data:

    Reading | ################################################## | 100% 0.03s

    avrdude: verifying …
    avrdude: verification error, first mismatch at byte 0x0000
    0x3f != 0x00
    avrdude: verification error; content mismatch

    avrdude: safemode: lfuse reads as 0
    avrdude: safemode: hfuse reads as 0
    avrdude: safemode: efuse reads as 0
    avrdude: safemode: Fuses OK

    avrdude done. Thank you.

    C:\WinAVR-20100110\bin>
    C:\WinAVR-20100110\bin>avrdude -p m328p -P com7 -c stk500v1 -b 19200 -F -v -v -e
    -U flash:w:ATmegaBOOT_168_atmega328.hex

    avrdude: Version 5.10, compiled on Jan 19 2010 at 10:45:23
    Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
    Copyright (c) 2007-2009 Joerg Wunsch

    System wide configuration file is “C:\WinAVR-20100110\bin\avrdude.conf”

    Using Port : com7
    Using Programmer : stk500v1
    Overriding Baud Rate : 19200
    AVR Part : ATMEGA328P
    Chip Erase delay : 9000 us
    PAGEL : PD7
    BS2 : PC2
    RESET disposition : dedicated
    RETRY pulse : SCK
    serial program mode : yes
    parallel program mode : yes
    Timeout : 200
    StabDelay : 100
    CmdexeDelay : 25
    SyncLoops : 32
    ByteDelay : 0
    PollIndex : 3
    PollValue : 0x53
    Memory Detail :

    Block Poll Page
    Polled
    Memory Type Mode Delay Size Indx Paged Size Size #Pages MinW Max
    W ReadBack
    ———– —- —– —– —- —— —— —- —— —– —
    — ———
    eeprom 65 5 4 0 no 1024 4 0 3600 36
    00 0xff 0xff
    flash 65 6 128 0 yes 32768 128 256 4500 45
    00 0xff 0xff
    lfuse 0 0 0 0 no 1 0 0 4500 45
    00 0x00 0x00
    hfuse 0 0 0 0 no 1 0 0 4500 45
    00 0x00 0x00
    efuse 0 0 0 0 no 1 0 0 4500 45
    00 0x00 0x00
    lock 0 0 0 0 no 1 0 0 4500 45
    00 0x00 0x00
    calibration 0 0 0 0 no 1 0 0 0
    0 0x00 0x00
    signature 0 0 0 0 no 3 0 0 0
    0 0x00 0x00

    Programmer Type : STK500
    Description : Atmel STK500 Version 1.x firmware
    Hardware Version: 2
    Firmware Version: 1.18
    Topcard : Unknown
    Vtarget : 0.0 V
    Varef : 0.0 V
    Oscillator : Off
    SCK period : 0.1 us

    avrdude: AVR device initialized and ready to accept instructions

    Reading | ################################################## | 100% 0.06s

    avrdude: Device signature = 0x000000
    avrdude: Yikes! Invalid device signature.
    avrdude: Expected signature for ATMEGA328P is 1E 95 0F
    avrdude: safemode: lfuse reads as 0
    avrdude: safemode: hfuse reads as 0
    avrdude: safemode: efuse reads as 0
    avrdude: erasing chip
    avrdude: reading input file “ATmegaBOOT_168_atmega328.hex”
    avrdude: input file ATmegaBOOT_168_atmega328.hex auto detected as Intel Hex
    avrdude: writing flash (32670 bytes):

    Writing | ################################################## | 100% 2.59s

    avrdude: 32670 bytes of flash written
    avrdude: verifying flash memory against ATmegaBOOT_168_atmega328.hex:
    avrdude: load data flash data from input file ATmegaBOOT_168_atmega328.hex:
    avrdude: input file ATmegaBOOT_168_atmega328.hex auto detected as Intel Hex
    avrdude: input file ATmegaBOOT_168_atmega328.hex contains 32670 bytes
    avrdude: reading on-chip flash data:

    Reading | ################################################## | 100% 25.34s

    avrdude: verifying …
    avrdude: verification error, first mismatch at byte 0x0000
    0xff != 0x00
    avrdude: verification error; content mismatch

    avrdude: safemode: lfuse reads as 0
    avrdude: safemode: hfuse reads as 0
    avrdude: safemode: efuse reads as 0
    avrdude: safemode: Fuses OK

    avrdude done. Thank you.

    C:\WinAVR-20100110\bin>avrdude -p m328p -P com7 -c stk500v1 -b 19200 -F -v -v -e
    -U flash:w:ATmegaBOOT_168_atmega328.hex

    avrdude: Version 5.10, compiled on Jan 19 2010 at 10:45:23
    Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
    Copyright (c) 2007-2009 Joerg Wunsch

    System wide configuration file is “C:\WinAVR-20100110\bin\avrdude.conf”

    Using Port : com7
    Using Programmer : stk500v1
    Overriding Baud Rate : 19200
    AVR Part : ATMEGA328P
    Chip Erase delay : 9000 us
    PAGEL : PD7
    BS2 : PC2
    RESET disposition : dedicated
    RETRY pulse : SCK
    serial program mode : yes
    parallel program mode : yes
    Timeout : 200
    StabDelay : 100
    CmdexeDelay : 25
    SyncLoops : 32
    ByteDelay : 0
    PollIndex : 3
    PollValue : 0x53
    Memory Detail :

    Block Poll Page
    Polled
    Memory Type Mode Delay Size Indx Paged Size Size #Pages MinW Max
    W ReadBack
    ———– —- —– —– —- —— —— —- —— —– —
    — ———
    eeprom 65 5 4 0 no 1024 4 0 3600 36
    00 0xff 0xff
    flash 65 6 128 0 yes 32768 128 256 4500 45
    00 0xff 0xff
    lfuse 0 0 0 0 no 1 0 0 4500 45
    00 0x00 0x00
    hfuse 0 0 0 0 no 1 0 0 4500 45
    00 0x00 0x00
    efuse 0 0 0 0 no 1 0 0 4500 45
    00 0x00 0x00
    lock 0 0 0 0 no 1 0 0 4500 45
    00 0x00 0x00
    calibration 0 0 0 0 no 1 0 0 0
    0 0x00 0x00
    signature 0 0 0 0 no 3 0 0 0
    0 0x00 0x00

    Programmer Type : STK500
    Description : Atmel STK500 Version 1.x firmware
    Hardware Version: 2
    Firmware Version: 1.18
    Topcard : Unknown
    Vtarget : 0.0 V
    Varef : 0.0 V
    Oscillator : Off
    SCK period : 0.1 us

    avrdude: AVR device initialized and ready to accept instructions

    Reading | ################################################## | 100% 0.06s

    avrdude: Device signature = 0x000000
    avrdude: Yikes! Invalid device signature.
    avrdude: Expected signature for ATMEGA328P is 1E 95 0F
    avrdude: safemode: lfuse reads as 0
    avrdude: safemode: hfuse reads as 0
    avrdude: safemode: efuse reads as 0
    avrdude: erasing chip
    avrdude: reading input file “ATmegaBOOT_168_atmega328.hex”
    avrdude: input file ATmegaBOOT_168_atmega328.hex auto detected as Intel Hex
    avrdude: writing flash (32670 bytes):

    Writing | ################################################## | 100% 2.61s

    avrdude: 32670 bytes of flash written
    avrdude: verifying flash memory against ATmegaBOOT_168_atmega328.hex:
    avrdude: load data flash data from input file ATmegaBOOT_168_atmega328.hex:
    avrdude: input file ATmegaBOOT_168_atmega328.hex auto detected as Intel Hex
    avrdude: input file ATmegaBOOT_168_atmega328.hex contains 32670 bytes
    avrdude: reading on-chip flash data:

    Reading | ################################################## | 100% 25.34s

    avrdude: verifying …
    avrdude: verification error, first mismatch at byte 0x0000
    0xff != 0x00
    avrdude: verification error; content mismatch

    avrdude: safemode: lfuse reads as 0
    avrdude: safemode: hfuse reads as 0
    avrdude: safemode: efuse reads as 0
    avrdude: safemode: Fuses OK

    avrdude done. Thank you.