Browse Source

add bootloader

Signed-off-by: surenyi <surenyi82@163.com>
master
surenyi 6 months ago
parent
commit
b4bbac0c44
  1. 2
      .vscode/settings.json
  2. 1
      CMakeLists.txt
  3. 90
      bootloader/board.c
  4. 9
      bootloader/board_config.h
  5. 67
      bootloader/bootloader.c
  6. 225
      bootloader/syscalls.c
  7. 22
      driver/common.c
  8. 15
      scripts/gdbscript.txt
  9. 12
      scripts/stm32f4xx_linker.ld

2
.vscode/settings.json

@ -36,7 +36,7 @@
"editor.formatOnSave": true, "editor.formatOnSave": true,
"editor.formatOnType": true, "editor.formatOnType": true,
"editor.formatOnPaste": true, "editor.formatOnPaste": true,
"editor.defaultFormatter": "xaver.clang-format" //"editor.defaultFormatter": "xaver.clang-format"
}, },
"cmake.options.statusBarVisibility": "hidden" "cmake.options.statusBarVisibility": "hidden"
} }

1
CMakeLists.txt

@ -68,6 +68,7 @@ target_sources(${tgt_name} PRIVATE
driver/printf.c driver/printf.c
driver/flash_if.c driver/flash_if.c
driver/ymodem.c driver/ymodem.c
driver/common.c
${_tgt_srcs} ${_tgt_srcs}
) )

90
bootloader/board.c

@ -0,0 +1,90 @@
/*
* port to ZD32F40X by surenyi (2024/04/26)
*/
#include <stdint.h>
#include "board_config.h"
#define _SCB_BASE (0xE000E010UL)
#define _SYSTICK_CTRL (*(uint32_t *)(_SCB_BASE + 0x0))
#define _SYSTICK_LOAD (*(uint32_t *)(_SCB_BASE + 0x4))
#define _SYSTICK_VAL (*(uint32_t *)(_SCB_BASE + 0x8))
#define _SYSTICK_CALIB (*(uint32_t *)(_SCB_BASE + 0xC))
#define _SYSTICK_PRI (*(uint8_t *)(0xE000ED23UL))
// Updates the variable SystemCoreClock and must be called
// whenever the core clock is changed during program execution.
extern void SystemCoreClockUpdate(void);
// Holds the system core clock, which is the system clock
// frequency supplied to the SysTick timer and the processor
// core clock.
extern uint32_t SystemCoreClock;
static uint32_t _SysTick_Config(uint32_t ticks)
{
if ((ticks - 1) > 0xFFFFFF) {
return 1;
}
_SYSTICK_LOAD = ticks - 1;
_SYSTICK_PRI = 0xFF;
_SYSTICK_VAL = 0;
_SYSTICK_CTRL = 0x07;
return 0;
}
void delay_microseconds(uint32_t us)
{
uint32_t start, now, delta, reload, us_tick;
start = _SYSTICK_VAL;
reload = _SYSTICK_LOAD;
us_tick = (SystemCoreClock / 1000000UL) * us;
do {
now = _SYSTICK_VAL;
delta = (start > now) ? (start - now) : (reload + start - now);
} while (delta < us_tick);
}
/**
* This function will initial your board.
*/
extern int main();
void entry()
{
/* System Clock Update */
SystemCoreClockUpdate();
/* System Tick Configuration */
_SysTick_Config(SystemCoreClock / BOARD_TICK_PER_SECOND);
main();
}
volatile uint64_t __current_ticks;
void SysTick_Handler(void)
{
++__current_ticks;
}
uint64_t millis()
{
return __current_ticks * (SystemCoreClock / BOARD_TICK_PER_SECOND);
}
/* Default empty handler */
static void Dummy_Handler(void)
{
#if defined DEBUG
__BKPT(3);
#endif
for (;;) {
}
}
void PendSV_Handler(void) __attribute__((weak, alias("Dummy_Handler")));
void HardFault_Handler(void) __attribute__((weak, alias("Dummy_Handler")));

9
bootloader/board_config.h

@ -0,0 +1,9 @@
#pragma once
#define BOARD_HAS_USART1 1
#define BOARD_HEAP_SIZE (16384)
#define BOARD_TICK_PER_SECOND (1000)
#define BOARD_APPLICATION_ENTRY (0x08080000)
#define BOARD_CONSOLE (&serial0)

67
bootloader/bootloader.c

@ -0,0 +1,67 @@
#include "board_config.h"
#include <stdio.h>
#include "stm32f4xx.h"
#include "bkp_sram.h"
#include "serial.h"
int go(unsigned long vect)
{
volatile unsigned int *ptr = (volatile unsigned int *)vect;
register unsigned int stack = ptr[0];
register unsigned int addr = ptr[1];
// printf("stack: %x, entry: %x, [%x, %x]\r\n", stack, addr, (stack & 0x2ffC0000), (stack & 0x1ffe0000));
// printf("off: %x\n", (vect - NVIC_VectTab_FLASH));
if (((stack & 0x2ffc0000) == 0x20000000) /* SRAM */ || ((stack & 0x1ffe0000) == 0x10000000) /* CCMRAM */) {
/* disable global irq */
__disable_irq();
NVIC_SetVectorTable(NVIC_VectTab_FLASH, (vect - NVIC_VectTab_FLASH));
/* set the stack pointer, then run */
__asm__ __volatile__("msr msp, %[tos]\n\t"
"msr psp, %[tos]\n\t"
"isb sy\n\t"
"dsb sy\n\t"
"blx %[app]\n\t"
:
: [tos] "r"(stack), [app] "r"(addr));
}
return -1;
}
void early_boot_sketch()
{
unsigned int magic;
bkp_sram_init();
magic = bkp_sram_read(MAGIC_POS);
if (magic != MAGIC_BOOT) {
go(BOARD_APPLICATION_ENTRY);
}
}
int console_read(void *ptr, int len)
{
return -1;
}
int console_write(const void *ptr, int len)
{
return 0;
}
void lowlevel_hw_init()
{
serial_setup(BOARD_CONSOLE, 115200, 8, SERIAL_STOPBITS_1);
}
int main()
{
printf("BootLoader\r\n");
while (1)
;
return 0;
}

225
bootloader/syscalls.c

@ -0,0 +1,225 @@
/*
* syscall stub to newlib
*/
#include <stdlib.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include "stm32f4xx.h"
#include "config.h"
#undef errno
extern int errno;
int * __errno()
{
return &errno;
}
/*
* Environment variables.
* A pointer to a list of environment variables and their values. For a minimal
* environment, this empty list is adequate:
*/
char *__env[1] = { 0 };
char **environ = __env;
__attribute__((weak)) int console_read(void *ptr, int len)
{
errno = EBADF;
return -1;
}
static void itm_send(const char *ptr, int n)
{
while (n > 0) {
ITM_SendChar(*ptr);
++ptr;
--n;
}
}
__attribute__((weak)) int console_write(const void *ptr, int len)
{
itm_send(ptr, len);
return len;
}
/*
* Close a file.
*/
int _close(int file)
{
errno = EBADF;
return -1;
}
/*
* Transfer control to a new process.
*/
int _execve(char *name, char **argv, char **env)
{
errno = ENOMEM;
return -1;
}
/*
* Exit a program without cleaning up files.
*/
void _exit( int code )
{
/* Should we force a system reset? */
while (1) {
;
}
}
/*
* Create a new process.
*/
int _fork(void)
{
errno = EAGAIN;
return -1;
}
/*
* Status of an open file.
*/
int _fstat(int file, struct stat *st)
{
if ((STDOUT_FILENO == file) || (STDERR_FILENO == file) || (STDIN_FILENO)) {
st->st_mode = S_IFCHR;
return 0;
}
errno = EBADF;
return -1;
}
/*
* Process-ID
*/
int _getpid(void)
{
return 1;
}
/*
* Query whether output stream is a terminal.
*/
int _isatty(int file)
{
if ((STDOUT_FILENO == file) || (STDERR_FILENO == file) || (STDIN_FILENO)) {
return 1;
}
errno = EBADF;
return -1;
}
/*
* Send a signal.
*/
int _kill(int pid, int sig)
{
errno = EINVAL;
return -1;
}
/*
* Establish a new name for an existing file.
*/
int _link(char *old, char *new)
{
errno = EMLINK;
return -1;
}
/*
* Set position in a file.
*/
int _lseek(int file, int ptr, int dir)
{
if ((STDOUT_FILENO == file) || (STDERR_FILENO == file) || (STDIN_FILENO)) {
return 0;
}
errno = EBADF;
return -1;
}
/*
* Open a file.
*/
int _open(const char *name, int flags, int mode)
{
errno = ENOSYS;
return -1;
}
/*
* Read from a file.
*/
int _read(int file, char *ptr, int len)
{
if (STDIN_FILENO == file)
return console_read(ptr, len);
errno = EBADF;
return -1;
}
/*
* Write to a file. libc subroutines will use this system routine for output to
* all files, including stdout梥o if you need to generate any output, for
* example to a serial port for debugging, you should make your minimal write
* capable of doing this.
*/
int _write_r( void * reent, int file, char * ptr, int len )
{
if ((STDOUT_FILENO == file) || (STDERR_FILENO == file)) {
return console_write(ptr, len);
}
errno = EBADF;
return -1;
}
/*
* Increase program data space. As malloc and related functions depend on this,
* it is useful to have a working implementation. The following suffices for a
* standalone system; it exploits the symbol _end automatically defined by the
* GNU linker.
*/
static char __heap[BOARD_HEAP_SIZE] __attribute__((section(".heap._sbrk,\"aw\",%nobits@")));
caddr_t _sbrk(int incr)
{
static char *heap_start = __heap;
char *prev_heap_end;
prev_heap_end = heap_start;
if (heap_start + incr > (__heap + BOARD_HEAP_SIZE)) {
_write_r ((void *)0, 1, "heap and stack collision\r\n", 26);
return (caddr_t)NULL;
}
heap_start += incr;
return (caddr_t) prev_heap_end;
}
/*
* Remove a file's directory entry.
*/
int _unlink(char *name)
{
errno = ENOENT;
return -1;
}
/*
* Wait for a child process.
*/
int _wait(int *status)
{
errno = ECHILD;
return -1;
}

22
driver/common.c

@ -0,0 +1,22 @@
#include <rtthread.h>
#include <finsh.h>
#include <finsh_api.h>
#include "stm32f4xx_flash.h"
#include "stm32f4xx.h"
static int flash_option(int argc, char *argv[])
{
rt_uint8_t option;
if (argc == 1) {
option = *(volatile rt_uint8_t *)(OPTCR_BYTE0_ADDRESS);
rt_kprintf("%04x\n", option);
} else if (argc >= 2) {
option = strtoul(argv[1], NULL, 16);
FLASH_Unlock();
FLASH_Lock();
}
return 0;
}
MSH_CMD_EXPORT(flash_option, flash option);

15
scripts/gdbscript.txt

@ -1,15 +0,0 @@
# gdbscript: script for download elf file
# gdb --batch -nx -x gdbscript.txt
set confirm off
target remote localhost:2331
set mem inaccessible-by-default off
monitor flash device = %DEVICE_TYPE%
monitor flash download = 1
monitor endian little
monitor speed auto
monitor reset
monitor sleep 100
load %TARGET_FILE%
monitor go
quit

12
scripts/stm32f4xx_linker.ld

@ -112,10 +112,11 @@ SECTIONS
} > FLASH } > FLASH
__exidx_end = .; __exidx_end = .;
__rodata_start = .;
.rodata : .rodata : AT(__exidx_end)
{ {
. = ALIGN(4); . = ALIGN(4);
__rodata_start = .;
*(.rodata*) *(.rodata*)
. = ALIGN(4); . = ALIGN(4);
@ -137,8 +138,11 @@ SECTIONS
KEEP(*(SORT(.fini_array.*))) KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array)) KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .); PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
__rodata_end = .;
} > FLASH } > FLASH
__rodata_end = .;
/* To copy multiple ROM to RAM sections, /* To copy multiple ROM to RAM sections,
* uncomment .copy.table section and, * uncomment .copy.table section and,
@ -182,7 +186,7 @@ SECTIONS
*(.data*) *(.data*)
KEEP(*(.jcr*)) KEEP(*(.jcr*))
. = ALIGN(8); . = ALIGN(4);
/* All data end */ /* All data end */
__data_end__ = .; __data_end__ = .;
} > RAM } > RAM

Loading…
Cancel
Save