Add Bootloader
This commit is contained in:
parent
40422d883d
commit
bd1cdfe5b5
237
src/Bootloader.cc
Normal file
237
src/Bootloader.cc
Normal 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
91
src/Bootloader.h
Normal 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
|
Loading…
Reference in New Issue
Block a user