developed_by_feng-arch_add_dma_support_in_machine_spi #1
@ -36,7 +36,8 @@
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
// MicroPython bindings for generic machine.SPI
|
// MicroPython bindings for generic machine.SPI
|
||||||
|
|
||||||
static mp_obj_t machine_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
static mp_obj_t machine_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||||
|
{
|
||||||
mp_obj_base_t *s = (mp_obj_base_t *)MP_OBJ_TO_PTR(args[0]);
|
mp_obj_base_t *s = (mp_obj_base_t *)MP_OBJ_TO_PTR(args[0]);
|
||||||
mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t *)MP_OBJ_TYPE_GET_SLOT(s->type, protocol);
|
mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t *)MP_OBJ_TYPE_GET_SLOT(s->type, protocol);
|
||||||
spi_p->init(s, n_args - 1, args + 1, kw_args);
|
spi_p->init(s, n_args - 1, args + 1, kw_args);
|
||||||
@ -44,23 +45,50 @@ static mp_obj_t machine_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *
|
|||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_KW(machine_spi_init_obj, 1, machine_spi_init);
|
static MP_DEFINE_CONST_FUN_OBJ_KW(machine_spi_init_obj, 1, machine_spi_init);
|
||||||
|
|
||||||
static mp_obj_t machine_spi_deinit(mp_obj_t self) {
|
static mp_obj_t machine_spi_deinit(mp_obj_t self)
|
||||||
|
{
|
||||||
mp_obj_base_t *s = (mp_obj_base_t *)MP_OBJ_TO_PTR(self);
|
mp_obj_base_t *s = (mp_obj_base_t *)MP_OBJ_TO_PTR(self);
|
||||||
mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t *)MP_OBJ_TYPE_GET_SLOT(s->type, protocol);
|
mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t *)MP_OBJ_TYPE_GET_SLOT(s->type, protocol);
|
||||||
if (spi_p->deinit != NULL) {
|
if (spi_p->deinit != NULL)
|
||||||
|
{
|
||||||
spi_p->deinit(s);
|
spi_p->deinit(s);
|
||||||
}
|
}
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
static MP_DEFINE_CONST_FUN_OBJ_1(machine_spi_deinit_obj, machine_spi_deinit);
|
static MP_DEFINE_CONST_FUN_OBJ_1(machine_spi_deinit_obj, machine_spi_deinit);
|
||||||
|
|
||||||
static void mp_machine_spi_transfer(mp_obj_t self, size_t len, const void *src, void *dest) {
|
static void mp_machine_spi_transfer(mp_obj_t self, size_t len, const void *src, void *dest)
|
||||||
|
{
|
||||||
mp_obj_base_t *s = (mp_obj_base_t *)MP_OBJ_TO_PTR(self);
|
mp_obj_base_t *s = (mp_obj_base_t *)MP_OBJ_TO_PTR(self);
|
||||||
mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t *)MP_OBJ_TYPE_GET_SLOT(s->type, protocol);
|
mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t *)MP_OBJ_TYPE_GET_SLOT(s->type, protocol);
|
||||||
spi_p->transfer(s, len, src, dest);
|
spi_p->transfer(s, len, src, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
static mp_obj_t mp_machine_spi_read(size_t n_args, const mp_obj_t *args) {
|
static mp_obj_t mp_machine_spi_wait_done(size_t n_args, const mp_obj_t *args)
|
||||||
|
{
|
||||||
|
mp_obj_base_t *s = (mp_obj_base_t *)MP_OBJ_TO_PTR(args[0]);
|
||||||
|
mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t *)MP_OBJ_TYPE_GET_SLOT(s->type, protocol);
|
||||||
|
if (spi_p->wait_done != NULL)
|
||||||
|
{
|
||||||
|
spi_p->wait_done(s);
|
||||||
|
}
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_wait_done_obj, 1, 2, mp_machine_spi_wait_done);
|
||||||
|
|
||||||
|
static mp_obj_t mp_machine_spi_set_tx_irq(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args){
|
||||||
|
mp_obj_base_t *s = (mp_obj_base_t *)MP_OBJ_TO_PTR(args[0]);
|
||||||
|
mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t *)MP_OBJ_TYPE_GET_SLOT(s->type, protocol);
|
||||||
|
if (spi_p->set_tx_isr != NULL)
|
||||||
|
{
|
||||||
|
spi_p->set_tx_isr(s, n_args - 1, args + 1, kw_args);
|
||||||
|
}
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
static MP_DEFINE_CONST_FUN_OBJ_KW(machine_spi_set_tx_irq_obj, 1, mp_machine_spi_set_tx_irq);
|
||||||
|
|
||||||
|
static mp_obj_t mp_machine_spi_read(size_t n_args, const mp_obj_t *args)
|
||||||
|
{
|
||||||
vstr_t vstr;
|
vstr_t vstr;
|
||||||
vstr_init_len(&vstr, mp_obj_get_int(args[1]));
|
vstr_init_len(&vstr, mp_obj_get_int(args[1]));
|
||||||
memset(vstr.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, vstr.len);
|
memset(vstr.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, vstr.len);
|
||||||
@ -69,7 +97,8 @@ static mp_obj_t mp_machine_spi_read(size_t n_args, const mp_obj_t *args) {
|
|||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj, 2, 3, mp_machine_spi_read);
|
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj, 2, 3, mp_machine_spi_read);
|
||||||
|
|
||||||
static mp_obj_t mp_machine_spi_readinto(size_t n_args, const mp_obj_t *args) {
|
static mp_obj_t mp_machine_spi_readinto(size_t n_args, const mp_obj_t *args)
|
||||||
|
{
|
||||||
mp_buffer_info_t bufinfo;
|
mp_buffer_info_t bufinfo;
|
||||||
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
|
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
|
||||||
memset(bufinfo.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, bufinfo.len);
|
memset(bufinfo.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, bufinfo.len);
|
||||||
@ -78,7 +107,8 @@ static mp_obj_t mp_machine_spi_readinto(size_t n_args, const mp_obj_t *args) {
|
|||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj, 2, 3, mp_machine_spi_readinto);
|
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj, 2, 3, mp_machine_spi_readinto);
|
||||||
|
|
||||||
static mp_obj_t mp_machine_spi_write(mp_obj_t self, mp_obj_t wr_buf) {
|
static mp_obj_t mp_machine_spi_write(mp_obj_t self, mp_obj_t wr_buf)
|
||||||
|
{
|
||||||
mp_buffer_info_t src;
|
mp_buffer_info_t src;
|
||||||
mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ);
|
mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ);
|
||||||
mp_machine_spi_transfer(self, src.len, (const uint8_t *)src.buf, NULL);
|
mp_machine_spi_transfer(self, src.len, (const uint8_t *)src.buf, NULL);
|
||||||
@ -86,12 +116,14 @@ static mp_obj_t mp_machine_spi_write(mp_obj_t self, mp_obj_t wr_buf) {
|
|||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj, mp_machine_spi_write);
|
MP_DEFINE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj, mp_machine_spi_write);
|
||||||
|
|
||||||
static mp_obj_t mp_machine_spi_write_readinto(mp_obj_t self, mp_obj_t wr_buf, mp_obj_t rd_buf) {
|
static mp_obj_t mp_machine_spi_write_readinto(mp_obj_t self, mp_obj_t wr_buf, mp_obj_t rd_buf)
|
||||||
|
{
|
||||||
mp_buffer_info_t src;
|
mp_buffer_info_t src;
|
||||||
mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ);
|
mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ);
|
||||||
mp_buffer_info_t dest;
|
mp_buffer_info_t dest;
|
||||||
mp_get_buffer_raise(rd_buf, &dest, MP_BUFFER_WRITE);
|
mp_get_buffer_raise(rd_buf, &dest, MP_BUFFER_WRITE);
|
||||||
if (src.len != dest.len) {
|
if (src.len != dest.len)
|
||||||
|
{
|
||||||
mp_raise_ValueError(MP_ERROR_TEXT("buffers must be the same length"));
|
mp_raise_ValueError(MP_ERROR_TEXT("buffers must be the same length"));
|
||||||
}
|
}
|
||||||
mp_machine_spi_transfer(self, src.len, src.buf, dest.buf);
|
mp_machine_spi_transfer(self, src.len, src.buf, dest.buf);
|
||||||
@ -106,6 +138,8 @@ static const mp_rom_map_elem_t machine_spi_locals_dict_table[] = {
|
|||||||
{MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj)},
|
{MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj)},
|
{MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj)},
|
{MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj)},
|
||||||
|
{MP_ROM_QSTR(MP_QSTR_wait_done), MP_ROM_PTR(&mp_machine_spi_wait_done_obj)},
|
||||||
|
{MP_ROM_QSTR(MP_QSTR_set_tx_irq), MP_ROM_PTR(&machine_spi_set_tx_irq_obj)},
|
||||||
|
|
||||||
{MP_ROM_QSTR(MP_QSTR_MSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_MSB)},
|
{MP_ROM_QSTR(MP_QSTR_MSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_MSB)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_LSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_LSB)},
|
{MP_ROM_QSTR(MP_QSTR_LSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_LSB)},
|
||||||
@ -119,34 +153,42 @@ MP_DEFINE_CONST_DICT(mp_machine_spi_locals_dict, machine_spi_locals_dict_table);
|
|||||||
|
|
||||||
#if MICROPY_PY_MACHINE_SOFTSPI
|
#if MICROPY_PY_MACHINE_SOFTSPI
|
||||||
|
|
||||||
static uint32_t baudrate_from_delay_half(uint32_t delay_half) {
|
static uint32_t baudrate_from_delay_half(uint32_t delay_half)
|
||||||
|
{
|
||||||
#ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
|
#ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
|
||||||
if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) {
|
if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY)
|
||||||
|
{
|
||||||
return MICROPY_HW_SOFTSPI_MAX_BAUDRATE;
|
return MICROPY_HW_SOFTSPI_MAX_BAUDRATE;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
return 500000 / delay_half;
|
return 500000 / delay_half;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t baudrate_to_delay_half(uint32_t baudrate) {
|
static uint32_t baudrate_to_delay_half(uint32_t baudrate)
|
||||||
|
{
|
||||||
#ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
|
#ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
|
||||||
if (baudrate >= MICROPY_HW_SOFTSPI_MAX_BAUDRATE) {
|
if (baudrate >= MICROPY_HW_SOFTSPI_MAX_BAUDRATE)
|
||||||
|
{
|
||||||
return MICROPY_HW_SOFTSPI_MIN_DELAY;
|
return MICROPY_HW_SOFTSPI_MIN_DELAY;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
uint32_t delay_half = 500000 / baudrate;
|
uint32_t delay_half = 500000 / baudrate;
|
||||||
// round delay_half up so that: actual_baudrate <= requested_baudrate
|
// round delay_half up so that: actual_baudrate <= requested_baudrate
|
||||||
if (500000 % baudrate != 0) {
|
if (500000 % baudrate != 0)
|
||||||
|
{
|
||||||
delay_half += 1;
|
delay_half += 1;
|
||||||
}
|
}
|
||||||
return delay_half;
|
return delay_half;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mp_machine_soft_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
static void mp_machine_soft_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
|
||||||
|
{
|
||||||
mp_machine_soft_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_machine_soft_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
mp_printf(print, "SoftSPI(baudrate=%u, polarity=%u, phase=%u, firstbit=%u,"
|
mp_printf(print, "SoftSPI(baudrate=%u, polarity=%u, phase=%u, firstbit=%u,"
|
||||||
" sck=" MP_HAL_PIN_FMT ", mosi=" MP_HAL_PIN_FMT ", miso=" MP_HAL_PIN_FMT ")",
|
" sck=" MP_HAL_PIN_FMT ", mosi=" MP_HAL_PIN_FMT ", miso=" MP_HAL_PIN_FMT ")",
|
||||||
@ -154,8 +196,19 @@ static void mp_machine_soft_spi_print(const mp_print_t *print, mp_obj_t self_in,
|
|||||||
mp_hal_pin_name(self->spi.sck), mp_hal_pin_name(self->spi.mosi), mp_hal_pin_name(self->spi.miso));
|
mp_hal_pin_name(self->spi.sck), mp_hal_pin_name(self->spi.mosi), mp_hal_pin_name(self->spi.miso));
|
||||||
}
|
}
|
||||||
|
|
||||||
static mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
static mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args)
|
||||||
enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso };
|
{
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ARG_baudrate,
|
||||||
|
ARG_polarity,
|
||||||
|
ARG_phase,
|
||||||
|
ARG_bits,
|
||||||
|
ARG_firstbit,
|
||||||
|
ARG_sck,
|
||||||
|
ARG_mosi,
|
||||||
|
ARG_miso
|
||||||
|
};
|
||||||
static const mp_arg_t allowed_args[] = {
|
static const mp_arg_t allowed_args[] = {
|
||||||
{MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 500000}},
|
{MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 500000}},
|
||||||
{MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0}},
|
{MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0}},
|
||||||
@ -176,13 +229,13 @@ static mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n
|
|||||||
self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
|
self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
|
||||||
self->spi.polarity = args[ARG_polarity].u_int;
|
self->spi.polarity = args[ARG_polarity].u_int;
|
||||||
self->spi.phase = args[ARG_phase].u_int;
|
self->spi.phase = args[ARG_phase].u_int;
|
||||||
if (args[ARG_bits].u_int != 8) {
|
if (args[ARG_bits].u_int != 8)
|
||||||
|
{
|
||||||
mp_raise_ValueError(MP_ERROR_TEXT("bits must be 8"));
|
mp_raise_ValueError(MP_ERROR_TEXT("bits must be 8"));
|
||||||
}
|
}
|
||||||
self->spi.firstbit = args[ARG_firstbit].u_int;
|
self->spi.firstbit = args[ARG_firstbit].u_int;
|
||||||
if (args[ARG_sck].u_obj == MP_OBJ_NULL
|
if (args[ARG_sck].u_obj == MP_OBJ_NULL || args[ARG_mosi].u_obj == MP_OBJ_NULL || args[ARG_miso].u_obj == MP_OBJ_NULL)
|
||||||
|| args[ARG_mosi].u_obj == MP_OBJ_NULL
|
{
|
||||||
|| args[ARG_miso].u_obj == MP_OBJ_NULL) {
|
|
||||||
mp_raise_ValueError(MP_ERROR_TEXT("must specify all of sck/mosi/miso"));
|
mp_raise_ValueError(MP_ERROR_TEXT("must specify all of sck/mosi/miso"));
|
||||||
}
|
}
|
||||||
self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
|
self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
|
||||||
@ -195,10 +248,20 @@ static mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n
|
|||||||
return MP_OBJ_FROM_PTR(self);
|
return MP_OBJ_FROM_PTR(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mp_machine_soft_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
static void mp_machine_soft_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
|
||||||
|
{
|
||||||
mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t *)self_in;
|
mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t *)self_in;
|
||||||
|
|
||||||
enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso };
|
enum
|
||||||
|
{
|
||||||
|
ARG_baudrate,
|
||||||
|
ARG_polarity,
|
||||||
|
ARG_phase,
|
||||||
|
ARG_firstbit,
|
||||||
|
ARG_sck,
|
||||||
|
ARG_mosi,
|
||||||
|
ARG_miso
|
||||||
|
};
|
||||||
static const mp_arg_t allowed_args[] = {
|
static const mp_arg_t allowed_args[] = {
|
||||||
{MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1}},
|
{MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1}},
|
||||||
{MP_QSTR_polarity, MP_ARG_INT, {.u_int = -1}},
|
{MP_QSTR_polarity, MP_ARG_INT, {.u_int = -1}},
|
||||||
@ -211,25 +274,32 @@ static void mp_machine_soft_spi_init(mp_obj_base_t *self_in, size_t n_args, cons
|
|||||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
|
||||||
if (args[ARG_baudrate].u_int != -1) {
|
if (args[ARG_baudrate].u_int != -1)
|
||||||
|
{
|
||||||
self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
|
self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
|
||||||
}
|
}
|
||||||
if (args[ARG_polarity].u_int != -1) {
|
if (args[ARG_polarity].u_int != -1)
|
||||||
|
{
|
||||||
self->spi.polarity = args[ARG_polarity].u_int;
|
self->spi.polarity = args[ARG_polarity].u_int;
|
||||||
}
|
}
|
||||||
if (args[ARG_phase].u_int != -1) {
|
if (args[ARG_phase].u_int != -1)
|
||||||
|
{
|
||||||
self->spi.phase = args[ARG_phase].u_int;
|
self->spi.phase = args[ARG_phase].u_int;
|
||||||
}
|
}
|
||||||
if (args[ARG_firstbit].u_int != -1) {
|
if (args[ARG_firstbit].u_int != -1)
|
||||||
|
{
|
||||||
self->spi.firstbit = args[ARG_firstbit].u_int;
|
self->spi.firstbit = args[ARG_firstbit].u_int;
|
||||||
}
|
}
|
||||||
if (args[ARG_sck].u_obj != MP_OBJ_NULL) {
|
if (args[ARG_sck].u_obj != MP_OBJ_NULL)
|
||||||
|
{
|
||||||
self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
|
self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
|
||||||
}
|
}
|
||||||
if (args[ARG_mosi].u_obj != MP_OBJ_NULL) {
|
if (args[ARG_mosi].u_obj != MP_OBJ_NULL)
|
||||||
|
{
|
||||||
self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);
|
self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);
|
||||||
}
|
}
|
||||||
if (args[ARG_miso].u_obj != MP_OBJ_NULL) {
|
if (args[ARG_miso].u_obj != MP_OBJ_NULL)
|
||||||
|
{
|
||||||
self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
|
self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +307,8 @@ static void mp_machine_soft_spi_init(mp_obj_base_t *self_in, size_t n_args, cons
|
|||||||
mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT);
|
mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
|
static void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest)
|
||||||
|
{
|
||||||
mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t *)self_in;
|
mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t *)self_in;
|
||||||
mp_soft_spi_transfer(&self->spi, len, src, dest);
|
mp_soft_spi_transfer(&self->spi, len, src, dest);
|
||||||
}
|
}
|
||||||
@ -255,7 +326,6 @@ MP_DEFINE_CONST_OBJ_TYPE(
|
|||||||
make_new, mp_machine_soft_spi_make_new,
|
make_new, mp_machine_soft_spi_make_new,
|
||||||
print, mp_machine_soft_spi_print,
|
print, mp_machine_soft_spi_print,
|
||||||
protocol, &mp_machine_soft_spi_p,
|
protocol, &mp_machine_soft_spi_p,
|
||||||
locals_dict, &mp_machine_spi_locals_dict
|
locals_dict, &mp_machine_spi_locals_dict);
|
||||||
);
|
|
||||||
|
|
||||||
#endif // MICROPY_PY_MACHINE_SOFTSPI
|
#endif // MICROPY_PY_MACHINE_SOFTSPI
|
||||||
|
|||||||
@ -90,10 +90,13 @@
|
|||||||
|
|
||||||
// Temporary support for legacy construction of SoftI2C via I2C type.
|
// Temporary support for legacy construction of SoftI2C via I2C type.
|
||||||
#define MP_MACHINE_I2C_CHECK_FOR_LEGACY_SOFTI2C_CONSTRUCTION(n_args, n_kw, all_args) \
|
#define MP_MACHINE_I2C_CHECK_FOR_LEGACY_SOFTI2C_CONSTRUCTION(n_args, n_kw, all_args) \
|
||||||
do { \
|
do \
|
||||||
if (n_args == 0 || all_args[0] == MP_OBJ_NEW_SMALL_INT(-1)) { \
|
{ \
|
||||||
|
if (n_args == 0 || all_args[0] == MP_OBJ_NEW_SMALL_INT(-1)) \
|
||||||
|
{ \
|
||||||
mp_print_str(MICROPY_ERROR_PRINTER, "Warning: I2C(-1, ...) is deprecated, use SoftI2C(...) instead\n"); \
|
mp_print_str(MICROPY_ERROR_PRINTER, "Warning: I2C(-1, ...) is deprecated, use SoftI2C(...) instead\n"); \
|
||||||
if (n_args != 0) { \
|
if (n_args != 0) \
|
||||||
|
{ \
|
||||||
--n_args; \
|
--n_args; \
|
||||||
++all_args; \
|
++all_args; \
|
||||||
} \
|
} \
|
||||||
@ -103,10 +106,13 @@
|
|||||||
|
|
||||||
// Temporary support for legacy construction of SoftSPI via SPI type.
|
// Temporary support for legacy construction of SoftSPI via SPI type.
|
||||||
#define MP_MACHINE_SPI_CHECK_FOR_LEGACY_SOFTSPI_CONSTRUCTION(n_args, n_kw, all_args) \
|
#define MP_MACHINE_SPI_CHECK_FOR_LEGACY_SOFTSPI_CONSTRUCTION(n_args, n_kw, all_args) \
|
||||||
do { \
|
do \
|
||||||
if (n_args == 0 || all_args[0] == MP_OBJ_NEW_SMALL_INT(-1)) { \
|
{ \
|
||||||
|
if (n_args == 0 || all_args[0] == MP_OBJ_NEW_SMALL_INT(-1)) \
|
||||||
|
{ \
|
||||||
mp_print_str(MICROPY_ERROR_PRINTER, "Warning: SPI(-1, ...) is deprecated, use SoftSPI(...) instead\n"); \
|
mp_print_str(MICROPY_ERROR_PRINTER, "Warning: SPI(-1, ...) is deprecated, use SoftSPI(...) instead\n"); \
|
||||||
if (n_args != 0) { \
|
if (n_args != 0) \
|
||||||
|
{ \
|
||||||
--n_args; \
|
--n_args; \
|
||||||
++all_args; \
|
++all_args; \
|
||||||
} \
|
} \
|
||||||
@ -134,14 +140,16 @@ typedef struct _machine_pwm_obj_t machine_pwm_obj_t;
|
|||||||
typedef struct _machine_uart_obj_t machine_uart_obj_t;
|
typedef struct _machine_uart_obj_t machine_uart_obj_t;
|
||||||
typedef struct _machine_wdt_obj_t machine_wdt_obj_t;
|
typedef struct _machine_wdt_obj_t machine_wdt_obj_t;
|
||||||
|
|
||||||
typedef struct _machine_mem_obj_t {
|
typedef struct _machine_mem_obj_t
|
||||||
|
{
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
unsigned elem_size; // in bytes
|
unsigned elem_size; // in bytes
|
||||||
} machine_mem_obj_t;
|
} machine_mem_obj_t;
|
||||||
|
|
||||||
#if MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C
|
#if MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C
|
||||||
|
|
||||||
typedef struct _mp_machine_i2c_buf_t {
|
typedef struct _mp_machine_i2c_buf_t
|
||||||
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
} mp_machine_i2c_buf_t;
|
} mp_machine_i2c_buf_t;
|
||||||
@ -151,7 +159,8 @@ typedef struct _mp_machine_i2c_buf_t {
|
|||||||
// - start/stop/read/write can be NULL, meaning operation is not supported
|
// - start/stop/read/write can be NULL, meaning operation is not supported
|
||||||
// - transfer must be non-NULL
|
// - transfer must be non-NULL
|
||||||
// - transfer_single only needs to be set if transfer=mp_machine_i2c_transfer_adaptor
|
// - transfer_single only needs to be set if transfer=mp_machine_i2c_transfer_adaptor
|
||||||
typedef struct _mp_machine_i2c_p_t {
|
typedef struct _mp_machine_i2c_p_t
|
||||||
|
{
|
||||||
#if MICROPY_PY_MACHINE_I2C_TRANSFER_WRITE1
|
#if MICROPY_PY_MACHINE_I2C_TRANSFER_WRITE1
|
||||||
bool transfer_supports_write1;
|
bool transfer_supports_write1;
|
||||||
#endif
|
#endif
|
||||||
@ -165,7 +174,8 @@ typedef struct _mp_machine_i2c_p_t {
|
|||||||
} mp_machine_i2c_p_t;
|
} mp_machine_i2c_p_t;
|
||||||
|
|
||||||
// SoftI2C object.
|
// SoftI2C object.
|
||||||
typedef struct _mp_machine_soft_i2c_obj_t {
|
typedef struct _mp_machine_soft_i2c_obj_t
|
||||||
|
{
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
uint32_t us_delay;
|
uint32_t us_delay;
|
||||||
uint32_t us_timeout;
|
uint32_t us_timeout;
|
||||||
@ -178,14 +188,18 @@ typedef struct _mp_machine_soft_i2c_obj_t {
|
|||||||
#if MICROPY_PY_MACHINE_SPI || MICROPY_PY_MACHINE_SOFTSPI
|
#if MICROPY_PY_MACHINE_SPI || MICROPY_PY_MACHINE_SOFTSPI
|
||||||
|
|
||||||
// SPI protocol.
|
// SPI protocol.
|
||||||
typedef struct _mp_machine_spi_p_t {
|
typedef struct _mp_machine_spi_p_t
|
||||||
|
{
|
||||||
void (*init)(mp_obj_base_t *obj, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
void (*init)(mp_obj_base_t *obj, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||||
void (*deinit)(mp_obj_base_t *obj); // can be NULL
|
void (*deinit)(mp_obj_base_t *obj); // can be NULL
|
||||||
void (*transfer)(mp_obj_base_t *obj, size_t len, const uint8_t *src, uint8_t *dest);
|
void (*transfer)(mp_obj_base_t *obj, size_t len, const uint8_t *src, uint8_t *dest);
|
||||||
|
void (*wait_done)(mp_obj_base_t *obj); // can be NULL
|
||||||
|
void (*set_tx_isr)(mp_obj_base_t *obj, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); // can be NULL
|
||||||
} mp_machine_spi_p_t;
|
} mp_machine_spi_p_t;
|
||||||
|
|
||||||
// SoftSPI object.
|
// SoftSPI object.
|
||||||
typedef struct _mp_machine_soft_spi_obj_t {
|
typedef struct _mp_machine_soft_spi_obj_t
|
||||||
|
{
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
mp_soft_spi_obj_t spi;
|
mp_soft_spi_obj_t spi;
|
||||||
} mp_machine_soft_spi_obj_t;
|
} mp_machine_soft_spi_obj_t;
|
||||||
|
|||||||
17
make_and_flash_rp2.sh
Executable file
17
make_and_flash_rp2.sh
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
rm -rf ./ports/rp2/build-RPI_PICO/*
|
||||||
|
|
||||||
|
make -j -C ports/rp2 BOARD=RPI_PICO USER_C_MODULES=../../user_modules/user.cmake
|
||||||
|
exit status=$?
|
||||||
|
# 检查编译是否成功
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "编译成功,开始烧录固件..."
|
||||||
|
sudo mount /dev/sde1 /mnt/usb
|
||||||
|
sudo cp ./ports/rp2/build-RPI_PICO/firmware.uf2 /mnt/usb/
|
||||||
|
sudo umount /mnt/usb
|
||||||
|
echo "Firmware flashed to RPI_PICO"
|
||||||
|
echo "You can now safely eject the RPI_PICO from your computer."
|
||||||
|
else
|
||||||
|
echo "编译失败,已取消烧录操作"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@ -2,4 +2,4 @@
|
|||||||
#define MICROPY_HW_BOARD_NAME "Raspberry Pi Pico"
|
#define MICROPY_HW_BOARD_NAME "Raspberry Pi Pico"
|
||||||
// Modified from MPY origin to reduce flash storage to accommodate larger program flash requirement
|
// Modified from MPY origin to reduce flash storage to accommodate larger program flash requirement
|
||||||
// of lvgl and its bindings. Developers should review this setting when adding additional features
|
// of lvgl and its bindings. Developers should review this setting when adding additional features
|
||||||
#define MICROPY_HW_FLASH_STORAGE_BYTES (1024 * 1024)
|
#define MICROPY_HW_FLASH_STORAGE_BYTES (512 * 1024)
|
||||||
|
|||||||
@ -25,8 +25,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
|
#include "py/gc.h"
|
||||||
#include "py/mphal.h"
|
#include "py/mphal.h"
|
||||||
#include "py/mperrno.h"
|
#include "py/mperrno.h"
|
||||||
|
#include "shared/runtime/mpirq.h"
|
||||||
#include "extmod/modmachine.h"
|
#include "extmod/modmachine.h"
|
||||||
|
|
||||||
#include "hardware/spi.h"
|
#include "hardware/spi.h"
|
||||||
@ -101,6 +103,10 @@ typedef struct _machine_spi_obj_t {
|
|||||||
uint8_t mosi;
|
uint8_t mosi;
|
||||||
uint8_t miso;
|
uint8_t miso;
|
||||||
uint32_t baudrate;
|
uint32_t baudrate;
|
||||||
|
int chan_tx;
|
||||||
|
int chan_rx;
|
||||||
|
// 这里只为屏幕设置了tx中断,用来控制cs引脚和lv.disp_flush_ready()
|
||||||
|
mp_irq_obj_t *tx_isr_obj;
|
||||||
} machine_spi_obj_t;
|
} machine_spi_obj_t;
|
||||||
|
|
||||||
static machine_spi_obj_t machine_spi_obj[] = {
|
static machine_spi_obj_t machine_spi_obj[] = {
|
||||||
@ -109,12 +115,20 @@ static machine_spi_obj_t machine_spi_obj[] = {
|
|||||||
DEFAULT_SPI_POLARITY, DEFAULT_SPI_PHASE, DEFAULT_SPI_BITS, DEFAULT_SPI_FIRSTBIT,
|
DEFAULT_SPI_POLARITY, DEFAULT_SPI_PHASE, DEFAULT_SPI_BITS, DEFAULT_SPI_FIRSTBIT,
|
||||||
MICROPY_HW_SPI0_SCK, MICROPY_HW_SPI0_MOSI, MICROPY_HW_SPI0_MISO,
|
MICROPY_HW_SPI0_SCK, MICROPY_HW_SPI0_MOSI, MICROPY_HW_SPI0_MISO,
|
||||||
0,
|
0,
|
||||||
|
// DMA channels, -1 means not claimed
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
NULL
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{&machine_spi_type}, spi1, 1,
|
{&machine_spi_type}, spi1, 1,
|
||||||
DEFAULT_SPI_POLARITY, DEFAULT_SPI_PHASE, DEFAULT_SPI_BITS, DEFAULT_SPI_FIRSTBIT,
|
DEFAULT_SPI_POLARITY, DEFAULT_SPI_PHASE, DEFAULT_SPI_BITS, DEFAULT_SPI_FIRSTBIT,
|
||||||
MICROPY_HW_SPI1_SCK, MICROPY_HW_SPI1_MOSI, MICROPY_HW_SPI1_MISO,
|
MICROPY_HW_SPI1_SCK, MICROPY_HW_SPI1_MOSI, MICROPY_HW_SPI1_MISO,
|
||||||
0,
|
0,
|
||||||
|
// DMA channels, -1 means not claimed
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
NULL
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -166,6 +180,8 @@ mp_obj_t machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
|
|||||||
mp_raise_ValueError(MP_ERROR_TEXT("bad MOSI pin"));
|
mp_raise_ValueError(MP_ERROR_TEXT("bad MOSI pin"));
|
||||||
}
|
}
|
||||||
self->mosi = mosi;
|
self->mosi = mosi;
|
||||||
|
if (self->chan_tx < 0)
|
||||||
|
self->chan_tx = dma_claim_unused_channel(true);
|
||||||
}
|
}
|
||||||
if (args[ARG_miso].u_obj != mp_const_none) {
|
if (args[ARG_miso].u_obj != mp_const_none) {
|
||||||
int miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
|
int miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
|
||||||
@ -173,6 +189,8 @@ mp_obj_t machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
|
|||||||
mp_raise_ValueError(MP_ERROR_TEXT("bad MISO pin"));
|
mp_raise_ValueError(MP_ERROR_TEXT("bad MISO pin"));
|
||||||
}
|
}
|
||||||
self->miso = miso;
|
self->miso = miso;
|
||||||
|
if (self->chan_rx < 0)
|
||||||
|
self->chan_rx = dma_claim_unused_channel(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialise the SPI peripheral if any arguments given, or it was not initialised previously.
|
// Initialise the SPI peripheral if any arguments given, or it was not initialised previously.
|
||||||
@ -233,41 +251,175 @@ static void machine_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj
|
|||||||
}
|
}
|
||||||
if (args[ARG_firstbit].u_int != -1) {
|
if (args[ARG_firstbit].u_int != -1) {
|
||||||
self->firstbit = args[ARG_firstbit].u_int;
|
self->firstbit = args[ARG_firstbit].u_int;
|
||||||
if (self->firstbit == SPI_LSB_FIRST) {
|
if (self->firstbit == SPI_LSB_FIRST)
|
||||||
|
{
|
||||||
mp_raise_NotImplementedError(MP_ERROR_TEXT("LSB"));
|
mp_raise_NotImplementedError(MP_ERROR_TEXT("LSB"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (self->miso > 0 && self->chan_rx < 0) {
|
||||||
|
self->chan_rx = dma_claim_unused_channel(true);
|
||||||
|
}
|
||||||
|
if (self->mosi > 0 && self->chan_tx < 0) {
|
||||||
|
self->chan_tx = dma_claim_unused_channel(true);
|
||||||
|
}
|
||||||
if (set_format) {
|
if (set_format) {
|
||||||
spi_set_format(self->spi_inst, self->bits, self->polarity, self->phase, self->firstbit);
|
spi_set_format(self->spi_inst, self->bits, self->polarity, self->phase, self->firstbit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void machine_spi0_tx_irq_handler(void)
|
||||||
|
{
|
||||||
|
// currently only used for spi0
|
||||||
|
// mp_printf(&mp_plat_print, "program running isr spi0 tx irq %d\n", __LINE__);
|
||||||
|
machine_spi_obj_t *self = &machine_spi_obj[0];
|
||||||
|
spi_hw_t *spi_hw = spi_get_hw(self->spi_inst);
|
||||||
|
// clear the interrupt flag
|
||||||
|
spi_hw->imsc &= ~(1 << 3);
|
||||||
|
// 检查是否是发送FIFO中断(已屏蔽的中断)
|
||||||
|
// if (spi_hw->mis & (1 << 3)) { // TXMIS=1
|
||||||
|
// 确认发送真正完成:发送FIFO为空且SPI不忙
|
||||||
|
// mp_raise_msg_varg(&mp_type_AssertionError, MP_ERROR_TEXT("IRQ triggered"));
|
||||||
|
if ((spi_hw->sr & (1 << 0)) && !(spi_hw->sr & (1 << 4)) && dma_channel_is_busy(self->chan_tx) == false) {
|
||||||
|
if (self->tx_isr_obj != NULL && self->tx_isr_obj->handler != mp_const_none)
|
||||||
|
{
|
||||||
|
// mp_printf(&mp_plat_print, "program running isr spi0 tx irq %d\n", __LINE__);
|
||||||
|
if(self->tx_isr_obj->ishard){
|
||||||
|
// mp_sched_lock();
|
||||||
|
// gc_lock();
|
||||||
|
mp_call_function_1(self->tx_isr_obj->handler, self->tx_isr_obj->parent);
|
||||||
|
// gc_unlock();
|
||||||
|
// mp_sched_unlock();
|
||||||
|
} else {
|
||||||
|
mp_irq_handler(self->tx_isr_obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void machine_spi1_tx_irq_handler(void)
|
||||||
|
{
|
||||||
|
// currently not used
|
||||||
|
machine_spi_obj_t *self = &machine_spi_obj[1];
|
||||||
|
spi_hw_t *spi_hw = spi_get_hw(self->spi_inst);
|
||||||
|
// clear the interrupt flag
|
||||||
|
spi_hw->imsc &= ~(1 << 3);
|
||||||
|
if (spi_hw->mis & (1 << 3)) { // TXMIS=1
|
||||||
|
// 确认发送真正完成:发送FIFO为空且SPI不忙
|
||||||
|
if ((spi_hw->sr & (1 << 0)) && !(spi_hw->sr & (1 << 4))) {
|
||||||
|
if (self->tx_isr_obj != NULL && self->tx_isr_obj->handler != mp_const_none)
|
||||||
|
{
|
||||||
|
mp_irq_handler(self->tx_isr_obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void machine_spi_set_tx_isr(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
|
||||||
|
{
|
||||||
|
machine_spi_obj_t *self = (machine_spi_obj_t *)self_in;
|
||||||
|
if (self->tx_isr_obj == NULL) {
|
||||||
|
self->tx_isr_obj = m_new_obj(mp_irq_obj_t);
|
||||||
|
// MP_STATE_PORT(rp2_uart_irq_obj)[self->uart_id] = self->mp_irq_obj;
|
||||||
|
}
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ARG_tx_isr,
|
||||||
|
ARG_hard
|
||||||
|
};
|
||||||
|
static const mp_arg_t allowed_args[] = {
|
||||||
|
{MP_QSTR_tx_isr, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none}},
|
||||||
|
{ MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
|
||||||
|
};
|
||||||
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
|
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
|
||||||
|
if (n_args < 1) {
|
||||||
|
mp_raise_ValueError(MP_ERROR_TEXT("missing tx_isr"));
|
||||||
|
}
|
||||||
|
mp_obj_t handler = args[ARG_tx_isr].u_obj;
|
||||||
|
if (handler == mp_const_none || !mp_obj_is_callable(handler)) {
|
||||||
|
mp_raise_ValueError(MP_ERROR_TEXT("handler must be callable"));
|
||||||
|
}
|
||||||
|
if (self->tx_isr_obj == NULL) {
|
||||||
|
// disable previous irq
|
||||||
|
}
|
||||||
|
irq_set_enabled(self->spi_id == 0 ? SPI0_IRQ : SPI1_IRQ, false);
|
||||||
|
self->tx_isr_obj->handler = handler;
|
||||||
|
// self->tx_isr_obj->base.type = &mp_type_irq;
|
||||||
|
// self->tx_isr_obj->methods = &mp_irq_methods;
|
||||||
|
self->tx_isr_obj->ishard = args[ARG_hard].u_bool;
|
||||||
|
self->tx_isr_obj->parent = MP_OBJ_FROM_PTR(self);
|
||||||
|
|
||||||
|
|
||||||
|
irq_set_exclusive_handler(self->spi_id == 0 ? SPI0_IRQ : SPI1_IRQ, self->spi_id == 0 ? machine_spi0_tx_irq_handler : machine_spi1_tx_irq_handler);
|
||||||
|
spi_hw_t *spi_hw = spi_get_hw(self->spi_inst);
|
||||||
|
spi_hw->imsc |= (1 << 3);
|
||||||
|
irq_set_enabled(self->spi_id == 0 ? SPI0_IRQ : SPI1_IRQ, true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void machine_spi_wait_done(mp_obj_base_t *self_in)
|
||||||
|
{
|
||||||
|
machine_spi_obj_t *self = (machine_spi_obj_t *)self_in;
|
||||||
|
int chan_tx = self->chan_tx;
|
||||||
|
int chan_rx = self->chan_rx;
|
||||||
|
if (chan_rx >= 0)
|
||||||
|
dma_channel_wait_for_finish_blocking(chan_rx);
|
||||||
|
if (chan_tx >= 0)
|
||||||
|
dma_channel_wait_for_finish_blocking(chan_tx);
|
||||||
|
spi_hw_t *spi_hw = spi_get_hw(self->spi_inst);
|
||||||
|
while (!((spi_hw->sr & (1 << 0)) && !(spi_hw->sr & (1 << 4)))) {
|
||||||
|
// wait for TX FIFO to be empty and SPI not busy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void machine_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
|
static void machine_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
|
||||||
machine_spi_obj_t *self = (machine_spi_obj_t *)self_in;
|
machine_spi_obj_t *self = (machine_spi_obj_t *)self_in;
|
||||||
// Use DMA for large transfers if channels are available
|
|
||||||
const size_t dma_min_size_threshold = 32;
|
|
||||||
int chan_tx = -1;
|
|
||||||
int chan_rx = -1;
|
|
||||||
if (len >= dma_min_size_threshold) {
|
|
||||||
// Use two DMA channels to service the two FIFOs
|
|
||||||
chan_tx = dma_claim_unused_channel(false);
|
|
||||||
chan_rx = dma_claim_unused_channel(false);
|
|
||||||
}
|
|
||||||
bool use_dma = chan_rx >= 0 && chan_tx >= 0;
|
|
||||||
// note src is guaranteed to be non-NULL
|
|
||||||
bool write_only = dest == NULL;
|
bool write_only = dest == NULL;
|
||||||
|
const size_t dma_min_size_threshold = 8;
|
||||||
|
if (len <= dma_min_size_threshold){
|
||||||
|
// Use software for small transfers
|
||||||
|
if (write_only) {
|
||||||
|
spi_write_blocking(self->spi_inst, src, len);
|
||||||
|
} else {
|
||||||
|
spi_write_read_blocking(self->spi_inst, src, dest, len);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Use DMA for large transfers if channels are available
|
||||||
|
int chan_tx = self->chan_tx;
|
||||||
|
int chan_rx = self->chan_rx;
|
||||||
|
if (chan_rx < 0 && chan_tx < 0)
|
||||||
|
{
|
||||||
|
mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("Error when using DMA, chan rx: %d, chan tx: %d"), chan_rx, chan_tx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// if (chan_rx >= 0)
|
||||||
|
// dma_channel_wait_for_finish_blocking(chan_rx);
|
||||||
|
// if (chan_tx >= 0)
|
||||||
|
// dma_channel_wait_for_finish_blocking(chan_tx);
|
||||||
|
machine_spi_wait_done(self_in);
|
||||||
|
// bool use_dma = chan_rx >= 0 && chan_tx >= 0;
|
||||||
|
// note src is guaranteed to be non-NULL
|
||||||
|
|
||||||
if (use_dma) {
|
|
||||||
uint8_t dev_null;
|
uint8_t dev_null;
|
||||||
dma_channel_config c = dma_channel_get_default_config(chan_tx);
|
dma_channel_config c;
|
||||||
|
if (chan_tx >= 0)
|
||||||
|
{
|
||||||
|
c = dma_channel_get_default_config(chan_tx);
|
||||||
channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
|
channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
|
||||||
channel_config_set_dreq(&c, spi_get_index(self->spi_inst) ? DREQ_SPI1_TX : DREQ_SPI0_TX);
|
channel_config_set_dreq(&c, spi_get_index(self->spi_inst) ? DREQ_SPI1_TX : DREQ_SPI0_TX);
|
||||||
dma_channel_configure(chan_tx, &c,
|
dma_channel_configure(chan_tx, &c,
|
||||||
&spi_get_hw(self->spi_inst)->dr,
|
&spi_get_hw(self->spi_inst)->dr,
|
||||||
src,
|
src,
|
||||||
len,
|
len,
|
||||||
false);
|
true);
|
||||||
|
}
|
||||||
|
if (chan_rx >= 0)
|
||||||
|
{
|
||||||
c = dma_channel_get_default_config(chan_rx);
|
c = dma_channel_get_default_config(chan_rx);
|
||||||
channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
|
channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
|
||||||
channel_config_set_dreq(&c, spi_get_index(self->spi_inst) ? DREQ_SPI1_RX : DREQ_SPI0_RX);
|
channel_config_set_dreq(&c, spi_get_index(self->spi_inst) ? DREQ_SPI1_RX : DREQ_SPI0_RX);
|
||||||
@ -277,29 +429,28 @@ static void machine_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8
|
|||||||
write_only ? &dev_null : dest,
|
write_only ? &dev_null : dest,
|
||||||
&spi_get_hw(self->spi_inst)->dr,
|
&spi_get_hw(self->spi_inst)->dr,
|
||||||
len,
|
len,
|
||||||
false);
|
true);
|
||||||
|
|
||||||
dma_start_channel_mask((1u << chan_rx) | (1u << chan_tx));
|
|
||||||
dma_channel_wait_for_finish_blocking(chan_rx);
|
|
||||||
dma_channel_wait_for_finish_blocking(chan_tx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dma_channel_wait_for_finish_blocking(chan_rx);
|
||||||
|
// dma_channel_wait_for_finish_blocking(chan_tx);
|
||||||
|
|
||||||
// If we have claimed only one channel successfully, we should release immediately
|
// If we have claimed only one channel successfully, we should release immediately
|
||||||
if (chan_rx >= 0) {
|
// if (chan_rx >= 0) {
|
||||||
dma_channel_unclaim(chan_rx);
|
// dma_channel_unclaim(chan_rx);
|
||||||
}
|
// }
|
||||||
if (chan_tx >= 0) {
|
// if (chan_tx >= 0) {
|
||||||
dma_channel_unclaim(chan_tx);
|
// dma_channel_unclaim(chan_tx);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (!use_dma) {
|
// if (!use_dma) {
|
||||||
// Use software for small transfers, or if couldn't claim two DMA channels
|
// // Use software for small transfers, or if couldn't claim two DMA channels
|
||||||
if (write_only) {
|
// if (write_only) {
|
||||||
spi_write_blocking(self->spi_inst, src, len);
|
// spi_write_blocking(self->spi_inst, src, len);
|
||||||
} else {
|
// } else {
|
||||||
spi_write_read_blocking(self->spi_inst, src, dest, len);
|
// spi_write_read_blocking(self->spi_inst, src, dest, len);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buffer protocol implementation for SPI.
|
// Buffer protocol implementation for SPI.
|
||||||
@ -317,6 +468,8 @@ static mp_int_t machine_spi_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo,
|
|||||||
static const mp_machine_spi_p_t machine_spi_p = {
|
static const mp_machine_spi_p_t machine_spi_p = {
|
||||||
.init = machine_spi_init,
|
.init = machine_spi_init,
|
||||||
.transfer = machine_spi_transfer,
|
.transfer = machine_spi_transfer,
|
||||||
|
.wait_done = machine_spi_wait_done,
|
||||||
|
.set_tx_isr = machine_spi_set_tx_isr,
|
||||||
};
|
};
|
||||||
|
|
||||||
MP_DEFINE_CONST_OBJ_TYPE(
|
MP_DEFINE_CONST_OBJ_TYPE(
|
||||||
|
|||||||
341
user_modules/eigenmath/eheap.c
Normal file
341
user_modules/eigenmath/eheap.c
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
/*========================================================================
|
||||||
|
* eheap.c – Improved standalone heap manager
|
||||||
|
* 32-bit, aligned, safe operations
|
||||||
|
*======================================================================*/
|
||||||
|
|
||||||
|
#include "eheap.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "py/runtime.h"
|
||||||
|
|
||||||
|
#ifndef EHEAP_ALIGN
|
||||||
|
#define EHEAP_ALIGN 4 /* default byte alignment (power of two) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ALIGN_MASK (EHEAP_ALIGN - 1)
|
||||||
|
#define ALIGN_UP(x) (((x) + ALIGN_MASK) & ~ALIGN_MASK)
|
||||||
|
|
||||||
|
/*-------------------------------------------------- block header layout */
|
||||||
|
typedef struct block_link {
|
||||||
|
struct block_link *next;
|
||||||
|
size_t size; /* MSB=1 => allocated, lower bits => block size */
|
||||||
|
} block_t;
|
||||||
|
|
||||||
|
#define USED_MASK ((size_t)1 << (sizeof(size_t)*8 - 1))
|
||||||
|
#define IS_USED(b) (((b)->size) & USED_MASK)
|
||||||
|
#define MARK_USED(b) ((b)->size |= USED_MASK)
|
||||||
|
#define MARK_FREE(b) ((b)->size &= ~USED_MASK)
|
||||||
|
#define BLOCK_SIZE(b) ((b)->size & ~USED_MASK)
|
||||||
|
|
||||||
|
#define HDR_SIZE ALIGN_UP(sizeof(block_t))
|
||||||
|
#define MIN_SPLIT (HDR_SIZE * 2)
|
||||||
|
|
||||||
|
/*-------------------------------------------------- heap globals */
|
||||||
|
static uint8_t *heap_base = NULL;
|
||||||
|
static uint8_t *heap_end = NULL;
|
||||||
|
static size_t heap_total = 0;
|
||||||
|
|
||||||
|
static block_t start_node; /* dummy head */
|
||||||
|
static block_t end_marker; /* tail sentinel storage */
|
||||||
|
static block_t *end_node = &end_marker;
|
||||||
|
|
||||||
|
static size_t free_bytes = 0;
|
||||||
|
static size_t min_free = 0;
|
||||||
|
static bool initialized = false;
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------*/
|
||||||
|
static bool is_valid_block(block_t *blk) {
|
||||||
|
uint8_t *ptr = (uint8_t*)blk;
|
||||||
|
if (ptr < heap_base || ptr >= heap_end) return false;
|
||||||
|
return (((uintptr_t)ptr - (uintptr_t)heap_base) & ALIGN_MASK) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert and coalesce a free block (address-ordered), with overflow guards */
|
||||||
|
static void insert_free(block_t *blk) {
|
||||||
|
if (!is_valid_block(blk) || IS_USED(blk)) {
|
||||||
|
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("insert_free: invalid or used block"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t blk_sz = BLOCK_SIZE(blk);
|
||||||
|
/* guard pointer addition overflow */
|
||||||
|
if (blk_sz > (size_t)(heap_end - (uint8_t*)blk)) {
|
||||||
|
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("insert_free: block size overflow"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t *blk_end = (uint8_t*)blk + blk_sz;
|
||||||
|
|
||||||
|
block_t *prev = &start_node;
|
||||||
|
/* find insertion point */
|
||||||
|
while (prev->next < blk && prev->next != end_node) {
|
||||||
|
prev = prev->next;
|
||||||
|
if (!is_valid_block(prev)) {
|
||||||
|
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("insert_free: corrupted free list"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* forward merge */
|
||||||
|
if (prev->next != end_node) {
|
||||||
|
block_t *fwd = prev->next;
|
||||||
|
if (!IS_USED(fwd) &&
|
||||||
|
(uint8_t*)fwd == blk_end) {
|
||||||
|
/* fuse sizes */
|
||||||
|
size_t total = blk_sz + BLOCK_SIZE(fwd);
|
||||||
|
if (total < blk_sz) { /* overflow? */
|
||||||
|
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("insert_free: combine overflow"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
blk->size = total;
|
||||||
|
blk->next = fwd->next;
|
||||||
|
blk_sz = total; /* update for potential backward merge */
|
||||||
|
} else {
|
||||||
|
blk->next = fwd;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
blk->next = end_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* backward merge */
|
||||||
|
if (prev != &start_node && !IS_USED(prev)) {
|
||||||
|
uint8_t *prev_end = (uint8_t*)prev + BLOCK_SIZE(prev);
|
||||||
|
if (prev_end == (uint8_t*)blk) {
|
||||||
|
size_t total = BLOCK_SIZE(prev) + blk_sz;
|
||||||
|
if (total < BLOCK_SIZE(prev)) { /* overflow? */
|
||||||
|
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("insert_free: combine overflow"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prev->size = total;
|
||||||
|
prev->next = blk->next;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev->next = blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void heap_init_once(void) {
|
||||||
|
if (initialized) return;
|
||||||
|
|
||||||
|
/* single free block covers [heap_base .. heap_end) excluding end_node */
|
||||||
|
block_t *first = (block_t*)heap_base;
|
||||||
|
first->size = (heap_total - HDR_SIZE);
|
||||||
|
MARK_FREE(first);
|
||||||
|
first->next = end_node;
|
||||||
|
|
||||||
|
start_node.next = first;
|
||||||
|
start_node.size = 0;
|
||||||
|
|
||||||
|
/* initialize end marker */
|
||||||
|
end_node->next = NULL;
|
||||||
|
end_node->size = 0;
|
||||||
|
MARK_USED(end_node);
|
||||||
|
|
||||||
|
free_bytes = BLOCK_SIZE(first);
|
||||||
|
min_free = free_bytes;
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void eheap_init(void *buf, size_t bytes) {
|
||||||
|
if (!buf || bytes <= HDR_SIZE*2 + ALIGN_MASK) {
|
||||||
|
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("eheap_init: invalid region"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* align base upward */
|
||||||
|
uintptr_t start = ALIGN_UP((uintptr_t)buf);
|
||||||
|
size_t loss = start - (uintptr_t)buf;
|
||||||
|
bytes = (bytes > loss) ? bytes - loss : 0;
|
||||||
|
bytes = (bytes / EHEAP_ALIGN) * EHEAP_ALIGN;
|
||||||
|
if (bytes <= HDR_SIZE*2) {
|
||||||
|
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("eheap_init: too small after align"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
heap_base = (uint8_t*)start;
|
||||||
|
heap_total = bytes;
|
||||||
|
|
||||||
|
/* reserve tail for end_node */
|
||||||
|
size_t res = ALIGN_UP(sizeof(block_t));
|
||||||
|
heap_total -= res;
|
||||||
|
end_node = (block_t*)(heap_base + heap_total);
|
||||||
|
|
||||||
|
heap_end = heap_base + heap_total;
|
||||||
|
|
||||||
|
initialized = false;
|
||||||
|
heap_init_once();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* e_malloc(size_t size) {
|
||||||
|
if (size == 0 || !initialized) return NULL;
|
||||||
|
|
||||||
|
/* check overflow */
|
||||||
|
if (size > SIZE_MAX - HDR_SIZE) return NULL;
|
||||||
|
size_t needed = ALIGN_UP(size + HDR_SIZE);
|
||||||
|
|
||||||
|
block_t *prev = &start_node;
|
||||||
|
block_t *cur = start_node.next;
|
||||||
|
|
||||||
|
while (cur != end_node) {
|
||||||
|
if (!is_valid_block(cur)) {
|
||||||
|
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("e_malloc: corrupted heap"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!IS_USED(cur) && BLOCK_SIZE(cur) >= needed) {
|
||||||
|
size_t remain = BLOCK_SIZE(cur) - needed;
|
||||||
|
if (remain >= MIN_SPLIT) {
|
||||||
|
/* split */
|
||||||
|
block_t *split = (block_t*)((uint8_t*)cur + needed);
|
||||||
|
split->size = remain;
|
||||||
|
MARK_FREE(split);
|
||||||
|
split->next = cur->next;
|
||||||
|
|
||||||
|
cur->size = needed;
|
||||||
|
prev->next = split;
|
||||||
|
} else {
|
||||||
|
/* use entire */
|
||||||
|
prev->next = cur->next;
|
||||||
|
needed = BLOCK_SIZE(cur);
|
||||||
|
}
|
||||||
|
MARK_USED(cur);
|
||||||
|
|
||||||
|
free_bytes -= needed;
|
||||||
|
if (free_bytes < min_free) min_free = free_bytes;
|
||||||
|
return (uint8_t*)cur + HDR_SIZE;
|
||||||
|
}
|
||||||
|
prev = cur;
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void e_free(void *ptr) {
|
||||||
|
if (!ptr || !initialized) return;
|
||||||
|
|
||||||
|
uint8_t *p = (uint8_t*)ptr;
|
||||||
|
if (p < heap_base + HDR_SIZE || p >= heap_end) {
|
||||||
|
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("e_free: invalid ptr"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (((uintptr_t)p - HDR_SIZE) & ALIGN_MASK) {
|
||||||
|
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("e_free: unaligned ptr"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
block_t *blk = (block_t*)(p - HDR_SIZE);
|
||||||
|
if (!IS_USED(blk)) {
|
||||||
|
//mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("e_free: double free"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sz = BLOCK_SIZE(blk);
|
||||||
|
if (sz == 0 || (uint8_t*)blk + sz > heap_end) {
|
||||||
|
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("e_free: bad size"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MARK_FREE(blk);
|
||||||
|
free_bytes += sz;
|
||||||
|
insert_free(blk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* e_realloc(void *ptr, size_t new_size) {
|
||||||
|
if (!ptr) return e_malloc(new_size);
|
||||||
|
if (new_size == 0) { e_free(ptr); return NULL; }
|
||||||
|
if (!initialized) return NULL;
|
||||||
|
|
||||||
|
uint8_t *p = (uint8_t*)ptr;
|
||||||
|
if (p < heap_base + HDR_SIZE || p >= heap_end) {
|
||||||
|
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("e_realloc: invalid ptr"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
block_t *blk = (block_t*)(p - HDR_SIZE);
|
||||||
|
if (!IS_USED(blk)) {
|
||||||
|
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("e_realloc: block not used"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t curr = BLOCK_SIZE(blk) - HDR_SIZE;
|
||||||
|
if (new_size <= curr) return ptr;
|
||||||
|
|
||||||
|
/* try expand into next free block */
|
||||||
|
uint8_t *next_addr = (uint8_t*)blk + BLOCK_SIZE(blk);
|
||||||
|
if (next_addr + HDR_SIZE <= heap_end) {
|
||||||
|
block_t *next = (block_t*)next_addr;
|
||||||
|
if (is_valid_block(next) && !IS_USED(next)) {
|
||||||
|
size_t combined = BLOCK_SIZE(blk) + BLOCK_SIZE(next);
|
||||||
|
size_t need = ALIGN_UP(new_size + HDR_SIZE);
|
||||||
|
if (combined >= need) {
|
||||||
|
/* remove next from free list */
|
||||||
|
block_t *prev = &start_node;
|
||||||
|
while (prev->next != next && prev->next != end_node) {
|
||||||
|
prev = prev->next;
|
||||||
|
}
|
||||||
|
if (prev->next == next) {
|
||||||
|
prev->next = next->next;
|
||||||
|
/* compute new free_bytes: remove next size */
|
||||||
|
free_bytes -= BLOCK_SIZE(next);
|
||||||
|
|
||||||
|
/* update blk size */
|
||||||
|
blk->size = (blk->size & USED_MASK) | need;
|
||||||
|
size_t leftover = combined - need;
|
||||||
|
if (leftover >= MIN_SPLIT) {
|
||||||
|
block_t *split = (block_t*)((uint8_t*)blk + need);
|
||||||
|
split->size = leftover;
|
||||||
|
MARK_FREE(split);
|
||||||
|
insert_free(split);
|
||||||
|
} else {
|
||||||
|
/* absorb all */
|
||||||
|
blk->size = (blk->size & USED_MASK) | combined;
|
||||||
|
}
|
||||||
|
if (free_bytes < min_free) min_free = free_bytes;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fallback: alloc-copy-free */
|
||||||
|
void *nptr = e_malloc(new_size);
|
||||||
|
if (nptr) {
|
||||||
|
memcpy(nptr, ptr, curr);
|
||||||
|
e_free(ptr);
|
||||||
|
}
|
||||||
|
return nptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t e_heap_free(void) { return free_bytes; }
|
||||||
|
size_t e_heap_min_free(void) { return min_free; }
|
||||||
|
|
||||||
|
|
||||||
|
int e_heap_fragmentation(void) {
|
||||||
|
if (!initialized || free_bytes == 0) return 0;
|
||||||
|
size_t largest = 0;
|
||||||
|
for (block_t *b = start_node.next; b != end_node; b = b->next) {
|
||||||
|
if (!IS_USED(b) && BLOCK_SIZE(b) > largest) {
|
||||||
|
largest = BLOCK_SIZE(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (largest == 0) return 100;
|
||||||
|
return (int)(100 - (largest * 100) / free_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool e_heap_validate(void) {
|
||||||
|
if (!initialized) return false;
|
||||||
|
size_t counted = 0;
|
||||||
|
for (block_t *b = start_node.next; b != end_node; b = b->next) {
|
||||||
|
if (!is_valid_block(b)) return false;
|
||||||
|
if ((uint8_t*)b + BLOCK_SIZE(b) > heap_end) return false;
|
||||||
|
if (!IS_USED(b)) {
|
||||||
|
counted += BLOCK_SIZE(b);
|
||||||
|
/* ensure no adjacent free blocks */
|
||||||
|
block_t *n = b->next;
|
||||||
|
if (n != end_node && !IS_USED(n) &&
|
||||||
|
(uint8_t*)b + BLOCK_SIZE(b) == (uint8_t*)n) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (counted == free_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
33
user_modules/eigenmath/eheap.h
Normal file
33
user_modules/eigenmath/eheap.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*========================================================================
|
||||||
|
* eheap.h – Minimal standalone heap manager (Freertos heap_4 style)
|
||||||
|
* ---------------------------------------------------------------------
|
||||||
|
* API:
|
||||||
|
* void eheap_init(void *buffer, size_t size);
|
||||||
|
* void* e_malloc(size_t bytes);
|
||||||
|
* void e_free(void *ptr);
|
||||||
|
* void* e_realloc(void *ptr, size_t new_size);
|
||||||
|
* size_t e_heap_free(void);
|
||||||
|
* size_t e_heap_min_free(void);
|
||||||
|
*======================================================================*/
|
||||||
|
|
||||||
|
#ifndef EHEAP_H
|
||||||
|
#define EHEAP_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void eheap_init(void *buffer, size_t size);
|
||||||
|
void* e_malloc(size_t size);
|
||||||
|
void e_free(void *ptr);
|
||||||
|
void* e_realloc(void *ptr, size_t new_size);
|
||||||
|
size_t e_heap_free(void);
|
||||||
|
size_t e_heap_min_free(void);
|
||||||
|
int e_heap_fragmentation(void);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* EHEAP_H */
|
||||||
18471
user_modules/eigenmath/eigenmath.c
Normal file
18471
user_modules/eigenmath/eigenmath.c
Normal file
File diff suppressed because it is too large
Load Diff
35
user_modules/eigenmath/eigenmath.h
Normal file
35
user_modules/eigenmath/eigenmath.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
#ifndef EIGENMATH_H
|
||||||
|
#define EIGENMATH_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define STRBUFLEN 1000
|
||||||
|
#define BUCKETSIZE 100
|
||||||
|
#define MAXDIM 24
|
||||||
|
|
||||||
|
//extern struct atom *mem ;
|
||||||
|
//extern struct atom **stack ; //
|
||||||
|
//extern struct atom **symtab ; // symbol table
|
||||||
|
//extern struct atom **binding ;
|
||||||
|
//extern struct atom **usrfunc ;
|
||||||
|
//extern char *strbuf ;
|
||||||
|
|
||||||
|
//extern uint32_t STACKSIZE ; // evaluation stack
|
||||||
|
//extern uint32_t MAXATOMS ; // 10,240 atoms
|
||||||
|
|
||||||
|
extern bool noprint;
|
||||||
|
extern char *outbuf;
|
||||||
|
extern int outbuf_index;
|
||||||
|
extern void eigenmath_init(uint8_t *pHeap,size_t heapSize);
|
||||||
|
extern void run(char *buf);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* EHEAP_H */
|
||||||
281
user_modules/eigenmath/eigenmath_mpy.c
Normal file
281
user_modules/eigenmath/eigenmath_mpy.c
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "py/obj.h"
|
||||||
|
//#include "py/mpconfig.h"
|
||||||
|
#include "py/misc.h"
|
||||||
|
#include "py/runtime.h"
|
||||||
|
#include "py/objstr.h"
|
||||||
|
#include "shared/readline/readline.h"
|
||||||
|
#include "py/binary.h"
|
||||||
|
#include "py/gc.h"
|
||||||
|
#include "py/stream.h"
|
||||||
|
#include "eigenmath.h"
|
||||||
|
#include "eheap.h"
|
||||||
|
//-DPICO_STACK_SIZE=0x4000 ??
|
||||||
|
|
||||||
|
typedef struct _mp_obj_eigenmath_t {
|
||||||
|
mp_obj_base_t base;
|
||||||
|
size_t heapSize;
|
||||||
|
uint8_t *pHeap;
|
||||||
|
} mp_obj_eigenmath_t;
|
||||||
|
|
||||||
|
static void eigenmath_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||||
|
mp_printf(print, "<EigenMath instance>");
|
||||||
|
}
|
||||||
|
|
||||||
|
static mp_obj_t eigenmath_make_new(const mp_obj_type_t *type,
|
||||||
|
size_t n_args, size_t n_kw,
|
||||||
|
const mp_obj_t *args) {
|
||||||
|
|
||||||
|
mp_arg_check_num(n_args, n_kw, 1, 1, false);
|
||||||
|
mp_obj_eigenmath_t *self = mp_obj_malloc(mp_obj_eigenmath_t, type);
|
||||||
|
self->base.type = type;
|
||||||
|
self->heapSize = mp_obj_get_int(args[0]); // 350 * 1024; // 350KB
|
||||||
|
//mp_printf(&mp_plat_print,"heapSize = %d\n", self->heapSize);
|
||||||
|
|
||||||
|
self->pHeap = (uint8_t *)m_malloc(self->heapSize);
|
||||||
|
|
||||||
|
//mp_printf(&mp_plat_print,"ptemp = %x\n", (uint32_t)(ptemp));
|
||||||
|
//mp_printf(&mp_plat_print,"self->pHeap = %x\n", (uint32_t)(self->pHeap));
|
||||||
|
if (self->pHeap == NULL){
|
||||||
|
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("Failed to initialize heap"));
|
||||||
|
return MP_OBJ_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
eigenmath_init(self->pHeap,self->heapSize);
|
||||||
|
|
||||||
|
return MP_OBJ_FROM_PTR(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static mp_obj_t eigenmath_run(size_t n_args, const mp_obj_t *args) {
|
||||||
|
//mp_obj_eigenmath_t *self = MP_OBJ_TO_PTR(self_in);mp_obj_t input_str_obj
|
||||||
|
size_t len;
|
||||||
|
if (n_args >= 3){
|
||||||
|
mp_obj_t arg = args[2];
|
||||||
|
if (mp_obj_is_bool(arg) || mp_obj_is_int(arg)) {
|
||||||
|
noprint = mp_obj_is_true(arg);
|
||||||
|
} else {
|
||||||
|
mp_raise_TypeError(MP_ERROR_TEXT("expected a bool"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
noprint = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mp_obj_is_str(args[1])) {
|
||||||
|
mp_raise_TypeError(MP_ERROR_TEXT("expected a string as input"));
|
||||||
|
}
|
||||||
|
const char *buf = mp_obj_str_get_data(args[1], &len);
|
||||||
|
|
||||||
|
//GET_STR_DATA_LEN(input_str_obj, str, str_len);
|
||||||
|
run((char *)buf);
|
||||||
|
|
||||||
|
if (noprint == true){
|
||||||
|
return mp_obj_new_bytearray_by_ref(outbuf_index-1, outbuf);
|
||||||
|
// return memoryview
|
||||||
|
//return mp_obj_new_memoryview(BYTEARRAY_TYPECODE, outbuf);
|
||||||
|
|
||||||
|
}else{
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(eigenmath_run_obj,2,3, eigenmath_run);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static mp_obj_t eigenmath_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||||
|
//mp_obj_eigenmath_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
noprint = false;
|
||||||
|
if (n_args != 1 || n_kw != 0) {
|
||||||
|
mp_raise_TypeError(MP_ERROR_TEXT("Expected 1 positional argument"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *cmd = mp_obj_str_get_str(args[0]);
|
||||||
|
run((char *)cmd); //
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
|
||||||
|
static mp_obj_t eigenmath_cmd(mp_obj_t self_in) {
|
||||||
|
//mp_obj_eigenmath_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
vstr_t* vstr_inbuf = vstr_new(1);
|
||||||
|
for (;;) {
|
||||||
|
vstr_clear(vstr_inbuf);
|
||||||
|
int res = readline(vstr_inbuf,"eigenmath> ");
|
||||||
|
mp_printf(&mp_plat_print, "Eigenmath run:\n");
|
||||||
|
mp_printf(&mp_plat_print, "res=%d\n", res);
|
||||||
|
mp_printf(&mp_plat_print, "%s\n", vstr_inbuf->buf);
|
||||||
|
run(vstr_inbuf->buf);
|
||||||
|
}
|
||||||
|
return mp_const_none;
|
||||||
|
|
||||||
|
}
|
||||||
|
static MP_DEFINE_CONST_FUN_OBJ_1(eigenmath_cmd_obj, eigenmath_cmd);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static mp_obj_t eigenmath_runfile(size_t n_args, const mp_obj_t *args ) {//mp_obj_t input_file_obj
|
||||||
|
|
||||||
|
if (n_args >= 3){
|
||||||
|
mp_obj_t arg = args[2];
|
||||||
|
if (mp_obj_is_bool(arg) || mp_obj_is_int(arg)) {
|
||||||
|
noprint = mp_obj_is_true(arg);
|
||||||
|
} else {
|
||||||
|
mp_raise_TypeError(MP_ERROR_TEXT("expected a bool"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
noprint = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const mp_stream_p_t *stream_p = mp_get_stream_raise(args[1], MP_STREAM_OP_READ | MP_STREAM_OP_IOCTL);
|
||||||
|
if (stream_p == NULL) {
|
||||||
|
mp_raise_TypeError(MP_ERROR_TEXT("expected a file-like object"));
|
||||||
|
}
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
// get file size
|
||||||
|
struct mp_stream_seek_t seek = {
|
||||||
|
.offset = 0,
|
||||||
|
.whence = MP_SEEK_END,
|
||||||
|
};
|
||||||
|
mp_obj_t input_file_obj = args[1];
|
||||||
|
if (stream_p->ioctl(input_file_obj, MP_STREAM_SEEK, (uintptr_t)&seek, &error) == MP_STREAM_ERROR) {
|
||||||
|
mp_raise_OSError(error);
|
||||||
|
}
|
||||||
|
mp_off_t size = seek.offset;
|
||||||
|
|
||||||
|
// move to front
|
||||||
|
seek.offset = 0;
|
||||||
|
seek.whence = MP_SEEK_SET;
|
||||||
|
if (stream_p->ioctl(input_file_obj, MP_STREAM_SEEK, (uintptr_t)&seek, &error) == MP_STREAM_ERROR) {
|
||||||
|
mp_raise_OSError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get buffer
|
||||||
|
char *buf = m_new(char, size + 1);
|
||||||
|
|
||||||
|
// read file
|
||||||
|
mp_uint_t out_sz = stream_p->read(input_file_obj, buf, size, &error);
|
||||||
|
if (error != 0 || out_sz != size) {
|
||||||
|
m_del(char, buf, size + 1);
|
||||||
|
mp_raise_OSError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add end
|
||||||
|
buf[out_sz] = '\0';
|
||||||
|
|
||||||
|
// run
|
||||||
|
run(buf);
|
||||||
|
|
||||||
|
// release buffer
|
||||||
|
m_del(char, buf, size + 1);
|
||||||
|
|
||||||
|
if (noprint == true){
|
||||||
|
return mp_obj_new_bytearray_by_ref(outbuf_index-1, outbuf);
|
||||||
|
// return memoryview
|
||||||
|
//return mp_obj_new_memoryview(BYTEARRAY_TYPECODE, bytearray);
|
||||||
|
|
||||||
|
}else{
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(eigenmath_runfile_obj, 2,3,eigenmath_runfile);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern int free_count;
|
||||||
|
extern int MAXATOMS;
|
||||||
|
static mp_obj_t eigenmath_status(mp_obj_t self_in) {
|
||||||
|
//mp_obj_eigenmath_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
int fragmentation = e_heap_fragmentation();
|
||||||
|
size_t free_bytes = e_heap_free();
|
||||||
|
size_t min_free = e_heap_min_free();
|
||||||
|
int num_atoms = free_count;
|
||||||
|
mp_printf(&mp_plat_print,"Heap fragmentation: %d%%\n", fragmentation);
|
||||||
|
mp_printf(&mp_plat_print,"Free bytes in Heap: %d\n", (int)free_bytes);
|
||||||
|
mp_printf(&mp_plat_print,"Minimum free bytes in Heap: %d\n", (int)min_free);
|
||||||
|
mp_printf(&mp_plat_print,"Number of free atoms: %d of %d\n", num_atoms,MAXATOMS);
|
||||||
|
return mp_const_none;
|
||||||
|
|
||||||
|
}
|
||||||
|
static MP_DEFINE_CONST_FUN_OBJ_1(eigenmath_status_obj, eigenmath_status);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern struct atom *zero;
|
||||||
|
static mp_obj_t eigenmath_del(mp_obj_t self_in) {
|
||||||
|
mp_obj_eigenmath_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
m_free(&self->pHeap); // deinitialize the hea
|
||||||
|
zero = NULL;
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
static MP_DEFINE_CONST_FUN_OBJ_1(eigenmath_del_obj, eigenmath_del);
|
||||||
|
|
||||||
|
extern struct atom *zero;
|
||||||
|
static mp_obj_t eigenmath_reset(mp_obj_t self_in) {
|
||||||
|
mp_obj_eigenmath_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
eigenmath_init(self->pHeap,self->heapSize);
|
||||||
|
zero = NULL;//triger the symbol table initialization
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
static MP_DEFINE_CONST_FUN_OBJ_1(eigenmath_reset_obj, eigenmath_reset);
|
||||||
|
|
||||||
|
mp_obj_t eigenmath_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||||
|
if (dest[0] == MP_OBJ_NULL && attr == MP_QSTR___del__) {
|
||||||
|
dest[0] = MP_OBJ_FROM_PTR(&eigenmath_del_obj);
|
||||||
|
dest[1] = self_in;
|
||||||
|
}else{
|
||||||
|
// For any other attribute, indicate that lookup should continue in the locals dict
|
||||||
|
dest[1] = MP_OBJ_SENTINEL;
|
||||||
|
return MP_OBJ_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MP_OBJ_NULL;
|
||||||
|
}
|
||||||
|
static const mp_rom_map_elem_t eigenmath_locals_dict_table[] = {
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&eigenmath_run_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_runfile), MP_ROM_PTR(&eigenmath_runfile_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_cmd), MP_ROM_PTR(&eigenmath_cmd_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&eigenmath_reset_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&eigenmath_status_obj) },
|
||||||
|
};
|
||||||
|
static MP_DEFINE_CONST_DICT(eigenmath_locals_dict, eigenmath_locals_dict_table);
|
||||||
|
|
||||||
|
|
||||||
|
MP_DEFINE_CONST_OBJ_TYPE(
|
||||||
|
eigenmath_type,
|
||||||
|
MP_QSTR_EigenMath,
|
||||||
|
MP_TYPE_FLAG_NONE,
|
||||||
|
make_new, eigenmath_make_new,
|
||||||
|
call,eigenmath_call, // call handler for the run method
|
||||||
|
attr, eigenmath_attr, // attr handler before locals_dict
|
||||||
|
locals_dict, &eigenmath_locals_dict,
|
||||||
|
print, eigenmath_print
|
||||||
|
);
|
||||||
|
|
||||||
|
static const mp_rom_map_elem_t eigenmath_module_globals_table[] = {
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_eigenmath) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_EigenMath), MP_ROM_PTR(&eigenmath_type) },
|
||||||
|
};
|
||||||
|
static MP_DEFINE_CONST_DICT(mp_module_eigenmath_globals, eigenmath_module_globals_table);
|
||||||
|
|
||||||
|
const mp_obj_module_t eigenmath_user_cmodule = {
|
||||||
|
.base = { &mp_type_module },
|
||||||
|
.globals = (mp_obj_dict_t*)&mp_module_eigenmath_globals,
|
||||||
|
};
|
||||||
|
|
||||||
|
MP_REGISTER_MODULE(MP_QSTR_eigenmath, eigenmath_user_cmodule);
|
||||||
19
user_modules/eigenmath/micropython.cmake
Normal file
19
user_modules/eigenmath/micropython.cmake
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Create an INTERFACE library for our C module.
|
||||||
|
add_library(usermod_eigenmath INTERFACE)
|
||||||
|
|
||||||
|
# Add our source files to the lib
|
||||||
|
target_sources(usermod_eigenmath INTERFACE
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/eigenmath.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/eheap.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/eigenmath_mpy.c
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add the current directory as an include directory.
|
||||||
|
target_include_directories(usermod_eigenmath INTERFACE
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}
|
||||||
|
)
|
||||||
|
set(PICO_STACK_SIZE 0x4000 CACHE STRING "App stack size" FORCE)
|
||||||
|
|
||||||
|
# Link our INTERFACE library to the usermod target.
|
||||||
|
target_link_libraries(usermod INTERFACE usermod_eigenmath)
|
||||||
|
|
||||||
10
user_modules/eigenmath/micropython.mk
Normal file
10
user_modules/eigenmath/micropython.mk
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
PICOCALCDISPLAY_MOD_DIR := $(USERMOD_DIR)
|
||||||
|
|
||||||
|
# Add all C files to SRC_USERMOD.
|
||||||
|
SRC_USERMOD += $(PICOCALCDISPLAY_MOD_DIR)/eigenmath.c\
|
||||||
|
$(PICOCALCDISPLAY_MOD_DIR)/eigenmath_mpy.h\
|
||||||
|
$(PICOCALCDISPLAY_MOD_DIR)/eheap.c\
|
||||||
|
|
||||||
|
# We can add our module folder to include paths if needed
|
||||||
|
# This is not actually needed in this example.
|
||||||
|
CFLAGS_USERMOD += -I$(PICOCALCDISPLAY_MOD_DIR)
|
||||||
2
user_modules/user.cmake
Normal file
2
user_modules/user.cmake
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
include(${CMAKE_CURRENT_LIST_DIR}/eigenmath/micropython.cmake)
|
||||||
|
include(${CMAKE_CURRENT_LIST_DIR}/lv_binding_micropython/bindings.cmake)
|
||||||
Loading…
x
Reference in New Issue
Block a user