kopia lustrzana https://github.com/pimoroni/pimoroni-pico
First pass at MP support
rodzic
70b589d431
commit
564fecf1de
|
@ -0,0 +1,65 @@
|
||||||
|
#include "encoder.h"
|
||||||
|
|
||||||
|
|
||||||
|
/***** Methods *****/
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(Encoder___del___obj, Encoder___del__);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(Encoder_pins_obj, Encoder_pins);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(Encoder_state_obj, Encoder_state);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(Encoder_count_obj, Encoder_count);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(Encoder_revolutions_obj, Encoder_revolutions);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(Encoder_angle_degrees_obj, Encoder_angle_degrees);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(Encoder_angle_radians_obj, Encoder_angle_radians);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(Encoder_frequency_obj, Encoder_frequency);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(Encoder_revolutions_per_second_obj, Encoder_revolutions_per_second);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(Encoder_revolutions_per_minute_obj, Encoder_revolutions_per_minute);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(Encoder_degrees_per_second_obj, Encoder_degrees_per_second);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(Encoder_radians_per_second_obj, Encoder_radians_per_second);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(Encoder_zero_count_obj, Encoder_zero_count);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(Encoder_take_snapshot_obj, Encoder_take_snapshot);
|
||||||
|
|
||||||
|
/***** Binding of Methods *****/
|
||||||
|
STATIC const mp_rom_map_elem_t Encoder_locals_dict_table[] = {
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&Encoder___del___obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_pins), MP_ROM_PTR(&Encoder_pins_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&Encoder_state_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&Encoder_count_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_revolutions), MP_ROM_PTR(&Encoder_revolutions_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_angle_degrees), MP_ROM_PTR(&Encoder_angle_degrees_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_angle_radians), MP_ROM_PTR(&Encoder_angle_radians_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&Encoder_frequency_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_revolutions_per_second), MP_ROM_PTR(&Encoder_revolutions_per_second_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_revolutions_per_minute), MP_ROM_PTR(&Encoder_revolutions_per_minute_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_degrees_per_second), MP_ROM_PTR(&Encoder_degrees_per_second_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_radians_per_second), MP_ROM_PTR(&Encoder_radians_per_second_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_zero_count), MP_ROM_PTR(&Encoder_zero_count_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_take_snapshot), MP_ROM_PTR(&Encoder_take_snapshot_obj) },
|
||||||
|
};
|
||||||
|
|
||||||
|
STATIC MP_DEFINE_CONST_DICT(Encoder_locals_dict, Encoder_locals_dict_table);
|
||||||
|
|
||||||
|
/***** Class Definition *****/
|
||||||
|
const mp_obj_type_t Encoder_type = {
|
||||||
|
{ &mp_type_type },
|
||||||
|
.name = MP_QSTR_encoder,
|
||||||
|
.print = Encoder_print,
|
||||||
|
.make_new = Encoder_make_new,
|
||||||
|
.locals_dict = (mp_obj_dict_t*)&Encoder_locals_dict,
|
||||||
|
};
|
||||||
|
|
||||||
|
/***** Globals Table *****/
|
||||||
|
STATIC const mp_map_elem_t encoder_globals_table[] = {
|
||||||
|
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_encoder) },
|
||||||
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_Encoder), (mp_obj_t)&Encoder_type },
|
||||||
|
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_ANGULAR), MP_ROM_INT(0x00) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_LINEAR), MP_ROM_INT(0x01) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_CONTINUOUS), MP_ROM_INT(0x02) },
|
||||||
|
};
|
||||||
|
STATIC MP_DEFINE_CONST_DICT(mp_module_encoder_globals, encoder_globals_table);
|
||||||
|
|
||||||
|
/***** Module Definition *****/
|
||||||
|
const mp_obj_module_t encoder_user_cmodule = {
|
||||||
|
.base = { &mp_type_module },
|
||||||
|
.globals = (mp_obj_dict_t*)&mp_module_encoder_globals,
|
||||||
|
};
|
||||||
|
MP_REGISTER_MODULE(MP_QSTR_encoder, encoder_user_cmodule, MODULE_ENCODER_ENABLED);
|
|
@ -0,0 +1,229 @@
|
||||||
|
#include "drivers/encoder-pio/capture.hpp"
|
||||||
|
#include "drivers/encoder-pio/encoder.hpp"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o))
|
||||||
|
|
||||||
|
using namespace pimoroni;
|
||||||
|
//using namespace encoder;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "encoder.h"
|
||||||
|
#include "py/builtin.h"
|
||||||
|
|
||||||
|
|
||||||
|
/********** Encoder **********/
|
||||||
|
|
||||||
|
/***** Variables Struct *****/
|
||||||
|
typedef struct _Encoder_obj_t {
|
||||||
|
mp_obj_base_t base;
|
||||||
|
Encoder* encoder;
|
||||||
|
} _Encoder_obj_t;
|
||||||
|
|
||||||
|
|
||||||
|
/***** Print *****/
|
||||||
|
void Encoder_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||||
|
(void)kind; //Unused input parameter
|
||||||
|
_Encoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Encoder_obj_t);
|
||||||
|
mp_print_str(print, "Encoder(");
|
||||||
|
|
||||||
|
mp_print_str(print, "pins = (");
|
||||||
|
pin_pair pins = self->encoder->pins();
|
||||||
|
mp_obj_print_helper(print, mp_obj_new_int(pins.a), PRINT_REPR);
|
||||||
|
mp_print_str(print, ", ");
|
||||||
|
mp_obj_print_helper(print, mp_obj_new_int(pins.b), PRINT_REPR);
|
||||||
|
mp_print_str(print, "), enabled = ");
|
||||||
|
/*mp_obj_print_helper(print, self->encoder->is_enabled() ? mp_const_true : mp_const_false, PRINT_REPR);
|
||||||
|
mp_print_str(print, ", pulse = ");
|
||||||
|
mp_obj_print_helper(print, mp_obj_new_float(self->encoder->pulse()), PRINT_REPR);
|
||||||
|
mp_print_str(print, ", value = ");
|
||||||
|
mp_obj_print_helper(print, mp_obj_new_float(self->encoder->value()), PRINT_REPR);
|
||||||
|
mp_print_str(print, ", freq = ");
|
||||||
|
mp_obj_print_helper(print, mp_obj_new_float(self->encoder->frequency()), PRINT_REPR);
|
||||||
|
*/
|
||||||
|
mp_print_str(print, ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***** Constructor *****/
|
||||||
|
mp_obj_t Encoder_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||||
|
_Encoder_obj_t *self = nullptr;
|
||||||
|
|
||||||
|
enum { ARG_pio, ARG_sm, ARG_pins, ARG_pin_c, ARG_calibration, ARG_freq };
|
||||||
|
static const mp_arg_t allowed_args[] = {
|
||||||
|
{ MP_QSTR_pio, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||||
|
{ MP_QSTR_sm, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||||
|
{ MP_QSTR_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||||
|
{ MP_QSTR_pin_c, MP_ARG_INT, {.u_int = PIN_UNUSED} },
|
||||||
|
{ MP_QSTR_calibration, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||||
|
{ MP_QSTR_freq, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse args.
|
||||||
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
|
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
|
||||||
|
PIO pio = args[ARG_pio].u_int == 0 ? pio0 : pio1;
|
||||||
|
int sm = args[ARG_sm].u_int;
|
||||||
|
|
||||||
|
size_t pin_count = 0;
|
||||||
|
pin_pair pins;
|
||||||
|
|
||||||
|
// Determine what pair of pins this encoder will use
|
||||||
|
const mp_obj_t object = args[ARG_pins].u_obj;
|
||||||
|
mp_obj_t *items = nullptr;
|
||||||
|
if(mp_obj_is_type(object, &mp_type_list)) {
|
||||||
|
mp_obj_list_t *list = MP_OBJ_TO_PTR2(object, mp_obj_list_t);
|
||||||
|
pin_count = list->len;
|
||||||
|
items = list->items;
|
||||||
|
}
|
||||||
|
else if(mp_obj_is_type(object, &mp_type_tuple)) {
|
||||||
|
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(object, mp_obj_tuple_t);
|
||||||
|
pin_count = tuple->len;
|
||||||
|
items = tuple->items;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(items == nullptr)
|
||||||
|
mp_raise_TypeError("cannot convert object to a list or tuple of pins");
|
||||||
|
else if(pin_count != 2)
|
||||||
|
mp_raise_TypeError("list or tuple must only contain two integers");
|
||||||
|
else {
|
||||||
|
int a = mp_obj_get_int(items[0]);
|
||||||
|
int b = mp_obj_get_int(items[1]);
|
||||||
|
if((a < 0 || a >= (int)NUM_BANK0_GPIOS) ||
|
||||||
|
(b < 0 || b >= (int)NUM_BANK0_GPIOS)) {
|
||||||
|
mp_raise_ValueError("a pin in the list or tuple is out of range. Expected 0 to 29");
|
||||||
|
}
|
||||||
|
else if(a == b) {
|
||||||
|
mp_raise_ValueError("cannot use the same pin for encoder A and B");
|
||||||
|
}
|
||||||
|
|
||||||
|
pins.a = (uint8_t)a;
|
||||||
|
pins.b = (uint8_t)b;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
encoder::Calibration *calib = nullptr;
|
||||||
|
encoder::CalibrationType calibration_type = encoder::CalibrationType::ANGULAR;
|
||||||
|
const mp_obj_t calib_object = args[ARG_calibration].u_obj;
|
||||||
|
if(calib_object != mp_const_none) {
|
||||||
|
if(mp_obj_is_int(calib_object)) {
|
||||||
|
int type = mp_obj_get_int(calib_object);
|
||||||
|
if(type < 0 || type >= 3) {
|
||||||
|
mp_raise_ValueError("type out of range. Expected ANGULAR (0), LINEAR (1) or CONTINUOUS (2)");
|
||||||
|
}
|
||||||
|
calibration_type = (encoder::CalibrationType)type;
|
||||||
|
}
|
||||||
|
else if(mp_obj_is_type(calib_object, &Calibration_type)) {
|
||||||
|
calib = (MP_OBJ_TO_PTR2(calib_object, _Calibration_obj_t)->calibration);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mp_raise_TypeError("cannot convert object to an integer or a Calibration class instance");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float freq = encoder::EncoderState::DEFAULT_FREQUENCY;
|
||||||
|
if(args[ARG_freq].u_obj != mp_const_none) {
|
||||||
|
freq = mp_obj_get_float(args[ARG_freq].u_obj);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Encoder *encoder = new Encoder(pio, sm, pins, args[ARG_pin_c].u_int);
|
||||||
|
if(!encoder->init()) {
|
||||||
|
delete encoder;
|
||||||
|
mp_raise_msg(&mp_type_RuntimeError, "unable to allocate the hardware resources needed to initialise this Encoder. Try running `import gc` followed by `gc.collect()` before creating it");
|
||||||
|
}
|
||||||
|
|
||||||
|
self = m_new_obj_with_finaliser(_Encoder_obj_t);
|
||||||
|
self->base.type = &Encoder_type;
|
||||||
|
self->encoder = encoder;
|
||||||
|
|
||||||
|
return MP_OBJ_FROM_PTR(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***** Destructor ******/
|
||||||
|
mp_obj_t Encoder___del__(mp_obj_t self_in) {
|
||||||
|
_Encoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Encoder_obj_t);
|
||||||
|
delete self->encoder;
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***** Methods *****/
|
||||||
|
extern mp_obj_t Encoder_pins(mp_obj_t self_in) {
|
||||||
|
_Encoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Encoder_obj_t);
|
||||||
|
pin_pair pins = self->encoder->pins();
|
||||||
|
|
||||||
|
mp_obj_t tuple[2];
|
||||||
|
tuple[0] = mp_obj_new_int(pins.a);
|
||||||
|
tuple[1] = mp_obj_new_int(pins.b);
|
||||||
|
return mp_obj_new_tuple(2, tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern mp_obj_t Encoder_state(mp_obj_t self_in) {
|
||||||
|
_Encoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Encoder_obj_t);
|
||||||
|
bool_pair state = self->encoder->state();
|
||||||
|
|
||||||
|
mp_obj_t tuple[2];
|
||||||
|
tuple[0] = state.a ? mp_const_true : mp_const_false;
|
||||||
|
tuple[1] = state.b ? mp_const_true : mp_const_false;
|
||||||
|
return mp_obj_new_tuple(2, tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern mp_obj_t Encoder_count(mp_obj_t self_in) {
|
||||||
|
_Encoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Encoder_obj_t);
|
||||||
|
return mp_obj_new_int(self->encoder->count());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern mp_obj_t Encoder_revolutions(mp_obj_t self_in) {
|
||||||
|
_Encoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Encoder_obj_t);
|
||||||
|
return mp_obj_new_float(self->encoder->revolutions());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern mp_obj_t Encoder_angle_degrees(mp_obj_t self_in) {
|
||||||
|
_Encoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Encoder_obj_t);
|
||||||
|
return mp_obj_new_float(self->encoder->angle_degrees());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern mp_obj_t Encoder_angle_radians(mp_obj_t self_in) {
|
||||||
|
_Encoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Encoder_obj_t);
|
||||||
|
return mp_obj_new_float(self->encoder->angle_radians());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern mp_obj_t Encoder_frequency(mp_obj_t self_in) {
|
||||||
|
_Encoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Encoder_obj_t);
|
||||||
|
return mp_obj_new_float(self->encoder->frequency());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern mp_obj_t Encoder_revolutions_per_second(mp_obj_t self_in) {
|
||||||
|
_Encoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Encoder_obj_t);
|
||||||
|
return mp_obj_new_float(self->encoder->revolutions_per_second());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern mp_obj_t Encoder_revolutions_per_minute(mp_obj_t self_in) {
|
||||||
|
_Encoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Encoder_obj_t);
|
||||||
|
return mp_obj_new_float(self->encoder->revolutions_per_minute());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern mp_obj_t Encoder_degrees_per_second(mp_obj_t self_in) {
|
||||||
|
_Encoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Encoder_obj_t);
|
||||||
|
return mp_obj_new_float(self->encoder->degrees_per_second());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern mp_obj_t Encoder_radians_per_second(mp_obj_t self_in) {
|
||||||
|
_Encoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Encoder_obj_t);
|
||||||
|
return mp_obj_new_float(self->encoder->radians_per_second());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern mp_obj_t Encoder_zero_count(mp_obj_t self_in) {
|
||||||
|
_Encoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Encoder_obj_t);
|
||||||
|
self->encoder->zero_count();
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern mp_obj_t Encoder_take_snapshot(mp_obj_t self_in) {
|
||||||
|
//_Encoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Encoder_obj_t);
|
||||||
|
//Capture capture = self->encoder->perform_capture();
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Include MicroPython API.
|
||||||
|
#include "py/runtime.h"
|
||||||
|
|
||||||
|
/***** Extern of Class Definition *****/
|
||||||
|
extern const mp_obj_type_t Encoder_type;
|
||||||
|
|
||||||
|
/***** Extern of Class Methods *****/
|
||||||
|
extern void Encoder_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
|
||||||
|
extern mp_obj_t Encoder_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
|
||||||
|
extern mp_obj_t Encoder___del__(mp_obj_t self_in);
|
||||||
|
extern mp_obj_t Encoder_pins(mp_obj_t self_in);
|
||||||
|
extern mp_obj_t Encoder_state(mp_obj_t self_in);
|
||||||
|
extern mp_obj_t Encoder_count(mp_obj_t self_in);
|
||||||
|
extern mp_obj_t Encoder_revolutions(mp_obj_t self_in);
|
||||||
|
extern mp_obj_t Encoder_angle_degrees(mp_obj_t self_in);
|
||||||
|
extern mp_obj_t Encoder_angle_radians(mp_obj_t self_in);
|
||||||
|
extern mp_obj_t Encoder_frequency(mp_obj_t self_in);
|
||||||
|
extern mp_obj_t Encoder_revolutions_per_second(mp_obj_t self_in);
|
||||||
|
extern mp_obj_t Encoder_revolutions_per_minute(mp_obj_t self_in);
|
||||||
|
extern mp_obj_t Encoder_degrees_per_second(mp_obj_t self_in);
|
||||||
|
extern mp_obj_t Encoder_radians_per_second(mp_obj_t self_in);
|
||||||
|
extern mp_obj_t Encoder_zero_count(mp_obj_t self_in);
|
||||||
|
extern mp_obj_t Encoder_take_snapshot(mp_obj_t self_in);
|
|
@ -0,0 +1,22 @@
|
||||||
|
set(MOD_NAME encoder)
|
||||||
|
string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER)
|
||||||
|
add_library(usermod_${MOD_NAME} INTERFACE)
|
||||||
|
|
||||||
|
target_sources(usermod_${MOD_NAME} INTERFACE
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/encoder-pio/capture.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/encoder-pio/encoder.cpp
|
||||||
|
)
|
||||||
|
pico_generate_pio_header(usermod_${MOD_NAME} ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/encoder-pio/encoder.pio)
|
||||||
|
|
||||||
|
target_include_directories(usermod_${MOD_NAME} INTERFACE
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../../../drivers/encoder-pio/
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(usermod_${MOD_NAME} INTERFACE
|
||||||
|
MODULE_ENCODER_ENABLED=1
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(usermod INTERFACE usermod_${MOD_NAME})
|
|
@ -43,6 +43,7 @@ include(bitmap_fonts/micropython)
|
||||||
include(plasma/micropython)
|
include(plasma/micropython)
|
||||||
include(hub75/micropython)
|
include(hub75/micropython)
|
||||||
include(servo/micropython)
|
include(servo/micropython)
|
||||||
|
include(encoder/micropython)
|
||||||
include(ulab/code/micropython)
|
include(ulab/code/micropython)
|
||||||
include(qrcode/micropython/micropython)
|
include(qrcode/micropython/micropython)
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue