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; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy