From 4851487818206ab47ad5c4f2accbdb56113cccbc Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Wed, 18 Jan 2023 14:37:46 +0000 Subject: [PATCH 01/11] ports/rp2: Adding RP2 DMA class. Signed-off-by: mark --- .gitignore | 3 + docs/rp2/general.rst | 1 + docs/rp2/quickref.rst | 44 +++ examples/rp2/dma_write_from.py | 55 ++++ ports/rp2/CMakeLists.txt | 2 + ports/rp2/README.md | 2 +- ports/rp2/dma.c | 568 +++++++++++++++++++++++++++++++++ ports/rp2/main.c | 1 + ports/rp2/modrp2.c | 2 + ports/rp2/modrp2.h | 4 + 10 files changed, 681 insertions(+), 1 deletion(-) create mode 100644 examples/rp2/dma_write_from.py create mode 100644 ports/rp2/dma.c diff --git a/.gitignore b/.gitignore index 2d20cb18970e8..344ebf1d549c9 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ user.props # MacOS desktop metadata files .DS_Store + +# VScode config +.vscode diff --git a/docs/rp2/general.rst b/docs/rp2/general.rst index 6a8958d172a84..01457b6232f20 100644 --- a/docs/rp2/general.rst +++ b/docs/rp2/general.rst @@ -34,3 +34,4 @@ The peripherals include: * 16 PWM channels * USB 1.1 controller * 8 PIO state machines +* 12 DMA channels and 4 pacing timers diff --git a/docs/rp2/quickref.rst b/docs/rp2/quickref.rst index 430c130c6e865..9c721dfa907f8 100644 --- a/docs/rp2/quickref.rst +++ b/docs/rp2/quickref.rst @@ -298,6 +298,50 @@ See :ref:`machine.WDT `. :: The maximum value for timeout is 8388 ms. +DMA (Direct memory access) +-------------------------- + +The RP2040 has a DMA subsytem that has 12 hardware controlled DMA channels and 4 pacing timers. + +Example using DMA to fade an LED:: + + from rp2 import DMA, Timer + from machine import Pin, PWM + + led = Pin(16, Pin.OUT) + pwm1 = PWM(led) + pwm1.freq(1000) + pwm1.duty_u16(0) + + # PWM 0A for GPIO16. Lower 16 bits of CC + dest = 0x4005000e + dma = DMA() + dma.claim() + t = Timer() + + t.claim() + # go as slowly as possible + t.set(0x0001, 0xffff) + + data_size = dma.DMA_SIZE_16 + buffer_size = 32768 + from_buffer = bytearray(buffer_size) + for i in range(0, buffer_size, 2): + from_buffer[i]= i & 0xff + from_buffer[i+1]= (i>>8) & 0xff + + dma.write_from(from_buffer=from_buffer, + to_address=dest, + transfer_count=buffer_size>>data_size, + dreq=dreq, + data_size=data_size) + while dma.isbusy(): + time.sleep_ms(1) + + t.unclaim() + dma.unclaim() + + OneWire driver -------------- diff --git a/examples/rp2/dma_write_from.py b/examples/rp2/dma_write_from.py new file mode 100644 index 0000000000000..469cb3392595a --- /dev/null +++ b/examples/rp2/dma_write_from.py @@ -0,0 +1,55 @@ +import time +from rp2 import DMA, Timer +from machine import Pin, PWM + +def led(): + print("DMA write_from demo") + led = Pin(16, Pin.OUT) + pwm1 = PWM(led) + pwm1.freq(1000) + pwm1.duty_u16(0) + + # pwm 0A attached to GPIO 16 + dest = 0x4005000e + dma = DMA() + dma.claim() + t = Timer() + + X = 0x0001 + Y = 0xffff + t.claim() + t.set(X, Y) + + print(f"Starting\nDMA:{dma}\nTimer:{t}") + + dreq = t.dreq() + + data_size = dma.DMA_SIZE_16 + buffer_size = 32768 + from_buffer = bytearray(buffer_size) + + # create a 16 bit fade + for i in range(0, buffer_size, 2): + from_buffer[i]= i & 0xff + from_buffer[i+1]= (i>>8) & 0xff + + start = time.ticks_ms() + + dma.write_from(from_buffer=from_buffer, + to_address=dest, + transfer_count=buffer_size>>data_size, + dreq=dreq, + data_size=data_size) + while dma.isbusy(): + time.sleep_ms(1) + + end = time.ticks_ms() + + t.unclaim() + dma.unclaim() + print(f"Write from fade took {end-start}mS") + print("Done") + pwm1.duty_u16(0) + +if __name__ == '__main__': + led() diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 357125e734c3a..35d2a0283a787 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -109,6 +109,7 @@ set(MICROPY_SOURCE_PORT fatfs_port.c machine_adc.c machine_bitstream.c + dma.c machine_i2c.c machine_i2s.c machine_pin.c @@ -140,6 +141,7 @@ set(MICROPY_SOURCE_QSTR ${MICROPY_DIR}/shared/runtime/mpirq.c ${MICROPY_DIR}/shared/runtime/sys_stdio_mphal.c ${PROJECT_SOURCE_DIR}/machine_adc.c + ${PROJECT_SOURCE_DIR}/dma.c ${PROJECT_SOURCE_DIR}/machine_i2c.c ${PROJECT_SOURCE_DIR}/machine_i2s.c ${PROJECT_SOURCE_DIR}/machine_pin.c diff --git a/ports/rp2/README.md b/ports/rp2/README.md index 078919ce81940..8e52eb6b23051 100644 --- a/ports/rp2/README.md +++ b/ports/rp2/README.md @@ -10,7 +10,7 @@ Currently supported features are: - `uos` module with VFS support. - `machine` module with the following classes: `Pin`, `ADC`, `PWM`, `I2C`, `SPI`, `SoftI2C`, `SoftSPI`, `Timer`, `UART`, `WDT`. -- `rp2` module with programmable IO (PIO) support. +- `rp2` module with programmable IO (PIO) support and DMA module. See the `examples/rp2/` directory for some example code. diff --git a/ports/rp2/dma.c b/ports/rp2/dma.c new file mode 100644 index 0000000000000..925f3bab4e89f --- /dev/null +++ b/ports/rp2/dma.c @@ -0,0 +1,568 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022-2023 Mark Burton + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "string.h" + +#include "py/gc.h" +#include "py/mphal.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "shared/runtime/mpirq.h" + +#include "hardware/dma.h" + +#define DBG_PRINTF(...) mp_printf(&mp_plat_print, "rp2.dma: " __VA_ARGS__) + +extern const mp_obj_type_t dma_DMA_type; +extern const mp_obj_type_t dma_Timer_type; + +/***************************************************************************** + * Data types +*/ +typedef struct _dma_DMA_obj_t { + mp_obj_base_t base; + uint8_t dma_channel; + uint32_t requests; + uint32_t transfers; + mp_obj_t handler; +} dma_DMA_obj_t; + +typedef struct _dma_Timer_obj_t { + mp_obj_base_t base; + uint8_t timer; +} dma_Timer_obj_t; + +/****************************************************************************** + * Private methods +*/ +void dma_irq_handler() +{ + uint32_t insts0 = dma_hw->ints0; + // clear the dma irq + dma_hw->ints0 = dma_hw->ints0; + + dma_DMA_obj_t *dma_callback = NULL; + mp_obj_t callback = mp_const_none; + + for(uint8_t i=0;ihandler; + if(callback != mp_const_none) + { + mp_sched_lock(); + // When executing code within a handler we must lock the GC to prevent + // any memory allocations. We must also catch any exceptions. + gc_lock(); + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) + { + uint32_t status = dma_channel_hw_addr(i)->ctrl_trig; + mp_call_function_1(callback, mp_obj_new_int_from_uint((status >> 29) & 3)); + dma_callback->handler = mp_const_none; + nlr_pop(); + } + else + {} + + gc_unlock(); + mp_sched_unlock(); + } + } + } + } +} + +void dma_irq_init(dma_DMA_obj_t *self, mp_obj_t handler) +{ + self->handler = handler; + MP_STATE_PORT(dma_DMA_obj_all)[self->dma_channel] = self; + dma_channel_set_irq0_enabled(self->dma_channel, true); + irq_set_exclusive_handler(DMA_IRQ_0, dma_irq_handler); + irq_set_enabled(DMA_IRQ_0, true); +} + + void check_init(dma_DMA_obj_t *self) + { + if(self->dma_channel == 0xff) + { + mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA channel not claimed")); + } + } + + +uint32_t dma_get_error_status(uint channel) +{ + dma_channel_hw_t* dma = dma_channel_hw_addr(channel); + return (dma->ctrl_trig>>29) & 7; +} + +void dma_check_and_raise_status(dma_DMA_obj_t *self,dma_channel_config* config) +{ + uint32_t status = dma_get_error_status(self->dma_channel); + if(status & 0x04) + { + dma_channel_hw_t* dma = dma_channel_hw_addr(self->dma_channel); + channel_config_set_enable(config, false); + // disable the channel on IRQ0 + dma_channel_set_irq0_enabled(self->dma_channel, false); + // abort the channel + dma_channel_abort(self->dma_channel); + // clear the spurious IRQ (if there was one) + dma_channel_acknowledge_irq0(self->dma_channel); + mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA transfer error %d read addr: 0x%08x write addr: 0x%08x"), status & 3,dma->read_addr, dma->write_addr); + } +} + +void dma_start_request(dma_DMA_obj_t *self, + dma_channel_config* config, + void * to_address_ptr, + void *from_address_ptr, + uint32_t transfer_count, + uint32_t dreq, + uint32_t data_size, + mp_obj_t handler) +{ + if(dreq != 0) + channel_config_set_dreq(config, dreq); + + channel_config_set_transfer_data_size(config, data_size); + + // IRQ stuff + if(mp_obj_is_callable(handler)) + { + dma_irq_init(self, handler); + } + else + { + dma_channel_set_irq0_enabled(self->dma_channel, false); + } + + // configure a one shot DMA request. + dma_channel_configure(self->dma_channel, config, + to_address_ptr, // Destinatinon pointer + from_address_ptr, // Source pointer + transfer_count, // Number of transfers + true // Start immediately + ); + + dma_check_and_raise_status(self, config); +} + + +MP_REGISTER_ROOT_POINTER(struct _dma_DMA_obj_t *dma_DMA_obj_all[NUM_DMA_CHANNELS]); + +void dma_init(void) +{ + memset(MP_STATE_PORT(dma_DMA_obj_all), 0, sizeof(MP_STATE_PORT(dma_DMA_obj_all))); +} + +STATIC mp_obj_t dma_DMA_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + dma_DMA_obj_t *self = mp_obj_malloc(dma_DMA_obj_t, &dma_DMA_type); + self->dma_channel = 0xff; + self->handler = mp_const_none; + self->requests = 0; + self->transfers = 0; + return MP_OBJ_FROM_PTR(self); +} +STATIC void dma_DMA_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + dma_DMA_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", self->dma_channel, self->requests, self->transfers); +} + +STATIC mp_obj_t dma_DMA_claim(mp_obj_t self_in) { + dma_DMA_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->dma_channel = dma_claim_unused_channel(false); + if(self->dma_channel == -1) + mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA No channels available")); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_claim_obj, dma_DMA_claim); + +STATIC mp_obj_t dma_DMA_unclaim(mp_obj_t self_in) { + dma_DMA_obj_t *self = MP_OBJ_TO_PTR(self_in); + if(self->dma_channel != 0xff) + { + dma_irqn_set_channel_enabled(DMA_IRQ_0, self->dma_channel, false); + dma_channel_abort(self->dma_channel); + dma_channel_unclaim(self->dma_channel); + self->dma_channel = 0xff; + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_unclaim_obj, dma_DMA_unclaim); + +STATIC mp_obj_t dma_DMA_isclaimed(mp_obj_t self_in) { + dma_DMA_obj_t *self = MP_OBJ_TO_PTR(self_in); + bool claimed = dma_channel_is_claimed(self->dma_channel); + if(claimed) + return mp_const_true; + else + return mp_const_false; + +} +MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_isclaimed_obj, dma_DMA_isclaimed); + + +/***************************************************************************** + * write_from + * + * Arguments + * from_buffer - bytearray + * data_size - 1,2,4 bytes (use constant) + * transfer_count - + * to_address - address to send data + * dreq - optional throttle transfer. Default is to go as fast as possible + * handler - optional IRQ handler + * +*/ +STATIC mp_obj_t dma_DMA_write_from(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_from_buffer, ARG_to_address, ARG_dreq, ARG_transfer_count, ARG_data_size, ARG_handler}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_from_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_to_address, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_dreq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_transfer_count, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_data_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DMA_SIZE_8} }, + { MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + dma_DMA_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + check_init(self); + + void * to_address_ptr = (void*)args[ARG_to_address].u_int; + uint32_t dreq = args[ARG_dreq].u_int; + uint32_t transfer_count = args[ARG_transfer_count].u_int; + uint32_t data_size = args[ARG_data_size].u_int; + mp_obj_t handler = args[ARG_handler].u_obj; + + mp_buffer_info_t bufinfo; + bufinfo.buf = NULL; + mp_get_buffer_raise(args[ARG_from_buffer].u_obj, &bufinfo, MP_BUFFER_READ); + + if(transfer_count == 0) + transfer_count = bufinfo.len >> data_size; + + self->requests++; + self->transfers+=transfer_count; + + dma_channel_config config = dma_channel_get_default_config(self->dma_channel); + + channel_config_set_read_increment(&config, true); + channel_config_set_write_increment(&config, false); + + dma_start_request(self, &config, to_address_ptr, bufinfo.buf, transfer_count, dreq, data_size, handler); + + return mp_obj_new_int(bufinfo.len); + +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dma_DMA_write_from_obj, 1, dma_DMA_write_from); + + +/***************************************************************************** + * read_into + * + * Arguments + * from_address - address to send data + * data_size - 1,2,4 bytes (use constant) + * transfer_count - + * to_buffer - bytearray + * dreq - optional throttle transfer. Default is to go as fast as possible + * handler - optional IRQ handler + * +*/ +STATIC mp_obj_t dma_DMA_read_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_from_address, ARG_to_buffer, ARG_transfer_count, ARG_data_size, ARG_dreq, ARG_handler}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_from_address, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_to_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_transfer_count, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_data_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DMA_SIZE_8} }, + { MP_QSTR_dreq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + dma_DMA_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_init(self); + + void * from_address_ptr = (void*)(args[ARG_from_address].u_int); + + uint32_t dreq = args[ARG_dreq].u_int; + uint32_t transfer_count = args[ARG_transfer_count].u_int; + uint32_t data_size = args[ARG_data_size].u_int; + mp_obj_t handler = args[ARG_handler].u_obj; + + mp_buffer_info_t bufinfo; + bufinfo.buf = NULL; + mp_get_buffer_raise(args[ARG_to_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE); + + if(transfer_count == 0) + transfer_count = bufinfo.len >> data_size; + + self->requests++; + self->transfers+=transfer_count; + + dma_channel_config config = dma_channel_get_default_config(self->dma_channel); + channel_config_set_read_increment(&config, false); + channel_config_set_write_increment(&config, true); + + dma_start_request(self, &config, bufinfo.buf, from_address_ptr, transfer_count, dreq, data_size, handler); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dma_DMA_read_into_obj, 1, dma_DMA_read_into); + +/***************************************************************************** + * copy + * + * Arguments + * from_buffer - source bytearray + * data_size - 1,2,4 bytes (use constant) + * to_buffer - bytearray + * handler - optional IRQ handler + * +*/ +STATIC mp_obj_t dma_DMA_copy(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_from_buffer, ARG_to_buffer, ARG_handler}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_from_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_to_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + dma_DMA_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + mp_buffer_info_t from_buffer; + from_buffer.buf = NULL; + mp_get_buffer_raise(args[ARG_from_buffer].u_obj, &from_buffer, MP_BUFFER_READ); + + mp_buffer_info_t to_buffer; + to_buffer.buf = NULL; + mp_get_buffer_raise(args[ARG_to_buffer].u_obj, &to_buffer, MP_BUFFER_WRITE); + mp_obj_t handler = args[ARG_handler].u_obj; + + if (from_buffer.len > to_buffer.len) + mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA buffer overrun %d > %d "), from_buffer.len, to_buffer.len); + + self->requests++; + self->transfers+=from_buffer.len; + + dma_channel_config config = dma_channel_get_default_config(self->dma_channel); + channel_config_set_read_increment(&config, true); + channel_config_set_write_increment(&config, true); + + dma_start_request(self, &config, to_buffer.buf, from_buffer.buf, from_buffer.len, 0x3f, DMA_SIZE_8, handler); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dma_DMA_copy_obj, 1, dma_DMA_copy); + +STATIC mp_obj_t dma_DMA_isbusy(mp_obj_t self_in) { + dma_DMA_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(dma_channel_is_busy(self->dma_channel)); +} +MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_isbusy_obj, dma_DMA_isbusy); + +STATIC mp_obj_t dma_DMA_error_status(mp_obj_t self_in) { + dma_DMA_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint32_t status = dma_channel_hw_addr(self->dma_channel)->ctrl_trig; + return mp_obj_new_int_from_uint((status >> 29) & 3); +} +MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_error_status_obj, dma_DMA_error_status); + +STATIC mp_obj_t dma_DMA_clear_error(mp_obj_t self_in) { + dma_DMA_obj_t *self = MP_OBJ_TO_PTR(self_in); + hw_set_bits(&dma_hw->ch[self->dma_channel].al1_ctrl, 3u << 29); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_clear_error_obj, dma_DMA_clear_error); + +STATIC mp_obj_t dma_DMA_request_count(mp_obj_t self_in) { + dma_DMA_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(self->requests); + +} +MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_request_count_obj, dma_DMA_request_count); + +STATIC const mp_rom_map_elem_t dma_DMA_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_claim), MP_ROM_PTR(&dma_DMA_claim_obj) }, + { MP_ROM_QSTR(MP_QSTR_unclaim), MP_ROM_PTR(&dma_DMA_unclaim_obj) }, + { MP_ROM_QSTR(MP_QSTR_isclaimed), MP_ROM_PTR(&dma_DMA_isclaimed_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_from), (mp_obj_t)&dma_DMA_write_from_obj }, + { MP_ROM_QSTR(MP_QSTR_read_into), MP_ROM_PTR(&dma_DMA_read_into_obj) }, + { MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&dma_DMA_copy_obj) }, + { MP_ROM_QSTR(MP_QSTR_isbusy), MP_ROM_PTR(&dma_DMA_isbusy_obj) }, + { MP_ROM_QSTR(MP_QSTR_error_status), (mp_obj_t)&dma_DMA_error_status_obj }, + { MP_ROM_QSTR(MP_QSTR_clear_error), MP_ROM_PTR(&dma_DMA_clear_error_obj) }, + { MP_ROM_QSTR(MP_QSTR_request_count), MP_ROM_PTR(&dma_DMA_request_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_DMA_SIZE_8), MP_ROM_INT(DMA_SIZE_8) }, + { MP_ROM_QSTR(MP_QSTR_DMA_SIZE_16), MP_ROM_INT(DMA_SIZE_16) }, + { MP_ROM_QSTR(MP_QSTR_DMA_SIZE_32), MP_ROM_INT(DMA_SIZE_32) }, +}; + +STATIC MP_DEFINE_CONST_DICT(dma_DMA_locals_dict, dma_DMA_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + dma_DMA_type, + MP_QSTR_DMA, + MP_TYPE_FLAG_NONE, + make_new, dma_DMA_make_new, + print, dma_DMA_print, + locals_dict, &dma_DMA_locals_dict + ); + + +/////////////////////////////////////////////////////////////////////////////////// +/* + * Timer + * Arguments + * timer_id +*/ +STATIC mp_obj_t dma_Timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + dma_Timer_obj_t *self = mp_obj_malloc(dma_Timer_obj_t, &dma_Timer_type); + self->timer = 0xff; + return MP_OBJ_FROM_PTR(self); +} + +STATIC void dma_Timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + dma_Timer_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", self->timer); +} + + +STATIC mp_obj_t dma_Timer_claim(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_timer_id, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xff} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + dma_Timer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + uint32_t timer_id = args[0].u_int; + if (self->timer != 0xff) + { + mp_raise_ValueError("Timer already claimed"); + } + else if (timer_id == 0xff) + { + int claimed_timer_id = dma_claim_unused_timer(false); + if (claimed_timer_id == -1) + { + mp_raise_ValueError("No timers available"); + } + else + { + self->timer = claimed_timer_id; + } + } + else + { + self->timer = timer_id; + if(dma_timer_is_claimed(self->timer)) + { + mp_raise_ValueError("Timer already claimed"); + } + else + { + dma_timer_claim(self->timer); + } + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dma_Timer_claim_obj, 1, dma_Timer_claim); + +STATIC mp_obj_t dma_Timer_unclaim(mp_obj_t self_in) { + dma_Timer_obj_t *self = MP_OBJ_TO_PTR(self_in); + if(dma_timer_is_claimed(self->timer)) + { + dma_timer_unclaim(self->timer); + self->timer = 0xff; + } + else + { + mp_raise_ValueError("Timer already unclaimed"); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(dma_Timer_unclaim_obj, dma_Timer_unclaim); + +STATIC mp_obj_t dma_Timer_isclaimed(mp_obj_t self_in) { + dma_Timer_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(dma_timer_is_claimed(self->timer)); + +} +MP_DEFINE_CONST_FUN_OBJ_1(dma_Timer_isclaimed_obj, dma_Timer_isclaimed); + + +STATIC mp_obj_t dma_Timer_set(mp_obj_t self_in, mp_obj_t numerator_obj, mp_obj_t denominator_obj) { + dma_Timer_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint16_t numerator = mp_obj_get_int(numerator_obj); + uint16_t denominator = mp_obj_get_int(denominator_obj); + dma_timer_set_fraction(self->timer, numerator, denominator); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_3(dma_Timer_set_obj, dma_Timer_set); + +STATIC mp_obj_t dma_Timer_dreq(mp_obj_t self_in) { + dma_Timer_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(dma_get_timer_dreq(self->timer)); +} +MP_DEFINE_CONST_FUN_OBJ_1(dma_Timer_dreq_obj, dma_Timer_dreq); + + +STATIC const mp_rom_map_elem_t dma_Timer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_claim), MP_ROM_PTR(&dma_Timer_claim_obj) }, + { MP_ROM_QSTR(MP_QSTR_unclaim), MP_ROM_PTR(&dma_Timer_unclaim_obj) }, + { MP_ROM_QSTR(MP_QSTR_isclaimed), MP_ROM_PTR(&dma_Timer_isclaimed_obj) }, + { MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&dma_Timer_set_obj) }, + { MP_ROM_QSTR(MP_QSTR_dreq), MP_ROM_PTR(&dma_Timer_dreq_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(dma_Timer_locals_dict, dma_Timer_locals_dict_table); + + +MP_DEFINE_CONST_OBJ_TYPE( + dma_Timer_type, + MP_QSTR_Timer, + MP_TYPE_FLAG_NONE, + make_new, dma_Timer_make_new, + print, dma_Timer_print, + locals_dict, &dma_Timer_locals_dict + ); diff --git a/ports/rp2/main.c b/ports/rp2/main.c index c5b50374912c3..0ec371ab815c6 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -162,6 +162,7 @@ int main(int argc, char **argv) { machine_pin_init(); rp2_pio_init(); machine_i2s_init0(); + dma_init(); #if MICROPY_PY_BLUETOOTH mp_bluetooth_hci_init(); diff --git a/ports/rp2/modrp2.c b/ports/rp2/modrp2.c index 2601a7f443de4..6e2c62095cda9 100644 --- a/ports/rp2/modrp2.c +++ b/ports/rp2/modrp2.c @@ -55,6 +55,8 @@ STATIC const mp_rom_map_elem_t rp2_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&rp2_flash_type) }, { MP_ROM_QSTR(MP_QSTR_PIO), MP_ROM_PTR(&rp2_pio_type) }, { MP_ROM_QSTR(MP_QSTR_StateMachine), MP_ROM_PTR(&rp2_state_machine_type) }, + { MP_ROM_QSTR(MP_QSTR_DMA), MP_ROM_PTR(&dma_DMA_type) }, + { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&dma_Timer_type) }, #if MICROPY_PY_NETWORK_CYW43 { MP_ROM_QSTR(MP_QSTR_country), MP_ROM_PTR(&rp2_country_obj) }, diff --git a/ports/rp2/modrp2.h b/ports/rp2/modrp2.h index 805c785f2d8cd..15d13623825bd 100644 --- a/ports/rp2/modrp2.h +++ b/ports/rp2/modrp2.h @@ -31,8 +31,12 @@ extern const mp_obj_type_t rp2_flash_type; extern const mp_obj_type_t rp2_pio_type; extern const mp_obj_type_t rp2_state_machine_type; +extern const mp_obj_type_t dma_DMA_type; +extern const mp_obj_type_t dma_Timer_type; + void rp2_pio_init(void); void rp2_pio_deinit(void); +void dma_init(); #endif // MICROPY_INCLUDED_RP2_MODRP2_H From a6ebf364354387a380f224e12d14ec7205a45a91 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Fri, 20 Jan 2023 14:07:55 +0000 Subject: [PATCH 02/11] rp2/dma.c: Add abort, busy to API. add abort. check busy. cleanup Signed-off-by: mark --- ports/rp2/dma.c | 65 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/ports/rp2/dma.c b/ports/rp2/dma.c index 925f3bab4e89f..b22af79903b4b 100644 --- a/ports/rp2/dma.c +++ b/ports/rp2/dma.c @@ -34,7 +34,13 @@ #include "hardware/dma.h" -#define DBG_PRINTF(...) mp_printf(&mp_plat_print, "rp2.dma: " __VA_ARGS__) +#define RP2_DEBUG 0 + +#if RP2_DEBUG + #define DBG_PRINTF(...) mp_printf(&mp_plat_print, "rp2.dma: " __VA_ARGS__) +#else + #define DBG_PRINTF(...) +#endif extern const mp_obj_type_t dma_DMA_type; extern const mp_obj_type_t dma_Timer_type; @@ -57,7 +63,7 @@ typedef struct _dma_Timer_obj_t { /****************************************************************************** * Private methods -*/ +******************************************************************************/ void dma_irq_handler() { uint32_t insts0 = dma_hw->ints0; @@ -82,7 +88,7 @@ void dma_irq_handler() // any memory allocations. We must also catch any exceptions. gc_lock(); nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) + if(nlr_push(&nlr) == 0) { uint32_t status = dma_channel_hw_addr(i)->ctrl_trig; mp_call_function_1(callback, mp_obj_new_int_from_uint((status >> 29) & 3)); @@ -90,8 +96,10 @@ void dma_irq_handler() nlr_pop(); } else - {} - + { + dma_callback->handler = mp_const_none; + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } gc_unlock(); mp_sched_unlock(); } @@ -117,6 +125,11 @@ void dma_irq_init(dma_DMA_obj_t *self, mp_obj_t handler) } } +void check_busy(dma_DMA_obj_t *self) +{ + if(dma_channel_is_busy(self->dma_channel)) + mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA channel is already active")); +} uint32_t dma_get_error_status(uint channel) { @@ -176,7 +189,6 @@ void dma_start_request(dma_DMA_obj_t *self, dma_check_and_raise_status(self, config); } - MP_REGISTER_ROOT_POINTER(struct _dma_DMA_obj_t *dma_DMA_obj_all[NUM_DMA_CHANNELS]); void dma_init(void) @@ -192,6 +204,7 @@ STATIC mp_obj_t dma_DMA_make_new(const mp_obj_type_t *type, size_t n_args, size_ self->transfers = 0; return MP_OBJ_FROM_PTR(self); } + STATIC void dma_DMA_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { dma_DMA_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "", self->dma_channel, self->requests, self->transfers); @@ -222,12 +235,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_unclaim_obj, dma_DMA_unclaim); STATIC mp_obj_t dma_DMA_isclaimed(mp_obj_t self_in) { dma_DMA_obj_t *self = MP_OBJ_TO_PTR(self_in); - bool claimed = dma_channel_is_claimed(self->dma_channel); - if(claimed) - return mp_const_true; - else - return mp_const_false; - + return mp_obj_new_bool(dma_channel_is_claimed(self->dma_channel)); } MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_isclaimed_obj, dma_DMA_isclaimed); @@ -243,7 +251,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_isclaimed_obj, dma_DMA_isclaimed); * dreq - optional throttle transfer. Default is to go as fast as possible * handler - optional IRQ handler * -*/ +*******************************************************************************/ STATIC mp_obj_t dma_DMA_write_from(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_from_buffer, ARG_to_address, ARG_dreq, ARG_transfer_count, ARG_data_size, ARG_handler}; static const mp_arg_t allowed_args[] = { @@ -254,13 +262,17 @@ STATIC mp_obj_t dma_DMA_write_from(size_t n_args, const mp_obj_t *pos_args, mp_m { MP_QSTR_data_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DMA_SIZE_8} }, { MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, }; - + DBG_PRINTF("write_from\n"); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); dma_DMA_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); check_init(self); + check_busy(self); + + if(dma_channel_is_busy(self->dma_channel)) + mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA channel is already active")); void * to_address_ptr = (void*)args[ARG_to_address].u_int; uint32_t dreq = args[ARG_dreq].u_int; @@ -302,7 +314,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dma_DMA_write_from_obj, 1, dma_DMA_write_from) * dreq - optional throttle transfer. Default is to go as fast as possible * handler - optional IRQ handler * -*/ +*******************************************************************************/ STATIC mp_obj_t dma_DMA_read_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_from_address, ARG_to_buffer, ARG_transfer_count, ARG_data_size, ARG_dreq, ARG_handler}; static const mp_arg_t allowed_args[] = { @@ -313,11 +325,13 @@ STATIC mp_obj_t dma_DMA_read_into(size_t n_args, const mp_obj_t *pos_args, mp_ma { MP_QSTR_dreq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, }; + DBG_PRINTF("read_into\n"); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); dma_DMA_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); check_init(self); + check_busy(self); void * from_address_ptr = (void*)(args[ARG_from_address].u_int); @@ -351,11 +365,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dma_DMA_read_into_obj, 1, dma_DMA_read_into); * * Arguments * from_buffer - source bytearray - * data_size - 1,2,4 bytes (use constant) * to_buffer - bytearray * handler - optional IRQ handler * -*/ +*******************************************************************************/ STATIC mp_obj_t dma_DMA_copy(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_from_buffer, ARG_to_buffer, ARG_handler}; static const mp_arg_t allowed_args[] = { @@ -363,11 +376,15 @@ STATIC mp_obj_t dma_DMA_copy(size_t n_args, const mp_obj_t *pos_args, mp_map_t * { MP_QSTR_to_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, }; + DBG_PRINTF("copy\n"); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); dma_DMA_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_init(self); + check_busy(self); + mp_buffer_info_t from_buffer; from_buffer.buf = NULL; mp_get_buffer_raise(args[ARG_from_buffer].u_obj, &from_buffer, MP_BUFFER_READ); @@ -393,6 +410,19 @@ STATIC mp_obj_t dma_DMA_copy(size_t n_args, const mp_obj_t *pos_args, mp_map_t * } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dma_DMA_copy_obj, 1, dma_DMA_copy); +STATIC mp_obj_t dma_DMA_abort(mp_obj_t self_in) { + dma_DMA_obj_t *self = MP_OBJ_TO_PTR(self_in); + + dma_channel_set_irq0_enabled(self->dma_channel, false); + // abort the channel + dma_channel_abort(self->dma_channel); + // clear the spurious IRQ (if there was one) + dma_channel_acknowledge_irq0(self->dma_channel); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_abort_obj, dma_DMA_abort); + STATIC mp_obj_t dma_DMA_isbusy(mp_obj_t self_in) { dma_DMA_obj_t *self = MP_OBJ_TO_PTR(self_in); return mp_obj_new_bool(dma_channel_is_busy(self->dma_channel)); @@ -427,6 +457,7 @@ STATIC const mp_rom_map_elem_t dma_DMA_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_write_from), (mp_obj_t)&dma_DMA_write_from_obj }, { MP_ROM_QSTR(MP_QSTR_read_into), MP_ROM_PTR(&dma_DMA_read_into_obj) }, { MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&dma_DMA_copy_obj) }, + { MP_ROM_QSTR(MP_QSTR_abort), MP_ROM_PTR(&dma_DMA_abort_obj) }, { MP_ROM_QSTR(MP_QSTR_isbusy), MP_ROM_PTR(&dma_DMA_isbusy_obj) }, { MP_ROM_QSTR(MP_QSTR_error_status), (mp_obj_t)&dma_DMA_error_status_obj }, { MP_ROM_QSTR(MP_QSTR_clear_error), MP_ROM_PTR(&dma_DMA_clear_error_obj) }, From 237a40c082a4eebf9d732e1e9feb7883ff83f647 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Fri, 3 Feb 2023 16:43:15 +0000 Subject: [PATCH 03/11] rp2/dma.c: Add work around for spurious IRQ's. Signed-off-by: mark --- ports/rp2/dma.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ports/rp2/dma.c b/ports/rp2/dma.c index b22af79903b4b..66dec7a528bfd 100644 --- a/ports/rp2/dma.c +++ b/ports/rp2/dma.c @@ -112,7 +112,14 @@ void dma_irq_init(dma_DMA_obj_t *self, mp_obj_t handler) { self->handler = handler; MP_STATE_PORT(dma_DMA_obj_all)[self->dma_channel] = self; + + // work around to prevent spurious IRQ's + dma_channel_set_irq0_enabled(self->dma_channel, false); + dma_channel_abort(self->dma_channel); + // clear the spurious IRQ (if there was one) + dma_channel_acknowledge_irq0(self->dma_channel); dma_channel_set_irq0_enabled(self->dma_channel, true); + irq_set_exclusive_handler(DMA_IRQ_0, dma_irq_handler); irq_set_enabled(DMA_IRQ_0, true); } @@ -271,9 +278,6 @@ STATIC mp_obj_t dma_DMA_write_from(size_t n_args, const mp_obj_t *pos_args, mp_m check_init(self); check_busy(self); - if(dma_channel_is_busy(self->dma_channel)) - mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA channel is already active")); - void * to_address_ptr = (void*)args[ARG_to_address].u_int; uint32_t dreq = args[ARG_dreq].u_int; uint32_t transfer_count = args[ARG_transfer_count].u_int; From 1bb6f2efb971b9a6aa3e5f1b0fabe7b5e9cb006e Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Fri, 3 Feb 2023 16:58:01 +0000 Subject: [PATCH 04/11] examples/rp2: Update dma examples. Signed-off-by: mark --- examples/rp2/dma_write_from.py | 2 +- examples/rp2/dma_write_from_irq.py | 71 ++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 examples/rp2/dma_write_from_irq.py diff --git a/examples/rp2/dma_write_from.py b/examples/rp2/dma_write_from.py index 469cb3392595a..07f28af23c014 100644 --- a/examples/rp2/dma_write_from.py +++ b/examples/rp2/dma_write_from.py @@ -41,7 +41,7 @@ def led(): dreq=dreq, data_size=data_size) while dma.isbusy(): - time.sleep_ms(1) + time.sleep_ms(100) end = time.ticks_ms() diff --git a/examples/rp2/dma_write_from_irq.py b/examples/rp2/dma_write_from_irq.py new file mode 100644 index 0000000000000..b1e9a2d0b5c81 --- /dev/null +++ b/examples/rp2/dma_write_from_irq.py @@ -0,0 +1,71 @@ +import uasyncio +import time +from rp2 import DMA, Timer +from machine import Pin, PWM + +async def led(): + print("DMA write_from demo") + led = Pin(16, Pin.OUT) + pwm1 = PWM(led) + pwm1.freq(1000) + pwm1.duty_u16(0) + + # pwm 0A attached to GPIO 16 + dest = 0x4005000e + dma = DMA() + dma.claim() + t = Timer() + + # slow the timer to it's slowest rate + X = 0x0001 + Y = 0xffff + t.claim() + t.set(X, Y) + + print(f"Starting\nDMA:{dma}\nTimer:{t}") + + dreq = t.dreq() + + data_size = dma.DMA_SIZE_16 + buffer_size = 32768 + from_buffer = bytearray(buffer_size) + + # create a 16 bit fade + for i in range(0, buffer_size, 2): + from_buffer[i]= i & 0xff + from_buffer[i+1]= (i>>8) & 0xff + + start = time.ticks_ms() + + e = uasyncio.ThreadSafeFlag() + + def _callback(dma_status): + print("callback") + e.set() + + dma.write_from(from_buffer=from_buffer, + to_address=dest, + transfer_count=buffer_size>>data_size, + dreq=dreq, + data_size=data_size, + handler=_callback) + + await e.wait() + + end = time.ticks_ms() + + t.unclaim() + dma.unclaim() + print(f"Write from fade took {end-start}mS") + print("Done") + pwm1.duty_u16(0) + +async def async_led(): + t = uasyncio.create_task(led()) + await t + +def main(): + uasyncio.run(async_led()) + +if __name__ == '__main__': + main() From 5a8c5f6654169ac249c6e4cbfa341b6aef72dc34 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Tue, 7 Feb 2023 16:11:35 +0000 Subject: [PATCH 05/11] examples/rp2: Fix python code formatting. Signed-off-by: mark --- examples/rp2/dma_write_from.py | 33 +++++++++++++------------ examples/rp2/dma_write_from_irq.py | 39 +++++++++++++++++------------- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/examples/rp2/dma_write_from.py b/examples/rp2/dma_write_from.py index 07f28af23c014..d258f27ecde06 100644 --- a/examples/rp2/dma_write_from.py +++ b/examples/rp2/dma_write_from.py @@ -2,6 +2,7 @@ from rp2 import DMA, Timer from machine import Pin, PWM + def led(): print("DMA write_from demo") led = Pin(16, Pin.OUT) @@ -10,46 +11,48 @@ def led(): pwm1.duty_u16(0) # pwm 0A attached to GPIO 16 - dest = 0x4005000e + dest = 0x4005000E dma = DMA() dma.claim() t = Timer() X = 0x0001 - Y = 0xffff + Y = 0xFFFF t.claim() t.set(X, Y) print(f"Starting\nDMA:{dma}\nTimer:{t}") - + dreq = t.dreq() - + data_size = dma.DMA_SIZE_16 buffer_size = 32768 from_buffer = bytearray(buffer_size) - + # create a 16 bit fade for i in range(0, buffer_size, 2): - from_buffer[i]= i & 0xff - from_buffer[i+1]= (i>>8) & 0xff - + from_buffer[i]= i & 0xFF + from_buffer[i+1]= (i>>8) & 0xFF + start = time.ticks_ms() - + dma.write_from(from_buffer=from_buffer, - to_address=dest, - transfer_count=buffer_size>>data_size, - dreq=dreq, - data_size=data_size) + to_address=dest, + transfer_count=buffer_size>>data_size, + dreq=dreq, + data_size=data_size + ) while dma.isbusy(): time.sleep_ms(100) end = time.ticks_ms() - + t.unclaim() dma.unclaim() print(f"Write from fade took {end-start}mS") print("Done") pwm1.duty_u16(0) - + + if __name__ == '__main__': led() diff --git a/examples/rp2/dma_write_from_irq.py b/examples/rp2/dma_write_from_irq.py index b1e9a2d0b5c81..5a1f962a17e00 100644 --- a/examples/rp2/dma_write_from_irq.py +++ b/examples/rp2/dma_write_from_irq.py @@ -3,6 +3,7 @@ from rp2 import DMA, Timer from machine import Pin, PWM + async def led(): print("DMA write_from demo") led = Pin(16, Pin.OUT) @@ -11,32 +12,32 @@ async def led(): pwm1.duty_u16(0) # pwm 0A attached to GPIO 16 - dest = 0x4005000e + dest = 0x4005000E dma = DMA() dma.claim() t = Timer() # slow the timer to it's slowest rate X = 0x0001 - Y = 0xffff + Y = 0xFFFF t.claim() t.set(X, Y) print(f"Starting\nDMA:{dma}\nTimer:{t}") - + dreq = t.dreq() - + data_size = dma.DMA_SIZE_16 buffer_size = 32768 from_buffer = bytearray(buffer_size) - + # create a 16 bit fade for i in range(0, buffer_size, 2): - from_buffer[i]= i & 0xff - from_buffer[i+1]= (i>>8) & 0xff - + from_buffer[i]= i & 0xFF + from_buffer[i+1]= (i>>8) & 0xFF + start = time.ticks_ms() - + e = uasyncio.ThreadSafeFlag() def _callback(dma_status): @@ -44,28 +45,32 @@ def _callback(dma_status): e.set() dma.write_from(from_buffer=from_buffer, - to_address=dest, - transfer_count=buffer_size>>data_size, - dreq=dreq, - data_size=data_size, - handler=_callback) - + to_address=dest, + transfer_count=buffer_size>>data_size, + dreq=dreq, + data_size=data_size, + handler=_callback + ) + await e.wait() - + end = time.ticks_ms() - + t.unclaim() dma.unclaim() print(f"Write from fade took {end-start}mS") print("Done") pwm1.duty_u16(0) + async def async_led(): t = uasyncio.create_task(led()) await t + def main(): uasyncio.run(async_led()) + if __name__ == '__main__': main() From 56609bec1ad62f1d78e288f9394ed1ac1bbe75fe Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Tue, 7 Feb 2023 16:18:19 +0000 Subject: [PATCH 06/11] examples/rp2: Fix python formatting. Signed-off-by: mark --- examples/rp2/dma_write_from.py | 13 +++++++------ examples/rp2/dma_write_from_irq.py | 13 +++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/examples/rp2/dma_write_from.py b/examples/rp2/dma_write_from.py index d258f27ecde06..49cc554024435 100644 --- a/examples/rp2/dma_write_from.py +++ b/examples/rp2/dma_write_from.py @@ -31,16 +31,17 @@ def led(): # create a 16 bit fade for i in range(0, buffer_size, 2): - from_buffer[i]= i & 0xFF - from_buffer[i+1]= (i>>8) & 0xFF + from_buffer[i] = i & 0xFF + from_buffer[i+1] = (i>>8) & 0xFF start = time.ticks_ms() - dma.write_from(from_buffer=from_buffer, + dma.write_from( + from_buffer=from_buffer, to_address=dest, - transfer_count=buffer_size>>data_size, + transfer_count=buffer_size >> data_size, dreq=dreq, - data_size=data_size + data_size=data_size, ) while dma.isbusy(): time.sleep_ms(100) @@ -54,5 +55,5 @@ def led(): pwm1.duty_u16(0) -if __name__ == '__main__': +if __name__ == "__main__": led() diff --git a/examples/rp2/dma_write_from_irq.py b/examples/rp2/dma_write_from_irq.py index 5a1f962a17e00..cd6f329f20286 100644 --- a/examples/rp2/dma_write_from_irq.py +++ b/examples/rp2/dma_write_from_irq.py @@ -33,8 +33,8 @@ async def led(): # create a 16 bit fade for i in range(0, buffer_size, 2): - from_buffer[i]= i & 0xFF - from_buffer[i+1]= (i>>8) & 0xFF + from_buffer[i] = i & 0xFF + from_buffer[i+1] = (i>>8) & 0xFF start = time.ticks_ms() @@ -44,12 +44,13 @@ def _callback(dma_status): print("callback") e.set() - dma.write_from(from_buffer=from_buffer, + dma.write_from( + from_buffer=from_buffer, to_address=dest, - transfer_count=buffer_size>>data_size, + transfer_count=buffer_size >> data_size, dreq=dreq, data_size=data_size, - handler=_callback + handler=_callback, ) await e.wait() @@ -72,5 +73,5 @@ def main(): uasyncio.run(async_led()) -if __name__ == '__main__': +if __name__ == "__main__": main() From e9f80f7ce2d8ed0637df4f9fbcf3ad769a3c3c8e Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Tue, 7 Feb 2023 16:21:35 +0000 Subject: [PATCH 07/11] examples/rp2: Fix python formatting. Signed-off-by: mark --- examples/rp2/dma_write_from.py | 2 +- examples/rp2/dma_write_from_irq.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/rp2/dma_write_from.py b/examples/rp2/dma_write_from.py index 49cc554024435..fe9d56bb82ca5 100644 --- a/examples/rp2/dma_write_from.py +++ b/examples/rp2/dma_write_from.py @@ -32,7 +32,7 @@ def led(): # create a 16 bit fade for i in range(0, buffer_size, 2): from_buffer[i] = i & 0xFF - from_buffer[i+1] = (i>>8) & 0xFF + from_buffer[i+1] = (i >> 8) & 0xFF start = time.ticks_ms() diff --git a/examples/rp2/dma_write_from_irq.py b/examples/rp2/dma_write_from_irq.py index cd6f329f20286..6223fa159bff5 100644 --- a/examples/rp2/dma_write_from_irq.py +++ b/examples/rp2/dma_write_from_irq.py @@ -34,7 +34,7 @@ async def led(): # create a 16 bit fade for i in range(0, buffer_size, 2): from_buffer[i] = i & 0xFF - from_buffer[i+1] = (i>>8) & 0xFF + from_buffer[i+1] = (i >> 8) & 0xFF start = time.ticks_ms() From 6619d8209cd7b946ff73817de115b90ac8cf84ce Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Tue, 7 Feb 2023 16:37:46 +0000 Subject: [PATCH 08/11] examples/rp2: Fix python code formatting. Signed-off-by: mark --- examples/rp2/dma_write_from.py | 2 +- examples/rp2/dma_write_from_irq.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/rp2/dma_write_from.py b/examples/rp2/dma_write_from.py index fe9d56bb82ca5..5f745ceaa9842 100644 --- a/examples/rp2/dma_write_from.py +++ b/examples/rp2/dma_write_from.py @@ -32,7 +32,7 @@ def led(): # create a 16 bit fade for i in range(0, buffer_size, 2): from_buffer[i] = i & 0xFF - from_buffer[i+1] = (i >> 8) & 0xFF + from_buffer[i + 1] = (i >> 8) & 0xFF start = time.ticks_ms() diff --git a/examples/rp2/dma_write_from_irq.py b/examples/rp2/dma_write_from_irq.py index 6223fa159bff5..d5e765a4c2bd0 100644 --- a/examples/rp2/dma_write_from_irq.py +++ b/examples/rp2/dma_write_from_irq.py @@ -34,7 +34,7 @@ async def led(): # create a 16 bit fade for i in range(0, buffer_size, 2): from_buffer[i] = i & 0xFF - from_buffer[i+1] = (i >> 8) & 0xFF + from_buffer[i + 1] = (i >> 8) & 0xFF start = time.ticks_ms() From cce40d486d35f72c2b42fc8087bd0b2046426bc1 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Tue, 7 Feb 2023 16:43:57 +0000 Subject: [PATCH 09/11] rp2/dma.c: Fix C code formatting. Signed-off-by: mark --- ports/rp2/dma.c | 234 +++++++++++++++++++++--------------------------- 1 file changed, 103 insertions(+), 131 deletions(-) diff --git a/ports/rp2/dma.c b/ports/rp2/dma.c index 66dec7a528bfd..d3b1afb36c2a0 100644 --- a/ports/rp2/dma.c +++ b/ports/rp2/dma.c @@ -64,39 +64,32 @@ typedef struct _dma_Timer_obj_t { /****************************************************************************** * Private methods ******************************************************************************/ -void dma_irq_handler() -{ +void dma_irq_handler() { uint32_t insts0 = dma_hw->ints0; // clear the dma irq dma_hw->ints0 = dma_hw->ints0; dma_DMA_obj_t *dma_callback = NULL; mp_obj_t callback = mp_const_none; - - for(uint8_t i=0;ihandler; - if(callback != mp_const_none) - { + if (callback != mp_const_none) { mp_sched_lock(); // When executing code within a handler we must lock the GC to prevent // any memory allocations. We must also catch any exceptions. gc_lock(); nlr_buf_t nlr; - if(nlr_push(&nlr) == 0) - { - uint32_t status = dma_channel_hw_addr(i)->ctrl_trig; + if (nlr_push(&nlr) == 0) { + uint32_t status = dma_channel_hw_addr(i)->ctrl_trig; mp_call_function_1(callback, mp_obj_new_int_from_uint((status >> 29) & 3)); dma_callback->handler = mp_const_none; nlr_pop(); - } - else - { + } else { dma_callback->handler = mp_const_none; mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); } @@ -108,48 +101,42 @@ void dma_irq_handler() } } -void dma_irq_init(dma_DMA_obj_t *self, mp_obj_t handler) -{ +void dma_irq_init(dma_DMA_obj_t *self, mp_obj_t handler) { self->handler = handler; MP_STATE_PORT(dma_DMA_obj_all)[self->dma_channel] = self; - + // work around to prevent spurious IRQ's dma_channel_set_irq0_enabled(self->dma_channel, false); dma_channel_abort(self->dma_channel); // clear the spurious IRQ (if there was one) dma_channel_acknowledge_irq0(self->dma_channel); dma_channel_set_irq0_enabled(self->dma_channel, true); - + irq_set_exclusive_handler(DMA_IRQ_0, dma_irq_handler); irq_set_enabled(DMA_IRQ_0, true); } - void check_init(dma_DMA_obj_t *self) - { - if(self->dma_channel == 0xff) - { - mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA channel not claimed")); +void check_init(dma_DMA_obj_t *self) { + if (self->dma_channel == 0xff) { + mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA channel not claimed")); } - } +} -void check_busy(dma_DMA_obj_t *self) -{ - if(dma_channel_is_busy(self->dma_channel)) - mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA channel is already active")); +void check_busy(dma_DMA_obj_t *self) { + if (dma_channel_is_busy(self->dma_channel)) { + mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA channel is already active")); + } } -uint32_t dma_get_error_status(uint channel) -{ - dma_channel_hw_t* dma = dma_channel_hw_addr(channel); - return (dma->ctrl_trig>>29) & 7; +uint32_t dma_get_error_status(uint channel) { + dma_channel_hw_t *dma = dma_channel_hw_addr(channel); + return (dma->ctrl_trig >> 29) & 7; } -void dma_check_and_raise_status(dma_DMA_obj_t *self,dma_channel_config* config) -{ - uint32_t status = dma_get_error_status(self->dma_channel); - if(status & 0x04) - { - dma_channel_hw_t* dma = dma_channel_hw_addr(self->dma_channel); +void dma_check_and_raise_status(dma_DMA_obj_t *self, dma_channel_config *config) { + uint32_t status = dma_get_error_status(self->dma_channel); + if (status & 0x04) { + dma_channel_hw_t *dma = dma_channel_hw_addr(self->dma_channel); channel_config_set_enable(config, false); // disable the channel on IRQ0 dma_channel_set_irq0_enabled(self->dma_channel, false); @@ -157,49 +144,45 @@ void dma_check_and_raise_status(dma_DMA_obj_t *self,dma_channel_config* config) dma_channel_abort(self->dma_channel); // clear the spurious IRQ (if there was one) dma_channel_acknowledge_irq0(self->dma_channel); - mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA transfer error %d read addr: 0x%08x write addr: 0x%08x"), status & 3,dma->read_addr, dma->write_addr); + mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA transfer error %d read addr: 0x%08x write addr: 0x%08x"), status & 3, dma->read_addr, dma->write_addr); } } -void dma_start_request(dma_DMA_obj_t *self, - dma_channel_config* config, - void * to_address_ptr, - void *from_address_ptr, - uint32_t transfer_count, - uint32_t dreq, - uint32_t data_size, - mp_obj_t handler) -{ - if(dreq != 0) +void dma_start_request(dma_DMA_obj_t *self, + dma_channel_config *config, + void *to_address_ptr, + void *from_address_ptr, + uint32_t transfer_count, + uint32_t dreq, + uint32_t data_size, + mp_obj_t handler) { + if (dreq != 0) { channel_config_set_dreq(config, dreq); - + } + channel_config_set_transfer_data_size(config, data_size); // IRQ stuff - if(mp_obj_is_callable(handler)) - { + if (mp_obj_is_callable(handler)) { dma_irq_init(self, handler); - } - else - { + } else { dma_channel_set_irq0_enabled(self->dma_channel, false); } - + // configure a one shot DMA request. dma_channel_configure(self->dma_channel, config, to_address_ptr, // Destinatinon pointer from_address_ptr, // Source pointer transfer_count, // Number of transfers true // Start immediately - ); + ); dma_check_and_raise_status(self, config); } MP_REGISTER_ROOT_POINTER(struct _dma_DMA_obj_t *dma_DMA_obj_all[NUM_DMA_CHANNELS]); -void dma_init(void) -{ +void dma_init(void) { memset(MP_STATE_PORT(dma_DMA_obj_all), 0, sizeof(MP_STATE_PORT(dma_DMA_obj_all))); } @@ -220,8 +203,9 @@ STATIC void dma_DMA_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki STATIC mp_obj_t dma_DMA_claim(mp_obj_t self_in) { dma_DMA_obj_t *self = MP_OBJ_TO_PTR(self_in); self->dma_channel = dma_claim_unused_channel(false); - if(self->dma_channel == -1) - mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA No channels available")); + if (self->dma_channel == -1) { + mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA No channels available")); + } return mp_const_none; } @@ -229,35 +213,34 @@ MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_claim_obj, dma_DMA_claim); STATIC mp_obj_t dma_DMA_unclaim(mp_obj_t self_in) { dma_DMA_obj_t *self = MP_OBJ_TO_PTR(self_in); - if(self->dma_channel != 0xff) - { + if (self->dma_channel != 0xff) { dma_irqn_set_channel_enabled(DMA_IRQ_0, self->dma_channel, false); - dma_channel_abort(self->dma_channel); + dma_channel_abort(self->dma_channel); dma_channel_unclaim(self->dma_channel); self->dma_channel = 0xff; } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_unclaim_obj, dma_DMA_unclaim); - + STATIC mp_obj_t dma_DMA_isclaimed(mp_obj_t self_in) { dma_DMA_obj_t *self = MP_OBJ_TO_PTR(self_in); return mp_obj_new_bool(dma_channel_is_claimed(self->dma_channel)); } MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_isclaimed_obj, dma_DMA_isclaimed); - + /***************************************************************************** * write_from - * + * * Arguments - * from_buffer - bytearray + * from_buffer - bytearray * data_size - 1,2,4 bytes (use constant) - * transfer_count - + * transfer_count - * to_address - address to send data * dreq - optional throttle transfer. Default is to go as fast as possible * handler - optional IRQ handler - * + * *******************************************************************************/ STATIC mp_obj_t dma_DMA_write_from(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_from_buffer, ARG_to_address, ARG_dreq, ARG_transfer_count, ARG_data_size, ARG_handler}; @@ -271,53 +254,54 @@ STATIC mp_obj_t dma_DMA_write_from(size_t n_args, const mp_obj_t *pos_args, mp_m }; DBG_PRINTF("write_from\n"); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); dma_DMA_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - + check_init(self); check_busy(self); - void * to_address_ptr = (void*)args[ARG_to_address].u_int; + void *to_address_ptr = (void *)args[ARG_to_address].u_int; uint32_t dreq = args[ARG_dreq].u_int; uint32_t transfer_count = args[ARG_transfer_count].u_int; uint32_t data_size = args[ARG_data_size].u_int; mp_obj_t handler = args[ARG_handler].u_obj; - + mp_buffer_info_t bufinfo; bufinfo.buf = NULL; mp_get_buffer_raise(args[ARG_from_buffer].u_obj, &bufinfo, MP_BUFFER_READ); - if(transfer_count == 0) + if (transfer_count == 0) { transfer_count = bufinfo.len >> data_size; + } self->requests++; - self->transfers+=transfer_count; - + self->transfers += transfer_count; + dma_channel_config config = dma_channel_get_default_config(self->dma_channel); - + channel_config_set_read_increment(&config, true); channel_config_set_write_increment(&config, false); dma_start_request(self, &config, to_address_ptr, bufinfo.buf, transfer_count, dreq, data_size, handler); return mp_obj_new_int(bufinfo.len); - + } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dma_DMA_write_from_obj, 1, dma_DMA_write_from); /***************************************************************************** * read_into - * + * * Arguments * from_address - address to send data * data_size - 1,2,4 bytes (use constant) - * transfer_count - - * to_buffer - bytearray + * transfer_count - + * to_buffer - bytearray * dreq - optional throttle transfer. Default is to go as fast as possible * handler - optional IRQ handler - * + * *******************************************************************************/ STATIC mp_obj_t dma_DMA_read_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_from_address, ARG_to_buffer, ARG_transfer_count, ARG_data_size, ARG_dreq, ARG_handler}; @@ -331,13 +315,13 @@ STATIC mp_obj_t dma_DMA_read_into(size_t n_args, const mp_obj_t *pos_args, mp_ma }; DBG_PRINTF("read_into\n"); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + dma_DMA_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); check_init(self); check_busy(self); - - void * from_address_ptr = (void*)(args[ARG_from_address].u_int); + + void *from_address_ptr = (void *)(args[ARG_from_address].u_int); uint32_t dreq = args[ARG_dreq].u_int; uint32_t transfer_count = args[ARG_transfer_count].u_int; @@ -348,30 +332,31 @@ STATIC mp_obj_t dma_DMA_read_into(size_t n_args, const mp_obj_t *pos_args, mp_ma bufinfo.buf = NULL; mp_get_buffer_raise(args[ARG_to_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE); - if(transfer_count == 0) + if (transfer_count == 0) { transfer_count = bufinfo.len >> data_size; + } self->requests++; - self->transfers+=transfer_count; + self->transfers += transfer_count; dma_channel_config config = dma_channel_get_default_config(self->dma_channel); channel_config_set_read_increment(&config, false); channel_config_set_write_increment(&config, true); dma_start_request(self, &config, bufinfo.buf, from_address_ptr, transfer_count, dreq, data_size, handler); - + return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dma_DMA_read_into_obj, 1, dma_DMA_read_into); /***************************************************************************** * copy - * + * * Arguments * from_buffer - source bytearray - * to_buffer - bytearray + * to_buffer - bytearray * handler - optional IRQ handler - * + * *******************************************************************************/ STATIC mp_obj_t dma_DMA_copy(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_from_buffer, ARG_to_buffer, ARG_handler}; @@ -382,8 +367,8 @@ STATIC mp_obj_t dma_DMA_copy(size_t n_args, const mp_obj_t *pos_args, mp_map_t * }; DBG_PRINTF("copy\n"); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + dma_DMA_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); check_init(self); @@ -398,25 +383,26 @@ STATIC mp_obj_t dma_DMA_copy(size_t n_args, const mp_obj_t *pos_args, mp_map_t * mp_get_buffer_raise(args[ARG_to_buffer].u_obj, &to_buffer, MP_BUFFER_WRITE); mp_obj_t handler = args[ARG_handler].u_obj; - if (from_buffer.len > to_buffer.len) - mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA buffer overrun %d > %d "), from_buffer.len, to_buffer.len); + if (from_buffer.len > to_buffer.len) { + mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA buffer overrun %d > %d "), from_buffer.len, to_buffer.len); + } self->requests++; - self->transfers+=from_buffer.len; + self->transfers += from_buffer.len; dma_channel_config config = dma_channel_get_default_config(self->dma_channel); channel_config_set_read_increment(&config, true); channel_config_set_write_increment(&config, true); dma_start_request(self, &config, to_buffer.buf, from_buffer.buf, from_buffer.len, 0x3f, DMA_SIZE_8, handler); - + return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dma_DMA_copy_obj, 1, dma_DMA_copy); STATIC mp_obj_t dma_DMA_abort(mp_obj_t self_in) { dma_DMA_obj_t *self = MP_OBJ_TO_PTR(self_in); - + dma_channel_set_irq0_enabled(self->dma_channel, false); // abort the channel dma_channel_abort(self->dma_channel); @@ -435,7 +421,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_isbusy_obj, dma_DMA_isbusy); STATIC mp_obj_t dma_DMA_error_status(mp_obj_t self_in) { dma_DMA_obj_t *self = MP_OBJ_TO_PTR(self_in); - uint32_t status = dma_channel_hw_addr(self->dma_channel)->ctrl_trig; + uint32_t status = dma_channel_hw_addr(self->dma_channel)->ctrl_trig; return mp_obj_new_int_from_uint((status >> 29) & 3); } MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_error_status_obj, dma_DMA_error_status); @@ -487,7 +473,7 @@ MP_DEFINE_CONST_OBJ_TYPE( /* * Timer * Arguments - * timer_id + * timer_id */ STATIC mp_obj_t dma_Timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { dma_Timer_obj_t *self = mp_obj_malloc(dma_Timer_obj_t, &dma_Timer_type); @@ -502,40 +488,29 @@ STATIC void dma_Timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ STATIC mp_obj_t dma_Timer_claim(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - static const mp_arg_t allowed_args[] = { + static const mp_arg_t allowed_args[] = { { MP_QSTR_timer_id, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xff} }, }; - + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); dma_Timer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); uint32_t timer_id = args[0].u_int; - if (self->timer != 0xff) - { + if (self->timer != 0xff) { mp_raise_ValueError("Timer already claimed"); - } - else if (timer_id == 0xff) - { + } else if (timer_id == 0xff) { int claimed_timer_id = dma_claim_unused_timer(false); - if (claimed_timer_id == -1) - { + if (claimed_timer_id == -1) { mp_raise_ValueError("No timers available"); - } - else - { + } else { self->timer = claimed_timer_id; } - } - else - { + } else { self->timer = timer_id; - if(dma_timer_is_claimed(self->timer)) - { + if (dma_timer_is_claimed(self->timer)) { mp_raise_ValueError("Timer already claimed"); - } - else - { + } else { dma_timer_claim(self->timer); } } @@ -545,13 +520,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dma_Timer_claim_obj, 1, dma_Timer_claim); STATIC mp_obj_t dma_Timer_unclaim(mp_obj_t self_in) { dma_Timer_obj_t *self = MP_OBJ_TO_PTR(self_in); - if(dma_timer_is_claimed(self->timer)) - { + if (dma_timer_is_claimed(self->timer)) { dma_timer_unclaim(self->timer); self->timer = 0xff; - } - else - { + } else { mp_raise_ValueError("Timer already unclaimed"); } return mp_const_none; @@ -561,7 +533,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(dma_Timer_unclaim_obj, dma_Timer_unclaim); STATIC mp_obj_t dma_Timer_isclaimed(mp_obj_t self_in) { dma_Timer_obj_t *self = MP_OBJ_TO_PTR(self_in); return mp_obj_new_bool(dma_timer_is_claimed(self->timer)); - + } MP_DEFINE_CONST_FUN_OBJ_1(dma_Timer_isclaimed_obj, dma_Timer_isclaimed); From c5544c4cae6b7866516cf68eed7eeead8d5b64a8 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Thu, 9 Feb 2023 16:41:44 +0000 Subject: [PATCH 10/11] rp2/dma.c: Added IRQ0 & IRQ1 handling. Signed-off-by: Mark Burton --- ports/rp2/dma.c | 71 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/ports/rp2/dma.c b/ports/rp2/dma.c index d3b1afb36c2a0..9709739469343 100644 --- a/ports/rp2/dma.c +++ b/ports/rp2/dma.c @@ -64,17 +64,14 @@ typedef struct _dma_Timer_obj_t { /****************************************************************************** * Private methods ******************************************************************************/ -void dma_irq_handler() { - uint32_t insts0 = dma_hw->ints0; - // clear the dma irq - dma_hw->ints0 = dma_hw->ints0; - +void dma_irq_handler(uint32_t irq_status) { + DBG_PRINTF("dma_irq_handler 0x%08x\n", irq_status); dma_DMA_obj_t *dma_callback = NULL; mp_obj_t callback = mp_const_none; for (uint8_t i = 0; i < NUM_DMA_CHANNELS; i++) { - if (insts0 & (1 << i)) { + if (irq_status & (1 << i)) { dma_callback = MP_STATE_PORT(dma_DMA_obj_all)[i]; if (dma_callback) { callback = dma_callback->handler; @@ -101,19 +98,43 @@ void dma_irq_handler() { } } -void dma_irq_init(dma_DMA_obj_t *self, mp_obj_t handler) { +void dma_irq_handler0() { + uint32_t insts0 = dma_hw->ints0; + // clear the dma irq + dma_hw->ints0 = dma_hw->ints0; + dma_irq_handler(insts0); +} + +void dma_irq_handler1() { + uint32_t insts1 = dma_hw->ints1; + // clear the dma irq + dma_hw->ints1 = dma_hw->ints1; + dma_irq_handler(insts1); +} + +void dma_irq_init(dma_DMA_obj_t *self, mp_obj_t handler, uint32_t irq) { + DBG_PRINTF("dma_irq_init %d\n", irq); self->handler = handler; MP_STATE_PORT(dma_DMA_obj_all)[self->dma_channel] = self; // work around to prevent spurious IRQ's - dma_channel_set_irq0_enabled(self->dma_channel, false); + dma_irqn_set_channel_enabled(irq, self->dma_channel, false); dma_channel_abort(self->dma_channel); // clear the spurious IRQ (if there was one) dma_channel_acknowledge_irq0(self->dma_channel); - dma_channel_set_irq0_enabled(self->dma_channel, true); + if (irq == DMA_IRQ_0) { + dma_irqn_set_channel_enabled(0, self->dma_channel, true); + } else { + dma_irqn_set_channel_enabled(1, self->dma_channel, true); + } - irq_set_exclusive_handler(DMA_IRQ_0, dma_irq_handler); - irq_set_enabled(DMA_IRQ_0, true); + if (irq == DMA_IRQ_0) { + irq_set_exclusive_handler(DMA_IRQ_0, dma_irq_handler0); + } else { + irq_set_exclusive_handler(DMA_IRQ_1, dma_irq_handler1); + } + + irq_set_enabled(irq, true); } void check_init(dma_DMA_obj_t *self) { @@ -155,7 +176,8 @@ void dma_start_request(dma_DMA_obj_t *self, uint32_t transfer_count, uint32_t dreq, uint32_t data_size, - mp_obj_t handler) { + mp_obj_t handler, + uint32_t irq) { if (dreq != 0) { channel_config_set_dreq(config, dreq); } @@ -164,9 +186,10 @@ void dma_start_request(dma_DMA_obj_t *self, // IRQ stuff if (mp_obj_is_callable(handler)) { - dma_irq_init(self, handler); + dma_irq_init(self, handler, irq); } else { dma_channel_set_irq0_enabled(self->dma_channel, false); + dma_channel_set_irq1_enabled(self->dma_channel, false); } // configure a one shot DMA request. @@ -243,7 +266,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_isclaimed_obj, dma_DMA_isclaimed); * *******************************************************************************/ STATIC mp_obj_t dma_DMA_write_from(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_from_buffer, ARG_to_address, ARG_dreq, ARG_transfer_count, ARG_data_size, ARG_handler}; + enum { ARG_from_buffer, ARG_to_address, ARG_dreq, ARG_transfer_count, ARG_data_size, ARG_handler, ARG_irq}; static const mp_arg_t allowed_args[] = { { MP_QSTR_from_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_to_address, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, @@ -251,6 +274,8 @@ STATIC mp_obj_t dma_DMA_write_from(size_t n_args, const mp_obj_t *pos_args, mp_m { MP_QSTR_transfer_count, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_data_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DMA_SIZE_8} }, { MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_irq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DMA_IRQ_0} }, + }; DBG_PRINTF("write_from\n"); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -266,6 +291,7 @@ STATIC mp_obj_t dma_DMA_write_from(size_t n_args, const mp_obj_t *pos_args, mp_m uint32_t transfer_count = args[ARG_transfer_count].u_int; uint32_t data_size = args[ARG_data_size].u_int; mp_obj_t handler = args[ARG_handler].u_obj; + uint32_t irq = args[ARG_irq].u_int; mp_buffer_info_t bufinfo; bufinfo.buf = NULL; @@ -283,7 +309,7 @@ STATIC mp_obj_t dma_DMA_write_from(size_t n_args, const mp_obj_t *pos_args, mp_m channel_config_set_read_increment(&config, true); channel_config_set_write_increment(&config, false); - dma_start_request(self, &config, to_address_ptr, bufinfo.buf, transfer_count, dreq, data_size, handler); + dma_start_request(self, &config, to_address_ptr, bufinfo.buf, transfer_count, dreq, data_size, handler, irq); return mp_obj_new_int(bufinfo.len); @@ -304,7 +330,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dma_DMA_write_from_obj, 1, dma_DMA_write_from) * *******************************************************************************/ STATIC mp_obj_t dma_DMA_read_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_from_address, ARG_to_buffer, ARG_transfer_count, ARG_data_size, ARG_dreq, ARG_handler}; + enum { ARG_from_address, ARG_to_buffer, ARG_transfer_count, ARG_data_size, ARG_dreq, ARG_handler, ARG_irq}; static const mp_arg_t allowed_args[] = { { MP_QSTR_from_address, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_to_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, @@ -312,6 +338,7 @@ STATIC mp_obj_t dma_DMA_read_into(size_t n_args, const mp_obj_t *pos_args, mp_ma { MP_QSTR_data_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DMA_SIZE_8} }, { MP_QSTR_dreq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_irq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DMA_IRQ_0} }, }; DBG_PRINTF("read_into\n"); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -327,6 +354,8 @@ STATIC mp_obj_t dma_DMA_read_into(size_t n_args, const mp_obj_t *pos_args, mp_ma uint32_t transfer_count = args[ARG_transfer_count].u_int; uint32_t data_size = args[ARG_data_size].u_int; mp_obj_t handler = args[ARG_handler].u_obj; + uint32_t irq = args[ARG_irq].u_int; + mp_buffer_info_t bufinfo; bufinfo.buf = NULL; @@ -343,7 +372,7 @@ STATIC mp_obj_t dma_DMA_read_into(size_t n_args, const mp_obj_t *pos_args, mp_ma channel_config_set_read_increment(&config, false); channel_config_set_write_increment(&config, true); - dma_start_request(self, &config, bufinfo.buf, from_address_ptr, transfer_count, dreq, data_size, handler); + dma_start_request(self, &config, bufinfo.buf, from_address_ptr, transfer_count, dreq, data_size, handler, irq); return mp_const_none; } @@ -359,17 +388,19 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dma_DMA_read_into_obj, 1, dma_DMA_read_into); * *******************************************************************************/ STATIC mp_obj_t dma_DMA_copy(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_from_buffer, ARG_to_buffer, ARG_handler}; + enum { ARG_from_buffer, ARG_to_buffer, ARG_handler, ARG_irq}; static const mp_arg_t allowed_args[] = { { MP_QSTR_from_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_to_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_irq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DMA_IRQ_0} }, }; DBG_PRINTF("copy\n"); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); dma_DMA_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + uint32_t irq = args[ARG_irq].u_int; check_init(self); check_busy(self); @@ -394,7 +425,7 @@ STATIC mp_obj_t dma_DMA_copy(size_t n_args, const mp_obj_t *pos_args, mp_map_t * channel_config_set_read_increment(&config, true); channel_config_set_write_increment(&config, true); - dma_start_request(self, &config, to_buffer.buf, from_buffer.buf, from_buffer.len, 0x3f, DMA_SIZE_8, handler); + dma_start_request(self, &config, to_buffer.buf, from_buffer.buf, from_buffer.len, 0x3f, DMA_SIZE_8, handler, irq); return mp_const_none; } @@ -455,6 +486,8 @@ STATIC const mp_rom_map_elem_t dma_DMA_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_DMA_SIZE_8), MP_ROM_INT(DMA_SIZE_8) }, { MP_ROM_QSTR(MP_QSTR_DMA_SIZE_16), MP_ROM_INT(DMA_SIZE_16) }, { MP_ROM_QSTR(MP_QSTR_DMA_SIZE_32), MP_ROM_INT(DMA_SIZE_32) }, + { MP_ROM_QSTR(MP_QSTR_DMA_IRQ_0), MP_ROM_INT(DMA_IRQ_0) }, + { MP_ROM_QSTR(MP_QSTR_DMA_IRQ_1), MP_ROM_INT(DMA_IRQ_1) }, }; STATIC MP_DEFINE_CONST_DICT(dma_DMA_locals_dict, dma_DMA_locals_dict_table); From 870d8fa2174389d60fe7f5bb6af4799597fbd113 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Fri, 10 Feb 2023 12:11:41 +0000 Subject: [PATCH 11/11] rp2/dma.c: Check for valid IRQ. Signed-off-by: Mark Burton --- ports/rp2/dma.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ports/rp2/dma.c b/ports/rp2/dma.c index 9709739469343..5622c8b0a41ed 100644 --- a/ports/rp2/dma.c +++ b/ports/rp2/dma.c @@ -149,6 +149,12 @@ void check_busy(dma_DMA_obj_t *self) { } } +void check_irq(uint32_t irq) { + if (irq != DMA_IRQ_0 && irq != DMA_IRQ_1) { + mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("DMA invalid IRQ %d"), irq); + } +} + uint32_t dma_get_error_status(uint channel) { dma_channel_hw_t *dma = dma_channel_hw_addr(channel); return (dma->ctrl_trig >> 29) & 7; @@ -263,6 +269,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(dma_DMA_isclaimed_obj, dma_DMA_isclaimed); * to_address - address to send data * dreq - optional throttle transfer. Default is to go as fast as possible * handler - optional IRQ handler + * irq - optional irq channel. Either DMA_IRQ_0 or DMA_IRQ_1 * *******************************************************************************/ STATIC mp_obj_t dma_DMA_write_from(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -293,6 +300,8 @@ STATIC mp_obj_t dma_DMA_write_from(size_t n_args, const mp_obj_t *pos_args, mp_m mp_obj_t handler = args[ARG_handler].u_obj; uint32_t irq = args[ARG_irq].u_int; + check_irq(irq); + mp_buffer_info_t bufinfo; bufinfo.buf = NULL; mp_get_buffer_raise(args[ARG_from_buffer].u_obj, &bufinfo, MP_BUFFER_READ); @@ -327,6 +336,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dma_DMA_write_from_obj, 1, dma_DMA_write_from) * to_buffer - bytearray * dreq - optional throttle transfer. Default is to go as fast as possible * handler - optional IRQ handler + * irq - optional irq channel. Either DMA_IRQ_0 or DMA_IRQ_1 * *******************************************************************************/ STATIC mp_obj_t dma_DMA_read_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -356,6 +366,7 @@ STATIC mp_obj_t dma_DMA_read_into(size_t n_args, const mp_obj_t *pos_args, mp_ma mp_obj_t handler = args[ARG_handler].u_obj; uint32_t irq = args[ARG_irq].u_int; + check_irq(irq); mp_buffer_info_t bufinfo; bufinfo.buf = NULL; @@ -385,6 +396,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dma_DMA_read_into_obj, 1, dma_DMA_read_into); * from_buffer - source bytearray * to_buffer - bytearray * handler - optional IRQ handler + * irq - optional irq channel. Either DMA_IRQ_0 or DMA_IRQ_1 * *******************************************************************************/ STATIC mp_obj_t dma_DMA_copy(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -404,6 +416,7 @@ STATIC mp_obj_t dma_DMA_copy(size_t n_args, const mp_obj_t *pos_args, mp_map_t * check_init(self); check_busy(self); + check_irq(irq); mp_buffer_info_t from_buffer; from_buffer.buf = NULL;