From e46776795baa53afa508bbce47d4b38620a6d8a1 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Sat, 9 Sep 2023 20:03:47 -0700 Subject: [PATCH 1/4] drivers: Upgrade SPI driver to support py drivers on all boards. --- src/omv/common/omv_spi.h | 25 ++- src/omv/common/vospi.c | 226 +++++++++++---------- src/omv/common/vospi.h | 1 - src/omv/ports/mimxrt/mimxrt_hal.c | 73 ++++++- src/omv/ports/mimxrt/mimxrt_hal.h | 2 +- src/omv/ports/mimxrt/omv_portconfig.h | 8 + src/omv/ports/mimxrt/omv_spi.c | 250 +++++++++++++++++------- src/omv/ports/stm32/omv_portconfig.h | 4 + src/omv/ports/stm32/omv_spi.c | 192 ++++++++++++++---- src/omv/ports/stm32/stm32fxxx_hal_msp.c | 83 ++++++++ src/omv/sensors/lepton.c | 2 +- 11 files changed, 652 insertions(+), 214 deletions(-) diff --git a/src/omv/common/omv_spi.h b/src/omv/common/omv_spi.h index bab8bff76..a75bc9db5 100644 --- a/src/omv/common/omv_spi.h +++ b/src/omv/common/omv_spi.h @@ -16,19 +16,26 @@ // Config options are defined in ports so they can be used // directly to initialize peripherals without remapping them. + +typedef enum { + OMV_SPI_DMA_NORMAL = (1 << 0), + OMV_SPI_DMA_CIRCULAR = (1 << 1), + OMV_SPI_DMA_DOUBLE = (1 << 2) +} omv_spi_dma_flags_t; + typedef enum { OMV_SPI_XFER_DMA = (1 << 0), OMV_SPI_XFER_BLOCKING = (1 << 1), OMV_SPI_XFER_NONBLOCK = (1 << 2), - OMV_SPI_XFER_CIRCULAR = (1 << 3), - OMV_SPI_XFER_FAILED = (1 << 4), - OMV_SPI_XFER_COMPLETE = (1 << 5), + OMV_SPI_XFER_FAILED = (1 << 3), + OMV_SPI_XFER_COMPLETE = (1 << 4), + OMV_SPI_XFER_16_BIT = (1 << 5), + OMV_SPI_XFER_HALF = (1 << 6), // Internal for Double Buffer mode. } omv_spi_xfer_flags_t; typedef struct _omv_spi_config { uint8_t id; uint32_t baudrate; - uint8_t datasize; uint32_t spi_mode; uint32_t bus_mode; uint32_t bit_order; @@ -36,13 +43,13 @@ typedef struct _omv_spi_config { uint32_t clk_pha; uint32_t nss_pol; bool nss_enable; - bool dma_enable; + uint32_t dma_flags; bool data_retained; } omv_spi_config_t; typedef struct _omv_spi omv_spi_t; -typedef void (*omv_spi_callback_t) (omv_spi_t *spi, void *data); +typedef void (*omv_spi_callback_t) (omv_spi_t *spi, void *userdata, void *rxbuf); typedef struct _omv_spi_transfer { void *txbuf; @@ -57,7 +64,7 @@ typedef struct _omv_spi_transfer { typedef struct _omv_spi { uint8_t id; bool initialized; - bool dma_enabled; + uint32_t dma_flags; omv_gpio_t cs; // For soft-NSS mode. void *userdata; omv_spi_callback_t callback; @@ -72,9 +79,11 @@ typedef struct _omv_spi { } omv_spi_t; int omv_spi_init(omv_spi_t *spi, omv_spi_config_t *config); -// Default config: MASTER | FDX | 10MHz | 8 bits | MSB FIRST | NSS HARD | NSS/CPHA/CPOL LOW. +// Default config: MASTER | FDX | 10MHz | MSB FIRST | NSS HARD | NSS/CPHA/CPOL LOW. int omv_spi_default_config(omv_spi_config_t *config, uint32_t bus_id); int omv_spi_deinit(omv_spi_t *spi); +int omv_spi_set_baudrate(omv_spi_t *spi, uint32_t baudrate); int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer); int omv_spi_transfer_abort(omv_spi_t *spi); + #endif // __OMV_SPI_H__ diff --git a/src/omv/common/vospi.c b/src/omv/common/vospi.c index 49a2d2de9..fa4c1c04a 100644 --- a/src/omv/common/vospi.c +++ b/src/omv/common/vospi.c @@ -10,154 +10,184 @@ */ #include "omv_boardconfig.h" #if OMV_ENABLE_VOSPI || OMV_ENABLE_LEPTON - -#include #include "py/mphal.h" -#include "vospi.h" #include "crc16.h" + #include "omv_common.h" #include "omv_spi.h" -#define VOSPI_LINE_PIXELS (80) -#define VOSPI_NUMBER_PACKETS (60) -#define VOSPI_SPECIAL_PACKET (20) -#define VOSPI_LINE_SIZE (80 * 2) -#define VOSPI_HEADER_SIZE (4) -#define VOSPI_PACKET_SIZE (VOSPI_HEADER_SIZE + VOSPI_LINE_SIZE) -#define VOSPI_FIRST_PACKET (0) -#define VOSPI_FIRST_SEGMENT (1) -#ifndef VOSPI_PACKET_ALIGNMENT -#define VOSPI_PACKET_ALIGNMENT (4) -#endif -#define VOSPI_HEADER_SEG(buf) (((buf[0] >> 4) & 0x7)) -#define VOSPI_HEADER_PID(buf) (((buf[0] << 8) | (buf[1] << 0)) & 0x0FFF) -#define VOSPI_HEADER_CRC(buf) (((buf[2] << 8) | (buf[3] << 0))) +static volatile bool waiting_for_data = false; +static uint16_t *framebuffer = 0; -typedef enum { - VOSPI_FLAGS_RESET = (1 << 0), - VOSPI_FLAGS_RESYNC = (1 << 1), -} vospi_flags_t; +static bool vospi_lepton_3 = false; -typedef struct _vospi_state { - volatile uint32_t pid; - volatile uint32_t sid; - uint8_t *buffer; - uint32_t n_packets; - omv_spi_t spi_bus; - volatile uint32_t flags; -} vospi_state_t; +static omv_spi_t spi_bus = {}; -static vospi_state_t vospi; -static uint8_t OMV_ATTR_SECTION( - OMV_ATTR_ALIGNED(vospi_packet[VOSPI_PACKET_SIZE], VOSPI_PACKET_ALIGNMENT), ".dma_buffer" - ); +#define VOSPI_HEADER_WORDS (2) // 16-bits +#define VOSPI_PID_SIZE_PIXELS (80) // w, 16-bits per pixel +#define VOSPI_PIDS_PER_SEG (60) // h +#define VOSPI_SEGS_PER_FRAME (4) +#define VOSPI_PACKET_SIZE (VOSPI_HEADER_WORDS + VOSPI_PID_SIZE_PIXELS) // 16-bits +#define VOSPI_SEG_SIZE_PIXELS (VOSPI_PIDS_PER_SEG * VOSPI_PID_SIZE_PIXELS) // 16-bits -static void vospi_callback(omv_spi_t *spi, void *data); -#if (OMV_ENABLE_VOSPI_CRC) -static uint16_t vospi_calc_crc(uint8_t *buf) { - buf[0] &= 0x0F; - buf[1] &= 0xFF; - buf[2] = 0; - buf[3] = 0; - return CalcCRC16Bytes(VOSPI_PACKET_SIZE, (char *) buf); -} -#endif +#define VOSPI_BUFFER_SIZE (VOSPI_PACKET_SIZE * 2) // 16-bits +#define VOSPI_CLOCK_SPEED 20000000 // hz +#define VOSPI_SYNC_MS 200 // ms -static void vospi_do_resync() { +static int vospi_rx_cb_expected_pid = 0; +static int vospi_rx_cb_expected_seg = 0; +static uint16_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED_DMA(vospi_buf[VOSPI_BUFFER_SIZE]), ".dma_buffer"); +static void vospi_callback(omv_spi_t *spi, void *userdata, void *rxbuf); + +static volatile bool vospi_resync_callback_flag = true; +static void vospi_resync_callback() { omv_spi_transfer_t spi_xfer = { - .txbuf = NULL, - .rxbuf = vospi_packet, - .size = VOSPI_PACKET_SIZE, - .timeout = 0, - .flags = OMV_SPI_XFER_DMA | OMV_SPI_XFER_CIRCULAR, - .userdata = NULL, + .rxbuf = vospi_buf, + .size = VOSPI_BUFFER_SIZE, + .flags = OMV_SPI_XFER_DMA | OMV_SPI_XFER_16_BIT, .callback = vospi_callback, }; - omv_spi_transfer_abort(&vospi.spi_bus); - mp_hal_delay_ms(200); - vospi.flags = VOSPI_FLAGS_RESET; - omv_spi_transfer_start(&vospi.spi_bus, &spi_xfer); - debug_printf("vospi resync...\n"); + mp_hal_delay_ms(VOSPI_SYNC_MS); + omv_spi_transfer_start(&spi_bus, &spi_xfer); } -static void vospi_callback(omv_spi_t *spi, void *data) { - if (vospi.flags & VOSPI_FLAGS_RESYNC) { - // Captured a packet before an resync is complete. +#if defined(OMV_ENABLE_VOSPI_CRC) +static bool vospi_check_crc(const uint16_t *base) { + int id = base[0]; + int packet_crc = base[1]; + int crc = ByteCRC16((id >> 8) & 0x0F, 0); + crc = ByteCRC16(id, crc); + crc = ByteCRC16(0, crc); + crc = ByteCRC16(0, crc); + + for (int i = VOSPI_HEADER_WORDS; i < VOSPI_PACKET_SIZE; i++) { + int value = base[i]; + crc = ByteCRC16(value >> 8, crc); + crc = ByteCRC16(value, crc); + } + + return packet_crc == crc; +} +#endif + + +void vospi_callback(omv_spi_t *spi, void *userdata, void *rxbuf) { + if (!waiting_for_data) { return; } - if (vospi.flags & VOSPI_FLAGS_RESET) { - vospi.pid = VOSPI_FIRST_PACKET; - vospi.sid = VOSPI_FIRST_SEGMENT; - vospi.flags &= ~(VOSPI_FLAGS_RESET); + const uint16_t *base = (uint16_t *) rxbuf; + + int id = base[0]; + + // Ignore don't care packets. + if ((id & 0x0F00) == 0x0F00) { + return; } - if (vospi.pid < vospi.n_packets && (vospi_packet[0] & 0xF) != 0xF) { - uint32_t pid = VOSPI_HEADER_PID(vospi_packet); - uint32_t sid = VOSPI_HEADER_SEG(vospi_packet); - if (pid != (vospi.pid % VOSPI_NUMBER_PACKETS)) { - if (vospi.pid != VOSPI_FIRST_PACKET) { - vospi.flags |= VOSPI_FLAGS_RESYNC; // lost sync - debug_printf("lost sync, packet id:%lu expected id:%lu \n", pid, vospi.pid); - } - } else if (vospi.n_packets > VOSPI_NUMBER_PACKETS - && pid == VOSPI_SPECIAL_PACKET && sid != vospi.sid) { - if (vospi.sid != VOSPI_FIRST_SEGMENT) { - vospi.flags |= VOSPI_FLAGS_RESYNC; // lost sync - debug_printf("lost sync, segment id:%lu expected id:%lu\n", sid, vospi.sid); + int pid = id & 0x0FFF; + int seg = ((id >> 12) & 0x7) - 1; + + // Discard packets with a pid != 0 when waiting for the first packet. + if ((vospi_rx_cb_expected_pid == 0) && (pid != 0)) { + return; + } + + // Discard segments with a seg != 0 when waiting for the first segment. + if (vospi_lepton_3 && (pid == 20) && (vospi_rx_cb_expected_seg == 0) && (seg != 0)) { + vospi_rx_cb_expected_pid = 0; + return; + } + + // Are we in sync with the flir lepton? + if ((pid != vospi_rx_cb_expected_pid) + #if defined(OMV_ENABLE_VOSPI_CRC) + || (!vospi_check_crc(base)) + #endif + || (vospi_lepton_3 && (pid == 20) && (seg != vospi_rx_cb_expected_seg))) { + vospi_rx_cb_expected_pid = 0; + vospi_rx_cb_expected_seg = 0; + omv_spi_transfer_abort(&spi_bus); + vospi_resync_callback_flag = true; + return; + } + + memcpy(framebuffer + + (vospi_rx_cb_expected_pid * VOSPI_PID_SIZE_PIXELS) + + (vospi_rx_cb_expected_seg * VOSPI_SEG_SIZE_PIXELS), + base + VOSPI_HEADER_WORDS, VOSPI_PID_SIZE_PIXELS * sizeof(uint16_t)); + + vospi_rx_cb_expected_pid += 1; + if (vospi_rx_cb_expected_pid == VOSPI_PIDS_PER_SEG) { + vospi_rx_cb_expected_pid = 0; + + bool frame_ready = false; + + // For the FLIR Lepton 3 we have to receive all the pids in all the segments. + if (vospi_lepton_3) { + vospi_rx_cb_expected_seg += 1; + if (vospi_rx_cb_expected_seg == VOSPI_SEGS_PER_FRAME) { + vospi_rx_cb_expected_seg = 0; + frame_ready = true; } + // For the FLIR Lepton 1/2 we just have to receive all the pids. } else { - memcpy(vospi.buffer + vospi.pid * VOSPI_LINE_SIZE, - vospi_packet + VOSPI_HEADER_SIZE, VOSPI_LINE_SIZE); - if ((++vospi.pid % VOSPI_NUMBER_PACKETS) == 0) { - vospi.sid++; - } + frame_ready = true; + } + + if (frame_ready) { + waiting_for_data = false; } } } int vospi_init(uint32_t n_packets, void *buffer) { - memset(&vospi, 0, sizeof(vospi_state_t)); - vospi.buffer = buffer; - vospi.n_packets = n_packets; - // resync on first snapshot. - vospi.flags = VOSPI_FLAGS_RESYNC; + vospi_lepton_3 = n_packets > VOSPI_PIDS_PER_SEG; + framebuffer = buffer; omv_spi_config_t spi_config; omv_spi_default_config(&spi_config, ISC_SPI_ID); + spi_config.baudrate = VOSPI_CLOCK_SPEED; spi_config.bus_mode = OMV_SPI_BUS_RX; - spi_config.baudrate = ISC_SPI_BAUDRATE; - spi_config.dma_enable = true; + spi_config.dma_flags = OMV_SPI_DMA_CIRCULAR | OMV_SPI_DMA_DOUBLE; - if (omv_spi_init(&vospi.spi_bus, &spi_config) != 0) { + if (omv_spi_init(&spi_bus, &spi_config) != 0) { return -1; } return 0; } int vospi_snapshot(uint32_t timeout_ms) { - // Restart counters to capture a new frame. - vospi.flags |= VOSPI_FLAGS_RESET; + waiting_for_data = true; - // Snapshot start tick mp_uint_t tick_start = mp_hal_ticks_ms(); - do { - if (vospi.flags & VOSPI_FLAGS_RESYNC) { - vospi_do_resync(); + for (;;) { + if (vospi_resync_callback_flag) { + vospi_resync_callback_flag = false; + vospi_resync_callback(); } - if ((mp_hal_ticks_ms() - tick_start) >= timeout_ms) { - // Timeout error. - return -1; + if (!waiting_for_data) { + break; } MICROPY_EVENT_POLL_HOOK - } while (vospi.pid < vospi.n_packets); + + if ((mp_hal_ticks_ms() - tick_start) > timeout_ms) { + omv_spi_transfer_abort(&spi_bus); + waiting_for_data = false; + vospi_rx_cb_expected_pid = 0; + vospi_rx_cb_expected_seg = 0; + vospi_resync_callback_flag = true; + return -1; + } + } return 0; } + #endif diff --git a/src/omv/common/vospi.h b/src/omv/common/vospi.h index bde67e9b5..0754cb57b 100644 --- a/src/omv/common/vospi.h +++ b/src/omv/common/vospi.h @@ -8,7 +8,6 @@ * * VOSPI driver. */ - #ifndef __VOSPI_H__ #define __VOSPI_H__ int vospi_init(uint32_t n_packets, void *buffer); diff --git a/src/omv/ports/mimxrt/mimxrt_hal.c b/src/omv/ports/mimxrt/mimxrt_hal.c index 7fd2898c4..ffef8f863 100644 --- a/src/omv/ports/mimxrt/mimxrt_hal.c +++ b/src/omv/ports/mimxrt/mimxrt_hal.c @@ -20,6 +20,7 @@ #include "fsl_usb_phy.h" #include "fsl_device_registers.h" #include CLOCK_CONFIG_H +#include "dma_manager.h" #include "irq.h" #include "omv_boardconfig.h" @@ -198,6 +199,22 @@ int mimxrt_hal_spi_init(uint32_t bus_id, bool nss_enable, uint32_t nss_pol) { break; } #endif + #if defined(LPSPI2_ID) + case LPSPI2_ID: { + spi_pins = (spi_pins_t) { + LPSPI2_SCLK_PIN, LPSPI2_MISO_PIN, LPSPI2_MOSI_PIN, LPSPI2_SSEL_PIN + }; + break; + } + #endif + #if defined(LPSPI3_ID) + case LPSPI3_ID: { + spi_pins = (spi_pins_t) { + LPSPI3_SCLK_PIN, LPSPI3_MISO_PIN, LPSPI3_MOSI_PIN, LPSPI3_SSEL_PIN + }; + break; + } + #endif #if defined(LPSPI4_ID) case LPSPI4_ID: { spi_pins = (spi_pins_t) { @@ -216,7 +233,7 @@ int mimxrt_hal_spi_init(uint32_t bus_id, bool nss_enable, uint32_t nss_pol) { if (nss_enable) { omv_gpio_config(spi_pins.ssel_pin, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_MED, -1); } else { - omv_gpio_config(spi_pins.ssel_pin, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_MED, -1); + omv_gpio_config(spi_pins.ssel_pin, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_MED, 5); if (nss_pol == OMV_SPI_NSS_LOW) { omv_gpio_write(spi_pins.ssel_pin, 1); } else { @@ -226,6 +243,60 @@ int mimxrt_hal_spi_init(uint32_t bus_id, bool nss_enable, uint32_t nss_pol) { return 0; } +int mimxrt_hal_spi_deinit(uint32_t bus_id) { + typedef struct { + omv_gpio_t sclk_pin; + omv_gpio_t miso_pin; + omv_gpio_t mosi_pin; + omv_gpio_t ssel_pin; + } spi_pins_t; + + spi_pins_t spi_pins = { NULL, NULL, NULL, NULL }; + + switch (bus_id) { + #if defined(LPSPI1_ID) + case LPSPI1_ID: { + spi_pins = (spi_pins_t) { + LPSPI1_SCLK_PIN, LPSPI1_MISO_PIN, LPSPI1_MOSI_PIN, LPSPI1_SSEL_PIN + }; + break; + } + #endif + #if defined(LPSPI2_ID) + case LPSPI2_ID: { + spi_pins = (spi_pins_t) { + LPSPI2_SCLK_PIN, LPSPI2_MISO_PIN, LPSPI2_MOSI_PIN, LPSPI2_SSEL_PIN + }; + break; + } + #endif + #if defined(LPSPI3_ID) + case LPSPI3_ID: { + spi_pins = (spi_pins_t) { + LPSPI3_SCLK_PIN, LPSPI3_MISO_PIN, LPSPI3_MOSI_PIN, LPSPI3_SSEL_PIN + }; + break; + } + #endif + #if defined(LPSPI4_ID) + case LPSPI4_ID: { + spi_pins = (spi_pins_t) { + LPSPI4_SCLK_PIN, LPSPI4_MISO_PIN, LPSPI4_MOSI_PIN, LPSPI4_SSEL_PIN + }; + break; + } + #endif + default: + return -1; + } + + omv_gpio_deinit(spi_pins.sclk_pin); + omv_gpio_deinit(spi_pins.miso_pin); + omv_gpio_deinit(spi_pins.mosi_pin); + omv_gpio_deinit(spi_pins.ssel_pin); + return 0; +} + void CSI_IRQHandler(void) { uint32_t csisr = CSI_REG_SR(CSI); extern void sensor_sof_callback(); diff --git a/src/omv/ports/mimxrt/mimxrt_hal.h b/src/omv/ports/mimxrt/mimxrt_hal.h index 2c9e19b83..4957272f5 100644 --- a/src/omv/ports/mimxrt/mimxrt_hal.h +++ b/src/omv/ports/mimxrt/mimxrt_hal.h @@ -10,10 +10,10 @@ */ #ifndef __MIMXRT_HAL_H__ #define __MIMXRT_HAL_H__ - void mimxrt_hal_init(); void mimxrt_hal_bootloader(); int mimxrt_hal_csi_init(CSI_Type *inst); int mimxrt_hal_i2c_init(uint32_t bus_id); int mimxrt_hal_spi_init(uint32_t bus_id, bool nss_enable, uint32_t nss_pol); +int mimxrt_hal_spi_deinit(uint32_t bus_id); #endif //__MIMXRT_HAL_H__ diff --git a/src/omv/ports/mimxrt/omv_portconfig.h b/src/omv/ports/mimxrt/omv_portconfig.h index 54b397b51..874e09343 100644 --- a/src/omv/ports/mimxrt/omv_portconfig.h +++ b/src/omv/ports/mimxrt/omv_portconfig.h @@ -46,6 +46,7 @@ #define OMV_GPIO_MODE_IT_FALL ((6 << 17) | IOMUXC_PAD_CTL(DSE, 0U) | IOMUXC_PAD_CTL(HYS, 1U)) #define OMV_GPIO_MODE_IT_RISE ((7 << 17) | IOMUXC_PAD_CTL(DSE, 0U) | IOMUXC_PAD_CTL(HYS, 1U)) #define OMV_GPIO_MODE_IT_BOTH ((8 << 17) | IOMUXC_PAD_CTL(DSE, 0U) | IOMUXC_PAD_CTL(HYS, 1U)) + // *INDENT-OFF* typedef struct { @@ -106,14 +107,21 @@ typedef LPI2C_Type *omv_i2c_dev_t; #define OMV_SPI_NSS_LOW (kLPSPI_PcsActiveLow) #define OMV_SPI_NSS_HIGH (kLPSPI_PcsActiveHigh) +#define OMV_SPI_MAX_8BIT_XFER (32768U - 32U) +#define OMV_SPI_MAX_16BIT_XFER (32768U - 16U) +#define OMV_SPI_MAX_TIMEOUT (0xFFFFFFFF) + #define OMV_SPI_PORT_BITS \ struct { \ LPSPI_Type *inst; \ + lpspi_master_config_t config_backup; \ edma_handle_t dma_descr_tx; \ edma_handle_t dma_descr_rx; \ union { \ lpspi_slave_handle_t descr_slave; \ lpspi_master_handle_t descr_master; \ + }; \ + union { \ lpspi_slave_edma_handle_t descr_slave_edma; \ lpspi_master_edma_handle_t descr_master_edma; \ }; \ diff --git a/src/omv/ports/mimxrt/omv_spi.c b/src/omv/ports/mimxrt/omv_spi.c index 9f3be1723..24658ae28 100644 --- a/src/omv/ports/mimxrt/omv_spi.c +++ b/src/omv/ports/mimxrt/omv_spi.c @@ -9,7 +9,6 @@ * OMV SPI bus port for mimxrt. */ #include "omv_boardconfig.h" -#include #include "py/mphal.h" #include "fsl_gpio.h" @@ -18,6 +17,7 @@ #include "fsl_lpspi_edma.h" #include "fsl_dmamux.h" #include CLOCK_CONFIG_H +#include "dma_manager.h" #include "mimxrt_hal.h" #include "omv_common.h" @@ -26,7 +26,6 @@ typedef struct dma_descr { DMA_Type *dma_inst; DMAMUX_Type *dma_mux; - uint32_t channel; uint32_t request; } dma_descr_t; @@ -40,36 +39,66 @@ typedef struct omv_spi_descr { static const omv_spi_descr_t omv_spi_descr_all[] = { #if defined(LPSPI1_ID) { LPSPI1, LPSPI1_SSEL_PIN, - { DMA0, DMAMUX, LPSPI1_DMA_TX_CHANNEL, kDmaRequestMuxLPSPI1Tx }, - { DMA0, DMAMUX, LPSPI1_DMA_RX_CHANNEL, kDmaRequestMuxLPSPI1Rx } }, + { DMA0, DMAMUX, kDmaRequestMuxLPSPI1Tx }, + { DMA0, DMAMUX, kDmaRequestMuxLPSPI1Rx } }, #else - { NULL, NULL, { NULL, NULL, 0, 0 }, { NULL, NULL, 0, 0 } }, + { NULL, NULL, { NULL, NULL, 0 }, { NULL, NULL, 0 } }, #endif + #if defined(LPSPI2_ID) { LPSPI2, LPSPI2_SSEL_PIN, - { DMA0, DMAMUX, LPSPI2_DMA_TX_CHANNEL, kDmaRequestMuxLPSPI2Tx }, - { DMA0, DMAMUX, LPSPI2_DMA_RX_CHANNEL, kDmaRequestMuxLPSPI2Rx } }, + { DMA0, DMAMUX, kDmaRequestMuxLPSPI2Tx }, + { DMA0, DMAMUX, kDmaRequestMuxLPSPI2Rx } }, #else - { NULL, NULL, { NULL, NULL, 0, 0 }, { NULL, NULL, 0, 0 } }, + { NULL, NULL, { NULL, NULL, 0 }, { NULL, NULL, 0 } }, #endif #if defined(LPSPI3_ID) { LPSPI3, LPSPI3_SSEL_PIN, - { DMA0, DMAMUX, LPSPI3_DMA_TX_CHANNEL, kDmaRequestMuxLPSPI3Tx }, - { DMA0, DMAMUX, LPSPI3_DMA_RX_CHANNEL, kDmaRequestMuxLPSPI3Rx } }, + { DMA0, DMAMUX, kDmaRequestMuxLPSPI3Tx }, + { DMA0, DMAMUX, kDmaRequestMuxLPSPI3Rx } }, #else - { NULL, NULL, { NULL, NULL, 0, 0 }, { NULL, NULL, 0, 0 } }, + { NULL, NULL, { NULL, NULL, 0 }, { NULL, NULL, 0 } }, #endif #if defined(LPSPI4_ID) { LPSPI4, LPSPI4_SSEL_PIN, - { DMA0, DMAMUX, LPSPI4_DMA_TX_CHANNEL, kDmaRequestMuxLPSPI4Tx }, - { DMA0, DMAMUX, LPSPI4_DMA_RX_CHANNEL, kDmaRequestMuxLPSPI4Rx } }, + { DMA0, DMAMUX, kDmaRequestMuxLPSPI4Tx }, + { DMA0, DMAMUX, kDmaRequestMuxLPSPI4Rx } }, #else - { NULL, NULL, { NULL, NULL, 0, 0 }, { NULL, NULL, 0, 0 } }, + { NULL, NULL, { NULL, NULL, 0 }, { NULL, NULL, 0 } }, #endif }; +// LPSPI_MasterTransferEDMA doesn't have any code at all to generate a callback on transmit complete. So, we +// add one here that simulates that. However, the DMA interrupt will occur before the SPI bus is done sending +// data. So, we cannot call spi_master_callback below as it will happen before the data is actually sent. Instead, +// we use the SPI transfer complete interrupt to call spi_master_callback at the right time. Note that we have +// to zero out the descriptor to prevent LPSPI_MasterTransferHandleIRQ from doing anything we don't want it to do. +static void EDMA_LpspiMasterTxCallback(edma_handle_t *edmaHandle, void *user, bool transferDone, uint32_t tcds) { + omv_spi_t *spi = (omv_spi_t *) user; + spi->descr_master_edma.state = (uint8_t) kLPSPI_Idle; + spi->descr_master.state = (uint8_t) kLPSPI_Idle; + spi->descr_master.txData = NULL; + spi->descr_master.rxData = NULL; + spi->descr_master.txRemainingByteCount = 0; + spi->descr_master.rxRemainingByteCount = 0; + spi->descr_master.totalByteCount = 0; + spi->descr_master.writeTcrInIsr = false; + spi->descr_master.bytesPerFrame = 0; + spi->descr_master.writeRegRemainingTimes = 0; + spi->descr_master.readRegRemainingTimes = 0; + spi->descr_master.txBuffIfNull = 0; + spi->descr_master.fifoSize = 0; + spi->descr_master.isPcsContinuous = 0; + spi->descr_master.isByteSwap = 0; + spi->descr_master.bytesEachWrite = 0; + spi->descr_master.bytesEachRead = 0; + spi->descr_master.rxWatermark = 0; + spi->descr_master.isTxMask = 0; + LPSPI_EnableInterrupts(spi->inst, (uint32_t) kLPSPI_TransferCompleteFlag); +} + static void spi_master_callback(LPSPI_Type *base, void *handle, status_t status, void *user) { omv_spi_t *spi = (omv_spi_t *) user; @@ -78,65 +107,118 @@ static void spi_master_callback(LPSPI_Type *base, void *handle, status_t status, } else { spi->xfer_flags |= OMV_SPI_XFER_FAILED; spi->xfer_error = status; - if (spi->xfer_flags & OMV_SPI_XFER_DMA) { - LPSPI_MasterTransferAbortEDMA(spi->inst, &spi->descr_master_edma); + omv_spi_transfer_abort(spi); + } + + void *rxBuf = spi->xfer_descr.rxData; + + // The IMXRT doesn't support half complete transfer interrupts (in the lpspi driver) like the STM32 + // does. So, mimick support for them by toggling the half flag. + uint32_t flags = (OMV_SPI_XFER_DMA | OMV_SPI_XFER_COMPLETE); + if ((spi->dma_flags & OMV_SPI_DMA_DOUBLE) && ((spi->xfer_flags & flags) == flags)) { + if (spi->xfer_flags & OMV_SPI_XFER_HALF) { + spi->xfer_flags &= ~OMV_SPI_XFER_HALF; + if (spi->xfer_descr.txData) { + spi->xfer_descr.txData -= spi->xfer_descr.dataSize; + } + if (spi->xfer_descr.rxData) { + spi->xfer_descr.rxData -= spi->xfer_descr.dataSize; + } } else { - LPSPI_MasterTransferAbort(spi->inst, &spi->descr_master); + spi->xfer_flags |= OMV_SPI_XFER_HALF; + if (spi->xfer_descr.txData) { + spi->xfer_descr.txData += spi->xfer_descr.dataSize; + } + if (spi->xfer_descr.rxData) { + spi->xfer_descr.rxData += spi->xfer_descr.dataSize; + } } } - if (spi->callback) { - spi->callback(spi, spi->userdata); + // Start the next DMA transfer before calling the callback. This minimizes the time + // when DMA is not running. Also, if the callback aborts this will stop the DMA transfer. + if ((spi->dma_flags & OMV_SPI_DMA_CIRCULAR) && ((spi->xfer_flags & flags) == flags)) { + // Restart transfer for circular transfers. Note that we can't be interrupted again + // by this until this callback finishes so it is okay to clear xfer complete later. + LPSPI_MasterTransferEDMA(spi->inst, &spi->descr_master_edma, &spi->xfer_descr); } - uint32_t flags = (OMV_SPI_XFER_DMA | OMV_SPI_XFER_CIRCULAR | OMV_SPI_XFER_COMPLETE); - if ((spi->xfer_flags & flags) == flags) { - // Restart transfer for circular transfers. - spi->xfer_flags &= ~(OMV_SPI_XFER_COMPLETE); - LPSPI_MasterTransferEDMA(spi->inst, &spi->descr_master_edma, &spi->xfer_descr); + if (spi->callback) { + spi->callback(spi, spi->userdata, rxBuf); + } + + // Clear after the callback so the callback gets the xfer complete flag set. + // This needs to be cleared to prevent circular DMA from re-triggering on a failure. + spi->xfer_flags &= ~(OMV_SPI_XFER_COMPLETE); +} + +// The LPSPI_MasterTransferNonBlocking function call does not clear the LPSPI_TCR_FRAMESZ_MASK bit +// even if kLPSPI_MasterByteSwap is not set in the xfer. So, we have to clear this bit at the same +// time as changing the framesize. Splitting this will result in inconsitent settings. Finally, +// the TCR register doesn't always update itself correctly so you have to try in a loop... +void omv_spi_set_frame_size(omv_spi_t *spi, uint16_t size) { + for (;;) { + uint32_t tcr = spi->inst->TCR; + uint16_t s = (uint16_t) ((tcr & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) + 1U; + if (s != size) { + spi->inst->TCR = (tcr & ~(LPSPI_TCR_BYSW_MASK | LPSPI_TCR_FRAMESZ_MASK)) | LPSPI_TCR_FRAMESZ(size - 1U); + } else { + break; + } } } int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) { spi->callback = xfer->callback; spi->userdata = xfer->userdata; + spi->xfer_error = 0; spi->xfer_flags = xfer->flags; - // Duplicate & stash transfer in spi struct, to avoid recreating - // it for circular transfers. NOTE: If circular transfers ever - // works this can be removed. + + uint32_t datasize = 8; + if (xfer->flags & OMV_SPI_XFER_16_BIT) { + datasize = 16; + } + + omv_spi_set_frame_size(spi, datasize); + spi->xfer_descr.txData = xfer->txbuf; spi->xfer_descr.rxData = xfer->rxbuf; spi->xfer_descr.dataSize = xfer->size; - spi->xfer_descr.configFlags = kLPSPI_MasterPcs0 | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap; + spi->xfer_descr.configFlags = kLPSPI_MasterPcs0 | kLPSPI_MasterPcsContinuous; spi->xfer_flags &= ~(OMV_SPI_XFER_FAILED | OMV_SPI_XFER_COMPLETE); - if (spi->xfer_flags & OMV_SPI_XFER_DMA) { - // DMA transfer (circular or one-shot) - if (LPSPI_MasterTransferEDMA(spi->inst, &spi->descr_master_edma, &spi->xfer_descr) != kStatus_Success) { + if (xfer->flags & OMV_SPI_XFER_16_BIT) { + spi->xfer_descr.dataSize *= 2; + } + + if (spi->dma_flags & OMV_SPI_DMA_DOUBLE) { + spi->xfer_descr.dataSize /= 2; + } + + // Check if we can optimize the transfer by doing things in 32-bit chunks. + if ((!(spi->xfer_descr.dataSize % 4)) && (!(xfer->flags & OMV_SPI_XFER_16_BIT))) { + omv_spi_set_frame_size(spi, 32); + spi->xfer_descr.configFlags |= kLPSPI_MasterByteSwap; + } + + if (spi->xfer_flags & OMV_SPI_XFER_BLOCKING) { + if (LPSPI_MasterTransferBlocking(spi->inst, &spi->xfer_descr) != kStatus_Success) { return -1; } - } else if (spi->xfer_flags & (OMV_SPI_XFER_BLOCKING | OMV_SPI_XFER_NONBLOCK)) { - // Use non-blocking mode for both non-blocking and blocking - // transfers, this way we can control the timeout better. + } else if (spi->xfer_flags & OMV_SPI_XFER_NONBLOCK) { if (LPSPI_MasterTransferNonBlocking(spi->inst, &spi->descr_master, &spi->xfer_descr) != kStatus_Success) { return -1; } - - // Non-blocking transfetr, return immediately and the user - // callback will be called when the transfer is done. - if (spi->xfer_flags & OMV_SPI_XFER_NONBLOCK) { - return 0; + } else if (spi->xfer_flags & OMV_SPI_XFER_DMA) { + if (LPSPI_MasterTransferEDMA(spi->inst, &spi->descr_master_edma, &spi->xfer_descr) != kStatus_Success) { + return -1; } - - // Blocking transfetr, wait for transfer complete or timeout. - mp_uint_t start = mp_hal_ticks_ms(); - while (!(spi->xfer_flags & OMV_SPI_XFER_COMPLETE)) { - if ((spi->xfer_flags & OMV_SPI_XFER_FAILED) || - ((mp_hal_ticks_ms() - start) > xfer->timeout)) { - LPSPI_MasterTransferAbort(spi->inst, &spi->descr_master); - return -1; - } - MICROPY_EVENT_POLL_HOOK + if (xfer->txbuf) { + // There isn't a race condition here to worry about since the major interrupt status flag + // will remain asserted even if the DMA transfer was to complete before we enable the interrupt. + EDMA_SetCallback(&spi->dma_descr_tx, EDMA_LpspiMasterTxCallback, spi); + EDMA_EnableChannelInterrupts(spi->dma_descr_tx.base, spi->dma_descr_tx.channel, + (uint32_t) kEDMA_MajorInterruptEnable); } } else { return -1; @@ -145,46 +227,64 @@ int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) { } int omv_spi_transfer_abort(omv_spi_t *spi) { - LPSPI_MasterTransferAbortEDMA(spi->inst, &spi->descr_master_edma); + if (spi->dma_flags & (OMV_SPI_DMA_NORMAL | OMV_SPI_DMA_CIRCULAR)) { + LPSPI_MasterTransferAbortEDMA(spi->inst, &spi->descr_master_edma); + } + LPSPI_MasterTransferAbort(spi->inst, &spi->descr_master); + LPSPI_MasterInit(spi->inst, &spi->config_backup, BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT); return 0; } static int omv_spi_dma_init(edma_handle_t *dma_handle, const dma_descr_t *dma_descr) { - DMAMUX_SetSource(dma_descr->dma_mux, dma_descr->channel, dma_descr->request); - DMAMUX_EnableChannel(dma_descr->dma_mux, dma_descr->channel); - EDMA_CreateHandle(dma_handle, dma_descr->dma_inst, dma_descr->channel); + int channel = allocate_dma_channel(); + DMAMUX_SetSource(dma_descr->dma_mux, channel, dma_descr->request); + DMAMUX_EnableChannel(dma_descr->dma_mux, channel); + EDMA_CreateHandle(dma_handle, dma_descr->dma_inst, channel); return 0; } int omv_spi_init(omv_spi_t *spi, omv_spi_config_t *config) { - // Configure clocks, pins and DMA MUX. - mimxrt_hal_spi_init(config->id, config->nss_enable, config->nss_pol); + memset(spi, 0, sizeof(omv_spi_t)); const omv_spi_descr_t *spi_descr = &omv_spi_descr_all[config->id - 1]; if (spi_descr->inst == NULL) { return -1; } - memset(spi, 0, sizeof(omv_spi_t)); spi->id = config->id; spi->inst = spi_descr->inst; spi->cs = spi_descr->cs; - spi->dma_enabled = config->dma_enable; + spi->dma_flags = config->dma_flags; lpspi_master_config_t spi_config; LPSPI_MasterGetDefaultConfig(&spi_config); spi_config.whichPcs = kLPSPI_Pcs0; spi_config.baudRate = config->baudrate; - spi_config.bitsPerFrame = config->datasize; + spi_config.bitsPerFrame = 8; spi_config.direction = config->bit_order; spi_config.pcsActiveHighOrLow = config->nss_pol; spi_config.cpol = config->clk_pol; spi_config.cpha = config->clk_pha; + spi_config.pcsToSckDelayInNanoSec = 0; + spi_config.lastSckToPcsDelayInNanoSec = 0; + spi_config.betweenTransferDelayInNanoSec = 0; + spi_config.pinCfg = kLPSPI_SdiInSdoOut; spi_config.dataOutConfig = config->data_retained ? kLpspiDataOutRetained : kLpspiDataOutTristate; + spi_config.enableInputDelay = false; LPSPI_MasterInit(spi->inst, &spi_config, BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT); + spi->config_backup = spi_config; - if (config->dma_enable) { + // Configure pins. + mimxrt_hal_spi_init(config->id, config->nss_enable, config->nss_pol); + + LPSPI_MasterTransferCreateHandle( + spi->inst, + &spi->descr_master, + (lpspi_master_transfer_callback_t) spi_master_callback, + spi); + + if (config->dma_flags & (OMV_SPI_DMA_NORMAL | OMV_SPI_DMA_CIRCULAR)) { // Configure DMA. // Note the FSL driver doesn't support half-duplex, so the both // TX/RX channels, descriptors etc... must be initialized. @@ -199,33 +299,47 @@ int omv_spi_init(omv_spi_t *spi, omv_spi_config_t *config) { spi, &spi->dma_descr_rx, &spi->dma_descr_tx); - } else { - LPSPI_MasterTransferCreateHandle( - spi->inst, - &spi->descr_master, - (lpspi_master_transfer_callback_t) spi_master_callback, - spi); } + spi->initialized = true; return 0; } int omv_spi_deinit(omv_spi_t *spi) { + if (spi && spi->initialized) { + spi->initialized = false; + omv_spi_transfer_abort(spi); + if (spi->dma_flags & (OMV_SPI_DMA_NORMAL | OMV_SPI_DMA_CIRCULAR)) { + const omv_spi_descr_t *spi_descr = &omv_spi_descr_all[spi->id - 1]; + DMAMUX_DisableChannel(spi_descr->dma_descr_tx.dma_mux, spi->dma_descr_tx.channel); + free_dma_channel(spi->dma_descr_tx.channel); + DMAMUX_DisableChannel(spi_descr->dma_descr_rx.dma_mux, spi->dma_descr_rx.channel); + free_dma_channel(spi->dma_descr_rx.channel); + } + LPSPI_Deinit(spi->inst); + mimxrt_hal_spi_deinit(spi->id); + } + return 0; +} + +int omv_spi_set_baudrate(omv_spi_t *spi, uint32_t baudrate) { + // LPSPI_MasterSetBaudRate doesn't work. Change the baudrate via a reinit here. + spi->config_backup.baudRate = baudrate; + omv_spi_transfer_abort(spi); return 0; } int omv_spi_default_config(omv_spi_config_t *config, uint32_t bus_id) { config->id = bus_id; config->baudrate = 10000000; - config->datasize = 8; config->spi_mode = OMV_SPI_MODE_MASTER; config->bus_mode = OMV_SPI_BUS_TX_RX; config->bit_order = OMV_SPI_MSB_FIRST; config->clk_pol = OMV_SPI_CPOL_HIGH; - config->clk_pha = OMV_SPI_CPHA_2EDGE; + config->clk_pha = OMV_SPI_CPHA_1EDGE; config->nss_pol = OMV_SPI_NSS_LOW; config->nss_enable = true; - config->dma_enable = false; + config->dma_flags = 0; config->data_retained = true; return 0; } diff --git a/src/omv/ports/stm32/omv_portconfig.h b/src/omv/ports/stm32/omv_portconfig.h index 12f454dda..b65ca4075 100644 --- a/src/omv/ports/stm32/omv_portconfig.h +++ b/src/omv/ports/stm32/omv_portconfig.h @@ -86,6 +86,10 @@ typedef I2C_HandleTypeDef *omv_i2c_dev_t; #define OMV_SPI_NSS_LOW (0) #define OMV_SPI_NSS_HIGH (1) +#define OMV_SPI_MAX_8BIT_XFER (65536U - 16U) +#define OMV_SPI_MAX_16BIT_XFER (65536U - 8U) +#define OMV_SPI_MAX_TIMEOUT (HAL_MAX_DELAY) + #define OMV_SPI_PORT_BITS \ struct { \ IRQn_Type irqn; \ diff --git a/src/omv/ports/stm32/omv_spi.c b/src/omv/ports/stm32/omv_spi.c index a4e3727a0..26f7ce5ca 100644 --- a/src/omv/ports/stm32/omv_spi.c +++ b/src/omv/ports/stm32/omv_spi.c @@ -124,7 +124,7 @@ static int omv_spi_prescaler(SPI_TypeDef *spi, uint32_t baudrate) { return SPI_BAUDRATEPRESCALER_256; } -static void omv_spi_callback(SPI_HandleTypeDef *hspi) { +static omv_spi_t *omv_spi_get_descr(SPI_HandleTypeDef *hspi) { omv_spi_t *spi = NULL; if (0) { #if defined(SPI1_ID) @@ -152,18 +152,72 @@ static void omv_spi_callback(SPI_HandleTypeDef *hspi) { spi = omv_spi_descr_all[5]; #endif } - if (spi == NULL) { - return; - } + return spi; +} +static void omv_spi_callback_error_check(SPI_HandleTypeDef *hspi, omv_spi_t *spi) { if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) { spi->xfer_flags |= OMV_SPI_XFER_FAILED; spi->xfer_error = hspi->ErrorCode; omv_spi_transfer_abort(spi); + } else { + spi->xfer_flags |= OMV_SPI_XFER_COMPLETE; + } +} + +static void *omv_spi_callback_rxbuf(omv_spi_t *spi) { + // On TX without RX pRxBuffPtr is zero. + uint8_t *rxbuf = (uint8_t *) spi->descr->pRxBuffPtr; + if (spi->xfer_flags & OMV_SPI_XFER_HALF) { + return rxbuf; + } else { + // On TX without RX RxXferSize is zero. + uint32_t rxsize = spi->descr->RxXferSize * ((spi->xfer_flags & OMV_SPI_XFER_16_BIT) ? 2 : 1); + return rxbuf + (rxsize / 2); + } +} + +static void omv_spi_callback(SPI_HandleTypeDef *hspi) { + omv_spi_t *spi = omv_spi_get_descr(hspi); + if (spi == NULL) { + return; } + omv_spi_callback_error_check(hspi, spi); + spi->xfer_flags &= ~OMV_SPI_XFER_HALF; + if (spi->callback) { - spi->callback(spi, spi->userdata); + spi->callback(spi, spi->userdata, omv_spi_callback_rxbuf(spi)); + } +} + +static void omv_spi_half_callback(SPI_HandleTypeDef *hspi) { + omv_spi_t *spi = omv_spi_get_descr(hspi); + if (spi == NULL) { + return; + } + + omv_spi_callback_error_check(hspi, spi); + spi->xfer_flags |= OMV_SPI_XFER_HALF; + + if (spi->callback) { + spi->callback(spi, spi->userdata, omv_spi_callback_rxbuf(spi)); + } +} + +static void omv_spi_dma_burst_mode(DMA_HandleTypeDef *hdma, bool on, bool sixteenbit) { + // Handle may not be initialized. + if (hdma->State == HAL_DMA_STATE_READY) { + hdma->Init.MemBurst = on ? DMA_MBURST_INC4 : DMA_MBURST_SINGLE; + hdma->Init.FIFOThreshold = on ? DMA_FIFO_THRESHOLD_FULL : DMA_FIFO_THRESHOLD_1QUARTERFULL; + uint32_t registerValue = ((DMA_Stream_TypeDef *) hdma->Instance)->CR; + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + hdma->Init.PeriphDataAlignment = sixteenbit ? DMA_PDATAALIGN_HALFWORD : DMA_PDATAALIGN_BYTE; + registerValue = (registerValue & ~DMA_SxCR_PSIZE) | hdma->Init.PeriphDataAlignment; + #endif + ((DMA_Stream_TypeDef *) hdma->Instance)->CR = (registerValue & ~DMA_SxCR_MBURST) | hdma->Init.MemBurst; + registerValue = ((DMA_Stream_TypeDef *) hdma->Instance)->FCR; + ((DMA_Stream_TypeDef *) hdma->Instance)->FCR = (registerValue & ~DMA_SxFCR_FTH) | hdma->Init.FIFOThreshold; } } @@ -173,6 +227,37 @@ int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) { spi->xfer_error = 0; spi->xfer_flags = xfer->flags; + bool sixteenbit = xfer->flags & OMV_SPI_XFER_16_BIT; + size_t xfer_byte_size = xfer->size * (sixteenbit ? 2 : 1); + #if defined(MCU_SERIES_H7) + // Default to moving one element at a time through the fifo for 8-bit/16-bit transfers. + uint8_t fthlv = SPI_FIFO_THRESHOLD_01DATA; + // Do word sized transfers one at a time. + if (!(xfer_byte_size % 4)) { + fthlv = sixteenbit ? SPI_FIFO_THRESHOLD_02DATA : SPI_FIFO_THRESHOLD_04DATA; + } + #endif + + spi->descr->Init.DataSize = sixteenbit ? SPI_DATASIZE_16BIT : SPI_DATASIZE_8BIT; + #if defined(MCU_SERIES_H7) + spi->descr->Init.FifoThreshold = fthlv; + spi->descr->Instance->CFG1 = (spi->descr->Instance->CFG1 & ~SPI_CFG1_DSIZE_Msk) | spi->descr->Init.DataSize; + spi->descr->Instance->CFG1 = (spi->descr->Instance->CFG1 & ~SPI_CFG1_FTHLV_Msk) | fthlv; + #elif defined(MCU_SERIES_F7) + spi->descr->Instance->CR2 = (spi->descr->Instance->CR2 & ~SPI_CR2_DS_Msk) | spi->descr->Init.DataSize; + #elif defined(MCU_SERIES_F4) + spi->descr->Instance->CR1 = (spi->descr->Instance->CR1 & ~SPI_CR1_DFF_Msk) | spi->descr->Init.DataSize; + #endif + + // If the DMA transfer is not a multiple of 16 bytes then we cannot use any burst modes. + if (xfer->flags & OMV_SPI_XFER_DMA) { + bool on = !(xfer_byte_size % 16); + omv_spi_dma_burst_mode(&spi->dma_descr_tx, on, sixteenbit); + omv_spi_dma_burst_mode(&spi->dma_descr_rx, on, sixteenbit); + } + + spi->xfer_flags &= ~(OMV_SPI_XFER_FAILED | OMV_SPI_XFER_COMPLETE | OMV_SPI_XFER_HALF); + if (spi->xfer_flags & OMV_SPI_XFER_BLOCKING) { if (xfer->txbuf && xfer->rxbuf) { if (HAL_SPI_TransmitReceive(spi->descr, xfer->txbuf, @@ -188,6 +273,21 @@ int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) { return -1; } } + } else if (spi->xfer_flags & OMV_SPI_XFER_NONBLOCK) { + if (xfer->txbuf && xfer->rxbuf) { + if (HAL_SPI_TransmitReceive_IT(spi->descr, xfer->txbuf, + xfer->rxbuf, xfer->size) != HAL_OK) { + return -1; + } + } else if (xfer->txbuf) { + if (HAL_SPI_Transmit_IT(spi->descr, xfer->txbuf, xfer->size) != HAL_OK) { + return -1; + } + } else if (xfer->rxbuf) { + if (HAL_SPI_Receive_IT(spi->descr, xfer->rxbuf, xfer->size) != HAL_OK) { + return -1; + } + } } else if (spi->xfer_flags & OMV_SPI_XFER_DMA) { if (xfer->txbuf && xfer->rxbuf) { if (HAL_SPI_TransmitReceive_DMA(spi->descr, xfer->txbuf, @@ -210,12 +310,15 @@ int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) { } int omv_spi_transfer_abort(omv_spi_t *spi) { - HAL_NVIC_DisableIRQ(spi->irqn); - HAL_SPI_Abort(spi->descr); + if (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) { + HAL_SPI_Abort_IT(spi->descr); + } else { + HAL_SPI_Abort(spi->descr); + } return 0; } -static int omv_spi_dma_init(omv_spi_t *spi, uint32_t direction) { +static int omv_spi_dma_init(omv_spi_t *spi, uint32_t direction, omv_spi_config_t *config) { DMA_HandleTypeDef *dma_descr; if (direction == DMA_MEMORY_TO_PERIPH) { @@ -225,19 +328,19 @@ static int omv_spi_dma_init(omv_spi_t *spi, uint32_t direction) { } // Configure the SPI DMA steam. - dma_descr->Init.Mode = DMA_CIRCULAR; // TODO FIX - dma_descr->Init.Priority = DMA_PRIORITY_HIGH; + dma_descr->Init.Mode = (config->dma_flags & OMV_SPI_DMA_CIRCULAR) ? DMA_CIRCULAR : DMA_NORMAL; + dma_descr->Init.Priority = DMA_PRIORITY_LOW; dma_descr->Init.Direction = direction; - // When the DMA is configured in direct mode (the FIFO is disabled), the source and - // destination transfer widths are equal, and both defined by PSIZE (MSIZE is ignored). - // Additionally, burst transfers are not possible (MBURST and PBURST are both ignored). - dma_descr->Init.FIFOMode = DMA_FIFOMODE_DISABLE; + dma_descr->Init.FIFOMode = DMA_FIFOMODE_ENABLE; dma_descr->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; - // Note MBURST and PBURST are ignored. dma_descr->Init.MemBurst = DMA_MBURST_INC4; - dma_descr->Init.PeriphBurst = DMA_PBURST_INC4; dma_descr->Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dma_descr->Init.PeriphBurst = DMA_PBURST_SINGLE; + #if defined(MCU_SERIES_H7) dma_descr->Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + #else + dma_descr->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + #endif dma_descr->Init.MemInc = DMA_MINC_ENABLE; dma_descr->Init.PeriphInc = DMA_PINC_DISABLE; @@ -261,7 +364,7 @@ static int omv_spi_dma_init(omv_spi_t *spi, uint32_t direction) { uint8_t dma_irqn = dma_utils_channel_to_irqn(dma_descr->Instance); // Configure and enable DMA IRQ channel. - NVIC_SetPriority(dma_irqn, IRQ_PRI_DMA21); + NVIC_SetPriority(dma_irqn, IRQ_PRI_DMA); HAL_NVIC_EnableIRQ(dma_irqn); return 0; @@ -272,8 +375,9 @@ static int omv_spi_bus_init(omv_spi_t *spi, omv_spi_config_t *config) { spi_descr->Init.Mode = config->spi_mode; spi_descr->Init.TIMode = SPI_TIMODE_DISABLE; + spi_descr->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; spi_descr->Init.NSS = (config->nss_enable == false) ? SPI_NSS_SOFT : SPI_NSS_HARD_OUTPUT; - spi_descr->Init.DataSize = (config->datasize == 8) ? SPI_DATASIZE_8BIT : SPI_DATASIZE_16BIT; + spi_descr->Init.DataSize = SPI_DATASIZE_8BIT; spi_descr->Init.FirstBit = config->bit_order; spi_descr->Init.CLKPhase = config->clk_pha; spi_descr->Init.CLKPolarity = config->clk_pol; @@ -282,9 +386,13 @@ static int omv_spi_bus_init(omv_spi_t *spi, omv_spi_config_t *config) { spi_descr->Init.NSSPMode = SPI_NSS_PULSE_DISABLE; #if defined(MCU_SERIES_H7) spi_descr->Init.NSSPolarity = (config->nss_pol == 0) ? SPI_NSS_POLARITY_LOW : SPI_NSS_POLARITY_HIGH; - spi_descr->Init.FifoThreshold = SPI_FIFO_THRESHOLD_04DATA; + spi_descr->Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA; + spi_descr->Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE; + spi_descr->Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE; + spi_descr->Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE; spi_descr->Init.MasterKeepIOState = (config->data_retained == true) ? SPI_MASTER_KEEP_IO_STATE_ENABLE : SPI_MASTER_KEEP_IO_STATE_ENABLE; + spi_descr->Init.IOSwap = SPI_IO_SWAP_DISABLE; #endif #endif @@ -344,29 +452,30 @@ int omv_spi_init(omv_spi_t *spi, omv_spi_config_t *config) { return -1; } - if (config->dma_enable) { + if (config->dma_flags & (OMV_SPI_DMA_NORMAL | OMV_SPI_DMA_CIRCULAR)) { if (config->bus_mode & OMV_SPI_BUS_TX) { - omv_spi_dma_init(spi, DMA_MEMORY_TO_PERIPH); + omv_spi_dma_init(spi, DMA_MEMORY_TO_PERIPH, config); } if (config->bus_mode & OMV_SPI_BUS_RX) { - omv_spi_dma_init(spi, DMA_PERIPH_TO_MEMORY); + omv_spi_dma_init(spi, DMA_PERIPH_TO_MEMORY, config); } - // Configure and enable SPI IRQ channel. - NVIC_SetPriority(spi->irqn, IRQ_PRI_DCMI);// TODO use lower priority - HAL_NVIC_EnableIRQ(spi->irqn); } + // Configure and enable SPI IRQ channel. + NVIC_SetPriority(spi->irqn, IRQ_PRI_SPI); + HAL_NVIC_EnableIRQ(spi->irqn); // Install TX/RX callbacks even if DMA mode is not enabled for non-blocking transfers. - if (config->bus_mode & OMV_SPI_BUS_TX) { - HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_TX_COMPLETE_CB_ID, omv_spi_callback); - } - - if (config->bus_mode & OMV_SPI_BUS_RX) { - HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_RX_COMPLETE_CB_ID, omv_spi_callback); + HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_TX_RX_COMPLETE_CB_ID, omv_spi_callback); + HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_TX_COMPLETE_CB_ID, omv_spi_callback); + HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_RX_COMPLETE_CB_ID, omv_spi_callback); + if (config->dma_flags & OMV_SPI_DMA_DOUBLE) { + HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_TX_RX_HALF_COMPLETE_CB_ID, omv_spi_half_callback); + HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_TX_HALF_COMPLETE_CB_ID, omv_spi_half_callback); + HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_RX_HALF_COMPLETE_CB_ID, omv_spi_half_callback); } spi->initialized = true; - spi->dma_enabled = config->dma_enable; + spi->dma_flags = config->dma_flags; omv_spi_descr_all[config->id - 1] = spi; return 0; } @@ -376,18 +485,29 @@ int omv_spi_deinit(omv_spi_t *spi) { spi->initialized = false; omv_spi_descr_all[spi->id - 1] = NULL; omv_spi_transfer_abort(spi); - if (spi->dma_enabled) { - // TODO: Deinit DMA + if (spi->dma_flags & (OMV_SPI_DMA_NORMAL | OMV_SPI_DMA_CIRCULAR)) { + if (spi->descr->hdmatx != NULL) { + HAL_DMA_Abort(spi->descr->hdmatx); + } + if (spi->descr->hdmarx != NULL) { + HAL_DMA_Abort(spi->descr->hdmarx); + } } HAL_SPI_DeInit(spi->descr); + HAL_NVIC_DisableIRQ(spi->irqn); } return 0; } +// This function is only needed for the py_tv driver on the RT1060 to slow down the SPI bus on reads. +// The STM32 is capable of reading data on the SPI bus at high speeds without issues... +int omv_spi_set_baudrate(omv_spi_t *spi, uint32_t baudrate) { + return 0; +} + int omv_spi_default_config(omv_spi_config_t *config, uint32_t bus_id) { config->id = bus_id; config->baudrate = 10000000; - config->datasize = 8; config->spi_mode = OMV_SPI_MODE_MASTER; config->bus_mode = OMV_SPI_BUS_TX_RX; config->bit_order = OMV_SPI_MSB_FIRST; @@ -395,7 +515,7 @@ int omv_spi_default_config(omv_spi_config_t *config, uint32_t bus_id) { config->clk_pha = OMV_SPI_CPHA_1EDGE; config->nss_pol = OMV_SPI_NSS_LOW; config->nss_enable = true; - config->dma_enable = false; + config->dma_flags = 0; config->data_retained = true; return 0; } diff --git a/src/omv/ports/stm32/stm32fxxx_hal_msp.c b/src/omv/ports/stm32/stm32fxxx_hal_msp.c index 81f43efaf..2b3b66705 100644 --- a/src/omv/ports/stm32/stm32fxxx_hal_msp.c +++ b/src/omv/ports/stm32/stm32fxxx_hal_msp.c @@ -433,7 +433,17 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) { return; } + #if defined(MCU_SERIES_H7) omv_gpio_config(spi_pins.sclk_pin, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_HIGH, -1); + #else + // The STM32F4 and STM32F7 don't set the initial state of the clock line until transmitting the + // first packet... which means the first packet may be seen as corrupt by the slave device. + if (hspi->Init.CLKPolarity == SPI_POLARITY_HIGH) { + omv_gpio_config(spi_pins.sclk_pin, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_HIGH, -1); + } else { + omv_gpio_config(spi_pins.sclk_pin, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_DOWN, OMV_GPIO_SPEED_HIGH, -1); + } + #endif omv_gpio_config(spi_pins.miso_pin, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_HIGH, -1); omv_gpio_config(spi_pins.mosi_pin, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_HIGH, -1); if (hspi->Init.NSS != SPI_NSS_SOFT) { @@ -446,12 +456,85 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) { } else { omv_gpio_write(spi_pins.ssel_pin, 0); } + #else + omv_gpio_write(spi_pins.ssel_pin, 1); #endif } } void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi) { + typedef struct { + omv_gpio_t sclk_pin; + omv_gpio_t miso_pin; + omv_gpio_t mosi_pin; + omv_gpio_t ssel_pin; + } spi_pins_t; + spi_pins_t spi_pins = { NULL, NULL, NULL, NULL }; + + if (0) { + #if defined(SPI1_ID) + } else if (hspi->Instance == SPI1) { + __HAL_RCC_SPI1_FORCE_RESET(); + __HAL_RCC_SPI1_RELEASE_RESET(); + __HAL_RCC_SPI1_CLK_DISABLE(); + spi_pins = (spi_pins_t) { + SPI1_SCLK_PIN, SPI1_MISO_PIN, SPI1_MOSI_PIN, SPI1_SSEL_PIN + }; + #endif + #if defined(SPI2_ID) + } else if (hspi->Instance == SPI2) { + __HAL_RCC_SPI2_FORCE_RESET(); + __HAL_RCC_SPI2_RELEASE_RESET(); + __HAL_RCC_SPI2_CLK_DISABLE(); + spi_pins = (spi_pins_t) { + SPI2_SCLK_PIN, SPI2_MISO_PIN, SPI2_MOSI_PIN, SPI2_SSEL_PIN + }; + #endif + #if defined(SPI3_ID) + } else if (hspi->Instance == SPI3) { + __HAL_RCC_SPI3_FORCE_RESET(); + __HAL_RCC_SPI3_RELEASE_RESET(); + __HAL_RCC_SPI3_CLK_DISABLE(); + spi_pins = (spi_pins_t) { + SPI3_SCLK_PIN, SPI3_MISO_PIN, SPI3_MOSI_PIN, SPI3_SSEL_PIN + }; + #endif + #if defined(SPI4_ID) + } else if (hspi->Instance == SPI4) { + __HAL_RCC_SPI4_FORCE_RESET(); + __HAL_RCC_SPI4_RELEASE_RESET(); + __HAL_RCC_SPI4_CLK_DISABLE(); + spi_pins = (spi_pins_t) { + SPI4_SCLK_PIN, SPI4_MISO_PIN, SPI4_MOSI_PIN, SPI4_SSEL_PIN + }; + #endif + #if defined(SPI5_ID) + } else if (hspi->Instance == SPI5) { + __HAL_RCC_SPI5_FORCE_RESET(); + __HAL_RCC_SPI5_RELEASE_RESET(); + __HAL_RCC_SPI5_CLK_DISABLE(); + spi_pins = (spi_pins_t) { + SPI5_SCLK_PIN, SPI5_MISO_PIN, SPI5_MOSI_PIN, SPI5_SSEL_PIN + }; + #endif + #if defined(SPI6_ID) + } else if (hspi->Instance == SPI6) { + __HAL_RCC_SPI6_FORCE_RESET(); + __HAL_RCC_SPI6_RELEASE_RESET(); + __HAL_RCC_SPI6_CLK_DISABLE(); + spi_pins = (spi_pins_t) { + SPI6_SCLK_PIN, SPI6_MISO_PIN, SPI6_MOSI_PIN, SPI6_SSEL_PIN + }; + #endif + } else { + return; + } + + omv_gpio_deinit(spi_pins.sclk_pin); + omv_gpio_deinit(spi_pins.miso_pin); + omv_gpio_deinit(spi_pins.mosi_pin); + omv_gpio_deinit(spi_pins.ssel_pin); } #if defined(AUDIO_SAI) diff --git a/src/omv/sensors/lepton.c b/src/omv/sensors/lepton.c index 00894340b..cafe96e2c 100644 --- a/src/omv/sensors/lepton.c +++ b/src/omv/sensors/lepton.c @@ -432,7 +432,7 @@ static int snapshot(sensor_t *sensor, image_t *image, uint32_t flags) { // Value is the 14/16-bit value from the FLIR IR camera. // However, with AGC enabled only the bottom 8-bits are non-zero. - int value = __REV16(row_ptr[fast_floorf(x * scale_inv)]); + int value = row_ptr[fast_floorf(x * scale_inv)]; if (lepton.measurement_mode) { // Need to convert 14/16-bits to 8-bits ourselves... From 4639b1eb2f258e3b6ca395b42548dbad694570aa Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Sat, 9 Sep 2023 20:09:38 -0700 Subject: [PATCH 2/4] drivers: Make all spi based py modules cross platform. --- .../ARDUINO_NICLA_VISION/omv_boardconfig.h | 39 ++- .../boards/ARDUINO_NICLA_VISION/omv_pins.h | 7 +- .../ARDUINO_PORTENTA_H7/omv_boardconfig.h | 41 +-- src/omv/boards/ARDUINO_PORTENTA_H7/omv_pins.h | 5 +- src/omv/boards/OPENMV2/omv_boardconfig.h | 15 +- src/omv/boards/OPENMV3/omv_boardconfig.h | 13 +- src/omv/boards/OPENMV4/omv_boardconfig.h | 14 +- src/omv/boards/OPENMV4P/omv_boardconfig.h | 15 +- src/omv/boards/OPENMVPT/omv_boardconfig.h | 37 ++- .../{ports/stm32 => }/modules/py_fir_lepton.c | 107 +++---- .../{ports/stm32 => }/modules/py_fir_lepton.h | 0 src/omv/{ports/stm32 => }/modules/py_lcd.c | 272 ++++++++---------- src/omv/{ports/stm32 => }/modules/py_lcd.h | 0 .../{ports/stm32 => }/modules/py_lcd_cec.c | 0 .../{ports/stm32 => }/modules/py_lcd_cec.h | 0 .../{ports/stm32 => }/modules/py_lcd_touch.c | 2 - .../{ports/stm32 => }/modules/py_lcd_touch.h | 0 src/omv/{ports/stm32 => }/modules/py_tv.c | 223 ++++++-------- src/omv/{ports/stm32 => }/modules/py_tv.h | 0 src/omv/ports/stm32/stm32fxxx.ld.S | 4 - src/uvc/stm32fxxx.ld.S | 4 - 21 files changed, 346 insertions(+), 452 deletions(-) rename src/omv/{ports/stm32 => }/modules/py_fir_lepton.c (82%) rename src/omv/{ports/stm32 => }/modules/py_fir_lepton.h (100%) rename src/omv/{ports/stm32 => }/modules/py_lcd.c (88%) rename src/omv/{ports/stm32 => }/modules/py_lcd.h (100%) rename src/omv/{ports/stm32 => }/modules/py_lcd_cec.c (100%) rename src/omv/{ports/stm32 => }/modules/py_lcd_cec.h (100%) rename src/omv/{ports/stm32 => }/modules/py_lcd_touch.c (99%) rename src/omv/{ports/stm32 => }/modules/py_lcd_touch.h (100%) rename src/omv/{ports/stm32 => }/modules/py_tv.c (82%) rename src/omv/{ports/stm32 => }/modules/py_tv.h (100%) diff --git a/src/omv/boards/ARDUINO_NICLA_VISION/omv_boardconfig.h b/src/omv/boards/ARDUINO_NICLA_VISION/omv_boardconfig.h index 7ce238491..b51ee996d 100644 --- a/src/omv/boards/ARDUINO_NICLA_VISION/omv_boardconfig.h +++ b/src/omv/boards/ARDUINO_NICLA_VISION/omv_boardconfig.h @@ -163,7 +163,6 @@ #define OMV_LINE_BUF_SIZE (3 * 1024) // Image line buffer round(640 * 2BPP * 2 buffers). #define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data #define OMV_VFS_BUF_SIZE (1K) // VFS struct + FATFS file buffer (624 bytes) -#define OMV_FIR_LEPTON_BUF_SIZE (1K) // FIR Lepton Packet Double Buffer (328 bytes) #define OMV_JPEG_BUF_SIZE (32 * 1024) // IDE JPEG buffer (header + data). // Memory map. @@ -227,8 +226,8 @@ #define FIR_I2C_SPEED (OMV_I2C_SPEED_FULL) // Soft I2C bus -#define SOFT_I2C_SIOC_PIN (&omv_pin_C10_GPIO) -#define SOFT_I2C_SIOD_PIN (&omv_pin_C11_GPIO) +#define SOFT_I2C_SIOC_PIN (&omv_pin_B8_GPIO) +#define SOFT_I2C_SIOD_PIN (&omv_pin_B9_GPIO) #define SOFT_I2C_SPIN_DELAY 64 // IMU SPI bus @@ -287,7 +286,8 @@ #define AUDIO_DFSDM_CLK_DISABLE() __HAL_RCC_DFSDM1_CLK_DISABLE() #define AUDIO_DFSDM_DMA_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE() -// Physical I2C buses +// Physical I2C buses. + // I2C bus 1 #define I2C1_ID (1) #define I2C1_SCL_PIN (&omv_pin_B8_I2C1) @@ -299,6 +299,16 @@ #define I2C3_SDA_PIN (&omv_pin_C9_I2C3) // Physical SPI buses. + +// SPI bus 4 +#define SPI4_ID (4) +#define SPI4_SCLK_PIN (&omv_pin_E12_SPI4) +#define SPI4_MISO_PIN (&omv_pin_E13_SPI4) +#define SPI4_MOSI_PIN (&omv_pin_E14_SPI4) +#define SPI4_SSEL_PIN (&omv_pin_E11_SPI4) +#define SPI4_DMA_TX_CHANNEL (DMA2_Stream4) +#define SPI4_DMA_RX_CHANNEL (DMA2_Stream3) + // SPI bus 5 #define SPI5_ID (5) #define SPI5_SCLK_PIN (&omv_pin_F7_SPI5) @@ -309,33 +319,20 @@ #define SPI5_DMA_RX_CHANNEL (DMA2_Stream3) // SPI LCD Interface -#define OMV_SPI_LCD_CONTROLLER (&spi_obj[3]) -#define OMV_SPI_LCD_CONTROLLER_INSTANCE (SPI4) - +#define OMV_SPI_LCD_SPI_BUS (SPI4_ID) #define OMV_SPI_LCD_MOSI_PIN (&omv_pin_E14_SPI4) #define OMV_SPI_LCD_MISO_PIN (&omv_pin_E13_SPI4) #define OMV_SPI_LCD_SCLK_PIN (&omv_pin_E12_SPI4) #define OMV_SPI_LCD_SSEL_PIN (&omv_pin_E11_GPIO) -#define OMV_SPI_LCD_RS_PIN (&omv_pin_C11_GPIO) -//#define OMV_SPI_LCD_BL_PIN (&omv_pin_A4_GPIO) -#define OMV_SPI_LCD_RST_PIN (&omv_pin_C10_GPIO) - -#ifdef OMV_SPI_LCD_BL_PIN -#define OMV_SPI_LCD_BL_DAC (DAC1) -#define OMV_SPI_LCD_BL_DAC_CHANNEL (DAC_CHANNEL_1) -#define OMV_SPI_LCD_BL_DAC_CLK_ENABLE() __HAL_RCC_DAC12_CLK_ENABLE() -#define OMV_SPI_LCD_BL_DAC_CLK_DISABLE() __HAL_RCC_DAC12_CLK_DISABLE() -#define OMV_SPI_LCD_BL_DAC_FORCE_RESET() __HAL_RCC_DAC12_FORCE_RESET() -#define OMV_SPI_LCD_BL_DAC_RELEASE_RESET() __HAL_RCC_DAC12_RELEASE_RESET() -#endif +#define OMV_SPI_LCD_RS_PIN (&omv_pin_G12_GPIO) +#define OMV_SPI_LCD_RST_PIN (&omv_pin_G1_GPIO) // FIR Lepton #define OMV_FIR_LEPTON_I2C_BUS (FIR_I2C_ID) #define OMV_FIR_LEPTON_I2C_BUS_SPEED (FIR_I2C_SPEED) -#define OMV_FIR_LEPTON_CONTROLLER (&spi_obj[3]) -#define OMV_FIR_LEPTON_CONTROLLER_INSTANCE (SPI4) +#define OMV_FIR_LEPTON_SPI_BUS (SPI4_ID) #define OMV_FIR_LEPTON_MOSI_PIN (&omv_pin_E14_SPI4) #define OMV_FIR_LEPTON_MISO_PIN (&omv_pin_E13_SPI4) #define OMV_FIR_LEPTON_SCLK_PIN (&omv_pin_E12_SPI4) diff --git a/src/omv/boards/ARDUINO_NICLA_VISION/omv_pins.h b/src/omv/boards/ARDUINO_NICLA_VISION/omv_pins.h index 8498345bf..3add31c02 100644 --- a/src/omv/boards/ARDUINO_NICLA_VISION/omv_pins.h +++ b/src/omv/boards/ARDUINO_NICLA_VISION/omv_pins.h @@ -5,15 +5,15 @@ OMV_GPIO_DEFINE(A, 7, AF2, TIM3) OMV_GPIO_DEFINE(A, 8, AF4, I2C3) OMV_GPIO_DEFINE(A, 10, NONE, GPIO) OMV_GPIO_DEFINE(B, 4, NONE, GPIO) +OMV_GPIO_DEFINE(B, 8, NONE, GPIO) OMV_GPIO_DEFINE(B, 8, AF4, I2C1) +OMV_GPIO_DEFINE(B, 9, NONE, GPIO) OMV_GPIO_DEFINE(B, 9, AF4, I2C1) OMV_GPIO_DEFINE(C, 0, AF10, OTG_HS) OMV_GPIO_DEFINE(C, 2, AF10, OTG_HS) OMV_GPIO_DEFINE(C, 6, AF13, DCMI) OMV_GPIO_DEFINE(C, 7, AF13, DCMI) OMV_GPIO_DEFINE(C, 9, AF4, I2C3) -OMV_GPIO_DEFINE(C, 10, NONE, GPIO) -OMV_GPIO_DEFINE(C, 11, NONE, GPIO) OMV_GPIO_DEFINE(D, 3, AF13, DCMI) OMV_GPIO_DEFINE(D, 10, AF3, DFSDM1) OMV_GPIO_DEFINE(E, 0, AF13, DCMI) @@ -23,6 +23,7 @@ OMV_GPIO_DEFINE(E, 5, AF13, DCMI) OMV_GPIO_DEFINE(E, 6, AF13, DCMI) OMV_GPIO_DEFINE(E, 7, AF3, DFSDM1) OMV_GPIO_DEFINE(E, 11, NONE, GPIO) +OMV_GPIO_DEFINE(E, 11, AF5, SPI4) OMV_GPIO_DEFINE(E, 12, AF5, SPI4) OMV_GPIO_DEFINE(E, 13, AF5, SPI4) OMV_GPIO_DEFINE(E, 14, AF5, SPI4) @@ -30,5 +31,7 @@ OMV_GPIO_DEFINE(F, 6, AF5, SPI5) OMV_GPIO_DEFINE(F, 7, AF5, SPI5) OMV_GPIO_DEFINE(F, 8, AF5, SPI5) OMV_GPIO_DEFINE(F, 11, AF5, SPI5) +OMV_GPIO_DEFINE(G, 1, NONE, GPIO) OMV_GPIO_DEFINE(G, 3, NONE, GPIO) OMV_GPIO_DEFINE(G, 9, AF13, DCMI) +OMV_GPIO_DEFINE(G, 12, NONE, GPIO) diff --git a/src/omv/boards/ARDUINO_PORTENTA_H7/omv_boardconfig.h b/src/omv/boards/ARDUINO_PORTENTA_H7/omv_boardconfig.h index 30502ccf8..3f229e7a5 100644 --- a/src/omv/boards/ARDUINO_PORTENTA_H7/omv_boardconfig.h +++ b/src/omv/boards/ARDUINO_PORTENTA_H7/omv_boardconfig.h @@ -178,7 +178,6 @@ #define OMV_LINE_BUF_SIZE (11 * 1024) // Image line buffer round(2592 * 2BPP * 2 buffers). #define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data #define OMV_VFS_BUF_SIZE (1K) // VFS struct + FATFS file buffer (624 bytes) -#define OMV_FIR_LEPTON_BUF_SIZE (1K) // FIR Lepton Packet Double Buffer (328 bytes) #define OMV_JPEG_BUF_SIZE (1024 * 1024) // IDE JPEG buffer (header + data). // Memory map. @@ -240,13 +239,14 @@ #define ISC_I2C_ALT_ID (4) #define ISC_I2C_ALT_SPEED (OMV_I2C_SPEED_STANDARD) -// FIR I2C +// Thermal image sensor I2C bus #define FIR_I2C_ID (3) #define FIR_I2C_SPEED (OMV_I2C_SPEED_STANDARD) -//#define SOFT_I2C_SIOC_PIN (&omv_pin_B10_GPIO) -//#define SOFT_I2C_SIOD_PIN (&omv_pin_B11_GPIO) -//#define SOFT_I2C_SPIN_DELAY 64 +// Soft I2C bus +//#define SOFT_I2C_SIOC_PIN (&omv_pin_PH7_GPIO) +//#define SOFT_I2C_SIOD_PIN (&omv_pin_PH8_GPIO) +//#define SOFT_I2C_SPIN_DELAY 64 // GPIO.0 is connected to the sensor module reset pin on the Portenta // breakout board and to the LDO's LDO_ENABLE pin on the Himax shield. @@ -288,6 +288,7 @@ #define DCMI_PXCLK_PIN (&omv_pin_A6_DCMI) // Physical I2C buses. + // I2C bus 3 #define I2C3_ID (3) #define I2C3_SCL_PIN (&omv_pin_H7_I2C3) @@ -298,6 +299,17 @@ #define I2C4_SCL_PIN (&omv_pin_H11_I2C4) #define I2C4_SDA_PIN (&omv_pin_H12_I2C4) +// Physical SPI buses. + +// SPI bus 2 +#define SPI2_ID (2) +#define SPI2_SCLK_PIN (&omv_pin_I1_SPI2) +#define SPI2_MISO_PIN (&omv_pin_C2_SPI2) +#define SPI2_MOSI_PIN (&omv_pin_C3_SPI2) +#define SPI2_SSEL_PIN (&omv_pin_I0_SPI2) +#define SPI2_DMA_TX_CHANNEL (DMA1_Stream4) +#define SPI2_DMA_RX_CHANNEL (DMA1_Stream3) + // SAI4 #define AUDIO_SAI (SAI4_Block_A) // SCKx frequency = SAI_KER_CK / MCKDIV / 2 @@ -351,31 +363,22 @@ #define OMV_DSI_RELEASE_RESET() __HAL_RCC_DSI_RELEASE_RESET() // SPI LCD Interface -#define OMV_SPI_LCD_CONTROLLER (&spi_obj[1]) -#define OMV_SPI_LCD_CONTROLLER_INSTANCE (SPI2) - +#define OMV_SPI_LCD_SPI_BUS (SPI2_ID) #define OMV_SPI_LCD_MOSI_PIN (&omv_pin_C3_SPI2) #define OMV_SPI_LCD_MISO_PIN (&omv_pin_C2_SPI2) #define OMV_SPI_LCD_SCLK_PIN (&omv_pin_I1_SPI2) #define OMV_SPI_LCD_SSEL_PIN (&omv_pin_I0_GPIO) -#define OMV_SPI_LCD_RS_PIN (&omv_pin_K1_GPIO) -#define OMV_SPI_LCD_BL_PIN (&omv_pin_A4_GPIO) -#define OMV_SPI_LCD_RST_PIN (&omv_pin_H15_GPIO) +#define OMV_SPI_LCD_RS_PIN (&omv_pin_C6_GPIO) +#define OMV_SPI_LCD_RST_PIN (&omv_pin_C7_GPIO) -#define OMV_SPI_LCD_BL_DAC (DAC1) -#define OMV_SPI_LCD_BL_DAC_CHANNEL (DAC_CHANNEL_1) -#define OMV_SPI_LCD_BL_DAC_CLK_ENABLE() __HAL_RCC_DAC12_CLK_ENABLE() -#define OMV_SPI_LCD_BL_DAC_CLK_DISABLE() __HAL_RCC_DAC12_CLK_DISABLE() -#define OMV_SPI_LCD_BL_DAC_FORCE_RESET() __HAL_RCC_DAC12_FORCE_RESET() -#define OMV_SPI_LCD_BL_DAC_RELEASE_RESET() __HAL_RCC_DAC12_RELEASE_RESET() +#define OMV_SPI_LCD_DEF_TRIPLE_BUF (true) // FIR Lepton #define OMV_FIR_LEPTON_I2C_BUS (FIR_I2C_ID) #define OMV_FIR_LEPTON_I2C_BUS_SPEED (FIR_I2C_SPEED) -#define OMV_FIR_LEPTON_CONTROLLER (&spi_obj[1]) -#define OMV_FIR_LEPTON_CONTROLLER_INSTANCE (SPI2) +#define OMV_FIR_LEPTON_SPI_BUS (SPI2_ID) #define OMV_FIR_LEPTON_MOSI_PIN (&omv_pin_C3_SPI2) #define OMV_FIR_LEPTON_MISO_PIN (&omv_pin_C2_SPI2) #define OMV_FIR_LEPTON_SCLK_PIN (&omv_pin_I1_SPI2) diff --git a/src/omv/boards/ARDUINO_PORTENTA_H7/omv_pins.h b/src/omv/boards/ARDUINO_PORTENTA_H7/omv_pins.h index 65f77e6bf..0d8619e73 100644 --- a/src/omv/boards/ARDUINO_PORTENTA_H7/omv_pins.h +++ b/src/omv/boards/ARDUINO_PORTENTA_H7/omv_pins.h @@ -7,6 +7,8 @@ OMV_GPIO_DEFINE(B, 2, AF10, SAI4) OMV_GPIO_DEFINE(C, 0, AF10, OTG_HS) OMV_GPIO_DEFINE(C, 2, AF5, SPI2) OMV_GPIO_DEFINE(C, 3, AF5, SPI2) +OMV_GPIO_DEFINE(C, 6, NONE, GPIO) +OMV_GPIO_DEFINE(C, 7, NONE, GPIO) OMV_GPIO_DEFINE(C, 13, NONE, GPIO) OMV_GPIO_DEFINE(C, 15, NONE, GPIO) OMV_GPIO_DEFINE(D, 5, NONE, GPIO) @@ -21,13 +23,12 @@ OMV_GPIO_DEFINE(H, 11, AF13, DCMI) OMV_GPIO_DEFINE(H, 12, AF4, I2C4) OMV_GPIO_DEFINE(H, 12, AF13, DCMI) OMV_GPIO_DEFINE(H, 14, AF13, DCMI) -OMV_GPIO_DEFINE(H, 15, NONE, GPIO) OMV_GPIO_DEFINE(I, 0, NONE, GPIO) +OMV_GPIO_DEFINE(I, 0, AF5, SPI2) OMV_GPIO_DEFINE(I, 1, AF5, SPI2) OMV_GPIO_DEFINE(I, 4, AF13, DCMI) OMV_GPIO_DEFINE(I, 5, AF13, DCMI) OMV_GPIO_DEFINE(I, 6, AF13, DCMI) OMV_GPIO_DEFINE(I, 7, AF13, DCMI) OMV_GPIO_DEFINE(I, 11, AF10, OTG_HS) -OMV_GPIO_DEFINE(K, 1, NONE, GPIO) OMV_GPIO_DEFINE(K, 1, AF1, TIM1) diff --git a/src/omv/boards/OPENMV2/omv_boardconfig.h b/src/omv/boards/OPENMV2/omv_boardconfig.h index 33f7eed4b..fc231d9ad 100644 --- a/src/omv/boards/OPENMV2/omv_boardconfig.h +++ b/src/omv/boards/OPENMV2/omv_boardconfig.h @@ -109,7 +109,6 @@ #define OMV_LINE_BUF_SIZE (2 * 1024) // Image line buffer round(320 * 2BPP * 2 buffers). #define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data #define OMV_VFS_BUF_SIZE (1K) // VFS struct + FATFS file buffer (624 bytes) -#define OMV_FIR_LEPTON_BUF_SIZE (1K) // FIR Lepton Packet Double Buffer (328 bytes) #define OMV_FFS_BUF_SIZE (16K) // Flash filesystem cache #define OMV_JPEG_BUF_SIZE (8 * 1024) // IDE JPEG buffer size (header + data). @@ -174,7 +173,8 @@ #define DCMI_VSYNC_PIN (&omv_pin_B7_DCMI) #define DCMI_PXCLK_PIN (&omv_pin_A6_DCMI) -// Physical I2C buses +// Physical I2C buses. + // I2C bus 1 #define I2C1_ID (1) #define I2C1_SCL_PIN (&omv_pin_B8_I2C1) @@ -185,7 +185,8 @@ #define I2C2_SCL_PIN (&omv_pin_B10_I2C2) #define I2C2_SDA_PIN (&omv_pin_B11_I2C2) -// Physical SPI buses +// Physical SPI buses. + // SPI bus 2 #define SPI2_ID (2) #define SPI2_SCLK_PIN (&omv_pin_B13_SPI2) @@ -198,9 +199,7 @@ #define DMA_REQUEST_SPI2_RX (DMA_CHANNEL_0) // SPI LCD Interface -#define OMV_SPI_LCD_CONTROLLER (&spi_obj[1]) -#define OMV_SPI_LCD_CONTROLLER_INSTANCE (SPI2) - +#define OMV_SPI_LCD_SPI_BUS (SPI2_ID) #define OMV_SPI_LCD_MOSI_PIN (&omv_pin_B15_SPI2) #define OMV_SPI_LCD_MISO_PIN (&omv_pin_B14_SPI2) #define OMV_SPI_LCD_SCLK_PIN (&omv_pin_B13_SPI2) @@ -220,11 +219,11 @@ // FIR Lepton #define OMV_FIR_LEPTON_I2C_BUS (FIR_I2C_ID) #define OMV_FIR_LEPTON_I2C_BUS_SPEED (FIR_I2C_SPEED) -#define OMV_FIR_LEPTON_CONTROLLER (&spi_obj[1]) -#define OMV_FIR_LEPTON_CONTROLLER_INSTANCE (SPI2) +#define OMV_FIR_LEPTON_SPI_BUS (SPI2_ID) #define OMV_FIR_LEPTON_MOSI_PIN (&omv_pin_B15_SPI2) #define OMV_FIR_LEPTON_MISO_PIN (&omv_pin_B14_SPI2) #define OMV_FIR_LEPTON_SCLK_PIN (&omv_pin_B13_SPI2) #define OMV_FIR_LEPTON_SSEL_PIN (&omv_pin_B12_GPIO) + #endif //__OMV_BOARDCONFIG_H__ diff --git a/src/omv/boards/OPENMV3/omv_boardconfig.h b/src/omv/boards/OPENMV3/omv_boardconfig.h index d85df39fa..7a525f5f9 100644 --- a/src/omv/boards/OPENMV3/omv_boardconfig.h +++ b/src/omv/boards/OPENMV3/omv_boardconfig.h @@ -109,7 +109,6 @@ #define OMV_LINE_BUF_SIZE (3 * 1024) // Image line buffer round(640 * 2BPP * 2 buffers). #define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data #define OMV_VFS_BUF_SIZE (1K) // VFS struct + FATFS file buffer (624 bytes) -#define OMV_FIR_LEPTON_BUF_SIZE (1K) // FIR Lepton Packet Double Buffer (328 bytes) #define OMV_FFS_BUF_SIZE (32K) // Flash filesystem cache #define OMV_JPEG_BUF_SIZE (22 * 1024) // IDE JPEG buffer (header + data). @@ -175,6 +174,7 @@ #define DCMI_PXCLK_PIN (&omv_pin_A6_DCMI) // Physical I2C buses. + // I2C bus 1 #define I2C1_ID (1) #define I2C1_SCL_PIN (&omv_pin_B8_I2C1) @@ -185,7 +185,8 @@ #define I2C2_SCL_PIN (&omv_pin_B10_I2C2) #define I2C2_SDA_PIN (&omv_pin_B11_I2C2) -// Physical SPI buses +// Physical SPI buses. + // SPI bus 2 #define SPI2_ID (2) #define SPI2_SCLK_PIN (&omv_pin_B13_SPI2) @@ -198,9 +199,7 @@ #define DMA_REQUEST_SPI2_RX (DMA_CHANNEL_0) // SPI LCD Interface -#define OMV_SPI_LCD_CONTROLLER (&spi_obj[1]) -#define OMV_SPI_LCD_CONTROLLER_INSTANCE (SPI2) - +#define OMV_SPI_LCD_SPI_BUS (SPI2_ID) #define OMV_SPI_LCD_MOSI_PIN (&omv_pin_B15_SPI2) #define OMV_SPI_LCD_MISO_PIN (&omv_pin_B14_SPI2) #define OMV_SPI_LCD_SCLK_PIN (&omv_pin_B13_SPI2) @@ -220,11 +219,11 @@ // FIR Lepton #define OMV_FIR_LEPTON_I2C_BUS (FIR_I2C_ID) #define OMV_FIR_LEPTON_I2C_BUS_SPEED (FIR_I2C_SPEED) -#define OMV_FIR_LEPTON_CONTROLLER (&spi_obj[1]) -#define OMV_FIR_LEPTON_CONTROLLER_INSTANCE (SPI2) +#define OMV_FIR_LEPTON_SPI_BUS (SPI2_ID) #define OMV_FIR_LEPTON_MOSI_PIN (&omv_pin_B15_SPI2) #define OMV_FIR_LEPTON_MISO_PIN (&omv_pin_B14_SPI2) #define OMV_FIR_LEPTON_SCLK_PIN (&omv_pin_B13_SPI2) #define OMV_FIR_LEPTON_SSEL_PIN (&omv_pin_B12_GPIO) + #endif //__OMV_BOARDCONFIG_H__ diff --git a/src/omv/boards/OPENMV4/omv_boardconfig.h b/src/omv/boards/OPENMV4/omv_boardconfig.h index 86e300c21..978f26760 100644 --- a/src/omv/boards/OPENMV4/omv_boardconfig.h +++ b/src/omv/boards/OPENMV4/omv_boardconfig.h @@ -168,7 +168,6 @@ #define OMV_LINE_BUF_SIZE (5 * 1024) // Image line buffer. #define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data #define OMV_VFS_BUF_SIZE (1K) // VFS struct + FATFS file buffer (624 bytes) -#define OMV_FIR_LEPTON_BUF_SIZE (1K) // FIR Lepton Packet Double Buffer (328 bytes) #define OMV_JPEG_BUF_SIZE (32 * 1024) // IDE JPEG buffer (header + data). // Memory map. @@ -231,7 +230,6 @@ // Main image sensor SPI bus #define ISC_SPI_ID (3) -#define ISC_SPI_BAUDRATE (20000000) // WINC1500 WiFi module SPI bus #define WINC_SPI_ID (2) @@ -267,16 +265,19 @@ #define DCMI_PXCLK_PIN (&omv_pin_A6_DCMI) // Physical I2C buses. + // I2C bus 1 #define I2C1_ID (1) #define I2C1_SCL_PIN (&omv_pin_B8_I2C1) #define I2C1_SDA_PIN (&omv_pin_B9_I2C1) + // I2C bus 2 #define I2C2_ID (2) #define I2C2_SCL_PIN (&omv_pin_B10_I2C2) #define I2C2_SDA_PIN (&omv_pin_B11_I2C2) // Physical SPI buses. + // SPI bus 2 #define SPI2_ID (2) #define SPI2_SCLK_PIN (&omv_pin_B13_SPI2) @@ -286,6 +287,7 @@ #define SPI2_DMA_TX_CHANNEL (DMA1_Stream4) #define SPI2_DMA_RX_CHANNEL (DMA1_Stream3) +// SPI bus 3 #define SPI3_ID (3) #define SPI3_SCLK_PIN (&omv_pin_B3_SPI3) #define SPI3_MISO_PIN (&omv_pin_B4_SPI3) @@ -295,9 +297,7 @@ #define SPI3_DMA_RX_CHANNEL (DMA1_Stream2) // SPI LCD Interface -#define OMV_SPI_LCD_CONTROLLER (&spi_obj[1]) -#define OMV_SPI_LCD_CONTROLLER_INSTANCE (SPI2) - +#define OMV_SPI_LCD_SPI_BUS (SPI2_ID) #define OMV_SPI_LCD_MOSI_PIN (&omv_pin_B15_SPI2) #define OMV_SPI_LCD_MISO_PIN (&omv_pin_B14_SPI2) #define OMV_SPI_LCD_SCLK_PIN (&omv_pin_B13_SPI2) @@ -317,11 +317,11 @@ // FIR Lepton #define OMV_FIR_LEPTON_I2C_BUS (FIR_I2C_ID) #define OMV_FIR_LEPTON_I2C_BUS_SPEED (FIR_I2C_SPEED) -#define OMV_FIR_LEPTON_CONTROLLER (&spi_obj[1]) -#define OMV_FIR_LEPTON_CONTROLLER_INSTANCE (SPI2) +#define OMV_FIR_LEPTON_SPI_BUS (SPI2_ID) #define OMV_FIR_LEPTON_MOSI_PIN (&omv_pin_B15_SPI2) #define OMV_FIR_LEPTON_MISO_PIN (&omv_pin_B14_SPI2) #define OMV_FIR_LEPTON_SCLK_PIN (&omv_pin_B13_SPI2) #define OMV_FIR_LEPTON_SSEL_PIN (&omv_pin_B12_GPIO) + #endif //__OMV_BOARDCONFIG_H__ diff --git a/src/omv/boards/OPENMV4P/omv_boardconfig.h b/src/omv/boards/OPENMV4P/omv_boardconfig.h index 8445f6c70..f3ac85402 100644 --- a/src/omv/boards/OPENMV4P/omv_boardconfig.h +++ b/src/omv/boards/OPENMV4P/omv_boardconfig.h @@ -170,7 +170,6 @@ #define OMV_LINE_BUF_SIZE (11 * 1024) // Image line buffer round(2592 * 2BPP * 2 buffers). #define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data #define OMV_VFS_BUF_SIZE (1K) // VFS struct + FATFS file buffer (624 bytes) -#define OMV_FIR_LEPTON_BUF_SIZE (1K) // FIR Lepton Packet Double Buffer (328 bytes) #define OMV_JPEG_BUF_SIZE (1024 * 1024) // IDE JPEG buffer (header + data). // Memory map. @@ -234,7 +233,6 @@ // Main image sensor SPI bus #define ISC_SPI_ID (3) -#define ISC_SPI_BAUDRATE (20000000) // WINC1500 WiFi module SPI bus #define WINC_SPI_ID (2) @@ -270,16 +268,19 @@ #define DCMI_PXCLK_PIN (&omv_pin_A6_DCMI) // Physical I2C buses. + // I2C bus 1 #define I2C1_ID (1) #define I2C1_SCL_PIN (&omv_pin_B8_I2C1) #define I2C1_SDA_PIN (&omv_pin_B9_I2C1) + // I2C bus 2 #define I2C2_ID (2) #define I2C2_SCL_PIN (&omv_pin_B10_I2C2) #define I2C2_SDA_PIN (&omv_pin_B11_I2C2) // Physical SPI buses. + // SPI bus 2 #define SPI2_ID (2) #define SPI2_SCLK_PIN (&omv_pin_B13_SPI2) @@ -289,6 +290,7 @@ #define SPI2_DMA_TX_CHANNEL (DMA1_Stream4) #define SPI2_DMA_RX_CHANNEL (DMA1_Stream3) +// SPI bus 3 #define SPI3_ID (3) #define SPI3_SCLK_PIN (&omv_pin_B3_SPI3) #define SPI3_MISO_PIN (&omv_pin_B4_SPI3) @@ -298,9 +300,7 @@ #define SPI3_DMA_RX_CHANNEL (DMA1_Stream2) // SPI LCD Interface -#define OMV_SPI_LCD_CONTROLLER (&spi_obj[1]) -#define OMV_SPI_LCD_CONTROLLER_INSTANCE (SPI2) - +#define OMV_SPI_LCD_SPI_BUS (SPI2_ID) #define OMV_SPI_LCD_MOSI_PIN (&omv_pin_B15_SPI2) #define OMV_SPI_LCD_MISO_PIN (&omv_pin_B14_SPI2) #define OMV_SPI_LCD_SCLK_PIN (&omv_pin_B13_SPI2) @@ -317,12 +317,13 @@ #define OMV_SPI_LCD_BL_DAC_FORCE_RESET() __HAL_RCC_DAC12_FORCE_RESET() #define OMV_SPI_LCD_BL_DAC_RELEASE_RESET() __HAL_RCC_DAC12_RELEASE_RESET() +#define OMV_SPI_LCD_DEF_TRIPLE_BUF (true) + // FIR Lepton #define OMV_FIR_LEPTON_I2C_BUS (FIR_I2C_ID) #define OMV_FIR_LEPTON_I2C_BUS_SPEED (FIR_I2C_SPEED) -#define OMV_FIR_LEPTON_CONTROLLER (&spi_obj[1]) -#define OMV_FIR_LEPTON_CONTROLLER_INSTANCE (SPI2) +#define OMV_FIR_LEPTON_SPI_BUS (SPI2_ID) #define OMV_FIR_LEPTON_MOSI_PIN (&omv_pin_B15_SPI2) #define OMV_FIR_LEPTON_MISO_PIN (&omv_pin_B14_SPI2) #define OMV_FIR_LEPTON_SCLK_PIN (&omv_pin_B13_SPI2) diff --git a/src/omv/boards/OPENMVPT/omv_boardconfig.h b/src/omv/boards/OPENMVPT/omv_boardconfig.h index 36fc656a2..2d4f9559b 100644 --- a/src/omv/boards/OPENMVPT/omv_boardconfig.h +++ b/src/omv/boards/OPENMVPT/omv_boardconfig.h @@ -175,7 +175,6 @@ #define OMV_LINE_BUF_SIZE (11 * 1024) // Image line buffer round(2592 * 2BPP * 2 buffers). #define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data #define OMV_VFS_BUF_SIZE (1K) // VFS struct + FATFS file buffer (624 bytes) -#define OMV_FIR_LEPTON_BUF_SIZE (1K) // FIR Lepton Packet Double Buffer (328 bytes) #define OMV_JPEG_BUF_SIZE (1024 * 1024) // IDE JPEG buffer (header + data). // Memory map. @@ -272,16 +271,37 @@ #define DCMI_PXCLK_PIN (&omv_pin_A6_DCMI) // Physical I2C buses. + // I2C bus 1 #define I2C1_ID (1) #define I2C1_SCL_PIN (&omv_pin_B8_I2C1) #define I2C1_SDA_PIN (&omv_pin_B9_I2C1) + // I2C bus 2 #define I2C2_ID (2) #define I2C2_SCL_PIN (&omv_pin_B10_I2C2) #define I2C2_SDA_PIN (&omv_pin_B11_I2C2) // Physical SPI buses. + +// SPI bus 2 +#define SPI2_ID (2) +#define SPI2_SCLK_PIN (&omv_pin_B13_SPI2) +#define SPI2_MISO_PIN (&omv_pin_B14_SPI2) +#define SPI2_MOSI_PIN (&omv_pin_B15_SPI2) +#define SPI2_SSEL_PIN (&omv_pin_B12_GPIO) +#define SPI2_DMA_TX_CHANNEL (DMA1_Stream4) +#define SPI2_DMA_RX_CHANNEL (DMA1_Stream3) + +// SPI bus 3 +#define SPI3_ID (3) +#define SPI3_SCLK_PIN (&omv_pin_B3_SPI3) +#define SPI3_MISO_PIN (&omv_pin_B4_SPI3) +#define SPI3_MOSI_PIN (&omv_pin_B5_SPI3) +#define SPI3_SSEL_PIN (&omv_pin_A15_GPIO) +#define SPI3_DMA_TX_CHANNEL (DMA1_Stream7) +#define SPI3_DMA_RX_CHANNEL (DMA1_Stream2) + // SPI bus 5 #define SPI5_ID (5) #define SPI5_SCLK_PIN (&omv_pin_H6_SPI5) @@ -342,17 +362,15 @@ #define OMV_LCD_BL_TIM_PCLK_FREQ() HAL_RCC_GetPCLK1Freq() // SPI LCD Interface -#define OMV_SPI_LCD_CONTROLLER (&spi_obj[1]) -#define OMV_SPI_LCD_CONTROLLER_INSTANCE (SPI2) - +#define OMV_SPI_LCD_SPI_BUS (SPI2_ID) #define OMV_SPI_LCD_MOSI_PIN (&omv_pin_B15_SPI2) #define OMV_SPI_LCD_MISO_PIN (&omv_pin_B14_SPI2) #define OMV_SPI_LCD_SCLK_PIN (&omv_pin_B13_SPI2) - -#define OMV_SPI_LCD_RST_PIN (&omv_pin_D12_GPIO) -#define OMV_SPI_LCD_RS_PIN (&omv_pin_D13_GPIO) #define OMV_SPI_LCD_SSEL_PIN (&omv_pin_B12_GPIO) + +#define OMV_SPI_LCD_RS_PIN (&omv_pin_D13_GPIO) #define OMV_SPI_LCD_BL_PIN (&omv_pin_A5_GPIO) +#define OMV_SPI_LCD_RST_PIN (&omv_pin_D12_GPIO) #define OMV_SPI_LCD_BL_DAC (DAC1) #define OMV_SPI_LCD_BL_DAC_CHANNEL (DAC_CHANNEL_2) @@ -361,6 +379,8 @@ #define OMV_SPI_LCD_BL_DAC_FORCE_RESET() __HAL_RCC_DAC12_FORCE_RESET() #define OMV_SPI_LCD_BL_DAC_RELEASE_RESET() __HAL_RCC_DAC12_RELEASE_RESET() +#define OMV_SPI_LCD_DEF_TRIPLE_BUF (true) + // DVI TFP410PAP I/O #define OMV_DVI_PRESENT #define OMV_DVI_RESET_PIN (&omv_pin_D11_GPIO) @@ -387,9 +407,8 @@ // FIR Lepton #define OMV_FIR_LEPTON_I2C_BUS (ISC_I2C_ID) #define OMV_FIR_LEPTON_I2C_BUS_SPEED (ISC_I2C_SPEED) -#define OMV_FIR_LEPTON_CONTROLLER (&spi_obj[2]) -#define OMV_FIR_LEPTON_CONTROLLER_INSTANCE (SPI3) +#define OMV_FIR_LEPTON_SPI_BUS (SPI3_ID) #define OMV_FIR_LEPTON_MOSI_PIN (&omv_pin_B5_SPI3) #define OMV_FIR_LEPTON_MISO_PIN (&omv_pin_B4_SPI3) #define OMV_FIR_LEPTON_SCLK_PIN (&omv_pin_B3_SPI3) diff --git a/src/omv/ports/stm32/modules/py_fir_lepton.c b/src/omv/modules/py_fir_lepton.c similarity index 82% rename from src/omv/ports/stm32/modules/py_fir_lepton.c rename to src/omv/modules/py_fir_lepton.c index d16081e51..bded8cd14 100644 --- a/src/omv/ports/stm32/modules/py_fir_lepton.c +++ b/src/omv/modules/py_fir_lepton.c @@ -10,12 +10,10 @@ */ #include "omv_boardconfig.h" #if (OMV_ENABLE_FIR_LEPTON == 1) -#include STM32_HAL_H #include "py/nlr.h" #include "py/runtime.h" #include "py/obj.h" #include "py/mphal.h" -#include "spi.h" #include "softtimer.h" #include "crc16.h" @@ -28,7 +26,9 @@ #include "LEPTON_I2C_Reg.h" #include "py_helper.h" +#include "omv_common.h" #include "omv_gpio.h" +#include "omv_spi.h" #define FRAMEBUFFER_COUNT 3 static volatile int framebuffer_tail = 0; @@ -43,7 +43,7 @@ static TIM_HandleTypeDef fir_lepton_mclk_tim_handle = {}; #endif static LEP_CAMERA_PORT_DESC_T fir_lepton_handle = {}; -static DMA_HandleTypeDef fir_lepton_spi_rx_dma = {}; +static omv_spi_t spi_bus = {}; #define VOSPI_HEADER_WORDS (2) // 16-bits #define VOSPI_PID_SIZE_PIXELS (80) // w, 16-bits per pixel @@ -60,7 +60,8 @@ static soft_timer_entry_t flir_lepton_spi_rx_timer = {}; static int fir_lepton_spi_rx_cb_tail = 0; static int fir_lepton_spi_rx_cb_expected_pid = 0; static int fir_lepton_spi_rx_cb_expected_seg = 0; -extern int _fir_lepton_buf[]; +static uint16_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED_DMA(fir_lepton_buf[VOSPI_BUFFER_SIZE]), ".dma_buffer"); +static void fir_lepton_spi_callback(omv_spi_t *spi, void *userdata, void *buf); STATIC mp_obj_t fir_lepton_spi_resync_callback(mp_obj_t unused) { // For triple buffering we are never drawing where tail or head @@ -70,9 +71,15 @@ STATIC mp_obj_t fir_lepton_spi_resync_callback(mp_obj_t unused) { fir_lepton_spi_rx_cb_tail = (fir_lepton_spi_rx_cb_tail + 1) % FRAMEBUFFER_COUNT; } - omv_gpio_write(OMV_FIR_LEPTON_SSEL_PIN, 0); - HAL_SPI_Receive_DMA(OMV_FIR_LEPTON_CONTROLLER->spi, (uint8_t *) &_fir_lepton_buf, VOSPI_BUFFER_SIZE); + omv_spi_transfer_t spi_xfer = { + .rxbuf = fir_lepton_buf, + .size = VOSPI_BUFFER_SIZE, + .flags = OMV_SPI_XFER_DMA | OMV_SPI_XFER_16_BIT, + .callback = fir_lepton_spi_callback, + }; + omv_gpio_write(OMV_FIR_LEPTON_SSEL_PIN, 0); + omv_spi_transfer_start(&spi_bus, &spi_xfer); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(fir_lepton_spi_resync_callback_obj, fir_lepton_spi_resync_callback); @@ -106,7 +113,9 @@ static bool fir_lepton_spi_check_crc(const uint16_t *base) { static mp_obj_t fir_lepton_frame_cb = mp_const_none; -void fir_lepton_spi_callback(const uint16_t *base) { +void fir_lepton_spi_callback(omv_spi_t *spi, void *userdata, void *buf) { + const uint16_t *base = (uint16_t *) buf; + int id = base[0]; // Ignore don't care packets. @@ -136,7 +145,7 @@ void fir_lepton_spi_callback(const uint16_t *base) { || (fir_lepton_3 && (pid == 20) && (seg != fir_lepton_spi_rx_cb_expected_seg))) { fir_lepton_spi_rx_cb_expected_pid = 0; fir_lepton_spi_rx_cb_expected_seg = 0; - HAL_SPI_Abort_IT(OMV_FIR_LEPTON_CONTROLLER->spi); + omv_spi_transfer_abort(&spi_bus); omv_gpio_write(OMV_FIR_LEPTON_SSEL_PIN, 1); fir_lepton_spi_resync(); return; @@ -184,14 +193,6 @@ void fir_lepton_spi_callback(const uint16_t *base) { } } -static void fir_lepton_spi_callback_half(SPI_HandleTypeDef *hspi) { - fir_lepton_spi_callback((uint16_t *) &_fir_lepton_buf); -} - -static void fir_lepton_spi_callback_full(SPI_HandleTypeDef *hspi) { - fir_lepton_spi_callback(((uint16_t *) &_fir_lepton_buf) + VOSPI_PACKET_SIZE); -} - #if defined(OMV_FIR_LEPTON_VSYNC_PIN) static mp_obj_t fir_lepton_vsync_cb = NULL; @@ -203,7 +204,7 @@ static void fir_lepton_extint_callback(void *data) { #endif void fir_lepton_deinit() { - HAL_SPI_Abort(OMV_FIR_LEPTON_CONTROLLER->spi); + omv_spi_transfer_abort(&spi_bus); fir_lepton_spi_rx_cb_expected_pid = 0; fir_lepton_spi_rx_cb_expected_seg = 0; fb_alloc_free_till_mark_past_mark_permanent(); @@ -217,48 +218,38 @@ void fir_lepton_deinit() { omv_gpio_deinit(OMV_FIR_LEPTON_MCLK_PIN); #endif - spi_deinit(OMV_FIR_LEPTON_CONTROLLER); + omv_spi_deinit(&spi_bus); - // Do not put in HAL_SPI_MspDeinit as other modules may share the SPI bus. - omv_gpio_deinit(OMV_FIR_LEPTON_MOSI_PIN); - omv_gpio_deinit(OMV_FIR_LEPTON_MISO_PIN); - omv_gpio_deinit(OMV_FIR_LEPTON_SCLK_PIN); - omv_gpio_deinit(OMV_FIR_LEPTON_SSEL_PIN); #if defined(OMV_FIR_LEPTON_RESET_PIN) omv_gpio_deinit(OMV_FIR_LEPTON_RESET_PIN); #endif + #if defined(OMV_FIR_LEPTON_POWER_PIN) omv_gpio_deinit(OMV_FIR_LEPTON_POWER_PIN); #endif } int fir_lepton_init(omv_i2c_t *bus, int *w, int *h, int *refresh, int *resolution) { - SPI_HandleTypeDef *hspi = OMV_FIR_LEPTON_CONTROLLER->spi; + omv_spi_config_t spi_config; + omv_spi_default_config(&spi_config, OMV_FIR_LEPTON_SPI_BUS); - hspi->Init.Mode = SPI_MODE_MASTER; - hspi->Init.Direction = SPI_DIRECTION_2LINES_RXONLY; - hspi->Init.NSS = SPI_NSS_SOFT; - hspi->Init.TIMode = SPI_TIMODE_DISABLE; - hspi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; - #if defined(MCU_SERIES_H7) - hspi->Init.FifoThreshold = SPI_FIFO_THRESHOLD_02DATA; - hspi->Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; + #if OMV_FIR_LEPTON_RX_CLK_DIV + spi_config.baudrate = VOSPI_CLOCK_SPEED / OMV_FIR_LEPTON_RX_CLK_DIV; + #else + spi_config.baudrate = VOSPI_CLOCK_SPEED; #endif - spi_set_params(OMV_FIR_LEPTON_CONTROLLER, 0xffffffff, VOSPI_CLOCK_SPEED, 1, 1, 16, 0); - spi_init(OMV_FIR_LEPTON_CONTROLLER, true); - HAL_SPI_RegisterCallback(hspi, HAL_SPI_RX_COMPLETE_CB_ID, fir_lepton_spi_callback_full); - HAL_SPI_RegisterCallback(hspi, HAL_SPI_RX_HALF_COMPLETE_CB_ID, fir_lepton_spi_callback_half); + spi_config.bus_mode = OMV_SPI_BUS_RX; + spi_config.nss_enable = false; + spi_config.dma_flags = OMV_SPI_DMA_CIRCULAR | OMV_SPI_DMA_DOUBLE; + omv_spi_init(&spi_bus, &spi_config); - // Do not put in HAL_SPI_MspInit as other modules share the SPI2/3 bus. - omv_gpio_config(OMV_FIR_LEPTON_MOSI_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_MED, -1); - omv_gpio_config(OMV_FIR_LEPTON_MISO_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_MED, -1); - omv_gpio_config(OMV_FIR_LEPTON_SCLK_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_MED, -1); - omv_gpio_config(OMV_FIR_LEPTON_SSEL_PIN, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_LOW, -1); omv_gpio_write(OMV_FIR_LEPTON_SSEL_PIN, 1); + #if defined(OMV_FIR_LEPTON_RESET_PIN) omv_gpio_config(OMV_FIR_LEPTON_RESET_PIN, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_LOW, -1); omv_gpio_write(OMV_FIR_LEPTON_RESET_PIN, 1); #endif + #if defined(OMV_FIR_LEPTON_POWER_PIN) omv_gpio_config(OMV_FIR_LEPTON_POWER_PIN, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_LOW, -1); omv_gpio_write(OMV_FIR_LEPTON_POWER_PIN, 1); @@ -400,38 +391,6 @@ int fir_lepton_init(omv_i2c_t *bus, int *w, int *h, int *refresh, int *resolutio framebuffers[i] = (uint16_t *) fb_alloc0(flir_w * flir_h * sizeof(uint16_t), FB_ALLOC_NO_HINT); } - dma_init(&fir_lepton_spi_rx_dma, OMV_FIR_LEPTON_CONTROLLER->rx_dma_descr, DMA_PERIPH_TO_MEMORY, hspi); - - hspi->hdmatx = NULL; - hspi->hdmarx = &fir_lepton_spi_rx_dma; - - #if defined(MCU_SERIES_H7) - fir_lepton_spi_rx_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; - #else - fir_lepton_spi_rx_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; - #endif - fir_lepton_spi_rx_dma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; - fir_lepton_spi_rx_dma.Init.Mode = DMA_CIRCULAR; - fir_lepton_spi_rx_dma.Init.FIFOMode = DMA_FIFOMODE_ENABLE; - fir_lepton_spi_rx_dma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL; - fir_lepton_spi_rx_dma.Init.MemBurst = DMA_MBURST_SINGLE; - fir_lepton_spi_rx_dma.Init.PeriphBurst = DMA_PBURST_SINGLE; - - DMA_Stream_TypeDef *dma_chan = (DMA_Stream_TypeDef *) fir_lepton_spi_rx_dma.Instance; - dma_chan->CR = - (dma_chan->CR & ~DMA_SxCR_PSIZE_Msk) | - #if defined(MCU_SERIES_H7) - DMA_PDATAALIGN_WORD; - #else - DMA_PDATAALIGN_HALFWORD; - #endif - dma_chan->CR = (dma_chan->CR & ~DMA_SxCR_MSIZE_Msk) | DMA_MDATAALIGN_WORD; - dma_chan->CR = (dma_chan->CR & ~DMA_SxCR_CIRC_Msk) | DMA_CIRCULAR; - dma_chan->FCR = (dma_chan->FCR & ~DMA_SxFCR_DMDIS_Msk) | DMA_FIFOMODE_ENABLE; - dma_chan->FCR = (dma_chan->FCR & ~DMA_SxFCR_FTH_Msk) | DMA_FIFO_THRESHOLD_1QUARTERFULL; - dma_chan->CR = (dma_chan->CR & ~DMA_SxCR_MBURST_Msk) | DMA_MBURST_SINGLE; - dma_chan->CR = (dma_chan->CR & ~DMA_SxCR_PBURST_Msk) | DMA_PBURST_SINGLE; - fb_alloc_mark_permanent(); fir_lepton_spi_resync(); return 0; @@ -476,7 +435,7 @@ static const uint16_t *fir_lepton_get_frame(int timeout) { mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Timeout!")); } - __WFI(); + MICROPY_EVENT_POLL_HOOK } } diff --git a/src/omv/ports/stm32/modules/py_fir_lepton.h b/src/omv/modules/py_fir_lepton.h similarity index 100% rename from src/omv/ports/stm32/modules/py_fir_lepton.h rename to src/omv/modules/py_fir_lepton.h diff --git a/src/omv/ports/stm32/modules/py_lcd.c b/src/omv/modules/py_lcd.c similarity index 88% rename from src/omv/ports/stm32/modules/py_lcd.c rename to src/omv/modules/py_lcd.c index 019ba42a2..ada7029d2 100644 --- a/src/omv/ports/stm32/modules/py_lcd.c +++ b/src/omv/modules/py_lcd.c @@ -11,12 +11,11 @@ #include "omv_boardconfig.h" #if MICROPY_PY_LCD -#include STM32_HAL_H + #include "py/obj.h" #include "py/nlr.h" #include "py/runtime.h" #include "pendsv.h" -#include "spi.h" #include "py_lcd_cec.h" #include "py_lcd_touch.h" @@ -24,6 +23,7 @@ #include "py_image.h" #include "extmod/machine_i2c.h" #include "omv_gpio.h" +#include "omv_spi.h" #define FRAMEBUFFER_COUNT 3 static int framebuffer_tail = 0; @@ -72,8 +72,8 @@ lcd_resolution = LCD_DISPLAY_QVGA; static int lcd_refresh = 0; static int lcd_intensity = 0; -#ifdef OMV_SPI_LCD_CONTROLLER -static DMA_HandleTypeDef spi_tx_dma = {}; +#ifdef OMV_SPI_LCD_SPI_BUS +static omv_spi_t spi_bus = {}; static volatile enum { SPI_TX_CB_IDLE, @@ -84,46 +84,63 @@ static volatile enum { } spi_tx_cb_state = SPI_TX_CB_IDLE; +static void spi_transmit(uint8_t *txdata, uint16_t size, bool end) { + omv_spi_transfer_t spi_xfer = { + .txbuf = txdata, + .size = size, + .timeout = OMV_SPI_MAX_TIMEOUT, + .flags = OMV_SPI_XFER_BLOCKING + }; + + omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); + omv_spi_transfer_start(&spi_bus, &spi_xfer); + + if (end) { + omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + } +} + +static void spi_transmit_16(uint8_t *txdata, uint16_t size) { + omv_spi_transfer_t spi_xfer = { + .txbuf = txdata, + .size = (!lcd_byte_reverse) ? size : (size * 2), + .timeout = OMV_SPI_MAX_TIMEOUT, + .flags = OMV_SPI_XFER_BLOCKING | ((!lcd_byte_reverse) ? OMV_SPI_XFER_16_BIT : 0) + }; + + omv_spi_transfer_start(&spi_bus, &spi_xfer); +} + static void spi_config_deinit() { if (lcd_triple_buffer) { - HAL_SPI_Abort(OMV_SPI_LCD_CONTROLLER->spi); + omv_spi_transfer_abort(&spi_bus); spi_tx_cb_state = SPI_TX_CB_IDLE; fb_alloc_free_till_mark_past_mark_permanent(); } - spi_deinit(OMV_SPI_LCD_CONTROLLER); + omv_spi_deinit(&spi_bus); - // Do not put in HAL_SPI_MspDeinit as other modules share the SPI2 bus. - omv_gpio_deinit(OMV_SPI_LCD_MOSI_PIN); - omv_gpio_deinit(OMV_SPI_LCD_SCLK_PIN); - omv_gpio_deinit(OMV_SPI_LCD_RST_PIN); omv_gpio_deinit(OMV_SPI_LCD_RS_PIN); - omv_gpio_deinit(OMV_SPI_LCD_SSEL_PIN); + omv_gpio_deinit(OMV_SPI_LCD_RST_PIN); } -static void spi_lcd_callback(SPI_HandleTypeDef *hspi); +static void spi_config_init(int w, int h, int refresh_rate, bool triple_buffer, bool bgr, bool byte_reverse) { + omv_spi_config_t spi_config; + omv_spi_default_config(&spi_config, OMV_SPI_LCD_SPI_BUS); -static void spi_config_init(int w, int h, int refresh_rate, bool triple_buffer, bool bgr) { - SPI_HandleTypeDef *hspi = OMV_SPI_LCD_CONTROLLER->spi; + spi_config.baudrate = w * h * refresh_rate * 16; + spi_config.bus_mode = OMV_SPI_BUS_TX; + spi_config.nss_enable = false; + spi_config.dma_flags = triple_buffer ? OMV_SPI_DMA_NORMAL : 0; + omv_spi_init(&spi_bus, &spi_config); - hspi->Init.Mode = SPI_MODE_MASTER; - hspi->Init.Direction = SPI_DIRECTION_1LINE; - hspi->Init.NSS = SPI_NSS_SOFT; - hspi->Init.TIMode = SPI_TIMODE_DISABLE; - hspi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; - spi_set_params(OMV_SPI_LCD_CONTROLLER, 0xffffffff, w * h * refresh_rate * 16, 0, 0, 8, 0); - spi_init(OMV_SPI_LCD_CONTROLLER, true); - HAL_SPI_RegisterCallback(hspi, HAL_SPI_TX_COMPLETE_CB_ID, spi_lcd_callback); + omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); - // Do not put in HAL_SPI_MspInit as other modules share the SPI2 bus. - omv_gpio_config(OMV_SPI_LCD_MOSI_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1); - omv_gpio_config(OMV_SPI_LCD_SCLK_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1); omv_gpio_config(OMV_SPI_LCD_RST_PIN, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_LOW, -1); omv_gpio_write(OMV_SPI_LCD_RST_PIN, 1); + omv_gpio_config(OMV_SPI_LCD_RS_PIN, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_LOW, -1); omv_gpio_write(OMV_SPI_LCD_RS_PIN, 1); - omv_gpio_config(OMV_SPI_LCD_SSEL_PIN, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_LOW, -1); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); omv_gpio_write(OMV_SPI_LCD_RST_PIN, 0); mp_hal_delay_ms(100); @@ -131,29 +148,19 @@ static void spi_config_init(int w, int h, int refresh_rate, bool triple_buffer, mp_hal_delay_ms(100); omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_Transmit(hspi, (uint8_t []) {0x11}, 1, HAL_MAX_DELAY); // sleep out - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + spi_transmit((uint8_t []) {0x11}, 1, true); // sleep out omv_gpio_write(OMV_SPI_LCD_RS_PIN, 1); mp_hal_delay_ms(120); omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_Transmit(hspi, (uint8_t []) {0x36}, 1, HAL_MAX_DELAY); // memory data access control - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + spi_transmit((uint8_t []) {0x36}, 1, true); // memory data access control omv_gpio_write(OMV_SPI_LCD_RS_PIN, 1); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_Transmit(hspi, (uint8_t []) {bgr ? 0xC8 : 0xC0}, 1, HAL_MAX_DELAY); // argument - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + spi_transmit((uint8_t []) {bgr ? 0xC8 : 0xC0}, 1, true); // argument omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_Transmit(hspi, (uint8_t []) {0x3A}, 1, HAL_MAX_DELAY); // interface pixel format - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + spi_transmit((uint8_t []) {0x3A}, 1, true); // interface pixel format omv_gpio_write(OMV_SPI_LCD_RS_PIN, 1); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_Transmit(hspi, (uint8_t []) {0x05}, 1, HAL_MAX_DELAY); // argument - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + spi_transmit((uint8_t []) {0x05}, 1, true); // argument if (triple_buffer) { fb_alloc_mark(); @@ -165,38 +172,6 @@ static void spi_config_init(int w, int h, int refresh_rate, bool triple_buffer, framebuffers[i] = (uint16_t *) fb_alloc0(w * h * sizeof(uint16_t), FB_ALLOC_CACHE_ALIGN); } - dma_init(&spi_tx_dma, OMV_SPI_LCD_CONTROLLER->tx_dma_descr, DMA_MEMORY_TO_PERIPH, hspi); - hspi->hdmatx = &spi_tx_dma; - hspi->hdmarx = NULL; - #if defined(MCU_SERIES_H7) - spi_tx_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; - #else - spi_tx_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; - #endif - spi_tx_dma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; - spi_tx_dma.Init.FIFOMode = DMA_FIFOMODE_ENABLE; - spi_tx_dma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; - spi_tx_dma.Init.MemBurst = DMA_MBURST_INC4; - #if defined(MCU_SERIES_H7) - spi_tx_dma.Init.PeriphBurst = DMA_PBURST_INC4; - #else - spi_tx_dma.Init.PeriphBurst = DMA_PBURST_SINGLE; - #endif - DMA_Stream_TypeDef *dma_chan = spi_tx_dma.Instance; - #if defined(MCU_SERIES_H7) - dma_chan->CR = (dma_chan->CR & ~DMA_SxCR_PSIZE_Msk) | DMA_PDATAALIGN_WORD; - #else - dma_chan->CR = (dma_chan->CR & ~DMA_SxCR_PSIZE_Msk) | DMA_PDATAALIGN_HALFWORD; - #endif - dma_chan->CR = (dma_chan->CR & ~DMA_SxCR_MSIZE_Msk) | DMA_MDATAALIGN_WORD; - dma_chan->FCR = (dma_chan->FCR & ~DMA_SxFCR_DMDIS_Msk) | DMA_FIFOMODE_ENABLE; - dma_chan->FCR = (dma_chan->FCR & ~DMA_SxFCR_FTH_Msk) | DMA_FIFO_THRESHOLD_FULL; - dma_chan->CR = (dma_chan->CR & ~DMA_SxCR_MBURST_Msk) | DMA_MBURST_INC4; - #if defined(MCU_SERIES_H7) - dma_chan->CR = (dma_chan->CR & ~DMA_SxCR_PBURST_Msk) | DMA_PBURST_INC4; - #else - dma_chan->CR = (dma_chan->CR & ~DMA_SxCR_PBURST_Msk) | DMA_PBURST_SINGLE; - #endif fb_alloc_mark_permanent(); } } @@ -207,82 +182,89 @@ static const uint8_t display_off[] = {0x28}; static const uint8_t display_on[] = {0x29}; static const uint8_t memory_write[] = {0x2C}; -static void spi_lcd_callback(SPI_HandleTypeDef *hspi) { +static void spi_lcd_callback(omv_spi_t *spi, void *userdata, void *buf) { if (lcd_type == LCD_SHIELD) { - static uint16_t *spi_tx_cb_state_memory_write_addr = NULL; + static uint8_t *spi_tx_cb_state_memory_write_addr = NULL; static size_t spi_tx_cb_state_memory_write_count = 0; static bool spi_tx_cb_state_memory_write_first = false; switch (spi_tx_cb_state) { case SPI_TX_CB_MEMORY_WRITE_CMD: { + omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); if (!spi_tx_cb_state_on[framebuffer_tail]) { - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); - omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); spi_tx_cb_state = SPI_TX_CB_DISPLAY_OFF; framebuffer_head = framebuffer_tail; omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_Transmit_IT(hspi, (uint8_t *) display_off, sizeof(display_off)); + omv_spi_transfer_t spi_xfer = { + .txbuf = (uint8_t *) display_off, + .size = sizeof(display_off), + .flags = OMV_SPI_XFER_NONBLOCK, + .callback = spi_lcd_callback, + }; + omv_spi_transfer_start(&spi_bus, &spi_xfer); } else { - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); - omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); spi_tx_cb_state = SPI_TX_CB_MEMORY_WRITE; - spi_tx_cb_state_memory_write_addr = framebuffers[framebuffer_tail]; + spi_tx_cb_state_memory_write_addr = (uint8_t *) framebuffers[framebuffer_tail]; spi_tx_cb_state_memory_write_count = lcd_width * lcd_height; + if (lcd_byte_reverse) { + spi_tx_cb_state_memory_write_count *= 2; + } spi_tx_cb_state_memory_write_first = true; framebuffer_head = framebuffer_tail; omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - // When starting the interrupt chain the first HAL_SPI_Transmit_IT is not executed - // in interrupt context. So, disable interrupts for the first HAL_SPI_Transmit_IT so + // When starting the interrupt chain the first transfer is not executed + // in interrupt context. So, disable interrupts for the first transfer so // that it completes first and unlocks the SPI bus before allowing the interrupt // it causes to trigger starting the interrupt chain. + omv_spi_transfer_t spi_xfer = { + .txbuf = (uint8_t *) memory_write, + .size = sizeof(memory_write), + .flags = OMV_SPI_XFER_NONBLOCK, + .callback = spi_lcd_callback, + }; uint32_t irq_state = disable_irq(); - HAL_SPI_Transmit_IT(hspi, (uint8_t *) memory_write, sizeof(memory_write)); + omv_spi_transfer_start(&spi_bus, &spi_xfer); enable_irq(irq_state); } break; } case SPI_TX_CB_MEMORY_WRITE: { - uint16_t *addr = spi_tx_cb_state_memory_write_addr; - size_t count = IM_MIN(spi_tx_cb_state_memory_write_count, (65536 - 8u)); - spi_tx_cb_state = - (spi_tx_cb_state_memory_write_count > (65536 - 8u)) ? SPI_TX_CB_MEMORY_WRITE : SPI_TX_CB_DISPLAY_ON; - spi_tx_cb_state_memory_write_addr += count; + size_t spi_tx_cb_state_memory_write_limit = (!lcd_byte_reverse) + ? OMV_SPI_MAX_16BIT_XFER : OMV_SPI_MAX_8BIT_XFER; + uint8_t *addr = spi_tx_cb_state_memory_write_addr; + size_t count = IM_MIN(spi_tx_cb_state_memory_write_count, spi_tx_cb_state_memory_write_limit); + spi_tx_cb_state = (spi_tx_cb_state_memory_write_count > spi_tx_cb_state_memory_write_limit) + ? SPI_TX_CB_MEMORY_WRITE : SPI_TX_CB_DISPLAY_ON; + spi_tx_cb_state_memory_write_addr += (!lcd_byte_reverse) ? (count * 2) : count; spi_tx_cb_state_memory_write_count -= count; if (spi_tx_cb_state_memory_write_first) { omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); omv_gpio_write(OMV_SPI_LCD_RS_PIN, 1); spi_tx_cb_state_memory_write_first = false; - if (!lcd_byte_reverse) { - hspi->Init.DataSize = SPI_DATASIZE_16BIT; - #if defined(MCU_SERIES_H7) - hspi->Instance->CFG1 = (hspi->Instance->CFG1 & ~SPI_CFG1_DSIZE_Msk) | SPI_DATASIZE_16BIT; - hspi->Instance->CFG1 = (hspi->Instance->CFG1 & ~SPI_CFG1_FTHLV_Msk) | SPI_FIFO_THRESHOLD_08DATA; - #elif defined(MCU_SERIES_F7) - hspi->Instance->CR2 = (hspi->Instance->CR2 & ~SPI_CR2_DS_Msk) | SPI_DATASIZE_16BIT; - #elif defined(MCU_SERIES_F4) - hspi->Instance->CR1 = (hspi->Instance->CR1 & ~SPI_CR1_DFF_Msk) | SPI_DATASIZE_16BIT; - #endif - } omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); } - HAL_SPI_Transmit_DMA(hspi, (uint8_t *) addr, count); + omv_spi_transfer_t spi_xfer = { + .txbuf = addr, + .size = count, + .flags = OMV_SPI_XFER_DMA | ((!lcd_byte_reverse) ? OMV_SPI_XFER_16_BIT : 0), + .callback = spi_lcd_callback, + }; + omv_spi_transfer_start(&spi_bus, &spi_xfer); break; } case SPI_TX_CB_DISPLAY_ON: { omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); spi_tx_cb_state = SPI_TX_CB_MEMORY_WRITE_CMD; - hspi->Init.DataSize = SPI_DATASIZE_8BIT; - #if defined(MCU_SERIES_H7) - hspi->Instance->CFG1 = (hspi->Instance->CFG1 & ~SPI_CFG1_DSIZE_Msk) | SPI_DATASIZE_8BIT; - hspi->Instance->CFG1 = (hspi->Instance->CFG1 & ~SPI_CFG1_FTHLV_Msk) | SPI_FIFO_THRESHOLD_01DATA; - #elif defined(MCU_SERIES_F7) - hspi->Instance->CR2 = (hspi->Instance->CR2 & ~SPI_CR2_DS_Msk) | SPI_DATASIZE_8BIT; - #elif defined(MCU_SERIES_F4) - hspi->Instance->CR1 = (hspi->Instance->CR1 & ~SPI_CR1_DFF_Msk) | SPI_DATASIZE_8BIT; - #endif omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_Transmit_IT(hspi, (uint8_t *) display_on, sizeof(display_on)); + omv_spi_transfer_t spi_xfer = { + .txbuf = (uint8_t *) display_on, + .size = sizeof(display_on), + .flags = OMV_SPI_XFER_NONBLOCK, + .callback = spi_lcd_callback, + }; + omv_spi_transfer_start(&spi_bus, &spi_xfer); break; } case SPI_TX_CB_DISPLAY_OFF: { @@ -314,12 +296,12 @@ static void spi_lcd_kick() { } spi_tx_cb_state = SPI_TX_CB_MEMORY_WRITE_CMD; - spi_lcd_callback(OMV_SPI_LCD_CONTROLLER->spi); + spi_lcd_callback(&spi_bus, NULL, NULL); } } static void spi_lcd_draw_image_cb(int x_start, int x_end, int y_row, imlib_draw_row_data_t *data) { - HAL_SPI_Transmit(OMV_SPI_LCD_CONTROLLER->spi, data->dst_row_override, lcd_width, HAL_MAX_DELAY); + spi_transmit_16(data->dst_row_override, lcd_width); } static void spi_lcd_display(image_t *src_img, int dst_x_start, int dst_y_start, @@ -335,35 +317,23 @@ static void spi_lcd_display(image_t *src_img, int dst_x_start, int dst_y_start, x_scale, y_scale, roi, alpha, alpha_palette, hint, &x0, &x1, &y0, &y1); if (!lcd_triple_buffer) { - SPI_HandleTypeDef *hspi = OMV_SPI_LCD_CONTROLLER->spi; dst_img.data = fb_alloc0(lcd_width * sizeof(uint16_t), FB_ALLOC_NO_HINT); omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - // memory write - HAL_SPI_Transmit(hspi, (uint8_t *) memory_write, sizeof(memory_write), HAL_MAX_DELAY); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + spi_transmit((uint8_t *) memory_write, sizeof(memory_write), true); omv_gpio_write(OMV_SPI_LCD_RS_PIN, 1); omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - hspi->Init.DataSize = SPI_DATASIZE_16BIT; - #if defined(MCU_SERIES_H7) - hspi->Instance->CFG1 = (hspi->Instance->CFG1 & ~SPI_CFG1_DSIZE_Msk) | SPI_DATASIZE_16BIT; - #elif defined(MCU_SERIES_F7) - hspi->Instance->CR2 = (hspi->Instance->CR2 & ~SPI_CR2_DS_Msk) | SPI_DATASIZE_16BIT; - #elif defined(MCU_SERIES_F4) - hspi->Instance->CR1 = (hspi->Instance->CR1 & ~SPI_CR1_DFF_Msk) | SPI_DATASIZE_16BIT; - #endif if (black) { // zero the whole image for (int i = 0; i < lcd_height; i++) { - HAL_SPI_Transmit(hspi, dst_img.data, lcd_width, HAL_MAX_DELAY); + spi_transmit_16(dst_img.data, lcd_width); } } else { // Zero the top rows for (int i = 0; i < y0; i++) { - HAL_SPI_Transmit(hspi, dst_img.data, lcd_width, HAL_MAX_DELAY); + spi_transmit_16(dst_img.data, lcd_width); } // Transmits left/right parts already zeroed... @@ -375,25 +345,16 @@ static void spi_lcd_display(image_t *src_img, int dst_x_start, int dst_y_start, if (y1 < lcd_height) { memset(dst_img.data, 0, lcd_width * sizeof(uint16_t)); } + for (int i = y1; i < lcd_height; i++) { - HAL_SPI_Transmit(hspi, dst_img.data, lcd_width, HAL_MAX_DELAY); + spi_transmit_16(dst_img.data, lcd_width); } } - hspi->Init.DataSize = SPI_DATASIZE_8BIT; - #if defined(MCU_SERIES_H7) - hspi->Instance->CFG1 = (hspi->Instance->CFG1 & ~SPI_CFG1_DSIZE_Msk) | SPI_DATASIZE_8BIT; - #elif defined(MCU_SERIES_F7) - hspi->Instance->CR2 = (hspi->Instance->CR2 & ~SPI_CR2_DS_Msk) | SPI_DATASIZE_8BIT; - #elif defined(MCU_SERIES_F4) - hspi->Instance->CR1 = (hspi->Instance->CR1 & ~SPI_CR1_DFF_Msk) | SPI_DATASIZE_8BIT; - #endif omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_Transmit(hspi, (uint8_t *) display_on, sizeof(display_on), HAL_MAX_DELAY); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + spi_transmit((uint8_t *) display_on, sizeof(display_on), true); omv_gpio_write(OMV_SPI_LCD_RS_PIN, 1); fb_free(); @@ -459,9 +420,7 @@ static void spi_lcd_display(image_t *src_img, int dst_x_start, int dst_y_start, static void spi_lcd_clear() { if (!lcd_triple_buffer) { omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_Transmit(OMV_SPI_LCD_CONTROLLER->spi, (uint8_t *) display_off, sizeof(display_off), HAL_MAX_DELAY); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + spi_transmit((uint8_t *) display_off, sizeof(display_off), true); omv_gpio_write(OMV_SPI_LCD_RS_PIN, 1); } else { // For triple buffering we are never drawing where tail or head (which may instantly update to @@ -529,7 +488,7 @@ static void spi_lcd_set_backlight(int intensity) { lcd_intensity = intensity; } #endif // OMV_SPI_LCD_BL_PIN -#endif // OMV_SPI_LCD_CONTROLLER +#endif // OMV_SPI_LCD_SPI_BUS #ifdef OMV_LCD_CONTROLLER static const uint32_t resolution_clock[] = { @@ -1303,7 +1262,7 @@ static void ltdc_dvi_register_hotplug_cb(mp_obj_t cb) { STATIC mp_obj_t py_lcd_deinit() { switch (lcd_type) { - #ifdef OMV_SPI_LCD_CONTROLLER + #ifdef OMV_SPI_LCD_SPI_BUS case LCD_SHIELD: { spi_config_deinit(); #ifdef OMV_SPI_LCD_BL_PIN @@ -1361,7 +1320,7 @@ STATIC mp_obj_t py_lcd_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args int type = py_helper_keyword_int(n_args, args, 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_type), LCD_SHIELD); switch (type) { - #ifdef OMV_SPI_LCD_CONTROLLER + #ifdef OMV_SPI_LCD_SPI_BUS case LCD_SHIELD: { int w = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_width), 128); if ((w <= 0) || (32767 < w)) { @@ -1375,10 +1334,16 @@ STATIC mp_obj_t py_lcd_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args if ((refresh_rate < 30) || (120 < refresh_rate)) { mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Invalid Refresh Rate!")); } - bool triple_buffer = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_triple_buffer), false); + bool triple_buffer_def = false; + #ifdef OMV_SPI_LCD_DEF_TRIPLE_BUF + triple_buffer_def = OMV_SPI_LCD_DEF_TRIPLE_BUF; + #endif + bool triple_buffer = py_helper_keyword_int(n_args, args, 4, kw_args, + MP_OBJ_NEW_QSTR(MP_QSTR_triple_buffer), triple_buffer_def); bool bgr = py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bgr), false); - bool byte_reverse = py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_byte_reverse), false); - spi_config_init(w, h, refresh_rate, triple_buffer, bgr); + bool byte_reverse = py_helper_keyword_int(n_args, args, 6, kw_args, + MP_OBJ_NEW_QSTR(MP_QSTR_byte_reverse), false); + spi_config_init(w, h, refresh_rate, triple_buffer, bgr, byte_reverse); #ifdef OMV_SPI_LCD_BL_PIN spi_lcd_set_backlight(255); // to on state #endif @@ -1517,7 +1482,7 @@ STATIC mp_obj_t py_lcd_set_backlight(mp_obj_t intensity_obj) { } switch (lcd_type) { - #if defined(OMV_SPI_LCD_CONTROLLER) && defined(OMV_SPI_LCD_BL_PIN) + #if defined(OMV_SPI_LCD_SPI_BUS) && defined(OMV_SPI_LCD_BL_PIN) case LCD_SHIELD: { spi_lcd_set_backlight(intensity); break; @@ -1736,7 +1701,7 @@ STATIC mp_obj_t py_lcd_display(uint n_args, const mp_obj_t *args, mp_map_t *kw_a } switch (lcd_type) { - #ifdef OMV_SPI_LCD_CONTROLLER + #ifdef OMV_SPI_LCD_SPI_BUS case LCD_SHIELD: { fb_alloc_mark(); spi_lcd_display(arg_img, arg_x_off, arg_y_off, arg_x_scale, arg_y_scale, &arg_roi, @@ -1765,7 +1730,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_lcd_display_obj, 1, py_lcd_display); STATIC mp_obj_t py_lcd_clear(uint n_args, const mp_obj_t *args) { switch (lcd_type) { - #ifdef OMV_SPI_LCD_CONTROLLER + #ifdef OMV_SPI_LCD_SPI_BUS case LCD_SHIELD: { if (n_args && mp_obj_get_int(*args)) { // turns the display off (may not be black) @@ -1916,4 +1881,5 @@ void py_lcd_init0() { } MP_REGISTER_MODULE(MP_QSTR_lcd, lcd_module); + #endif // MICROPY_PY_LCD diff --git a/src/omv/ports/stm32/modules/py_lcd.h b/src/omv/modules/py_lcd.h similarity index 100% rename from src/omv/ports/stm32/modules/py_lcd.h rename to src/omv/modules/py_lcd.h diff --git a/src/omv/ports/stm32/modules/py_lcd_cec.c b/src/omv/modules/py_lcd_cec.c similarity index 100% rename from src/omv/ports/stm32/modules/py_lcd_cec.c rename to src/omv/modules/py_lcd_cec.c diff --git a/src/omv/ports/stm32/modules/py_lcd_cec.h b/src/omv/modules/py_lcd_cec.h similarity index 100% rename from src/omv/ports/stm32/modules/py_lcd_cec.h rename to src/omv/modules/py_lcd_cec.h diff --git a/src/omv/ports/stm32/modules/py_lcd_touch.c b/src/omv/modules/py_lcd_touch.c similarity index 99% rename from src/omv/ports/stm32/modules/py_lcd_touch.c rename to src/omv/modules/py_lcd_touch.c index 27fb31773..f6d3d05f0 100644 --- a/src/omv/ports/stm32/modules/py_lcd_touch.c +++ b/src/omv/modules/py_lcd_touch.c @@ -11,8 +11,6 @@ #include "omv_boardconfig.h" #if MICROPY_PY_LCD -#include STM32_HAL_H - #include "py/obj.h" #include "py/nlr.h" #include "py/runtime.h" diff --git a/src/omv/ports/stm32/modules/py_lcd_touch.h b/src/omv/modules/py_lcd_touch.h similarity index 100% rename from src/omv/ports/stm32/modules/py_lcd_touch.h rename to src/omv/modules/py_lcd_touch.h diff --git a/src/omv/ports/stm32/modules/py_tv.c b/src/omv/modules/py_tv.c similarity index 82% rename from src/omv/ports/stm32/modules/py_tv.c rename to src/omv/modules/py_tv.c index 06d29a65c..e74be6b5d 100644 --- a/src/omv/ports/stm32/modules/py_tv.c +++ b/src/omv/modules/py_tv.c @@ -1,9 +1,9 @@ /* * This file is part of the OpenMV project. * - * Copyright (c) 2013-2020 Ibrahim Abdelkader - * Copyright (c) 2013-2020 Kwabena W. Agyeman - * Copyright (c) 2013-2020 Kaizhi Wong + * Copyright (c) 2013-2023 Ibrahim Abdelkader + * Copyright (c) 2013-2023 Kwabena W. Agyeman + * Copyright (c) 2013-2023 Kaizhi Wong * * This work is licensed under the MIT license, see the file LICENSE for details. * @@ -12,16 +12,15 @@ #include "omv_boardconfig.h" #if MICROPY_PY_TV -#include STM32_HAL_H #include "py/obj.h" #include "py/nlr.h" #include "py/runtime.h" -#include "spi.h" #include "py_helper.h" #include "py_image.h" #include "omv_gpio.h" +#include "omv_spi.h" #define TV_WIDTH 352 #define TV_HEIGHT 240 @@ -35,7 +34,7 @@ #error "TV_HEIGHT not even" #endif -#ifdef OMV_SPI_LCD_CONTROLLER +#ifdef OMV_SPI_LCD_SPI_BUS ///////////////////////////////////////////////////////////// // http://www.vsdsp-forum.com/phpbb/viewtopic.php?f=14&t=1801 ///////////////////////////////////////////////////////////// @@ -207,70 +206,67 @@ #error "TV_WIDTH * TV_HEIGHT is too big!" #endif -static void SpiRamWriteByteRegister(int opcode, int data) { - uint8_t packet[2] = {opcode, data}; +#define TV_BAUDRATE (TV_WIDTH * TV_HEIGHT * TV_REFRESH * PICBITS) + +static omv_spi_t spi_bus = {}; + +static void SpiTransmitReceivePacket(uint8_t *txdata, uint8_t *rxdata, uint16_t size, bool end) { + omv_spi_transfer_t spi_xfer = { + .txbuf = txdata, + .rxbuf = rxdata, + .size = size, + .timeout = OMV_SPI_MAX_TIMEOUT, + .flags = OMV_SPI_XFER_BLOCKING + }; omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_Transmit(OMV_SPI_LCD_CONTROLLER->spi, packet, sizeof(packet), HAL_MAX_DELAY); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + omv_spi_transfer_start(&spi_bus, &spi_xfer); + + if (end) { + omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + } +} + +static void SpiRamWriteByteRegister(int opcode, int data) { + uint8_t packet[2] = {opcode, data}; + SpiTransmitReceivePacket(packet, NULL, sizeof(packet), true); } static int SpiRamReadByteRegister(int opcode) { uint8_t packet[2] = {opcode, 0}; - - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_TransmitReceive(OMV_SPI_LCD_CONTROLLER->spi, packet, packet, sizeof(packet), HAL_MAX_DELAY); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); - + SpiTransmitReceivePacket(packet, packet, sizeof(packet), true); return packet[1]; } static void SpiRamWriteWordRegister(int opcode, int data) { uint8_t packet[3] = {opcode, data >> 8, data}; - - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_Transmit(OMV_SPI_LCD_CONTROLLER->spi, packet, sizeof(packet), HAL_MAX_DELAY); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + SpiTransmitReceivePacket(packet, NULL, sizeof(packet), true); } static void SpiClearRam() { uint8_t packet[4] = {WRITE_SRAM, 0, 0, 0}; - - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_Transmit(OMV_SPI_LCD_CONTROLLER->spi, packet, sizeof(packet), HAL_MAX_DELAY); - + SpiTransmitReceivePacket(packet, NULL, sizeof(packet), false); packet[0] = 0; for (int i = 0; i < (SPI_RAM_SIZE / sizeof(packet)); i++) { - HAL_SPI_Transmit(OMV_SPI_LCD_CONTROLLER->spi, packet, sizeof(packet), HAL_MAX_DELAY); + SpiTransmitReceivePacket(packet, NULL, sizeof(packet), (i + 1) == (SPI_RAM_SIZE / sizeof(packet))); } - - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); } static void SpiRamWriteProgram(int data0, int data1, int data2, int data3) { uint8_t packet[5] = {PROGRAM, data3, data2, data1, data0}; - - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_Transmit(OMV_SPI_LCD_CONTROLLER->spi, packet, sizeof(packet), HAL_MAX_DELAY); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + SpiTransmitReceivePacket(packet, NULL, sizeof(packet), true); } static void SpiRamWriteLowPassFilter(int data) { uint8_t packet[6] = {WRITE_BLOCKMVC1, 0, 0, 0, 0, data}; - - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_Transmit(OMV_SPI_LCD_CONTROLLER->spi, packet, sizeof(packet), HAL_MAX_DELAY); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + SpiTransmitReceivePacket(packet, NULL, sizeof(packet), true); } static void SpiRamWriteWord(int w_address, int data) { int address = w_address * sizeof(uint16_t); uint8_t packet[6] = {WRITE_SRAM, address >> 16, address >> 8, address, data >> 8, data}; - - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_Transmit(OMV_SPI_LCD_CONTROLLER->spi, packet, sizeof(packet), HAL_MAX_DELAY); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + SpiTransmitReceivePacket(packet, NULL, sizeof(packet), true); } static void SpiRamWriteVSyncProtoLine(int line, int length_1, int length_2) { @@ -294,10 +290,7 @@ static void SpiRamWriteLine(int line, int index) { int address = INDEX_START_BYTES + (line * LINE_INDEX_BYTE_SIZE); int data = index << 7; uint8_t packet[7] = {WRITE_SRAM, address >> 16, address >> 8, address, data, data >> 8, data >> 16}; - - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_Transmit(OMV_SPI_LCD_CONTROLLER->spi, packet, sizeof(packet), HAL_MAX_DELAY); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + SpiTransmitReceivePacket(packet, NULL, sizeof(packet), true); } static void SpiRamVideoInit() { @@ -402,9 +395,7 @@ tv_type = TV_NONE; static bool tv_triple_buffer = false; -#ifdef OMV_SPI_LCD_CONTROLLER -static DMA_HandleTypeDef spi_tx_dma = {}; - +#ifdef OMV_SPI_LCD_SPI_BUS static volatile enum { SPI_TX_CB_IDLE, SPI_TX_CB_MEMORY_WRITE_CMD, @@ -414,39 +405,23 @@ spi_tx_cb_state = SPI_TX_CB_IDLE; static void spi_config_deinit() { if (tv_triple_buffer) { - HAL_SPI_Abort(OMV_SPI_LCD_CONTROLLER->spi); + omv_spi_transfer_abort(&spi_bus); spi_tx_cb_state = SPI_TX_CB_IDLE; fb_alloc_free_till_mark_past_mark_permanent(); } - spi_deinit(OMV_SPI_LCD_CONTROLLER); - - // Do not put in HAL_SPI_MspDeinit as other modules share the SPI2 bus. - omv_gpio_deinit(OMV_SPI_LCD_MOSI_PIN); - omv_gpio_deinit(OMV_SPI_LCD_MISO_PIN); - omv_gpio_deinit(OMV_SPI_LCD_SCLK_PIN); - omv_gpio_deinit(OMV_SPI_LCD_SSEL_PIN); + omv_spi_deinit(&spi_bus); } -static void spi_tv_callback(SPI_HandleTypeDef *hspi); - static void spi_config_init(bool triple_buffer) { - OMV_SPI_LCD_CONTROLLER->spi->Init.Mode = SPI_MODE_MASTER; - OMV_SPI_LCD_CONTROLLER->spi->Init.Direction = SPI_DIRECTION_2LINES; - OMV_SPI_LCD_CONTROLLER->spi->Init.NSS = SPI_NSS_SOFT; - OMV_SPI_LCD_CONTROLLER->spi->Init.TIMode = SPI_TIMODE_DISABLE; - OMV_SPI_LCD_CONTROLLER->spi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; - spi_set_params(OMV_SPI_LCD_CONTROLLER, 0xffffffff, - TV_WIDTH * TV_HEIGHT * TV_REFRESH * PICBITS, - 0, 0, 8, 0); - spi_init(OMV_SPI_LCD_CONTROLLER, true); - HAL_SPI_RegisterCallback(OMV_SPI_LCD_CONTROLLER->spi, HAL_SPI_TX_COMPLETE_CB_ID, spi_tv_callback); + omv_spi_config_t spi_config; + omv_spi_default_config(&spi_config, OMV_SPI_LCD_SPI_BUS); + + spi_config.baudrate = TV_BAUDRATE; + spi_config.nss_enable = false; + spi_config.dma_flags = triple_buffer ? OMV_SPI_DMA_NORMAL : 0; + omv_spi_init(&spi_bus, &spi_config); - // Do not put in HAL_SPI_MspInit as other modules share the SPI2 bus. - omv_gpio_config(OMV_SPI_LCD_MOSI_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1); - omv_gpio_config(OMV_SPI_LCD_MISO_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1); - omv_gpio_config(OMV_SPI_LCD_SCLK_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1); - omv_gpio_config(OMV_SPI_LCD_SSEL_PIN, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_LOW, -1); omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); SpiRamVideoInit(); @@ -464,51 +439,19 @@ static void spi_config_init(bool triple_buffer) { framebuffers[i] = (uint16_t *) fb_alloc0(TV_WIDTH_RGB565 * TV_HEIGHT, FB_ALLOC_CACHE_ALIGN); } - dma_init(&spi_tx_dma, OMV_SPI_LCD_CONTROLLER->tx_dma_descr, DMA_MEMORY_TO_PERIPH, OMV_SPI_LCD_CONTROLLER->spi); - OMV_SPI_LCD_CONTROLLER->spi->hdmatx = &spi_tx_dma; - OMV_SPI_LCD_CONTROLLER->spi->hdmarx = NULL; - #if defined(MCU_SERIES_H7) - spi_tx_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; - #else - spi_tx_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; - #endif - spi_tx_dma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; - spi_tx_dma.Init.FIFOMode = DMA_FIFOMODE_ENABLE; - spi_tx_dma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; - spi_tx_dma.Init.MemBurst = DMA_MBURST_INC4; - #if defined(MCU_SERIES_H7) - spi_tx_dma.Init.PeriphBurst = DMA_PBURST_INC4; - #else - spi_tx_dma.Init.PeriphBurst = DMA_PBURST_SINGLE; - #endif - DMA_Stream_TypeDef *dma_chan = spi_tx_dma.Instance; - #if defined(MCU_SERIES_H7) - dma_chan->CR = (dma_chan->CR & ~DMA_SxCR_PSIZE_Msk) | DMA_PDATAALIGN_WORD; - #else - dma_chan->CR = (dma_chan->CR & ~DMA_SxCR_PSIZE_Msk) | DMA_PDATAALIGN_BYTE; - #endif - dma_chan->CR = (dma_chan->CR & ~DMA_SxCR_MSIZE_Msk) | DMA_MDATAALIGN_WORD; - dma_chan->FCR = (dma_chan->FCR & ~DMA_SxFCR_DMDIS_Msk) | DMA_FIFOMODE_ENABLE; - dma_chan->FCR = (dma_chan->FCR & ~DMA_SxFCR_FTH_Msk) | DMA_FIFO_THRESHOLD_FULL; - dma_chan->CR = (dma_chan->CR & ~DMA_SxCR_MBURST_Msk) | DMA_MBURST_INC4; - #if defined(MCU_SERIES_H7) - dma_chan->CR = (dma_chan->CR & ~DMA_SxCR_PBURST_Msk) | DMA_PBURST_INC4; - #else - dma_chan->CR = (dma_chan->CR & ~DMA_SxCR_PBURST_Msk) | DMA_PBURST_SINGLE; - #endif fb_alloc_mark_permanent(); } } static const uint8_t write_sram[] = { - // Cannot be allocated on the stack for HAL_SPI_Transmit_IT(). + // Cannot be allocated on the stack. WRITE_SRAM, (uint8_t) (PICLINE_BYTE_ADDRESS(0) >> 16), (uint8_t) (PICLINE_BYTE_ADDRESS(0) >> 8), (uint8_t) (PICLINE_BYTE_ADDRESS(0) >> 0) }; -static void spi_tv_callback(SPI_HandleTypeDef *hspi) { +static void spi_tv_callback(omv_spi_t *spi, void *userdata, void *buf) { if (tv_type == TV_SHIELD) { static uint8_t *spi_tx_cb_state_memory_write_addr = NULL; static size_t spi_tx_cb_state_memory_write_count = 0; @@ -520,33 +463,37 @@ static void spi_tv_callback(SPI_HandleTypeDef *hspi) { spi_tx_cb_state_memory_write_addr = (uint8_t *) framebuffers[framebuffer_head]; spi_tx_cb_state_memory_write_count = PICLINE_LENGTH_BYTES * TV_HEIGHT; framebuffer_tail = framebuffer_head; - #if defined(MCU_SERIES_H7) - OMV_SPI_LCD_CONTROLLER->spi->Instance->CFG1 = - (OMV_SPI_LCD_CONTROLLER->spi->Instance->CFG1 & ~SPI_CFG1_FTHLV_Msk) | SPI_FIFO_THRESHOLD_01DATA; - #endif omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - // When starting the interrupt chain the first HAL_SPI_Transmit_IT is not executed - // in interrupt context. So, disable interrupts for the first HAL_SPI_Transmit_IT so + // When starting the interrupt chain the first transfer is not executed + // in interrupt context. So, disable interrupts for the first transfer so // that it completes first and unlocks the SPI bus before allowing the interrupt // it causes to trigger starting the interrupt chain. + omv_spi_transfer_t spi_xfer = { + .txbuf = (uint8_t *) write_sram, + .size = sizeof(write_sram), + .flags = OMV_SPI_XFER_NONBLOCK, + .callback = spi_tv_callback, + }; uint32_t irq_state = disable_irq(); - HAL_SPI_Transmit_IT(OMV_SPI_LCD_CONTROLLER->spi, (uint8_t *) write_sram, sizeof(write_sram)); + omv_spi_transfer_start(&spi_bus, &spi_xfer); enable_irq(irq_state); break; } case SPI_TX_CB_MEMORY_WRITE: { uint8_t *addr = spi_tx_cb_state_memory_write_addr; - size_t count = IM_MIN(spi_tx_cb_state_memory_write_count, (65536 - 16u)); - spi_tx_cb_state = (spi_tx_cb_state_memory_write_count > (65536 - 16)) + size_t count = IM_MIN(spi_tx_cb_state_memory_write_count, OMV_SPI_MAX_8BIT_XFER); + spi_tx_cb_state = (spi_tx_cb_state_memory_write_count > OMV_SPI_MAX_8BIT_XFER) ? SPI_TX_CB_MEMORY_WRITE : SPI_TX_CB_MEMORY_WRITE_CMD; spi_tx_cb_state_memory_write_addr += count; spi_tx_cb_state_memory_write_count -= count; - #if defined(MCU_SERIES_H7) - OMV_SPI_LCD_CONTROLLER->spi->Instance->CFG1 = - (OMV_SPI_LCD_CONTROLLER->spi->Instance->CFG1 & ~SPI_CFG1_FTHLV_Msk) | SPI_FIFO_THRESHOLD_16DATA; - #endif - HAL_SPI_Transmit_DMA(OMV_SPI_LCD_CONTROLLER->spi, addr, count); + omv_spi_transfer_t spi_xfer = { + .txbuf = addr, + .size = count, + .flags = OMV_SPI_XFER_DMA, + .callback = spi_tv_callback, + }; + omv_spi_transfer_start(&spi_bus, &spi_xfer); break; } default: { @@ -619,12 +566,12 @@ static void spi_tv_draw_image_cb_convert_rgb565(uint16_t *row_pointer_i, uint8_t static void spi_tv_draw_image_cb_grayscale(int x_start, int x_end, int y_row, imlib_draw_row_data_t *data) { spi_tv_draw_image_cb_convert_grayscale((uint8_t *) data->dst_row_override, (uint8_t *) data->dst_row_override); - HAL_SPI_Transmit(OMV_SPI_LCD_CONTROLLER->spi, data->dst_row_override, PICLINE_LENGTH_BYTES, HAL_MAX_DELAY); + SpiTransmitReceivePacket(data->dst_row_override, NULL, PICLINE_LENGTH_BYTES, false); } static void spi_tv_draw_image_cb_rgb565(int x_start, int x_end, int y_row, imlib_draw_row_data_t *data) { spi_tv_draw_image_cb_convert_rgb565((uint16_t *) data->dst_row_override, (uint8_t *) data->dst_row_override); - HAL_SPI_Transmit(OMV_SPI_LCD_CONTROLLER->spi, data->dst_row_override, PICLINE_LENGTH_BYTES, HAL_MAX_DELAY); + SpiTransmitReceivePacket(data->dst_row_override, NULL, PICLINE_LENGTH_BYTES, false); } static void spi_tv_display(image_t *src_img, int dst_x_start, int dst_y_start, float x_scale, float y_scale, @@ -645,19 +592,18 @@ static void spi_tv_display(image_t *src_img, int dst_x_start, int dst_y_start, f if (!tv_triple_buffer) { dst_img.data = fb_alloc0(TV_WIDTH_RGB565, FB_ALLOC_NO_HINT); - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - HAL_SPI_Transmit(OMV_SPI_LCD_CONTROLLER->spi, (uint8_t *) write_sram, sizeof(write_sram), HAL_MAX_DELAY); + SpiTransmitReceivePacket((uint8_t *) write_sram, NULL, sizeof(write_sram), false); if (black) { // zero the whole image for (int i = 0; i < TV_HEIGHT; i++) { - HAL_SPI_Transmit(OMV_SPI_LCD_CONTROLLER->spi, dst_img.data, PICLINE_LENGTH_BYTES, HAL_MAX_DELAY); + SpiTransmitReceivePacket(dst_img.data, NULL, PICLINE_LENGTH_BYTES, false); } } else { // Zero the top rows for (int i = 0; i < y0; i++) { - HAL_SPI_Transmit(OMV_SPI_LCD_CONTROLLER->spi, dst_img.data, PICLINE_LENGTH_BYTES, HAL_MAX_DELAY); + SpiTransmitReceivePacket(dst_img.data, NULL, PICLINE_LENGTH_BYTES, false); } // Transmits left/right parts already zeroed... @@ -671,7 +617,7 @@ static void spi_tv_display(image_t *src_img, int dst_x_start, int dst_y_start, f } for (int i = y1; i < TV_HEIGHT; i++) { - HAL_SPI_Transmit(OMV_SPI_LCD_CONTROLLER->spi, dst_img.data, PICLINE_LENGTH_BYTES, HAL_MAX_DELAY); + SpiTransmitReceivePacket(dst_img.data, NULL, PICLINE_LENGTH_BYTES, false); } } @@ -782,7 +728,7 @@ static void spi_tv_display(image_t *src_img, int dst_x_start, int dst_y_start, f // Kick off an update of the display. if (spi_tx_cb_state == SPI_TX_CB_IDLE) { spi_tx_cb_state = SPI_TX_CB_MEMORY_WRITE_CMD; - spi_tv_callback(OMV_SPI_LCD_CONTROLLER->spi); + spi_tv_callback(&spi_bus, NULL, NULL); } } } @@ -790,7 +736,7 @@ static void spi_tv_display(image_t *src_img, int dst_x_start, int dst_y_start, f STATIC mp_obj_t py_tv_deinit() { switch (tv_type) { - #ifdef OMV_SPI_LCD_CONTROLLER + #ifdef OMV_SPI_LCD_SPI_BUS case TV_SHIELD: { spi_config_deinit(); break; @@ -814,10 +760,14 @@ STATIC mp_obj_t py_tv_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) MP_OBJ_NEW_QSTR(MP_QSTR_type), TV_SHIELD); switch (type) { - #ifdef OMV_SPI_LCD_CONTROLLER + #ifdef OMV_SPI_LCD_SPI_BUS case TV_SHIELD: { + bool triple_buffer_def = false; + #ifdef OMV_SPI_LCD_DEF_TRIPLE_BUF + triple_buffer_def = OMV_SPI_LCD_DEF_TRIPLE_BUF; + #endif bool triple_buffer = py_helper_keyword_int(n_args, args, 1, kw_args, - MP_OBJ_NEW_QSTR(MP_QSTR_triple_buffer), false); + MP_OBJ_NEW_QSTR(MP_QSTR_triple_buffer), triple_buffer_def); spi_config_init(triple_buffer); tv_type = TV_SHIELD; tv_triple_buffer = triple_buffer; @@ -883,9 +833,9 @@ STATIC mp_obj_t py_tv_channel(uint n_args, const mp_obj_t *args) { return mp_const_none; } - #ifdef OMV_SPI_LCD_CONTROLLER + #ifdef OMV_SPI_LCD_SPI_BUS if (tv_triple_buffer) { - HAL_SPI_Abort(OMV_SPI_LCD_CONTROLLER->spi); + omv_spi_transfer_abort(&spi_bus); spi_tx_cb_state = SPI_TX_CB_IDLE; omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); } @@ -899,7 +849,13 @@ STATIC mp_obj_t py_tv_channel(uint n_args, const mp_obj_t *args) { SpiRamWriteByteRegister(WRITE_GPIO, 0x70 | (channel - 1)); } else { + #ifdef OMV_SPI_LCD_RX_CLK_DIV + omv_spi_set_baudrate(&spi_bus, TV_BAUDRATE / OMV_SPI_LCD_RX_CLK_DIV); + #endif int channel = SpiRamReadByteRegister(READ_GPIO); + #ifdef OMV_SPI_LCD_RX_CLK_DIV + omv_spi_set_baudrate(&spi_bus, TV_BAUDRATE); + #endif return mp_obj_new_int((channel & 0x7) + 1); } #endif @@ -993,7 +949,7 @@ STATIC mp_obj_t py_tv_display(uint n_args, const mp_obj_t *args, mp_map_t *kw_ar } switch (tv_type) { - #ifdef OMV_SPI_LCD_CONTROLLER + #ifdef OMV_SPI_LCD_SPI_BUS case TV_SHIELD: { fb_alloc_mark(); spi_tv_display(arg_img, arg_x_off, arg_y_off, arg_x_scale, arg_y_scale, &arg_roi, @@ -1013,7 +969,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_tv_display_obj, 1, py_tv_display); STATIC mp_obj_t py_tv_clear() { switch (tv_type) { - #ifdef OMV_SPI_LCD_CONTROLLER + #ifdef OMV_SPI_LCD_SPI_BUS case TV_SHIELD: { fb_alloc_mark(); spi_tv_display(NULL, 0, 0, 1.f, 1.f, NULL, @@ -1059,4 +1015,5 @@ void py_tv_init0() { } MP_REGISTER_MODULE(MP_QSTR_tv, tv_module); + #endif // MICROPY_PY_TV diff --git a/src/omv/ports/stm32/modules/py_tv.h b/src/omv/modules/py_tv.h similarity index 100% rename from src/omv/ports/stm32/modules/py_tv.h rename to src/omv/modules/py_tv.h diff --git a/src/omv/ports/stm32/stm32fxxx.ld.S b/src/omv/ports/stm32/stm32fxxx.ld.S index 1a85443be..bdec5029e 100755 --- a/src/omv/ports/stm32/stm32fxxx.ld.S +++ b/src/omv/ports/stm32/stm32fxxx.ld.S @@ -151,10 +151,6 @@ SECTIONS _vfs_buf = .; // VFS struct + FATFS file buffer (around 624 bytes) . = . + OMV_VFS_BUF_SIZE; - . = ALIGN(16); - _fir_lepton_buf = .; // FIR Lepton Packet Double Buffer (328 bytes) - . = . + OMV_FIR_LEPTON_BUF_SIZE; - #if defined(OMV_FFS_BUF_SIZE) . = ALIGN(16); _micropy_hw_internal_flash_storage_ram_cache_start = .; diff --git a/src/uvc/stm32fxxx.ld.S b/src/uvc/stm32fxxx.ld.S index af9823711..3b058d97d 100755 --- a/src/uvc/stm32fxxx.ld.S +++ b/src/uvc/stm32fxxx.ld.S @@ -128,10 +128,6 @@ SECTIONS _vfs_buf = .; // VFS struct + FATFS file buffer (around 624 bytes) . = . + OMV_VFS_BUF_SIZE; - . = ALIGN(16); - _fir_lepton_buf = .; // FIR Lepton Packet Double Buffer (328 bytes) - . = . + OMV_FIR_LEPTON_BUF_SIZE; - #if defined(OMV_FFS_BUF_SIZE) . = ALIGN(16); _ffs_cache = .; // Flash filesystem cache From c37260df9525a93f98edb2def2039b7e6a0dcf6b Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Sat, 9 Sep 2023 20:10:06 -0700 Subject: [PATCH 3/4] ports/mimxrt: Enable support for all py modules. --- .../boards/OPENMV_RT1060/omv_boardconfig.h | 309 ++++++++++-------- .../boards/OPENMV_RT1060/omv_boardconfig.mk | 4 +- src/omv/boards/OPENMV_RT1060/omv_pins.h | 14 + src/omv/common/vospi.c | 144 ++++---- src/omv/modules/py_fir_lepton.c | 34 +- src/omv/ports/mimxrt/main.c | 6 +- src/omv/ports/mimxrt/mimxrt.ld.S | 4 - src/omv/ports/mimxrt/omv_portconfig.h | 1 - src/omv/ports/mimxrt/omv_portconfig.mk | 1 + src/omv/ports/mimxrt/omv_spi.c | 134 ++++---- src/omv/ports/stm32/omv_spi.c | 66 ++-- 11 files changed, 382 insertions(+), 335 deletions(-) diff --git a/src/omv/boards/OPENMV_RT1060/omv_boardconfig.h b/src/omv/boards/OPENMV_RT1060/omv_boardconfig.h index 05c1388cc..22f4c122d 100644 --- a/src/omv/boards/OPENMV_RT1060/omv_boardconfig.h +++ b/src/omv/boards/OPENMV_RT1060/omv_boardconfig.h @@ -12,195 +12,242 @@ #define __OMV_BOARDCONFIG_H__ // Architecture info -#define OMV_ARCH_STR "OMVRT1060 32768 SDRAM" // 33 chars max -#define OMV_BOARD_TYPE "IMXRT1060" -#define OMV_UNIQUE_ID_ADDR 0x401f4410 // Unique ID address. -#define OMV_UNIQUE_ID_SIZE 3 // Unique ID size in words. -#define OMV_UNIQUE_ID_OFFSET 12 // Bytes offset for multi-word UIDs. +#define OMV_ARCH_STR "OMVRT1060 32768 SDRAM" // 33 chars max +#define OMV_BOARD_TYPE "IMXRT1060" +#define OMV_UNIQUE_ID_ADDR 0x401f4410 // Unique ID address. +#define OMV_UNIQUE_ID_SIZE 3 // Unique ID size in words. +#define OMV_UNIQUE_ID_OFFSET 12 // Bytes offset for multi-word UIDs. // Needed by the SWD JTAG testrig - located at the bottom of the frame buffer stack. -#define OMV_SELF_TEST_SWD_ADDR MAIN_FB()->pixfmt +#define OMV_SELF_TEST_SWD_ADDR MAIN_FB()->pixfmt // Sensor external clock timer frequency. -#define OMV_XCLK_FREQUENCY (12000000) +#define OMV_XCLK_FREQUENCY (12000000) // OV767x sensor configuration. -#define OMV_OV7670_VERSION (70) -#define OMV_OV7670_CLKRC (0) +#define OMV_OV7670_VERSION (70) +#define OMV_OV7670_CLKRC (0) // OV7725 sensor configuration. -#define OMV_OV7725_PLL_CONFIG (0x41) // x4 -#define OMV_OV7725_BANDING (0x7F) +#define OMV_OV7725_PLL_CONFIG (0x41) // x4 +#define OMV_OV7725_BANDING (0x7F) // OV5640 Sensor Settings -#define OMV_ENABLE_OV5640_AF (0) -#define OMV_OV5640_XCLK_FREQ (24000000) -#define OMV_OV5640_PLL_CTRL2 (0x64) -#define OMV_OV5640_PLL_CTRL3 (0x13) -#define OMV_OV5640_REV_Y_CHECK (0) -#define OMV_OV5640_REV_Y_FREQ (25000000) -#define OMV_OV5640_REV_Y_CTRL2 (0x54) -#define OMV_OV5640_REV_Y_CTRL3 (0x13) +#define OMV_ENABLE_OV5640_AF (0) +#define OMV_OV5640_XCLK_FREQ (24000000) +#define OMV_OV5640_PLL_CTRL2 (0x64) +#define OMV_OV5640_PLL_CTRL3 (0x13) +#define OMV_OV5640_REV_Y_CHECK (0) +#define OMV_OV5640_REV_Y_FREQ (25000000) +#define OMV_OV5640_REV_Y_CTRL2 (0x54) +#define OMV_OV5640_REV_Y_CTRL3 (0x13) // Enable hardware JPEG -#define OMV_HARDWARE_JPEG (0) +#define OMV_HARDWARE_JPEG (0) // Enable sensor drivers -#define OMV_ENABLE_OV2640 (0) -#define OMV_ENABLE_OV5640 (1) -#define OMV_ENABLE_OV7670 (0) -#define OMV_ENABLE_OV7690 (0) -#define OMV_ENABLE_OV7725 (1) -#define OMV_ENABLE_OV9650 (0) -#define OMV_ENABLE_MT9M114 (1) -#define OMV_ENABLE_MT9V0XX (1) -#define OMV_ENABLE_LEPTON (1) -#define OMV_ENABLE_HM01B0 (0) -#define OMV_ENABLE_PAJ6100 (1) -#define OMV_ENABLE_FROGEYE2020 (1) +#define OMV_ENABLE_OV2640 (0) +#define OMV_ENABLE_OV5640 (1) +#define OMV_ENABLE_OV7670 (0) +#define OMV_ENABLE_OV7690 (0) +#define OMV_ENABLE_OV7725 (1) +#define OMV_ENABLE_OV9650 (0) +#define OMV_ENABLE_MT9M114 (1) +#define OMV_ENABLE_MT9V0XX (1) +#define OMV_ENABLE_LEPTON (1) +#define OMV_ENABLE_HM01B0 (0) +#define OMV_ENABLE_PAJ6100 (1) +#define OMV_ENABLE_FROGEYE2020 (1) +#define OMV_ENABLE_FIR_MLX90621 (1) +#define OMV_ENABLE_FIR_MLX90640 (1) +#define OMV_ENABLE_FIR_MLX90641 (1) +#define OMV_ENABLE_FIR_AMG8833 (1) +#define OMV_ENABLE_FIR_LEPTON (1) // Enable WiFi debug -#define OMV_ENABLE_WIFIDBG (0) -#define OMV_ENABLE_TUSBDBG (1) -#define OMV_TUSBDBG_PACKET (512) +#define OMV_ENABLE_WIFIDBG (0) +#define OMV_ENABLE_TUSBDBG (1) +#define OMV_TUSBDBG_PACKET (512) // Enable self-tests on first boot -#define OMV_ENABLE_SELFTEST (0) +#define OMV_ENABLE_SELFTEST (0) // If buffer size is bigger than this threshold, the quality is reduced. // This is only used for JPEG images sent to the IDE not normal compression. -#define JPEG_QUALITY_THRESH (320 * 240 * 2) +#define JPEG_QUALITY_THRESH (320 * 240 * 2) // Low and high JPEG QS. -#define JPEG_QUALITY_LOW 50 -#define JPEG_QUALITY_HIGH 90 +#define JPEG_QUALITY_LOW 50 +#define JPEG_QUALITY_HIGH 90 // FB Heap Block Size -#define OMV_UMM_BLOCK_SIZE 16 +#define OMV_UMM_BLOCK_SIZE 16 // Core VBAT for selftests -#define OMV_CORE_VBAT "3.3" +#define OMV_CORE_VBAT "3.3" // USB config. -#define OMV_USB_IRQN (USB_OTG1_IRQn) -#define OMV_USB1_IRQ_HANDLER (USB_OTG1_IRQHandler) -#define OMV_USB2_IRQ_HANDLER (USB_OTG2_IRQHandler) +#define OMV_USB_IRQN (USB_OTG1_IRQn) +#define OMV_USB1_IRQ_HANDLER (USB_OTG1_IRQHandler) +#define OMV_USB2_IRQ_HANDLER (USB_OTG2_IRQHandler) -#define OMV_USB_PHY_ID (kUSB_ControllerEhci0) -#define OMV_USB_PHY_D_CAL (0x0CU) -#define OMV_USB_PHY_TXCAL45DP (0x06U) -#define OMV_USB_PHY_TXCAL45DM (0x06U) +#define OMV_USB_PHY_ID (kUSB_ControllerEhci0) +#define OMV_USB_PHY_D_CAL (0x0CU) +#define OMV_USB_PHY_TXCAL45DP (0x06U) +#define OMV_USB_PHY_TXCAL45DM (0x06U) // Linker script constants (see the linker script template mimxrt10xx.ld.S). // Note: fb_alloc is a stack-based, dynamically allocated memory on FB. // The maximum available fb_alloc memory = FB_ALLOC_SIZE + FB_SIZE - (w*h*bpp). -//#define OMV_FFS_MEMORY DTCM // Flash filesystem cache memory -#define OMV_MAIN_MEMORY DTCM // data, bss and heap memory -#define OMV_STACK_MEMORY ITCM1 // stack memory -#define OMV_RAMFUNC_MEMORY ITCM2 // RAM code memory. -#define OMV_FB_MEMORY DRAM // Framebuffer, fb_alloc -#define OMV_DMA_MEMORY DTCM // DMA buffers memory. -#define OMV_JPEG_MEMORY DRAM // JPEG buffer memory buffer. -#define OMV_JPEG_MEMORY_OFFSET (31M) // JPEG buffer is placed after FB/fballoc memory. -#define OMV_VOSPI_MEMORY OCRM2 // VoSPI buffer memory. -#define OMV_FB_OVERLAY_MEMORY OCRM1 // Fast fb_alloc memory. +//#define OMV_FFS_MEMORY DTCM // Flash filesystem cache memory +#define OMV_MAIN_MEMORY DTCM // data, bss and heap memory +#define OMV_STACK_MEMORY ITCM1 // stack memory +#define OMV_RAMFUNC_MEMORY ITCM2 // RAM code memory. +#define OMV_FB_MEMORY DRAM // Framebuffer, fb_alloc +#define OMV_DMA_MEMORY DTCM // DMA buffers memory. +#define OMV_JPEG_MEMORY DRAM // JPEG buffer memory buffer. +#define OMV_JPEG_MEMORY_OFFSET (31M) // JPEG buffer is placed after FB/fballoc memory. +#define OMV_VOSPI_MEMORY OCRM2 // VoSPI buffer memory. +#define OMV_FB_OVERLAY_MEMORY OCRM1 // Fast fb_alloc memory. -#define OMV_FB_SIZE (10M) // FB memory: header + VGA/GS image -#define OMV_FB_ALLOC_SIZE (2M) // minimum fb alloc size -#define OMV_FB_OVERLAY_SIZE (512K) -#define OMV_STACK_SIZE (32K) -#define OMV_HEAP_SIZE (280K) -#define OMV_SDRAM_SIZE (32 * 1024 * 1024) // This needs to be here for UVC firmware. +#define OMV_FB_SIZE (10M) // FB memory: header + VGA/GS image +#define OMV_FB_ALLOC_SIZE (2M) // minimum fb alloc size +#define OMV_FB_OVERLAY_SIZE (512K) +#define OMV_STACK_SIZE (32K) +#define OMV_HEAP_SIZE (280K) +#define OMV_SDRAM_SIZE (32 * 1024 * 1024) // This needs to be here for UVC firmware. -#define OMV_LINE_BUF_SIZE (10 * 1024) // Image line buffer. +#define OMV_LINE_BUF_SIZE (10 * 1024) // Image line buffer. // TODO remove -#define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data -#define OMV_VFS_BUF_SIZE (1K) // VFS struct + FATFS file buffer (624 bytes) -#define OMV_FIR_LEPTON_BUF_SIZE (1K) // FIR Lepton Packet Double Buffer (328 bytes) -#define OMV_JPEG_BUF_SIZE (1024 * 1024) // IDE JPEG buffer (header + data). +#define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data +#define OMV_VFS_BUF_SIZE (1K) // VFS struct + FATFS file buffer (624 bytes) +#define OMV_JPEG_BUF_SIZE (1024 * 1024) // IDE JPEG buffer (header + data). // Memory configuration. -#define OMV_DTCM_ORIGIN 0x20000000 -#define OMV_DTCM_LENGTH 384K -#define OMV_ITCM1_ORIGIN 0x00000000 -#define OMV_ITCM1_LENGTH 32K -#define OMV_ITCM2_ORIGIN 0x00008000 -#define OMV_ITCM2_LENGTH 32K -#define OMV_OCRM1_ORIGIN 0x20200000 -#define OMV_OCRM1_LENGTH 512K -#define OMV_OCRM2_ORIGIN 0x20280000 // Allocated from FlexRAM. -#define OMV_OCRM2_LENGTH 64K -#define OMV_DRAM_ORIGIN 0x80000000 -#define OMV_DRAM_LENGTH 32M -#define OMV_FLEXRAM_CONFIG (0x5AAAAAAF) // OCRAM: 64K DTCM: 384K ITCM: 64K +#define OMV_DTCM_ORIGIN 0x20000000 +#define OMV_DTCM_LENGTH 384K +#define OMV_ITCM1_ORIGIN 0x00000000 +#define OMV_ITCM1_LENGTH 32K +#define OMV_ITCM2_ORIGIN 0x00008000 +#define OMV_ITCM2_LENGTH 32K +#define OMV_OCRM1_ORIGIN 0x20200000 +#define OMV_OCRM1_LENGTH 512K +#define OMV_OCRM2_ORIGIN 0x20280000 // Allocated from FlexRAM. +#define OMV_OCRM2_LENGTH 64K +#define OMV_DRAM_ORIGIN 0x80000000 +#define OMV_DRAM_LENGTH 32M +#define OMV_FLEXRAM_CONFIG (0x5AAAAAAF) // OCRAM: 64K DTCM: 384K ITCM: 64K // Flash configuration. -#define OMV_FLASH_ORIGIN 0x60000000 -#define OMV_FLASH_LENGTH 0x00800000 +#define OMV_FLASH_ORIGIN 0x60000000 +#define OMV_FLASH_LENGTH 0x00800000 -#define OMV_FLASH_APP_ORIGIN 0x60040000 // 256K reserved for bootloader -#define OMV_FLASH_APP_LENGTH 0x007C0000 +#define OMV_FLASH_APP_ORIGIN 0x60040000 // 256K reserved for bootloader +#define OMV_FLASH_APP_LENGTH 0x007C0000 -#define OMV_FLASH_TXT_ORIGIN 0x60043000 -#define OMV_FLASH_TXT_LENGTH 0x00380000 +#define OMV_FLASH_TXT_ORIGIN 0x60043000 +#define OMV_FLASH_TXT_LENGTH 0x00380000 -#define OMV_FLASH_FFS_ORIGIN 0x60400000 -#define OMV_FLASH_FFS_LENGTH 0x00400000 +#define OMV_FLASH_FFS_ORIGIN 0x60400000 +#define OMV_FLASH_FFS_LENGTH 0x00400000 -// ISC I2C configuration. -#define ISC_I2C_ID (1) -#define ISC_I2C_SPEED (OMV_I2C_SPEED_STANDARD) +// Main image sensor I2C bus +#define ISC_I2C_ID (1) +#define ISC_I2C_SPEED (OMV_I2C_SPEED_STANDARD) -// FIR I2C configuration. -#define FIR_I2C_ID (4) -#define FIR_I2C_SPEED (OMV_I2C_SPEED_FULL) +// Thermal image sensor I2C bus +#define FIR_I2C_ID (4) +#define FIR_I2C_SPEED (OMV_I2C_SPEED_FULL) -// ISC SPI configuration. -#define ISC_SPI_ID (4) -#define ISC_SPI_BAUDRATE (20000000) +// Main image sensor SPI bus +#define ISC_SPI_ID (4) // Physical I2C buses. + // LPI2C1 -#define LPI2C1_ID (1) -#define LPI2C1_SCL_PIN (&omv_pin_LPI2C1_SCL) -#define LPI2C1_SDA_PIN (&omv_pin_LPI2C1_SDA) +#define LPI2C1_ID (1) +#define LPI2C1_SCL_PIN (&omv_pin_LPI2C1_SCL) +#define LPI2C1_SDA_PIN (&omv_pin_LPI2C1_SDA) + +// LPI2C2 +#define LPI2C2_ID (2) +#define LPI2C2_SCL_PIN (&omv_pin_LPI2C2_SCL) +#define LPI2C2_SDA_PIN (&omv_pin_LPI2C2_SDA) // LPI2C4 -#define LPI2C4_ID (4) -#define LPI2C4_SCL_PIN (&omv_pin_LPI2C4_SCL) -#define LPI2C4_SDA_PIN (&omv_pin_LPI2C4_SDA) +#define LPI2C4_ID (4) +#define LPI2C4_SCL_PIN (&omv_pin_LPI2C4_SCL) +#define LPI2C4_SDA_PIN (&omv_pin_LPI2C4_SDA) // Physical SPI buses. -// LPSPI4 -#define LPSPI4_ID (4) -#define LPSPI4_SCLK_PIN (&omv_pin_LPSPI4_SCLK) -#define LPSPI4_MISO_PIN (&omv_pin_LPSPI4_MISO) -#define LPSPI4_MOSI_PIN (&omv_pin_LPSPI4_MOSI) -#define LPSPI4_SSEL_PIN (&omv_pin_LPSPI4_SSEL) -#define LPSPI4_DMA (DMA0) -#define LPSPI4_DMA_MUX (DMAMUX) -#define LPSPI4_DMA_TX_CHANNEL (1U) -#define LPSPI4_DMA_RX_CHANNEL (0U) +// LPSPI3 +#define LPSPI3_ID (3) +#define LPSPI3_SCLK_PIN (&omv_pin_LPSPI3_SCLK) +#define LPSPI3_MISO_PIN (&omv_pin_LPSPI3_MISO) +#define LPSPI3_MOSI_PIN (&omv_pin_LPSPI3_MOSI) +#define LPSPI3_SSEL_PIN (&omv_pin_LPSPI3_SSEL) +#define LPSPI3_DMA (DMA0) +#define LPSPI3_DMA_MUX (DMAMUX) +#define LPSPI3_DMA_TX_CHANNEL (3U) +#define LPSPI3_DMA_RX_CHANNEL (2U) + +// LPSPI4 +#define LPSPI4_ID (4) +#define LPSPI4_SCLK_PIN (&omv_pin_LPSPI4_SCLK) +#define LPSPI4_MISO_PIN (&omv_pin_LPSPI4_MISO) +#define LPSPI4_MOSI_PIN (&omv_pin_LPSPI4_MOSI) +#define LPSPI4_SSEL_PIN (&omv_pin_LPSPI4_SSEL) +#define LPSPI4_DMA (DMA0) +#define LPSPI4_DMA_MUX (DMAMUX) +#define LPSPI4_DMA_TX_CHANNEL (1U) +#define LPSPI4_DMA_RX_CHANNEL (0U) + +// SPI LCD Interface +#define OMV_SPI_LCD_SPI_BUS (LPSPI3_ID) +#define OMV_SPI_LCD_MOSI_PIN (&omv_pin_LPSPI3_MOSI) +#define OMV_SPI_LCD_MISO_PIN (&omv_pin_LPSPI3_MISO) +#define OMV_SPI_LCD_SCLK_PIN (&omv_pin_LPSPI3_SCLK) +#define OMV_SPI_LCD_SSEL_PIN (&omv_pin_LPSPI3_GPIO) + +#define OMV_SPI_LCD_RS_PIN (&omv_pin_P8_GPIO) +#define OMV_SPI_LCD_BL_PIN (&omv_pin_P6_GPIO) +#define OMV_SPI_LCD_RST_PIN (&omv_pin_P7_GPIO) + +#define OMV_SPI_LCD_DEF_TRIPLE_BUF (true) + +#define OMV_SPI_LCD_RX_CLK_DIV (8) + +// FIR Lepton +#define OMV_FIR_LEPTON_I2C_BUS (FIR_I2C_ID) +#define OMV_FIR_LEPTON_I2C_BUS_SPEED (FIR_I2C_SPEED) + +#define OMV_FIR_LEPTON_SPI_BUS (LPSPI3_ID) +#define OMV_FIR_LEPTON_MOSI_PIN (&omv_pin_LPSPI3_MOSI) +#define OMV_FIR_LEPTON_MISO_PIN (&omv_pin_LPSPI3_MISO) +#define OMV_FIR_LEPTON_SCLK_PIN (&omv_pin_LPSPI3_SCLK) +#define OMV_FIR_LEPTON_SSEL_PIN (&omv_pin_LPSPI3_GPIO) + +#define OMV_FIR_LEPTON_RX_CLK_DIV (8) // Camera interface configuration. -#define OMV_CSI_BASE (CSI) +#define OMV_CSI_BASE (CSI) -#define DCMI_RESET_PIN (&omv_pin_DCMI_RESET) -#define DCMI_POWER_PIN (&omv_pin_DCMI_POWER) -//#define DCMI_FSYNC_PIN (&omv_pin_DCMI_FSYNC) +#define DCMI_RESET_PIN (&omv_pin_DCMI_RESET) +#define DCMI_POWER_PIN (&omv_pin_DCMI_POWER) +//#define DCMI_FSYNC_PIN (&omv_pin_DCMI_FSYNC) -#define DCMI_D0_PIN (&omv_pin_DCMI_D0) -#define DCMI_D1_PIN (&omv_pin_DCMI_D1) -#define DCMI_D2_PIN (&omv_pin_DCMI_D2) -#define DCMI_D3_PIN (&omv_pin_DCMI_D3) -#define DCMI_D4_PIN (&omv_pin_DCMI_D4) -#define DCMI_D5_PIN (&omv_pin_DCMI_D5) -#define DCMI_D6_PIN (&omv_pin_DCMI_D6) -#define DCMI_D7_PIN (&omv_pin_DCMI_D7) -#define DCMI_MCLK_PIN (&omv_pin_DCMI_MCLK) -#define DCMI_HSYNC_PIN (&omv_pin_DCMI_HSYNC) -#define DCMI_VSYNC_PIN (&omv_pin_DCMI_VSYNC) -#define DCMI_PXCLK_PIN (&omv_pin_DCMI_PXCLK) +#define DCMI_D0_PIN (&omv_pin_DCMI_D0) +#define DCMI_D1_PIN (&omv_pin_DCMI_D1) +#define DCMI_D2_PIN (&omv_pin_DCMI_D2) +#define DCMI_D3_PIN (&omv_pin_DCMI_D3) +#define DCMI_D4_PIN (&omv_pin_DCMI_D4) +#define DCMI_D5_PIN (&omv_pin_DCMI_D5) +#define DCMI_D6_PIN (&omv_pin_DCMI_D6) +#define DCMI_D7_PIN (&omv_pin_DCMI_D7) +#define DCMI_MCLK_PIN (&omv_pin_DCMI_MCLK) +#define DCMI_HSYNC_PIN (&omv_pin_DCMI_HSYNC) +#define DCMI_VSYNC_PIN (&omv_pin_DCMI_VSYNC) +#define DCMI_PXCLK_PIN (&omv_pin_DCMI_PXCLK) #endif //__OMV_BOARDCONFIG_H__ diff --git a/src/omv/boards/OPENMV_RT1060/omv_boardconfig.mk b/src/omv/boards/OPENMV_RT1060/omv_boardconfig.mk index 0864f872b..d7cd15e89 100755 --- a/src/omv/boards/OPENMV_RT1060/omv_boardconfig.mk +++ b/src/omv/boards/OPENMV_RT1060/omv_boardconfig.mk @@ -19,6 +19,6 @@ MICROPY_PY_LWIP = 1 MICROPY_PY_NETWORK_CYW43 = 1 MICROPY_PY_BLUETOOTH = 1 MICROPY_BLUETOOTH_NIMBLE = 1 -MICROPY_PY_LCD = 0 -MICROPY_PY_TV = 0 +MICROPY_PY_LCD = 1 +MICROPY_PY_TV = 1 MICROPY_PY_BUZZER = 0 diff --git a/src/omv/boards/OPENMV_RT1060/omv_pins.h b/src/omv/boards/OPENMV_RT1060/omv_pins.h index a98f8a136..26f5d34cc 100644 --- a/src/omv/boards/OPENMV_RT1060/omv_pins.h +++ b/src/omv/boards/OPENMV_RT1060/omv_pins.h @@ -1,13 +1,27 @@ OMV_GPIO_DEFINE(LPI2C1_SCL, AD_B1_00, LPI2C1, 1) OMV_GPIO_DEFINE(LPI2C1_SDA, AD_B1_01, LPI2C1, 1) +OMV_GPIO_DEFINE(LPI2C2_SCL, B0_04, LPI2C2, 1) +OMV_GPIO_DEFINE(LPI2C2_SDA, B0_05, LPI2C2, 1) + OMV_GPIO_DEFINE(LPI2C4_SCL, AD_B0_12, LPI2C4, 1) OMV_GPIO_DEFINE(LPI2C4_SDA, AD_B0_13, LPI2C4, 1) +OMV_GPIO_DEFINE(LPSPI3_SCLK, AD_B0_00, LPSPI3, 0) +OMV_GPIO_DEFINE(LPSPI3_MISO, AD_B0_02, LPSPI3, 0) +OMV_GPIO_DEFINE(LPSPI3_MOSI, AD_B0_01, LPSPI3, 0) +OMV_GPIO_DEFINE(LPSPI3_SSEL, AD_B0_03, LPSPI3, 0) +OMV_GPIO_DEFINE(LPSPI3_GPIO, AD_B0_03, GPIO, 0) + OMV_GPIO_DEFINE(LPSPI4_SCLK, B0_03, LPSPI4, 0) OMV_GPIO_DEFINE(LPSPI4_MISO, B0_02, LPSPI4, 0) OMV_GPIO_DEFINE(LPSPI4_MOSI, B0_01, LPSPI4, 0) OMV_GPIO_DEFINE(LPSPI4_SSEL, B0_00, LPSPI4, 0) +OMV_GPIO_DEFINE(LPSPI4_GPIO, B0_00, GPIO, 0) + +OMV_GPIO_DEFINE(P6_GPIO, AD_B1_03, GPIO, 0) +OMV_GPIO_DEFINE(P7_GPIO, B0_06, GPIO, 0) +OMV_GPIO_DEFINE(P8_GPIO, B0_07, GPIO, 0) OMV_GPIO_DEFINE(DCMI_D0, AD_B1_15, CSI, 0) OMV_GPIO_DEFINE(DCMI_D1, AD_B1_14, CSI, 0) diff --git a/src/omv/common/vospi.c b/src/omv/common/vospi.c index fa4c1c04a..c6dbfc362 100644 --- a/src/omv/common/vospi.c +++ b/src/omv/common/vospi.c @@ -10,38 +10,48 @@ */ #include "omv_boardconfig.h" #if OMV_ENABLE_VOSPI || OMV_ENABLE_LEPTON +#include #include "py/mphal.h" +#include "vospi.h" #include "crc16.h" #include "omv_common.h" #include "omv_spi.h" -static volatile bool waiting_for_data = false; -static uint16_t *framebuffer = 0; +typedef struct _vospi_state { + int pid; + int sid; + uint16_t *framebuffer; + bool lepton_3; + omv_spi_t spi_bus; + volatile bool waiting_for_data; + volatile bool resync_flag; +} vospi_state_t; -static bool vospi_lepton_3 = false; +static vospi_state_t vospi; -static omv_spi_t spi_bus = {}; +#define VOSPI_HEADER_WORDS (2) // 16-bits +#define VOSPI_PID_SIZE_PIXELS (80) // w, 16-bits per pixel +#define VOSPI_PIDS_PER_SEG (60) // h +#define VOSPI_SEGS_PER_FRAME (4) +#define VOSPI_PACKET_SIZE (VOSPI_HEADER_WORDS + VOSPI_PID_SIZE_PIXELS) // 16-bits +#define VOSPI_SEG_SIZE_PIXELS (VOSPI_PIDS_PER_SEG * VOSPI_PID_SIZE_PIXELS) // 16-bits -#define VOSPI_HEADER_WORDS (2) // 16-bits -#define VOSPI_PID_SIZE_PIXELS (80) // w, 16-bits per pixel -#define VOSPI_PIDS_PER_SEG (60) // h -#define VOSPI_SEGS_PER_FRAME (4) -#define VOSPI_PACKET_SIZE (VOSPI_HEADER_WORDS + VOSPI_PID_SIZE_PIXELS) // 16-bits -#define VOSPI_SEG_SIZE_PIXELS (VOSPI_PIDS_PER_SEG * VOSPI_PID_SIZE_PIXELS) // 16-bits +#define VOSPI_SPECIAL_PACKET (20) +#define VOSPI_DONT_CARE_PACKET (0x0F00) +#define VOSPI_HEADER_DONT_CARE(x) (((x) & VOSPI_DONT_CARE_PACKET) == VOSPI_DONT_CARE_PACKET) +#define VOSPI_HEADER_PID(id) ((id) & 0x0FFF) +#define VOSPI_HEADER_SID(id) (((id) >> 12) & 0x7) -#define VOSPI_BUFFER_SIZE (VOSPI_PACKET_SIZE * 2) // 16-bits -#define VOSPI_CLOCK_SPEED 20000000 // hz -#define VOSPI_SYNC_MS 200 // ms +#define VOSPI_BUFFER_SIZE (VOSPI_PACKET_SIZE * 2) // 16-bits +#define VOSPI_CLOCK_SPEED 20000000 // hz +#define VOSPI_SYNC_MS 200 // ms -static int vospi_rx_cb_expected_pid = 0; -static int vospi_rx_cb_expected_seg = 0; static uint16_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED_DMA(vospi_buf[VOSPI_BUFFER_SIZE]), ".dma_buffer"); -static void vospi_callback(omv_spi_t *spi, void *userdata, void *rxbuf); +static void vospi_callback(omv_spi_t *spi, void *userdata, void *buf); -static volatile bool vospi_resync_callback_flag = true; -static void vospi_resync_callback() { +static void vospi_resync() { omv_spi_transfer_t spi_xfer = { .rxbuf = vospi_buf, .size = VOSPI_BUFFER_SIZE, @@ -50,7 +60,7 @@ static void vospi_resync_callback() { }; mp_hal_delay_ms(VOSPI_SYNC_MS); - omv_spi_transfer_start(&spi_bus, &spi_xfer); + omv_spi_transfer_start(&vospi.spi_bus, &spi_xfer); } #if defined(OMV_ENABLE_VOSPI_CRC) @@ -72,80 +82,76 @@ static bool vospi_check_crc(const uint16_t *base) { } #endif - -void vospi_callback(omv_spi_t *spi, void *userdata, void *rxbuf) { - if (!waiting_for_data) { +void vospi_callback(omv_spi_t *spi, void *userdata, void *buf) { + if (!vospi.waiting_for_data) { return; } - const uint16_t *base = (uint16_t *) rxbuf; + const uint16_t *base = (uint16_t *) buf; int id = base[0]; // Ignore don't care packets. - if ((id & 0x0F00) == 0x0F00) { + if (VOSPI_HEADER_DONT_CARE(id)) { return; } - int pid = id & 0x0FFF; - int seg = ((id >> 12) & 0x7) - 1; + int pid = VOSPI_HEADER_PID(id); + int sid = VOSPI_HEADER_SID(id) - 1; // Discard packets with a pid != 0 when waiting for the first packet. - if ((vospi_rx_cb_expected_pid == 0) && (pid != 0)) { + if ((vospi.pid == 0) && (pid != 0)) { return; } - // Discard segments with a seg != 0 when waiting for the first segment. - if (vospi_lepton_3 && (pid == 20) && (vospi_rx_cb_expected_seg == 0) && (seg != 0)) { - vospi_rx_cb_expected_pid = 0; + // Discard segments with a sid != 0 when waiting for the first segment. + if (vospi.lepton_3 && (pid == VOSPI_SPECIAL_PACKET) && (vospi.sid == 0) && (sid != 0)) { + vospi.pid = 0; return; } // Are we in sync with the flir lepton? - if ((pid != vospi_rx_cb_expected_pid) + if ((pid != vospi.pid) #if defined(OMV_ENABLE_VOSPI_CRC) || (!vospi_check_crc(base)) #endif - || (vospi_lepton_3 && (pid == 20) && (seg != vospi_rx_cb_expected_seg))) { - vospi_rx_cb_expected_pid = 0; - vospi_rx_cb_expected_seg = 0; - omv_spi_transfer_abort(&spi_bus); - vospi_resync_callback_flag = true; + || (vospi.lepton_3 && (pid == VOSPI_SPECIAL_PACKET) && (sid != vospi.sid))) { + vospi.pid = 0; + vospi.sid = 0; + omv_spi_transfer_abort(&vospi.spi_bus); + vospi.resync_flag = true; return; } - memcpy(framebuffer - + (vospi_rx_cb_expected_pid * VOSPI_PID_SIZE_PIXELS) - + (vospi_rx_cb_expected_seg * VOSPI_SEG_SIZE_PIXELS), + memcpy(vospi.framebuffer + + (vospi.pid * VOSPI_PID_SIZE_PIXELS) + + (vospi.sid * VOSPI_SEG_SIZE_PIXELS), base + VOSPI_HEADER_WORDS, VOSPI_PID_SIZE_PIXELS * sizeof(uint16_t)); - vospi_rx_cb_expected_pid += 1; - if (vospi_rx_cb_expected_pid == VOSPI_PIDS_PER_SEG) { - vospi_rx_cb_expected_pid = 0; - - bool frame_ready = false; + vospi.pid += 1; + if (vospi.pid == VOSPI_PIDS_PER_SEG) { + vospi.pid = 0; // For the FLIR Lepton 3 we have to receive all the pids in all the segments. - if (vospi_lepton_3) { - vospi_rx_cb_expected_seg += 1; - if (vospi_rx_cb_expected_seg == VOSPI_SEGS_PER_FRAME) { - vospi_rx_cb_expected_seg = 0; - frame_ready = true; + if (vospi.lepton_3) { + vospi.sid += 1; + if (vospi.sid == VOSPI_SEGS_PER_FRAME) { + vospi.sid = 0; + vospi.waiting_for_data = false; } // For the FLIR Lepton 1/2 we just have to receive all the pids. } else { - frame_ready = true; - } - - if (frame_ready) { - waiting_for_data = false; + vospi.waiting_for_data = false; } } } int vospi_init(uint32_t n_packets, void *buffer) { - vospi_lepton_3 = n_packets > VOSPI_PIDS_PER_SEG; - framebuffer = buffer; + memset(&vospi, 0, sizeof(vospi_state_t)); + vospi.lepton_3 = n_packets > VOSPI_PIDS_PER_SEG; + vospi.framebuffer = buffer; + // resync on first snapshot. + vospi.resync_flag = true; omv_spi_config_t spi_config; omv_spi_default_config(&spi_config, ISC_SPI_ID); @@ -154,37 +160,37 @@ int vospi_init(uint32_t n_packets, void *buffer) { spi_config.bus_mode = OMV_SPI_BUS_RX; spi_config.dma_flags = OMV_SPI_DMA_CIRCULAR | OMV_SPI_DMA_DOUBLE; - if (omv_spi_init(&spi_bus, &spi_config) != 0) { + if (omv_spi_init(&vospi.spi_bus, &spi_config) != 0) { return -1; } return 0; } int vospi_snapshot(uint32_t timeout_ms) { - waiting_for_data = true; + vospi.waiting_for_data = true; mp_uint_t tick_start = mp_hal_ticks_ms(); for (;;) { - if (vospi_resync_callback_flag) { - vospi_resync_callback_flag = false; - vospi_resync_callback(); + if (vospi.resync_flag) { + vospi.resync_flag = false; + vospi_resync(); } - if (!waiting_for_data) { + if (!vospi.waiting_for_data) { break; } - MICROPY_EVENT_POLL_HOOK - if ((mp_hal_ticks_ms() - tick_start) > timeout_ms) { - omv_spi_transfer_abort(&spi_bus); - waiting_for_data = false; - vospi_rx_cb_expected_pid = 0; - vospi_rx_cb_expected_seg = 0; - vospi_resync_callback_flag = true; + omv_spi_transfer_abort(&vospi.spi_bus); + vospi.waiting_for_data = false; + vospi.pid = 0; + vospi.sid = 0; + vospi.resync_flag = true; return -1; } + + MICROPY_EVENT_POLL_HOOK } return 0; diff --git a/src/omv/modules/py_fir_lepton.c b/src/omv/modules/py_fir_lepton.c index bded8cd14..9a4f05876 100644 --- a/src/omv/modules/py_fir_lepton.c +++ b/src/omv/modules/py_fir_lepton.c @@ -45,16 +45,22 @@ static TIM_HandleTypeDef fir_lepton_mclk_tim_handle = {}; static LEP_CAMERA_PORT_DESC_T fir_lepton_handle = {}; static omv_spi_t spi_bus = {}; -#define VOSPI_HEADER_WORDS (2) // 16-bits -#define VOSPI_PID_SIZE_PIXELS (80) // w, 16-bits per pixel -#define VOSPI_PIDS_PER_SEG (60) // h -#define VOSPI_SEGS_PER_FRAME (4) -#define VOSPI_PACKET_SIZE (VOSPI_HEADER_WORDS + VOSPI_PID_SIZE_PIXELS) // 16-bits -#define VOSPI_SEG_SIZE_PIXELS (VOSPI_PIDS_PER_SEG * VOSPI_PID_SIZE_PIXELS) // 16-bits +#define VOSPI_HEADER_WORDS (2) // 16-bits +#define VOSPI_PID_SIZE_PIXELS (80) // w, 16-bits per pixel +#define VOSPI_PIDS_PER_SEG (60) // h +#define VOSPI_SEGS_PER_FRAME (4) +#define VOSPI_PACKET_SIZE (VOSPI_HEADER_WORDS + VOSPI_PID_SIZE_PIXELS) // 16-bits +#define VOSPI_SEG_SIZE_PIXELS (VOSPI_PIDS_PER_SEG * VOSPI_PID_SIZE_PIXELS) // 16-bits -#define VOSPI_BUFFER_SIZE (VOSPI_PACKET_SIZE * 2) // 16-bits -#define VOSPI_CLOCK_SPEED 20000000 // hz -#define VOSPI_SYNC_MS 200 // ms +#define VOSPI_SPECIAL_PACKET (20) +#define VOSPI_DONT_CARE_PACKET (0x0F00) +#define VOSPI_HEADER_DONT_CARE(x) (((x) & VOSPI_DONT_CARE_PACKET) == VOSPI_DONT_CARE_PACKET) +#define VOSPI_HEADER_PID(id) ((id) & 0x0FFF) +#define VOSPI_HEADER_SID(id) (((id) >> 12) & 0x7) + +#define VOSPI_BUFFER_SIZE (VOSPI_PACKET_SIZE * 2) // 16-bits +#define VOSPI_CLOCK_SPEED 20000000 // hz +#define VOSPI_SYNC_MS 200 // ms static soft_timer_entry_t flir_lepton_spi_rx_timer = {}; static int fir_lepton_spi_rx_cb_tail = 0; @@ -119,12 +125,12 @@ void fir_lepton_spi_callback(omv_spi_t *spi, void *userdata, void *buf) { int id = base[0]; // Ignore don't care packets. - if ((id & 0x0F00) == 0x0F00) { + if (VOSPI_HEADER_DONT_CARE(id)) { return; } - int pid = id & 0x0FFF; - int seg = ((id >> 12) & 0x7) - 1; + int pid = VOSPI_HEADER_PID(id); + int seg = VOSPI_HEADER_SID(id) - 1; // Discard packets with a pid != 0 when waiting for the first packet. if ((fir_lepton_spi_rx_cb_expected_pid == 0) && (pid != 0)) { @@ -132,7 +138,7 @@ void fir_lepton_spi_callback(omv_spi_t *spi, void *userdata, void *buf) { } // Discard segments with a seg != 0 when waiting for the first segment. - if (fir_lepton_3 && (pid == 20) && (fir_lepton_spi_rx_cb_expected_seg == 0) && (seg != 0)) { + if (fir_lepton_3 && (pid == VOSPI_SPECIAL_PACKET) && (fir_lepton_spi_rx_cb_expected_seg == 0) && (seg != 0)) { fir_lepton_spi_rx_cb_expected_pid = 0; return; } @@ -142,7 +148,7 @@ void fir_lepton_spi_callback(omv_spi_t *spi, void *userdata, void *buf) { #if defined(OMV_FIR_LEPTON_CHECK_CRC) || (!fir_lepton_spi_check_crc(base)) #endif - || (fir_lepton_3 && (pid == 20) && (seg != fir_lepton_spi_rx_cb_expected_seg))) { + || (fir_lepton_3 && (pid == VOSPI_SPECIAL_PACKET) && (seg != fir_lepton_spi_rx_cb_expected_seg))) { fir_lepton_spi_rx_cb_expected_pid = 0; fir_lepton_spi_rx_cb_expected_seg = 0; omv_spi_transfer_abort(&spi_bus); diff --git a/src/omv/ports/mimxrt/main.c b/src/omv/ports/mimxrt/main.c index f9ad2c579..6d4a84522 100644 --- a/src/omv/ports/mimxrt/main.c +++ b/src/omv/ports/mimxrt/main.c @@ -28,6 +28,10 @@ #include "systick.h" #include "modmimxrt.h" +#include "py_lcd.h" +#include "py_fir.h" +#include "py_tv.h" + #if MICROPY_PY_LWIP #include "lwip/init.h" #include "lwip/apps/mdns.h" @@ -114,7 +118,7 @@ soft_reset: #if MICROPY_PY_LCD py_lcd_init0(); #endif - //py_fir_init0(); + py_fir_init0(); #if MICROPY_PY_TV py_tv_init0(); #endif diff --git a/src/omv/ports/mimxrt/mimxrt.ld.S b/src/omv/ports/mimxrt/mimxrt.ld.S index 728938e30..7b9e55183 100644 --- a/src/omv/ports/mimxrt/mimxrt.ld.S +++ b/src/omv/ports/mimxrt/mimxrt.ld.S @@ -234,10 +234,6 @@ SECTIONS _vfs_buf = .; // VFS struct + FATFS file buffer (around 624 bytes) . = . + OMV_VFS_BUF_SIZE; - . = ALIGN(16); - _fir_lepton_buf = .; // FIR Lepton Packet Double Buffer (328 bytes) - . = . + OMV_FIR_LEPTON_BUF_SIZE; - #if !defined(OMV_JPEG_MEMORY) . = ALIGN(16); _jpeg_buf = .; // IDE JPEG buffer diff --git a/src/omv/ports/mimxrt/omv_portconfig.h b/src/omv/ports/mimxrt/omv_portconfig.h index 874e09343..fe10f2668 100644 --- a/src/omv/ports/mimxrt/omv_portconfig.h +++ b/src/omv/ports/mimxrt/omv_portconfig.h @@ -46,7 +46,6 @@ #define OMV_GPIO_MODE_IT_FALL ((6 << 17) | IOMUXC_PAD_CTL(DSE, 0U) | IOMUXC_PAD_CTL(HYS, 1U)) #define OMV_GPIO_MODE_IT_RISE ((7 << 17) | IOMUXC_PAD_CTL(DSE, 0U) | IOMUXC_PAD_CTL(HYS, 1U)) #define OMV_GPIO_MODE_IT_BOTH ((8 << 17) | IOMUXC_PAD_CTL(DSE, 0U) | IOMUXC_PAD_CTL(HYS, 1U)) - // *INDENT-OFF* typedef struct { diff --git a/src/omv/ports/mimxrt/omv_portconfig.mk b/src/omv/ports/mimxrt/omv_portconfig.mk index f5b0966c5..88994c355 100644 --- a/src/omv/ports/mimxrt/omv_portconfig.mk +++ b/src/omv/ports/mimxrt/omv_portconfig.mk @@ -40,6 +40,7 @@ MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/lib/tinyusb/src MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/lib/lwip/src/include/ MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/ports/mimxrt/ MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/ports/mimxrt/lwip_inc/ +MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/shared/runtime/ ifeq ($(MICROPY_PY_LWIP), 0) MICROPY_ARGS += MICROPY_PY_LWIP=0 MICROPY_PY_USSL=0 diff --git a/src/omv/ports/mimxrt/omv_spi.c b/src/omv/ports/mimxrt/omv_spi.c index 24658ae28..90496cc6b 100644 --- a/src/omv/ports/mimxrt/omv_spi.c +++ b/src/omv/ports/mimxrt/omv_spi.c @@ -17,7 +17,6 @@ #include "fsl_lpspi_edma.h" #include "fsl_dmamux.h" #include CLOCK_CONFIG_H -#include "dma_manager.h" #include "mimxrt_hal.h" #include "omv_common.h" @@ -26,6 +25,7 @@ typedef struct dma_descr { DMA_Type *dma_inst; DMAMUX_Type *dma_mux; + uint32_t channel; uint32_t request; } dma_descr_t; @@ -39,63 +39,45 @@ typedef struct omv_spi_descr { static const omv_spi_descr_t omv_spi_descr_all[] = { #if defined(LPSPI1_ID) { LPSPI1, LPSPI1_SSEL_PIN, - { DMA0, DMAMUX, kDmaRequestMuxLPSPI1Tx }, - { DMA0, DMAMUX, kDmaRequestMuxLPSPI1Rx } }, + { LPSPI1_DMA, LPSPI1_DMA_MUX, LPSPI1_DMA_TX_CHANNEL, kDmaRequestMuxLPSPI1Tx }, + { LPSPI1_DMA, LPSPI1_DMA_MUX, LPSPI1_DMA_RX_CHANNEL, kDmaRequestMuxLPSPI1Rx } }, #else - { NULL, NULL, { NULL, NULL, 0 }, { NULL, NULL, 0 } }, + { NULL, NULL, { NULL, NULL, 0, 0 }, { NULL, NULL, 0, 0 } }, #endif #if defined(LPSPI2_ID) { LPSPI2, LPSPI2_SSEL_PIN, - { DMA0, DMAMUX, kDmaRequestMuxLPSPI2Tx }, - { DMA0, DMAMUX, kDmaRequestMuxLPSPI2Rx } }, + { LPSPI2_DMA, LPSPI2_DMA_MUX, LPSPI2_DMA_TX_CHANNEL, kDmaRequestMuxLPSPI2Tx }, + { LPSPI2_DMA, LPSPI2_DMA_MUX, LPSPI2_DMA_RX_CHANNEL, kDmaRequestMuxLPSPI2Rx } }, #else - { NULL, NULL, { NULL, NULL, 0 }, { NULL, NULL, 0 } }, + { NULL, NULL, { NULL, NULL, 0, 0 }, { NULL, NULL, 0, 0 } }, #endif #if defined(LPSPI3_ID) { LPSPI3, LPSPI3_SSEL_PIN, - { DMA0, DMAMUX, kDmaRequestMuxLPSPI3Tx }, - { DMA0, DMAMUX, kDmaRequestMuxLPSPI3Rx } }, + { LPSPI3_DMA, LPSPI3_DMA_MUX, LPSPI3_DMA_TX_CHANNEL, kDmaRequestMuxLPSPI3Tx }, + { LPSPI3_DMA, LPSPI3_DMA_MUX, LPSPI3_DMA_RX_CHANNEL, kDmaRequestMuxLPSPI3Rx } }, #else - { NULL, NULL, { NULL, NULL, 0 }, { NULL, NULL, 0 } }, + { NULL, NULL, { NULL, NULL, 0, 0 }, { NULL, NULL, 0, 0 } }, #endif #if defined(LPSPI4_ID) { LPSPI4, LPSPI4_SSEL_PIN, - { DMA0, DMAMUX, kDmaRequestMuxLPSPI4Tx }, - { DMA0, DMAMUX, kDmaRequestMuxLPSPI4Rx } }, + { LPSPI4_DMA, LPSPI4_DMA_MUX, LPSPI4_DMA_TX_CHANNEL, kDmaRequestMuxLPSPI4Tx }, + { LPSPI4_DMA, LPSPI4_DMA_MUX, LPSPI4_DMA_RX_CHANNEL, kDmaRequestMuxLPSPI4Rx } }, #else - { NULL, NULL, { NULL, NULL, 0 }, { NULL, NULL, 0 } }, + { NULL, NULL, { NULL, NULL, 0, 0 }, { NULL, NULL, 0, 0 } }, #endif }; -// LPSPI_MasterTransferEDMA doesn't have any code at all to generate a callback on transmit complete. So, we -// add one here that simulates that. However, the DMA interrupt will occur before the SPI bus is done sending -// data. So, we cannot call spi_master_callback below as it will happen before the data is actually sent. Instead, -// we use the SPI transfer complete interrupt to call spi_master_callback at the right time. Note that we have -// to zero out the descriptor to prevent LPSPI_MasterTransferHandleIRQ from doing anything we don't want it to do. +// Enable the SPI frame transfer complete at the end of the DMA transfer, when are absolutely sure that the whole +// DMA transfer is complete. This way we get one interrupt at the end of the transfer, vs after every SPI frame. +// descr_master.rxData must be set to null to ensure LPSPI_MasterTransferHandleIRQ clears the +// kLPSPI_TransferCompleteFlag and calls LPSPI_MasterTransferComplete which calls spi_master_callback. static void EDMA_LpspiMasterTxCallback(edma_handle_t *edmaHandle, void *user, bool transferDone, uint32_t tcds) { omv_spi_t *spi = (omv_spi_t *) user; spi->descr_master_edma.state = (uint8_t) kLPSPI_Idle; - spi->descr_master.state = (uint8_t) kLPSPI_Idle; - spi->descr_master.txData = NULL; spi->descr_master.rxData = NULL; - spi->descr_master.txRemainingByteCount = 0; - spi->descr_master.rxRemainingByteCount = 0; - spi->descr_master.totalByteCount = 0; - spi->descr_master.writeTcrInIsr = false; - spi->descr_master.bytesPerFrame = 0; - spi->descr_master.writeRegRemainingTimes = 0; - spi->descr_master.readRegRemainingTimes = 0; - spi->descr_master.txBuffIfNull = 0; - spi->descr_master.fifoSize = 0; - spi->descr_master.isPcsContinuous = 0; - spi->descr_master.isByteSwap = 0; - spi->descr_master.bytesEachWrite = 0; - spi->descr_master.bytesEachRead = 0; - spi->descr_master.rxWatermark = 0; - spi->descr_master.isTxMask = 0; LPSPI_EnableInterrupts(spi->inst, (uint32_t) kLPSPI_TransferCompleteFlag); } @@ -110,29 +92,24 @@ static void spi_master_callback(LPSPI_Type *base, void *handle, status_t status, omv_spi_transfer_abort(spi); } - void *rxBuf = spi->xfer_descr.rxData; + void *buf = spi->xfer_descr.rxData; + + if (buf == NULL) { + buf = spi->xfer_descr.txData; + } // The IMXRT doesn't support half complete transfer interrupts (in the lpspi driver) like the STM32 // does. So, mimick support for them by toggling the half flag. uint32_t flags = (OMV_SPI_XFER_DMA | OMV_SPI_XFER_COMPLETE); if ((spi->dma_flags & OMV_SPI_DMA_DOUBLE) && ((spi->xfer_flags & flags) == flags)) { - if (spi->xfer_flags & OMV_SPI_XFER_HALF) { - spi->xfer_flags &= ~OMV_SPI_XFER_HALF; - if (spi->xfer_descr.txData) { - spi->xfer_descr.txData -= spi->xfer_descr.dataSize; - } - if (spi->xfer_descr.rxData) { - spi->xfer_descr.rxData -= spi->xfer_descr.dataSize; - } - } else { - spi->xfer_flags |= OMV_SPI_XFER_HALF; - if (spi->xfer_descr.txData) { - spi->xfer_descr.txData += spi->xfer_descr.dataSize; - } - if (spi->xfer_descr.rxData) { - spi->xfer_descr.rxData += spi->xfer_descr.dataSize; - } + int32_t offset = (spi->xfer_flags & OMV_SPI_XFER_HALF) ? -spi->xfer_descr.dataSize : spi->xfer_descr.dataSize; + if (spi->xfer_descr.txData) { + spi->xfer_descr.txData += offset; } + if (spi->xfer_descr.rxData) { + spi->xfer_descr.rxData += offset; + } + spi->xfer_flags ^= OMV_SPI_XFER_HALF; } // Start the next DMA transfer before calling the callback. This minimizes the time @@ -144,12 +121,14 @@ static void spi_master_callback(LPSPI_Type *base, void *handle, status_t status, } if (spi->callback) { - spi->callback(spi, spi->userdata, rxBuf); + spi->callback(spi, spi->userdata, buf); } // Clear after the callback so the callback gets the xfer complete flag set. // This needs to be cleared to prevent circular DMA from re-triggering on a failure. - spi->xfer_flags &= ~(OMV_SPI_XFER_COMPLETE); + if (spi->dma_flags & OMV_SPI_DMA_CIRCULAR) { + spi->xfer_flags &= ~(OMV_SPI_XFER_COMPLETE); + } } // The LPSPI_MasterTransferNonBlocking function call does not clear the LPSPI_TCR_FRAMESZ_MASK bit @@ -169,6 +148,11 @@ void omv_spi_set_frame_size(omv_spi_t *spi, uint16_t size) { } int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) { + // No TX trasnfers in circular or double buffer mode. + if ((spi->dma_flags & (OMV_SPI_DMA_CIRCULAR | OMV_SPI_DMA_DOUBLE)) && xfer->txbuf) { + return -1; + } + spi->callback = xfer->callback; spi->userdata = xfer->userdata; spi->xfer_error = 0; @@ -201,15 +185,7 @@ int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) { spi->xfer_descr.configFlags |= kLPSPI_MasterByteSwap; } - if (spi->xfer_flags & OMV_SPI_XFER_BLOCKING) { - if (LPSPI_MasterTransferBlocking(spi->inst, &spi->xfer_descr) != kStatus_Success) { - return -1; - } - } else if (spi->xfer_flags & OMV_SPI_XFER_NONBLOCK) { - if (LPSPI_MasterTransferNonBlocking(spi->inst, &spi->descr_master, &spi->xfer_descr) != kStatus_Success) { - return -1; - } - } else if (spi->xfer_flags & OMV_SPI_XFER_DMA) { + if (spi->xfer_flags & OMV_SPI_XFER_DMA) { if (LPSPI_MasterTransferEDMA(spi->inst, &spi->descr_master_edma, &spi->xfer_descr) != kStatus_Success) { return -1; } @@ -220,6 +196,28 @@ int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) { EDMA_EnableChannelInterrupts(spi->dma_descr_tx.base, spi->dma_descr_tx.channel, (uint32_t) kEDMA_MajorInterruptEnable); } + } else if (spi->xfer_flags & (OMV_SPI_XFER_BLOCKING | OMV_SPI_XFER_NONBLOCK)) { + // Use non-blocking mode for both non-blocking and blocking + // transfers, this way we can control the timeout better. + if (LPSPI_MasterTransferNonBlocking(spi->inst, &spi->descr_master, &spi->xfer_descr) != kStatus_Success) { + return -1; + } + + // Non-blocking transfetr, return immediately and the user + // callback will be called when the transfer is done. + if (spi->xfer_flags & OMV_SPI_XFER_NONBLOCK) { + return 0; + } + + // Blocking transfetr, wait for transfer complete or timeout. + mp_uint_t start = mp_hal_ticks_ms(); + while (!(spi->xfer_flags & (OMV_SPI_XFER_COMPLETE | OMV_SPI_XFER_FAILED))) { + if ((spi->xfer_flags & OMV_SPI_XFER_FAILED) || + ((mp_hal_ticks_ms() - start) > xfer->timeout)) { + return -1; + } + MICROPY_EVENT_POLL_HOOK + } } else { return -1; } @@ -230,16 +228,16 @@ int omv_spi_transfer_abort(omv_spi_t *spi) { if (spi->dma_flags & (OMV_SPI_DMA_NORMAL | OMV_SPI_DMA_CIRCULAR)) { LPSPI_MasterTransferAbortEDMA(spi->inst, &spi->descr_master_edma); } + // The SPI bus must be aborted too on LPSPI_MasterTransferAbortEDMA. LPSPI_MasterTransferAbort(spi->inst, &spi->descr_master); LPSPI_MasterInit(spi->inst, &spi->config_backup, BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT); return 0; } static int omv_spi_dma_init(edma_handle_t *dma_handle, const dma_descr_t *dma_descr) { - int channel = allocate_dma_channel(); - DMAMUX_SetSource(dma_descr->dma_mux, channel, dma_descr->request); - DMAMUX_EnableChannel(dma_descr->dma_mux, channel); - EDMA_CreateHandle(dma_handle, dma_descr->dma_inst, channel); + DMAMUX_SetSource(dma_descr->dma_mux, dma_descr->channel, dma_descr->request); + DMAMUX_EnableChannel(dma_descr->dma_mux, dma_descr->channel); + EDMA_CreateHandle(dma_handle, dma_descr->dma_inst, dma_descr->channel); return 0; } @@ -312,9 +310,7 @@ int omv_spi_deinit(omv_spi_t *spi) { if (spi->dma_flags & (OMV_SPI_DMA_NORMAL | OMV_SPI_DMA_CIRCULAR)) { const omv_spi_descr_t *spi_descr = &omv_spi_descr_all[spi->id - 1]; DMAMUX_DisableChannel(spi_descr->dma_descr_tx.dma_mux, spi->dma_descr_tx.channel); - free_dma_channel(spi->dma_descr_tx.channel); DMAMUX_DisableChannel(spi_descr->dma_descr_rx.dma_mux, spi->dma_descr_rx.channel); - free_dma_channel(spi->dma_descr_rx.channel); } LPSPI_Deinit(spi->inst); mimxrt_hal_spi_deinit(spi->id); diff --git a/src/omv/ports/stm32/omv_spi.c b/src/omv/ports/stm32/omv_spi.c index 26f7ce5ca..66997abec 100644 --- a/src/omv/ports/stm32/omv_spi.c +++ b/src/omv/ports/stm32/omv_spi.c @@ -124,7 +124,7 @@ static int omv_spi_prescaler(SPI_TypeDef *spi, uint32_t baudrate) { return SPI_BAUDRATEPRESCALER_256; } -static omv_spi_t *omv_spi_get_descr(SPI_HandleTypeDef *hspi) { +static void omv_spi_callback(SPI_HandleTypeDef *hspi) { omv_spi_t *spi = NULL; if (0) { #if defined(SPI1_ID) @@ -152,10 +152,11 @@ static omv_spi_t *omv_spi_get_descr(SPI_HandleTypeDef *hspi) { spi = omv_spi_descr_all[5]; #endif } - return spi; -} -static void omv_spi_callback_error_check(SPI_HandleTypeDef *hspi, omv_spi_t *spi) { + if (spi == NULL) { + return; + } + if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) { spi->xfer_flags |= OMV_SPI_XFER_FAILED; spi->xfer_error = hspi->ErrorCode; @@ -163,45 +164,17 @@ static void omv_spi_callback_error_check(SPI_HandleTypeDef *hspi, omv_spi_t *spi } else { spi->xfer_flags |= OMV_SPI_XFER_COMPLETE; } -} - -static void *omv_spi_callback_rxbuf(omv_spi_t *spi) { - // On TX without RX pRxBuffPtr is zero. - uint8_t *rxbuf = (uint8_t *) spi->descr->pRxBuffPtr; - if (spi->xfer_flags & OMV_SPI_XFER_HALF) { - return rxbuf; - } else { - // On TX without RX RxXferSize is zero. - uint32_t rxsize = spi->descr->RxXferSize * ((spi->xfer_flags & OMV_SPI_XFER_16_BIT) ? 2 : 1); - return rxbuf + (rxsize / 2); - } -} - -static void omv_spi_callback(SPI_HandleTypeDef *hspi) { - omv_spi_t *spi = omv_spi_get_descr(hspi); - if (spi == NULL) { - return; - } - - omv_spi_callback_error_check(hspi, spi); - spi->xfer_flags &= ~OMV_SPI_XFER_HALF; if (spi->callback) { - spi->callback(spi, spi->userdata, omv_spi_callback_rxbuf(spi)); - } -} - -static void omv_spi_half_callback(SPI_HandleTypeDef *hspi) { - omv_spi_t *spi = omv_spi_get_descr(hspi); - if (spi == NULL) { - return; - } - - omv_spi_callback_error_check(hspi, spi); - spi->xfer_flags |= OMV_SPI_XFER_HALF; - - if (spi->callback) { - spi->callback(spi, spi->userdata, omv_spi_callback_rxbuf(spi)); + uint8_t *buf = spi->descr->pRxBuffPtr ? spi->descr->pRxBuffPtr : spi->descr->pTxBuffPtr; + if (spi->dma_flags & OMV_SPI_DMA_DOUBLE) { + if (spi->xfer_flags & OMV_SPI_XFER_HALF) { + uint32_t size = spi->descr->RxXferSize ? spi->descr->RxXferSize : spi->descr->TxXferSize; + buf += (size * ((spi->xfer_flags & OMV_SPI_XFER_16_BIT) ? 2 : 1)) / 2; + } + spi->xfer_flags ^= OMV_SPI_XFER_HALF; + } + spi->callback(spi, spi->userdata, buf); } } @@ -222,6 +195,11 @@ static void omv_spi_dma_burst_mode(DMA_HandleTypeDef *hdma, bool on, bool sixtee } int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) { + // No TX trasnfers in circular or double buffer mode. + if ((spi->dma_flags & (OMV_SPI_DMA_CIRCULAR | OMV_SPI_DMA_DOUBLE)) && xfer->txbuf) { + return -1; + } + spi->callback = xfer->callback; spi->userdata = xfer->userdata; spi->xfer_error = 0; @@ -469,9 +447,9 @@ int omv_spi_init(omv_spi_t *spi, omv_spi_config_t *config) { HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_TX_COMPLETE_CB_ID, omv_spi_callback); HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_RX_COMPLETE_CB_ID, omv_spi_callback); if (config->dma_flags & OMV_SPI_DMA_DOUBLE) { - HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_TX_RX_HALF_COMPLETE_CB_ID, omv_spi_half_callback); - HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_TX_HALF_COMPLETE_CB_ID, omv_spi_half_callback); - HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_RX_HALF_COMPLETE_CB_ID, omv_spi_half_callback); + HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_TX_RX_HALF_COMPLETE_CB_ID, omv_spi_callback); + HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_TX_HALF_COMPLETE_CB_ID, omv_spi_callback); + HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_RX_HALF_COMPLETE_CB_ID, omv_spi_callback); } spi->initialized = true; From d7687260fea592b97ed2a08465a40becf6429a13 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Sun, 17 Sep 2023 22:17:08 -0700 Subject: [PATCH 4/4] drivers: Update SPI code to not reconfigure bus dynamically. --- .../ARDUINO_PORTENTA_H7/omv_boardconfig.h | 2 +- src/omv/boards/OPENMV4P/omv_boardconfig.h | 2 +- src/omv/boards/OPENMVPT/omv_boardconfig.h | 2 +- .../boards/OPENMV_RT1060/omv_boardconfig.h | 2 +- src/omv/common/omv_spi.h | 6 +- src/omv/common/vospi.c | 86 +++---- src/omv/modules/py_fir_lepton.c | 44 ++-- src/omv/modules/py_lcd.c | 234 ++++++++---------- src/omv/ports/mimxrt/mimxrt_hal.c | 1 - src/omv/ports/mimxrt/omv_spi.c | 47 +--- src/omv/ports/stm32/omv_spi.c | 72 ++---- 11 files changed, 194 insertions(+), 304 deletions(-) diff --git a/src/omv/boards/ARDUINO_PORTENTA_H7/omv_boardconfig.h b/src/omv/boards/ARDUINO_PORTENTA_H7/omv_boardconfig.h index 3f229e7a5..a7da981fc 100644 --- a/src/omv/boards/ARDUINO_PORTENTA_H7/omv_boardconfig.h +++ b/src/omv/boards/ARDUINO_PORTENTA_H7/omv_boardconfig.h @@ -372,7 +372,7 @@ #define OMV_SPI_LCD_RS_PIN (&omv_pin_C6_GPIO) #define OMV_SPI_LCD_RST_PIN (&omv_pin_C7_GPIO) -#define OMV_SPI_LCD_DEF_TRIPLE_BUF (true) +#define OMV_SPI_LCD_DEF_TRIPLE_BUF (1) // FIR Lepton #define OMV_FIR_LEPTON_I2C_BUS (FIR_I2C_ID) diff --git a/src/omv/boards/OPENMV4P/omv_boardconfig.h b/src/omv/boards/OPENMV4P/omv_boardconfig.h index f3ac85402..804b0c8ef 100644 --- a/src/omv/boards/OPENMV4P/omv_boardconfig.h +++ b/src/omv/boards/OPENMV4P/omv_boardconfig.h @@ -317,7 +317,7 @@ #define OMV_SPI_LCD_BL_DAC_FORCE_RESET() __HAL_RCC_DAC12_FORCE_RESET() #define OMV_SPI_LCD_BL_DAC_RELEASE_RESET() __HAL_RCC_DAC12_RELEASE_RESET() -#define OMV_SPI_LCD_DEF_TRIPLE_BUF (true) +#define OMV_SPI_LCD_DEF_TRIPLE_BUF (1) // FIR Lepton #define OMV_FIR_LEPTON_I2C_BUS (FIR_I2C_ID) diff --git a/src/omv/boards/OPENMVPT/omv_boardconfig.h b/src/omv/boards/OPENMVPT/omv_boardconfig.h index 2d4f9559b..e3e2efb9b 100644 --- a/src/omv/boards/OPENMVPT/omv_boardconfig.h +++ b/src/omv/boards/OPENMVPT/omv_boardconfig.h @@ -379,7 +379,7 @@ #define OMV_SPI_LCD_BL_DAC_FORCE_RESET() __HAL_RCC_DAC12_FORCE_RESET() #define OMV_SPI_LCD_BL_DAC_RELEASE_RESET() __HAL_RCC_DAC12_RELEASE_RESET() -#define OMV_SPI_LCD_DEF_TRIPLE_BUF (true) +#define OMV_SPI_LCD_DEF_TRIPLE_BUF (1) // DVI TFP410PAP I/O #define OMV_DVI_PRESENT diff --git a/src/omv/boards/OPENMV_RT1060/omv_boardconfig.h b/src/omv/boards/OPENMV_RT1060/omv_boardconfig.h index 22f4c122d..f82a654ab 100644 --- a/src/omv/boards/OPENMV_RT1060/omv_boardconfig.h +++ b/src/omv/boards/OPENMV_RT1060/omv_boardconfig.h @@ -215,7 +215,7 @@ #define OMV_SPI_LCD_BL_PIN (&omv_pin_P6_GPIO) #define OMV_SPI_LCD_RST_PIN (&omv_pin_P7_GPIO) -#define OMV_SPI_LCD_DEF_TRIPLE_BUF (true) +#define OMV_SPI_LCD_DEF_TRIPLE_BUF (1) #define OMV_SPI_LCD_RX_CLK_DIV (8) diff --git a/src/omv/common/omv_spi.h b/src/omv/common/omv_spi.h index a75bc9db5..26d52073d 100644 --- a/src/omv/common/omv_spi.h +++ b/src/omv/common/omv_spi.h @@ -29,13 +29,13 @@ typedef enum { OMV_SPI_XFER_NONBLOCK = (1 << 2), OMV_SPI_XFER_FAILED = (1 << 3), OMV_SPI_XFER_COMPLETE = (1 << 4), - OMV_SPI_XFER_16_BIT = (1 << 5), OMV_SPI_XFER_HALF = (1 << 6), // Internal for Double Buffer mode. } omv_spi_xfer_flags_t; typedef struct _omv_spi_config { uint8_t id; uint32_t baudrate; + uint8_t datasize; uint32_t spi_mode; uint32_t bus_mode; uint32_t bit_order; @@ -49,7 +49,7 @@ typedef struct _omv_spi_config { typedef struct _omv_spi omv_spi_t; -typedef void (*omv_spi_callback_t) (omv_spi_t *spi, void *userdata, void *rxbuf); +typedef void (*omv_spi_callback_t) (omv_spi_t *spi, void *userdata, void *buf); typedef struct _omv_spi_transfer { void *txbuf; @@ -79,7 +79,7 @@ typedef struct _omv_spi { } omv_spi_t; int omv_spi_init(omv_spi_t *spi, omv_spi_config_t *config); -// Default config: MASTER | FDX | 10MHz | MSB FIRST | NSS HARD | NSS/CPHA/CPOL LOW. +// Default config: MASTER | FDX | 10MHz | 8 bits | MSB FIRST | NSS HARD | NSS/CPHA/CPOL LOW. int omv_spi_default_config(omv_spi_config_t *config, uint32_t bus_id); int omv_spi_deinit(omv_spi_t *spi); int omv_spi_set_baudrate(omv_spi_t *spi, uint32_t baudrate); diff --git a/src/omv/common/vospi.c b/src/omv/common/vospi.c index c6dbfc362..31f7f5dc3 100644 --- a/src/omv/common/vospi.c +++ b/src/omv/common/vospi.c @@ -10,33 +10,25 @@ */ #include "omv_boardconfig.h" #if OMV_ENABLE_VOSPI || OMV_ENABLE_LEPTON + #include #include "py/mphal.h" #include "vospi.h" #include "crc16.h" - #include "omv_common.h" #include "omv_spi.h" -typedef struct _vospi_state { - int pid; - int sid; - uint16_t *framebuffer; - bool lepton_3; - omv_spi_t spi_bus; - volatile bool waiting_for_data; - volatile bool resync_flag; -} vospi_state_t; - -static vospi_state_t vospi; - #define VOSPI_HEADER_WORDS (2) // 16-bits #define VOSPI_PID_SIZE_PIXELS (80) // w, 16-bits per pixel -#define VOSPI_PIDS_PER_SEG (60) // h -#define VOSPI_SEGS_PER_FRAME (4) +#define VOSPI_PIDS_PER_SID (60) // h +#define VOSPI_SIDS_PER_FRAME (4) #define VOSPI_PACKET_SIZE (VOSPI_HEADER_WORDS + VOSPI_PID_SIZE_PIXELS) // 16-bits -#define VOSPI_SEG_SIZE_PIXELS (VOSPI_PIDS_PER_SEG * VOSPI_PID_SIZE_PIXELS) // 16-bits +#define VOSPI_SID_SIZE_PIXELS (VOSPI_PIDS_PER_SID * VOSPI_PID_SIZE_PIXELS) // 16-bits + +#define VOSPI_BUFFER_SIZE (VOSPI_PACKET_SIZE * 2) // 16-bits +#define VOSPI_CLOCK_SPEED 20000000 // hz +#define VOSPI_SYNC_MS 200 // ms #define VOSPI_SPECIAL_PACKET (20) #define VOSPI_DONT_CARE_PACKET (0x0F00) @@ -44,9 +36,21 @@ static vospi_state_t vospi; #define VOSPI_HEADER_PID(id) ((id) & 0x0FFF) #define VOSPI_HEADER_SID(id) (((id) >> 12) & 0x7) -#define VOSPI_BUFFER_SIZE (VOSPI_PACKET_SIZE * 2) // 16-bits -#define VOSPI_CLOCK_SPEED 20000000 // hz -#define VOSPI_SYNC_MS 200 // ms +typedef enum { + VOSPI_FLAGS_CAPTURE = (1 << 0), + VOSPI_FLAGS_RESYNC = (1 << 1), +} vospi_flags_t; + +typedef struct _vospi_state { + int pid; + int sid; + uint16_t *framebuffer; + bool lepton_3; + omv_spi_t spi_bus; + volatile uint32_t flags; +} vospi_state_t; + +static vospi_state_t vospi; static uint16_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED_DMA(vospi_buf[VOSPI_BUFFER_SIZE]), ".dma_buffer"); static void vospi_callback(omv_spi_t *spi, void *userdata, void *buf); @@ -55,7 +59,7 @@ static void vospi_resync() { omv_spi_transfer_t spi_xfer = { .rxbuf = vospi_buf, .size = VOSPI_BUFFER_SIZE, - .flags = OMV_SPI_XFER_DMA | OMV_SPI_XFER_16_BIT, + .flags = OMV_SPI_XFER_DMA, .callback = vospi_callback, }; @@ -83,7 +87,7 @@ static bool vospi_check_crc(const uint16_t *base) { #endif void vospi_callback(omv_spi_t *spi, void *userdata, void *buf) { - if (!vospi.waiting_for_data) { + if (!(vospi.flags & VOSPI_FLAGS_CAPTURE)) { return; } @@ -104,7 +108,7 @@ void vospi_callback(omv_spi_t *spi, void *userdata, void *buf) { return; } - // Discard segments with a sid != 0 when waiting for the first segment. + // Discard sidments with a sid != 0 when waiting for the first segment. if (vospi.lepton_3 && (pid == VOSPI_SPECIAL_PACKET) && (vospi.sid == 0) && (sid != 0)) { vospi.pid = 0; return; @@ -119,45 +123,46 @@ void vospi_callback(omv_spi_t *spi, void *userdata, void *buf) { vospi.pid = 0; vospi.sid = 0; omv_spi_transfer_abort(&vospi.spi_bus); - vospi.resync_flag = true; + vospi.flags |= VOSPI_FLAGS_RESYNC; return; } memcpy(vospi.framebuffer + (vospi.pid * VOSPI_PID_SIZE_PIXELS) - + (vospi.sid * VOSPI_SEG_SIZE_PIXELS), + + (vospi.sid * VOSPI_SID_SIZE_PIXELS), base + VOSPI_HEADER_WORDS, VOSPI_PID_SIZE_PIXELS * sizeof(uint16_t)); vospi.pid += 1; - if (vospi.pid == VOSPI_PIDS_PER_SEG) { + if (vospi.pid == VOSPI_PIDS_PER_SID) { vospi.pid = 0; // For the FLIR Lepton 3 we have to receive all the pids in all the segments. if (vospi.lepton_3) { vospi.sid += 1; - if (vospi.sid == VOSPI_SEGS_PER_FRAME) { + if (vospi.sid == VOSPI_SIDS_PER_FRAME) { vospi.sid = 0; - vospi.waiting_for_data = false; + vospi.flags &= ~VOSPI_FLAGS_CAPTURE; } // For the FLIR Lepton 1/2 we just have to receive all the pids. } else { - vospi.waiting_for_data = false; + vospi.flags &= ~VOSPI_FLAGS_CAPTURE; } } } int vospi_init(uint32_t n_packets, void *buffer) { memset(&vospi, 0, sizeof(vospi_state_t)); - vospi.lepton_3 = n_packets > VOSPI_PIDS_PER_SEG; + vospi.lepton_3 = n_packets > VOSPI_PIDS_PER_SID; vospi.framebuffer = buffer; // resync on first snapshot. - vospi.resync_flag = true; + vospi.flags = VOSPI_FLAGS_RESYNC; omv_spi_config_t spi_config; omv_spi_default_config(&spi_config, ISC_SPI_ID); - spi_config.baudrate = VOSPI_CLOCK_SPEED; spi_config.bus_mode = OMV_SPI_BUS_RX; + spi_config.datasize = 16; + spi_config.baudrate = VOSPI_CLOCK_SPEED; spi_config.dma_flags = OMV_SPI_DMA_CIRCULAR | OMV_SPI_DMA_DOUBLE; if (omv_spi_init(&vospi.spi_bus, &spi_config) != 0) { @@ -167,31 +172,28 @@ int vospi_init(uint32_t n_packets, void *buffer) { } int vospi_snapshot(uint32_t timeout_ms) { - vospi.waiting_for_data = true; + // Restart counters to capture a new frame. + vospi.flags |= VOSPI_FLAGS_CAPTURE; + // Snapshot start tick mp_uint_t tick_start = mp_hal_ticks_ms(); - for (;;) { - if (vospi.resync_flag) { - vospi.resync_flag = false; + do { + if (vospi.flags & VOSPI_FLAGS_RESYNC) { + vospi.flags &= ~VOSPI_FLAGS_RESYNC; vospi_resync(); } - if (!vospi.waiting_for_data) { - break; - } - if ((mp_hal_ticks_ms() - tick_start) > timeout_ms) { omv_spi_transfer_abort(&vospi.spi_bus); - vospi.waiting_for_data = false; vospi.pid = 0; vospi.sid = 0; - vospi.resync_flag = true; + vospi.flags = VOSPI_FLAGS_RESYNC; return -1; } MICROPY_EVENT_POLL_HOOK - } + } while (vospi.flags & VOSPI_FLAGS_CAPTURE); return 0; } diff --git a/src/omv/modules/py_fir_lepton.c b/src/omv/modules/py_fir_lepton.c index 9a4f05876..c6c0379e4 100644 --- a/src/omv/modules/py_fir_lepton.c +++ b/src/omv/modules/py_fir_lepton.c @@ -47,10 +47,14 @@ static omv_spi_t spi_bus = {}; #define VOSPI_HEADER_WORDS (2) // 16-bits #define VOSPI_PID_SIZE_PIXELS (80) // w, 16-bits per pixel -#define VOSPI_PIDS_PER_SEG (60) // h -#define VOSPI_SEGS_PER_FRAME (4) +#define VOSPI_PIDS_PER_SID (60) // h +#define VOSPI_SIDS_PER_FRAME (4) #define VOSPI_PACKET_SIZE (VOSPI_HEADER_WORDS + VOSPI_PID_SIZE_PIXELS) // 16-bits -#define VOSPI_SEG_SIZE_PIXELS (VOSPI_PIDS_PER_SEG * VOSPI_PID_SIZE_PIXELS) // 16-bits +#define VOSPI_SID_SIZE_PIXELS (VOSPI_PIDS_PER_SID * VOSPI_PID_SIZE_PIXELS) // 16-bits + +#define VOSPI_BUFFER_SIZE (VOSPI_PACKET_SIZE * 2) // 16-bits +#define VOSPI_CLOCK_SPEED 20000000 // hz +#define VOSPI_SYNC_MS 200 // ms #define VOSPI_SPECIAL_PACKET (20) #define VOSPI_DONT_CARE_PACKET (0x0F00) @@ -58,14 +62,10 @@ static omv_spi_t spi_bus = {}; #define VOSPI_HEADER_PID(id) ((id) & 0x0FFF) #define VOSPI_HEADER_SID(id) (((id) >> 12) & 0x7) -#define VOSPI_BUFFER_SIZE (VOSPI_PACKET_SIZE * 2) // 16-bits -#define VOSPI_CLOCK_SPEED 20000000 // hz -#define VOSPI_SYNC_MS 200 // ms - static soft_timer_entry_t flir_lepton_spi_rx_timer = {}; static int fir_lepton_spi_rx_cb_tail = 0; static int fir_lepton_spi_rx_cb_expected_pid = 0; -static int fir_lepton_spi_rx_cb_expected_seg = 0; +static int fir_lepton_spi_rx_cb_expected_sid = 0; static uint16_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED_DMA(fir_lepton_buf[VOSPI_BUFFER_SIZE]), ".dma_buffer"); static void fir_lepton_spi_callback(omv_spi_t *spi, void *userdata, void *buf); @@ -80,7 +80,7 @@ STATIC mp_obj_t fir_lepton_spi_resync_callback(mp_obj_t unused) { omv_spi_transfer_t spi_xfer = { .rxbuf = fir_lepton_buf, .size = VOSPI_BUFFER_SIZE, - .flags = OMV_SPI_XFER_DMA | OMV_SPI_XFER_16_BIT, + .flags = OMV_SPI_XFER_DMA, .callback = fir_lepton_spi_callback, }; @@ -130,15 +130,15 @@ void fir_lepton_spi_callback(omv_spi_t *spi, void *userdata, void *buf) { } int pid = VOSPI_HEADER_PID(id); - int seg = VOSPI_HEADER_SID(id) - 1; + int sid = VOSPI_HEADER_SID(id) - 1; // Discard packets with a pid != 0 when waiting for the first packet. if ((fir_lepton_spi_rx_cb_expected_pid == 0) && (pid != 0)) { return; } - // Discard segments with a seg != 0 when waiting for the first segment. - if (fir_lepton_3 && (pid == VOSPI_SPECIAL_PACKET) && (fir_lepton_spi_rx_cb_expected_seg == 0) && (seg != 0)) { + // Discard sidments with a sid != 0 when waiting for the first segment. + if (fir_lepton_3 && (pid == VOSPI_SPECIAL_PACKET) && (fir_lepton_spi_rx_cb_expected_sid == 0) && (sid != 0)) { fir_lepton_spi_rx_cb_expected_pid = 0; return; } @@ -148,9 +148,9 @@ void fir_lepton_spi_callback(omv_spi_t *spi, void *userdata, void *buf) { #if defined(OMV_FIR_LEPTON_CHECK_CRC) || (!fir_lepton_spi_check_crc(base)) #endif - || (fir_lepton_3 && (pid == VOSPI_SPECIAL_PACKET) && (seg != fir_lepton_spi_rx_cb_expected_seg))) { + || (fir_lepton_3 && (pid == VOSPI_SPECIAL_PACKET) && (sid != fir_lepton_spi_rx_cb_expected_sid))) { fir_lepton_spi_rx_cb_expected_pid = 0; - fir_lepton_spi_rx_cb_expected_seg = 0; + fir_lepton_spi_rx_cb_expected_sid = 0; omv_spi_transfer_abort(&spi_bus); omv_gpio_write(OMV_FIR_LEPTON_SSEL_PIN, 1); fir_lepton_spi_resync(); @@ -159,20 +159,20 @@ void fir_lepton_spi_callback(omv_spi_t *spi, void *userdata, void *buf) { memcpy(framebuffers[fir_lepton_spi_rx_cb_tail] + (fir_lepton_spi_rx_cb_expected_pid * VOSPI_PID_SIZE_PIXELS) - + (fir_lepton_spi_rx_cb_expected_seg * VOSPI_SEG_SIZE_PIXELS), + + (fir_lepton_spi_rx_cb_expected_sid * VOSPI_SID_SIZE_PIXELS), base + VOSPI_HEADER_WORDS, VOSPI_PID_SIZE_PIXELS * sizeof(uint16_t)); fir_lepton_spi_rx_cb_expected_pid += 1; - if (fir_lepton_spi_rx_cb_expected_pid == VOSPI_PIDS_PER_SEG) { + if (fir_lepton_spi_rx_cb_expected_pid == VOSPI_PIDS_PER_SID) { fir_lepton_spi_rx_cb_expected_pid = 0; bool frame_ready = false; // For the FLIR Lepton 3 we have to receive all the pids in all the segments. if (fir_lepton_3) { - fir_lepton_spi_rx_cb_expected_seg += 1; - if (fir_lepton_spi_rx_cb_expected_seg == VOSPI_SEGS_PER_FRAME) { - fir_lepton_spi_rx_cb_expected_seg = 0; + fir_lepton_spi_rx_cb_expected_sid += 1; + if (fir_lepton_spi_rx_cb_expected_sid == VOSPI_SIDS_PER_FRAME) { + fir_lepton_spi_rx_cb_expected_sid = 0; frame_ready = true; } // For the FLIR Lepton 1/2 we just have to receive all the pids. @@ -212,7 +212,7 @@ static void fir_lepton_extint_callback(void *data) { void fir_lepton_deinit() { omv_spi_transfer_abort(&spi_bus); fir_lepton_spi_rx_cb_expected_pid = 0; - fir_lepton_spi_rx_cb_expected_seg = 0; + fir_lepton_spi_rx_cb_expected_sid = 0; fb_alloc_free_till_mark_past_mark_permanent(); #if defined(OMV_FIR_LEPTON_MCLK) @@ -244,6 +244,8 @@ int fir_lepton_init(omv_i2c_t *bus, int *w, int *h, int *refresh, int *resolutio #else spi_config.baudrate = VOSPI_CLOCK_SPEED; #endif + + spi_config.datasize = 16; spi_config.bus_mode = OMV_SPI_BUS_RX; spi_config.nss_enable = false; spi_config.dma_flags = OMV_SPI_DMA_CIRCULAR | OMV_SPI_DMA_DOUBLE; @@ -371,7 +373,7 @@ int fir_lepton_init(omv_i2c_t *bus, int *w, int *h, int *refresh, int *resolutio int flir_w = roi.endCol + 1; int flir_h = roi.endRow + 1; - fir_lepton_3 = flir_h > VOSPI_PIDS_PER_SEG; + fir_lepton_3 = flir_h > VOSPI_PIDS_PER_SID; fir_lepton_rad_en = rad == LEP_RAD_ENABLE; *w = flir_w; *h = flir_h; diff --git a/src/omv/modules/py_lcd.c b/src/omv/modules/py_lcd.c index ada7029d2..b6723159c 100644 --- a/src/omv/modules/py_lcd.c +++ b/src/omv/modules/py_lcd.c @@ -75,14 +75,8 @@ static int lcd_intensity = 0; #ifdef OMV_SPI_LCD_SPI_BUS static omv_spi_t spi_bus = {}; -static volatile enum { - SPI_TX_CB_IDLE, - SPI_TX_CB_MEMORY_WRITE_CMD, - SPI_TX_CB_MEMORY_WRITE, - SPI_TX_CB_DISPLAY_ON, - SPI_TX_CB_DISPLAY_OFF -} -spi_tx_cb_state = SPI_TX_CB_IDLE; +static bool spi_tx_thread_running = false; +static uint32_t spi_tx_baudrate = 0; static void spi_transmit(uint8_t *txdata, uint16_t size, bool end) { omv_spi_transfer_t spi_xfer = { @@ -105,7 +99,7 @@ static void spi_transmit_16(uint8_t *txdata, uint16_t size) { .txbuf = txdata, .size = (!lcd_byte_reverse) ? size : (size * 2), .timeout = OMV_SPI_MAX_TIMEOUT, - .flags = OMV_SPI_XFER_BLOCKING | ((!lcd_byte_reverse) ? OMV_SPI_XFER_16_BIT : 0) + .flags = OMV_SPI_XFER_BLOCKING, }; omv_spi_transfer_start(&spi_bus, &spi_xfer); @@ -114,10 +108,12 @@ static void spi_transmit_16(uint8_t *txdata, uint16_t size) { static void spi_config_deinit() { if (lcd_triple_buffer) { omv_spi_transfer_abort(&spi_bus); - spi_tx_cb_state = SPI_TX_CB_IDLE; + spi_tx_thread_running = false; fb_alloc_free_till_mark_past_mark_permanent(); } + spi_tx_baudrate = 0; + omv_spi_deinit(&spi_bus); omv_gpio_deinit(OMV_SPI_LCD_RS_PIN); @@ -128,10 +124,10 @@ static void spi_config_init(int w, int h, int refresh_rate, bool triple_buffer, omv_spi_config_t spi_config; omv_spi_default_config(&spi_config, OMV_SPI_LCD_SPI_BUS); - spi_config.baudrate = w * h * refresh_rate * 16; + spi_tx_baudrate = w * h * refresh_rate * 16; + spi_config.baudrate = spi_tx_baudrate; spi_config.bus_mode = OMV_SPI_BUS_TX; spi_config.nss_enable = false; - spi_config.dma_flags = triple_buffer ? OMV_SPI_DMA_NORMAL : 0; omv_spi_init(&spi_bus, &spi_config); omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); @@ -176,127 +172,103 @@ static void spi_config_init(int w, int h, int refresh_rate, bool triple_buffer, } } -static bool spi_tx_cb_state_on[FRAMEBUFFER_COUNT] = {}; - static const uint8_t display_off[] = {0x28}; static const uint8_t display_on[] = {0x29}; static const uint8_t memory_write[] = {0x2C}; +static void spi_lcd_switch_mode(int bits, bool dma) { + omv_spi_deinit(&spi_bus); + + omv_spi_config_t spi_config; + omv_spi_default_config(&spi_config, OMV_SPI_LCD_SPI_BUS); + + spi_config.baudrate = spi_tx_baudrate; + spi_config.datasize = bits; + spi_config.bus_mode = OMV_SPI_BUS_TX; + spi_config.nss_enable = false; + spi_config.dma_flags = dma ? OMV_SPI_DMA_NORMAL : 0; + omv_spi_init(&spi_bus, &spi_config); +} + static void spi_lcd_callback(omv_spi_t *spi, void *userdata, void *buf) { if (lcd_type == LCD_SHIELD) { static uint8_t *spi_tx_cb_state_memory_write_addr = NULL; static size_t spi_tx_cb_state_memory_write_count = 0; - static bool spi_tx_cb_state_memory_write_first = false; - switch (spi_tx_cb_state) { - case SPI_TX_CB_MEMORY_WRITE_CMD: { - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); - omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); - if (!spi_tx_cb_state_on[framebuffer_tail]) { - spi_tx_cb_state = SPI_TX_CB_DISPLAY_OFF; - framebuffer_head = framebuffer_tail; - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - omv_spi_transfer_t spi_xfer = { - .txbuf = (uint8_t *) display_off, - .size = sizeof(display_off), - .flags = OMV_SPI_XFER_NONBLOCK, - .callback = spi_lcd_callback, - }; - omv_spi_transfer_start(&spi_bus, &spi_xfer); - } else { - spi_tx_cb_state = SPI_TX_CB_MEMORY_WRITE; - spi_tx_cb_state_memory_write_addr = (uint8_t *) framebuffers[framebuffer_tail]; - spi_tx_cb_state_memory_write_count = lcd_width * lcd_height; - if (lcd_byte_reverse) { - spi_tx_cb_state_memory_write_count *= 2; - } - spi_tx_cb_state_memory_write_first = true; - framebuffer_head = framebuffer_tail; - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - // When starting the interrupt chain the first transfer is not executed - // in interrupt context. So, disable interrupts for the first transfer so - // that it completes first and unlocks the SPI bus before allowing the interrupt - // it causes to trigger starting the interrupt chain. - omv_spi_transfer_t spi_xfer = { - .txbuf = (uint8_t *) memory_write, - .size = sizeof(memory_write), - .flags = OMV_SPI_XFER_NONBLOCK, - .callback = spi_lcd_callback, - }; - uint32_t irq_state = disable_irq(); - omv_spi_transfer_start(&spi_bus, &spi_xfer); - enable_irq(irq_state); - } - break; - } - case SPI_TX_CB_MEMORY_WRITE: { - size_t spi_tx_cb_state_memory_write_limit = (!lcd_byte_reverse) - ? OMV_SPI_MAX_16BIT_XFER : OMV_SPI_MAX_8BIT_XFER; - uint8_t *addr = spi_tx_cb_state_memory_write_addr; - size_t count = IM_MIN(spi_tx_cb_state_memory_write_count, spi_tx_cb_state_memory_write_limit); - spi_tx_cb_state = (spi_tx_cb_state_memory_write_count > spi_tx_cb_state_memory_write_limit) - ? SPI_TX_CB_MEMORY_WRITE : SPI_TX_CB_DISPLAY_ON; - spi_tx_cb_state_memory_write_addr += (!lcd_byte_reverse) ? (count * 2) : count; - spi_tx_cb_state_memory_write_count -= count; - if (spi_tx_cb_state_memory_write_first) { - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); - omv_gpio_write(OMV_SPI_LCD_RS_PIN, 1); - spi_tx_cb_state_memory_write_first = false; - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - } - omv_spi_transfer_t spi_xfer = { - .txbuf = addr, - .size = count, - .flags = OMV_SPI_XFER_DMA | ((!lcd_byte_reverse) ? OMV_SPI_XFER_16_BIT : 0), - .callback = spi_lcd_callback, - }; - omv_spi_transfer_start(&spi_bus, &spi_xfer); - break; - } - case SPI_TX_CB_DISPLAY_ON: { - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); - omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); - spi_tx_cb_state = SPI_TX_CB_MEMORY_WRITE_CMD; - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - omv_spi_transfer_t spi_xfer = { - .txbuf = (uint8_t *) display_on, - .size = sizeof(display_on), - .flags = OMV_SPI_XFER_NONBLOCK, - .callback = spi_lcd_callback, - }; - omv_spi_transfer_start(&spi_bus, &spi_xfer); - break; - } - case SPI_TX_CB_DISPLAY_OFF: { - omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); - spi_tx_cb_state = SPI_TX_CB_IDLE; - break; - } - default: { - break; + // If userdata is not null then it means that we are being kicked off. + if (userdata != NULL) { + spi_tx_cb_state_memory_write_count = 0; + } + + if (!spi_tx_cb_state_memory_write_count) { + spi_tx_cb_state_memory_write_addr = (uint8_t *) framebuffers[framebuffer_tail]; + spi_tx_cb_state_memory_write_count = lcd_width * lcd_height; + + if (lcd_byte_reverse) { + spi_tx_cb_state_memory_write_count *= 2; } + + framebuffer_head = framebuffer_tail; + } + + size_t spi_tx_cb_state_memory_write_limit = (!lcd_byte_reverse) + ? OMV_SPI_MAX_16BIT_XFER : OMV_SPI_MAX_8BIT_XFER; + uint8_t *addr = spi_tx_cb_state_memory_write_addr; + size_t count = IM_MIN(spi_tx_cb_state_memory_write_count, spi_tx_cb_state_memory_write_limit); + spi_tx_cb_state_memory_write_addr += (!lcd_byte_reverse) ? (count * 2) : count; + spi_tx_cb_state_memory_write_count -= count; + // When starting the interrupt chain the first transfer is not executed + // in interrupt context. So, disable interrupts for the first transfer so + // that it completes first and unlocks the SPI bus before allowing the interrupt + // it causes to trigger starting the interrupt chain. + omv_spi_transfer_t spi_xfer = { + .txbuf = addr, + .size = count, + .flags = OMV_SPI_XFER_DMA, + .callback = spi_lcd_callback, + }; + if (userdata != NULL) { + uint32_t irq_state = disable_irq(); + omv_spi_transfer_start(&spi_bus, &spi_xfer); + enable_irq(irq_state); + } else { + omv_spi_transfer_start(&spi_bus, &spi_xfer); } } } -// If the callback chain is not running restart it. Display off may have been called so we need wait -// for that operation to complete before restarting the process. static void spi_lcd_kick() { - int spi_tx_cb_state_sampled = spi_tx_cb_state; // volatile + if (!spi_tx_thread_running) { + omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); + spi_transmit((uint8_t *) memory_write, sizeof(memory_write), true); + omv_gpio_write(OMV_SPI_LCD_RS_PIN, 1); - if ((spi_tx_cb_state_sampled == SPI_TX_CB_IDLE) - || (spi_tx_cb_state_sampled == SPI_TX_CB_DISPLAY_OFF)) { - uint32_t tick = mp_hal_ticks_ms(); + spi_lcd_switch_mode((!lcd_byte_reverse) ? 16 : 8, true); + omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); - while (spi_tx_cb_state != SPI_TX_CB_IDLE) { - // volatile - if ((mp_hal_ticks_ms() - tick) > 1000) { - return; // give up (should not happen) - } + // Limit the transfer size to single lines as you cannot send more + // than 64KB per SPI transaction generally. + for (int i = 0; i < lcd_height; i++) { + spi_transmit_16((uint8_t *) (framebuffers[framebuffer_tail] + (lcd_width * i)), lcd_width); } - spi_tx_cb_state = SPI_TX_CB_MEMORY_WRITE_CMD; - spi_lcd_callback(&spi_bus, NULL, NULL); + spi_lcd_switch_mode(8, false); + omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); + + omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); + spi_transmit((uint8_t *) display_on, sizeof(display_on), true); + omv_gpio_write(OMV_SPI_LCD_RS_PIN, 1); + + omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); + spi_transmit((uint8_t *) memory_write, sizeof(memory_write), true); + omv_gpio_write(OMV_SPI_LCD_RS_PIN, 1); + + spi_lcd_switch_mode((!lcd_byte_reverse) ? 16 : 8, true); + omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); + + // Kickoff interrupt driven image update. + spi_tx_thread_running = true; + spi_lcd_callback(&spi_bus, &spi_bus, NULL); } } @@ -323,6 +295,7 @@ static void spi_lcd_display(image_t *src_img, int dst_x_start, int dst_y_start, spi_transmit((uint8_t *) memory_write, sizeof(memory_write), true); omv_gpio_write(OMV_SPI_LCD_RS_PIN, 1); + spi_lcd_switch_mode((!lcd_byte_reverse) ? 16 : 8, true); omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 0); if (black) { @@ -351,6 +324,7 @@ static void spi_lcd_display(image_t *src_img, int dst_x_start, int dst_y_start, } } + spi_lcd_switch_mode(8, false); omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); @@ -401,9 +375,6 @@ static void spi_lcd_display(image_t *src_img, int dst_x_start, int dst_y_start, } } - // Tell the call back FSM that we want to turn the display on. - spi_tx_cb_state_on[new_framebuffer_tail] = true; - #ifdef __DCACHE_PRESENT // Flush data for DMA SCB_CleanDCache_by_Addr((uint32_t *) dst_img.data, image_size(&dst_img)); @@ -418,27 +389,16 @@ static void spi_lcd_display(image_t *src_img, int dst_x_start, int dst_y_start, } static void spi_lcd_clear() { - if (!lcd_triple_buffer) { - omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); - spi_transmit((uint8_t *) display_off, sizeof(display_off), true); - omv_gpio_write(OMV_SPI_LCD_RS_PIN, 1); - } else { - // For triple buffering we are never drawing where tail or head (which may instantly update to - // to be equal to tail) is. - int new_framebuffer_tail = (framebuffer_tail + 1) % FRAMEBUFFER_COUNT; - if (new_framebuffer_tail == framebuffer_head) { - new_framebuffer_tail = (new_framebuffer_tail + 1) % FRAMEBUFFER_COUNT; - } - - // Tell the call back FSM that we want to turn the display off. - spi_tx_cb_state_on[new_framebuffer_tail] = false; - - // Update tail which means a new image is ready. - framebuffer_tail = new_framebuffer_tail; - - // Kick off an update of the display. - spi_lcd_kick(); + if (spi_tx_thread_running) { + omv_spi_transfer_abort(&spi_bus); + spi_tx_thread_running = false; + spi_lcd_switch_mode(8, false); + omv_gpio_write(OMV_SPI_LCD_SSEL_PIN, 1); } + + omv_gpio_write(OMV_SPI_LCD_RS_PIN, 0); + spi_transmit((uint8_t *) display_off, sizeof(display_off), true); + omv_gpio_write(OMV_SPI_LCD_RS_PIN, 1); } #ifdef OMV_SPI_LCD_BL_DAC diff --git a/src/omv/ports/mimxrt/mimxrt_hal.c b/src/omv/ports/mimxrt/mimxrt_hal.c index ffef8f863..a94fc68c0 100644 --- a/src/omv/ports/mimxrt/mimxrt_hal.c +++ b/src/omv/ports/mimxrt/mimxrt_hal.c @@ -20,7 +20,6 @@ #include "fsl_usb_phy.h" #include "fsl_device_registers.h" #include CLOCK_CONFIG_H -#include "dma_manager.h" #include "irq.h" #include "omv_boardconfig.h" diff --git a/src/omv/ports/mimxrt/omv_spi.c b/src/omv/ports/mimxrt/omv_spi.c index 90496cc6b..aa3429372 100644 --- a/src/omv/ports/mimxrt/omv_spi.c +++ b/src/omv/ports/mimxrt/omv_spi.c @@ -103,9 +103,6 @@ static void spi_master_callback(LPSPI_Type *base, void *handle, status_t status, uint32_t flags = (OMV_SPI_XFER_DMA | OMV_SPI_XFER_COMPLETE); if ((spi->dma_flags & OMV_SPI_DMA_DOUBLE) && ((spi->xfer_flags & flags) == flags)) { int32_t offset = (spi->xfer_flags & OMV_SPI_XFER_HALF) ? -spi->xfer_descr.dataSize : spi->xfer_descr.dataSize; - if (spi->xfer_descr.txData) { - spi->xfer_descr.txData += offset; - } if (spi->xfer_descr.rxData) { spi->xfer_descr.rxData += offset; } @@ -131,24 +128,8 @@ static void spi_master_callback(LPSPI_Type *base, void *handle, status_t status, } } -// The LPSPI_MasterTransferNonBlocking function call does not clear the LPSPI_TCR_FRAMESZ_MASK bit -// even if kLPSPI_MasterByteSwap is not set in the xfer. So, we have to clear this bit at the same -// time as changing the framesize. Splitting this will result in inconsitent settings. Finally, -// the TCR register doesn't always update itself correctly so you have to try in a loop... -void omv_spi_set_frame_size(omv_spi_t *spi, uint16_t size) { - for (;;) { - uint32_t tcr = spi->inst->TCR; - uint16_t s = (uint16_t) ((tcr & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) + 1U; - if (s != size) { - spi->inst->TCR = (tcr & ~(LPSPI_TCR_BYSW_MASK | LPSPI_TCR_FRAMESZ_MASK)) | LPSPI_TCR_FRAMESZ(size - 1U); - } else { - break; - } - } -} - int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) { - // No TX trasnfers in circular or double buffer mode. + // No TX transfers in circular or double buffer mode. if ((spi->dma_flags & (OMV_SPI_DMA_CIRCULAR | OMV_SPI_DMA_DOUBLE)) && xfer->txbuf) { return -1; } @@ -158,34 +139,18 @@ int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) { spi->xfer_error = 0; spi->xfer_flags = xfer->flags; - uint32_t datasize = 8; - if (xfer->flags & OMV_SPI_XFER_16_BIT) { - datasize = 16; - } - - omv_spi_set_frame_size(spi, datasize); - spi->xfer_descr.txData = xfer->txbuf; spi->xfer_descr.rxData = xfer->rxbuf; - spi->xfer_descr.dataSize = xfer->size; + spi->xfer_descr.dataSize = xfer->size * (spi->config_backup.bitsPerFrame / 8); spi->xfer_descr.configFlags = kLPSPI_MasterPcs0 | kLPSPI_MasterPcsContinuous; - spi->xfer_flags &= ~(OMV_SPI_XFER_FAILED | OMV_SPI_XFER_COMPLETE); - - if (xfer->flags & OMV_SPI_XFER_16_BIT) { - spi->xfer_descr.dataSize *= 2; - } + spi->xfer_flags &= ~(OMV_SPI_XFER_FAILED | OMV_SPI_XFER_COMPLETE | OMV_SPI_XFER_HALF); if (spi->dma_flags & OMV_SPI_DMA_DOUBLE) { spi->xfer_descr.dataSize /= 2; } - // Check if we can optimize the transfer by doing things in 32-bit chunks. - if ((!(spi->xfer_descr.dataSize % 4)) && (!(xfer->flags & OMV_SPI_XFER_16_BIT))) { - omv_spi_set_frame_size(spi, 32); - spi->xfer_descr.configFlags |= kLPSPI_MasterByteSwap; - } - if (spi->xfer_flags & OMV_SPI_XFER_DMA) { + // DMA transfer (circular or one-shot) if (LPSPI_MasterTransferEDMA(spi->inst, &spi->descr_master_edma, &spi->xfer_descr) != kStatus_Success) { return -1; } @@ -214,6 +179,7 @@ int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) { while (!(spi->xfer_flags & (OMV_SPI_XFER_COMPLETE | OMV_SPI_XFER_FAILED))) { if ((spi->xfer_flags & OMV_SPI_XFER_FAILED) || ((mp_hal_ticks_ms() - start) > xfer->timeout)) { + // The SPI bus was aborted by spi_master_callback. return -1; } MICROPY_EVENT_POLL_HOOK @@ -259,7 +225,7 @@ int omv_spi_init(omv_spi_t *spi, omv_spi_config_t *config) { spi_config.whichPcs = kLPSPI_Pcs0; spi_config.baudRate = config->baudrate; - spi_config.bitsPerFrame = 8; + spi_config.bitsPerFrame = config->datasize; spi_config.direction = config->bit_order; spi_config.pcsActiveHighOrLow = config->nss_pol; spi_config.cpol = config->clk_pol; @@ -328,6 +294,7 @@ int omv_spi_set_baudrate(omv_spi_t *spi, uint32_t baudrate) { int omv_spi_default_config(omv_spi_config_t *config, uint32_t bus_id) { config->id = bus_id; config->baudrate = 10000000; + config->datasize = 8; config->spi_mode = OMV_SPI_MODE_MASTER; config->bus_mode = OMV_SPI_BUS_TX_RX; config->bit_order = OMV_SPI_MSB_FIRST; diff --git a/src/omv/ports/stm32/omv_spi.c b/src/omv/ports/stm32/omv_spi.c index 66997abec..4643b8d98 100644 --- a/src/omv/ports/stm32/omv_spi.c +++ b/src/omv/ports/stm32/omv_spi.c @@ -170,7 +170,7 @@ static void omv_spi_callback(SPI_HandleTypeDef *hspi) { if (spi->dma_flags & OMV_SPI_DMA_DOUBLE) { if (spi->xfer_flags & OMV_SPI_XFER_HALF) { uint32_t size = spi->descr->RxXferSize ? spi->descr->RxXferSize : spi->descr->TxXferSize; - buf += (size * ((spi->xfer_flags & OMV_SPI_XFER_16_BIT) ? 2 : 1)) / 2; + buf += (size * ((spi->descr->Init.DataSize == SPI_DATASIZE_8BIT) ? 1 : 2)) / 2; } spi->xfer_flags ^= OMV_SPI_XFER_HALF; } @@ -178,24 +178,8 @@ static void omv_spi_callback(SPI_HandleTypeDef *hspi) { } } -static void omv_spi_dma_burst_mode(DMA_HandleTypeDef *hdma, bool on, bool sixteenbit) { - // Handle may not be initialized. - if (hdma->State == HAL_DMA_STATE_READY) { - hdma->Init.MemBurst = on ? DMA_MBURST_INC4 : DMA_MBURST_SINGLE; - hdma->Init.FIFOThreshold = on ? DMA_FIFO_THRESHOLD_FULL : DMA_FIFO_THRESHOLD_1QUARTERFULL; - uint32_t registerValue = ((DMA_Stream_TypeDef *) hdma->Instance)->CR; - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) - hdma->Init.PeriphDataAlignment = sixteenbit ? DMA_PDATAALIGN_HALFWORD : DMA_PDATAALIGN_BYTE; - registerValue = (registerValue & ~DMA_SxCR_PSIZE) | hdma->Init.PeriphDataAlignment; - #endif - ((DMA_Stream_TypeDef *) hdma->Instance)->CR = (registerValue & ~DMA_SxCR_MBURST) | hdma->Init.MemBurst; - registerValue = ((DMA_Stream_TypeDef *) hdma->Instance)->FCR; - ((DMA_Stream_TypeDef *) hdma->Instance)->FCR = (registerValue & ~DMA_SxFCR_FTH) | hdma->Init.FIFOThreshold; - } -} - int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) { - // No TX trasnfers in circular or double buffer mode. + // No TX transfers in circular or double buffer mode. if ((spi->dma_flags & (OMV_SPI_DMA_CIRCULAR | OMV_SPI_DMA_DOUBLE)) && xfer->txbuf) { return -1; } @@ -205,35 +189,6 @@ int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) { spi->xfer_error = 0; spi->xfer_flags = xfer->flags; - bool sixteenbit = xfer->flags & OMV_SPI_XFER_16_BIT; - size_t xfer_byte_size = xfer->size * (sixteenbit ? 2 : 1); - #if defined(MCU_SERIES_H7) - // Default to moving one element at a time through the fifo for 8-bit/16-bit transfers. - uint8_t fthlv = SPI_FIFO_THRESHOLD_01DATA; - // Do word sized transfers one at a time. - if (!(xfer_byte_size % 4)) { - fthlv = sixteenbit ? SPI_FIFO_THRESHOLD_02DATA : SPI_FIFO_THRESHOLD_04DATA; - } - #endif - - spi->descr->Init.DataSize = sixteenbit ? SPI_DATASIZE_16BIT : SPI_DATASIZE_8BIT; - #if defined(MCU_SERIES_H7) - spi->descr->Init.FifoThreshold = fthlv; - spi->descr->Instance->CFG1 = (spi->descr->Instance->CFG1 & ~SPI_CFG1_DSIZE_Msk) | spi->descr->Init.DataSize; - spi->descr->Instance->CFG1 = (spi->descr->Instance->CFG1 & ~SPI_CFG1_FTHLV_Msk) | fthlv; - #elif defined(MCU_SERIES_F7) - spi->descr->Instance->CR2 = (spi->descr->Instance->CR2 & ~SPI_CR2_DS_Msk) | spi->descr->Init.DataSize; - #elif defined(MCU_SERIES_F4) - spi->descr->Instance->CR1 = (spi->descr->Instance->CR1 & ~SPI_CR1_DFF_Msk) | spi->descr->Init.DataSize; - #endif - - // If the DMA transfer is not a multiple of 16 bytes then we cannot use any burst modes. - if (xfer->flags & OMV_SPI_XFER_DMA) { - bool on = !(xfer_byte_size % 16); - omv_spi_dma_burst_mode(&spi->dma_descr_tx, on, sixteenbit); - omv_spi_dma_burst_mode(&spi->dma_descr_rx, on, sixteenbit); - } - spi->xfer_flags &= ~(OMV_SPI_XFER_FAILED | OMV_SPI_XFER_COMPLETE | OMV_SPI_XFER_HALF); if (spi->xfer_flags & OMV_SPI_XFER_BLOCKING) { @@ -307,17 +262,21 @@ static int omv_spi_dma_init(omv_spi_t *spi, uint32_t direction, omv_spi_config_t // Configure the SPI DMA steam. dma_descr->Init.Mode = (config->dma_flags & OMV_SPI_DMA_CIRCULAR) ? DMA_CIRCULAR : DMA_NORMAL; - dma_descr->Init.Priority = DMA_PRIORITY_LOW; + dma_descr->Init.Priority = DMA_PRIORITY_HIGH; dma_descr->Init.Direction = direction; - dma_descr->Init.FIFOMode = DMA_FIFOMODE_ENABLE; - dma_descr->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; - dma_descr->Init.MemBurst = DMA_MBURST_INC4; - dma_descr->Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + // When the DMA is configured in direct mode (the FIFO is disabled), the source and + // destination transfer widths are equal, and both defined by PSIZE (MSIZE is ignored). + // Additionally, burst transfers are not possible (MBURST and PBURST are both ignored). + dma_descr->Init.FIFOMode = DMA_FIFOMODE_DISABLE; + dma_descr->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL; + // Note MBURST and PBURST are ignored. + dma_descr->Init.MemBurst = DMA_MBURST_SINGLE; dma_descr->Init.PeriphBurst = DMA_PBURST_SINGLE; + dma_descr->Init.MemDataAlignment = DMA_MDATAALIGN_WORD; #if defined(MCU_SERIES_H7) dma_descr->Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; #else - dma_descr->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + dma_descr->Init.PeriphDataAlignment = (config->datasize == 8) ? DMA_PDATAALIGN_BYTE : DMA_PDATAALIGN_HALFWORD; #endif dma_descr->Init.MemInc = DMA_MINC_ENABLE; dma_descr->Init.PeriphInc = DMA_PINC_DISABLE; @@ -355,7 +314,7 @@ static int omv_spi_bus_init(omv_spi_t *spi, omv_spi_config_t *config) { spi_descr->Init.TIMode = SPI_TIMODE_DISABLE; spi_descr->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; spi_descr->Init.NSS = (config->nss_enable == false) ? SPI_NSS_SOFT : SPI_NSS_HARD_OUTPUT; - spi_descr->Init.DataSize = SPI_DATASIZE_8BIT; + spi_descr->Init.DataSize = (config->datasize == 8) ? SPI_DATASIZE_8BIT : SPI_DATASIZE_16BIT; spi_descr->Init.FirstBit = config->bit_order; spi_descr->Init.CLKPhase = config->clk_pha; spi_descr->Init.CLKPolarity = config->clk_pol; @@ -364,12 +323,12 @@ static int omv_spi_bus_init(omv_spi_t *spi, omv_spi_config_t *config) { spi_descr->Init.NSSPMode = SPI_NSS_PULSE_DISABLE; #if defined(MCU_SERIES_H7) spi_descr->Init.NSSPolarity = (config->nss_pol == 0) ? SPI_NSS_POLARITY_LOW : SPI_NSS_POLARITY_HIGH; - spi_descr->Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA; + spi_descr->Init.FifoThreshold = SPI_FIFO_THRESHOLD_04DATA; spi_descr->Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE; spi_descr->Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE; spi_descr->Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE; spi_descr->Init.MasterKeepIOState = (config->data_retained == true) ? - SPI_MASTER_KEEP_IO_STATE_ENABLE : SPI_MASTER_KEEP_IO_STATE_ENABLE; + SPI_MASTER_KEEP_IO_STATE_ENABLE : SPI_MASTER_KEEP_IO_STATE_DISABLE; spi_descr->Init.IOSwap = SPI_IO_SWAP_DISABLE; #endif #endif @@ -486,6 +445,7 @@ int omv_spi_set_baudrate(omv_spi_t *spi, uint32_t baudrate) { int omv_spi_default_config(omv_spi_config_t *config, uint32_t bus_id) { config->id = bus_id; config->baudrate = 10000000; + config->datasize = 8; config->spi_mode = OMV_SPI_MODE_MASTER; config->bus_mode = OMV_SPI_BUS_TX_RX; config->bit_order = OMV_SPI_MSB_FIRST;