提交 f14b92b9 编写于 作者: D Dave Hylands

REPl working on UART6 with STMHAL

上级 19438fd3
......@@ -19,6 +19,7 @@ CROSS_COMPILE = arm-none-eabi-
INC = -I.
INC += -I$(PY_SRC)
INC += -I$(CMSIS_DIR)
INC += -I$(CMSIS_DIR)/inc
INC += -I$(CMSIS_DIR)/devinc
INC += -I$(HAL_DIR)/inc
......@@ -54,28 +55,30 @@ LIBS =
SRC_C = \
main.c \
string0.c \
system_stm32f4xx.c \
stm32f4xx_it.c \
stm32f4xx_hal_msp.c \
systick.c \
led.c \
pin.c \
usart.c \
printf.c \
math.c \
malloc0.c \
gccollect.c \
pyexec.c \
pybmodule.c \
import.c \
lexerfatfs.c \
# printf.c \
# math.c \
# string0.c \
# malloc0.c \
# systick.c \
# pendsv.c \
# gccollect.c \
# lexerfatfs.c \
# import.c \
# pyexec.c \
# led.c \
# gpio.c \
# lcd.c \
# servo.c \
# flash.c \
# storage.c \
# accel.c \
# usart.c \
# usb.c \
# timer.c \
# audio.c \
......@@ -84,24 +87,23 @@ SRC_C = \
# adc.c \
# rtc.c \
# file.c \
# pin.c \
# pin_named_pins.c \
# pin_map.c \
# exti.c \
# usrsw.c \
# pybmodule.c \
# pybwlan.c \
SRC_S = \
startup_stm32f40xx.s \
# gchelper.s \
gchelper.s \
SRC_HAL = $(addprefix $(HAL_DIR)/src/,\
stm32f4xx_hal.c \
stm32f4xx_hal_cortex.c \
stm32f4xx_hal_rcc.c \
stm32f4xx_hal_dma.c \
stm32f4xx_hal_gpio.c \
stm32f4xx_hal_rcc.c \
stm32f4xx_hal_uart.c \
)
SRC_STMPERIPH = $(addprefix $(STMPERIPH_DIR)/,\
......@@ -182,7 +184,7 @@ SRC_CC3K = $(addprefix $(CC3K_DIR)/,\
)
OBJ =
#OBJ += $(PY_O)
OBJ += $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_HAL:.c=.o))
......@@ -191,7 +193,7 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_HAL:.c=.o))
#OBJ += $(addprefix $(BUILD)/, $(SRC_STMUSBH:.c=.o))
#OBJ += $(addprefix $(BUILD)/, $(SRC_FATFS:.c=.o))
#OBJ += $(addprefix $(BUILD)/, $(SRC_CC3K:.c=.o))
#OBJ += $(BUILD)/pins_$(BOARD).o
OBJ += $(BUILD)/pins_$(BOARD).o
all: $(BUILD)/flash.dfu
......@@ -222,7 +224,12 @@ GEN_PINS_HDR = $(BUILD)/pins.h
# any of the objects. The normal dependency generation will deal with the
# case when pins.h is modified. But when it doesn't exist, we don't know
# which source files might need it.
#$(OBJ): | $(BUILD)/pins.h
$(OBJ): | $(BUILD)/pins.h
# temp hack
$(PY_BUILD):
mkdir -p $@
$(OBJ): | $(PY_BUILD) $(PY_BUILD)/qstrdefs.generated.h
# Use a pattern rule here so that make will only call make-pins.py once to make
# both pins_$(BOARD).c and pins.h
......
......@@ -2,7 +2,7 @@
#include <stdio.h>
#include <stdint.h>
#include <stm32f4xx.h>
#include <stm32f4xx_hal.h>
#include "misc.h"
#include "mpconfig.h"
......
#include <stdio.h>
#include <stm32f4xx_hal.h>
#include "misc.h"
#include "mpconfig.h"
#include "qstr.h"
#include "obj.h"
#include "gc.h"
#include "gccollect.h"
machine_uint_t gc_helper_get_regs_and_sp(machine_uint_t *regs);
// obsolete
// void gc_helper_get_regs_and_clean_stack(machine_uint_t *regs, machine_uint_t heap_end);
void gc_collect(void) {
// get current time, in case we want to time the GC
uint32_t start = HAL_GetTick();
// start the GC
gc_collect_start();
// scan everything in RAM before the heap
// this includes the data and bss segments
// TODO possibly don't need to scan data, since all pointers should start out NULL and be in bss
gc_collect_root((void**)&_ram_start, ((uint32_t)&_ebss - (uint32_t)&_ram_start) / sizeof(uint32_t));
// get the registers and the sp
machine_uint_t regs[10];
machine_uint_t sp = gc_helper_get_regs_and_sp(regs);
// trace the stack, including the registers (since they live on the stack in this function)
gc_collect_root((void**)sp, ((uint32_t)&_ram_end - sp) / sizeof(uint32_t));
// end the GC
gc_collect_end();
if (0) {
// print GC info
uint32_t ticks = HAL_GetTick() - start; // TODO implement a function that does this properly
gc_info_t info;
gc_info(&info);
printf("GC@%lu %lums\n", start, ticks);
printf(" %lu total\n", info.total);
printf(" %lu : %lu\n", info.used, info.free);
printf(" 1=%lu 2=%lu m=%lu\n", info.num_1block, info.num_2block, info.max_block);
}
}
static mp_obj_t pyb_gc(void) {
gc_collect();
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(pyb_gc_obj, pyb_gc);
// variables defining memory layout
// (these probably belong somewhere else...)
extern uint32_t _etext;
extern uint32_t _sidata;
extern uint32_t _ram_start;
extern uint32_t _sdata;
extern uint32_t _edata;
extern uint32_t _sbss;
extern uint32_t _ebss;
extern uint32_t _heap_start;
extern uint32_t _heap_end;
extern uint32_t _estack;
extern uint32_t _ram_end;
void gc_collect(void);
MP_DECLARE_CONST_FUN_OBJ(pyb_gc_obj);
.syntax unified
.cpu cortex-m4
.thumb
.text
.align 2
@ uint gc_helper_get_regs_and_sp(r0=uint regs[10])
.global gc_helper_get_regs_and_sp
.thumb
.thumb_func
.type gc_helper_get_regs_and_sp, %function
gc_helper_get_regs_and_sp:
@ store registers into given array
str r4, [r0], #4
str r5, [r0], #4
str r6, [r0], #4
str r7, [r0], #4
str r8, [r0], #4
str r9, [r0], #4
str r10, [r0], #4
str r11, [r0], #4
str r12, [r0], #4
str r13, [r0], #4
@ return the sp
mov r0, sp
bx lr
@ this next function is now obsolete
.size gc_helper_get_regs_and_clean_stack, .-gc_helper_get_regs_and_clean_stack
@ void gc_helper_get_regs_and_clean_stack(r0=uint regs[10], r1=heap_end)
.global gc_helper_get_regs_and_clean_stack
.thumb
.thumb_func
.type gc_helper_get_regs_and_clean_stack, %function
gc_helper_get_regs_and_clean_stack:
@ store registers into given array
str r4, [r0], #4
str r5, [r0], #4
str r6, [r0], #4
str r7, [r0], #4
str r8, [r0], #4
str r9, [r0], #4
str r10, [r0], #4
str r11, [r0], #4
str r12, [r0], #4
str r13, [r0], #4
@ clean the stack from given pointer up to current sp
movs r0, #0
mov r2, sp
b.n .entry
.loop:
str r0, [r1], #4
.entry:
cmp r1, r2
bcc.n .loop
bx lr
.size gc_helper_get_regs_and_clean_stack, .-gc_helper_get_regs_and_clean_stack
#include <stdint.h>
#include "misc.h"
#include "mpconfig.h"
#include "qstr.h"
#include "lexer.h"
#if 0
#include "ff.h"
#endif
mp_import_stat_t mp_import_stat(const char *path) {
#if 0
FILINFO fno;
FRESULT res = f_stat(path, &fno);
if (res == FR_OK) {
if ((fno.fattrib & AM_DIR) != 0) {
return MP_IMPORT_STAT_DIR;
} else {
return MP_IMPORT_STAT_FILE;
}
}
#endif
return MP_IMPORT_STAT_NO_EXIST;
}
#include <stdio.h>
#include <stm32f4xx_hal.h>
#include "misc.h"
#include "mpconfig.h"
#include "qstr.h"
#include "obj.h"
#include "led.h"
#include "pin.h"
#include "build/pins.h"
static const pin_obj_t *gLed[] = {
&PYB_LED1,
#if defined(PYB_LED2)
&PYB_LED2,
#if defined(PYB_LED3)
&PYB_LED3,
#if defined(PYB_LED4)
&PYB_LED4,
#endif
#endif
#endif
};
#define NUM_LEDS (sizeof(gLed) / sizeof(gLed[0]))
void led_init(void) {
/* GPIO structure */
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure I/O speed, mode, output type and pull */
GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
/* Turn off LEDs and initialize */
for (int led = 0; led < NUM_LEDS; led++) {
PYB_LED_OFF(gLed[led]);
GPIO_InitStructure.Pin = gLed[led]->pin_mask;
HAL_GPIO_Init(gLed[led]->gpio, &GPIO_InitStructure);
}
}
void led_state(pyb_led_t led, int state) {
if (led < 1 || led > NUM_LEDS) {
return;
}
const pin_obj_t *led_pin = gLed[led - 1];
if (state == 0) {
// turn LED off
PYB_LED_OFF(led_pin);
} else {
// turn LED on
PYB_LED_ON(led_pin);
}
}
void led_toggle(pyb_led_t led) {
if (led < 1 || led > NUM_LEDS) {
return;
}
const pin_obj_t *led_pin = gLed[led - 1];
GPIO_TypeDef *gpio = led_pin->gpio;
// We don't know if we're turning the LED on or off, but we don't really
// care. Just invert the state.
if (gpio->ODR & led_pin->pin_mask) {
// pin is high, make it low
gpio->BSRRH = led_pin->pin_mask;
} else {
// pin is low, make it high
gpio->BSRRL = led_pin->pin_mask;
}
}
#if 0
/******************************************************************************/
/* Micro Python bindings */
typedef struct _pyb_led_obj_t {
mp_obj_base_t base;
uint led_id;
} pyb_led_obj_t;
void led_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_led_obj_t *self = self_in;
print(env, "<LED %lu>", self->led_id);
}
mp_obj_t led_obj_on(mp_obj_t self_in) {
pyb_led_obj_t *self = self_in;
led_state(self->led_id, 1);
return mp_const_none;
}
mp_obj_t led_obj_off(mp_obj_t self_in) {
pyb_led_obj_t *self = self_in;
led_state(self->led_id, 0);
return mp_const_none;
}
mp_obj_t led_obj_toggle(mp_obj_t self_in) {
pyb_led_obj_t *self = self_in;
led_toggle(self->led_id);
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_1(led_obj_on_obj, led_obj_on);
static MP_DEFINE_CONST_FUN_OBJ_1(led_obj_off_obj, led_obj_off);
static MP_DEFINE_CONST_FUN_OBJ_1(led_obj_toggle_obj, led_obj_toggle);
static const mp_method_t led_methods[] = {
{ "on", &led_obj_on_obj },
{ "off", &led_obj_off_obj },
{ "toggle", &led_obj_toggle_obj },
{ NULL, NULL },
};
static const mp_obj_type_t led_obj_type = {
{ &mp_type_type },
.name = MP_QSTR_Led,
.print = led_obj_print,
.methods = led_methods,
};
static mp_obj_t pyb_Led(mp_obj_t led_id) {
pyb_led_obj_t *o = m_new_obj(pyb_led_obj_t);
o->base.type = &led_obj_type;
o->led_id = mp_obj_get_int(led_id);
return o;
}
MP_DEFINE_CONST_FUN_OBJ_1(pyb_Led_obj, pyb_Led);
#endif
typedef enum {
// PYBv3
PYB_LED_R1 = 1,
PYB_LED_R2 = 2,
PYB_LED_G1 = 3,
PYB_LED_G2 = 4,
// PYBv4
PYB_LED_RED = 1,
PYB_LED_GREEN = 2,
PYB_LED_YELLOW = 3,
PYB_LED_BLUE = 4,
//STM32F4DISC
PYB_LED_R = 1,
PYB_LED_G = 2,
PYB_LED_B = 3,
PYB_LED_O = 4,
} pyb_led_t;
void led_init(void);
void led_state(pyb_led_t led, int state);
void led_toggle(pyb_led_t led);
#if 0
MP_DECLARE_CONST_FUN_OBJ(pyb_Led_obj);
#endif
#include <stdint.h>
#include <stdio.h>
#if 0
#include "ff.h"
#endif
#include "misc.h"
#include "mpconfig.h"
#include "qstr.h"
#include "lexer.h"
#include "lexerfatfs.h"
#if 0
typedef struct _mp_lexer_file_buf_t {
FIL fp;
char buf[20];
uint16_t len;
uint16_t pos;
} mp_lexer_file_buf_t;
static unichar file_buf_next_char(mp_lexer_file_buf_t *fb) {
if (fb->pos >= fb->len) {
if (fb->len < sizeof(fb->buf)) {
return MP_LEXER_CHAR_EOF;
} else {
UINT n;
f_read(&fb->fp, fb->buf, sizeof(fb->buf), &n);
if (n == 0) {
return MP_LEXER_CHAR_EOF;
}
fb->len = n;
fb->pos = 0;
}
}
return fb->buf[fb->pos++];
}
static void file_buf_close(mp_lexer_file_buf_t *fb) {
f_close(&fb->fp);
m_del_obj(mp_lexer_file_buf_t, fb);
}
#endif
mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
#if 0
mp_lexer_file_buf_t *fb = m_new_obj(mp_lexer_file_buf_t);
FRESULT res = f_open(&fb->fp, filename, FA_READ);
if (res != FR_OK) {
m_del_obj(mp_lexer_file_buf_t, fb);
return NULL;
}
UINT n;
f_read(&fb->fp, fb->buf, sizeof(fb->buf), &n);
fb->len = n;
fb->pos = 0;
return mp_lexer_new(qstr_from_str(filename), fb, (mp_lexer_stream_next_char_t)file_buf_next_char, (mp_lexer_stream_close_t)file_buf_close);
#else
return NULL;
#endif
}
mp_lexer_t *mp_lexer_new_from_file(const char *filename);
......@@ -15,19 +15,18 @@
#include <stm32f4xx_usart.h>
#include <stm32f4xx_rng.h>
#include <usbd_storage_msd.h>
#include <stm_misc.h>
#endif
#include "std.h"
#if 0
#include "misc.h"
#include "ff.h"
#include "systick.h"
#include "led.h"
#include "usart.h"
#include "mpconfig.h"
#include "qstr.h"
#include "nlr.h"
#include "misc.h"
#include "lexer.h"
#include "lexerfatfs.h"
#include "parse.h"
#include "obj.h"
#include "parsehelper.h"
......@@ -36,10 +35,12 @@
#include "runtime.h"
#include "gc.h"
#include "gccollect.h"
#include "systick.h"
#include "pendsv.h"
#include "pyexec.h"
#include "led.h"
#include "pybmodule.h"
#if 0
#include "ff.h"
#include "lexerfatfs.h"
#include "pendsv.h"
#include "servo.h"
#include "lcd.h"
#include "storage.h"
......@@ -53,9 +54,11 @@
#include "file.h"
#include "pin.h"
#include "exti.h"
#include "pybmodule.h"
#endif
void SystemClock_Config(void);
int errno;
#if 0
......@@ -65,7 +68,6 @@ static FATFS fatfs1;
#endif
#endif
#if 0
void flash_error(int n) {
for (int i = 0; i < n; i++) {
led_state(PYB_LED_R1, 1);
......@@ -87,9 +89,7 @@ void __fatal_error(const char *msg) {
flash_error(1);
}
}
#endif
#if 0
STATIC mp_obj_t pyb_config_source_dir = MP_OBJ_NULL;
STATIC mp_obj_t pyb_config_main = MP_OBJ_NULL;
......@@ -161,93 +161,6 @@ static mp_obj_t pyb_help(void) {
printf("%s", help_text);
return mp_const_none;
}
#endif
void led_init(void) {
/* GPIO structure */
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure I/O speed, mode, output type and pull */
GPIO_InitStructure.Pin = GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
GPIO_InitStructure.Alternate = 0; // unused
/* initialize */
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void led_state(int led_id, int state) {
HAL_GPIO_WritePin(GPIOA, 1 << (13 + led_id), state);
}
/**
* @brief System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL (HSE)
* SYSCLK(Hz) = 168000000
* HCLK(Hz) = 168000000
* AHB Prescaler = 1
* APB1 Prescaler = 4
* APB2 Prescaler = 2
* HSE Frequency(Hz) = 8000000
* PLL_M = 8
* PLL_N = 336
* PLL_P = 2
* PLL_Q = 7
* VDD(V) = 3.3
* Main regulator output voltage = Scale1 mode
* Flash Latency(WS) = 5
* @param None
* @retval None
*/
static void SystemClock_Config(void) {
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
/* Enable Power Control clock */
__PWR_CLK_ENABLE();
/* The voltage scaling allows optimizing the power consumption when the device is
clocked below the maximum system frequency, to update the voltage scaling value
regarding system frequency refer to product datasheet. */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
/* Initialization Error */
for (;;) {
}
}
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
/* Initialization Error */
for (;;) {
}
}
// Make SysTick interrupt have the highest priority
// This is needed so that SysTick runs in all ISRs.
NVIC_SetPriority(SysTick_IRQn, 0);
}
int main(void) {
// TODO disable JTAG
......@@ -279,15 +192,13 @@ int main(void) {
led_state(1, 0);
led_state(2, 1);
#if 0
for (;;) {
HAL_Delay(500);
led_state(1, 1);
HAL_Delay(500);
led_state(1, 0);
}
#if 0
_fatal_error("done");
#endif
#if 0
......@@ -328,29 +239,57 @@ int main(void) {
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_SET);
}
#endif
#endif
// basic sub-system init
sys_tick_init();
#if 0
pendsv_init();
#endif
led_init();
#if 0
#if MICROPY_HW_ENABLE_RTC
rtc_init();
#endif
#endif
// turn on LED to indicate bootup
led_state(PYB_LED_G1, 1);
#if 0
// more sub-system init
#if MICROPY_HW_HAS_SDCARD
sdcard_init();
#endif
storage_init();
#endif
// uncomment these 2 lines if you want REPL on USART_6 (or another usart) as well as on USB VCP
//pyb_usart_global_debug = PYB_USART_YA;
//usart_init(pyb_usart_global_debug, 115200);
pyb_usart_global_debug = PYB_USART_YA;
usart_init(pyb_usart_global_debug, 115200);
#if 0
pyb_led_t led = 1;
while (1) {
led_state(led, 1);
usart_tx_strn_cooked(pyb_usart_global_debug, "on\n", 3);
sys_tick_delay_ms(100);
led_state(led, 0);
usart_tx_strn_cooked(pyb_usart_global_debug, "off\n", 4);
sys_tick_delay_ms(100);
led_state(led, 1);
usart_tx_strn_cooked(pyb_usart_global_debug, "on\n", 3);
sys_tick_delay_ms(100);
led_state(led, 0);
usart_tx_strn_cooked(pyb_usart_global_debug, "off\n", 4);
sys_tick_delay_ms(700);
led = (led % 4) + 1;
}
__fatal_error("done");
#endif
int first_soft_reset = true;
......@@ -368,6 +307,7 @@ soft_reset:
def_path[2] = MP_OBJ_NEW_QSTR(MP_QSTR_0_colon__slash_lib);
sys_path = mp_obj_new_list(3, def_path);
#if 0
exti_init();
#if MICROPY_HW_HAS_SWITCH
......@@ -396,15 +336,19 @@ soft_reset:
#endif
pin_map_init();
#endif
// add some functions to the builtin Python namespace
rt_store_name(MP_QSTR_help, rt_make_function_n(0, pyb_help));
#if 0
rt_store_name(MP_QSTR_open, rt_make_function_n(2, pyb_io_open));
#endif
// we pre-import the pyb module
// probably shouldn't do this, so we are compatible with CPython
rt_store_name(MP_QSTR_pyb, (mp_obj_t)&pyb_module);
#if 0
// check if user switch held (initiates reset of filesystem)
bool reset_filesystem = false;
#if MICROPY_HW_HAS_SWITCH
......@@ -497,16 +441,20 @@ soft_reset:
flash_error(4);
}
#endif
if (first_soft_reset) {
#if 0
#if MICROPY_HW_HAS_MMA7660
// MMA accel: init and reset address to zero
accel_init();
#endif
#endif
}
// turn boot-up LED off
led_state(PYB_LED_G1, 0);
#if 0
#if MICROPY_HW_HAS_SDCARD
// if an SD card is present then mount it on 1:/
if (sdcard_is_present()) {
......@@ -591,16 +539,18 @@ soft_reset:
// wifi
pyb_wlan_init();
pyb_wlan_start();
#endif
#endif
pyexec_repl();
#if 0
printf("PYB: sync filesystems\n");
storage_flush();
#endif
printf("PYB: soft reboot\n");
first_soft_reset = false;
goto soft_reset;
#endif
}
#include <stdint.h>
#include "std.h"
#include "mpconfig.h"
#include "gc.h"
#if 0
static uint32_t mem = 0;
void *malloc(size_t n) {
if (mem == 0) {
extern uint32_t _heap_start;
mem = (uint32_t)&_heap_start; // need to use big ram block so we can execute code from it (is it true that we can't execute from CCM?)
}
void *ptr = (void*)mem;
mem = (mem + n + 3) & (~3);
if (mem > 0x20000000 + 0x18000) {
void __fatal_error(const char*);
__fatal_error("out of memory");
}
return ptr;
}
void free(void *ptr) {
}
void *realloc(void *ptr, size_t n) {
return malloc(n);
}
#endif
void __assert_func(void) {
printf("\nASSERT FAIL!");
for (;;) {
}
}
#include <stdint.h>
#include <math.h>
// these 2 functions seem to actually work... no idea why
// replacing with libgcc does not work (probably due to wrong calling conventions)
double __aeabi_f2d(float x) {
// TODO
return 0.0;
}
float __aeabi_d2f(double x) {
// TODO
return 0.0;
}
/*
double sqrt(double x) {
// TODO
return 0.0;
}
*/
float sqrtf(float x) {
asm volatile (
"vsqrt.f32 %[r], %[x]\n"
: [r] "=t" (x)
: [x] "t" (x));
return x;
}
// TODO we need import these functions from some library (eg musl or newlib)
float powf(float x, float y) { return 0.0; }
float logf(float x) { return 0.0; }
float log2f(float x) { return 0.0; }
float log10f(float x) { return 0.0; }
float tanhf(float x) { return 0.0; }
float acoshf(float x) { return 0.0; }
float asinhf(float x) { return 0.0; }
float atanhf(float x) { return 0.0; }
float cosf(float x) { return 0.0; }
float sinf(float x) { return 0.0; }
float tanf(float x) { return 0.0; }
float acosf(float x) { return 0.0; }
float asinf(float x) { return 0.0; }
float atanf(float x) { return 0.0; }
float atan2f(float x, float y) { return 0.0; }
/*****************************************************************************/
// from musl-0.9.15 libm.h
/* origin: FreeBSD /usr/src/lib/msun/src/math_private.h */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
#define FORCE_EVAL(x) do { \
if (sizeof(x) == sizeof(float)) { \
volatile float __x; \
__x = (x); \
(void)__x; \
} else if (sizeof(x) == sizeof(double)) { \
volatile double __x; \
__x = (x); \
(void)__x; \
} else { \
volatile long double __x; \
__x = (x); \
(void)__x; \
} \
} while(0)
/* Get a 32 bit int from a float. */
#define GET_FLOAT_WORD(w,d) \
do { \
union {float f; uint32_t i;} __u; \
__u.f = (d); \
(w) = __u.i; \
} while (0)
/* Set a float from a 32 bit int. */
#define SET_FLOAT_WORD(d,w) \
do { \
union {float f; uint32_t i;} __u; \
__u.i = (w); \
(d) = __u.f; \
} while (0)
/*****************************************************************************/
// scalbnf from musl-0.9.15
float scalbnf(float x, int n)
{
union {float f; uint32_t i;} u;
float_t y = x;
if (n > 127) {
y *= 0x1p127f;
n -= 127;
if (n > 127) {
y *= 0x1p127f;
n -= 127;
if (n > 127)
n = 127;
}
} else if (n < -126) {
y *= 0x1p-126f;
n += 126;
if (n < -126) {
y *= 0x1p-126f;
n += 126;
if (n < -126)
n = -126;
}
}
u.i = (uint32_t)(0x7f+n)<<23;
x = y * u.f;
return x;
}
/*****************************************************************************/
// expf from musl-0.9.15
/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
static const float
half[2] = {0.5,-0.5},
ln2hi = 6.9314575195e-1f, /* 0x3f317200 */
ln2lo = 1.4286067653e-6f, /* 0x35bfbe8e */
invln2 = 1.4426950216e+0f, /* 0x3fb8aa3b */
/*
* Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]:
* |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74
*/
P1 = 1.6666625440e-1f, /* 0xaaaa8f.0p-26 */
P2 = -2.7667332906e-3f; /* -0xb55215.0p-32 */
float expf(float x)
{
float_t hi, lo, c, xx, y;
int k, sign;
uint32_t hx;
GET_FLOAT_WORD(hx, x);
sign = hx >> 31; /* sign bit of x */
hx &= 0x7fffffff; /* high word of |x| */
/* special cases */
if (hx >= 0x42aeac50) { /* if |x| >= -87.33655f or NaN */
if (hx >= 0x42b17218 && !sign) { /* x >= 88.722839f */
/* overflow */
x *= 0x1p127f;
return x;
}
if (sign) {
/* underflow */
FORCE_EVAL(-0x1p-149f/x);
if (hx >= 0x42cff1b5) /* x <= -103.972084f */
return 0;
}
}
/* argument reduction */
if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */
if (hx > 0x3f851592) /* if |x| > 1.5 ln2 */
k = invln2*x + half[sign];
else
k = 1 - sign - sign;
hi = x - k*ln2hi; /* k*ln2hi is exact here */
lo = k*ln2lo;
x = hi - lo;
} else if (hx > 0x39000000) { /* |x| > 2**-14 */
k = 0;
hi = x;
lo = 0;
} else {
/* raise inexact */
FORCE_EVAL(0x1p127f + x);
return 1 + x;
}
/* x is now in primary range */
xx = x*x;
c = x - xx*(P1+xx*P2);
y = 1 + (x*c/(2-c) - lo + hi);
if (k == 0)
return y;
return scalbnf(y, k);
}
/*****************************************************************************/
// expm1f from musl-0.9.15
/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
static const float
o_threshold = 8.8721679688e+01, /* 0x42b17180 */
ln2_hi = 6.9313812256e-01, /* 0x3f317180 */
ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */
//invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */
/*
* Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]:
* |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04
* Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c):
*/
Q1 = -3.3333212137e-2, /* -0x888868.0p-28 */
Q2 = 1.5807170421e-3; /* 0xcf3010.0p-33 */
float expm1f(float x)
{
float_t y,hi,lo,c,t,e,hxs,hfx,r1,twopk;
union {float f; uint32_t i;} u = {x};
uint32_t hx = u.i & 0x7fffffff;
int k, sign = u.i >> 31;
/* filter out huge and non-finite argument */
if (hx >= 0x4195b844) { /* if |x|>=27*ln2 */
if (hx > 0x7f800000) /* NaN */
return x;
if (sign)
return -1;
if (x > o_threshold) {
x *= 0x1p127f;
return x;
}
}
/* argument reduction */
if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */
if (hx < 0x3F851592) { /* and |x| < 1.5 ln2 */
if (!sign) {
hi = x - ln2_hi;
lo = ln2_lo;
k = 1;
} else {
hi = x + ln2_hi;
lo = -ln2_lo;
k = -1;
}
} else {
k = invln2*x + (sign ? -0.5f : 0.5f);
t = k;
hi = x - t*ln2_hi; /* t*ln2_hi is exact here */
lo = t*ln2_lo;
}
x = hi-lo;
c = (hi-x)-lo;
} else if (hx < 0x33000000) { /* when |x|<2**-25, return x */
if (hx < 0x00800000)
FORCE_EVAL(x*x);
return x;
} else
k = 0;
/* x is now in primary range */
hfx = 0.5f*x;
hxs = x*hfx;
r1 = 1.0f+hxs*(Q1+hxs*Q2);
t = 3.0f - r1*hfx;
e = hxs*((r1-t)/(6.0f - x*t));
if (k == 0) /* c is 0 */
return x - (x*e-hxs);
e = x*(e-c) - c;
e -= hxs;
/* exp(x) ~ 2^k (x_reduced - e + 1) */
if (k == -1)
return 0.5f*(x-e) - 0.5f;
if (k == 1) {
if (x < -0.25f)
return -2.0f*(e-(x+0.5f));
return 1.0f + 2.0f*(x-e);
}
u.i = (0x7f+k)<<23; /* 2^k */
twopk = u.f;
if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */
y = x - e + 1.0f;
if (k == 128)
y = y*2.0f*0x1p127f;
else
y = y*twopk;
return y - 1.0f;
}
u.i = (0x7f-k)<<23; /* 2^-k */
if (k < 23)
y = (x-e+(1-u.f))*twopk;
else
y = (x-(e+u.f)+1)*twopk;
return y;
}
/*****************************************************************************/
// __expo2f from musl-0.9.15
/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */
static const int k = 235;
static const float kln2 = 0x1.45c778p+7f;
/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */
float __expo2f(float x)
{
float scale;
/* note that k is odd and scale*scale overflows */
SET_FLOAT_WORD(scale, (uint32_t)(0x7f + k/2) << 23);
/* exp(x - k ln2) * 2**(k-1) */
return expf(x - kln2) * scale * scale;
}
/*****************************************************************************/
// coshf from musl-0.9.15
float coshf(float x)
{
union {float f; uint32_t i;} u = {.f = x};
uint32_t w;
float t;
/* |x| */
u.i &= 0x7fffffff;
x = u.f;
w = u.i;
/* |x| < log(2) */
if (w < 0x3f317217) {
if (w < 0x3f800000 - (12<<23)) {
FORCE_EVAL(x + 0x1p120f);
return 1;
}
t = expm1f(x);
return 1 + t*t/(2*(1+t));
}
/* |x| < log(FLT_MAX) */
if (w < 0x42b17217) {
t = expf(x);
return 0.5f*(t + 1/t);
}
/* |x| > log(FLT_MAX) or nan */
t = __expo2f(x);
return t;
}
/*****************************************************************************/
// sinhf from musl-0.9.15
float sinhf(float x)
{
union {float f; uint32_t i;} u = {.f = x};
uint32_t w;
float t, h, absx;
h = 0.5;
if (u.i >> 31)
h = -h;
/* |x| */
u.i &= 0x7fffffff;
absx = u.f;
w = u.i;
/* |x| < log(FLT_MAX) */
if (w < 0x42b17217) {
t = expm1f(absx);
if (w < 0x3f800000) {
if (w < 0x3f800000 - (12<<23))
return x;
return h*(2*t - t*t/(t+1));
}
return h*(t + t/(t+1));
}
/* |x| > logf(FLT_MAX) or nan */
t = 2*h*__expo2f(absx);
return t;
}
#include <stdint.h>
// options to control how Micro Python is built
#define MICROPY_EMIT_THUMB (1)
#define MICROPY_EMIT_INLINE_THUMB (1)
#define MICROPY_ENABLE_GC (1)
#define MICROPY_ENABLE_REPL_HELPERS (1)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
#define MICROPY_PATH_MAX (128)
/* Enable FatFS LFNs
0: Disable LFN feature.
1: Enable LFN with static working buffer on the BSS. Always NOT reentrant.
2: Enable LFN with dynamic working buffer on the STACK.
3: Enable LFN with dynamic working buffer on the HEAP.
*/
#define MICROPY_ENABLE_LFN (0)
#define MICROPY_LFN_CODE_PAGE (1) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
// type definitions for the specific machine
#define BYTES_PER_WORD (4)
#define UINT_FMT "%lu"
#define INT_FMT "%ld"
typedef int32_t machine_int_t; // must be pointer size
typedef uint32_t machine_uint_t; // must be pointer size
typedef void *machine_ptr_t; // must be of pointer size
typedef const void *machine_const_ptr_t; // must be of pointer size
// There is no classical C heap in bare-metal ports, only Python
// garbage-collected heap. For completeness, emulate C heap via
// GC heap. Note that MicroPython core never uses malloc() and friends,
// so these defines are mostly to help extension module writers.
#define malloc gc_alloc
#define free gc_free
#define realloc gc_realloc
// board specific definitions
#include "mpconfigboard.h"
#define STM32F40_41xxx
#define USE_STDPERIPH_DRIVER
#if !defined(HSE_VALUE)
#define HSE_VALUE (8000000)
#endif
#define USE_DEVICE_MODE
//#define USE_HOST_MODE
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stm32f4xx_hal.h>
#include "misc.h"
#include "mpconfig.h"
#include "qstr.h"
#include "obj.h"
#include "pin.h"
#if 0
void pin_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
pin_obj_t *self = self_in;
print(env, "<Pin %s>", self->name);
}
mp_obj_t pin_obj_name(mp_obj_t self_in) {
pin_obj_t *self = self_in;
return MP_OBJ_NEW_QSTR(qstr_from_str(self->name));
}
mp_obj_t pin_obj_port(mp_obj_t self_in) {
pin_obj_t *self = self_in;
return MP_OBJ_NEW_SMALL_INT((mp_small_int_t)self->port);
}
mp_obj_t pin_obj_pin(mp_obj_t self_in) {
pin_obj_t *self = self_in;
return MP_OBJ_NEW_SMALL_INT((mp_small_int_t)self->pin);
}
static MP_DEFINE_CONST_FUN_OBJ_1(pin_obj_name_obj, pin_obj_name);
static MP_DEFINE_CONST_FUN_OBJ_1(pin_obj_port_obj, pin_obj_port);
static MP_DEFINE_CONST_FUN_OBJ_1(pin_obj_pin_obj, pin_obj_pin);
static const mp_method_t pin_methods[] = {
{ "name", &pin_obj_name_obj },
{ "port", &pin_obj_port_obj },
{ "pin", &pin_obj_pin_obj },
{ NULL, NULL },
};
#endif
const mp_obj_type_t pin_obj_type = {
#if 0
{ &mp_type_type },
#else
{ NULL },
#endif
.name = MP_QSTR_Pin,
#if 0
.print = pin_obj_print,
.methods = pin_methods,
#endif
};
#if 0
void pin_af_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
pin_af_obj_t *self = self_in;
print(env, "<Pin AF %d fn:%d unit:%d typ:%d>", self->idx, self->fn,
self->unit, self->type);
}
#endif
const mp_obj_type_t pin_af_obj_type = {
#if 0
{ &mp_type_type },
#else
{ NULL },
#endif
.name = MP_QSTR_PinAF,
#if 0
.print = pin_af_obj_print,
#endif
};
enum {
PORT_A,
PORT_B,
PORT_C,
PORT_D,
PORT_E,
PORT_F,
PORT_G,
PORT_H,
PORT_I,
PORT_J,
};
enum {
AF_FN_TIM,
AF_FN_I2C,
AF_FN_USART,
AF_FN_UART = AF_FN_USART,
AF_FN_SPI
};
enum {
AF_PIN_TYPE_TIM_CH1 = 0,
AF_PIN_TYPE_TIM_CH2,
AF_PIN_TYPE_TIM_CH3,
AF_PIN_TYPE_TIM_CH4,
AF_PIN_TYPE_TIM_CH1N,
AF_PIN_TYPE_TIM_CH2N,
AF_PIN_TYPE_TIM_CH3N,
AF_PIN_TYPE_TIM_CH1_ETR,
AF_PIN_TYPE_TIM_ETR,
AF_PIN_TYPE_TIM_BKIN,
AF_PIN_TYPE_I2C_SDA = 0,
AF_PIN_TYPE_I2C_SCL,
AF_PIN_TYPE_USART_TX = 0,
AF_PIN_TYPE_USART_RX,
AF_PIN_TYPE_USART_CTS,
AF_PIN_TYPE_USART_RTS,
AF_PIN_TYPE_USART_CK,
AF_PIN_TYPE_UART_TX = AF_PIN_TYPE_USART_TX,
AF_PIN_TYPE_UART_RX = AF_PIN_TYPE_USART_RX,
AF_PIN_TYPE_UART_CTS = AF_PIN_TYPE_USART_CTS,
AF_PIN_TYPE_UART_RTS = AF_PIN_TYPE_USART_RTS,
AF_PIN_TYPE_SPI_MOSI = 0,
AF_PIN_TYPE_SPI_MISO,
AF_PIN_TYPE_SPI_SCK,
AF_PIN_TYPE_SPI_NSS,
};
typedef struct {
mp_obj_base_t base;
uint8_t idx;
uint8_t fn;
uint8_t unit;
uint8_t type;
union {
void *reg;
TIM_TypeDef *TIM;
I2C_TypeDef *I2C;
USART_TypeDef *USART;
USART_TypeDef *UART;
SPI_TypeDef *SPI;
};
} pin_af_obj_t;
typedef struct {
mp_obj_base_t base;
const char *name;
uint16_t port : 4;
uint16_t pin : 4;
uint16_t num_af : 4;
uint16_t pin_mask;
GPIO_TypeDef *gpio;
const pin_af_obj_t *af;
} pin_obj_t;
extern const mp_obj_type_t pin_obj_type;
extern const mp_obj_type_t pin_af_obj_type;
typedef struct {
const char *name;
const pin_obj_t *pin;
} pin_named_pin_t;
extern const pin_named_pin_t pin_board_pins[];
extern const pin_named_pin_t pin_cpu_pins[];
typedef struct {
mp_obj_base_t base;
mp_obj_t mapper;
mp_obj_t map_dict;
bool debug;
} pin_map_obj_t;
extern pin_map_obj_t pin_map_obj;
typedef struct {
mp_obj_base_t base;
const char *name;
const pin_named_pin_t *named_pins;
} pin_named_pins_obj_t;
extern const pin_named_pins_obj_t pin_board_pins_obj;
extern const pin_named_pins_obj_t pin_cpu_pins_obj;
const pin_obj_t *pin_find_named_pin(const pin_named_pin_t *pins, const char *name);
const pin_af_obj_t *pin_find_af(const pin_obj_t *pin, uint8_t fn, uint8_t unit, uint8_t pin_type);
void pin_map_init(void);
// C function for mapping python pin identifier into an ordinal pin number.
const pin_obj_t *pin_map_user_obj(mp_obj_t user_obj);
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include "std.h"
#include "misc.h"
#include "systick.h"
#include "mpconfig.h"
#include "qstr.h"
#include "obj.h"
#if 0
#include "lcd.h"
#endif
#include "usart.h"
#if 0
#include "usb.h"
#endif
#if MICROPY_ENABLE_FLOAT
#include "formatfloat.h"
#endif
#define PF_FLAG_LEFT_ADJUST (0x01)
#define PF_FLAG_SHOW_SIGN (0x02)
#define PF_FLAG_SPACE_SIGN (0x04)
#define PF_FLAG_NO_TRAILZ (0x08)
#define PF_FLAG_ZERO_PAD (0x10)
// tricky; we compute pad string by: pad_chars + (flags & PF_FLAG_ZERO_PAD)
#define PF_PAD_SIZE PF_FLAG_ZERO_PAD
static const char *pad_chars = " 0000000000000000";
typedef struct _pfenv_t {
void *data;
void (*print_strn)(void *, const char *str, unsigned int len);
} pfenv_t;
static void print_str_dummy(void *data, const char *str, unsigned int len) {
}
const pfenv_t pfenv_dummy = {0, print_str_dummy};
static int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, int flags, int width) {
int pad = width - len;
if (pad > 0 && (flags & PF_FLAG_LEFT_ADJUST) == 0) {
while (pad > 0) {
int p = pad;
if (p > PF_PAD_SIZE)
p = PF_PAD_SIZE;
pfenv->print_strn(pfenv->data, pad_chars + (flags & PF_FLAG_ZERO_PAD), p);
pad -= p;
}
}
pfenv->print_strn(pfenv->data, str, len);
while (pad > 0) {
int p = pad;
if (p > PF_PAD_SIZE)
p = PF_PAD_SIZE;
pfenv->print_strn(pfenv->data, pad_chars, p);
pad -= p;
}
return len;
}
// enough room for 32 signed number
#define INT_BUF_SIZE (12)
static int pfenv_print_int(const pfenv_t *pfenv, unsigned int x, int sgn, int base, int base_char, int flags, int width) {
char sign = 0;
if (sgn) {
if ((int)x < 0) {
sign = '-';
x = -x;
} else if (flags & PF_FLAG_SHOW_SIGN) {
sign = '+';
} else if (flags & PF_FLAG_SPACE_SIGN) {
sign = ' ';
}
}
char buf[INT_BUF_SIZE];
char *b = buf + INT_BUF_SIZE;
if (x == 0) {
*(--b) = '0';
} else {
do {
int c = x % base;
x /= base;
if (c >= 10) {
c += base_char - 10;
} else {
c += '0';
}
*(--b) = c;
} while (b > buf && x != 0);
}
if (b > buf && sign != 0) {
*(--b) = sign;
}
return pfenv_print_strn(pfenv, b, buf + INT_BUF_SIZE - b, flags, width);
}
void pfenv_prints(const pfenv_t *pfenv, const char *str) {
pfenv->print_strn(pfenv->data, str, strlen(str));
}
int pfenv_printf(const pfenv_t *pfenv, const char *fmt, va_list args) {
int chrs = 0;
for (;;) {
{
const char *f = fmt;
while (*f != '\0' && *f != '%') {
++f; // XXX UTF8 advance char
}
if (f > fmt) {
pfenv->print_strn(pfenv->data, fmt, f - fmt);
chrs += f - fmt;
fmt = f;
}
}
if (*fmt == '\0') {
break;
}
// move past % character
++fmt;
// parse flags, if they exist
int flags = 0;
while (*fmt != '\0') {
if (*fmt == '-') flags |= PF_FLAG_LEFT_ADJUST;
else if (*fmt == '+') flags |= PF_FLAG_SHOW_SIGN;
else if (*fmt == ' ') flags |= PF_FLAG_SPACE_SIGN;
else if (*fmt == '!') flags |= PF_FLAG_NO_TRAILZ;
else if (*fmt == '0') flags |= PF_FLAG_ZERO_PAD;
else break;
++fmt;
}
// parse width, if it exists
int width = 0;
for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {
width = width * 10 + *fmt - '0';
}
// parse precision, if it exists
int prec = -1;
if (*fmt == '.') {
++fmt;
if (*fmt == '*') {
++fmt;
prec = va_arg(args, int);
} else {
prec = 0;
for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {
prec = prec * 10 + *fmt - '0';
}
}
if (prec < 0) {
prec = 0;
}
}
// parse long specifiers (current not used)
//bool long_arg = false;
if (*fmt == 'l') {
++fmt;
//long_arg = true;
}
if (*fmt == '\0') {
break;
}
switch (*fmt) {
case 'b':
if (va_arg(args, int)) {
chrs += pfenv_print_strn(pfenv, "true", 4, flags, width);
} else {
chrs += pfenv_print_strn(pfenv, "false", 5, flags, width);
}
break;
case 'c':
{
char str = va_arg(args, int);
chrs += pfenv_print_strn(pfenv, &str, 1, flags, width);
break;
}
case 's':
{
const char *str = va_arg(args, const char*);
if (str) {
if (prec < 0) {
prec = strlen(str);
}
chrs += pfenv_print_strn(pfenv, str, prec, flags, width);
} else {
chrs += pfenv_print_strn(pfenv, "(null)", 6, flags, width);
}
break;
}
case 'u':
chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 10, 'a', flags, width);
break;
case 'd':
chrs += pfenv_print_int(pfenv, va_arg(args, int), 1, 10, 'a', flags, width);
break;
case 'x':
case 'p': // ?
chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'a', flags, width);
break;
case 'X':
case 'P': // ?
chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'A', flags, width);
break;
#if MICROPY_ENABLE_FLOAT
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
{
char buf[32];
char sign = '\0';
if (flags & PF_FLAG_SHOW_SIGN) {
sign = '+';
}
else
if (flags & PF_FLAG_SPACE_SIGN) {
sign = ' ';
}
float f = va_arg(args, double);
int len = format_float(f, buf, sizeof(buf), *fmt, prec, sign);
char *s = buf;
// buf[0] < '0' returns true if the first character is space, + or -
// buf[1] < '9' matches a digit, and doesn't match when we get back +nan or +inf
if (buf[0] < '0' && buf[1] <= '9' && (flags & PF_FLAG_ZERO_PAD)) {
chrs += pfenv_print_strn(pfenv, &buf[0], 1, 0, 1);
s++;
width--;
len--;
}
if (*s < '0' || *s >= '9') {
// For inf or nan, we don't want to zero pad.
flags &= ~PF_FLAG_ZERO_PAD;
}
chrs += pfenv_print_strn(pfenv, s, len, flags, width);
break;
}
#endif
default:
pfenv->print_strn(pfenv->data, fmt, 1);
chrs += 1;
break;
}
++fmt;
}
return chrs;
}
void stdout_print_strn(void *data, const char *str, unsigned int len) {
// send stdout to USART, USB CDC VCP, and LCD if nothing else
bool any = false;
if (pyb_usart_global_debug != PYB_USART_NONE) {
usart_tx_strn_cooked(pyb_usart_global_debug, str, len);
any = true;
}
#if 0
if (usb_vcp_is_enabled()) {
usb_vcp_send_strn_cooked(str, len);
any = true;
}
#endif
if (!any) {
#if 0
#if MICROPY_HW_HAS_LCD
lcd_print_strn(str, len);
#endif
#endif
}
}
static const pfenv_t pfenv_stdout = {0, stdout_print_strn};
int printf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int ret = pfenv_printf(&pfenv_stdout, fmt, ap);
va_end(ap);
return ret;
}
int vprintf(const char *fmt, va_list ap) {
return pfenv_printf(&pfenv_stdout, fmt, ap);
}
#if MICROPY_DEBUG_PRINTERS
int DEBUG_printf(const char *fmt, ...) {
(void)stream;
va_list ap;
va_start(ap, fmt);
int ret = pfenv_printf(&pfenv_stdout, fmt, ap);
va_end(ap);
return ret;
}
#endif
// need this because gcc optimises printf("%c", c) -> putchar(c), and printf("a") -> putchar('a')
int putchar(int c) {
char chr = c;
stdout_print_strn(0, &chr, 1);
return chr;
}
// need this because gcc optimises printf("string\n") -> puts("string")
int puts(const char *s) {
stdout_print_strn(0, s, strlen(s));
char chr = '\n';
stdout_print_strn(0, &chr, 1);
return 1;
}
typedef struct _strn_pfenv_t {
char *cur;
size_t remain;
} strn_pfenv_t;
void strn_print_strn(void *data, const char *str, unsigned int len) {
strn_pfenv_t *strn_pfenv = data;
if (len > strn_pfenv->remain) {
len = strn_pfenv->remain;
}
memcpy(strn_pfenv->cur, str, len);
strn_pfenv->cur += len;
strn_pfenv->remain -= len;
}
int vsnprintf(char *str, size_t size, const char *fmt, va_list ap) {
strn_pfenv_t strn_pfenv;
strn_pfenv.cur = str;
strn_pfenv.remain = size;
pfenv_t pfenv;
pfenv.data = &strn_pfenv;
pfenv.print_strn = strn_print_strn;
int len = pfenv_printf(&pfenv, fmt, ap);
// add terminating null byte
if (size > 0) {
if (strn_pfenv.remain == 0) {
strn_pfenv.cur[-1] = 0;
} else {
strn_pfenv.cur[0] = 0;
}
}
return len;
}
int snprintf(char *str, size_t size, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int ret = vsnprintf(str, size, fmt, ap);
va_end(ap);
return ret;
}
#include <stdint.h>
#include <stdio.h>
#include <stm32f4xx_hal.h>
#include "misc.h"
#if 0
#include "ff.h"
#endif
#include "mpconfig.h"
#include "qstr.h"
#include "obj.h"
#include "map.h"
#include "gc.h"
#include "gccollect.h"
#include "systick.h"
#include "pyexec.h"
#if 0
#include "rtc.h"
#include "servo.h"
#include "storage.h"
#include "usb.h"
#include "usrsw.h"
#include "sdcard.h"
#include "accel.h"
#include "led.h"
#include "i2c.h"
#include "usart.h"
#include "adc.h"
#include "audio.h"
#include "pin.h"
#include "gpio.h"
#include "exti.h"
#endif
#include "pybmodule.h"
// get lots of info about the board
STATIC mp_obj_t pyb_info(void) {
// get and print unique id; 96 bits
{
byte *id = (byte*)0x1fff7a10;
printf("ID=%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x\n", id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], id[9], id[10], id[11]);
}
// get and print clock speeds
// SYSCLK=168MHz, HCLK=168MHz, PCLK1=42MHz, PCLK2=84MHz
{
printf("S=%lu\nH=%lu\nP1=%lu\nP2=%lu\n",
HAL_RCC_GetSysClockFreq(),
HAL_RCC_GetHCLKFreq(),
HAL_RCC_GetPCLK1Freq(),
HAL_RCC_GetPCLK2Freq());
}
// to print info about memory
{
printf("_etext=%p\n", &_etext);
printf("_sidata=%p\n", &_sidata);
printf("_sdata=%p\n", &_sdata);
printf("_edata=%p\n", &_edata);
printf("_sbss=%p\n", &_sbss);
printf("_ebss=%p\n", &_ebss);
printf("_estack=%p\n", &_estack);
printf("_ram_start=%p\n", &_ram_start);
printf("_heap_start=%p\n", &_heap_start);
printf("_heap_end=%p\n", &_heap_end);
printf("_ram_end=%p\n", &_ram_end);
}
// qstr info
{
uint n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
printf("qstr:\n n_pool=%u\n n_qstr=%u\n n_str_data_bytes=%u\n n_total_bytes=%u\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes);
}
// GC info
{
gc_info_t info;
gc_info(&info);
printf("GC:\n");
printf(" %lu total\n", info.total);
printf(" %lu : %lu\n", info.used, info.free);
printf(" 1=%lu 2=%lu m=%lu\n", info.num_1block, info.num_2block, info.max_block);
}
#if 0
// free space on flash
{
DWORD nclst;
FATFS *fatfs;
f_getfree("0:", &nclst, &fatfs);
printf("LFS free: %u bytes\n", (uint)(nclst * fatfs->csize * 512));
}
#endif
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_info_obj, pyb_info);
// sync all file systems
STATIC mp_obj_t pyb_sync(void) {
#if 0
storage_flush();
#endif
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_sync_obj, pyb_sync);
STATIC mp_obj_t pyb_millis(void) {
return mp_obj_new_int(HAL_GetTick());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_millis_obj, pyb_millis);
STATIC mp_obj_t pyb_delay(mp_obj_t count) {
sys_tick_delay_ms(mp_obj_get_int(count));
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_delay_obj, pyb_delay);
STATIC mp_obj_t pyb_udelay(mp_obj_t usec) {
uint32_t count = 0;
const uint32_t utime = (168 * mp_obj_get_int(usec) / 5);
for (;;) {
if (++count > utime) {
return mp_const_none;
}
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_udelay_obj, pyb_udelay);
STATIC mp_obj_t pyb_rng_get(void) {
#if 0
return mp_obj_new_int(RNG_GetRandomNumber() >> 16);
#else
return mp_obj_new_int(0);
#endif
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get);
#if 0
STATIC void SYSCLKConfig_STOP(void) {
/* After wake-up from STOP reconfigure the system clock */
/* Enable HSE */
RCC_HSEConfig(RCC_HSE_ON);
/* Wait till HSE is ready */
while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET) {
}
/* Enable PLL */
RCC_PLLCmd(ENABLE);
/* Wait till PLL is ready */
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {
}
/* Select PLL as system clock source */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* Wait till PLL is used as system clock source */
while (RCC_GetSYSCLKSource() != 0x08) {
}
}
#endif
STATIC mp_obj_t pyb_stop(void) {
#if 0
PWR_EnterSTANDBYMode();
//PWR_FlashPowerDownCmd(ENABLE); don't know what the logic is with this
/* Enter Stop Mode */
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
/* Configures system clock after wake-up from STOP: enable HSE, PLL and select
* PLL as system clock source (HSE and PLL are disabled in STOP mode) */
SYSCLKConfig_STOP();
//PWR_FlashPowerDownCmd(DISABLE);
#endif
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(pyb_stop_obj, pyb_stop);
STATIC mp_obj_t pyb_standby(void) {
#if 0
PWR_EnterSTANDBYMode();
#endif
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(pyb_standby_obj, pyb_standby);
STATIC mp_obj_t pyb_hid_send_report(mp_obj_t arg) {
#if 0
mp_obj_t *items = mp_obj_get_array_fixed_n(arg, 4);
uint8_t data[4];
data[0] = mp_obj_get_int(items[0]);
data[1] = mp_obj_get_int(items[1]);
data[2] = mp_obj_get_int(items[2]);
data[3] = mp_obj_get_int(items[3]);
usb_hid_send_report(data);
#endif
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj, pyb_hid_send_report);
#if 0
MP_DEFINE_CONST_FUN_OBJ_2(pyb_I2C_obj, pyb_I2C); // TODO put this in i2c.c
#endif
MP_DECLARE_CONST_FUN_OBJ(pyb_source_dir_obj); // defined in main.c
MP_DECLARE_CONST_FUN_OBJ(pyb_main_obj); // defined in main.c
STATIC const mp_map_elem_t pyb_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&pyb_info_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_gc), (mp_obj_t)&pyb_gc_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_repl_info), (mp_obj_t)&pyb_set_repl_info_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_stop), (mp_obj_t)&pyb_stop_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_standby), (mp_obj_t)&pyb_standby_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_source_dir), (mp_obj_t)&pyb_source_dir_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_main), (mp_obj_t)&pyb_main_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_millis), (mp_obj_t)&pyb_millis_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_delay), (mp_obj_t)&pyb_delay_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_udelay), (mp_obj_t)&pyb_udelay_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sync), (mp_obj_t)&pyb_sync_obj },
#if MICROPY_HW_ENABLE_RNG
{ MP_OBJ_NEW_QSTR(MP_QSTR_rand), (mp_obj_t)&pyb_rng_get_obj },
#endif
#if 0
#if MICROPY_HW_ENABLE_RTC
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&pyb_rtc_read_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_rtc_info), (mp_obj_t)&pyb_rtc_info_obj },
#endif
#if MICROPY_HW_ENABLE_SERVO
{ MP_OBJ_NEW_QSTR(MP_QSTR_pwm), (mp_obj_t)&pyb_pwm_set_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_servo), (mp_obj_t)&pyb_servo_set_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_Servo), (mp_obj_t)&pyb_Servo_obj },
#endif
#if MICROPY_HW_HAS_SWITCH
{ MP_OBJ_NEW_QSTR(MP_QSTR_switch), (mp_obj_t)&pyb_switch_obj },
#endif
#if MICROPY_HW_HAS_SDCARD
{ MP_OBJ_NEW_QSTR(MP_QSTR_SD), (mp_obj_t)&pyb_sdcard_obj },
#endif
#if MICROPY_HW_HAS_MMA7660
{ MP_OBJ_NEW_QSTR(MP_QSTR_accel), (mp_obj_t)&pyb_accel_read_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_accel_read), (mp_obj_t)&pyb_accel_read_all_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_accel_mode), (mp_obj_t)&pyb_accel_write_mode_obj },
#endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_hid), (mp_obj_t)&pyb_hid_send_report_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_Led), (mp_obj_t)&pyb_Led_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_I2C), (mp_obj_t)&pyb_I2C_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_Usart), (mp_obj_t)&pyb_Usart_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ADC_all), (mp_obj_t)&pyb_ADC_all_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ADC), (mp_obj_t)&pyb_ADC_obj },
#if MICROPY_HW_ENABLE_AUDIO
{ MP_OBJ_NEW_QSTR(MP_QSTR_Audio), (mp_obj_t)&pyb_Audio_obj },
#endif
// pin mapper
{ MP_OBJ_NEW_QSTR(MP_QSTR_Pin), (mp_obj_t)&pin_map_obj },
// GPIO bindings
{ MP_OBJ_NEW_QSTR(MP_QSTR_gpio), (mp_obj_t)&pyb_gpio_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_gpio_in), (mp_obj_t)&pyb_gpio_input_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_gpio_out), (mp_obj_t)&pyb_gpio_output_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PULL_NONE), MP_OBJ_NEW_SMALL_INT(GPIO_PuPd_NOPULL) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PULL_UP), MP_OBJ_NEW_SMALL_INT(GPIO_PuPd_UP) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PULL_DOWN), MP_OBJ_NEW_SMALL_INT(GPIO_PuPd_DOWN) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PUSH_PULL), MP_OBJ_NEW_SMALL_INT(GPIO_OType_PP) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_OPEN_DRAIN), MP_OBJ_NEW_SMALL_INT(GPIO_OType_OD) },
// EXTI bindings
{ MP_OBJ_NEW_QSTR(MP_QSTR_Exti), (mp_obj_t)&exti_obj_type },
#endif
};
STATIC const mp_map_t pyb_module_globals = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = sizeof(pyb_module_globals_table) / sizeof(mp_map_elem_t),
.alloc = sizeof(pyb_module_globals_table) / sizeof(mp_map_elem_t),
.table = (mp_map_elem_t*)pyb_module_globals_table,
};
const mp_obj_module_t pyb_module = {
.base = { &mp_type_module },
.name = MP_QSTR_pyb,
.globals = (mp_map_t*)&pyb_module_globals,
};
extern const mp_obj_module_t pyb_module;
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stm32f4xx_hal.h>
#include "nlr.h"
#include "misc.h"
#include "mpconfig.h"
#include "qstr.h"
#include "misc.h"
#include "lexer.h"
#include "parse.h"
#include "obj.h"
#include "parsehelper.h"
#include "compile.h"
#include "runtime.h"
#include "repl.h"
#include "gc.h"
#include "gccollect.h"
#include "systick.h"
#include "pyexec.h"
#if 0
#include "storage.h"
#include "usb.h"
#endif
#include "usart.h"
static bool repl_display_debugging_info = 0;
void stdout_tx_str(const char *str) {
if (pyb_usart_global_debug != PYB_USART_NONE) {
usart_tx_str(pyb_usart_global_debug, str);
}
#if defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
lcd_print_str(str);
#endif
#if 0
usb_vcp_send_str(str);
#endif
}
int stdin_rx_chr(void) {
for (;;) {
#if 0
#ifdef USE_HOST_MODE
pyb_usb_host_process();
int c = pyb_usb_host_get_keyboard();
if (c != 0) {
return c;
}
#endif
#endif
#if 0
if (usb_vcp_rx_any() != 0) {
return usb_vcp_rx_get();
} else
#endif
if (pyb_usart_global_debug != PYB_USART_NONE && usart_rx_any(pyb_usart_global_debug)) {
return usart_rx_char(pyb_usart_global_debug);
}
sys_tick_delay_ms(1);
#if 0
if (storage_needs_flush()) {
storage_flush();
}
#endif
}
}
char *str_dup(const char *str) {
uint32_t len = strlen(str);
char *s2 = m_new(char, len + 1);
memcpy(s2, str, len);
s2[len] = 0;
return s2;
}
#define READLINE_HIST_SIZE (8)
static const char *readline_hist[READLINE_HIST_SIZE] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
#if 0
#else
#define VCP_CHAR_CTRL_A (1)
#define VCP_CHAR_CTRL_C (3)
#define VCP_CHAR_CTRL_D (4)
#endif
int readline(vstr_t *line, const char *prompt) {
stdout_tx_str(prompt);
int len = vstr_len(line);
int escape = 0;
int hist_num = 0;
for (;;) {
int c = stdin_rx_chr();
if (escape == 0) {
if (VCP_CHAR_CTRL_A <= c && c <= VCP_CHAR_CTRL_D && vstr_len(line) == len) {
return c;
} else if (c == '\r') {
stdout_tx_str("\r\n");
for (int i = READLINE_HIST_SIZE - 1; i > 0; i--) {
readline_hist[i] = readline_hist[i - 1];
}
readline_hist[0] = str_dup(vstr_str(line));
return 0;
} else if (c == 27) {
escape = true;
} else if (c == 127) {
if (vstr_len(line) > len) {
vstr_cut_tail(line, 1);
stdout_tx_str("\b \b");
}
} else if (32 <= c && c <= 126) {
vstr_add_char(line, c);
stdout_tx_str(line->buf + line->len - 1);
}
} else if (escape == 1) {
if (c == '[') {
escape = 2;
} else {
escape = 0;
}
} else if (escape == 2) {
escape = 0;
if (c == 'A') {
// up arrow
if (hist_num < READLINE_HIST_SIZE && readline_hist[hist_num] != NULL) {
// erase line
for (int i = line->len - len; i > 0; i--) {
stdout_tx_str("\b \b");
}
// set line to history
line->len = len;
vstr_add_str(line, readline_hist[hist_num]);
// draw line
stdout_tx_str(readline_hist[hist_num]);
// increase hist num
hist_num += 1;
}
}
} else {
escape = 0;
}
sys_tick_delay_ms(1);
}
}
// parses, compiles and executes the code in the lexer
// frees the lexer before returning
bool parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bool is_repl) {
mp_parse_error_kind_t parse_error_kind;
mp_parse_node_t pn = mp_parse(lex, input_kind, &parse_error_kind);
qstr source_name = mp_lexer_source_name(lex);
if (pn == MP_PARSE_NODE_NULL) {
// parse error
mp_parse_show_exception(lex, parse_error_kind);
mp_lexer_free(lex);
return false;
}
mp_lexer_free(lex);
mp_obj_t module_fun = mp_compile(pn, source_name, is_repl);
mp_parse_node_free(pn);
if (module_fun == mp_const_none) {
return false;
}
nlr_buf_t nlr;
bool ret;
uint32_t start = HAL_GetTick();
if (nlr_push(&nlr) == 0) {
#if 0
usb_vcp_set_interrupt_char(VCP_CHAR_CTRL_C); // allow ctrl-C to interrupt us
#endif
rt_call_function_0(module_fun);
#if 0
usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt
#endif
nlr_pop();
ret = true;
} else {
// uncaught exception
// FIXME it could be that an interrupt happens just before we disable it here
#if 0
usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt
#endif
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
ret = false;
}
// display debugging info if wanted
if (is_repl && repl_display_debugging_info) {
uint32_t ticks = HAL_GetTick() - start; // TODO implement a function that does this properly
printf("took %lu ms\n", ticks);
gc_collect();
// qstr info
{
uint n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
printf("qstr:\n n_pool=%u\n n_qstr=%u\n n_str_data_bytes=%u\n n_total_bytes=%u\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes);
}
// GC info
{
gc_info_t info;
gc_info(&info);
printf("GC:\n");
printf(" %lu total\n", info.total);
printf(" %lu : %lu\n", info.used, info.free);
printf(" 1=%lu 2=%lu m=%lu\n", info.num_1block, info.num_2block, info.max_block);
}
}
return ret;
}
void pyexec_raw_repl(void) {
vstr_t line;
vstr_init(&line, 32);
raw_repl_reset:
stdout_tx_str("raw REPL; CTRL-C to exit\r\n");
for (;;) {
vstr_reset(&line);
stdout_tx_str(">");
for (;;) {
char c = stdin_rx_chr();
if (c == VCP_CHAR_CTRL_A) {
goto raw_repl_reset;
} else if (c == VCP_CHAR_CTRL_C) {
vstr_reset(&line);
break;
} else if (c == VCP_CHAR_CTRL_D) {
break;
} else if (c == '\r') {
vstr_add_char(&line, '\n');
} else if (32 <= c && c <= 126) {
vstr_add_char(&line, c);
}
}
stdout_tx_str("OK");
if (vstr_len(&line) == 0) {
// finished
break;
}
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0);
parse_compile_execute(lex, MP_PARSE_FILE_INPUT, false);
stdout_tx_str("\004");
}
vstr_clear(&line);
stdout_tx_str("\r\n");
}
void pyexec_repl(void) {
#if defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
// in host mode, we enable the LCD for the repl
mp_obj_t lcd_o = rt_call_function_0(rt_load_name(qstr_from_str("LCD")));
rt_call_function_1(rt_load_attr(lcd_o, qstr_from_str("light")), mp_const_true);
#endif
stdout_tx_str("Micro Python build <git hash> on 25/1/2014; " MICROPY_HW_BOARD_NAME " with STM32F405RG\r\n");
stdout_tx_str("Type \"help()\" for more information.\r\n");
// to test ctrl-C
/*
{
uint32_t x[4] = {0x424242, 0xdeaddead, 0x242424, 0xdeadbeef};
for (;;) {
nlr_buf_t nlr;
printf("pyexec_repl: %p\n", x);
usb_vcp_set_interrupt_char(VCP_CHAR_CTRL_C);
if (nlr_push(&nlr) == 0) {
for (;;) {
}
} else {
printf("break\n");
}
}
}
*/
vstr_t line;
vstr_init(&line, 32);
for (;;) {
vstr_reset(&line);
int ret = readline(&line, ">>> ");
if (ret == VCP_CHAR_CTRL_A) {
pyexec_raw_repl();
continue;
} else if (ret == VCP_CHAR_CTRL_C) {
stdout_tx_str("\r\n");
continue;
} else if (ret == VCP_CHAR_CTRL_D) {
// EOF
break;
} else if (vstr_len(&line) == 0) {
continue;
}
if (mp_repl_is_compound_stmt(vstr_str(&line))) {
for (;;) {
vstr_add_char(&line, '\n');
int len = vstr_len(&line);
int ret = readline(&line, "... ");
if (ret == VCP_CHAR_CTRL_D || vstr_len(&line) == len) {
// done entering compound statement
break;
}
}
}
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0);
parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, true);
}
stdout_tx_str("\r\n");
}
bool pyexec_file(const char *filename) {
mp_lexer_t *lex = mp_lexer_new_from_file(filename);
if (lex == NULL) {
printf("could not open file '%s' for reading\n", filename);
return false;
}
return parse_compile_execute(lex, MP_PARSE_FILE_INPUT, false);
}
mp_obj_t pyb_set_repl_info(mp_obj_t o_value) {
repl_display_debugging_info = mp_obj_get_int(o_value);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj, pyb_set_repl_info);
void pyexec_raw_repl(void);
void pyexec_repl(void);
bool pyexec_file(const char *filename);
MP_DECLARE_CONST_FUN_OBJ(pyb_set_repl_info_obj);
// qstrs specific to this port
Q(help)
Q(pyb)
Q(info)
Q(sd_test)
Q(stop)
Q(standby)
Q(source_dir)
Q(main)
Q(sync)
Q(gc)
Q(repl_info)
Q(delay)
Q(udelay)
Q(switch)
Q(SW)
Q(servo)
Q(pwm)
Q(accel)
Q(accel_read)
Q(accel_mode)
Q(hid)
Q(time)
Q(rand)
Q(Led)
Q(LCD)
Q(Servo)
Q(SD)
Q(SDcard)
Q(I2C)
Q(gpio)
Q(gpio_in)
Q(gpio_out)
Q(Usart)
Q(ADC)
Q(ADC_all)
Q(Audio)
Q(open)
Q(File)
// Entries for sys.path
Q(0:/)
Q(0:/src)
Q(0:/lib)
Q(Pin)
Q(PinMap)
Q(PinAF)
Q(PinNamed)
Q(Exti)
Q(ExtiMeta)
Q(rtc_info)
Q(millis)
Q(PULL_NONE)
Q(PULL_UP)
Q(PULL_DOWN)
Q(PUSH_PULL)
Q(OPEN_DRAIN)
......@@ -151,6 +151,7 @@ void PendSV_Handler(void)
{
}
#if 0 // defined in systick.c
/**
* @brief This function handles SysTick Handler.
* @param None
......@@ -160,6 +161,7 @@ void SysTick_Handler(void)
{
HAL_IncTick();
}
#endif
/******************************************************************************/
/* STM32F4xx Peripherals Interrupt Handlers */
......
#include <stdint.h>
#include "std.h"
void *memcpy(void *dest, const void *src, size_t n) {
// TODO align and copy 32 bits at a time
uint8_t *d = dest;
const uint8_t *s = src;
for (; n > 0; n--) {
*d++ = *s++;
}
return dest;
}
void *memmove(void *dest, const void *src, size_t n) {
if (src < dest && dest < src + n) {
// need to copy backwards
uint8_t *d = dest + n - 1;
const uint8_t *s = src + n - 1;
for (; n > 0; n--) {
*d-- = *s--;
}
return dest;
} else {
// can use normal memcpy
return memcpy(dest, src, n);
}
}
void *memset(void *s, int c, size_t n) {
uint8_t *s2 = s;
for (; n > 0; n--) {
*s2++ = c;
}
return s;
}
int memcmp(const char *s1, const char *s2, size_t n) {
while (n--) {
char c1 = *s1++;
char c2 = *s2++;
if (c1 < c2) return -1;
else if (c1 > c2) return 1;
}
return 0;
}
size_t strlen(const char *str) {
int len = 0;
for (const char *s = str; *s; s++) {
len += 1;
}
return len;
}
int strcmp(const char *s1, const char *s2) {
while (*s1 && *s2) {
char c1 = *s1++; // XXX UTF8 get char, next char
char c2 = *s2++; // XXX UTF8 get char, next char
if (c1 < c2) return -1;
else if (c1 > c2) return 1;
}
if (*s2) return -1;
else if (*s1) return 1;
else return 0;
}
int strncmp(const char *s1, const char *s2, size_t n) {
while (*s1 && *s2 && n > 0) {
char c1 = *s1++; // XXX UTF8 get char, next char
char c2 = *s2++; // XXX UTF8 get char, next char
n--;
if (c1 < c2) return -1;
else if (c1 > c2) return 1;
}
if (n == 0) return 0;
else if (*s2) return -1;
else if (*s1) return 1;
else return 0;
}
char *strcpy(char *dest, const char *src) {
char *d = dest;
while (*src) {
*d++ = *src++;
}
*d = '\0';
return dest;
}
// needed because gcc optimises strcpy + strcat to this
char *stpcpy(char *dest, const char *src) {
while (*src) {
*dest++ = *src++;
}
*dest = '\0';
return dest;
}
char *strcat(char *dest, const char *src) {
char *d = dest;
while (*d) {
d++;
}
while (*src) {
*d++ = *src++;
}
*d = '\0';
return dest;
}
// Public Domain implementation of strchr from:
// http://en.wikibooks.org/wiki/C_Programming/Strings#The_strchr_function
char *strchr(const char *s, int c)
{
/* Scan s for the character. When this loop is finished,
s will either point to the end of the string or the
character we were looking for. */
while (*s != '\0' && *s != (char)c)
s++;
return ((*s == c) ? (char *) s : 0);
}
// Public Domain implementation of strstr from:
// http://en.wikibooks.org/wiki/C_Programming/Strings#The_strstr_function
char *strstr(const char *haystack, const char *needle)
{
size_t needlelen;
/* Check for the null needle case. */
if (*needle == '\0')
return (char *) haystack;
needlelen = strlen(needle);
for (; (haystack = strchr(haystack, *needle)) != 0; haystack++)
if (strncmp(haystack, needle, needlelen) == 0)
return (char *) haystack;
return 0;
}
......@@ -65,6 +65,8 @@
#include "stm32f4xx_hal.h"
void __fatal_error(const char *msg);
/**
* @}
*/
......@@ -257,8 +259,64 @@ void SystemCoreClockUpdate(void)
}
/**
* @}
* @brief System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL (HSE)
* SYSCLK(Hz) = 168000000
* HCLK(Hz) = 168000000
* AHB Prescaler = 1
* APB1 Prescaler = 4
* APB2 Prescaler = 2
* HSE Frequency(Hz) = 8000000
* PLL_M = 8
* PLL_N = 336
* PLL_P = 2
* PLL_Q = 7
* VDD(V) = 3.3
* Main regulator output voltage = Scale1 mode
* Flash Latency(WS) = 5
* @param None
* @retval None
*/
void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
/* Enable Power Control clock */
__PWR_CLK_ENABLE();
/* The voltage scaling allows optimizing the power consumption when the device is
clocked below the maximum system frequency, to update the voltage scaling value
regarding system frequency refer to product datasheet. */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
__fatal_error("HAL_RCC_OscConfig");
}
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
__fatal_error("HAL_RCC_ClockConfig");
}
}
/**
* @}
......
#include <stm32f4xx_hal.h>
#include "misc.h"
#include "systick.h"
void sys_tick_init(void) {
// SysTick_Config is now called from HAL_RCC_ClockConfig, which is called
// from SystemClock_Config
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); // make it highest priority
}
// called on SysTick interrupt
void SysTick_Handler(void) {
HAL_IncTick();
HAL_SYSTICK_IRQHandler();
// hack!
//void audio_drain(void);
//audio_drain();
}
void sys_tick_delay_ms(uint32_t delay_ms) {
sys_tick_wait_at_least(HAL_GetTick(), delay_ms);
}
// waits until at least delay_ms milliseconds have passed from the sampling of stc
// handles overflow properl
// assumes stc was taken from HAL_GetTick() some time before calling this function
// eg stc <= HAL_GetTick() for the case of no wrap around of HAL_GetTick()
void sys_tick_wait_at_least(uint32_t stc, uint32_t delay_ms) {
// stc_wait is the value of HAL_GetTick() that we wait for
uint32_t stc_wait = stc + delay_ms;
if (stc_wait < stc) {
// stc_wait wrapped around
while (stc <= HAL_GetTick() || HAL_GetTick() < stc_wait) {
__WFI(); // enter sleep mode, waiting for interrupt
}
} else {
// stc_wait did not wrap around
while (stc <= HAL_GetTick() && HAL_GetTick() < stc_wait) {
__WFI(); // enter sleep mode, waiting for interrupt
}
}
}
bool sys_tick_has_passed(uint32_t stc, uint32_t delay_ms) {
// stc_wait is the value of HAL_GetTick() that we wait for
uint32_t stc_wait = stc + delay_ms;
if (stc_wait < stc) {
// stc_wait wrapped around
return !(stc <= HAL_GetTick() || HAL_GetTick() < stc_wait);
} else {
// stc_wait did not wrap around
return !(stc <= HAL_GetTick() && HAL_GetTick() < stc_wait);
}
}
void sys_tick_init(void);
void SysTick_Handler(void);
void sys_tick_delay_ms(uint32_t delay_ms);
void sys_tick_wait_at_least(uint32_t stc, uint32_t delay_ms);
bool sys_tick_has_passed(uint32_t stc, uint32_t delay_ms);
#include <stdio.h>
#include <string.h>
#include <stm32f4xx_hal.h>
#include "misc.h"
#include "mpconfig.h"
#include "qstr.h"
#include "obj.h"
#include "usart.h"
pyb_usart_t pyb_usart_global_debug = PYB_USART_NONE;
#if 0
#else
// This needs to be fixed. Right now its just a hack to get REPL working
static UART_HandleTypeDef UartHandle;
#endif
#if 0
static USART_TypeDef *usart_get_base(pyb_usart_t usart_id) {
USART_TypeDef *USARTx=NULL;
switch (usart_id) {
case PYB_USART_NONE:
break;
case PYB_USART_1:
USARTx = USART1;
break;
case PYB_USART_2:
USARTx = USART2;
break;
case PYB_USART_3:
USARTx = USART3;
break;
case PYB_USART_6:
USARTx = USART6;
break;
}
return USARTx;
}
#endif
void usart_init(pyb_usart_t usart_id, uint32_t baudrate) {
USART_TypeDef *USARTx=NULL;
uint32_t GPIO_Pin=0;
uint8_t GPIO_AF_USARTx=0;
GPIO_TypeDef* GPIO_Port=NULL;
switch (usart_id) {
case PYB_USART_NONE:
return;
case PYB_USART_1:
USARTx = USART1;
GPIO_Port = GPIOA;
GPIO_AF_USARTx = GPIO_AF7_USART1;
GPIO_Pin = GPIO_PIN_9 | GPIO_PIN_10;
__USART1_CLK_ENABLE();
break;
case PYB_USART_2:
USARTx = USART2;
GPIO_Port = GPIOD;
GPIO_AF_USARTx = GPIO_AF7_USART2;
GPIO_Pin = GPIO_PIN_5 | GPIO_PIN_6;
__USART2_CLK_ENABLE();
break;
case PYB_USART_3:
USARTx = USART3;
#if defined(PYBOARD3) || defined(PYBOARD4)
GPIO_Port = GPIOB;
GPIO_AF_USARTx = GPIO_AF7_USART3;
GPIO_Pin = GPIO_PIN_10 | GPIO_PIN_11;
#else
GPIO_Port = GPIOD;
GPIO_AF_USARTx = GPIO_AF7_USART3;
GPIO_Pin = GPIO_PIN_8 | GPIO_PIN_9;
#endif
__USART3_CLK_ENABLE();
break;
case PYB_USART_6:
USARTx = USART6;
GPIO_Port = GPIOC;
GPIO_AF_USARTx = GPIO_AF8_USART6;
GPIO_Pin = GPIO_PIN_6 | GPIO_PIN_7;
__USART6_CLK_ENABLE();
break;
}
/* Initialize USARTx */
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = GPIO_Pin;
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Alternate = GPIO_AF_USARTx;
HAL_GPIO_Init(GPIO_Port, &GPIO_InitStructure);
memset(&UartHandle, 0, sizeof(UartHandle));
UartHandle.Instance = USARTx;
UartHandle.Init.BaudRate = baudrate;
UartHandle.Init.WordLength = USART_WORDLENGTH_8B;
UartHandle.Init.StopBits = USART_STOPBITS_1;
UartHandle.Init.Parity = USART_PARITY_NONE;
UartHandle.Init.Mode = USART_MODE_TX_RX;
UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&UartHandle);
}
bool usart_rx_any(pyb_usart_t usart_id) {
#if 0
USART_TypeDef *USARTx = usart_get_base(usart_id);
return USART_GetFlagStatus(USARTx, USART_FLAG_RXNE) == SET;
#else
return __HAL_UART_GET_FLAG(&UartHandle, USART_FLAG_RXNE);
#endif
}
int usart_rx_char(pyb_usart_t usart_id) {
#if 0
USART_TypeDef *USARTx = usart_get_base(usart_id);
return USART_ReceiveData(USARTx);
#else
uint8_t ch;
if (HAL_UART_Receive(&UartHandle, &ch, 1, 0) != HAL_OK) {
ch = 0;
}
return ch;
#endif
}
void usart_tx_char(pyb_usart_t usart_id, int c) {
#if 0
USART_TypeDef *USARTx = usart_get_base(usart_id);
// wait until the end of any previous transmission
uint32_t timeout = 100000;
while (USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET && --timeout > 0) {
}
USART_SendData(USARTx, c);
#else
uint8_t ch = c;
HAL_UART_Transmit(&UartHandle, &ch, 1, 100000);
#endif
}
void usart_tx_str(pyb_usart_t usart_id, const char *str) {
for (; *str; str++) {
usart_tx_char(usart_id, *str);
}
}
void usart_tx_bytes(pyb_usart_t usart_id, const char *data, uint len) {
for (; len > 0; data++, len--) {
usart_tx_char(usart_id, *data);
}
}
void usart_tx_strn_cooked(pyb_usart_t usart_id, const char *str, int len) {
for (const char *top = str + len; str < top; str++) {
if (*str == '\n') {
usart_tx_char(usart_id, '\r');
}
usart_tx_char(usart_id, *str);
}
}
#if 0
/******************************************************************************/
/* Micro Python bindings */
typedef struct _pyb_usart_obj_t {
mp_obj_base_t base;
pyb_usart_t usart_id;
bool is_enabled;
} pyb_usart_obj_t;
static mp_obj_t usart_obj_status(mp_obj_t self_in) {
pyb_usart_obj_t *self = self_in;
if (usart_rx_any(self->usart_id)) {
return mp_const_true;
} else {
return mp_const_false;
}
}
static mp_obj_t usart_obj_rx_char(mp_obj_t self_in) {
mp_obj_t ret = mp_const_none;
pyb_usart_obj_t *self = self_in;
if (self->is_enabled) {
ret = mp_obj_new_int(usart_rx_char(self->usart_id));
}
return ret;
}
static mp_obj_t usart_obj_tx_char(mp_obj_t self_in, mp_obj_t c) {
pyb_usart_obj_t *self = self_in;
uint len;
const char *str = mp_obj_str_get_data(c, &len);
if (len == 1 && self->is_enabled) {
usart_tx_char(self->usart_id, str[0]);
}
return mp_const_none;
}
static mp_obj_t usart_obj_tx_str(mp_obj_t self_in, mp_obj_t s) {
pyb_usart_obj_t *self = self_in;
if (self->is_enabled) {
if (MP_OBJ_IS_STR(s)) {
uint len;
const char *data = mp_obj_str_get_data(s, &len);
usart_tx_bytes(self->usart_id, data, len);
}
}
return mp_const_none;
}
static void usart_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_usart_obj_t *self = self_in;
print(env, "<Usart %lu>", self->usart_id);
}
static MP_DEFINE_CONST_FUN_OBJ_1(usart_obj_status_obj, usart_obj_status);
static MP_DEFINE_CONST_FUN_OBJ_1(usart_obj_rx_char_obj, usart_obj_rx_char);
static MP_DEFINE_CONST_FUN_OBJ_2(usart_obj_tx_char_obj, usart_obj_tx_char);
static MP_DEFINE_CONST_FUN_OBJ_2(usart_obj_tx_str_obj, usart_obj_tx_str);
STATIC const mp_method_t usart_methods[] = {
{ "status", &usart_obj_status_obj },
{ "recv_chr", &usart_obj_rx_char_obj },
{ "send_chr", &usart_obj_tx_char_obj },
{ "send", &usart_obj_tx_str_obj },
{ NULL, NULL },
};
STATIC const mp_obj_type_t usart_obj_type = {
{ &mp_type_type },
.name = MP_QSTR_Usart,
.print = usart_obj_print,
.methods = usart_methods,
};
STATIC mp_obj_t pyb_Usart(mp_obj_t usart_id, mp_obj_t baudrate) {
if (mp_obj_get_int(usart_id)>PYB_USART_MAX) {
return mp_const_none;
}
/* init USART */
usart_init(mp_obj_get_int(usart_id), mp_obj_get_int(baudrate));
pyb_usart_obj_t *o = m_new_obj(pyb_usart_obj_t);
o->base.type = &usart_obj_type;
o->usart_id = mp_obj_get_int(usart_id);
o->is_enabled = true;
return o;
}
MP_DEFINE_CONST_FUN_OBJ_2(pyb_Usart_obj, pyb_Usart);
#endif
typedef enum {
PYB_USART_NONE = 0,
PYB_USART_1 = 1,
PYB_USART_2 = 2,
PYB_USART_3 = 3,
PYB_USART_6 = 4,
PYB_USART_MAX = 4,
//PYB_USART_XA = // USART4 on X1, X2 = PA0, PA1
PYB_USART_XB = 1, // USART1 on X9, X10 = PB6, PB7
PYB_USART_YA = 4, // USART6 on Y1, Y2 = PC6, PC7
PYB_USART_YB = 3, // USART3 on Y9, Y10 = PB10, PB11
} pyb_usart_t;
extern pyb_usart_t pyb_usart_global_debug;
void usart_init(pyb_usart_t usart_id, uint32_t baudrate);
bool usart_rx_any(pyb_usart_t usart_id);
int usart_rx_char(pyb_usart_t usart_id);
void usart_tx_str(pyb_usart_t usart_id, const char *str);
void usart_tx_strn_cooked(pyb_usart_t usart_id, const char *str, int len);
#if 0
MP_DECLARE_CONST_FUN_OBJ(pyb_Usart_obj);
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册