diff --git a/README.md b/README.md index 5315883..c69d4d5 100644 --- a/README.md +++ b/README.md @@ -1,103 +1,141 @@ # Purpose -This is a custom bootloader for the Commander X16 ATTiny861 based System Management Controller (SMC). +A custom bootloader for the Commander X16 ATtiny861 based System Management Controller (SMC). -The purpose of the bootloader is to make it possible to update the SMC firmware from the Commander X16 without using an external programmer. +The bootloader makes it possible to update the SMC firmware from the Commander X16 without an external programmer. -Firmware data is transmitted from the computer to the SMC over I2C. -# How it works +# How It Works -## SMC memory map +## Firmware Update Process -| Byte address | Size | Description | -|-------------- |-------------| ---------------------------| -| 0x0000-0x1DFF | 7,680 bytes | Firmware area | -| 0x0000 | 2 bytes | Reset vector | -| 0x0012 | 2 bytes | EE_RDY vector | -| 0x1E00-0x1FFF | 512 bytes | Bootloader area | -| 0x1E00 | 2 bytes | Bootloader main vector | -| 0x1E02 | 2 bytes | Start update vector | -| 0x1FFE | 2 bytes | Bootloader version | +The update process is started either by requesting the firmware to call +the bootloader's start update function or by holding down the Reset button +while connecting the computer to power. The latter is called a recovery +update. Read more about that below. +A firmware update program runs on the X16 and sends the new SMC firmware to +the bootloader over I2C. -## SMC reset procedure +The bootloader is responsible for checking the integrity of the transmitted data +and for writing it to the flash memory of the SMC. -On SMC reset the reset vector at address 0x0000 is always executed. -This happens both when mains power is connected to the computer -and when the SMC reset pin #10 is grounded. +The transmission is divided into packets of nine bytes. A packet begins with +eight firmware bytes. The last byte is a checksum, the +2's complement of the sum of the previous eight bytes in the packet. I2C command +offset 0x80 is used to transmit each byte of a packet. -When the bootloader is installed, the reset vector is -remapped and always jumps to the bootloader main vector (0x1E00). +A complete packet must committed using I2C command offset 0x81 before transmission +of the next packet is started. -The bootloader main function checks if the Reset button is being pressed. -If the button is pressed, the computer is powered on and the -bootloader's firmware update process is started. +The update process continues by transmitting and committing packets until the whole +firmware has been received by the bootloader. + +The update program running on the X16 can optionally rewind the target address +to 0x0000 using command 0x84 and use command 0x85 to read one byte at a time from +the SMC flash memory. This can be used to verify the update. + +Finally, the update program must use command 0x82 to reset the SMC. This will +write any remaining buffered data to flash memory and then turn off the computer. + +The SMC can only update the flash memory in whole pages of 64 bytes. The committed +bytes are buffered until there is a full page that can be written to flash memory. + +On receiving the first full page (address 0x0000-0x003f), the bootloader takes +these special actions: + +- Erasing the firmware area of the flash memory (address 0x0000-0x1dff) + +- Moving the firmware's reset vector (address 0x0000) to EE_RDY (address 0x0012) + +- Pointing the reset vector to the bootloader main vector (address 0x1e00) -If the Reset button was not pressed, the bootloader jumps to -the vector stored in EE_RDY (0x0012). The firmware's original -reset vector is always moved to this address when updating -the firmware. +The reason for this is explained in the SMC reset process below. -## Firmware update procedure +## SMC Reset Process and Starting the Bootloader Recovery Update -The update procedure can be started by holding down the Reset -button as described [above](#smc-reset-procedure). +The SMC is reset when first connecting it to power or when +the reset pin (#10) is grounded. On reset, execution always starts from the reset +vector (address 0x0000). -The procedure can also be started by requesting the -firmware to call the start update vector (0x1e02). This is -done through the I2C command 0x8F (Start bootloader). +When the bootloader is installed, the reset vector is set to jump to the bootloader main +function (address 0x1e00), as described above. -While the update procedure is active, firmware data -is transmitted from the CPU to the SMC over I2C as -follows: +The bootloader main function checks if the Reset button is being pressed. -- 8 bytes plus 1 checksum byte are transmitted -using the 0x80 I2C command (Transmit). +If the Reset button is not pressed, the bootloader jumps to +the EE_RDY vector (address 0x0012). The firmware's original +reset vector is moved here during the update process, as described above. -- The transmitted bytes are committed with -the 0x81 I2C command (Commit). +If the button is pressed, the computer is powered on and the +update process is started. + +The update process is usually started by the update program that runs +on the X16 requesting the firmware to call bootloader address +0x1e02. Starting the process by holding down the Reset button +is primarily intended for recovery of an inoperable (bricked) +SMC. + + +## Fail-Safe -- Transmitting and committing data is -repeated for the rest of the firmware. +The bootloader was designed to be fail-safe. In many +cases the bootloader recovery update process can be started even if +the firmware is inoperable (bricked). -- The flash memory is updated in pages of 64 bytes (pages). On every -8th commit, firmware data will actually be written to flash -memory. +The fail-safe was designed especially with these situations in mind: -- Just before writing the first flash memory page, all of -the firmware flash area is erased, starting from the last page. +- Update process interrupted during the firmware erase stage: Firmware +erase starts from the last page. If interrupted during this stage, +the reset vector at address 0x0000 is still unchanged, and a +recovery update is possible. -- Finally, the update program is expected to call -the 0x82 I2C command (Reboot) to reset the SMC and power -off the system. This will also write -any remaining data to flash memory. +- Update process interrupted after the whole firmware has been erased but +before writing any parts of the new firmware to flash memory: When +erasing the flash memory all words are set to byte value 0xffff, +which is interpreted as No Operation (NOP) by the SMC hardware. Execution +starts from the reset vector at 0x0000 and continues until +the first non NOP instruction at 0x1e00, the bootloader main function. +This makes it possible to start the recovery update in this situation. -If the update procedure was started by holding down -the Reset button, the system has no keyboard or mouse -connection. SMCUPDATE-x.x.x.PRG needs to stored as AUTOBOOT.X16 -on the SD card so that it is automatically loaded and run. +- Update process interrupted after writing parts of the new +firmware to flash memory: The first page written to flash memory +holds the reset vector that jumps to the bootloader main function making +it possible to start the recovery update. -# Building the project +## SMC Memory Map + +| Byte address | Size | Description | +|-------------- |-------------| ---------------------------| +| 0x0000-0x1DFF | 7,680 bytes | Firmware area | +| 0x0000 | 2 bytes | Reset vector | +| 0x0012 | 2 bytes | EE_RDY vector | +| 0x1E00-0x1FFF | 512 bytes | Bootloader area | +| 0x1E00 | 2 bytes | Bootloader main vector | +| 0x1E02 | 2 bytes | Start update vector | +| 0x1FFE | 2 bytes | Bootloader version | + -The firmware hex file (x16-smc.ino.hex) is expected to be found at x16-smc/build. You need -to build or download the firmware and store it there. The firmware is -typically built with the Arduino IDE. +# Building the Project Type ```make``` to build the bootloader. Build dependencies: +- make + - AVRA assembler https://github.com/Ro5bert/avra - Python 3 - Python intelhex module, install with pip intelhex +The bootloader is also automatically built by a Github action. + -# Fuse settings +# Fuse Settings The bootloader and the SMC firmware depend on several ATtiny fuse settings as set out below. @@ -108,10 +146,9 @@ The recommended high fuse value is 0xD4. This enables Brown-out Detection at 4.3 Finally, the extended fuse value must be 0xFE to enable self-programming of the flash memory. The bootloader cannot work without this setting. -# Initial programming of the SMC with avrdude +# Initial Programming of the SMC with Avrdude -The initial programming of the SMC must be done with an -external programmer. +The initial programming of the SMC is done with an external programmer. The command line utility avrdude is the recommended tool together with a programmer that is compatible with avrdude. @@ -138,7 +175,7 @@ The -U option performs a memory operation. "-U flash:w:filename:i" writes to fla Please note that some fuse settings may cause the ATtiny861 not to respond. Resetting might require equipment for high voltage programming. Be careful if you choose not to use the recommended values. -The Arduino IDE also uses avrdude in the background. If you have installed the IDE can use it to program the SMC, you may enable verbose output and see what parameters are used by the IDE when it starts avrdude. +The Arduino IDE also uses avrdude in the background. If you have installed the IDE you may enable verbose output and see what parameters are used by the IDE when it starts avrdude. # I2C API @@ -167,7 +204,7 @@ Value | Description 4 | Reserved 5 | Error, overwriting bootloader section -The firmware flash memory are will be erased on the 8th successful commit, just before writing the first 64 bytes to flash memory. +The firmware flash memory is erased on the 8th successful commit, just before writing the first 64 bytes to flash memory. ## Command 0x82 = Reboot (master write)