diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md
index df784e3..3ef6d23 100644
--- a/DOCUMENTATION.md
+++ b/DOCUMENTATION.md
@@ -15,6 +15,7 @@ If you are interested in using and understanding TAB, refer to this document.
* [Bootlaoder Erase](#bootloader-erase)
* [Bootloader Write Page](#bootloader-write-page)
* [Bootloader Write Page Addr32](#bootloader-write-page-addr32)
+ * [Bootloader Jump](#bootloader-jump)
* [Protocol](#protocol): TAB protocol
* [License](#license)
@@ -261,6 +262,24 @@ of the board using the address provided.
* Addr Byte4 is the LSByte
* Page Data has 128 bytes.
+### Bootloader Jump
+
+The command instructs the bootloader to jump to a different address in memory
+* Name: `bootloader_jump`
+* Required parameters: None
+* Optional parameters: None
+* Reply:
+ * If the bootloader is active and successfully performs the jump:
+ `bootloader_ack` with the JUMP payload
+ * If the bootloader is active and fails to perform the jump:
+ `bootloader_nack`
+ * Otherwise: `common_nack`
+
+**Header**
+
+| Start Byte 0 | Start Byte 1 | Remaining Bytes | HW ID LSByte | HW ID MSByte | MSG ID LSByte | MSG ID MSByte | Route Nibbles | Opcode |
+| ------------ | ------------ | --------------- | ------------ | ------------ | ------------- | ------------- | ------------- | ------ |
+| 0x22 | 0x69 | 0x06 | 0xHH | 0xHH | 0xHH | 0xHH | 0xSD | 0x0b |
## Protocol
diff --git a/c-examples/cdh-monolithic/cdh_monolithic.c b/c-examples/cdh-monolithic/cdh_monolithic.c
index ded7324..203bd2d 100644
--- a/c-examples/cdh-monolithic/cdh_monolithic.c
+++ b/c-examples/cdh-monolithic/cdh_monolithic.c
@@ -2,7 +2,7 @@
// TAB C Example CDH Monolithic
//
// Written by Bradley Denby
-// Other contributors: None
+// Other contributors: Chad Taylor
//
// See the top-level LICENSE file for the license.
@@ -16,6 +16,12 @@
// TAB header
#include // TAB header
+//// in_bootloader is an extern variable read by bootloader_running
+int in_bootloader;
+
+//// app_jump_pending is an extern variable modified in write_reply
+int app_jump_pending;
+
// Main
int main(void) {
// MCU initialization
@@ -26,11 +32,25 @@ int main(void) {
clear_rx_cmd_buff(&rx_cmd_buff);
tx_cmd_buff_t tx_cmd_buff = {.size=CMD_MAX_LEN};
clear_tx_cmd_buff(&tx_cmd_buff);
+ in_bootloader = 1;
+ app_jump_pending = 0;
// TAB loop
while(1) {
- rx_usart1(&rx_cmd_buff); // Collect command bytes
- reply(&rx_cmd_buff, &tx_cmd_buff); // Command reply logic
- tx_usart1(&tx_cmd_buff); // Send a response if any
+ if(!app_jump_pending) {
+ rx_usart1(&rx_cmd_buff); // Collect command bytes
+ reply(&rx_cmd_buff, &tx_cmd_buff); // Command reply logic
+ tx_usart1(&tx_cmd_buff); // Send a response if any
+ } else { // Jump triggered
+ while(!tx_cmd_buff.empty) { // If jumping to user app,
+ tx_usart1(&tx_cmd_buff); // finish sending response if any
+ }
+ for(size_t i=0; i<4000000; i++) { // Wait for UART TX FIFO to flush
+ __asm__ volatile("nop");
+ }
+ app_jump_pending = 0; // Housekeeping
+ in_bootloader = 0;
+ bl_jump_to_app(); // Jump
+ }
}
// Should never reach this point
return 0;
diff --git a/c-examples/cdh-monolithic/support/cdh.c b/c-examples/cdh-monolithic/support/cdh.c
index d700c83..6fd6ae2 100644
--- a/c-examples/cdh-monolithic/support/cdh.c
+++ b/c-examples/cdh-monolithic/support/cdh.c
@@ -14,6 +14,7 @@
#include // used in init_gpio
#include // used in init_clock, init_rtc
#include // used in init_uart
+#include // SCB_VTOR
// Board-specific header
#include // Header file
@@ -21,6 +22,10 @@
// TAB header
#include // TAOLST protocol macros, typedefs, fnctns
+// Variables
+extern int in_bootloader; // Used in bootloader main to indicate MCU state
+extern int app_jump_pending; // Used in bootloader main to signal jump to app
+
// Functions required by TAB
// This example implementation of handle_common_data checks whether the bytes
@@ -132,9 +137,46 @@ int handle_bootloader_write_page_addr32(rx_cmd_buff_t* rx_cmd_buff){
}
}
-// This example implementation of bootloader_active always returns true
+// This example implementation of bl_check_app checks whether the jump address
+// is valid or not
+int bl_check_app(void) {
+ // Does the first four bytes of the application represent the initialization
+ // location of a stack pointer within the boundaries of the RAM?
+ return (((*(uint32_t*)APP_ADDR)-SRAM1_BASE) <= SRAM1_SIZE);
+}
+
+// This example implementation of bl_jump_to_app jumps to a hardcoded
+// address in memory called APP_ADDR
+void bl_jump_to_app(void) {
+ // The first 4 bytes hold the stack address, so jump address is after that
+ uint32_t jump_addr =
+ *(volatile uint32_t*)(APP_ADDR+((uint32_t)0x00000004U));
+ // Create a jump() function
+ void (*jump)(void) = (void (*)(void))jump_addr;
+ // Set the vector table
+ SCB_VTOR = APP_ADDR;
+ // Set the master stack pointer
+ __asm__ volatile("msr msp, %0"::"g" (*(volatile uint32_t*)APP_ADDR));
+ // Jump to the application
+ jump();
+}
+
+// This example implementation of handle_bootloader_jump sets app_jump_pending
+// to 1 to trigger a jump after checking for a valid app address
+int handle_bootloader_jump(void){
+ if (bl_check_app()) {
+ app_jump_pending = 1;
+ return 1;
+ } else { // Something wrong, abort jump
+ return 0;
+ }
+
+}
+
+// This example implementation of bootloader_active always returns whether the
+// board is in bootloader mode or not
int bootloader_active(void) {
- return 1;
+ return in_bootloader;
}
// Board initialization functions
diff --git a/c-examples/cdh-monolithic/support/cdh.h b/c-examples/cdh-monolithic/support/cdh.h
index d4fbcc7..7988bf7 100644
--- a/c-examples/cdh-monolithic/support/cdh.h
+++ b/c-examples/cdh-monolithic/support/cdh.h
@@ -19,12 +19,19 @@
//// Application start address
#define APP_ADDR ((uint32_t)0x08008000U)
+//// SRAM1 start address
+#define SRAM1_BASE ((uint32_t)0x20000000U)
+
+//// SRAM1 size
+#define SRAM1_SIZE ((uint32_t)0x00040000U)
+
// Functions required by TAB
int handle_common_data(common_data_t common_data_buff_i);
int handle_bootloader_erase(void);
int handle_bootloader_write_page(rx_cmd_buff_t* rx_cmd_buff);
int handle_bootloader_write_page_addr32(rx_cmd_buff_t* rx_cmd_buff);
+int handle_bootloader_jump(void);
int bootloader_active(void);
// Board initialization functions
@@ -32,6 +39,11 @@ int bootloader_active(void);
void init_clock(void);
void init_uart(void);
+// Board jump functions
+
+int bl_check_app(void);
+void bl_jump_to_app(void);
+
// Feature functions
void rx_usart1(rx_cmd_buff_t* rx_cmd_buff_o);
diff --git a/c-implementation/tab.c b/c-implementation/tab.c
index 5994323..e1f671b 100644
--- a/c-implementation/tab.c
+++ b/c-implementation/tab.c
@@ -19,6 +19,7 @@ extern int handle_common_data(common_data_t common_data_buff_i);
extern int handle_bootloader_erase(void);
extern int handle_bootloader_write_page(rx_cmd_buff_t* rx_cmd_buff);
extern int handle_bootloader_write_page_addr32(rx_cmd_buff_t* rx_cmd_buff);
+extern int handle_bootloader_jump(void);
extern int bootloader_active(void);
// Helper functions
@@ -248,6 +249,22 @@ void write_reply(rx_cmd_buff_t* rx_cmd_buff_o, tx_cmd_buff_t* tx_cmd_buff_o) {
tx_cmd_buff_o->data[OPCODE_INDEX] = COMMON_NACK_OPCODE;
}
break;
+ case BOOTLOADER_JUMP_OPCODE:
+ if(bootloader_active()) {
+ success = handle_bootloader_jump();
+ if(success) {
+ tx_cmd_buff_o->data[MSG_LEN_INDEX] = ((uint8_t)0x07);
+ tx_cmd_buff_o->data[OPCODE_INDEX] = BOOTLOADER_ACK_OPCODE;
+ tx_cmd_buff_o->data[PLD_START_INDEX] = BOOTLOADER_ACK_REASON_JUMP;
+ } else {
+ tx_cmd_buff_o->data[MSG_LEN_INDEX] = ((uint8_t)0x06);
+ tx_cmd_buff_o->data[OPCODE_INDEX] = BOOTLOADER_NACK_OPCODE;
+ }
+ } else {
+ tx_cmd_buff_o->data[MSG_LEN_INDEX] = ((uint8_t)0x06);
+ tx_cmd_buff_o->data[OPCODE_INDEX] = COMMON_NACK_OPCODE;
+ }
+ break;
default:
break;
}
diff --git a/c-implementation/tab.h b/c-implementation/tab.h
index 127e62e..fb4646d 100644
--- a/c-implementation/tab.h
+++ b/c-implementation/tab.h
@@ -32,6 +32,7 @@
#define BOOTLOADER_ERASE_OPCODE ((uint8_t)0x0c)
#define BOOTLOADER_WRITE_PAGE_OPCODE ((uint8_t)0x02)
#define BOOTLOADER_WRITE_PAGE_ADDR32_OPCODE ((uint8_t)0x20)
+#define BOOTLOADER_JUMP_OPCODE ((uint8_t)0x0b)
//// BOOTLOADER_ACK reasons
#define BOOTLOADER_ACK_REASON_PONG ((uint8_t)0x00)
diff --git a/python-examples/tx/tx_example.py b/python-examples/tx/tx_example.py
index f82161d..ffee661 100644
--- a/python-examples/tx/tx_example.py
+++ b/python-examples/tx/tx_example.py
@@ -215,8 +215,7 @@
#10. Test Bootloader Write Page with expected reply of Bootloader Ack
# with Page Number reason
-print("Bootloader Write Page")
-cmd = TxCmd(BOOTLOADER_WRITE_PAGE_OPCODE, HWID, msgid, SRC, DST)
+cmd = TxCmd(BOOTLOADER_WRITE_PAGE_OPCODE, HWID, msgid, GND, CDH)
dummy_page_num = 1
dummy_page = [0] * 128
cmd.bootloader_write_page(page_number=dummy_page_num, page_data=dummy_page)
@@ -238,7 +237,7 @@
#11. Test Bootloader Write Page Addr32 with expected reply of
# Bootloader Ack with Address reason
-cmd = TxCmd(BOOTLOADER_WRITE_PAGE_ADDR32_OPCODE, HWID, msgid, SRC, DST)
+cmd = TxCmd(BOOTLOADER_WRITE_PAGE_ADDR32_OPCODE, HWID, msgid, GND, CDH)
page_num = 0
addr_write = START_ADDR + page_num * BYTES_PER_CMD
dummy_page = [0] * 128
@@ -256,4 +255,23 @@
print('reply: '+str(rx_cmd_buff)+'\n')
cmd.clear()
rx_cmd_buff.clear()
-msgid += 1
\ No newline at end of file
+msgid += 1
+
+#11. Test Bootloader Jump with expected reply of
+# Bootloader Nack
+cmd = TxCmd(BOOTLOADER_JUMP_OPCODE, HWID, msgid, GND, CDH)
+byte_i = 0
+while rx_cmd_buff.state != RxCmdBuffState.COMPLETE:
+ if byte_i < cmd.get_byte_count():
+ serial_port.write(cmd.data[byte_i].to_bytes(1, byteorder='big'))
+ byte_i += 1
+ if serial_port.in_waiting>0:
+ bytes = serial_port.read(1)
+ for b in bytes:
+ rx_cmd_buff.append_byte(b)
+print('txcmd: '+str(cmd))
+print('reply: '+str(rx_cmd_buff)+'\n')
+cmd.clear()
+rx_cmd_buff.clear()
+msgid += 1
+time.sleep(1.0)
\ No newline at end of file
diff --git a/python-implementation/tab.py b/python-implementation/tab.py
index 575b7cb..8d3a169 100644
--- a/python-implementation/tab.py
+++ b/python-implementation/tab.py
@@ -29,6 +29,7 @@
BOOTLOADER_ERASE_OPCODE = 0x0c
BOOTLOADER_WRITE_PAGE_OPCODE = 0x02
BOOTLOADER_WRITE_PAGE_ADDR32_OPCODE = 0x20
+BOOTLOADER_JUMP_OPCODE = 0x0b
## Route Nibble IDs
GND = 0x00
@@ -229,6 +230,9 @@ def generate_reply(self, rx_cmd_buff):
elif rx_cmd_buff.data[OPCODE_INDEX] == BOOTLOADER_WRITE_PAGE_ADDR32_OPCODE:
self.data[MSG_LEN_INDEX] = 0x06
self.data[OPCODE_INDEX] = COMMON_NACK_OPCODE
+ elif rx_cmd_buff.data[OPCODE_INDEX] == BOOTLOADER_JUMP_OPCODE:
+ self.data[MSG_LEN_INDEX] = 0x06
+ self.data[OPCODE_INDEX] = COMMON_NACK_OPCODE
# Helper functions
@@ -319,6 +323,8 @@ def cmd_bytes_to_str(data):
pld_str += ' hex_data:'
for i in range(0,data[MSG_LEN_INDEX]-0x07):
pld_str += '{:02x}'.format(data[PLD_START_INDEX+4+i])
+ elif data[OPCODE_INDEX] == BOOTLOADER_JUMP_OPCODE:
+ cmd_str += 'bootloader_jump'
# string construction common to all commands
cmd_str += ' hw_id:0x{:04x}'.format(\
(data[HWID_MSB_INDEX]<<8)|(data[HWID_LSB_INDEX]<<0)\
@@ -371,6 +377,8 @@ def __init__(self, opcode, hw_id, msg_id, src, dst):
elif self.data[OPCODE_INDEX] == BOOTLOADER_WRITE_PAGE_ADDR32_OPCODE:
self.data[MSG_LEN_INDEX] = 0x0a
self.data[PLD_START_INDEX] = 0x00
+ elif self.data[OPCODE_INDEX] == BOOTLOADER_JUMP_OPCODE:
+ self.data[MSG_LEN_INDEX] = 0x06
else:
self.data[MSG_LEN_INDEX] = 0x06