lv_micropython/ports/rp2/machine_spi.c
feng-arch a7373d23f4
Some checks failed
JavaScript code lint and formatting with Biome / eslint (push) Has been cancelled
Check code formatting / code-formatting (push) Has been cancelled
Check code size / build (push) Has been cancelled
Check spelling with codespell / codespell (push) Has been cancelled
Check commit message formatting / build (push) Has been cancelled
JavaScript code lint and formatting with Biome / eslint (pull_request) Has been cancelled
Build docs / build (push) Has been cancelled
Check code formatting / code-formatting (pull_request) Has been cancelled
Check code size / build (pull_request) Has been cancelled
Check examples / embedding (push) Has been cancelled
Check spelling with codespell / codespell (pull_request) Has been cancelled
Check commit message formatting / build (pull_request) Has been cancelled
Package mpremote / build (push) Has been cancelled
Build ports metadata / build (pull_request) Has been cancelled
cc3200 port / build (pull_request) Has been cancelled
.mpy file format and tools / test (push) Has been cancelled
esp32 port / build_idf (esp32_build_cmod_spiram_s2) (pull_request) Has been cancelled
esp32 port / build_idf (esp32_build_s3_c3) (pull_request) Has been cancelled
Build ports metadata / build (push) Has been cancelled
esp8266 port / build (pull_request) Has been cancelled
mimxrt port / build (pull_request) Has been cancelled
cc3200 port / build (push) Has been cancelled
nrf port / build (pull_request) Has been cancelled
powerpc port / build (pull_request) Has been cancelled
qemu port / build_and_test_arm (pull_request) Has been cancelled
qemu port / build_and_test_rv32 (pull_request) Has been cancelled
esp32 port / build_idf (esp32_build_cmod_spiram_s2) (push) Has been cancelled
esp32 port / build_idf (esp32_build_s3_c3) (push) Has been cancelled
renesas-ra port / build_renesas_ra_board (pull_request) Has been cancelled
rp2 port / build (pull_request) Has been cancelled
samd port / build (pull_request) Has been cancelled
esp8266 port / build (push) Has been cancelled
stm32 port / build_stm32 (stm32_misc_build) (pull_request) Has been cancelled
stm32 port / build_stm32 (stm32_nucleo_build) (pull_request) Has been cancelled
stm32 port / build_stm32 (stm32_pyb_build) (pull_request) Has been cancelled
mimxrt port / build (push) Has been cancelled
unix port / minimal (pull_request) Has been cancelled
unix port / reproducible (pull_request) Has been cancelled
unix port / standard (pull_request) Has been cancelled
unix port / standard_v2 (pull_request) Has been cancelled
unix port / coverage (pull_request) Has been cancelled
unix port / coverage_32bit (pull_request) Has been cancelled
unix port / nanbox (pull_request) Has been cancelled
unix port / float (pull_request) Has been cancelled
unix port / stackless_clang (pull_request) Has been cancelled
unix port / float_clang (pull_request) Has been cancelled
unix port / settrace (pull_request) Has been cancelled
unix port / settrace_stackless (pull_request) Has been cancelled
unix port / macos (pull_request) Has been cancelled
unix port / qemu_mips (pull_request) Has been cancelled
unix port / qemu_arm (pull_request) Has been cancelled
unix port / qemu_riscv64 (pull_request) Has been cancelled
nrf port / build (push) Has been cancelled
powerpc port / build (push) Has been cancelled
qemu port / build_and_test_arm (push) Has been cancelled
qemu port / build_and_test_rv32 (push) Has been cancelled
renesas-ra port / build_renesas_ra_board (push) Has been cancelled
rp2 port / build (push) Has been cancelled
samd port / build (push) Has been cancelled
webassembly port / build (pull_request) Has been cancelled
windows port / build-vs (Debug, x64, windows-2022, dev, 2022, [17, 18)) (pull_request) Has been cancelled
windows port / build-vs (Debug, x64, windows-latest, dev, 2017, [15, 16)) (pull_request) Has been cancelled
windows port / build-vs (Debug, x86, windows-2022, dev, 2022, [17, 18)) (pull_request) Has been cancelled
windows port / build-vs (Debug, x86, windows-latest, dev, 2017, [15, 16)) (pull_request) Has been cancelled
windows port / build-vs (Release, x64, windows-2019, dev, 2019, [16, 17)) (pull_request) Has been cancelled
windows port / build-vs (Release, x64, windows-2019, standard, 2019, [16, 17)) (pull_request) Has been cancelled
windows port / build-vs (Release, x64, windows-2022, dev, 2022, [17, 18)) (pull_request) Has been cancelled
windows port / build-vs (Release, x64, windows-2022, standard, 2022, [17, 18)) (pull_request) Has been cancelled
windows port / build-vs (Release, x64, windows-latest, dev, 2017, [15, 16)) (pull_request) Has been cancelled
windows port / build-vs (Release, x64, windows-latest, standard, 2017, [15, 16)) (pull_request) Has been cancelled
windows port / build-vs (Release, x86, windows-2019, dev, 2019, [16, 17)) (pull_request) Has been cancelled
windows port / build-vs (Release, x86, windows-2019, standard, 2019, [16, 17)) (pull_request) Has been cancelled
windows port / build-vs (Release, x86, windows-2022, dev, 2022, [17, 18)) (pull_request) Has been cancelled
windows port / build-vs (Release, x86, windows-2022, standard, 2022, [17, 18)) (pull_request) Has been cancelled
windows port / build-vs (Release, x86, windows-latest, dev, 2017, [15, 16)) (pull_request) Has been cancelled
windows port / build-vs (Release, x86, windows-latest, standard, 2017, [15, 16)) (pull_request) Has been cancelled
windows port / build-mingw (i686, mingw32, dev) (pull_request) Has been cancelled
windows port / build-mingw (i686, mingw32, standard) (pull_request) Has been cancelled
windows port / build-mingw (x86_64, mingw64, dev) (pull_request) Has been cancelled
windows port / build-mingw (x86_64, mingw64, standard) (pull_request) Has been cancelled
windows port / cross-build-on-linux (pull_request) Has been cancelled
stm32 port / build_stm32 (stm32_misc_build) (push) Has been cancelled
stm32 port / build_stm32 (stm32_nucleo_build) (push) Has been cancelled
stm32 port / build_stm32 (stm32_pyb_build) (push) Has been cancelled
zephyr port / build (pull_request) Has been cancelled
rp2 port / build (PICO) (pull_request) Has been cancelled
Python code lint and formatting with ruff / ruff (pull_request) Has been cancelled
stm32 port / build (STM32F7DISC) (pull_request) Has been cancelled
unix port / build (pull_request) Has been cancelled
unix port / minimal (push) Has been cancelled
unix port / reproducible (push) Has been cancelled
unix port / standard (push) Has been cancelled
unix port / standard_v2 (push) Has been cancelled
unix port / coverage (push) Has been cancelled
unix port / coverage_32bit (push) Has been cancelled
unix port / nanbox (push) Has been cancelled
unix port / float (push) Has been cancelled
unix port / stackless_clang (push) Has been cancelled
unix port / float_clang (push) Has been cancelled
unix port / settrace (push) Has been cancelled
unix port / settrace_stackless (push) Has been cancelled
unix port / macos (push) Has been cancelled
unix port / qemu_mips (push) Has been cancelled
unix port / qemu_arm (push) Has been cancelled
unix port / qemu_riscv64 (push) Has been cancelled
webassembly port / build (push) Has been cancelled
windows port / build-vs (Debug, x64, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Debug, x64, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Debug, x86, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Debug, x86, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2019, dev, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2019, standard, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2022, standard, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-latest, standard, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2019, dev, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2019, standard, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2022, standard, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-latest, standard, 2017, [15, 16)) (push) Has been cancelled
windows port / build-mingw (i686, mingw32, dev) (push) Has been cancelled
windows port / build-mingw (i686, mingw32, standard) (push) Has been cancelled
windows port / build-mingw (x86_64, mingw64, dev) (push) Has been cancelled
windows port / build-mingw (x86_64, mingw64, standard) (push) Has been cancelled
windows port / cross-build-on-linux (push) Has been cancelled
zephyr port / build (push) Has been cancelled
rp2 port / build (PICO) (push) Has been cancelled
Python code lint and formatting with ruff / ruff (push) Has been cancelled
stm32 port / build (STM32F7DISC) (push) Has been cancelled
unix port / build (push) Has been cancelled
feat: add support for eigenmath
2025-10-13 16:04:13 +08:00

499 lines
18 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020-2021 Damien P. George
*
* 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 "py/runtime.h"
#include "py/gc.h"
#include "py/mphal.h"
#include "py/mperrno.h"
#include "shared/runtime/mpirq.h"
#include "extmod/modmachine.h"
#include "hardware/spi.h"
#include "hardware/dma.h"
#define DEFAULT_SPI_BAUDRATE (1000000)
#define DEFAULT_SPI_POLARITY (0)
#define DEFAULT_SPI_PHASE (0)
#define DEFAULT_SPI_BITS (8)
#define DEFAULT_SPI_FIRSTBIT (SPI_MSB_FIRST)
#ifdef MICROPY_HW_SPI_NO_DEFAULT_PINS
// With no default SPI, need to require the pin args.
#define MICROPY_HW_SPI0_SCK (0)
#define MICROPY_HW_SPI0_MOSI (0)
#define MICROPY_HW_SPI0_MISO (0)
#define MICROPY_HW_SPI1_SCK (0)
#define MICROPY_HW_SPI1_MOSI (0)
#define MICROPY_HW_SPI1_MISO (0)
#define MICROPY_SPI_PINS_ARG_OPTS MP_ARG_REQUIRED
#else
// Most boards do not require pin args.
#define MICROPY_SPI_PINS_ARG_OPTS 0
#ifndef MICROPY_HW_SPI0_SCK
#if PICO_DEFAULT_SPI == 0
#define MICROPY_HW_SPI0_SCK (PICO_DEFAULT_SPI_SCK_PIN)
#define MICROPY_HW_SPI0_MOSI (PICO_DEFAULT_SPI_TX_PIN)
#define MICROPY_HW_SPI0_MISO (PICO_DEFAULT_SPI_RX_PIN)
#else
#define MICROPY_HW_SPI0_SCK (6)
#define MICROPY_HW_SPI0_MOSI (7)
#define MICROPY_HW_SPI0_MISO (4)
#endif
#endif
#ifndef MICROPY_HW_SPI1_SCK
#if PICO_DEFAULT_SPI == 1
#define MICROPY_HW_SPI1_SCK (PICO_DEFAULT_SPI_SCK_PIN)
#define MICROPY_HW_SPI1_MOSI (PICO_DEFAULT_SPI_TX_PIN)
#define MICROPY_HW_SPI1_MISO (PICO_DEFAULT_SPI_RX_PIN)
#else
#define MICROPY_HW_SPI1_SCK (10)
#define MICROPY_HW_SPI1_MOSI (11)
#define MICROPY_HW_SPI1_MISO (8)
#endif
#endif
#endif
// SPI0 can be GP{0..7,16..23}, SPI1 can be GP{8..15,24..29}.
#define IS_VALID_PERIPH(spi, pin) ((((pin) & 8) >> 3) == (spi))
// GP{2,6,10,14,...}
#define IS_VALID_SCK(spi, pin) (((pin) & 3) == 2 && IS_VALID_PERIPH(spi, pin))
// GP{3,7,11,15,...}
#define IS_VALID_MOSI(spi, pin) (((pin) & 3) == 3 && IS_VALID_PERIPH(spi, pin))
// GP{0,4,8,10,...}
#define IS_VALID_MISO(spi, pin) (((pin) & 3) == 0 && IS_VALID_PERIPH(spi, pin))
typedef struct _machine_spi_obj_t {
mp_obj_base_t base;
spi_inst_t *const spi_inst;
uint8_t spi_id;
uint8_t polarity;
uint8_t phase;
uint8_t bits;
uint8_t firstbit;
uint8_t sck;
uint8_t mosi;
uint8_t miso;
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[] = {
{
{&machine_spi_type}, spi0, 0,
DEFAULT_SPI_POLARITY, DEFAULT_SPI_PHASE, DEFAULT_SPI_BITS, DEFAULT_SPI_FIRSTBIT,
MICROPY_HW_SPI0_SCK, MICROPY_HW_SPI0_MOSI, MICROPY_HW_SPI0_MISO,
0,
// DMA channels, -1 means not claimed
-1,
-1,
NULL
},
{
{&machine_spi_type}, spi1, 1,
DEFAULT_SPI_POLARITY, DEFAULT_SPI_PHASE, DEFAULT_SPI_BITS, DEFAULT_SPI_FIRSTBIT,
MICROPY_HW_SPI1_SCK, MICROPY_HW_SPI1_MOSI, MICROPY_HW_SPI1_MISO,
0,
// DMA channels, -1 means not claimed
-1,
-1,
NULL
},
};
static void machine_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "SPI(%u, baudrate=%u, polarity=%u, phase=%u, bits=%u, sck=%u, mosi=%u, miso=%u)",
self->spi_id, self->baudrate, self->polarity, self->phase, self->bits,
self->sck, self->mosi, self->miso);
}
mp_obj_t machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = DEFAULT_SPI_BAUDRATE} },
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_POLARITY} },
{ MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_PHASE} },
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_BITS} },
{ MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_FIRSTBIT} },
{ MP_QSTR_sck, MICROPY_SPI_PINS_ARG_OPTS | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_mosi, MICROPY_SPI_PINS_ARG_OPTS | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_miso, MICROPY_SPI_PINS_ARG_OPTS | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
};
// Parse the arguments.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
// Get the SPI bus id.
int spi_id = mp_obj_get_int(args[ARG_id].u_obj);
if (spi_id < 0 || spi_id >= MP_ARRAY_SIZE(machine_spi_obj)) {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), spi_id);
}
// Get static peripheral object.
machine_spi_obj_t *self = (machine_spi_obj_t *)&machine_spi_obj[spi_id];
// Set SCK/MOSI/MISO pins if configured.
if (args[ARG_sck].u_obj != mp_const_none) {
int sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
if (!IS_VALID_SCK(self->spi_id, sck)) {
mp_raise_ValueError(MP_ERROR_TEXT("bad SCK pin"));
}
self->sck = sck;
}
if (args[ARG_mosi].u_obj != mp_const_none) {
int mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);
if (!IS_VALID_MOSI(self->spi_id, mosi)) {
mp_raise_ValueError(MP_ERROR_TEXT("bad MOSI pin"));
}
self->mosi = mosi;
if (self->chan_tx < 0)
self->chan_tx = dma_claim_unused_channel(true);
}
if (args[ARG_miso].u_obj != mp_const_none) {
int miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
if (!IS_VALID_MISO(self->spi_id, miso)) {
mp_raise_ValueError(MP_ERROR_TEXT("bad MISO pin"));
}
self->miso = miso;
if (self->chan_rx < 0)
self->chan_rx = dma_claim_unused_channel(true);
}
// Initialise the SPI peripheral if any arguments given, or it was not initialised previously.
if (n_args > 1 || n_kw > 0 || self->baudrate == 0) {
self->baudrate = args[ARG_baudrate].u_int;
self->polarity = args[ARG_polarity].u_int;
self->phase = args[ARG_phase].u_int;
self->bits = args[ARG_bits].u_int;
self->firstbit = args[ARG_firstbit].u_int;
if (self->firstbit == SPI_LSB_FIRST) {
mp_raise_NotImplementedError(MP_ERROR_TEXT("LSB"));
}
spi_init(self->spi_inst, self->baudrate);
self->baudrate = spi_set_baudrate(self->spi_inst, self->baudrate);
spi_set_format(self->spi_inst, self->bits, self->polarity, self->phase, self->firstbit);
gpio_set_function(self->sck, GPIO_FUNC_SPI);
gpio_set_function(self->miso, GPIO_FUNC_SPI);
gpio_set_function(self->mosi, GPIO_FUNC_SPI);
}
return MP_OBJ_FROM_PTR(self);
}
static void machine_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
};
// Parse the arguments.
machine_spi_obj_t *self = (machine_spi_obj_t *)self_in;
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);
// Reconfigure the baudrate if requested.
if (args[ARG_baudrate].u_int != -1) {
self->baudrate = spi_set_baudrate(self->spi_inst, args[ARG_baudrate].u_int);
}
// Reconfigure the format if requested.
bool set_format = false;
if (args[ARG_polarity].u_int != -1) {
self->polarity = args[ARG_polarity].u_int;
set_format = true;
}
if (args[ARG_phase].u_int != -1) {
self->phase = args[ARG_phase].u_int;
set_format = true;
}
if (args[ARG_bits].u_int != -1) {
self->bits = args[ARG_bits].u_int;
set_format = true;
}
if (args[ARG_firstbit].u_int != -1) {
self->firstbit = args[ARG_firstbit].u_int;
if (self->firstbit == SPI_LSB_FIRST)
{
mp_raise_NotImplementedError(MP_ERROR_TEXT("LSB"));
}
}
if (self->miso > 0 && self->chan_rx < 0) {
self->chan_rx = dma_claim_unused_channel(true);
}
if (self->mosi > 0 && self->chan_tx < 0) {
self->chan_tx = dma_claim_unused_channel(true);
}
if (set_format) {
spi_set_format(self->spi_inst, self->bits, self->polarity, self->phase, self->firstbit);
}
}
static void machine_spi0_tx_irq_handler(void)
{
// currently only used for spi0
// mp_printf(&mp_plat_print, "program running isr spi0 tx irq %d\n", __LINE__);
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_printf(&mp_plat_print, "program running isr spi0 tx irq %d\n", __LINE__);
if(self->tx_isr_obj->ishard){
// mp_sched_lock();
// gc_lock();
mp_call_function_1(self->tx_isr_obj->handler, self->tx_isr_obj->parent);
// gc_unlock();
// mp_sched_unlock();
} else {
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,
ARG_hard
};
static const mp_arg_t allowed_args[] = {
{MP_QSTR_tx_isr, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none}},
{ MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
};
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 = args[ARG_hard].u_bool;
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;
int chan_tx = self->chan_tx;
int chan_rx = self->chan_rx;
if (chan_rx >= 0)
dma_channel_wait_for_finish_blocking(chan_rx);
if (chan_tx >= 0)
dma_channel_wait_for_finish_blocking(chan_tx);
spi_hw_t *spi_hw = spi_get_hw(self->spi_inst);
while (!((spi_hw->sr & (1 << 0)) && !(spi_hw->sr & (1 << 4)))) {
// wait for TX FIFO to be empty and SPI not busy
}
}
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;
if (chan_rx < 0 && chan_tx < 0)
{
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);
machine_spi_wait_done(self_in);
// bool use_dma = chan_rx >= 0 && chan_tx >= 0;
// note src is guaranteed to be non-NULL
uint8_t dev_null;
dma_channel_config c;
if (chan_tx >= 0)
{
c = dma_channel_get_default_config(chan_tx);
channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
channel_config_set_dreq(&c, spi_get_index(self->spi_inst) ? DREQ_SPI1_TX : DREQ_SPI0_TX);
dma_channel_configure(chan_tx, &c,
&spi_get_hw(self->spi_inst)->dr,
src,
len,
true);
}
if (chan_rx >= 0)
{
c = dma_channel_get_default_config(chan_rx);
channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
channel_config_set_dreq(&c, spi_get_index(self->spi_inst) ? DREQ_SPI1_RX : DREQ_SPI0_RX);
channel_config_set_read_increment(&c, false);
channel_config_set_write_increment(&c, !write_only);
dma_channel_configure(chan_rx, &c,
write_only ? &dev_null : dest,
&spi_get_hw(self->spi_inst)->dr,
len,
true);
}
// dma_channel_wait_for_finish_blocking(chan_rx);
// dma_channel_wait_for_finish_blocking(chan_tx);
// If we have claimed only one channel successfully, we should release immediately
// if (chan_rx >= 0) {
// dma_channel_unclaim(chan_rx);
// }
// if (chan_tx >= 0) {
// dma_channel_unclaim(chan_tx);
// }
// if (!use_dma) {
// // Use software for small transfers, or if couldn't claim two DMA channels
// if (write_only) {
// spi_write_blocking(self->spi_inst, src, len);
// } else {
// spi_write_read_blocking(self->spi_inst, src, dest, len);
// }
// }
}
// Buffer protocol implementation for SPI.
// The buffer represents the SPI data FIFO.
static mp_int_t machine_spi_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
machine_spi_obj_t *self = MP_OBJ_TO_PTR(o_in);
bufinfo->len = 4;
bufinfo->typecode = 'I';
bufinfo->buf = (void *)&spi_get_hw(self->spi_inst)->dr;
return 0;
}
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,
MP_TYPE_FLAG_NONE,
make_new, machine_spi_make_new,
print, machine_spi_print,
protocol, &machine_spi_p,
buffer, machine_spi_get_buffer,
locals_dict, &mp_machine_spi_locals_dict
);
mp_obj_base_t *mp_hal_get_spi_obj(mp_obj_t o) {
if (mp_obj_is_type(o, &machine_spi_type)) {
return MP_OBJ_TO_PTR(o);
}
#if MICROPY_PY_MACHINE_SOFTSPI
else if (mp_obj_is_type(o, &mp_machine_soft_spi_type)) {
return MP_OBJ_TO_PTR(o);
}
#endif
else {
mp_raise_TypeError(MP_ERROR_TEXT("expecting an SPI object"));
}
}