diff --git a/extmod/machine_spi.c b/extmod/machine_spi.c index 04506370f..88dc79832 100644 --- a/extmod/machine_spi.c +++ b/extmod/machine_spi.c @@ -76,6 +76,17 @@ static mp_obj_t mp_machine_spi_wait_done(size_t n_args, const mp_obj_t *args) } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_wait_done_obj, 1, 2, mp_machine_spi_wait_done); +static mp_obj_t mp_machine_spi_set_tx_irq(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args){ + mp_obj_base_t *s = (mp_obj_base_t *)MP_OBJ_TO_PTR(args[0]); + mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t *)MP_OBJ_TYPE_GET_SLOT(s->type, protocol); + if (spi_p->set_tx_isr != NULL) + { + spi_p->set_tx_isr(s, n_args - 1, args + 1, kw_args); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_KW(machine_spi_set_tx_irq_obj, 1, mp_machine_spi_set_tx_irq); + static mp_obj_t mp_machine_spi_read(size_t n_args, const mp_obj_t *args) { vstr_t vstr; @@ -128,6 +139,7 @@ static const mp_rom_map_elem_t machine_spi_locals_dict_table[] = { {MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj)}, {MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj)}, {MP_ROM_QSTR(MP_QSTR_wait_done), MP_ROM_PTR(&mp_machine_spi_wait_done_obj)}, + {MP_ROM_QSTR(MP_QSTR_set_tx_irq), MP_ROM_PTR(&machine_spi_set_tx_irq_obj)}, {MP_ROM_QSTR(MP_QSTR_MSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_MSB)}, {MP_ROM_QSTR(MP_QSTR_LSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_LSB)}, diff --git a/extmod/modmachine.h b/extmod/modmachine.h index f1f455b41..4e8177b00 100644 --- a/extmod/modmachine.h +++ b/extmod/modmachine.h @@ -194,6 +194,7 @@ typedef struct _mp_machine_spi_p_t void (*deinit)(mp_obj_base_t *obj); // can be NULL void (*transfer)(mp_obj_base_t *obj, size_t len, const uint8_t *src, uint8_t *dest); void (*wait_done)(mp_obj_base_t *obj); // can be NULL + void (*set_tx_isr)(mp_obj_base_t *obj, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); // can be NULL } mp_machine_spi_p_t; // SoftSPI object. diff --git a/make_and_flash_rp2.sh b/make_and_flash_rp2.sh index 8bff03697..85c2141fa 100755 --- a/make_and_flash_rp2.sh +++ b/make_and_flash_rp2.sh @@ -1,4 +1,7 @@ -make -j -C ports/rp2 BOARD=RPI_PICO USER_C_MODULES=../../user_modules/lv_binding_micropython/bindings.cmake + +rm -rf ./ports/rp2/build-RPI_PICO/* + +make -j -C ports/rp2 BOARD=RPI_PICO USER_C_MODULES=../../user_modules/user.cmake exit status=$? # 检查编译是否成功 if [ $? -eq 0 ]; then diff --git a/ports/rp2/machine_spi.c b/ports/rp2/machine_spi.c index 3f35cd1a7..7b623fecf 100644 --- a/ports/rp2/machine_spi.c +++ b/ports/rp2/machine_spi.c @@ -27,6 +27,7 @@ #include "py/runtime.h" #include "py/mphal.h" #include "py/mperrno.h" +#include "shared/runtime/mpirq.h" #include "extmod/modmachine.h" #include "hardware/spi.h" @@ -104,6 +105,8 @@ typedef struct _machine_spi_obj_t uint32_t baudrate; int chan_tx; int chan_rx; + // 这里只为屏幕设置了tx中断,用来控制cs引脚和lv.disp_flush_ready() + mp_irq_obj_t *tx_isr_obj; } machine_spi_obj_t; static machine_spi_obj_t machine_spi_obj[] = { @@ -122,6 +125,7 @@ static machine_spi_obj_t machine_spi_obj[] = { // DMA channels, -1 means not claimed -1, -1, + NULL }, { {&machine_spi_type}, @@ -138,6 +142,7 @@ static machine_spi_obj_t machine_spi_obj[] = { // DMA channels, -1 means not claimed -1, -1, + NULL }, }; @@ -314,6 +319,87 @@ static void machine_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj } } +static void machine_spi0_tx_irq_handler(void) +{ + // currently only used for spi0 + machine_spi_obj_t *self = &machine_spi_obj[0]; + spi_hw_t *spi_hw = spi_get_hw(self->spi_inst); + // clear the interrupt flag + spi_hw->imsc &= ~(1 << 3); + // 检查是否是发送FIFO中断(已屏蔽的中断) + // if (spi_hw->mis & (1 << 3)) { // TXMIS=1 + // 确认发送真正完成:发送FIFO为空且SPI不忙 + // mp_raise_msg_varg(&mp_type_AssertionError, MP_ERROR_TEXT("IRQ triggered")); + if ((spi_hw->sr & (1 << 0)) && !(spi_hw->sr & (1 << 4)) && dma_channel_is_busy(self->chan_tx) == false) { + if (self->tx_isr_obj != NULL && self->tx_isr_obj->handler != mp_const_none) + { + mp_irq_handler(self->tx_isr_obj); + } + } + // } +} + + +static void machine_spi1_tx_irq_handler(void) +{ + // currently not used + machine_spi_obj_t *self = &machine_spi_obj[1]; + spi_hw_t *spi_hw = spi_get_hw(self->spi_inst); + // clear the interrupt flag + spi_hw->imsc &= ~(1 << 3); + if (spi_hw->mis & (1 << 3)) { // TXMIS=1 + // 确认发送真正完成:发送FIFO为空且SPI不忙 + if ((spi_hw->sr & (1 << 0)) && !(spi_hw->sr & (1 << 4))) { + if (self->tx_isr_obj != NULL && self->tx_isr_obj->handler != mp_const_none) + { + mp_irq_handler(self->tx_isr_obj); + } + } + } +} + + +static void machine_spi_set_tx_isr(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) +{ + machine_spi_obj_t *self = (machine_spi_obj_t *)self_in; + if (self->tx_isr_obj == NULL) { + self->tx_isr_obj = m_new_obj(mp_irq_obj_t); + // MP_STATE_PORT(rp2_uart_irq_obj)[self->uart_id] = self->mp_irq_obj; + } + enum + { + ARG_tx_isr, + }; + static const mp_arg_t allowed_args[] = { + {MP_QSTR_tx_isr, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none}}, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (n_args < 1) { + mp_raise_ValueError(MP_ERROR_TEXT("missing tx_isr")); + } + mp_obj_t handler = args[ARG_tx_isr].u_obj; + if (handler == mp_const_none || !mp_obj_is_callable(handler)) { + mp_raise_ValueError(MP_ERROR_TEXT("handler must be callable")); + } + if (self->tx_isr_obj == NULL) { + // disable previous irq + } + irq_set_enabled(self->spi_id == 0 ? SPI0_IRQ : SPI1_IRQ, false); + self->tx_isr_obj->handler = handler; + // self->tx_isr_obj->base.type = &mp_type_irq; + // self->tx_isr_obj->methods = &mp_irq_methods; + self->tx_isr_obj->ishard = true; + self->tx_isr_obj->parent = MP_OBJ_FROM_PTR(self); + + irq_set_exclusive_handler(self->spi_id == 0 ? SPI0_IRQ : SPI1_IRQ, self->spi_id == 0 ? machine_spi0_tx_irq_handler : machine_spi1_tx_irq_handler); + spi_hw_t *spi_hw = spi_get_hw(self->spi_inst); + spi_hw->imsc |= (1 << 3); + irq_set_enabled(self->spi_id == 0 ? SPI0_IRQ : SPI1_IRQ, true); + +} + static void machine_spi_wait_done(mp_obj_base_t *self_in) { machine_spi_obj_t *self = (machine_spi_obj_t *)self_in; @@ -332,6 +418,17 @@ static void machine_spi_wait_done(mp_obj_base_t *self_in) static void machine_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { machine_spi_obj_t *self = (machine_spi_obj_t *)self_in; + bool write_only = dest == NULL; + const size_t dma_min_size_threshold = 8; + if (len <= dma_min_size_threshold){ + // Use software for small transfers + if (write_only) { + spi_write_blocking(self->spi_inst, src, len); + } else { + spi_write_read_blocking(self->spi_inst, src, dest, len); + } + return; + } // Use DMA for large transfers if channels are available int chan_tx = self->chan_tx; int chan_rx = self->chan_rx; @@ -340,13 +437,13 @@ static void machine_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8 mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("Error when using DMA, chan rx: %d, chan tx: %d"), chan_rx, chan_tx); return; } - if (chan_rx >= 0) - dma_channel_wait_for_finish_blocking(chan_rx); - if (chan_tx >= 0) - dma_channel_wait_for_finish_blocking(chan_tx); + // if (chan_rx >= 0) + // dma_channel_wait_for_finish_blocking(chan_rx); + // if (chan_tx >= 0) + // dma_channel_wait_for_finish_blocking(chan_tx); + machine_spi_wait_done(self_in); // bool use_dma = chan_rx >= 0 && chan_tx >= 0; // note src is guaranteed to be non-NULL - bool write_only = dest == NULL; uint8_t dev_null; dma_channel_config c; @@ -413,8 +510,11 @@ static const mp_machine_spi_p_t machine_spi_p = { .init = machine_spi_init, .transfer = machine_spi_transfer, .wait_done = machine_spi_wait_done, + .set_tx_isr = machine_spi_set_tx_isr, }; + + MP_DEFINE_CONST_OBJ_TYPE( machine_spi_type, MP_QSTR_SPI,