Skip to content

Instantly share code, notes, and snippets.

@GMMan
Created February 7, 2026 07:17
Show Gist options
  • Select an option

  • Save GMMan/3208b3f8e290dbc5f21a0d6bcbed1bd0 to your computer and use it in GitHub Desktop.

Select an option

Save GMMan/3208b3f8e290dbc5f21a0d6bcbed1bd0 to your computer and use it in GitHub Desktop.
SNC7330 bootrom console over UART1

This code executes the SNC7330 bootrom built-in console standalone and uses UART1 instead of UART0 for I/O.

To build, use the SN_M3B SDK with default startup code to do some basic setup, and use this code for your main program. Add symbol mapping as necessary.

Auto-baud rate is enabled, so connect with any baud rate (115200 by default). Hit escape at start of line to have the console emit some newlines, and type ? to see commands. Be careful while working with the console, because it is capable of erasing flash.

#include <stdlib.h>
#include "snc_drv.h"
// FPB registers
#define FP_CTRL *((volatile unsigned int *)0xe0002000)
#define FP_REMAP *((volatile unsigned int *)0xe0002004)
#define FP_COMPn ((volatile unsigned int *)0xe0002008)
extern uint32_t remap_table[2]; // 0x20000180
// ROM structs
typedef struct {
void (*write_fn)(uint8_t ch);
uint8_t (*read_fn)(void);
} xmodem_callbacks_t;
// ROM variables
extern volatile uint32_t systick; // 0x18018434
extern uint32_t uart_console_proc_index; // 0x180185b8
extern uint32_t uart_console_print_greeting; // 0x180185bc
// ROM functions
extern int uart_init(SN_UART_Type *pDev, uint32_t sys_clock, uint32_t baud_rate); // 0x0800c3b8
extern int uart_console_procedure(void); // 0x08005b5c
extern void uart_console_xmodem_set_cb(xmodem_callbacks_t *cb); // 0x08004798
extern int UART_WriteByte(uart_port_t port_id, uint8_t data); // 0x08003604
extern uint32_t UART_ReadByte(uart_port_t port_id); // 0x080035c8
extern void UART_IRQ_Handler_ROM(SN_UART_Type *huart, uint32_t uart_index); // 0x08004b90
static void platform_init(void);
static void patch_rom(void);
static void uart_console_init(void);
int main(void) {
platform_init();
patch_rom();
SN_SYS1->PCLK_EN_b.UARTCLKEN = 1;
SN_SYS1->PCLK_RST_b.UARTRST = 1;
while (SN_SYS1->PCLK_RST_b.UARTRST);
uart_console_init();
uart_console_proc_index = 0;
uart_console_print_greeting = 1;
NVIC_EnableIRQ(UART1_IRQn);
for (;;) {
uart_console_procedure();
}
return 0; // Should never be reached
}
static void patch_rom(void)
{
// Setup remap table
// Patch UART_WriteByte() and UART_WriteMultiBytes() to use SN_UART1 for port_id == UART_PORT_0
// 0800360c: ldr.eq r0,[0x08003638]
// 0800360e: beq 0x08003618
remap_table[0] = 0xd003480a;
// 0800d548: ldr.eq r0,[0x0800d584]
// 0800d54a: beq 0x0800d554
remap_table[1] = 0xd003480e;
// Configure FPB
FP_REMAP = (unsigned int)&remap_table & 0x1FFFFFE0;
FP_COMPn[0] = 0x0800360c | 1; // REPLACE=0, ENABLE=1
FP_COMPn[1] = 0x0800d548 | 1;
FP_CTRL |= 3; // KEY=1, ENABLE=1
}
void uart_write_char(uint8_t ch)
{
UART_WriteByte(UART_PORT_1, ch);
}
uint8_t uart_read_char(void)
{
return UART_ReadByte(UART_PORT_1);
}
static void uart_console_init(void)
{
// Everything is UART1
xmodem_callbacks_t cb = {
.write_fn = uart_write_char,
.read_fn = uart_read_char,
};
uart_console_xmodem_set_cb(&cb);
uart_init(SN_UART1, System_Get_SysClk(), 115200);
SN_UART1->IE_b.ABEOIE = 1;
SN_UART1->ABCTRL_b.MODE = 1;
SN_UART1->ABCTRL_b.START = 1;
}
static void platform_init(void)
{
systick = 0;
SysTick_Config(System_Get_SysClk() / 1000);
}
void SysTick_Handler(void)
{
++systick;
}
void UART1_IRQHandler(void)
{
UART_IRQ_Handler_ROM(SN_UART1, 1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment