bare-arm: Clean up the code, make it run on an F405, and add a README.

This commit simplifies and cleans up the bare-arm port, and adds just
enough system and library code to make it execute on an STM32F405 MCU.

The mpconfigport.h configuration is simplified to just specify those
configuration values that are different from the defaults.  And the
addition of -fdata-sections and -ffunction-sections means the final
firmware is smaller than it previously was, by about 4200 bytes.

A README is also added.

Signed-off-by: Damien George <damien@micropython.org>
pull/7052/head
Damien George 2021-03-12 21:03:03 +11:00
rodzic 42cf77f48b
commit 4fc2866f45
8 zmienionych plików z 454 dodań i 276 usunięć

Wyświetl plik

@ -1,52 +1,59 @@
# Include the core environment definitions; this will set $(TOP).
include ../../py/mkenv.mk
# qstr definitions (must come before including py.mk)
QSTR_DEFS = qstrdefsport.h
# MicroPython feature configurations
MICROPY_ROM_TEXT_COMPRESSION ?= 1
# include py core make definitions
# Include py core make definitions.
include $(TOP)/py/py.mk
# Set makefile-level MicroPython feature configurations.
MICROPY_ROM_TEXT_COMPRESSION ?= 1
# Define toolchain and other tools.
CROSS_COMPILE ?= arm-none-eabi-
DFU ?= $(TOP)/tools/dfu.py
PYDFU ?= $(TOP)/tools/pydfu.py
INC += -I.
INC += -I$(TOP)
INC += -I$(BUILD)
# Set CFLAGS.
CFLAGS += -I. -I$(TOP) -I$(BUILD)
CFLAGS += -Wall -Werror -std=c99 -nostdlib
CFLAGS += -mthumb -mtune=cortex-m4 -mcpu=cortex-m4 -msoft-float
CSUPEROPT = -Os # save some code space for performance-critical code
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion
CFLAGS = $(INC) -Wall -Werror -std=c99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT)
CSUPEROPT = -Os # save some code space
#Debugging/Optimization
# Select debugging or optimisation build.
ifeq ($(DEBUG), 1)
CFLAGS += -O0 -ggdb
CFLAGS += -Og
else
CFLAGS += -Os -DNDEBUG
CFLAGS += -fdata-sections -ffunction-sections
endif
LDFLAGS = -nostdlib -T stm32f405.ld -Map=$@.map --cref
LIBS =
# Set linker flags.
LDFLAGS += -nostdlib -T stm32f405.ld --gc-sections
SRC_C = \
main.c \
# printf.c \
string0.c \
malloc0.c \
gccollect.c \
# Define the required source files.
SRC_C += lib.c main.c system.c
SRC_S = \
# startup_stm32f40xx.s \
gchelper.s \
# Define the required object files.
OBJ += $(PY_CORE_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o))
all: $(BUILD)/firmware.elf
# Define the top-level target, the main firmware.
all: $(BUILD)/firmware.dfu
$(BUILD)/firmware.elf: $(OBJ)
$(ECHO) "LINK $@"
$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
$(Q)$(LD) $(LDFLAGS) -o $@ $^
$(Q)$(SIZE) $@
$(BUILD)/firmware.bin: $(BUILD)/firmware.elf
$(ECHO) "Create $@"
$(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $@
$(BUILD)/firmware.dfu: $(BUILD)/firmware.bin
$(ECHO) "Create $@"
$(Q)$(PYTHON) $(DFU) -b 0x08000000:$^ $@
deploy: $(BUILD)/firmware.dfu
$(Q)$(PYTHON) $(PYDFU) -u $^
# Include remaining core make rules.
include $(TOP)/py/mkrules.mk

Wyświetl plik

@ -0,0 +1,21 @@
The bare-arm port
=================
This port is intended to be the bare-minimum amount of code and configuration
required to get MicroPython compiling and running on a bare-metal ARM-based
target. No external dependencies or libraries are needed for this build and
it shows exactly what hardware and system functionality MicroPython needs to
run.
To build, simply run `make` in this directory. The output will be
`build/firmware.elf` (and also corresponding `.bin` and `.dfu` files). This
firmware can run on an STM32F405-based board (eg a PYBv1.x) and `make deploy`
will program it to such an MCU when put in USB DFU mode. The output is a UART
at 115200 baud, with TX on PA0.
There are some simple demonstration code strings (see `main.c`) which are
compiled and executed when the firmware starts. They produce output on the
system's stdout.
The size of the firmware (the machine code that is programmed to the
microcontroller's flash/ROM) is currently around 61200 bytes.

Wyświetl plik

@ -0,0 +1,128 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <string.h>
// These memory functions are needed when the garbage collector is disabled.
// A full implementation should be provided, or the garbage collector enabled.
// The functions here are very simple.
extern char _heap_start;
void *malloc(size_t n) {
static char *cur_heap = NULL;
if (cur_heap == NULL) {
cur_heap = &_heap_start;
}
void *ptr = cur_heap;
cur_heap += (n + 7) & ~7;
return ptr;
}
void *realloc(void *ptr, size_t size) {
void *ptr2 = malloc(size);
if (ptr && size) {
memcpy(ptr2, ptr, size); // size may be greater than ptr's region, do copy anyway
}
return ptr2;
}
void free(void *p) {
}
// These standard string functions are needed by the runtime, and can be
// provided either by the system or lib/libc/string0.c. The implementations
// here are very simple.
int memcmp(const void *s1, const void *s2, size_t n) {
const unsigned char *ss1 = s1, *ss2 = s2;
while (n--) {
int c = *ss1++ - *ss2++;
if (c) {
return c;
}
}
return 0;
}
void *memcpy(void *dest, const void *src, size_t n) {
return memmove(dest, src, n);
}
void *memmove(void *dest, const void *src, size_t n) {
unsigned char *d = dest;
const unsigned char *s = src;
if (s < d && d < s + n) {
// Need to copy backwards.
d += n - 1;
s += n - 1;
while (n--) {
*d-- = *s--;
}
} else {
// Can copy forwards.
while (n--) {
*d++ = *s++;
}
}
return dest;
}
void *memset(void *s, int c, size_t n) {
unsigned char *ss = s;
while (n--) {
*ss++ = c;
}
return s;
}
char *strchr(const char *s, int c) {
while (*s) {
if (*s == c) {
return (char *)s;
}
++s;
}
return NULL;
}
int strcmp(const char *s1, const char *s2) {
while (*s1 && *s2) {
int c = *s1++ - *s2++;
if (c) {
return c;
}
}
return *s1 - *s2;
}
size_t strlen(const char *s) {
const char *ss = s;
while (*ss) {
++ss;
}
return ss - s;
}

Wyświetl plik

@ -1,15 +1,48 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014-2021 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <string.h>
#include "py/compile.h"
#include "py/runtime.h"
#include "py/repl.h"
#include "py/mperrno.h"
void do_str(const char *src, mp_parse_input_kind_t input_kind) {
static const char *demo_single_input =
"print('hello world!', list(x + 1 for x in range(10)), end='eol\\n')";
static const char *demo_file_input =
"import micropython\n"
"\n"
"print(dir(micropython))\n"
"\n"
"for i in range(10):\n"
" print('iter {:08}'.format(i))";
static void do_str(const char *src, mp_parse_input_kind_t input_kind) {
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
// Compile, parse and execute the given string.
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
qstr source_name = lex->source_name;
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
@ -17,121 +50,29 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) {
mp_call_function_0(module_fun);
nlr_pop();
} else {
// uncaught exception
// Uncaught exception: print it out.
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
}
}
int main(int argc, char **argv) {
// Main entry point: initialise the runtime and execute demo strings.
void bare_main(void) {
mp_init();
do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\\n')", MP_PARSE_SINGLE_INPUT);
do_str("for i in range(10):\n print(i)", MP_PARSE_FILE_INPUT);
do_str(demo_single_input, MP_PARSE_SINGLE_INPUT);
do_str(demo_file_input, MP_PARSE_FILE_INPUT);
mp_deinit();
return 0;
}
mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
mp_raise_OSError(MP_ENOENT);
}
mp_import_stat_t mp_import_stat(const char *path) {
return MP_IMPORT_STAT_NO_EXIST;
}
mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
// Called if an exception is raised outside all C exception-catching handlers.
void nlr_jump_fail(void *val) {
while (1) {
;
}
}
void NORETURN __fatal_error(const char *msg) {
while (1) {
;
for (;;) {
}
}
#ifndef NDEBUG
// Used when debugging is enabled.
void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) {
printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line);
__fatal_error("Assertion failed");
for (;;) {
}
}
#endif
/*
int _lseek() {return 0;}
int _read() {return 0;}
int _write() {return 0;}
int _close() {return 0;}
void _exit(int x) {for(;;){}}
int _sbrk() {return 0;}
int _kill() {return 0;}
int _getpid() {return 0;}
int _fstat() {return 0;}
int _isatty() {return 0;}
*/
void *malloc(size_t n) {
return NULL;
}
void *calloc(size_t nmemb, size_t size) {
return NULL;
}
void *realloc(void *ptr, size_t size) {
return NULL;
}
void free(void *p) {
}
int printf(const char *m, ...) {
return 0;
}
void *memcpy(void *dest, const void *src, size_t n) {
return NULL;
}
int memcmp(const void *s1, const void *s2, size_t n) {
return 0;
}
void *memmove(void *dest, const void *src, size_t n) {
return NULL;
}
void *memset(void *s, int c, size_t n) {
return NULL;
}
int strcmp(const char *s1, const char *s2) {
return 0;
}
int strncmp(const char *s1, const char *s2, size_t n) {
return 0;
}
size_t strlen(const char *s) {
return 0;
}
char *strcat(char *dest, const char *src) {
return NULL;
}
char *strchr(const char *dest, int c) {
return NULL;
}
#include <stdarg.h>
int vprintf(const char *format, va_list ap) {
return 0;
}
int vsnprintf(char *str, size_t size, const char *format, va_list ap) {
return 0;
}
#undef putchar
int putchar(int c) {
return 0;
}
int puts(const char *s) {
return 0;
}
void _start(void) {
main(0, NULL);
}

Wyświetl plik

@ -1,71 +1,71 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014-2021 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdint.h>
// options to control how MicroPython is built
// Options to control how MicroPython is built
#define MICROPY_QSTR_BYTES_IN_HASH (1)
#define MICROPY_ALLOC_PATH_MAX (512)
#define MICROPY_EMIT_X64 (0)
#define MICROPY_EMIT_THUMB (0)
#define MICROPY_EMIT_INLINE_THUMB (0)
#define MICROPY_COMP_MODULE_CONST (0)
#define MICROPY_COMP_CONST (0)
#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0)
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)
#define MICROPY_MEM_STATS (0)
#define MICROPY_DEBUG_PRINTERS (0)
#define MICROPY_ENABLE_GC (0)
#define MICROPY_HELPER_REPL (0)
#define MICROPY_HELPER_LEXER_UNIX (0)
#define MICROPY_ENABLE_SOURCE_LINE (0)
#define MICROPY_ENABLE_DOC_STRING (0)
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
#define MICROPY_PY_ASYNC_AWAIT (0)
#define MICROPY_PY_ASSIGN_EXPR (0)
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (0)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
#define MICROPY_PY_BUILTINS_ENUMERATE (0)
#define MICROPY_PY_BUILTINS_FROZENSET (0)
#define MICROPY_PY_BUILTINS_REVERSED (0)
#define MICROPY_PY_BUILTINS_SET (0)
#define MICROPY_PY_BUILTINS_SLICE (0)
#define MICROPY_PY_BUILTINS_PROPERTY (0)
#define MICROPY_PY_BUILTINS_STR_COUNT (0)
#define MICROPY_PY_BUILTINS_STR_OP_MODULO (0)
#define MICROPY_PY___FILE__ (0)
#define MICROPY_PY_GC (0)
#define MICROPY_PY_ARRAY (0)
#define MICROPY_PY_ATTRTUPLE (0)
#define MICROPY_PY_COLLECTIONS (0)
#define MICROPY_PY_MATH (0)
#define MICROPY_PY_CMATH (0)
#define MICROPY_PY_IO (0)
#define MICROPY_PY_STRUCT (0)
#define MICROPY_PY_SYS (0)
#define MICROPY_CPYTHON_COMPAT (0)
#define MICROPY_MODULE_GETATTR (0)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
#define MICROPY_USE_INTERNAL_PRINTF (0)
// Memory allocation policy
#define MICROPY_QSTR_BYTES_IN_HASH (1)
// type definitions for the specific machine
// Compiler configuration
#define MICROPY_COMP_CONST (0)
#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0)
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p) | 1))
// Python internal features
#define MICROPY_ENABLE_EXTERNAL_IMPORT (0)
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
#define MICROPY_CPYTHON_COMPAT (0)
#define MICROPY_MODULE_GETATTR (0)
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
#define UINT_FMT "%lu"
#define INT_FMT "%ld"
// Fine control over Python builtins, classes, modules, etc
#define MICROPY_PY_ASYNC_AWAIT (0)
#define MICROPY_PY_ASSIGN_EXPR (0)
#define MICROPY_PY_BUILTINS_STR_COUNT (0)
#define MICROPY_PY_BUILTINS_STR_OP_MODULO (0)
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (0)
#define MICROPY_PY_BUILTINS_SET (0)
#define MICROPY_PY_BUILTINS_SLICE (0)
#define MICROPY_PY_BUILTINS_PROPERTY (0)
#define MICROPY_PY_BUILTINS_ENUMERATE (0)
#define MICROPY_PY_BUILTINS_REVERSED (0)
#define MICROPY_PY___FILE__ (0)
#define MICROPY_PY_ARRAY (0)
#define MICROPY_PY_COLLECTIONS (0)
#define MICROPY_PY_IO (0)
#define MICROPY_PY_STRUCT (0)
#define MICROPY_PY_SYS (0)
// Type definitions for the specific machine
typedef int32_t mp_int_t; // must be pointer size
typedef uint32_t mp_uint_t; // must be pointer size
typedef long mp_off_t;
// dummy print
#define MP_PLAT_PRINT_STRN(str, len) (void)0
// extra built in names to add to the global namespace
#define MICROPY_PORT_BUILTINS \
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) },
// We need to provide a declaration/definition of alloca()
// Need to provide a declaration/definition of alloca()
#include <alloca.h>

Wyświetl plik

@ -1,2 +0,0 @@
// qstrs specific to this port
// *FORMAT-OFF*

Wyświetl plik

@ -1,117 +1,58 @@
/*
GNU linker script for STM32F405
*/
/* GNU linker script for STM32F405 */
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x100000 /* entire flash, 1 MiB */
FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 0x004000 /* sector 0, 16 KiB */
FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 0x080000 /* sectors 5,6,7,8, 4*128KiB = 512 KiB (could increase it more) */
CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 0x010000 /* 64 KiB */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x020000 /* 128 KiB */
}
/* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);
/* RAM extents for the garbage collector */
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
_heap_end = 0x2001c000; /* tunable */
/* define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
KEEP(*(.isr_vector))
. = ALIGN(4);
} >FLASH_ISR
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
/* *(.glue_7) */ /* glue arm to thumb code */
/* *(.glue_7t) */ /* glue thumb to arm code */
*(.text)
*(.text*)
*(.rodata)
*(.rodata*)
. = ALIGN(4);
_etext = .; /* define a global symbol at end of code */
_sidata = _etext; /* This is used by the startup in order to initialize the .data secion */
} >FLASH_TEXT
/*
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
_etext = .;
_sidata = _etext;
} >FLASH
.ARM :
{
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
*/
/* 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 FLASH (inidata).
It is one task of the startup to copy the initial values from FLASH to RAM. */
.data : AT ( _sidata )
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */
_ram_start = .; /* create a global symbol at ram start for garbage collector */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
_sdata = .;
*(.data)
*(.data*)
. = ALIGN(4);
_edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
_edata = .;
} >RAM
/* Uninitialized data section */
.bss :
{
. = ALIGN(4);
_sbss = .; /* define a global symbol at bss start; used by startup code */
_sbss = .;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end; used by startup code */
_ebss = .;
} >RAM
/* this is to define the start of the heap, and make sure we have a minimum size */
.heap :
{
. = ALIGN(4);
_heap_start = .; /* define a global symbol at heap start */
. = ALIGN(8);
_heap_start = .;
} >RAM
/* this just checks there is enough RAM for the stack */
.stack :
{
. = ALIGN(4);
} >RAM
/* Remove information from the standard libraries */
/*
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
*/
.ARM.attributes 0 : { *(.ARM.attributes) }
}

Wyświetl plik

@ -0,0 +1,142 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdint.h>
#include <string.h>
#define RCC ((periph_rcc_t *)0x40023800)
#define GPIOA ((periph_gpio_t *)0x40020000)
#define UART4 ((periph_uart_t *)0x40004C00)
typedef struct {
volatile uint32_t CR;
volatile uint32_t PLLCFGR;
volatile uint32_t CFGR;
volatile uint32_t CIR;
uint32_t _1[8];
volatile uint32_t AHB1ENR;
volatile uint32_t AHB2ENR;
volatile uint32_t AHB3ENR;
uint32_t _2;
volatile uint32_t APB1ENR;
volatile uint32_t APB2ENR;
} periph_rcc_t;
typedef struct {
volatile uint32_t MODER;
volatile uint32_t OTYPER;
volatile uint32_t OSPEEDR;
volatile uint32_t PUPDR;
volatile uint32_t IDR;
volatile uint32_t ODR;
volatile uint16_t BSRRL;
volatile uint16_t BSRRH;
volatile uint32_t LCKR;
volatile uint32_t AFR[2];
} periph_gpio_t;
typedef struct {
volatile uint32_t SR;
volatile uint32_t DR;
volatile uint32_t BRR;
volatile uint32_t CR1;
} periph_uart_t;
extern uint32_t _estack, _sidata, _sdata, _edata, _sbss, _ebss;
void Reset_Handler(void) __attribute__((naked));
void bare_main(void);
static void stm32_init(void);
static void gpio_init_alt(periph_gpio_t *gpio, int pin, int alt);
// Very simple ARM vector table.
const uint32_t isr_vector[] __attribute__((section(".isr_vector"))) = {
(uint32_t)&_estack,
(uint32_t)&Reset_Handler,
};
// The CPU runs this function after a reset.
void Reset_Handler(void) {
// Set stack pointer.
__asm volatile ("ldr sp, =_estack");
// Copy .data section from flash to RAM.
memcpy(&_sdata, &_sidata, (char *)&_edata - (char *)&_sdata);
// Zero out .bss section.
memset(&_sbss, 0, (char *)&_ebss - (char *)&_sbss);
// SCB->CCR: enable 8-byte stack alignment for IRQ handlers, in accord with EABI.
*((volatile uint32_t *)0xe000ed14) |= 1 << 9;
// Initialise the cpu and peripherals.
stm32_init();
// Now that there is a basic system up and running, call the main application code.
bare_main();
// This function must not return.
for (;;) {
}
}
// Set up the STM32 MCU.
static void stm32_init(void) {
// Note: default clock is internal 16MHz.
RCC->AHB1ENR |= 1 << 0; // GPIOAEN
RCC->APB1ENR |= 1 << 19; // UART4EN
gpio_init_alt(GPIOA, 0, 8);
UART4->BRR = (8 << 4) | 11; // 16MHz/(16*8.6875) = 115107 baud
UART4->CR1 = 0x00002008; // USART enable, tx enable, rx enable
}
// Configure a GPIO pin in alternate-function mode.
static void gpio_init_alt(periph_gpio_t *gpio, int pin, int alt) {
gpio->MODER = (gpio->MODER & ~(3 << (2 * pin))) | (2 << (2 * pin));
// OTYPER is left as default push-pull
// OSPEEDR is left as default low speed
// PUPDR is left as default no-pull
gpio->AFR[pin >> 3] = (gpio->AFR[pin >> 3] & ~(15 << (4 * (pin & 7)))) | (alt << (4 * (pin & 7)));
}
// Write a character out to the UART.
static inline void uart_write_char(int c) {
// Wait for TXE, then write the character.
while ((UART4->SR & (1 << 7)) == 0) {
}
UART4->DR = c;
}
// Send string of given length to stdout, converting \n to \r\n.
void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) {
while (len--) {
if (*str == '\n') {
uart_write_char('\r');
}
uart_write_char(*str++);
}
}