Skip to content

Commit

Permalink
Bootloader (#306)
Browse files Browse the repository at this point in the history
* bootloader datagram setup

* datagram class complete with test cases

* bootloader progress

* remove crc32 from can_datagram.py + modified unit test

* bootloader datagram setup

* datagram class complete with test cases

* bootloader progress

* complete flash_application code, unit tests required

* add jump application, both flash and jump app needs testing

* test jump application, valid results

* complete unit tests and remove typeerrors for flash app

* add and test multi-board flashing and jumping

* add and test validation static methods

* fix crc bits for can_datagram.py

* add state machine for bootloader

* add BOOTLOADER_FLASH_COMPLETE state for the state machine

* [API/CLI] Redid start and data messaging. Needs new tests. Begun API + Flash devlopment

* [DATA STATES] Seperated first data msg and following messages with arbitration id

* [JUMP APP/START] Wrote brief skeleton functions, needs more error handling

* [ADDED BACK DATA_READY STATE FOR SIMPLICITY]

* [LINKERSCRIPTS + SCON CHANGES FOR APPLICTION/BOOT FLASHING]

* [JUMP APPLICATION ASSEMBLY AND BAREMETAL CAN DRIVER]

* need to fix packet loss in can transmission

* [Formatting]

* BOOTLOADER

* Semi-working

* BOOTLOADER IS WORKING LETS GO

* Major cleanup

* formatingg/linting

* fixed small changes

* formatting

* Build fix

* build change

* build system changes

---------

Co-authored-by: Your Name <[email protected]>
Co-authored-by: Aditya Sen <[email protected]>
  • Loading branch information
3 people authored Sep 29, 2024
1 parent c7862e5 commit 7a0a7ae
Show file tree
Hide file tree
Showing 48 changed files with 2,199 additions and 181 deletions.
15 changes: 13 additions & 2 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,30 @@ AddOption(
help="(x86) Specifies the sanitizer. One of 'asan' for Address sanitizer or 'tsan' for Thread sanitizer. Defaults to none."
)

AddOption(
'--flash',
dest='flash',
type='choice',
choices=('bootloader', 'application', "default"),
default='default',
help="Specifies which application to flash. The bootloader, application or the entire flash bank"
)

PLATFORM = GetOption('platform')
TARGET = GetOption('name')
FLASH_TYPE = GetOption('flash')

###########################################################
# Environment setup
###########################################################

# Retrieve the construction environment from the appropriate platform script
env = SConscript(f'platform/{PLATFORM}.py')
env = SConscript(f'platform/{PLATFORM}.py', exports='FLASH_TYPE')

VARS = {
"PLATFORM": PLATFORM,
"TARGET": TARGET,
"FLASH_TYPE": FLASH_TYPE,
"env": env,
}

Expand Down Expand Up @@ -188,7 +199,7 @@ if PLATFORM == 'arm' and TARGET:

# flash the MCU using openocd
def flash_run_target(target, source, env):
serialData = flash_run(project_bin)
serialData = flash_run(project_bin, FLASH_TYPE)
#while True:
# line: str = serialData.readline().decode("utf-8")
# print(line, end='')
Expand Down
2 changes: 2 additions & 0 deletions can/inc/can_hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#define CAN_HW_DEV_INTERFACE "vcan0"
#endif

#define BOOTLOADER_JUMP_ID 35

typedef enum {
CAN_HW_BUS_STATUS_OK = 0,
CAN_HW_BUS_STATUS_ERROR,
Expand Down
16 changes: 16 additions & 0 deletions can/src/arm/can_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ static bool s_tx_full = false;
// takes 1 for filter_in, 2 for filter_out and default is 0
static int s_can_filter_en = 0;
static uint32_t can_filters[CAN_HW_NUM_FILTER_BANKS];
extern uint32_t _flash_start;

static void prv_add_filter_in(uint8_t filter_num, uint32_t mask, uint32_t filter) {
CAN_FilterInitTypeDef filter_cfg = {
Expand Down Expand Up @@ -213,6 +214,13 @@ void USB_LP_CAN1_RX0_IRQHandler(void) {
if (CAN_GetITStatus(CAN_HW_BASE, CAN_IT_FMP0) == SET) {
CanMessage rx_msg = { 0 };
if (can_hw_receive(&rx_msg.id.raw, (bool *)&rx_msg.extended, &rx_msg.data, &rx_msg.dlc)) {
// Handle bootloader jump request
if (rx_msg.id.raw == BOOTLOADER_JUMP_ID) {
CAN_ClearITPendingBit(CAN_HW_BASE, CAN_IT_FMP0);
__disable_irq();
NVIC_SystemReset();
while(1);
}
// check id against filter out, if matches any filter in filter out then dont push
bool s_filter_id_match = false;
for (int i = 0; i < CAN_HW_NUM_FILTER_BANKS; i++) {
Expand All @@ -238,6 +246,14 @@ void CAN1_RX1_IRQHandler(void) {
if (CAN_GetITStatus(CAN_HW_BASE, CAN_IT_FMP1) == SET) {
CanMessage rx_msg = { 0 };
if (can_hw_receive(&rx_msg.id.raw, (bool *)&rx_msg.extended, &rx_msg.data, &rx_msg.dlc)) {
// Handle bootloader jump request
if (rx_msg.id.raw == BOOTLOADER_JUMP_ID) {
CAN_ClearITPendingBit(CAN_HW_BASE, CAN_IT_FMP1);
__disable_irq();
NVIC_SystemReset();
while(1);
}

// check id against filter out, if matches any filter in filter out then dont push
bool s_filter_id_match = false;
for (int i = 0; i < CAN_HW_NUM_FILTER_BANKS; i++) {
Expand Down
7 changes: 5 additions & 2 deletions libraries/CMSIS/src/system_stm32f10x.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,11 @@
/*!< Uncomment the following line if you need to relocate your vector Table in
Internal SRAM. */
/* #define VECT_TAB_SRAM */
#define VECT_TAB_OFFSET 0x0 /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */

extern uint32_t _bootloader_size;

#define VECT_TAB_OFFSET ((uint32_t)(&_bootloader_size)) /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */


/**
Expand Down
58 changes: 58 additions & 0 deletions libraries/codegen/boards/bootloader.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Message Definitions in plaintext are on the wiki at:
# https://uwmidsun.atlassian.net/l/cp/Pxn8Xhm8
#
# If you are making changes to this file please update the corresponding entry
# on the wiki. If you need to add a new message use a reasonable
# reserved ID. The higher ID the lower the priority. Generally
# - 0-13: Critical messages (have ACK)
# - 14-30: Actionable messages (trigger a change in another system)
# - 30-63: Data messages (usually not actionable by an onboard device)

---
Messages:
bootloader_start:
id: 30
target:
bootloader:
watchdog: 0
critical: true
signals:
data0:
length: 8
data1:
length: 8
data2:
length: 8
data3:
length: 8
data4:
length: 8
data5:
length: 8
data6:
length: 8
data7:
length: 8
bootloader_data:
id: 31
target:
bootloader:
watchdog: 0
critical: true
signals:
data0:
length: 8
data1:
length: 8
data2:
length: 8
data3:
length: 8
data4:
length: 8
data5:
length: 8
data6:
length: 8
data7:
length: 8
46 changes: 28 additions & 18 deletions platform/arm.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
Import ('FLASH_TYPE')

PLATFORM_DIR = os.getcwd()

Expand Down Expand Up @@ -44,31 +45,40 @@
'--specs=nano.specs',
]

link_flags = [
'-L{}/linker_scripts'.format(PLATFORM_DIR),
'-Tstm32f1_default.ld',
]
def get_link_flags(flash_type='default'):
linker_scripts = {
'default': 'stm32f1_default.ld',
'bootloader': 'stm32f1_bootloader.ld',
'application': 'stm32f1_application.ld'
}
script = linker_scripts.get(flash_type, linker_scripts['default'])
return [
'-L{}/linker_scripts'.format(PLATFORM_DIR),
'-T{}'.format(script),
]

arm_env = Environment(
ENV = { 'PATH': os.environ['PATH'] },
def create_arm_env(flash_type='default'):
return Environment(
ENV = { 'PATH': os.environ['PATH'] },

CC=compiler,
CCFLAGS=cflags + arch_cflags + define_flags,
CPPPATH=[],
CC=compiler,
CCFLAGS=cflags + arch_cflags + define_flags,
CPPPATH=[],

AS=compiler,
ASFLAGS=['-c'] + cflags + arch_cflags + define_flags,

LINK=compiler,
LINKFLAGS=cflags + arch_cflags + link_flags,
AS=compiler,
ASFLAGS=['-c'] + cflags + arch_cflags + define_flags,
LINK=compiler,
LINKFLAGS=cflags + arch_cflags + get_link_flags(flash_type),

AR=ar,
RANLIB=ranlib,
AR=ar,
RANLIB=ranlib,

LIBS=['m'],
)
LIBS=['m'],
)

bin_builder = Builder(action='{} -O binary $SOURCE $TARGET'.format(objcopy))
arm_env = create_arm_env(FLASH_TYPE)
arm_env.Append(BUILDERS={'Bin': bin_builder})

Return('arm_env')
29 changes: 29 additions & 0 deletions platform/linker_scripts/bootloader/memory_sections.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
ENTRY(Reset_Handler)

_bootloader_size = 11K;

_flash_start = 0x08000000;
_flash_size = 64K;
_flash_page_size = 1K;

_ram_start = 0x20000000;
_ram_size = 20K;

_bootloader_start = _flash_start;
_application_start = _bootloader_start + _bootloader_size;

_application_size = _flash_size - (_application_start - _flash_start);

_vector_table_size = 0xEC; /* used for relocating the vector table to RAM for the application */

/* TODO: explicitly set aside the last page for calib */

MEMORY
{
BOOTLOADER (rx) : ORIGIN = _flash_start, LENGTH = _bootloader_size
APPLICATION (rx) : ORIGIN = _application_start, LENGTH = _application_size
RAM (rwx) : ORIGIN = _ram_start, LENGTH = _ram_size
}

/* highest address of the user mode stack */
_estack = _ram_start + _ram_size;
141 changes: 141 additions & 0 deletions platform/linker_scripts/bootloader/sections_flash_application.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
Linker subscript for section definitions for the bootloaded application.
See https://uwmidsun.atlassian.net/l/c/mHxmqjvn for more information.
*/

SECTIONS
{
/* The vector table stored at .isr_vector must end up at the beginning of the application flash.
This isn't at address 0, but the bootloader will set the vector table here when jumping to the
application's reset handler. */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >APPLICATION

/* application program code is stored in the .text section, which goes to application flash */
.text :
{
. = ALIGN(4);
*(.hardfault) /* Hardfault handlers */
*(.text) /* normal code */
*(.text.*) /* -ffunction-sections code */
*(.rodata) /* read-only data (constants) */
*(.rodata*) /* -fdata-sections read only data */
*(.glue_7) /* TBD - needed ? */
*(.glue_7t) /* TBD - needed ? */

/* Necessary KEEP sections (see http://sourceware.org/ml/newlib/2005/msg00255.html) */
KEEP (*(.init))
KEEP (*(.fini))

. = ALIGN(4);
_etext = .;
/* This is used by the startup in order to initialize the .data section */
_sidata = _etext;
} >APPLICATION

/* Dummy section to provide an offset for the vector table at the start of RAM.
The bootloader relocates the vector table to the start of RAM, so the .data section needs to start
after the vector table. This phony section increments the RAM counter to accomplish this. */
.data_phony : AT ( _sidata )
{
. += _vector_table_size;
} >RAM

/* This is the initialized data section
The program executes knowing that the data is in the RAM
but the loader puts the initial values in the APPLICATION flash.
It is one task of the startup to copy the initial values from flash to RAM. */
.data : AT ( _sidata )
{
. = ALIGN(4);
/* This is used by the startup in order to initialize the .data secion */
_sdata = .;
_data = .;

*(.data)
*(.data.*)
*(.RAMtext)

. = ALIGN(4);
/* This is used by the startup in order to initialize the .data secion */
_edata = .;
} >RAM

/* This is the uninitialized data section */
.bss :
{
. = ALIGN(4);
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .;
__bss_start__ = .;
_bss = .;
*(.bss)
*(.bss.*) /* patched by elias - allows the use of -fdata-sections */
*(COMMON)

. = ALIGN(4);
/* This is used by the startup in order to initialize the .bss secion */
_ebss = . ;
__bss_end__ = .;
} >RAM

.eh_frame :
{
. = ALIGN(4);
KEEP (*(.eh_frame))
} >RAM

PROVIDE ( end = _ebss );
PROVIDE ( _end = _ebss );

__exidx_start = .;
__exidx_end = .;

/* after that it's only debugging information. */

/* remove the debugging information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}

/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
}
Loading

0 comments on commit 7a0a7ae

Please sign in to comment.