kopia lustrzana https://github.com/micropython/micropython
qemu-arm: Rework to run bare-metal on boards with Cortex-M CPUs.
Adds support for 3 Cortex-M boards, selectable via "BOARD" in the Makefile: - microbit, Cortex-M0 via nRF51822 - netduino2, Cortex-M3 via STM32F205 - mps2-an385, Cortex-M3 via FPGA netduino2 is the default board because it's supported by older qemu versions (down to at least 2.5.0).pull/4470/head
rodzic
775c7b86f0
commit
e7332b0584
|
@ -7,6 +7,27 @@ QSTR_DEFS = qstrdefsport.h
|
||||||
# include py core make definitions
|
# include py core make definitions
|
||||||
include $(TOP)/py/py.mk
|
include $(TOP)/py/py.mk
|
||||||
|
|
||||||
|
BOARD ?= netduino2
|
||||||
|
|
||||||
|
ifeq ($(BOARD),netduino2)
|
||||||
|
CFLAGS += -mthumb -mcpu=cortex-m3 -mfloat-abi=soft
|
||||||
|
CFLAGS += -DQEMU_SOC_STM32
|
||||||
|
LDSCRIPT = stm32.ld
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(BOARD),microbit)
|
||||||
|
CFLAGS += -mthumb -mcpu=cortex-m0 -mfloat-abi=soft
|
||||||
|
CFLAGS += -DQEMU_SOC_NRF51
|
||||||
|
LDSCRIPT = nrf51.ld
|
||||||
|
QEMU_EXTRA = -global nrf51-soc.flash-size=1048576 -global nrf51-soc.sram-size=262144
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(BOARD),mps2-an385)
|
||||||
|
CFLAGS += -mthumb -mcpu=cortex-m3 -mfloat-abi=soft
|
||||||
|
CFLAGS += -DQEMU_SOC_MPS2
|
||||||
|
LDSCRIPT = mps2.ld
|
||||||
|
endif
|
||||||
|
|
||||||
CROSS_COMPILE = arm-none-eabi-
|
CROSS_COMPILE = arm-none-eabi-
|
||||||
|
|
||||||
TINYTEST = $(TOP)/lib/tinytest
|
TINYTEST = $(TOP)/lib/tinytest
|
||||||
|
@ -16,8 +37,7 @@ INC += -I$(TOP)
|
||||||
INC += -I$(BUILD)
|
INC += -I$(BUILD)
|
||||||
INC += -I$(TINYTEST)
|
INC += -I$(TINYTEST)
|
||||||
|
|
||||||
CFLAGS_CORTEX_M3 = -mthumb -mcpu=cortex-m3 -mfloat-abi=soft
|
CFLAGS += $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 $(COPT) \
|
||||||
CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 $(CFLAGS_CORTEX_M3) $(COPT) \
|
|
||||||
-ffunction-sections -fdata-sections
|
-ffunction-sections -fdata-sections
|
||||||
|
|
||||||
#Debugging/Optimization
|
#Debugging/Optimization
|
||||||
|
@ -34,9 +54,12 @@ endif
|
||||||
## else instead and according to the following files, this is what we need to pass to `$(CC).
|
## else instead and according to the following files, this is what we need to pass to `$(CC).
|
||||||
## - gcc-arm-none-eabi-4_8-2014q1/share/gcc-arm-none-eabi/samples/src/makefile.conf
|
## - gcc-arm-none-eabi-4_8-2014q1/share/gcc-arm-none-eabi/samples/src/makefile.conf
|
||||||
## - gcc-arm-none-eabi-4_8-2014q1/share/gcc-arm-none-eabi/samples/src/qemu/Makefile
|
## - gcc-arm-none-eabi-4_8-2014q1/share/gcc-arm-none-eabi/samples/src/qemu/Makefile
|
||||||
LDFLAGS= --specs=nano.specs --specs=rdimon.specs -Wl,--gc-sections -Wl,-Map=$(@:.elf=.map)
|
LDFLAGS= -T $(LDSCRIPT) --gc-sections -Map=$(@:.elf=.map)
|
||||||
|
LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
|
||||||
|
|
||||||
SRC_COMMON_C = \
|
SRC_COMMON_C = \
|
||||||
|
startup.c \
|
||||||
|
uart.c \
|
||||||
moduos.c \
|
moduos.c \
|
||||||
modmachine.c \
|
modmachine.c \
|
||||||
|
|
||||||
|
@ -47,6 +70,7 @@ SRC_TEST_C = \
|
||||||
test_main.c \
|
test_main.c \
|
||||||
|
|
||||||
LIB_SRC_C += $(addprefix lib/,\
|
LIB_SRC_C += $(addprefix lib/,\
|
||||||
|
libc/string0.c \
|
||||||
libm/math.c \
|
libm/math.c \
|
||||||
libm/fmodf.c \
|
libm/fmodf.c \
|
||||||
libm/nearbyintf.c \
|
libm/nearbyintf.c \
|
||||||
|
@ -89,11 +113,11 @@ SRC_QSTR += $(SRC_COMMON_C) $(SRC_RUN_C) $(LIB_SRC_C)
|
||||||
all: run
|
all: run
|
||||||
|
|
||||||
run: $(BUILD)/firmware.elf
|
run: $(BUILD)/firmware.elf
|
||||||
qemu-system-arm -machine integratorcp -cpu cortex-m3 -nographic -monitor null -serial null -semihosting -kernel $(BUILD)/firmware.elf
|
qemu-system-arm -machine $(BOARD) $(QEMU_EXTRA) -nographic -monitor null -semihosting -kernel $<
|
||||||
|
|
||||||
## `$(LD)` doesn't seem to like `--specs` for some reason, but we can just use `$(CC)` here.
|
## `$(LD)` doesn't seem to like `--specs` for some reason, but we can just use `$(CC)` here.
|
||||||
$(BUILD)/firmware.elf: $(OBJ_COMMON) $(OBJ_RUN)
|
$(BUILD)/firmware.elf: $(OBJ_COMMON) $(OBJ_RUN)
|
||||||
$(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
|
$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||||
$(Q)$(SIZE) $@
|
$(Q)$(SIZE) $@
|
||||||
|
|
||||||
include $(TOP)/py/mkrules.mk
|
include $(TOP)/py/mkrules.mk
|
||||||
|
|
|
@ -15,10 +15,10 @@ $(BUILD)/tinytest.o:
|
||||||
$(Q)$(CC) $(CFLAGS) -DNO_FORKING -o $@ -c $(TINYTEST)/tinytest.c
|
$(Q)$(CC) $(CFLAGS) -DNO_FORKING -o $@ -c $(TINYTEST)/tinytest.c
|
||||||
|
|
||||||
$(BUILD)/firmware-test.elf: $(OBJ_COMMON) $(OBJ_TEST)
|
$(BUILD)/firmware-test.elf: $(OBJ_COMMON) $(OBJ_TEST)
|
||||||
$(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
|
$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||||
$(Q)$(SIZE) $@
|
$(Q)$(SIZE) $@
|
||||||
|
|
||||||
test: $(BUILD)/firmware-test.elf
|
test: $(BUILD)/firmware-test.elf
|
||||||
qemu-system-arm -machine integratorcp -cpu cortex-m3 -nographic -monitor null -serial null -semihosting -kernel $(BUILD)/firmware-test.elf > $(BUILD)/console.out
|
qemu-system-arm -machine $(BOARD) $(QEMU_EXTRA) -nographic -monitor null -semihosting -kernel $< > $(BUILD)/console.out
|
||||||
$(Q)tail -n2 $(BUILD)/console.out
|
$(Q)tail -n2 $(BUILD)/console.out
|
||||||
$(Q)tail -n1 $(BUILD)/console.out | grep -q "status: 0"
|
$(Q)tail -n1 $(BUILD)/console.out | grep -q "status: 0"
|
||||||
|
|
|
@ -30,7 +30,7 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) {
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
mp_stack_ctrl_init();
|
mp_stack_ctrl_init();
|
||||||
mp_stack_set_limit(10240);
|
mp_stack_set_limit(10240);
|
||||||
void *heap = malloc(16 * 1024);
|
uint32_t heap[16*1024 / 4];
|
||||||
gc_init(heap, (char*)heap + 16 * 1024);
|
gc_init(heap, (char*)heap + 16 * 1024);
|
||||||
mp_init();
|
mp_init();
|
||||||
do_str("print('hello world!')", MP_PARSE_SINGLE_INPUT);
|
do_str("print('hello world!')", MP_PARSE_SINGLE_INPUT);
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
#define MICROPY_PY_UHASHLIB (1)
|
#define MICROPY_PY_UHASHLIB (1)
|
||||||
#define MICROPY_PY_MACHINE (1)
|
#define MICROPY_PY_MACHINE (1)
|
||||||
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
|
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
|
||||||
#define MICROPY_USE_INTERNAL_PRINTF (0)
|
#define MICROPY_USE_INTERNAL_PRINTF (1)
|
||||||
#define MICROPY_VFS (1)
|
#define MICROPY_VFS (1)
|
||||||
|
|
||||||
// type definitions for the specific machine
|
// type definitions for the specific machine
|
||||||
|
@ -54,9 +54,6 @@ typedef int32_t mp_int_t; // must be pointer size
|
||||||
typedef uint32_t mp_uint_t; // must be pointer size
|
typedef uint32_t mp_uint_t; // must be pointer size
|
||||||
typedef long mp_off_t;
|
typedef long mp_off_t;
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#define MP_PLAT_PRINT_STRN(str, len) write(1, str, len)
|
|
||||||
|
|
||||||
// extra built in names to add to the global namespace
|
// extra built in names to add to the global namespace
|
||||||
#define MICROPY_PORT_BUILTINS \
|
#define MICROPY_PORT_BUILTINS \
|
||||||
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) },
|
||||||
|
|
|
@ -1,2 +1,5 @@
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "uart.h"
|
||||||
|
|
||||||
#define mp_hal_stdin_rx_chr() (0)
|
#define mp_hal_stdin_rx_chr() (0)
|
||||||
#define mp_hal_stdout_tx_strn_cooked(s, l) write(1, (s), (l))
|
#define mp_hal_stdout_tx_strn_cooked(s, l) uart_tx_strn((s), (l))
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
RAM : ORIGIN = 0x00000000, LENGTH = 4M
|
||||||
|
}
|
||||||
|
|
||||||
|
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.text : {
|
||||||
|
. = ALIGN(4);
|
||||||
|
KEEP(*(.isr_vector))
|
||||||
|
*(.text*)
|
||||||
|
*(.rodata*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_etext = .;
|
||||||
|
_sidata = _etext;
|
||||||
|
} > RAM
|
||||||
|
|
||||||
|
.data : AT ( _sidata )
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_sdata = .;
|
||||||
|
*(.data*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_edata = .;
|
||||||
|
} >RAM
|
||||||
|
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_sbss = .;
|
||||||
|
*(.bss*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_ebss = .;
|
||||||
|
} >RAM
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
ROM : ORIGIN = 0x00000000, LENGTH = 1M
|
||||||
|
RAM : ORIGIN = 0x20000000, LENGTH = 256K
|
||||||
|
}
|
||||||
|
|
||||||
|
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.text : {
|
||||||
|
. = ALIGN(4);
|
||||||
|
KEEP(*(.isr_vector))
|
||||||
|
*(.text*)
|
||||||
|
*(.rodata*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_etext = .;
|
||||||
|
_sidata = _etext;
|
||||||
|
} > ROM
|
||||||
|
|
||||||
|
.data : AT ( _sidata )
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_sdata = .;
|
||||||
|
*(.data*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_edata = .;
|
||||||
|
} >RAM
|
||||||
|
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_sbss = .;
|
||||||
|
*(.bss*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_ebss = .;
|
||||||
|
} >RAM
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "uart.h"
|
||||||
|
|
||||||
|
extern uint32_t _estack, _sidata, _sdata, _edata, _sbss, _ebss;
|
||||||
|
|
||||||
|
__attribute__((naked)) void Reset_Handler(void) {
|
||||||
|
// set stack pointer
|
||||||
|
__asm volatile ("ldr r0, =_estack");
|
||||||
|
__asm volatile ("mov sp, r0");
|
||||||
|
// copy .data section from flash to RAM
|
||||||
|
for (uint32_t *src = &_sidata, *dest = &_sdata; dest < &_edata;) {
|
||||||
|
*dest++ = *src++;
|
||||||
|
}
|
||||||
|
// zero out .bss section
|
||||||
|
for (uint32_t *dest = &_sbss; dest < &_ebss;) {
|
||||||
|
*dest++ = 0;
|
||||||
|
}
|
||||||
|
// jump to board initialisation
|
||||||
|
void _start(void);
|
||||||
|
_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Default_Handler(void) {
|
||||||
|
for (;;) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t isr_vector[] __attribute__((section(".isr_vector"))) = {
|
||||||
|
(uint32_t)&_estack,
|
||||||
|
(uint32_t)&Reset_Handler,
|
||||||
|
(uint32_t)&Default_Handler, // NMI_Handler
|
||||||
|
(uint32_t)&Default_Handler, // HardFault_Handler
|
||||||
|
(uint32_t)&Default_Handler, // MemManage_Handler
|
||||||
|
(uint32_t)&Default_Handler, // BusFault_Handler
|
||||||
|
(uint32_t)&Default_Handler, // UsageFault_Handler
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
(uint32_t)&Default_Handler, // SVC_Handler
|
||||||
|
(uint32_t)&Default_Handler, // DebugMon_Handler
|
||||||
|
0,
|
||||||
|
(uint32_t)&Default_Handler, // PendSV_Handler
|
||||||
|
(uint32_t)&Default_Handler, // SysTick_Handler
|
||||||
|
};
|
||||||
|
|
||||||
|
void _start(void) {
|
||||||
|
// Enable the UART
|
||||||
|
uart_init();
|
||||||
|
|
||||||
|
// Now that we have a basic system up and running we can call main
|
||||||
|
extern int main();
|
||||||
|
main(0, 0);
|
||||||
|
|
||||||
|
// Finished
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((naked)) void exit(int status) {
|
||||||
|
// Force qemu to exit using ARM Semihosting
|
||||||
|
__asm volatile (
|
||||||
|
"mov r1, r0\n"
|
||||||
|
"cmp r1, #0\n"
|
||||||
|
"bne .notclean\n"
|
||||||
|
"ldr r1, =0x20026\n" // ADP_Stopped_ApplicationExit, a clean exit
|
||||||
|
".notclean:\n"
|
||||||
|
"movs r0, #0x18\n" // SYS_EXIT
|
||||||
|
"bkpt 0xab\n"
|
||||||
|
);
|
||||||
|
for (;;) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following are needed for tinytest
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int setvbuf(FILE *stream, char *buf, int mode, size_t size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct _reent *_impure_ptr;
|
|
@ -0,0 +1,39 @@
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
ROM : ORIGIN = 0x00000000, LENGTH = 1M
|
||||||
|
RAM : ORIGIN = 0x20000000, LENGTH = 128K
|
||||||
|
}
|
||||||
|
|
||||||
|
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.text : {
|
||||||
|
. = ALIGN(4);
|
||||||
|
KEEP(*(.isr_vector))
|
||||||
|
*(.text*)
|
||||||
|
*(.rodata*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_etext = .;
|
||||||
|
_sidata = _etext;
|
||||||
|
} > ROM
|
||||||
|
|
||||||
|
.data : AT ( _sidata )
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_sdata = .;
|
||||||
|
*(.data*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_edata = .;
|
||||||
|
} >RAM
|
||||||
|
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_sbss = .;
|
||||||
|
*(.bss*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_ebss = .;
|
||||||
|
} >RAM
|
||||||
|
}
|
|
@ -15,15 +15,14 @@
|
||||||
#include "tinytest.h"
|
#include "tinytest.h"
|
||||||
#include "tinytest_macros.h"
|
#include "tinytest_macros.h"
|
||||||
|
|
||||||
#define HEAP_SIZE (128 * 1024)
|
#define HEAP_SIZE (100 * 1024)
|
||||||
STATIC void *heap;
|
|
||||||
|
|
||||||
#include "genhdr/tests.h"
|
#include "genhdr/tests.h"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
mp_stack_ctrl_init();
|
mp_stack_ctrl_init();
|
||||||
mp_stack_set_limit(10240);
|
mp_stack_set_limit(10240);
|
||||||
heap = malloc(HEAP_SIZE);
|
static uint32_t heap[HEAP_SIZE / sizeof(uint32_t)];
|
||||||
upytest_set_heap(heap, (char*)heap + HEAP_SIZE);
|
upytest_set_heap(heap, (char*)heap + HEAP_SIZE);
|
||||||
int r = tinytest_main(0, NULL, groups);
|
int r = tinytest_main(0, NULL, groups);
|
||||||
printf("status: %d\n", r);
|
printf("status: %d\n", r);
|
||||||
|
@ -34,8 +33,7 @@ void gc_collect(void) {
|
||||||
gc_collect_start();
|
gc_collect_start();
|
||||||
|
|
||||||
// get the registers and the sp
|
// get the registers and the sp
|
||||||
jmp_buf env;
|
// TODO get registers
|
||||||
setjmp(env);
|
|
||||||
volatile mp_uint_t dummy;
|
volatile mp_uint_t dummy;
|
||||||
void *sp = (void*)&dummy;
|
void *sp = (void*)&dummy;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "uart.h"
|
||||||
|
|
||||||
|
#if defined(QEMU_SOC_STM32)
|
||||||
|
|
||||||
|
typedef struct _UART_t {
|
||||||
|
volatile uint32_t SR;
|
||||||
|
volatile uint32_t DR;
|
||||||
|
} UART_t;
|
||||||
|
|
||||||
|
#define UART0 ((UART_t*)(0x40011000))
|
||||||
|
|
||||||
|
void uart_init(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_tx_strn(const char *buf, size_t len) {
|
||||||
|
for (size_t i = 0; i < len; ++i) {
|
||||||
|
UART0->DR = buf[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(QEMU_SOC_NRF51)
|
||||||
|
|
||||||
|
typedef struct _UART_t {
|
||||||
|
volatile uint32_t r0[2];
|
||||||
|
volatile uint32_t STARTTX; // 0x008
|
||||||
|
volatile uint32_t r1[(0x500 - 0x008) / 4 - 1];
|
||||||
|
volatile uint32_t ENABLE; // 0x500
|
||||||
|
volatile uint32_t r2[(0x51c - 0x500) / 4 - 1];
|
||||||
|
volatile uint32_t TXD; // 0x51c
|
||||||
|
} UART_t;
|
||||||
|
|
||||||
|
#define UART0 ((UART_t*)(0x40002000))
|
||||||
|
|
||||||
|
void uart_init(void) {
|
||||||
|
UART0->ENABLE = 4;
|
||||||
|
UART0->STARTTX = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_tx_strn(const char *buf, size_t len) {
|
||||||
|
for (size_t i = 0; i < len; ++i) {
|
||||||
|
UART0->TXD = buf[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(QEMU_SOC_MPS2)
|
||||||
|
|
||||||
|
#define UART_STATE_TXFULL (1 << 0)
|
||||||
|
|
||||||
|
#define UART_CTRL_TX_EN (1 << 0)
|
||||||
|
#define UART_CTRL_RX_EN (1 << 1)
|
||||||
|
|
||||||
|
typedef struct _UART_t {
|
||||||
|
volatile uint32_t DATA;
|
||||||
|
volatile uint32_t STATE;
|
||||||
|
volatile uint32_t CTRL;
|
||||||
|
volatile uint32_t INTSTATUS;
|
||||||
|
volatile uint32_t BAUDDIV;
|
||||||
|
} UART_t;
|
||||||
|
|
||||||
|
#define UART0 ((UART_t*)(0x40004000))
|
||||||
|
|
||||||
|
void uart_init(void) {
|
||||||
|
UART0->BAUDDIV = 16;
|
||||||
|
UART0->CTRL = UART_CTRL_TX_EN;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_tx_strn(const char *buf, size_t len) {
|
||||||
|
for (size_t i = 0; i < len; ++i) {
|
||||||
|
while (UART0->STATE & UART_STATE_TXFULL) {
|
||||||
|
}
|
||||||
|
UART0->DATA = buf[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,2 @@
|
||||||
|
void uart_init(void);
|
||||||
|
void uart_tx_strn(const char *buf, size_t len);
|
Ładowanie…
Reference in New Issue