From aeec63b7ebc941d0006b699043a3987016de2dbc Mon Sep 17 00:00:00 2001 From: Bert Outtier Date: Fri, 27 Mar 2026 15:41:03 +0100 Subject: [PATCH 1/5] integrate esp32-component-rvswd and add bindings --- .gitmodules | 3 + c_mpos/micropython.cmake | 9 +- c_mpos/src/rvswd_module.c | 362 ++++++++++++++++++++++++++++++++++++++ esp32-component-rvswd | 1 + 4 files changed, 374 insertions(+), 1 deletion(-) create mode 100644 c_mpos/src/rvswd_module.c create mode 160000 esp32-component-rvswd diff --git a/.gitmodules b/.gitmodules index 36f11e8a..930b16ab 100644 --- a/.gitmodules +++ b/.gitmodules @@ -15,3 +15,6 @@ [submodule "micropython-nostr"] path = micropython-nostr url = https://github.com/MicroPythonOS/micropython-nostr +[submodule "esp32-component-rvswd"] + path = esp32-component-rvswd + url = https://github.com/Fri3dCamp/esp32-component-rvswd.git diff --git a/c_mpos/micropython.cmake b/c_mpos/micropython.cmake index cc443ae8..4fda85ae 100644 --- a/c_mpos/micropython.cmake +++ b/c_mpos/micropython.cmake @@ -9,6 +9,8 @@ set(MPOS_C_INCLUDES) set(MPOS_C_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/../lvgl_micropython/lib/micropython/ports/esp32/managed_components/espressif__esp_codec_dev/include/ ${CMAKE_CURRENT_LIST_DIR}/../lvgl_micropython/lib/micropython/ports/esp32/managed_components/espressif__esp_codec_dev/interface/ + # RVSWD programmer component headers + ${CMAKE_CURRENT_LIST_DIR}/../esp32-component-rvswd/include/ ) set(MPOS_C_SOURCES @@ -20,6 +22,12 @@ set(MPOS_C_SOURCES ${CMAKE_CURRENT_LIST_DIR}/quirc/lib/quirc.c # ${CMAKE_CURRENT_LIST_DIR}/../lvgl_micropython/lib/micropython/extmod/modwebrepl.c # ${CMAKE_CURRENT_LIST_DIR}/src/font_Noto_Sans_sat_emojis_compressed.c + # RVSWD programmer component sources + ${CMAKE_CURRENT_LIST_DIR}/src/rvswd_module.c + ${CMAKE_CURRENT_LIST_DIR}/../esp32-component-rvswd/src/rvswd.c + ${CMAKE_CURRENT_LIST_DIR}/../esp32-component-rvswd/src/rvswd_ch32.c + ${CMAKE_CURRENT_LIST_DIR}/../esp32-component-rvswd/src/rvswd_ch32v20x.c + ${CMAKE_CURRENT_LIST_DIR}/../esp32-component-rvswd/src/rvswd_ch32x03x.c ) # Add our source files to the lib @@ -42,4 +50,3 @@ target_compile_options(usermod_c_mpos INTERFACE # Link our INTERFACE library to the usermod target. target_link_libraries(usermod INTERFACE usermod_c_mpos) - diff --git a/c_mpos/src/rvswd_module.c b/c_mpos/src/rvswd_module.c new file mode 100644 index 00000000..509cd303 --- /dev/null +++ b/c_mpos/src/rvswd_module.c @@ -0,0 +1,362 @@ +/** + * MicroPython bindings for the esp32-component-rvswd RVSWD programmer. + * Exposes an RVSWD class for programming WCH CH32 microcontrollers from Python. + * + * Usage: + * import rvswd + * prog = rvswd.RVSWD(swdio=39, swclk=42) + * + * # Read chip identity + * vendor = prog.read_vendor_bytes() # returns tuple of 4 uint32 values + * + * # Program a CH32x03x chip (e.g. CH32X035) + * with open('firmware.bin', 'rb') as f: + * fw = f.read() + * prog.x03x_program(fw, lambda msg, pct: print(f"{msg}: {pct}%")) + * + * # Program a CH32V20x chip (e.g. CH32V203) + * prog.halt() + * prog.v20x_unlock_flash() + * prog.v20x_write_flash(0x08000000, fw, lambda msg, pct: print(f"{msg}: {pct}%")) + * prog.v20x_lock_flash() + * prog.reset_and_run() + */ + +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include +#include "rvswd.h" +#include "rvswd_ch32.h" +#include "rvswd_ch32v20x.h" +#include "rvswd_ch32x03x.h" + +// --------------------------------------------------------------------------- +// Object type +// --------------------------------------------------------------------------- + +typedef struct { + mp_obj_base_t base; + rvswd_handle_t handle; +} rvswd_obj_t; + +static const mp_obj_type_t rvswd_type; // forward declaration + +// --------------------------------------------------------------------------- +// Callback bridge +// Single-threaded MicroPython GIL makes a global safe here; +// these flash functions are blocking and never re-entrant. +// --------------------------------------------------------------------------- + +static mp_obj_t g_status_callback = MP_OBJ_NULL; + +static void c_status_callback(char const *msg, uint8_t progress) { + if (g_status_callback != MP_OBJ_NULL && g_status_callback != mp_const_none) { + mp_obj_t call_args[2] = { + mp_obj_new_str(msg, strlen(msg)), + MP_OBJ_NEW_SMALL_INT(progress), + }; + mp_call_function_n_kw(g_status_callback, 2, 0, call_args); + } +} + +// --------------------------------------------------------------------------- +// Internal helpers +// --------------------------------------------------------------------------- + +static void raise_rvswd_result(rvswd_result_t result) { + switch (result) { + case RVSWD_OK: return; + case RVSWD_FAIL: mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("RVSWD operation failed")); break; + case RVSWD_INVALID_ARGS: mp_raise_ValueError(MP_ERROR_TEXT("RVSWD invalid arguments")); break; + case RVSWD_PARITY_ERROR: mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("RVSWD parity error")); break; + default: mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("RVSWD error: %d"), (int)result); break; + } +} + +// --------------------------------------------------------------------------- +// Constructor: RVSWD(swdio, swclk) +// --------------------------------------------------------------------------- + +static mp_obj_t rvswd_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, 2, 2, false); + rvswd_obj_t *self = mp_obj_malloc(rvswd_obj_t, type); + self->handle.swdio = (gpio_num_t)mp_obj_get_int(args[0]); + self->handle.swclk = (gpio_num_t)mp_obj_get_int(args[1]); + rvswd_result_t result = rvswd_init(&self->handle); + if (result != RVSWD_OK) { + mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("rvswd_init failed: %d"), (int)result); + } + return MP_OBJ_FROM_PTR(self); +} + +// --------------------------------------------------------------------------- +// Low-level RVSWD protocol +// --------------------------------------------------------------------------- + +static mp_obj_t rvswd_reset(mp_obj_t self_in) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); + raise_rvswd_result(rvswd_reset(&self->handle)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_reset_obj, rvswd_reset); + +static mp_obj_t rvswd_write_reg(mp_obj_t self_in, mp_obj_t reg_in, mp_obj_t val_in) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint8_t reg = (uint8_t)mp_obj_get_int(reg_in); + uint32_t val = (uint32_t)mp_obj_get_int(val_in); + raise_rvswd_result(rvswd_write(&self->handle, reg, val)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_3(rvswd_write_reg_obj, rvswd_write_reg); + +static mp_obj_t rvswd_read_reg(mp_obj_t self_in, mp_obj_t reg_in) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint8_t reg = (uint8_t)mp_obj_get_int(reg_in); + uint32_t val = 0; + raise_rvswd_result(rvswd_read(&self->handle, reg, &val)); + return mp_obj_new_int_from_uint(val); +} +MP_DEFINE_CONST_FUN_OBJ_2(rvswd_read_reg_obj, rvswd_read_reg); + +// --------------------------------------------------------------------------- +// CH32 generic debug operations +// --------------------------------------------------------------------------- + +static mp_obj_t rvswd_halt(mp_obj_t self_in) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); + raise_rvswd_result(ch32_halt_microprocessor(&self->handle)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_halt_obj, rvswd_halt); + +static mp_obj_t rvswd_resume(mp_obj_t self_in) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); + raise_rvswd_result(ch32_resume_microprocessor(&self->handle)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_resume_obj, rvswd_resume); + +static mp_obj_t rvswd_reset_and_run(mp_obj_t self_in) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); + raise_rvswd_result(ch32_reset_microprocessor_and_run(&self->handle)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_reset_and_run_obj, rvswd_reset_and_run); + +static mp_obj_t rvswd_read_memory(mp_obj_t self_in, mp_obj_t addr_in) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint32_t addr = (uint32_t)mp_obj_get_int(addr_in); + uint32_t val = 0; + if (!ch32_read_memory_word(&self->handle, addr, &val)) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32_read_memory_word failed")); + } + return mp_obj_new_int_from_uint(val); +} +MP_DEFINE_CONST_FUN_OBJ_2(rvswd_read_memory_obj, rvswd_read_memory); + +static mp_obj_t rvswd_write_memory(mp_obj_t self_in, mp_obj_t addr_in, mp_obj_t val_in) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint32_t addr = (uint32_t)mp_obj_get_int(addr_in); + uint32_t val = (uint32_t)mp_obj_get_int(val_in); + if (!ch32_write_memory_word(&self->handle, addr, val)) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32_write_memory_word failed")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_3(rvswd_write_memory_obj, rvswd_write_memory); + +// Returns a 4-tuple of uint32 vendor bytes for chip identification. +static mp_obj_t rvswd_read_vendor_bytes(mp_obj_t self_in) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint32_t vendor_bytes[4] = {0, 0, 0, 0}; + if (!ch32_read_vendor_bytes(&self->handle, vendor_bytes)) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32_read_vendor_bytes failed")); + } + mp_obj_t tuple[4]; + for (int i = 0; i < 4; i++) { + tuple[i] = mp_obj_new_int_from_uint(vendor_bytes[i]); + } + return mp_obj_new_tuple(4, tuple); +} +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_read_vendor_bytes_obj, rvswd_read_vendor_bytes); + +// --------------------------------------------------------------------------- +// CH32V20x flash operations +// --------------------------------------------------------------------------- + +static mp_obj_t rvswd_v20x_unlock_flash(mp_obj_t self_in) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!ch32v20x_unlock_flash(&self->handle)) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32v20x_unlock_flash failed")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_v20x_unlock_flash_obj, rvswd_v20x_unlock_flash); + +static mp_obj_t rvswd_v20x_lock_flash(mp_obj_t self_in) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!ch32v20x_lock_flash(&self->handle)) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32v20x_lock_flash failed")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_v20x_lock_flash_obj, rvswd_v20x_lock_flash); + +// v20x_write_flash(addr, data[, callback]) +// data: bytes-like object with firmware content +// callback: optional callable(msg: str, progress: int) +static mp_obj_t rvswd_v20x_write_flash(size_t n_args, const mp_obj_t *args) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(args[0]); + uint32_t addr = (uint32_t)mp_obj_get_int(args[1]); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); + + g_status_callback = (n_args > 3) ? args[3] : mp_const_none; + ch32v20x_status_callback cb = (g_status_callback != mp_const_none) ? c_status_callback : NULL; + bool ok = ch32v20x_write_flash(&self->handle, addr, bufinfo.buf, bufinfo.len, cb); + g_status_callback = MP_OBJ_NULL; + + if (!ok) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32v20x_write_flash failed")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rvswd_v20x_write_flash_obj, 3, 4, rvswd_v20x_write_flash); + +static mp_obj_t rvswd_v20x_clear_ops(mp_obj_t self_in) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!ch32v20x_clear_running_operations(&self->handle)) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32v20x_clear_running_operations failed")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_v20x_clear_ops_obj, rvswd_v20x_clear_ops); + +// --------------------------------------------------------------------------- +// CH32x03x flash operations +// --------------------------------------------------------------------------- + +// x03x_program(firmware[, callback]) +// High-level: halts, erases, writes, verifies and restarts the target. +static mp_obj_t rvswd_x03x_program(size_t n_args, const mp_obj_t *args) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(args[0]); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + + g_status_callback = (n_args > 2) ? args[2] : mp_const_none; + ch32x03x_status_callback cb = (g_status_callback != mp_const_none) ? c_status_callback : NULL; + bool ok = ch32x03x_program(&self->handle, bufinfo.buf, bufinfo.len, cb); + g_status_callback = MP_OBJ_NULL; + + if (!ok) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32x03x_program failed")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rvswd_x03x_program_obj, 2, 3, rvswd_x03x_program); + +static mp_obj_t rvswd_x03x_unlock_flash(mp_obj_t self_in) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!ch32x03x_unlock_flash(&self->handle)) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32x03x_unlock_flash failed")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_x03x_unlock_flash_obj, rvswd_x03x_unlock_flash); + +static mp_obj_t rvswd_x03x_lock_flash(mp_obj_t self_in) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!ch32x03x_lock_flash(&self->handle)) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32x03x_lock_flash failed")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_x03x_lock_flash_obj, rvswd_x03x_lock_flash); + +// x03x_write_flash(addr, data[, callback]) +static mp_obj_t rvswd_x03x_write_flash(size_t n_args, const mp_obj_t *args) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(args[0]); + uint32_t addr = (uint32_t)mp_obj_get_int(args[1]); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); + + g_status_callback = (n_args > 3) ? args[3] : mp_const_none; + ch32x03x_status_callback cb = (g_status_callback != mp_const_none) ? c_status_callback : NULL; + bool ok = ch32x03x_write_flash(&self->handle, addr, bufinfo.buf, bufinfo.len, cb); + g_status_callback = MP_OBJ_NULL; + + if (!ok) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32x03x_write_flash failed")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rvswd_x03x_write_flash_obj, 3, 4, rvswd_x03x_write_flash); + +static mp_obj_t rvswd_x03x_clear_ops(mp_obj_t self_in) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!ch32x03x_clear_running_operations(&self->handle)) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32x03x_clear_running_operations failed")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_x03x_clear_ops_obj, rvswd_x03x_clear_ops); + +// --------------------------------------------------------------------------- +// Type definition +// --------------------------------------------------------------------------- + +static const mp_rom_map_elem_t rvswd_locals_dict_table[] = { + // Low-level RVSWD protocol + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&rvswd_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_reg), MP_ROM_PTR(&rvswd_write_reg_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_reg), MP_ROM_PTR(&rvswd_read_reg_obj) }, + // CH32 generic + { MP_ROM_QSTR(MP_QSTR_halt), MP_ROM_PTR(&rvswd_halt_obj) }, + { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&rvswd_resume_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset_and_run), MP_ROM_PTR(&rvswd_reset_and_run_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_memory), MP_ROM_PTR(&rvswd_read_memory_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_memory), MP_ROM_PTR(&rvswd_write_memory_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_vendor_bytes), MP_ROM_PTR(&rvswd_read_vendor_bytes_obj) }, + // CH32V20x + { MP_ROM_QSTR(MP_QSTR_v20x_unlock_flash), MP_ROM_PTR(&rvswd_v20x_unlock_flash_obj) }, + { MP_ROM_QSTR(MP_QSTR_v20x_lock_flash), MP_ROM_PTR(&rvswd_v20x_lock_flash_obj) }, + { MP_ROM_QSTR(MP_QSTR_v20x_write_flash), MP_ROM_PTR(&rvswd_v20x_write_flash_obj) }, + { MP_ROM_QSTR(MP_QSTR_v20x_clear_ops), MP_ROM_PTR(&rvswd_v20x_clear_ops_obj) }, + // CH32x03x + { MP_ROM_QSTR(MP_QSTR_x03x_program), MP_ROM_PTR(&rvswd_x03x_program_obj) }, + { MP_ROM_QSTR(MP_QSTR_x03x_unlock_flash), MP_ROM_PTR(&rvswd_x03x_unlock_flash_obj) }, + { MP_ROM_QSTR(MP_QSTR_x03x_lock_flash), MP_ROM_PTR(&rvswd_x03x_lock_flash_obj) }, + { MP_ROM_QSTR(MP_QSTR_x03x_write_flash), MP_ROM_PTR(&rvswd_x03x_write_flash_obj) }, + { MP_ROM_QSTR(MP_QSTR_x03x_clear_ops), MP_ROM_PTR(&rvswd_x03x_clear_ops_obj) }, +}; +static MP_DEFINE_CONST_DICT(rvswd_locals_dict, rvswd_locals_dict_table); + +static const mp_obj_type_t rvswd_type = { + { &mp_type_type }, + .name = MP_QSTR_RVSWD, + .make_new = rvswd_make_new, + .locals_dict = (mp_obj_dict_t *)&rvswd_locals_dict, +}; + +// --------------------------------------------------------------------------- +// Module definition +// --------------------------------------------------------------------------- + +static const mp_rom_map_elem_t rvswd_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_rvswd) }, + { MP_ROM_QSTR(MP_QSTR_RVSWD), MP_ROM_PTR(&rvswd_type) }, + // rvswd_result_t constants + { MP_ROM_QSTR(MP_QSTR_OK), MP_ROM_INT(RVSWD_OK) }, + { MP_ROM_QSTR(MP_QSTR_FAIL), MP_ROM_INT(RVSWD_FAIL) }, + { MP_ROM_QSTR(MP_QSTR_INVALID_ARGS), MP_ROM_INT(RVSWD_INVALID_ARGS) }, + { MP_ROM_QSTR(MP_QSTR_PARITY_ERROR), MP_ROM_INT(RVSWD_PARITY_ERROR) }, +}; +static MP_DEFINE_CONST_DICT(rvswd_module_globals, rvswd_module_globals_table); + +const mp_obj_module_t rvswd_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&rvswd_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_rvswd, rvswd_user_cmodule); diff --git a/esp32-component-rvswd b/esp32-component-rvswd new file mode 160000 index 00000000..8f30d6b1 --- /dev/null +++ b/esp32-component-rvswd @@ -0,0 +1 @@ +Subproject commit 8f30d6b190a8363446aab048d94f8b99061f752d From 68bff505edc14acc57297ba41ea0626e91d21891 Mon Sep 17 00:00:00 2001 From: Bert Outtier Date: Fri, 27 Mar 2026 16:13:25 +0100 Subject: [PATCH 2/5] fix name clash --- c_mpos/src/rvswd_module.c | 72 +++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/c_mpos/src/rvswd_module.c b/c_mpos/src/rvswd_module.c index 509cd303..66827adf 100644 --- a/c_mpos/src/rvswd_module.c +++ b/c_mpos/src/rvswd_module.c @@ -94,57 +94,57 @@ static mp_obj_t rvswd_make_new(const mp_obj_type_t *type, size_t n_args, size_t // Low-level RVSWD protocol // --------------------------------------------------------------------------- -static mp_obj_t rvswd_reset(mp_obj_t self_in) { +static mp_obj_t mprvswd_reset(mp_obj_t self_in) { rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); raise_rvswd_result(rvswd_reset(&self->handle)); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(rvswd_reset_obj, rvswd_reset); +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_reset_obj, mprvswd_reset); -static mp_obj_t rvswd_write_reg(mp_obj_t self_in, mp_obj_t reg_in, mp_obj_t val_in) { +static mp_obj_t mprvswd_write_reg(mp_obj_t self_in, mp_obj_t reg_in, mp_obj_t val_in) { rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); uint8_t reg = (uint8_t)mp_obj_get_int(reg_in); uint32_t val = (uint32_t)mp_obj_get_int(val_in); raise_rvswd_result(rvswd_write(&self->handle, reg, val)); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_3(rvswd_write_reg_obj, rvswd_write_reg); +MP_DEFINE_CONST_FUN_OBJ_3(rvswd_write_reg_obj, mprvswd_write_reg); -static mp_obj_t rvswd_read_reg(mp_obj_t self_in, mp_obj_t reg_in) { +static mp_obj_t mprvswd_read_reg(mp_obj_t self_in, mp_obj_t reg_in) { rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); uint8_t reg = (uint8_t)mp_obj_get_int(reg_in); uint32_t val = 0; raise_rvswd_result(rvswd_read(&self->handle, reg, &val)); return mp_obj_new_int_from_uint(val); } -MP_DEFINE_CONST_FUN_OBJ_2(rvswd_read_reg_obj, rvswd_read_reg); +MP_DEFINE_CONST_FUN_OBJ_2(rvswd_read_reg_obj, mprvswd_read_reg); // --------------------------------------------------------------------------- // CH32 generic debug operations // --------------------------------------------------------------------------- -static mp_obj_t rvswd_halt(mp_obj_t self_in) { +static mp_obj_t mprvswd_halt(mp_obj_t self_in) { rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); raise_rvswd_result(ch32_halt_microprocessor(&self->handle)); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(rvswd_halt_obj, rvswd_halt); +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_halt_obj, mprvswd_halt); -static mp_obj_t rvswd_resume(mp_obj_t self_in) { +static mp_obj_t mprvswd_resume(mp_obj_t self_in) { rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); raise_rvswd_result(ch32_resume_microprocessor(&self->handle)); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(rvswd_resume_obj, rvswd_resume); +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_resume_obj, mprvswd_resume); -static mp_obj_t rvswd_reset_and_run(mp_obj_t self_in) { +static mp_obj_t mprvswd_reset_and_run(mp_obj_t self_in) { rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); raise_rvswd_result(ch32_reset_microprocessor_and_run(&self->handle)); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(rvswd_reset_and_run_obj, rvswd_reset_and_run); +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_reset_and_run_obj, mprvswd_reset_and_run); -static mp_obj_t rvswd_read_memory(mp_obj_t self_in, mp_obj_t addr_in) { +static mp_obj_t mprvswd_read_memory(mp_obj_t self_in, mp_obj_t addr_in) { rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); uint32_t addr = (uint32_t)mp_obj_get_int(addr_in); uint32_t val = 0; @@ -153,9 +153,9 @@ static mp_obj_t rvswd_read_memory(mp_obj_t self_in, mp_obj_t addr_in) { } return mp_obj_new_int_from_uint(val); } -MP_DEFINE_CONST_FUN_OBJ_2(rvswd_read_memory_obj, rvswd_read_memory); +MP_DEFINE_CONST_FUN_OBJ_2(rvswd_read_memory_obj, mprvswd_read_memory); -static mp_obj_t rvswd_write_memory(mp_obj_t self_in, mp_obj_t addr_in, mp_obj_t val_in) { +static mp_obj_t mprvswd_write_memory(mp_obj_t self_in, mp_obj_t addr_in, mp_obj_t val_in) { rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); uint32_t addr = (uint32_t)mp_obj_get_int(addr_in); uint32_t val = (uint32_t)mp_obj_get_int(val_in); @@ -164,10 +164,10 @@ static mp_obj_t rvswd_write_memory(mp_obj_t self_in, mp_obj_t addr_in, mp_obj_t } return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_3(rvswd_write_memory_obj, rvswd_write_memory); +MP_DEFINE_CONST_FUN_OBJ_3(rvswd_write_memory_obj, mprvswd_write_memory); // Returns a 4-tuple of uint32 vendor bytes for chip identification. -static mp_obj_t rvswd_read_vendor_bytes(mp_obj_t self_in) { +static mp_obj_t mprvswd_read_vendor_bytes(mp_obj_t self_in) { rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); uint32_t vendor_bytes[4] = {0, 0, 0, 0}; if (!ch32_read_vendor_bytes(&self->handle, vendor_bytes)) { @@ -179,34 +179,34 @@ static mp_obj_t rvswd_read_vendor_bytes(mp_obj_t self_in) { } return mp_obj_new_tuple(4, tuple); } -MP_DEFINE_CONST_FUN_OBJ_1(rvswd_read_vendor_bytes_obj, rvswd_read_vendor_bytes); +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_read_vendor_bytes_obj, mprvswd_read_vendor_bytes); // --------------------------------------------------------------------------- // CH32V20x flash operations // --------------------------------------------------------------------------- -static mp_obj_t rvswd_v20x_unlock_flash(mp_obj_t self_in) { +static mp_obj_t mprvswd_v20x_unlock_flash(mp_obj_t self_in) { rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!ch32v20x_unlock_flash(&self->handle)) { mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32v20x_unlock_flash failed")); } return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(rvswd_v20x_unlock_flash_obj, rvswd_v20x_unlock_flash); +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_v20x_unlock_flash_obj, mprvswd_v20x_unlock_flash); -static mp_obj_t rvswd_v20x_lock_flash(mp_obj_t self_in) { +static mp_obj_t mprvswd_v20x_lock_flash(mp_obj_t self_in) { rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!ch32v20x_lock_flash(&self->handle)) { mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32v20x_lock_flash failed")); } return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(rvswd_v20x_lock_flash_obj, rvswd_v20x_lock_flash); +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_v20x_lock_flash_obj, mprvswd_v20x_lock_flash); // v20x_write_flash(addr, data[, callback]) // data: bytes-like object with firmware content // callback: optional callable(msg: str, progress: int) -static mp_obj_t rvswd_v20x_write_flash(size_t n_args, const mp_obj_t *args) { +static mp_obj_t mprvswd_v20x_write_flash(size_t n_args, const mp_obj_t *args) { rvswd_obj_t *self = MP_OBJ_TO_PTR(args[0]); uint32_t addr = (uint32_t)mp_obj_get_int(args[1]); mp_buffer_info_t bufinfo; @@ -222,16 +222,16 @@ static mp_obj_t rvswd_v20x_write_flash(size_t n_args, const mp_obj_t *args) { } return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rvswd_v20x_write_flash_obj, 3, 4, rvswd_v20x_write_flash); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rvswd_v20x_write_flash_obj, 3, 4, mprvswd_v20x_write_flash); -static mp_obj_t rvswd_v20x_clear_ops(mp_obj_t self_in) { +static mp_obj_t mprvswd_v20x_clear_ops(mp_obj_t self_in) { rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!ch32v20x_clear_running_operations(&self->handle)) { mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32v20x_clear_running_operations failed")); } return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(rvswd_v20x_clear_ops_obj, rvswd_v20x_clear_ops); +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_v20x_clear_ops_obj, mprvswd_v20x_clear_ops); // --------------------------------------------------------------------------- // CH32x03x flash operations @@ -239,7 +239,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(rvswd_v20x_clear_ops_obj, rvswd_v20x_clear_ops); // x03x_program(firmware[, callback]) // High-level: halts, erases, writes, verifies and restarts the target. -static mp_obj_t rvswd_x03x_program(size_t n_args, const mp_obj_t *args) { +static mp_obj_t mprvswd_x03x_program(size_t n_args, const mp_obj_t *args) { rvswd_obj_t *self = MP_OBJ_TO_PTR(args[0]); mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); @@ -254,28 +254,28 @@ static mp_obj_t rvswd_x03x_program(size_t n_args, const mp_obj_t *args) { } return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rvswd_x03x_program_obj, 2, 3, rvswd_x03x_program); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rvswd_x03x_program_obj, 2, 3, mprvswd_x03x_program); -static mp_obj_t rvswd_x03x_unlock_flash(mp_obj_t self_in) { +static mp_obj_t mprvswd_x03x_unlock_flash(mp_obj_t self_in) { rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!ch32x03x_unlock_flash(&self->handle)) { mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32x03x_unlock_flash failed")); } return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(rvswd_x03x_unlock_flash_obj, rvswd_x03x_unlock_flash); +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_x03x_unlock_flash_obj, mprvswd_x03x_unlock_flash); -static mp_obj_t rvswd_x03x_lock_flash(mp_obj_t self_in) { +static mp_obj_t mprvswd_x03x_lock_flash(mp_obj_t self_in) { rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!ch32x03x_lock_flash(&self->handle)) { mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32x03x_lock_flash failed")); } return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(rvswd_x03x_lock_flash_obj, rvswd_x03x_lock_flash); +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_x03x_lock_flash_obj, mprvswd_x03x_lock_flash); // x03x_write_flash(addr, data[, callback]) -static mp_obj_t rvswd_x03x_write_flash(size_t n_args, const mp_obj_t *args) { +static mp_obj_t mprvswd_x03x_write_flash(size_t n_args, const mp_obj_t *args) { rvswd_obj_t *self = MP_OBJ_TO_PTR(args[0]); uint32_t addr = (uint32_t)mp_obj_get_int(args[1]); mp_buffer_info_t bufinfo; @@ -291,16 +291,16 @@ static mp_obj_t rvswd_x03x_write_flash(size_t n_args, const mp_obj_t *args) { } return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rvswd_x03x_write_flash_obj, 3, 4, rvswd_x03x_write_flash); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rvswd_x03x_write_flash_obj, 3, 4, mprvswd_x03x_write_flash); -static mp_obj_t rvswd_x03x_clear_ops(mp_obj_t self_in) { +static mp_obj_t mprvswd_x03x_clear_ops(mp_obj_t self_in) { rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!ch32x03x_clear_running_operations(&self->handle)) { mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32x03x_clear_running_operations failed")); } return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(rvswd_x03x_clear_ops_obj, rvswd_x03x_clear_ops); +MP_DEFINE_CONST_FUN_OBJ_1(rvswd_x03x_clear_ops_obj, mprvswd_x03x_clear_ops); // --------------------------------------------------------------------------- // Type definition From e4ad2b4686ee5a4c502a674e4ff521eba85d787c Mon Sep 17 00:00:00 2001 From: Bert Outtier Date: Fri, 27 Mar 2026 16:25:40 +0100 Subject: [PATCH 3/5] add missing binding for programming ch32v20x --- c_mpos/src/rvswd_module.c | 20 ++++++++++++++++++++ esp32-component-rvswd | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/c_mpos/src/rvswd_module.c b/c_mpos/src/rvswd_module.c index 66827adf..c4166e27 100644 --- a/c_mpos/src/rvswd_module.c +++ b/c_mpos/src/rvswd_module.c @@ -185,6 +185,25 @@ MP_DEFINE_CONST_FUN_OBJ_1(rvswd_read_vendor_bytes_obj, mprvswd_read_vendor_bytes // CH32V20x flash operations // --------------------------------------------------------------------------- +// v20x_program(firmware[, callback]) +// High-level: halts, erases, writes, verifies and restarts the target. +static mp_obj_t mprvswd_v20x_program(size_t n_args, const mp_obj_t *args) { + rvswd_obj_t *self = MP_OBJ_TO_PTR(args[0]); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + + g_status_callback = (n_args > 2) ? args[2] : mp_const_none; + ch32v20x_status_callback cb = (g_status_callback != mp_const_none) ? c_status_callback : NULL; + bool ok = ch32v20x_program(&self->handle, bufinfo.buf, bufinfo.len, cb); + g_status_callback = MP_OBJ_NULL; + + if (!ok) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("ch32v20x_program failed")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rvswd_v20x_program_obj, 2, 3, mprvswd_v20x_program); + static mp_obj_t mprvswd_v20x_unlock_flash(mp_obj_t self_in) { rvswd_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!ch32v20x_unlock_flash(&self->handle)) { @@ -319,6 +338,7 @@ static const mp_rom_map_elem_t rvswd_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_write_memory), MP_ROM_PTR(&rvswd_write_memory_obj) }, { MP_ROM_QSTR(MP_QSTR_read_vendor_bytes), MP_ROM_PTR(&rvswd_read_vendor_bytes_obj) }, // CH32V20x + { MP_ROM_QSTR(MP_QSTR_v20x_program), MP_ROM_PTR(&rvswd_v20x_program_obj) }, { MP_ROM_QSTR(MP_QSTR_v20x_unlock_flash), MP_ROM_PTR(&rvswd_v20x_unlock_flash_obj) }, { MP_ROM_QSTR(MP_QSTR_v20x_lock_flash), MP_ROM_PTR(&rvswd_v20x_lock_flash_obj) }, { MP_ROM_QSTR(MP_QSTR_v20x_write_flash), MP_ROM_PTR(&rvswd_v20x_write_flash_obj) }, diff --git a/esp32-component-rvswd b/esp32-component-rvswd index 8f30d6b1..8187ed18 160000 --- a/esp32-component-rvswd +++ b/esp32-component-rvswd @@ -1 +1 @@ -Subproject commit 8f30d6b190a8363446aab048d94f8b99061f752d +Subproject commit 8187ed183ad76613ed8ecfd056781a05804028fe From 0167c8bf85ba9cc1998b46b5cf8f1c7f44bab898 Mon Sep 17 00:00:00 2001 From: Bert Outtier Date: Fri, 27 Mar 2026 16:41:26 +0100 Subject: [PATCH 4/5] use MP_DEFINE_CONST_OBJ_TYPE macro --- c_mpos/src/rvswd_module.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/c_mpos/src/rvswd_module.c b/c_mpos/src/rvswd_module.c index c4166e27..92634304 100644 --- a/c_mpos/src/rvswd_module.c +++ b/c_mpos/src/rvswd_module.c @@ -40,7 +40,6 @@ typedef struct { rvswd_handle_t handle; } rvswd_obj_t; -static const mp_obj_type_t rvswd_type; // forward declaration // --------------------------------------------------------------------------- // Callback bridge @@ -352,12 +351,13 @@ static const mp_rom_map_elem_t rvswd_locals_dict_table[] = { }; static MP_DEFINE_CONST_DICT(rvswd_locals_dict, rvswd_locals_dict_table); -static const mp_obj_type_t rvswd_type = { - { &mp_type_type }, - .name = MP_QSTR_RVSWD, - .make_new = rvswd_make_new, - .locals_dict = (mp_obj_dict_t *)&rvswd_locals_dict, -}; +MP_DEFINE_CONST_OBJ_TYPE( + rvswd_type, + MP_QSTR_RVSWD, + MP_TYPE_FLAG_NONE, + make_new, rvswd_make_new, + locals_dict, &rvswd_locals_dict +); // --------------------------------------------------------------------------- // Module definition From a0c14e0965eefd765abde9a11db22737e604ec78 Mon Sep 17 00:00:00 2001 From: Bert Outtier Date: Fri, 27 Mar 2026 19:30:30 +0100 Subject: [PATCH 5/5] fix missing include --- esp32-component-rvswd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esp32-component-rvswd b/esp32-component-rvswd index 8187ed18..74741287 160000 --- a/esp32-component-rvswd +++ b/esp32-component-rvswd @@ -1 +1 @@ -Subproject commit 8187ed183ad76613ed8ecfd056781a05804028fe +Subproject commit 74741287f6a706e8fb71adbc4c8dc0c3409b68ba