drivers: Make all SPI based Python modules portable. (#1918)

drivers: Make all SPI based Python modules portable.
This commit is contained in:
Ibrahim Abdelkader 2023-09-19 19:52:01 +03:00 committed by GitHub
commit 0d9ae4e178
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 1126 additions and 857 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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 (1)
// 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)

View File

@ -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)

View File

@ -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__

View File

@ -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__

View File

@ -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__

View File

@ -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 (1)
// 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)

View File

@ -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 (1)
// 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)

View File

@ -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 (1)
#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__

View File

@ -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

View File

@ -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)

View File

@ -16,13 +16,20 @@
// 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_HALF = (1 << 6), // Internal for Double Buffer mode.
} omv_spi_xfer_flags_t;
typedef struct _omv_spi_config {
@ -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 *buf);
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;
@ -75,6 +82,8 @@ 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.
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__

View File

@ -19,109 +19,141 @@
#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)))
#define VOSPI_HEADER_WORDS (2) // 16-bits
#define VOSPI_PID_SIZE_PIXELS (80) // w, 16-bits per pixel
#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_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)
#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)
typedef enum {
VOSPI_FLAGS_RESET = (1 << 0),
VOSPI_FLAGS_RESYNC = (1 << 1),
VOSPI_FLAGS_CAPTURE = (1 << 0),
VOSPI_FLAGS_RESYNC = (1 << 1),
} vospi_flags_t;
typedef struct _vospi_state {
volatile uint32_t pid;
volatile uint32_t sid;
uint8_t *buffer;
uint32_t n_packets;
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 uint8_t OMV_ATTR_SECTION(
OMV_ATTR_ALIGNED(vospi_packet[VOSPI_PACKET_SIZE], VOSPI_PACKET_ALIGNMENT), ".dma_buffer"
);
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
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);
static void vospi_do_resync() {
static void vospi_resync() {
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,
.callback = vospi_callback,
};
omv_spi_transfer_abort(&vospi.spi_bus);
mp_hal_delay_ms(200);
vospi.flags = VOSPI_FLAGS_RESET;
mp_hal_delay_ms(VOSPI_SYNC_MS);
omv_spi_transfer_start(&vospi.spi_bus, &spi_xfer);
debug_printf("vospi resync...\n");
}
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 *buf) {
if (!(vospi.flags & VOSPI_FLAGS_CAPTURE)) {
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 *) buf;
int id = base[0];
// Ignore don't care packets.
if (VOSPI_HEADER_DONT_CARE(id)) {
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 = 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.pid == 0) && (pid != 0)) {
return;
}
// 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;
}
// Are we in sync with the flir lepton?
if ((pid != vospi.pid)
#if defined(OMV_ENABLE_VOSPI_CRC)
|| (!vospi_check_crc(base))
#endif
|| (vospi.lepton_3 && (pid == VOSPI_SPECIAL_PACKET) && (sid != vospi.sid))) {
vospi.pid = 0;
vospi.sid = 0;
omv_spi_transfer_abort(&vospi.spi_bus);
vospi.flags |= VOSPI_FLAGS_RESYNC;
return;
}
memcpy(vospi.framebuffer
+ (vospi.pid * VOSPI_PID_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_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_SIDS_PER_FRAME) {
vospi.sid = 0;
vospi.flags &= ~VOSPI_FLAGS_CAPTURE;
}
// 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++;
}
vospi.flags &= ~VOSPI_FLAGS_CAPTURE;
}
}
}
int vospi_init(uint32_t n_packets, void *buffer) {
memset(&vospi, 0, sizeof(vospi_state_t));
vospi.buffer = buffer;
vospi.n_packets = n_packets;
vospi.lepton_3 = n_packets > VOSPI_PIDS_PER_SID;
vospi.framebuffer = buffer;
// resync on first snapshot.
vospi.flags = VOSPI_FLAGS_RESYNC;
@ -129,8 +161,9 @@ int vospi_init(uint32_t n_packets, void *buffer) {
omv_spi_default_config(&spi_config, ISC_SPI_ID);
spi_config.bus_mode = OMV_SPI_BUS_RX;
spi_config.baudrate = ISC_SPI_BAUDRATE;
spi_config.dma_enable = true;
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) {
return -1;
@ -140,24 +173,29 @@ int vospi_init(uint32_t n_packets, void *buffer) {
int vospi_snapshot(uint32_t timeout_ms) {
// Restart counters to capture a new frame.
vospi.flags |= VOSPI_FLAGS_RESET;
vospi.flags |= VOSPI_FLAGS_CAPTURE;
// Snapshot start tick
mp_uint_t tick_start = mp_hal_ticks_ms();
do {
if (vospi.flags & VOSPI_FLAGS_RESYNC) {
vospi_do_resync();
vospi.flags &= ~VOSPI_FLAGS_RESYNC;
vospi_resync();
}
if ((mp_hal_ticks_ms() - tick_start) >= timeout_ms) {
// Timeout error.
if ((mp_hal_ticks_ms() - tick_start) > timeout_ms) {
omv_spi_transfer_abort(&vospi.spi_bus);
vospi.pid = 0;
vospi.sid = 0;
vospi.flags = VOSPI_FLAGS_RESYNC;
return -1;
}
MICROPY_EVENT_POLL_HOOK
} while (vospi.pid < vospi.n_packets);
} while (vospi.flags & VOSPI_FLAGS_CAPTURE);
return 0;
}
#endif

View File

@ -8,7 +8,6 @@
*
* VOSPI driver.
*/
#ifndef __VOSPI_H__
#define __VOSPI_H__
int vospi_init(uint32_t n_packets, void *buffer);

View File

@ -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,24 +43,31 @@ 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
#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_SID (60) // h
#define VOSPI_SIDS_PER_FRAME (4)
#define VOSPI_PACKET_SIZE (VOSPI_HEADER_WORDS + 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_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)
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 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);
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 +77,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,
.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,24 +119,26 @@ 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.
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 ((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 == 20) && (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;
}
@ -133,10 +148,10 @@ void fir_lepton_spi_callback(const uint16_t *base) {
#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) && (sid != fir_lepton_spi_rx_cb_expected_sid))) {
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);
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();
return;
@ -144,20 +159,20 @@ void fir_lepton_spi_callback(const uint16_t *base) {
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.
@ -184,14 +199,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,9 +210,9 @@ 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;
fir_lepton_spi_rx_cb_expected_sid = 0;
fb_alloc_free_till_mark_past_mark_permanent();
#if defined(OMV_FIR_LEPTON_MCLK)
@ -217,48 +224,40 @@ 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);
// 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);
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;
omv_spi_init(&spi_bus, &spi_config);
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);
@ -374,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;
@ -400,38 +399,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 +443,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
}
}

View File

@ -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,58 +72,71 @@ 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,
SPI_TX_CB_MEMORY_WRITE_CMD,
SPI_TX_CB_MEMORY_WRITE,
SPI_TX_CB_DISPLAY_ON,
SPI_TX_CB_DISPLAY_OFF
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 = {
.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,
};
omv_spi_transfer_start(&spi_bus, &spi_xfer);
}
spi_tx_cb_state = SPI_TX_CB_IDLE;
static void spi_config_deinit() {
if (lcd_triple_buffer) {
HAL_SPI_Abort(OMV_SPI_LCD_CONTROLLER->spi);
spi_tx_cb_state = SPI_TX_CB_IDLE;
omv_spi_transfer_abort(&spi_bus);
spi_tx_thread_running = false;
fb_alloc_free_till_mark_past_mark_permanent();
}
spi_deinit(OMV_SPI_LCD_CONTROLLER);
spi_tx_baudrate = 0;
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_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;
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 +144,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,161 +168,112 @@ 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();
}
}
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_callback(SPI_HandleTypeDef *hspi) {
if (lcd_type == LCD_SHIELD) {
static uint16_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;
static void spi_lcd_switch_mode(int bits, bool dma) {
omv_spi_deinit(&spi_bus);
switch (spi_tx_cb_state) {
case SPI_TX_CB_MEMORY_WRITE_CMD: {
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));
} 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_count = lcd_width * lcd_height;
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
// that it completes first and unlocks the SPI bus before allowing the interrupt
// it causes to trigger starting the interrupt chain.
uint32_t irq_state = disable_irq();
HAL_SPI_Transmit_IT(hspi, (uint8_t *) memory_write, sizeof(memory_write));
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;
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);
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));
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;
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;
// 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(OMV_SPI_LCD_CONTROLLER->spi);
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);
}
}
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 +289,24 @@ 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);
spi_lcd_switch_mode((!lcd_byte_reverse) ? 16 : 8, true);
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 +318,17 @@ 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
spi_lcd_switch_mode(8, false);
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();
@ -440,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));
@ -457,29 +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);
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);
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, 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();
}
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
@ -529,7 +448,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 +1222,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 +1280,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 +1294,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 +1442,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 +1661,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 +1690,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 +1841,5 @@ void py_lcd_init0() {
}
MP_REGISTER_MODULE(MP_QSTR_lcd, lcd_module);
#endif // MICROPY_PY_LCD

View File

@ -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"

View File

@ -1,9 +1,9 @@
/*
* This file is part of the OpenMV project.
*
* Copyright (c) 2013-2020 Ibrahim Abdelkader <iabdalkader@openmv.io>
* Copyright (c) 2013-2020 Kwabena W. Agyeman <kwagyeman@openmv.io>
* Copyright (c) 2013-2020 Kaizhi Wong <kidswong999@gmail.com>
* Copyright (c) 2013-2023 Ibrahim Abdelkader <iabdalkader@openmv.io>
* Copyright (c) 2013-2023 Kwabena W. Agyeman <kwagyeman@openmv.io>
* Copyright (c) 2013-2023 Kaizhi Wong <kidswong999@gmail.com>
*
* 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

View File

@ -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

View File

@ -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

View File

@ -198,6 +198,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 +232,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 +242,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();

View File

@ -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__

View File

@ -106,14 +106,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; \
}; \

View File

@ -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

View File

@ -9,7 +9,6 @@
* OMV SPI bus port for mimxrt.
*/
#include "omv_boardconfig.h"
#include <stdint.h>
#include "py/mphal.h"
#include "fsl_gpio.h"
@ -40,36 +39,48 @@ 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 } },
{ 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, 0 }, { NULL, NULL, 0, 0 } },
#endif
#if defined(LPSPI2_ID)
{ LPSPI2, LPSPI2_SSEL_PIN,
{ DMA0, DMAMUX, LPSPI2_DMA_TX_CHANNEL, kDmaRequestMuxLPSPI2Tx },
{ DMA0, DMAMUX, LPSPI2_DMA_RX_CHANNEL, 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, 0 }, { NULL, NULL, 0, 0 } },
#endif
#if defined(LPSPI3_ID)
{ LPSPI3, LPSPI3_SSEL_PIN,
{ DMA0, DMAMUX, LPSPI3_DMA_TX_CHANNEL, kDmaRequestMuxLPSPI3Tx },
{ DMA0, DMAMUX, LPSPI3_DMA_RX_CHANNEL, 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, 0 }, { NULL, NULL, 0, 0 } },
#endif
#if defined(LPSPI4_ID)
{ LPSPI4, LPSPI4_SSEL_PIN,
{ DMA0, DMAMUX, LPSPI4_DMA_TX_CHANNEL, kDmaRequestMuxLPSPI4Tx },
{ DMA0, DMAMUX, LPSPI4_DMA_RX_CHANNEL, 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, 0 }, { NULL, NULL, 0, 0 } },
#endif
};
// 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.rxData = NULL;
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,43 +89,78 @@ 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);
} else {
LPSPI_MasterTransferAbort(spi->inst, &spi->descr_master);
omv_spi_transfer_abort(spi);
}
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)) {
int32_t offset = (spi->xfer_flags & OMV_SPI_XFER_HALF) ? -spi->xfer_descr.dataSize : spi->xfer_descr.dataSize;
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
// 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);
}
if (spi->callback) {
spi->callback(spi, spi->userdata);
spi->callback(spi, spi->userdata, buf);
}
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.
// 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.
if (spi->dma_flags & OMV_SPI_DMA_CIRCULAR) {
spi->xfer_flags &= ~(OMV_SPI_XFER_COMPLETE);
LPSPI_MasterTransferEDMA(spi->inst, &spi->descr_master_edma, &spi->xfer_descr);
}
}
int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) {
// 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;
}
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.
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_flags &= ~(OMV_SPI_XFER_FAILED | OMV_SPI_XFER_COMPLETE);
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 | OMV_SPI_XFER_HALF);
if (spi->dma_flags & OMV_SPI_DMA_DOUBLE) {
spi->xfer_descr.dataSize /= 2;
}
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;
}
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 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.
@ -130,10 +176,10 @@ int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) {
// Blocking transfetr, wait for transfer complete or timeout.
mp_uint_t start = mp_hal_ticks_ms();
while (!(spi->xfer_flags & OMV_SPI_XFER_COMPLETE)) {
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)) {
LPSPI_MasterTransferAbort(spi->inst, &spi->descr_master);
// The SPI bus was aborted by spi_master_callback.
return -1;
}
MICROPY_EVENT_POLL_HOOK
@ -145,7 +191,12 @@ 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);
}
// 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;
}
@ -157,19 +208,17 @@ static int omv_spi_dma_init(edma_handle_t *dma_handle, const dma_descr_t *dma_de
}
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);
@ -181,10 +230,25 @@ int omv_spi_init(omv_spi_t *spi, omv_spi_config_t *config) {
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,18 +263,31 @@ 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);
DMAMUX_DisableChannel(spi_descr->dma_descr_rx.dma_mux, 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;
}
@ -222,10 +299,10 @@ int omv_spi_default_config(omv_spi_config_t *config, uint32_t bus_id) {
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;
}

View File

@ -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; \

View File

@ -152,6 +152,7 @@ static void omv_spi_callback(SPI_HandleTypeDef *hspi) {
spi = omv_spi_descr_all[5];
#endif
}
if (spi == NULL) {
return;
}
@ -160,19 +161,36 @@ static void omv_spi_callback(SPI_HandleTypeDef *hspi) {
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;
}
if (spi->callback) {
spi->callback(spi, spi->userdata);
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->descr->Init.DataSize == SPI_DATASIZE_8BIT) ? 1 : 2)) / 2;
}
spi->xfer_flags ^= OMV_SPI_XFER_HALF;
}
spi->callback(spi, spi->userdata, buf);
}
}
int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) {
// 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;
}
spi->callback = xfer->callback;
spi->userdata = xfer->userdata;
spi->xfer_error = 0;
spi->xfer_flags = xfer->flags;
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 +206,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 +243,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 +261,23 @@ 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.Mode = (config->dma_flags & OMV_SPI_DMA_CIRCULAR) ? DMA_CIRCULAR : DMA_NORMAL;
dma_descr->Init.Priority = DMA_PRIORITY_HIGH;
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.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
dma_descr->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
// Note MBURST and PBURST are ignored.
dma_descr->Init.MemBurst = DMA_MBURST_INC4;
dma_descr->Init.PeriphBurst = DMA_PBURST_INC4;
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 = (config->datasize == 8) ? DMA_PDATAALIGN_BYTE : DMA_PDATAALIGN_HALFWORD;
#endif
dma_descr->Init.MemInc = DMA_MINC_ENABLE;
dma_descr->Init.PeriphInc = DMA_PINC_DISABLE;
@ -261,7 +301,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,6 +312,7 @@ 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.FirstBit = config->bit_order;
@ -283,8 +324,12 @@ static int omv_spi_bus_init(omv_spi_t *spi, omv_spi_config_t *config) {
#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.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
@ -344,29 +389,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_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;
spi->dma_enabled = config->dma_enable;
spi->dma_flags = config->dma_flags;
omv_spi_descr_all[config->id - 1] = spi;
return 0;
}
@ -376,14 +422,26 @@ 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;
@ -395,7 +453,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;
}

View File

@ -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 = .;

View File

@ -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)

View File

@ -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...

View File

@ -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