[Solved] Conditional bootloading on EEPROM value project need some help

I have an open source datalogger I designed for physics labs. It has the stock ATMEGA1284P optiboot bootloader installed with a firmware that displays and logs data from a number of sensors. I wonder, what if some curious students start uploading Arduino code to it. I'd like them to explore but knowing only a little is dangerous. They could fry the device before they learn how to hack it. So I wanted to have some control over who gets to upload sketches (teachers and maybe some advanced students).

I thought about a physical jumper (say reset pin) to enable/disable uploading sketches. I thought that was silly. Any monkey with fine motor skills can defeat that :D.

What about a modified bootloader, so the bootloader will look into the EEPROM for enable/disable bootloading? I've never messed with bootloader code before (only changed PID and VID in leo's bootloader).

Do you think it is feasible to fit a conditional statement with EEPROM read function in optiboot? Maybe reset that EEPROM content to disable after bootloading?

FYI, the 1284P has a 1024KB bootloader size so there is enough space for that.

1284P has several bootloader sizes:
256 bytes
512 bytes
1024 bytes
2048 bytes

So some room to grow if needed.

It seems pretty straightforward to use EEPROM in a bootloader but if you want an example of a bootloader that does this take a look at the Ariadne source: GitHub - codebndr/Ariadne-Bootloader: A little less unfinished TFTP bootloader for Arduino Ethernet or Arduino with Ethernet Shield It reads the network configuration settings from EEPROM.

Thanks pert. I was indeed looking for some sample bootloader. Will do my study on this.

CR, I thought the sizes start from 512 words (1024 bytes) and you can have up to 8192 bytes.

1284 bootloader size.PNG

Oops - missed by one part. Looks like I had info from 644 table instead of 1284 table.
Yes, 1K byte, 2K, 4K, 8K.

Done that myself (read info from 324 table) :smiley:

Just read the official optiboot code

Line 502 might be a good spot for the conditional. Read eeprom, if bootload is disabled, then set watchdog to a short time out and do a while loop. Otherwise do the one second watchdog.

Do you think it is ok to use eeprom library from arduino or should I learn the avr eeprom library? The ethernet bootloader is using avr's library. I'll give this a try and report back.

So I started modding the bootloader. My first attempt is to mod the optiboot.c that comes with 1284P mod. It is a bit old, 4.5 version but I thought I didn't have to add any 1284P-specific #def so that was a plus. Here is the appStart function that I thought was responsible for starting the sketch:

void appStart() {
  watchdogConfig(WATCHDOG_OFF);
  __asm__ __volatile__ (
#ifdef VIRTUAL_BOOT_PARTITION
    // Jump to WDT vector
    "ldi r30,4\n"
    "clr r31\n"
#else
    // Jump to RST vector
    "clr r30\n"
    "clr r31\n"
#endif
    "ijmp\n"
  );
}

I don't understand virtual boot partition. Are we using that at all? If not, the jump to rst vector commands are now clear to me. They clear a couple of registers and did an ijmp (indirect jmp according to avr assembler reference).

My understanding of the bootloading process must be incomplete so please give me some critique:

The fuse bytes are set to use a certain bootloader size and enable bootloader. The bootloader is in the NRWW memory. Anytime the MCU is reset, it runs the bootloader.

The bootloader first reads the source for reset. If it is external source, it then will monitor the serial port for new sketch. It also sets the WDT to 1 second so if no valid commands are received, it will reset itself and start over.

If the reset is not from an external source, it calls appStart() to jump to the existing sketch. The appStart() works like this: it resets r30 and r31 (i.e. register z), then will do indirect jmp, meaning loading the code from FLASH address 0, which is the location of the sketch. The sketch begins. I think the reason the bootloader wants to reset in case of no new sketch or internal reset sources is that it wants all the hardware to properly reset, instead of just jumping to 0000.

So if I want to add an additional condition for EEPROM check, I should place it where the bootloader sets WDT to 1 second. Basically it will determine whether the condition is met (EEPROM has bootloading enabled value), to decide whether to proceed or to set WDT to 16MS and run a while(1) loop.

I hope what I just wrote is mostly correct. Will get back to the thread with some results.

I'd PM westfw or NickGammon, they know a lot more about coding than I do.

Thanks CR. It seems that the new arduino IDE 1.6.5 r5 no longer comes with utilities such as make.exe LOL
I'll find out what to use first. I'm almost there.

Some just posted using one from 1.0.5.x.x

Oops, never mind - that was you!

CrossRoads:
Some just posted using one from 1.0.5.x.x

Oops, never mind - that was you!

Late afternoon :smiley: I found out that the zip file size shrinks from 210MB to 130MB between 1.6.1 and 1.6.2. I'm downloading 1.6.0 to find out if they have it.

OK, 1.6.0 has no make or any utilities.
1.0.6 does have it. Version 3.8.1 gcc 4.3.2. Will continue to look for the utilities with the correct version.

OK, got it working.
Logic:

  1. Check if the value stored in an eeprom location matches the value bl_enabled. If it does, continue doing what the bootloader does.
  2. If the stored value isn't bl_enabled, set WDT to 16ms and run an infinite loop to wait for reset.

Steps to build a bootloader:

  1. Download Arduino IDE 1.0.6, the last IDE version with make.exe included.
  2. Copy the 1284P's optiboot folder to arduino's own optiboot folder (rename the existing optiboot folder) at arduino/hardware/arduino/bootloaders/optiboot
  3. Include the path arduino/hardware/tools/avr/utils in your environment variable
  4. Start a command prompt and change folder to the optiboot folder, then type in command make atmega1284 ENV=arduino OS=windows
  5. Once make completes, you will have a new bootloader called optiboot_atmega1284p.hex
  6. The bootloader contains a line at address 0, with major and minor version numbers. If you are using Nick's hex programmer, it will make the program think there is no bootloader. So make sure to set the HIGH FUSE to the value that enables bootloader, such as 0xDE.
  7. Remove this first line if you wish to combine the bootloader with another sketch. Remove the last line of the compiled sketch (end of file) and copy paste bootloader to the end of the compiled sketch and save it. Repeat the last step to load it to the MCU.

I added a submenu in my open source data logger to toggle the eeprom value between enabled and disabled. Tests are all green.
Code addition:

#if defined (__AVR_ATmega1284P__)
#define OSPL_bl_enable_eeprom_address 4095
#else
#define OSPL_bl_enable_eeprom_address 511
#endif	
#define OSPL_bl_enabled 1
#define OSPL_bl_disabled 255

Modification:

  // Find out whether OSPL bootloading is enabled
  if((eeprom_read_byte(OSPL_bl_enable_eeprom_address))==OSPL_bl_enabled)
  {
    watchdogConfig(WATCHDOG_1S);
  }
  else
  {
    watchdogConfig(WATCHDOG_16MS);
	while(1){}
  }

Only the watchdogConfig(WATCHDOG_1S); was the original line.

Cool! Got this topic bookmarked for future use :slight_smile:

CrossRoads:
Cool! Got this topic bookmarked for future use :slight_smile:

Glad it may be useful to you! Took me several hours to figure out how to "make.exe" the bootloader. The actual code modification took minutes once I understood how optiboot works. WestFW did a good job explaining it:

I can't imagine getting this done without the internet :smiley: Had to search how to use make, reviewed intel hex format (yet again), read about registers r30 and r31, indirect jump, etc.