From f14b92b9e13c9cb9f54a1d740dbea1eeedeccb5b Mon Sep 17 00:00:00 2001 From: Dave Hylands Date: Wed, 12 Mar 2014 18:06:26 -0700 Subject: [PATCH] REPl working on UART6 with STMHAL --- stmhal/Makefile | 45 ++-- stmhal/boards/stm32f4xx-prefix.c | 2 +- stmhal/gccollect.c | 56 +++++ stmhal/gccollect.h | 17 ++ stmhal/gchelper.s | 62 +++++ stmhal/import.c | 24 ++ stmhal/led.c | 133 ++++++++++ stmhal/led.h | 25 ++ stmhal/lexerfatfs.c | 61 +++++ stmhal/lexerfatfs.h | 1 + stmhal/main.c | 158 ++++-------- stmhal/malloc0.c | 36 +++ stmhal/math.c | 407 +++++++++++++++++++++++++++++++ stmhal/mpconfigport.h | 51 ++++ stmhal/pin.c | 78 ++++++ stmhal/pin.h | 117 +++++++++ stmhal/printf.c | 371 ++++++++++++++++++++++++++++ stmhal/pybmodule.c | 312 +++++++++++++++++++++++ stmhal/pybmodule.h | 1 + stmhal/pyexec.c | 347 ++++++++++++++++++++++++++ stmhal/pyexec.h | 5 + stmhal/qstrdefsport.h | 57 +++++ stmhal/stm32f4xx_it.c | 2 + stmhal/string0.c | 137 +++++++++++ stmhal/system_stm32f4xx.c | 60 ++++- stmhal/systick.c | 54 ++++ stmhal/systick.h | 5 + stmhal/usart.c | 269 ++++++++++++++++++++ stmhal/usart.h | 25 ++ 29 files changed, 2793 insertions(+), 125 deletions(-) create mode 100644 stmhal/gccollect.c create mode 100644 stmhal/gccollect.h create mode 100644 stmhal/gchelper.s create mode 100644 stmhal/import.c create mode 100644 stmhal/led.c create mode 100644 stmhal/led.h create mode 100644 stmhal/lexerfatfs.c create mode 100644 stmhal/lexerfatfs.h create mode 100644 stmhal/malloc0.c create mode 100644 stmhal/math.c create mode 100644 stmhal/mpconfigport.h create mode 100644 stmhal/pin.c create mode 100644 stmhal/pin.h create mode 100644 stmhal/printf.c create mode 100644 stmhal/pybmodule.c create mode 100644 stmhal/pybmodule.h create mode 100644 stmhal/pyexec.c create mode 100644 stmhal/pyexec.h create mode 100644 stmhal/qstrdefsport.h create mode 100644 stmhal/string0.c create mode 100644 stmhal/systick.c create mode 100644 stmhal/systick.h create mode 100644 stmhal/usart.c create mode 100644 stmhal/usart.h diff --git a/stmhal/Makefile b/stmhal/Makefile index 2b5c5ffe28..f53887b746 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -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 diff --git a/stmhal/boards/stm32f4xx-prefix.c b/stmhal/boards/stm32f4xx-prefix.c index e68de4cf4e..af3ed325cb 100644 --- a/stmhal/boards/stm32f4xx-prefix.c +++ b/stmhal/boards/stm32f4xx-prefix.c @@ -2,7 +2,7 @@ #include #include -#include +#include #include "misc.h" #include "mpconfig.h" diff --git a/stmhal/gccollect.c b/stmhal/gccollect.c new file mode 100644 index 0000000000..e20e92de14 --- /dev/null +++ b/stmhal/gccollect.c @@ -0,0 +1,56 @@ +#include + +#include + +#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); diff --git a/stmhal/gccollect.h b/stmhal/gccollect.h new file mode 100644 index 0000000000..9aa0a44413 --- /dev/null +++ b/stmhal/gccollect.h @@ -0,0 +1,17 @@ +// 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); diff --git a/stmhal/gchelper.s b/stmhal/gchelper.s new file mode 100644 index 0000000000..6baedcdd0e --- /dev/null +++ b/stmhal/gchelper.s @@ -0,0 +1,62 @@ + .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 diff --git a/stmhal/import.c b/stmhal/import.c new file mode 100644 index 0000000000..f2fd3b3dee --- /dev/null +++ b/stmhal/import.c @@ -0,0 +1,24 @@ +#include + +#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; +} diff --git a/stmhal/led.c b/stmhal/led.c new file mode 100644 index 0000000000..a643ce84fd --- /dev/null +++ b/stmhal/led.c @@ -0,0 +1,133 @@ +#include +#include + +#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, "", 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 diff --git a/stmhal/led.h b/stmhal/led.h new file mode 100644 index 0000000000..9e9db16ac3 --- /dev/null +++ b/stmhal/led.h @@ -0,0 +1,25 @@ +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 diff --git a/stmhal/lexerfatfs.c b/stmhal/lexerfatfs.c new file mode 100644 index 0000000000..1910587d8e --- /dev/null +++ b/stmhal/lexerfatfs.c @@ -0,0 +1,61 @@ +#include +#include + +#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 +} diff --git a/stmhal/lexerfatfs.h b/stmhal/lexerfatfs.h new file mode 100644 index 0000000000..55902a3006 --- /dev/null +++ b/stmhal/lexerfatfs.h @@ -0,0 +1 @@ +mp_lexer_t *mp_lexer_new_from_file(const char *filename); diff --git a/stmhal/main.c b/stmhal/main.c index ec913c30c5..97a512cda7 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -15,19 +15,18 @@ #include #include #include -#include #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 } diff --git a/stmhal/malloc0.c b/stmhal/malloc0.c new file mode 100644 index 0000000000..85a643f72d --- /dev/null +++ b/stmhal/malloc0.c @@ -0,0 +1,36 @@ +#include +#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 (;;) { + } +} diff --git a/stmhal/math.c b/stmhal/math.c new file mode 100644 index 0000000000..8e2c6fc753 --- /dev/null +++ b/stmhal/math.c @@ -0,0 +1,407 @@ +#include +#include + +// 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; +} diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h new file mode 100644 index 0000000000..3f48c43f04 --- /dev/null +++ b/stmhal/mpconfigport.h @@ -0,0 +1,51 @@ +#include + +// 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 diff --git a/stmhal/pin.c b/stmhal/pin.c new file mode 100644 index 0000000000..735901c306 --- /dev/null +++ b/stmhal/pin.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include + +#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, "", 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, "", 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 +}; + diff --git a/stmhal/pin.h b/stmhal/pin.h new file mode 100644 index 0000000000..d5d769058a --- /dev/null +++ b/stmhal/pin.h @@ -0,0 +1,117 @@ +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); + diff --git a/stmhal/printf.c b/stmhal/printf.c new file mode 100644 index 0000000000..acd9816a55 --- /dev/null +++ b/stmhal/printf.c @@ -0,0 +1,371 @@ +#include +#include +#include + +#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; +} diff --git a/stmhal/pybmodule.c b/stmhal/pybmodule.c new file mode 100644 index 0000000000..f0a7ebb6dc --- /dev/null +++ b/stmhal/pybmodule.c @@ -0,0 +1,312 @@ +#include +#include + +#include + +#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, +}; diff --git a/stmhal/pybmodule.h b/stmhal/pybmodule.h new file mode 100644 index 0000000000..955aaefe3f --- /dev/null +++ b/stmhal/pybmodule.h @@ -0,0 +1 @@ +extern const mp_obj_module_t pyb_module; diff --git a/stmhal/pyexec.c b/stmhal/pyexec.c new file mode 100644 index 0000000000..2eca892a90 --- /dev/null +++ b/stmhal/pyexec.c @@ -0,0 +1,347 @@ +#include +#include +#include + +#include + +#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 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); diff --git a/stmhal/pyexec.h b/stmhal/pyexec.h new file mode 100644 index 0000000000..cad15af6fe --- /dev/null +++ b/stmhal/pyexec.h @@ -0,0 +1,5 @@ +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); diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h new file mode 100644 index 0000000000..13532892a7 --- /dev/null +++ b/stmhal/qstrdefsport.h @@ -0,0 +1,57 @@ +// 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) diff --git a/stmhal/stm32f4xx_it.c b/stmhal/stm32f4xx_it.c index 96b12bfe4a..61c4b7172e 100644 --- a/stmhal/stm32f4xx_it.c +++ b/stmhal/stm32f4xx_it.c @@ -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 */ diff --git a/stmhal/string0.c b/stmhal/string0.c new file mode 100644 index 0000000000..61350bd972 --- /dev/null +++ b/stmhal/string0.c @@ -0,0 +1,137 @@ +#include +#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; +} diff --git a/stmhal/system_stm32f4xx.c b/stmhal/system_stm32f4xx.c index aa9c984731..8d806041c1 100644 --- a/stmhal/system_stm32f4xx.c +++ b/stmhal/system_stm32f4xx.c @@ -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"); + } +} /** * @} diff --git a/stmhal/systick.c b/stmhal/systick.c new file mode 100644 index 0000000000..55c22dab01 --- /dev/null +++ b/stmhal/systick.c @@ -0,0 +1,54 @@ +#include +#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); + } +} diff --git a/stmhal/systick.h b/stmhal/systick.h new file mode 100644 index 0000000000..ce33e849b8 --- /dev/null +++ b/stmhal/systick.h @@ -0,0 +1,5 @@ +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); diff --git a/stmhal/usart.c b/stmhal/usart.c new file mode 100644 index 0000000000..16b23240a8 --- /dev/null +++ b/stmhal/usart.c @@ -0,0 +1,269 @@ +#include +#include +#include + +#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, "", 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 diff --git a/stmhal/usart.h b/stmhal/usart.h new file mode 100644 index 0000000000..2b1b60bfda --- /dev/null +++ b/stmhal/usart.h @@ -0,0 +1,25 @@ +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