Add Bootloader

This commit is contained in:
Thomas Klaehn 2021-08-13 09:00:05 +02:00
parent 40422d883d
commit bd1cdfe5b5
2 changed files with 328 additions and 0 deletions

237
src/Bootloader.cc Normal file
View File

@ -0,0 +1,237 @@
#include <unistd.h>
#include <assert.h>
#include "Bootloader.h"
Bootloader::Bootloader(Uart &uart) : uart(uart)
{
syn();
get();
get_chip_id();
get_flash_memory_size();
}
void Bootloader::syn()
{
unsigned char buffer = 0x7f;
uart.transmit(&buffer, 1);
int rec = uart.receive(&buffer, 1);
if ((rec >= 1) && ((buffer == ACK) || (buffer == NAK)))
{
is_sync = true;
}
}
void Bootloader::get()
{
unsigned char buffer[0xff];
send_command(commands.get);
usleep(10000);
int rec = uart.receive(buffer, sizeof(buffer));
if ((rec == 15) && ((buffer[0] == ACK) && (buffer[14] == ACK)))
{
chip.protocol_version_major = (buffer[2] & 0xf0) >> 4;
chip.protocol_version_minor = buffer[2] & 0x0f;
commands.get = buffer[3];
commands.get_version_and_read_protection_status = buffer[4];
commands.get_id = buffer[5];
commands.read_memory = buffer[6];
commands.go = buffer[7];
commands.write_memory = buffer[8];
commands.erase = buffer[9];
commands.write_protect = buffer[10];
commands.write_unprotect = buffer[11];
commands.readout_protect = buffer[12];
commands.readout_unprotect = buffer[13];
}
}
void Bootloader::get_chip_id()
{
unsigned char buffer[0xff];
send_command(commands.get_id);
usleep(10000);
int rec = uart.receive(buffer, sizeof(buffer));
if ((rec == 5) && ((buffer[0] == ACK) && (buffer[4] == ACK)))
{
chip.id = (buffer[2] << 8) + buffer[3];
if (chip.id == SUPPORTED_DEVICE_ID)
{
is_supported = true;
}
}
}
void Bootloader::get_flash_memory_size()
{
unsigned char buffer[2];
read_memory(FLASH_MEMORY_SIZE_DATA_REGISTER_ADDRESS, buffer, sizeof(buffer));
chip.flash_size = ((buffer[1] << 8) + buffer[0]) * 1024;
}
bool Bootloader::read_memory(uint32_t start_address, uint8_t *mem, uint16_t size)
{
if (size > 256)
{
return false;
}
bool ret = false;
unsigned char buffer[0x2];
send_command(commands.read_memory);
if (wait_for_ack())
{
send_address(start_address);
if (wait_for_ack())
{
buffer[0] = size - 1;
buffer[1] = buffer[0] ^ 0xff;
uart.transmit(buffer, 2);
if(wait_for_ack())
{
unsigned char* wptr = mem;
int rec = uart.receive(wptr, size);
int to_receice = size - rec;
while(to_receice > 0) {
wptr += rec;
assert(wptr <= mem + size);
rec = uart.receive(wptr, to_receice);
to_receice -= rec;
}
if(to_receice == 0) {
ret = true;
}
}
}
}
return ret;
}
bool Bootloader::write_memory(uint32_t start_address, uint8_t *mem, uint16_t size)
{
if (size > 256)
{
return false;
}
bool ret = false;
unsigned char buffer[0x101];
send_command(commands.write_memory);
if (wait_for_ack())
{
send_address(start_address);
if (wait_for_ack())
{
uint16_t len = size;
if (len % 4)
{
len = len + (4 - len % 4);
}
buffer[0] = (uint8_t)(len - 1);
memcpy(&buffer[1], mem, size);
buffer[len + 1] = 0;
for (uint16_t i = 0; i <= len; i++)
{
buffer[len + 1] ^= buffer[i];
}
uart.transmit(buffer, len + 2);
if (wait_for_ack())
{
ret = true;
}
}
}
return ret;
}
bool Bootloader::full_flash_erase()
{
bool ret = false;
unsigned char buffer[0x03];
send_command(commands.erase);
if (wait_for_ack())
{
buffer[0] = 0xff; // full flash erase
buffer[1] = 0xff; // full flash erase
buffer[2] = buffer[0] ^ buffer[1];
uart.transmit(buffer, 3);
if (wait_for_ack())
{
ret = true;
}
}
return ret;
}
bool Bootloader::go(uint32_t start_address)
{
bool ret = false;
unsigned char buffer[0x101];
send_command(commands.go);
usleep(10000);
int rec = uart.receive(buffer, sizeof(buffer));
if ((rec == 1) && (buffer[0] == ACK))
{
send_address(start_address);
if (wait_for_ack())
{
ret = true;
}
}
return ret;
}
void Bootloader::send_command(uint8_t command)
{
uint8_t buffer[2];
buffer[0] = command;
buffer[1] = buffer[0] ^ 0xff;
uart.transmit(buffer, 2);
}
void Bootloader::send_address(uint32_t address)
{
uint8_t buffer[5];
buffer[0] = (address >> 24) & 0xff;
buffer[1] = (address >> 16) & 0xff;
buffer[2] = (address >> 8) & 0xff;
buffer[3] = address & 0xff;
buffer[4] = buffer[0] ^ buffer[1] ^ buffer[2] ^ buffer[3];
uart.transmit(buffer, 5);
}
bool Bootloader::wait_for_ack()
{
unsigned char rx;
for (uint32_t i = 0; i < 10000; i++)
{
int rec = uart.receive(&rx, 1);
if (rec > 0)
{
if (rx == ACK)
{
return true;
}
else if (rx == NAK)
{
return false;
}
}
}
return false;
}
uint16_t Bootloader::chip_id()
{
return chip.id;
}
uint32_t Bootloader::flash_size()
{
return chip.flash_size;
}
bool Bootloader::chip_is_supported()
{
return is_supported;
}

91
src/Bootloader.h Normal file
View File

@ -0,0 +1,91 @@
#ifndef BOOTLOADER_H
#define BOOTLOADER_H
#include <cstdint>
#include "Uart.h"
class Bootloader
{
public:
Bootloader(Uart &uart);
uint16_t chip_id();
uint32_t flash_size();
bool chip_is_supported();
bool read_memory(uint32_t start_address, uint8_t *mem, uint16_t size);
bool write_memory(uint32_t start_address, uint8_t *mem, uint16_t size);
bool full_flash_erase();
bool go(uint32_t start_address);
const char *SUPPORTED_DEVICE_NAME = "STM32G03xxx/04xxx";
const uint32_t MAIN_FLASH_START_ADDRESS = 0x08000000;
struct ChipData
{
uint16_t id;
uint8_t protocol_version_major;
uint8_t protocol_version_minor;
uint32_t flash_size;
};
struct Commands
{
uint8_t get;
uint8_t get_version_and_read_protection_status;
uint8_t get_id;
uint8_t read_memory;
uint8_t go;
uint8_t write_memory;
uint8_t erase;
uint8_t write_protect;
uint8_t write_unprotect;
uint8_t readout_protect;
uint8_t readout_unprotect;
};
private:
void syn();
void get();
void get_chip_id();
void get_flash_memory_size();
void send_command(uint8_t command);
void send_address(uint32_t address);
bool wait_for_ack();
const uint32_t FLASH_MEMORY_SIZE_DATA_REGISTER_ADDRESS = 0x1fff75e0;
const uint16_t SUPPORTED_DEVICE_ID = 0x466;
const uint8_t ACK = 0x79;
const uint8_t NAK = 0x1f;
const struct Commands default_commands = {
.get = 0x00,
.get_version_and_read_protection_status = 0x01,
.get_id = 0x02,
.read_memory = 0x11,
.go = 0x21,
.write_memory = 0x31,
.erase = 0x43,
.write_protect = 0x63,
.write_unprotect = 0x73,
.readout_protect = 0x82,
.readout_unprotect = 0x92,
};
ChipData chip = {
.id = 0,
.protocol_version_major = 0,
.protocol_version_minor = 0,
.flash_size = 0,
};
Uart &uart;
Commands commands = default_commands;
bool is_sync = false;
bool is_supported = false;
};
#endif