Commit 3f489845 authored by Damien George's avatar Damien George
Browse files

stmhal: Add stm module, which contains some constants for the MCU.

Also contains raw memory read/write functions, read8, read16, read32,
write8, write16, write32.  Can now do:

stm.write16(stm.GPIOA + stm.GPIO_BSRRL, 1 << 13)

This turns on the red LED.

With the new constant folding, the above constants for the GPIO address
are actually compiled to constants (and the addition done) at compile
time.  For viper code and inline assembler, this optimisation will make
a big difference.  In the inline assembler, using these constants would
not be possible without this constant folding.
parent 57e99ebc
......@@ -77,8 +77,9 @@ SRC_C = \
pyexec.c \
help.c \
input.c \
modpyb.c \
modos.c \
modpyb.c \
modstm.c \
modtime.c \
import.c \
lexerfatfs.c \
......
#include <stdio.h>
#include <stdint.h>
#include <stm32f4xx_hal.h>
#include "nlr.h"
#include "misc.h"
#include "mpconfig.h"
#include "qstr.h"
#include "obj.h"
#include "modstm.h"
STATIC uint32_t get_read_addr(mp_obj_t addr_o, uint align) {
uint32_t addr = mp_obj_get_int(addr_o) & 0x7fffffff;
if (addr < 0x10000000) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "cannot read from address %08x", addr));
}
if ((addr & (align - 1)) != 0) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "address %08x is not aligned to %d bytes", addr, align));
}
return addr;
}
STATIC uint32_t get_write_addr(mp_obj_t addr_o, uint align) {
uint32_t addr = mp_obj_get_int(addr_o) & 0x7fffffff;
if (addr < 0x10000000) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "cannot write to address %08x", addr));
}
if ((addr & (align - 1)) != 0) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "address %08x is not aligned to %d bytes", addr, align));
}
return addr;
}
STATIC mp_obj_t stm_read8(mp_obj_t addr) {
uint32_t a = get_read_addr(addr, 1);
uint32_t v = *(uint8_t*)a;
return mp_obj_new_int(v);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(stm_read8_obj, stm_read8);
STATIC mp_obj_t stm_read16(mp_obj_t addr) {
uint32_t a = get_read_addr(addr, 2);
uint32_t v = *(uint16_t*)a;
return mp_obj_new_int(v);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(stm_read16_obj, stm_read16);
STATIC mp_obj_t stm_read32(mp_obj_t addr) {
uint32_t a = get_read_addr(addr, 4);
uint32_t v = *(uint32_t*)a;
return mp_obj_new_int(v);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(stm_read32_obj, stm_read32);
STATIC mp_obj_t stm_write8(mp_obj_t addr, mp_obj_t val) {
uint32_t a = get_write_addr(addr, 1);
uint32_t v = mp_obj_get_int(val);
*(uint8_t*)a = v;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(stm_write8_obj, stm_write8);
STATIC mp_obj_t stm_write16(mp_obj_t addr, mp_obj_t val) {
uint32_t a = get_write_addr(addr, 2);
uint32_t v = mp_obj_get_int(val);
*(uint16_t*)a = v;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(stm_write16_obj, stm_write16);
STATIC mp_obj_t stm_write32(mp_obj_t addr, mp_obj_t val) {
uint32_t a = get_write_addr(addr, 4);
uint32_t v = mp_obj_get_int(val);
*(uint32_t*)a = v;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(stm_write32_obj, stm_write32);
STATIC const mp_map_elem_t stm_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_stm) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_read8), (mp_obj_t)&stm_read8_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_read16), (mp_obj_t)&stm_read16_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_read32), (mp_obj_t)&stm_read32_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_write8), (mp_obj_t)&stm_write8_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_write16), (mp_obj_t)&stm_write16_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_write32), (mp_obj_t)&stm_write32_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_GPIOA), MP_OBJ_NEW_SMALL_INT(GPIOA_BASE) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_GPIOB), MP_OBJ_NEW_SMALL_INT(GPIOB_BASE) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_GPIOC), MP_OBJ_NEW_SMALL_INT(GPIOC_BASE) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_GPIOD), MP_OBJ_NEW_SMALL_INT(GPIOD_BASE) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_GPIO_IDR), MP_OBJ_NEW_SMALL_INT(0x10) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_GPIO_BSRRL), MP_OBJ_NEW_SMALL_INT(0x18) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_GPIO_BSRRH), MP_OBJ_NEW_SMALL_INT(0x1a) },
};
STATIC const mp_obj_dict_t stm_module_globals = {
.base = {&mp_type_dict},
.map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = sizeof(stm_module_globals_table) / sizeof(mp_map_elem_t),
.alloc = sizeof(stm_module_globals_table) / sizeof(mp_map_elem_t),
.table = (mp_map_elem_t*)stm_module_globals_table,
},
};
const mp_obj_module_t stm_module = {
.base = { &mp_type_module },
.name = MP_QSTR_stm,
.globals = (mp_obj_dict_t*)&stm_module_globals,
};
extern const mp_obj_module_t stm_module;
......@@ -31,12 +31,19 @@ extern const struct _mp_obj_fun_native_t mp_builtin_open_obj;
// extra built in modules to add to the list of known ones
extern const struct _mp_obj_module_t os_module;
extern const struct _mp_obj_module_t pyb_module;
extern const struct _mp_obj_module_t stm_module;
extern const struct _mp_obj_module_t time_module;
#define MICROPY_EXTRA_BUILTIN_MODULES \
{ MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&os_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_stm), (mp_obj_t)&stm_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_module }, \
// extra constants
#define MICROPY_EXTRA_CONSTANTS \
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_stm), (mp_obj_t)&stm_module }, \
// type definitions for the specific machine
#define BYTES_PER_WORD (4)
......
......@@ -130,3 +130,19 @@ Q(sleep)
// for input
Q(input)
// for stm module
Q(stm)
Q(read8)
Q(read16)
Q(read32)
Q(write8)
Q(write16)
Q(write32)
Q(GPIOA)
Q(GPIOB)
Q(GPIOC)
Q(GPIOD)
Q(GPIO_IDR)
Q(GPIO_BSRRL)
Q(GPIO_BSRRH)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment