mirror of
https://github.com/openmv/openmv.git
synced 2025-09-26 23:09:13 +08:00
Merge pull request #2603 from openmv/n6_port
Some checks are pending
🔥 Firmware Build / build-firmware (ARDUINO_GIGA) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_33_BLE_SENSE) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_RP2040_CONNECT) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NICLA_VISION) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_PORTENTA_H7) (push) Waiting to run
🔥 Firmware Build / build-firmware (DOCKER) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV2) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV3) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4P) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMVPT) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_AE3) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_N6) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_RT1060) (push) Waiting to run
🔥 Firmware Build / code-size-report (push) Blocked by required conditions
🔥 Firmware Build / stable-release (push) Blocked by required conditions
🔥 Firmware Build / development-release (push) Blocked by required conditions
Some checks are pending
🔥 Firmware Build / build-firmware (ARDUINO_GIGA) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_33_BLE_SENSE) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_RP2040_CONNECT) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NICLA_VISION) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_PORTENTA_H7) (push) Waiting to run
🔥 Firmware Build / build-firmware (DOCKER) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV2) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV3) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4P) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMVPT) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_AE3) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_N6) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_RT1060) (push) Waiting to run
🔥 Firmware Build / code-size-report (push) Blocked by required conditions
🔥 Firmware Build / stable-release (push) Blocked by required conditions
🔥 Firmware Build / development-release (push) Blocked by required conditions
ports/stm32: Add N6 support.
This commit is contained in:
commit
5534b34880
1
.github/workflows/firmware.yml
vendored
1
.github/workflows/firmware.yml
vendored
@ -42,6 +42,7 @@ jobs:
|
|||||||
- OPENMVPT
|
- OPENMVPT
|
||||||
- OPENMV_RT1060
|
- OPENMV_RT1060
|
||||||
- OPENMV_AE3
|
- OPENMV_AE3
|
||||||
|
- OPENMV_N6
|
||||||
- ARDUINO_PORTENTA_H7
|
- ARDUINO_PORTENTA_H7
|
||||||
- ARDUINO_GIGA
|
- ARDUINO_GIGA
|
||||||
- ARDUINO_NICLA_VISION
|
- ARDUINO_NICLA_VISION
|
||||||
|
5
Makefile
5
Makefile
@ -198,6 +198,11 @@ MPY_CFLAGS += -DMICROPY_PY_ML_TFLM=1
|
|||||||
MPY_MKARGS += MICROPY_PY_ML_TFLM=1
|
MPY_MKARGS += MICROPY_PY_ML_TFLM=1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(MICROPY_PY_ML_STAI), 1)
|
||||||
|
MPY_CFLAGS += -DMICROPY_PY_ML_STAI=1
|
||||||
|
MICROPY_ARGS += MICROPY_PY_ML_STAI=1
|
||||||
|
endif
|
||||||
|
|
||||||
MPY_PENDSV_ENTRIES := $(shell echo $(MPY_PENDSV_ENTRIES) | tr -d '[:space:]')
|
MPY_PENDSV_ENTRIES := $(shell echo $(MPY_PENDSV_ENTRIES) | tr -d '[:space:]')
|
||||||
MPY_CFLAGS += -DMICROPY_BOARD_PENDSV_ENTRIES="$(MPY_PENDSV_ENTRIES)"
|
MPY_CFLAGS += -DMICROPY_BOARD_PENDSV_ENTRIES="$(MPY_PENDSV_ENTRIES)"
|
||||||
MPY_CFLAGS += -DMP_CONFIGFILE=\<$(OMV_PORT_DIR)/omv_mpconfigport.h\>
|
MPY_CFLAGS += -DMP_CONFIGFILE=\<$(OMV_PORT_DIR)/omv_mpconfigport.h\>
|
||||||
|
149
boards/OPENMV_N6/imlib_config.h
Normal file
149
boards/OPENMV_N6/imlib_config.h
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
* Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
*
|
||||||
|
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
*
|
||||||
|
* Image library configuration.
|
||||||
|
*/
|
||||||
|
#ifndef __IMLIB_CONFIG_H__
|
||||||
|
#define __IMLIB_CONFIG_H__
|
||||||
|
|
||||||
|
// Enable Image I/O
|
||||||
|
#define IMLIB_ENABLE_IMAGE_IO
|
||||||
|
|
||||||
|
// Enable Image File I/O
|
||||||
|
#define IMLIB_ENABLE_IMAGE_FILE_IO
|
||||||
|
|
||||||
|
// Enable LAB LUT
|
||||||
|
#define IMLIB_ENABLE_LAB_LUT
|
||||||
|
|
||||||
|
// Enable YUV LUT
|
||||||
|
//#define IMLIB_ENABLE_YUV_LUT
|
||||||
|
|
||||||
|
// Enable ISP ops
|
||||||
|
#define IMLIB_ENABLE_ISP_OPS
|
||||||
|
|
||||||
|
// Enable binary ops
|
||||||
|
#define IMLIB_ENABLE_BINARY_OPS
|
||||||
|
|
||||||
|
// Enable math ops
|
||||||
|
#define IMLIB_ENABLE_MATH_OPS
|
||||||
|
|
||||||
|
// Enable flood_fill()
|
||||||
|
#define IMLIB_ENABLE_FLOOD_FILL
|
||||||
|
|
||||||
|
// Enable mean()
|
||||||
|
#define IMLIB_ENABLE_MEAN
|
||||||
|
|
||||||
|
// Enable median()
|
||||||
|
#define IMLIB_ENABLE_MEDIAN
|
||||||
|
|
||||||
|
// Enable mode()
|
||||||
|
#define IMLIB_ENABLE_MODE
|
||||||
|
|
||||||
|
// Enable midpoint()
|
||||||
|
#define IMLIB_ENABLE_MIDPOINT
|
||||||
|
|
||||||
|
// Enable morph()
|
||||||
|
#define IMLIB_ENABLE_MORPH
|
||||||
|
|
||||||
|
// Enable Gaussian
|
||||||
|
#define IMLIB_ENABLE_GAUSSIAN
|
||||||
|
|
||||||
|
// Enable Laplacian
|
||||||
|
#define IMLIB_ENABLE_LAPLACIAN
|
||||||
|
|
||||||
|
// Enable bilateral()
|
||||||
|
#define IMLIB_ENABLE_BILATERAL
|
||||||
|
|
||||||
|
// Enable linpolar()
|
||||||
|
#define IMLIB_ENABLE_LINPOLAR
|
||||||
|
|
||||||
|
// Enable logpolar()
|
||||||
|
#define IMLIB_ENABLE_LOGPOLAR
|
||||||
|
|
||||||
|
// Enable lens_corr()
|
||||||
|
#define IMLIB_ENABLE_LENS_CORR
|
||||||
|
|
||||||
|
// Enable rotation_corr()
|
||||||
|
#define IMLIB_ENABLE_ROTATION_CORR
|
||||||
|
|
||||||
|
// Enable phasecorrelate()
|
||||||
|
#if defined(IMLIB_ENABLE_ROTATION_CORR)
|
||||||
|
#define IMLIB_ENABLE_FIND_DISPLACEMENT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Enable get_similarity()
|
||||||
|
#define IMLIB_ENABLE_GET_SIMILARITY
|
||||||
|
|
||||||
|
// Enable find_lines()
|
||||||
|
#define IMLIB_ENABLE_FIND_LINES
|
||||||
|
|
||||||
|
// Enable find_line_segments()
|
||||||
|
#define IMLIB_ENABLE_FIND_LINE_SEGMENTS
|
||||||
|
|
||||||
|
// Enable find_circles()
|
||||||
|
#define IMLIB_ENABLE_FIND_CIRCLES
|
||||||
|
|
||||||
|
// Enable find_rects()
|
||||||
|
#define IMLIB_ENABLE_FIND_RECTS
|
||||||
|
|
||||||
|
// Enable find_qrcodes() (14 KB)
|
||||||
|
#define IMLIB_ENABLE_QRCODES
|
||||||
|
|
||||||
|
// Enable find_apriltags() (64 KB)
|
||||||
|
#define IMLIB_ENABLE_APRILTAGS
|
||||||
|
#define IMLIB_ENABLE_APRILTAGS_TAG36H11
|
||||||
|
|
||||||
|
// Enable fine find_apriltags() - (8-way connectivity versus 4-way connectivity)
|
||||||
|
// #define IMLIB_ENABLE_FINE_APRILTAGS
|
||||||
|
|
||||||
|
// Enable high res find_apriltags() - uses more RAM
|
||||||
|
#define IMLIB_ENABLE_HIGH_RES_APRILTAGS
|
||||||
|
|
||||||
|
// Enable find_datamatrices() (26 KB)
|
||||||
|
#define IMLIB_ENABLE_DATAMATRICES
|
||||||
|
|
||||||
|
// Enable find_barcodes() (42 KB)
|
||||||
|
#define IMLIB_ENABLE_BARCODES
|
||||||
|
|
||||||
|
// Enable find_features() and Haar cascades.
|
||||||
|
#define IMLIB_ENABLE_FEATURES
|
||||||
|
|
||||||
|
// Enable Tensor Flow
|
||||||
|
#define IMLIB_ENABLE_STAI
|
||||||
|
|
||||||
|
// Enable AGAST.
|
||||||
|
#define IMLIB_ENABLE_AGAST
|
||||||
|
|
||||||
|
// Enable find_template()
|
||||||
|
#define IMLIB_FIND_TEMPLATE
|
||||||
|
|
||||||
|
// Enable find_lbp()
|
||||||
|
#define IMLIB_ENABLE_FIND_LBP
|
||||||
|
|
||||||
|
// Enable find_keypoints()
|
||||||
|
#if defined(IMLIB_ENABLE_FAST) || defined(IMLIB_ENABLE_AGAST)
|
||||||
|
#define IMLIB_ENABLE_FIND_KEYPOINTS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Enable load, save and match descriptor
|
||||||
|
#define IMLIB_ENABLE_DESCRIPTOR
|
||||||
|
|
||||||
|
// Enable find_hog()
|
||||||
|
// #define IMLIB_ENABLE_HOG
|
||||||
|
|
||||||
|
// Enable selective_search()
|
||||||
|
// #define IMLIB_ENABLE_SELECTIVE_SEARCH
|
||||||
|
|
||||||
|
// Enable PNG encoder/decoder
|
||||||
|
#define IMLIB_ENABLE_PNG_ENCODER
|
||||||
|
#define IMLIB_ENABLE_PNG_DECODER
|
||||||
|
|
||||||
|
// Stereo Imaging
|
||||||
|
// #define IMLIB_ENABLE_STEREO_DISPARITY
|
||||||
|
|
||||||
|
#endif //__IMLIB_CONFIG_H__
|
33
boards/OPENMV_N6/manifest.py
Normal file
33
boards/OPENMV_N6/manifest.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
include("$(MPY_DIR)/extmod/asyncio")
|
||||||
|
|
||||||
|
# Filesystem
|
||||||
|
freeze ("$(OMV_LIB_DIR)/", "_boot.py")
|
||||||
|
|
||||||
|
# Drivers
|
||||||
|
freeze ("$(OMV_LIB_DIR)/", "modbus.py")
|
||||||
|
freeze ("$(OMV_LIB_DIR)/", "pid.py")
|
||||||
|
freeze ("$(OMV_LIB_DIR)/", "bno055.py")
|
||||||
|
freeze ("$(OMV_LIB_DIR)/", "ssd1306.py")
|
||||||
|
freeze ("$(OMV_LIB_DIR)/", "tb6612.py")
|
||||||
|
freeze ("$(OMV_LIB_DIR)/", "vl53l1x.py")
|
||||||
|
freeze ("$(OMV_LIB_DIR)/", "machine.py")
|
||||||
|
freeze ("$(OMV_LIB_DIR)/", "display.py")
|
||||||
|
freeze ("$(OMV_LIB_DIR)/ml")
|
||||||
|
|
||||||
|
# Networking
|
||||||
|
require("ssl")
|
||||||
|
require("ntptime")
|
||||||
|
require("webrepl")
|
||||||
|
freeze ("$(OMV_LIB_DIR)/", "rpc.py")
|
||||||
|
freeze ("$(OMV_LIB_DIR)/", "rtsp.py")
|
||||||
|
freeze ("$(OMV_LIB_DIR)/", "mqtt.py")
|
||||||
|
freeze ("$(OMV_LIB_DIR)/", "requests.py")
|
||||||
|
|
||||||
|
# Utils
|
||||||
|
require("time")
|
||||||
|
require("logging")
|
||||||
|
require("collections-defaultdict")
|
||||||
|
require("types")
|
||||||
|
|
||||||
|
# Bluetooth
|
||||||
|
require("aioble")
|
322
boards/OPENMV_N6/omv_boardconfig.h
Normal file
322
boards/OPENMV_N6/omv_boardconfig.h
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2024 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
* Copyright (c) 2013-2024 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
*
|
||||||
|
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
*
|
||||||
|
* Board configuration and pin definitions.
|
||||||
|
*/
|
||||||
|
#ifndef __OMV_BOARDCONFIG_H__
|
||||||
|
#define __OMV_BOARDCONFIG_H__
|
||||||
|
|
||||||
|
// Architecture info
|
||||||
|
#define OMV_BOARD_ARCH "OpenMV N6" // 33 chars max
|
||||||
|
#define OMV_BOARD_TYPE "N6"
|
||||||
|
#define OMV_BOARD_UID_ADDR 0x46009014 // Unique ID address.
|
||||||
|
#define OMV_BOARD_UID_SIZE 3 // Unique ID size in words.
|
||||||
|
#define OMV_BOARD_UID_OFFSET 4 // Bytes offset for multi-word UIDs.
|
||||||
|
|
||||||
|
// JPEG compression settings.
|
||||||
|
#define OMV_JPEG_CODEC_ENABLE (1)
|
||||||
|
#define OMV_JPEG_QUALITY_LOW (50)
|
||||||
|
#define OMV_JPEG_QUALITY_HIGH (90)
|
||||||
|
#define OMV_JPEG_QUALITY_THRESHOLD (800 * 600 * 2)
|
||||||
|
|
||||||
|
// Enable RAW preview.
|
||||||
|
#define OMV_RAW_PREVIEW_ENABLE (1)
|
||||||
|
#define OMV_RAW_PREVIEW_WIDTH (512)
|
||||||
|
#define OMV_RAW_PREVIEW_HEIGHT (512)
|
||||||
|
|
||||||
|
// GPU Configuration
|
||||||
|
#define OMV_GPU_ENABLE (1)
|
||||||
|
#define OMV_GPU_NEMA (1)
|
||||||
|
#define OMV_GPU_NEMA_BUFFER_SIZE (32 * 1024)
|
||||||
|
|
||||||
|
#define OMV_OV7725_ENABLE (1)
|
||||||
|
#define OMV_OV7725_PLL_CONFIG (0x41) // x4
|
||||||
|
#define OMV_OV7725_BANDING (0x7F)
|
||||||
|
|
||||||
|
#define OMV_OV5640_ENABLE (1)
|
||||||
|
#define OMV_OV5640_AF_ENABLE (1)
|
||||||
|
#define OMV_OV5640_CLK_FREQ (24000000)
|
||||||
|
#define OMV_OV5640_PLL_CTRL2 (0x64)
|
||||||
|
#define OMV_OV5640_PLL_CTRL3 (0x13)
|
||||||
|
#define OMV_OV5640_REV_Y_CHECK (1)
|
||||||
|
#define OMV_OV5640_REV_Y_FREQ (25000000)
|
||||||
|
#define OMV_OV5640_REV_Y_CTRL2 (0x54)
|
||||||
|
#define OMV_OV5640_REV_Y_CTRL3 (0x13)
|
||||||
|
|
||||||
|
#define OMV_MT9V0XX_ENABLE (1)
|
||||||
|
#define OMV_LEPTON_ENABLE (1)
|
||||||
|
#define OMV_PAG7936_ENABLE (1)
|
||||||
|
#define OMV_PAG7936_MIPI_CSI2 (1)
|
||||||
|
#define OMV_PS5520_ENABLE (1)
|
||||||
|
#define OMV_GENX320_EHC_ENABLE (1)
|
||||||
|
#define OMV_GENX320_HSYNC_VALUE (0x1)
|
||||||
|
|
||||||
|
// FIR drivers configuration.
|
||||||
|
#define OMV_FIR_MLX90621_ENABLE (1)
|
||||||
|
#define OMV_FIR_MLX90640_ENABLE (1)
|
||||||
|
#define OMV_FIR_MLX90641_ENABLE (1)
|
||||||
|
#define OMV_FIR_AMG8833_ENABLE (1)
|
||||||
|
#define OMV_FIR_LEPTON_ENABLE (0)
|
||||||
|
|
||||||
|
// UMM heap block size
|
||||||
|
#define OMV_UMM_BLOCK_SIZE 256
|
||||||
|
|
||||||
|
// USB IRQn.
|
||||||
|
#define OMV_USB_IRQN (USB1_OTG_HS_IRQn)
|
||||||
|
|
||||||
|
//PLL1 800MHz
|
||||||
|
#define OMV_OSC_PLL1M (3)
|
||||||
|
#define OMV_OSC_PLL1N (50)
|
||||||
|
#define OMV_OSC_PLL1P1 (1)
|
||||||
|
#define OMV_OSC_PLL1P2 (1)
|
||||||
|
#define OMV_OSC_PLL1FRAC (0)
|
||||||
|
#define OMV_OSC_PLL1SOURCE RCC_PLLSOURCE_HSE
|
||||||
|
|
||||||
|
//PLL2 1000MHz
|
||||||
|
#define OMV_OSC_PLL2M (6)
|
||||||
|
#define OMV_OSC_PLL2N (125)
|
||||||
|
#define OMV_OSC_PLL2P1 (1)
|
||||||
|
#define OMV_OSC_PLL2P2 (1)
|
||||||
|
#define OMV_OSC_PLL2FRAC (0)
|
||||||
|
#define OMV_OSC_PLL2SOURCE RCC_PLLSOURCE_HSE
|
||||||
|
|
||||||
|
//PLL3 1200MHz
|
||||||
|
#define OMV_OSC_PLL3M (1)
|
||||||
|
#define OMV_OSC_PLL3N (25)
|
||||||
|
#define OMV_OSC_PLL3P1 (1)
|
||||||
|
#define OMV_OSC_PLL3P2 (1)
|
||||||
|
#define OMV_OSC_PLL3FRAC (0)
|
||||||
|
#define OMV_OSC_PLL3SOURCE RCC_PLLSOURCE_HSE
|
||||||
|
|
||||||
|
//PLL4 1200MHz
|
||||||
|
#define OMV_OSC_PLL4M (1)
|
||||||
|
#define OMV_OSC_PLL4N (25)
|
||||||
|
#define OMV_OSC_PLL4P1 (1)
|
||||||
|
#define OMV_OSC_PLL4P2 (1)
|
||||||
|
#define OMV_OSC_PLL4FRAC (0)
|
||||||
|
#define OMV_OSC_PLL4SOURCE RCC_PLLSOURCE_HSE
|
||||||
|
|
||||||
|
// Clock Sources
|
||||||
|
#define OMV_RCC_IC8_SOURCE (RCC_ICCLKSOURCE_PLL3)
|
||||||
|
#define OMV_RCC_IC8_CLKDIV (25)
|
||||||
|
|
||||||
|
#define OMV_RCC_IC9_SOURCE (RCC_ICCLKSOURCE_PLL1)
|
||||||
|
#define OMV_RCC_IC9_CLKDIV (10)
|
||||||
|
|
||||||
|
#define OMV_RCC_IC10_SOURCE (RCC_ICCLKSOURCE_PLL1)
|
||||||
|
#define OMV_RCC_IC10_CLKDIV (8)
|
||||||
|
|
||||||
|
#define OMV_RCC_IC14_SOURCE (RCC_ICCLKSOURCE_PLL1)
|
||||||
|
#define OMV_RCC_IC14_CLKDIV (10)
|
||||||
|
|
||||||
|
#define OMV_RCC_IC15_SOURCE (RCC_ICCLKSOURCE_PLL1)
|
||||||
|
#define OMV_RCC_IC15_CLKDIV (16)
|
||||||
|
|
||||||
|
#define OMV_RCC_IC17_SOURCE (RCC_ICCLKSOURCE_PLL3)
|
||||||
|
#define OMV_RCC_IC17_CLKDIV (4)
|
||||||
|
|
||||||
|
#define OMV_RCC_IC18_SOURCE (RCC_ICCLKSOURCE_PLL3)
|
||||||
|
#define OMV_RCC_IC18_CLKDIV (60)
|
||||||
|
|
||||||
|
#define OMV_OSC_I2C3_SOURCE (RCC_I2C3CLKSOURCE_IC10)
|
||||||
|
#define OMV_OSC_SPI5_SOURCE (RCC_SPI5CLKSOURCE_IC9)
|
||||||
|
#define OMV_OSC_DCMIPP_SOURCE (RCC_DCMIPPCLKSOURCE_IC17)
|
||||||
|
#define OMV_OSC_CSI_SOURCE (0) // has one clock source IC18
|
||||||
|
#define OMV_OSC_ADF1_SOURCE (RCC_ADF1CLKSOURCE_IC8)
|
||||||
|
|
||||||
|
// HSE/HSI/CSI State
|
||||||
|
#define OMV_OSC_HSE_STATE (RCC_HSE_ON)
|
||||||
|
#define OMV_OSC_HSI_STATE (RCC_HSI_ON)
|
||||||
|
#define OMV_OSC_HSI_DIV (RCC_HSI_DIV1)
|
||||||
|
#define OMV_OSC_HSI_CAL (RCC_HSICALIBRATION_DEFAULT)
|
||||||
|
|
||||||
|
|
||||||
|
// Power supply configuration
|
||||||
|
#define OMV_PWR_SUPPLY (PWR_SMPS_SUPPLY)
|
||||||
|
|
||||||
|
// Linker script constants (see the linker script template stm32fxxx.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_MAIN_MEMORY SRAM1 // Data/BSS memory
|
||||||
|
#define OMV_STACK_MEMORY SRAM1 // stack memory
|
||||||
|
#define OMV_RAMFUNC_MEMORY ITCM
|
||||||
|
#define OMV_STACK_SIZE (64K)
|
||||||
|
#define OMV_HEAP_MEMORY SRAM1 // libc/sbrk heap memory
|
||||||
|
#define OMV_HEAP_SIZE (256K)
|
||||||
|
#define OMV_FB_MEMORY DRAM // Framebuffer, fb_alloc
|
||||||
|
#define OMV_FB_SIZE (20M) // FB memory.
|
||||||
|
#define OMV_FB_ALLOC_SIZE (11M) // minimum fb_alloc size
|
||||||
|
#define OMV_JPEG_MEMORY DRAM // JPEG buffer memory buffer.
|
||||||
|
#define OMV_JPEG_SIZE (1M) // IDE JPEG buffer (header + data).
|
||||||
|
#define OMV_VOSPI_MEMORY SRAM1 // VoSPI buffer memory.
|
||||||
|
#define OMV_VOSPI_SIZE (64K)
|
||||||
|
#define OMV_DMA_MEMORY SRAM1 // Misc DMA buffers memory.
|
||||||
|
#define OMV_GC_BLOCK0_MEMORY SRAM2 // Main GC block
|
||||||
|
#define OMV_GC_BLOCK0_SIZE (1M)
|
||||||
|
#define OMV_GC_BLOCK1_MEMORY DRAM // Main GC block
|
||||||
|
#define OMV_GC_BLOCK1_SIZE (32M)
|
||||||
|
#define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data
|
||||||
|
|
||||||
|
// Memory map.
|
||||||
|
#define OMV_DTCM_ORIGIN 0x20000000
|
||||||
|
#define OMV_DTCM_LENGTH 128K
|
||||||
|
#define OMV_ITCM_ORIGIN 0x00000000
|
||||||
|
#define OMV_ITCM_LENGTH 64K
|
||||||
|
#define OMV_SRAM1_ORIGIN 0x24000000 // AXISRAM1
|
||||||
|
#define OMV_SRAM1_LENGTH 1M // 1MB
|
||||||
|
#define OMV_SRAM2_ORIGIN 0x24100000 // AXISRAM2
|
||||||
|
#define OMV_SRAM2_LENGTH 1M // 1MB
|
||||||
|
#define OMV_SRAM3_ORIGIN 0x24200000 // AXISRAM3
|
||||||
|
#define OMV_SRAM3_LENGTH 448K // 448KB
|
||||||
|
#define OMV_SRAM4_ORIGIN 0x24270000 // AXISRAM4
|
||||||
|
#define OMV_SRAM4_LENGTH 448K // 448KB
|
||||||
|
#define OMV_SRAM5_ORIGIN 0x242E0000 // AXISRAM5
|
||||||
|
#define OMV_SRAM5_LENGTH 448K // 448KB
|
||||||
|
#define OMV_SRAM6_ORIGIN 0x24350000 // AXISRAM6
|
||||||
|
#define OMV_SRAM6_LENGTH 448K // 448KB
|
||||||
|
#define OMV_SRAM7_ORIGIN 0x28000000 // AHBSRAM1 + AHBSRAM2 combined
|
||||||
|
#define OMV_SRAM7_LENGTH 32K // 16KB + 16KB = 32KB
|
||||||
|
#define OMV_DRAM_ORIGIN 0x90000000 // XSPI1
|
||||||
|
#define OMV_DRAM_LENGTH 64M // 512 Mbits (64 MBytes)
|
||||||
|
|
||||||
|
// Flash configuration.
|
||||||
|
#define OMV_FLASH_BOOT_ORIGIN 0x34180400
|
||||||
|
#define OMV_FLASH_BOOT_LENGTH 512K
|
||||||
|
#define OMV_FLASH_TXT_ORIGIN 0x70080000
|
||||||
|
#define OMV_FLASH_TXT_LENGTH 3584K
|
||||||
|
#define OMV_ROMFS_PART0_ORIGIN 0x70800000
|
||||||
|
#define OMV_ROMFS_PART0_LENGTH 0x01800000
|
||||||
|
|
||||||
|
// Enable additional GPIO ports.
|
||||||
|
#define OMV_GPIO_PORT_F_ENABLE (1)
|
||||||
|
#define OMV_GPIO_PORT_G_ENABLE (1)
|
||||||
|
#define OMV_GPIO_PORT_H_ENABLE (1)
|
||||||
|
#define OMV_GPIO_PORT_N_ENABLE (1)
|
||||||
|
#define OMV_GPIO_PORT_O_ENABLE (1)
|
||||||
|
#define OMV_GPIO_PORT_P_ENABLE (1)
|
||||||
|
#define OMV_GPIO_PORT_Q_ENABLE (1)
|
||||||
|
|
||||||
|
// Physical I2C buses.
|
||||||
|
|
||||||
|
// I2C bus 3
|
||||||
|
#define OMV_I2C2_ID (2)
|
||||||
|
#define OMV_I2C2_SCL_PIN (&omv_pin_B10_I2C2)
|
||||||
|
#define OMV_I2C2_SDA_PIN (&omv_pin_B11_I2C2)
|
||||||
|
|
||||||
|
// I2C bus 3
|
||||||
|
#define OMV_I2C3_ID (3)
|
||||||
|
#define OMV_I2C3_SCL_PIN (&omv_pin_A8_I2C3)
|
||||||
|
#define OMV_I2C3_SDA_PIN (&omv_pin_A9_I2C3)
|
||||||
|
|
||||||
|
// I2C bus 4
|
||||||
|
#define OMV_I2C4_ID (4)
|
||||||
|
#define OMV_I2C4_SCL_PIN (&omv_pin_E13_I2C4)
|
||||||
|
#define OMV_I2C4_SDA_PIN (&omv_pin_E14_I2C4)
|
||||||
|
|
||||||
|
// Physical SPI buses.
|
||||||
|
|
||||||
|
// SPI bus 5
|
||||||
|
#define OMV_SPI5_ID (5)
|
||||||
|
#define OMV_SPI5_SCLK_PIN (&omv_pin_E15_SPI5)
|
||||||
|
#define OMV_SPI5_MISO_PIN (&omv_pin_D4_SPI5)
|
||||||
|
#define OMV_SPI5_MOSI_PIN (&omv_pin_A4_SPI5)
|
||||||
|
#define OMV_SPI5_SSEL_PIN (&omv_pin_A3_SPI5)
|
||||||
|
#define OMV_SPI5_DMA_TX_CHANNEL (GPDMA1_Channel0)
|
||||||
|
#define OMV_SPI5_DMA_TX_REQUEST (GPDMA1_REQUEST_SPI5_TX)
|
||||||
|
#define OMV_SPI5_DMA_RX_CHANNEL (GPDMA1_Channel1)
|
||||||
|
#define OMV_SPI5_DMA_RX_REQUEST (GPDMA1_REQUEST_SPI5_RX)
|
||||||
|
|
||||||
|
// CSI SPI bus
|
||||||
|
#define OMV_CSI_SPI_ID (OMV_SPI5_ID)
|
||||||
|
|
||||||
|
// CSI I2C bus
|
||||||
|
#define OMV_CSI_I2C_ID (OMV_I2C3_ID)
|
||||||
|
#define OMV_CSI_I2C_SPEED (OMV_I2C_SPEED_STANDARD)
|
||||||
|
|
||||||
|
// FIR I2C bus
|
||||||
|
#define OMV_FIR_I2C_ID (OMV_I2C2_ID)
|
||||||
|
#define OMV_FIR_I2C_SPEED (OMV_I2C_SPEED_FULL)
|
||||||
|
|
||||||
|
// IMU SPI bus
|
||||||
|
#define OMV_IMU_I2C_ID (OMV_I2C4_ID)
|
||||||
|
#define OMV_IMU_I2C_SPEED (OMV_I2C_SPEED_FULL)
|
||||||
|
#define OMV_IMU_CHIP_LSM6DSM (1)
|
||||||
|
#define OMV_IMU_X_Y_ROTATION_DEGREES 90
|
||||||
|
#define OMV_IMU_MOUNTING_Z_DIRECTION -1
|
||||||
|
|
||||||
|
// MDF1
|
||||||
|
#define OMV_MDF (ADF1_Filter0)
|
||||||
|
#define OMV_MDF_PROC_CLKDIV (2) // 48MHz / 2 = 24MHz
|
||||||
|
#define OMV_MDF_CCKY_CLKDIV (12) // 24MHz / 12 = 2 MHz
|
||||||
|
#define OMV_AUDIO_MAX_CHANNELS (2)
|
||||||
|
|
||||||
|
#define OMV_MDF_CK_PIN (&omv_pin_E2_ADF1)
|
||||||
|
#define OMV_MDF_D1_PIN (&omv_pin_B2_ADF1)
|
||||||
|
|
||||||
|
#define OMV_MDF_FLT0_IRQ ADF1_FLT0_IRQn
|
||||||
|
#define OMV_MDF_FLT0_IRQHandler ADF1_FLT0_IRQHandler
|
||||||
|
#define OMV_MDF_FLT0_DMA_STREAM GPDMA1_Channel6
|
||||||
|
#define OMV_MDF_FLT0_DMA_REQUEST GPDMA1_REQUEST_ADF1_FLT0
|
||||||
|
#define OMV_MDF_FLT0_DMA_IRQ GPDMA1_Channel6_IRQn
|
||||||
|
|
||||||
|
// Camera Interface
|
||||||
|
#define OMV_CSI_CLK_SOURCE (OMV_CSI_CLK_SOURCE_TIM)
|
||||||
|
#define OMV_CSI_CLK_FREQUENCY (12000000)
|
||||||
|
#define OMV_CSI_TIM (TIM1)
|
||||||
|
#define OMV_CSI_TIM_PIN (&omv_pin_E9_TIM1)
|
||||||
|
#define OMV_CSI_TIM_CHANNEL (TIM_CHANNEL_1)
|
||||||
|
#define OMV_CSI_TIM_CLK_ENABLE() __TIM1_CLK_ENABLE()
|
||||||
|
#define OMV_CSI_TIM_CLK_DISABLE() __TIM1_CLK_DISABLE()
|
||||||
|
#define OMV_CSI_TIM_CLK_SLEEP_ENABLE() __TIM1_CLK_SLEEP_ENABLE()
|
||||||
|
#define OMV_CSI_TIM_PCLK_FREQ() HAL_RCC_GetPCLK2Freq()
|
||||||
|
#define OMV_CSI_DMA_CHANNEL (HPDMA1_Channel12)
|
||||||
|
#define OMV_CSI_DMA_REQUEST (HPDMA1_REQUEST_DCMI_PSSI)
|
||||||
|
#define OMV_CSI_DMA_MEMCPY_ENABLE (0)
|
||||||
|
#define OMV_CSI_HW_CROP_ENABLE (1)
|
||||||
|
|
||||||
|
#define OMV_CSI_D0_PIN (&omv_pin_A1_DCMI)
|
||||||
|
#define OMV_CSI_D1_PIN (&omv_pin_A10_DCMI)
|
||||||
|
#define OMV_CSI_D2_PIN (&omv_pin_E0_DCMI)
|
||||||
|
#define OMV_CSI_D3_PIN (&omv_pin_E10_DCMI)
|
||||||
|
#define OMV_CSI_D4_PIN (&omv_pin_B0_DCMI)
|
||||||
|
#define OMV_CSI_D5_PIN (&omv_pin_E5_DCMI)
|
||||||
|
#define OMV_CSI_D6_PIN (&omv_pin_G2_DCMI)
|
||||||
|
#define OMV_CSI_D7_PIN (&omv_pin_F1_DCMI)
|
||||||
|
|
||||||
|
#define OMV_CSI_HSYNC_PIN (&omv_pin_D0_DCMI)
|
||||||
|
#define OMV_CSI_VSYNC_PIN (&omv_pin_E6_DCMI)
|
||||||
|
#define OMV_CSI_PXCLK_PIN (&omv_pin_G1_DCMI)
|
||||||
|
#define OMV_CSI_RESET_PIN (&omv_pin_E3_GPIO)
|
||||||
|
#define OMV_CSI_POWER_PIN (&omv_pin_E1_GPIO)
|
||||||
|
//#define OMV_CSI_FSYNC_PIN (&omv_pin_B4_GPIO)
|
||||||
|
|
||||||
|
#define OMV_XSPI1_IO00_PIN (&omv_pin_P0_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_IO01_PIN (&omv_pin_P1_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_IO02_PIN (&omv_pin_P2_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_IO03_PIN (&omv_pin_P3_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_IO04_PIN (&omv_pin_P4_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_IO05_PIN (&omv_pin_P5_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_IO06_PIN (&omv_pin_P6_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_IO07_PIN (&omv_pin_P7_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_IO08_PIN (&omv_pin_P8_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_IO09_PIN (&omv_pin_P9_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_IO10_PIN (&omv_pin_P10_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_IO11_PIN (&omv_pin_P11_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_IO12_PIN (&omv_pin_P12_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_IO13_PIN (&omv_pin_P13_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_IO14_PIN (&omv_pin_P14_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_IO15_PIN (&omv_pin_P15_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_NCS1_PIN (&omv_pin_O0_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_DQS0_PIN (&omv_pin_O2_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_DQS1_PIN (&omv_pin_O3_XSPIM_P1)
|
||||||
|
#define OMV_XSPI1_CLKP_PIN (&omv_pin_O4_XSPIM_P1)
|
||||||
|
|
||||||
|
#define OMV_XSPI_PSRAM_ID (1)
|
||||||
|
#define OMV_XSPI_PSRAM_SIZE (0x4000000)
|
||||||
|
#define OMV_XSPI_PSRAM_FREQUENCY (200000000)
|
||||||
|
#endif //__OMV_BOARDCONFIG_H__
|
42
boards/OPENMV_N6/omv_boardconfig.mk
Executable file
42
boards/OPENMV_N6/omv_boardconfig.mk
Executable file
@ -0,0 +1,42 @@
|
|||||||
|
MCU=STM32N657xx
|
||||||
|
CPU=cortex-m55
|
||||||
|
FPU=fpv5-d16
|
||||||
|
PORT=stm32
|
||||||
|
SYSTEM=st/system_stm32n6
|
||||||
|
DFU_DEVICE=0x37C5:0x9206
|
||||||
|
JLINK_DEVICE=STM32N657L0
|
||||||
|
OMV_FIRM_BASE=0x70000000
|
||||||
|
OMV_FIRM_ADDR=0x70080000
|
||||||
|
OMV_BOOT_ADDR=0x34180400
|
||||||
|
OMV_BOOT_CFLAGS=-mcmse \
|
||||||
|
-DOMV_BOOTLOADER \
|
||||||
|
-DUSER_TZ_SAU_SETUP \
|
||||||
|
-DCFG_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED \
|
||||||
|
-DCFG_TUSB_RHPORT0_MODE=OPT_MODE_DEVICE
|
||||||
|
OMV_BOARD_CFLAGS=-mcmse \
|
||||||
|
-DOMV_NOSYS_STUBS_ENABLE=1 \
|
||||||
|
-DMICROPY_HW_RUNS_FROM_EXT_FLASH=1
|
||||||
|
OMV_RAMFUNC_OBJS = bdev.o xspi.o spiflash.o
|
||||||
|
OMV_SIGN_BOOT=1
|
||||||
|
OMV_SIGN_HDRV=2.3
|
||||||
|
OMV_SIGN_FLAGS=0x80000000
|
||||||
|
OMV_PROG_STLDR=MX25UM51245G_STM32N6570-NUCLEO.stldr
|
||||||
|
OMV_HSE_VALUE=48000000
|
||||||
|
OMV_ENABLE_BL=1
|
||||||
|
OMV_BOSON_ENABLE=1
|
||||||
|
OMV_GENX320_ENABLE=1
|
||||||
|
OMV_LEPTON_SDK_ENABLE=1
|
||||||
|
MICROPY_PY_CSI = 1
|
||||||
|
MICROPY_PY_FIR = 1
|
||||||
|
MICROPY_PY_IMU = 1
|
||||||
|
MICROPY_PY_ULAB = 1
|
||||||
|
MICROPY_PY_AUDIO = 1
|
||||||
|
MICROPY_PY_LWIP = 1
|
||||||
|
MICROPY_PY_SSL = 1
|
||||||
|
MICROPY_PY_SSL_ECDSA_SIGN_ALT = 0
|
||||||
|
MICROPY_SSL_MBEDTLS = 1
|
||||||
|
MICROPY_PY_NETWORK_CYW43 = 1
|
||||||
|
MICROPY_PY_BLUETOOTH = 1
|
||||||
|
MICROPY_BLUETOOTH_NIMBLE = 1
|
||||||
|
MICROPY_PY_ML = 1
|
||||||
|
MICROPY_PY_ML_STAI = 1
|
89
boards/OPENMV_N6/omv_bootconfig.h
Normal file
89
boards/OPENMV_N6/omv_bootconfig.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013-2024 OpenMV, LLC.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* Board configuration and pin definitions.
|
||||||
|
*/
|
||||||
|
// *INDENT-OFF*
|
||||||
|
#ifndef __OMV_BOOTCONFIG_H__
|
||||||
|
#define __OMV_BOOTCONFIG_H__
|
||||||
|
#include STM32_HAL_H
|
||||||
|
#include "Legacy/stm32_hal_legacy.h"
|
||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
// Misc config.
|
||||||
|
#define OMV_BOOT_VID (0x37C5)
|
||||||
|
#define OMV_BOOT_PID (0x9206)
|
||||||
|
#define OMV_BOOT_DFU_TIMEOUT (1500)
|
||||||
|
#define OMV_BOOT_MAGIC_ADDR (0x3401FFFCU)
|
||||||
|
#define OMV_BOOT_LED_PIN (0) // index in omv_boot_pins
|
||||||
|
|
||||||
|
// Flash config.
|
||||||
|
#define OMV_BOOT_AXI_FLASH_ENABLE (0)
|
||||||
|
#define OMV_BOOT_SPI_FLASH_ENABLE (1)
|
||||||
|
#define OMV_BOOT_SPI_FLASH_MMAP (1) // Memory-map the flash on exit
|
||||||
|
#define OMV_BOOT_SPI_FLASH_MMAP_DTR (1)
|
||||||
|
|
||||||
|
// OSPI/XSPI config.
|
||||||
|
#define OMV_BOOT_XSPI_INSTANCE (2)
|
||||||
|
#define OMV_BOOT_XSPI_FREQUENCY (200000000)
|
||||||
|
#define OMV_BOOT_XSPI_FLASH_SIZE (0x2000000) // Must be a power of 2.
|
||||||
|
#define OMV_BOOT_XSPI_FLASH_RST_PIN (13) // index in omv_boot_pins
|
||||||
|
|
||||||
|
#define GPIO_SPEED_LOW GPIO_SPEED_FREQ_LOW
|
||||||
|
#define GPIO_SPEED_HIGH GPIO_SPEED_FREQ_VERY_HIGH
|
||||||
|
|
||||||
|
// Boot I/O pins.
|
||||||
|
static const pin_t omv_boot_pins[] = {
|
||||||
|
{ .gpio = GPIOA, .pin = GPIO_PIN_7, .speed = GPIO_SPEED_LOW, .mode = GPIO_MODE_OUTPUT_PP, .pull = GPIO_PULLUP },
|
||||||
|
{ .gpio = GPION, .pin = GPIO_PIN_0, .speed = GPIO_SPEED_HIGH, .mode = GPIO_MODE_AF_PP, .alt = GPIO_AF9_XSPIM_P2 },
|
||||||
|
{ .gpio = GPION, .pin = GPIO_PIN_1, .speed = GPIO_SPEED_HIGH, .mode = GPIO_MODE_AF_PP, .alt = GPIO_AF9_XSPIM_P2 },
|
||||||
|
{ .gpio = GPION, .pin = GPIO_PIN_2, .speed = GPIO_SPEED_HIGH, .mode = GPIO_MODE_AF_PP, .alt = GPIO_AF9_XSPIM_P2 },
|
||||||
|
{ .gpio = GPION, .pin = GPIO_PIN_3, .speed = GPIO_SPEED_HIGH, .mode = GPIO_MODE_AF_PP, .alt = GPIO_AF9_XSPIM_P2 },
|
||||||
|
{ .gpio = GPION, .pin = GPIO_PIN_4, .speed = GPIO_SPEED_HIGH, .mode = GPIO_MODE_AF_PP, .alt = GPIO_AF9_XSPIM_P2 },
|
||||||
|
{ .gpio = GPION, .pin = GPIO_PIN_5, .speed = GPIO_SPEED_HIGH, .mode = GPIO_MODE_AF_PP, .alt = GPIO_AF9_XSPIM_P2 },
|
||||||
|
{ .gpio = GPION, .pin = GPIO_PIN_6, .speed = GPIO_SPEED_HIGH, .mode = GPIO_MODE_AF_PP, .alt = GPIO_AF9_XSPIM_P2 },
|
||||||
|
{ .gpio = GPION, .pin = GPIO_PIN_7, .speed = GPIO_SPEED_HIGH, .mode = GPIO_MODE_AF_PP, .alt = GPIO_AF9_XSPIM_P2 },
|
||||||
|
{ .gpio = GPION, .pin = GPIO_PIN_8, .speed = GPIO_SPEED_HIGH, .mode = GPIO_MODE_AF_PP, .alt = GPIO_AF9_XSPIM_P2 },
|
||||||
|
{ .gpio = GPION, .pin = GPIO_PIN_9, .speed = GPIO_SPEED_HIGH, .mode = GPIO_MODE_AF_PP, .alt = GPIO_AF9_XSPIM_P2 },
|
||||||
|
{ .gpio = GPION, .pin = GPIO_PIN_10, .speed = GPIO_SPEED_HIGH, .mode = GPIO_MODE_AF_PP, .alt = GPIO_AF9_XSPIM_P2 },
|
||||||
|
{ .gpio = GPION, .pin = GPIO_PIN_11, .speed = GPIO_SPEED_HIGH, .mode = GPIO_MODE_AF_PP, .alt = GPIO_AF9_XSPIM_P2 },
|
||||||
|
{ .gpio = GPION, .pin = GPIO_PIN_12, .speed = GPIO_SPEED_LOW, .mode = GPIO_MODE_OUTPUT_PP, .pull = GPIO_PULLUP },
|
||||||
|
};
|
||||||
|
#define OMV_BOOT_PINS_COUNT (sizeof(omv_boot_pins) / sizeof(omv_boot_pins[0]))
|
||||||
|
|
||||||
|
// Boot partitions.
|
||||||
|
static const partition_t OMV_BOOT_DFU_PARTITIONS[] = {
|
||||||
|
{ .type = PTYPE_SPI_FLASH, .region = -1, .rdonly = 1, .start = 0x00000000, .limit = 0x00080000, .attr = 0 }, // Boot
|
||||||
|
{ .type = PTYPE_SPI_FLASH, .region = -1, .rdonly = 0, .start = 0x00080000, .limit = 0x00400000, .attr = 0 }, // FIRMWARE
|
||||||
|
{ .type = PTYPE_SPI_FLASH, .region = -1, .rdonly = 0, .start = 0x00400000, .limit = 0x00800000, .attr = 0 }, // FILESYSTEM
|
||||||
|
{ .type = PTYPE_SPI_FLASH, .region = -1, .rdonly = 0, .start = 0x00800000, .limit = 0x02000000, .attr = 0 }, // ROMFS0
|
||||||
|
};
|
||||||
|
#define OMV_BOOT_DFU_PARTITIONS_COUNT 4 // Must be a literal
|
||||||
|
#define OMV_BOOT_DFU_PARTITIONS_STR "BOOTLOADER", "FIRMWARE", "FILESYSTEM", "ROMFS0"
|
||||||
|
|
||||||
|
// XIP flash, not used for DFU.
|
||||||
|
static const partition_t OMV_BOOT_XIP_PARTITIONS[] = {
|
||||||
|
{ .type = PTYPE_XIP_FLASH, .region = 0, .rdonly = 1, .start = 0x70000000, .limit = 0x78000000, .attr = MEMATTR_NORMAL_WB_RA_WA },
|
||||||
|
};
|
||||||
|
#define OMV_BOOT_XIP_PARTITIONS_COUNT (sizeof(OMV_BOOT_XIP_PARTITIONS) / sizeof(OMV_BOOT_XIP_PARTITIONS[0]))
|
||||||
|
#endif //__OMV_BOOTCONFIG_H__
|
53
boards/OPENMV_N6/omv_pins.h
Normal file
53
boards/OPENMV_N6/omv_pins.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
OMV_GPIO_DEFINE(E, 15, AF5, SPI5) // SCLK
|
||||||
|
OMV_GPIO_DEFINE(D, 4, AF5, SPI5) // MISO
|
||||||
|
OMV_GPIO_DEFINE(A, 4, AF5, SPI5) // MOSI
|
||||||
|
OMV_GPIO_DEFINE(A, 3, AF5, SPI5) // SSEL
|
||||||
|
|
||||||
|
OMV_GPIO_DEFINE(B, 10, AF4, I2C2) // I2C2_SCL
|
||||||
|
OMV_GPIO_DEFINE(B, 11, AF4, I2C2) // I2C2_SDA
|
||||||
|
|
||||||
|
OMV_GPIO_DEFINE(A, 8, AF4, I2C3) // I2C3_SCL
|
||||||
|
OMV_GPIO_DEFINE(A, 9, AF4, I2C3) // I2C3_SDA
|
||||||
|
|
||||||
|
OMV_GPIO_DEFINE(E, 13, AF4, I2C4) // I2C4_SCL
|
||||||
|
OMV_GPIO_DEFINE(E, 14, AF4, I2C4) // I2C4_SDA
|
||||||
|
|
||||||
|
OMV_GPIO_DEFINE(E, 2, AF3, ADF1) // ADF1_CCK0
|
||||||
|
OMV_GPIO_DEFINE(B, 2, AF3, ADF1) // ADF1_SDI0
|
||||||
|
|
||||||
|
OMV_GPIO_DEFINE(A, 1, AF9, DCMI) // CSI_D0
|
||||||
|
OMV_GPIO_DEFINE(A, 10, AF9, DCMI) // CSI_D1
|
||||||
|
OMV_GPIO_DEFINE(E, 0, AF9, DCMI) // CSI_D2
|
||||||
|
OMV_GPIO_DEFINE(E, 10, AF9, DCMI) // CSI_D3
|
||||||
|
OMV_GPIO_DEFINE(B, 0, AF9, DCMI) // CSI_D4
|
||||||
|
OMV_GPIO_DEFINE(E, 5, AF9, DCMI) // CSI_D5
|
||||||
|
OMV_GPIO_DEFINE(G, 2, AF9, DCMI) // CSI_D6
|
||||||
|
OMV_GPIO_DEFINE(F, 1, AF9, DCMI) // CSI_D7
|
||||||
|
OMV_GPIO_DEFINE(E, 9, AF1, TIM1) // CSI_CLK
|
||||||
|
OMV_GPIO_DEFINE(D, 0, AF9, DCMI) // CSI_HSYNC
|
||||||
|
OMV_GPIO_DEFINE(E, 6, AF9, DCMI) // CSI_VSYNC
|
||||||
|
OMV_GPIO_DEFINE(G, 1, AF9, DCMI) // CSI_PXCLK
|
||||||
|
OMV_GPIO_DEFINE(E, 3, NONE, GPIO) // CSI_RESET
|
||||||
|
OMV_GPIO_DEFINE(E, 1, NONE, GPIO) // CSI_POWER
|
||||||
|
|
||||||
|
OMV_GPIO_DEFINE(P, 0, AF9, XSPIM_P1) // XSPIM_IO0
|
||||||
|
OMV_GPIO_DEFINE(P, 1, AF9, XSPIM_P1) // XSPIM_IO1
|
||||||
|
OMV_GPIO_DEFINE(P, 2, AF9, XSPIM_P1) // XSPIM_IO2
|
||||||
|
OMV_GPIO_DEFINE(P, 3, AF9, XSPIM_P1) // XSPIM_IO3
|
||||||
|
OMV_GPIO_DEFINE(P, 4, AF9, XSPIM_P1) // XSPIM_IO4
|
||||||
|
OMV_GPIO_DEFINE(P, 5, AF9, XSPIM_P1) // XSPIM_IO5
|
||||||
|
OMV_GPIO_DEFINE(P, 6, AF9, XSPIM_P1) // XSPIM_IO6
|
||||||
|
OMV_GPIO_DEFINE(P, 7, AF9, XSPIM_P1) // XSPIM_IO7
|
||||||
|
OMV_GPIO_DEFINE(P, 8, AF9, XSPIM_P1) // XSPIM_IO8
|
||||||
|
OMV_GPIO_DEFINE(P, 9, AF9, XSPIM_P1) // XSPIM_IO9
|
||||||
|
OMV_GPIO_DEFINE(P, 10, AF9, XSPIM_P1) // XSPIM_IO10
|
||||||
|
OMV_GPIO_DEFINE(P, 11, AF9, XSPIM_P1) // XSPIM_IO11
|
||||||
|
OMV_GPIO_DEFINE(P, 12, AF9, XSPIM_P1) // XSPIM_IO12
|
||||||
|
OMV_GPIO_DEFINE(P, 13, AF9, XSPIM_P1) // XSPIM_IO13
|
||||||
|
OMV_GPIO_DEFINE(P, 14, AF9, XSPIM_P1) // XSPIM_IO14
|
||||||
|
OMV_GPIO_DEFINE(P, 15, AF9, XSPIM_P1) // XSPIM_IO15
|
||||||
|
|
||||||
|
OMV_GPIO_DEFINE(O, 0, AF9, XSPIM_P1) // XSPIM_NCS1
|
||||||
|
OMV_GPIO_DEFINE(O, 2, AF9, XSPIM_P1) // XSPIM_DQS0
|
||||||
|
OMV_GPIO_DEFINE(O, 3, AF9, XSPIM_P1) // XSPIM_DQS1
|
||||||
|
OMV_GPIO_DEFINE(O, 4, AF9, XSPIM_P1) // XSPIM_CLKP
|
25
boards/OPENMV_N6/romfs.json
Normal file
25
boards/OPENMV_N6/romfs.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"0": {
|
||||||
|
"size": "0x1800000",
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"type": "tflite",
|
||||||
|
"path": "{TOP}/lib/models/fomo_face_detection.tflite",
|
||||||
|
"alignment": 32,
|
||||||
|
"profile": "default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tflite",
|
||||||
|
"path": "{TOP}/lib/models/yolo_v2_224_small.tflite",
|
||||||
|
"alignment": 32,
|
||||||
|
"profile": "default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tflite",
|
||||||
|
"path": "{TOP}/lib/models/yolo_v5_224_nano.tflite",
|
||||||
|
"alignment": 32,
|
||||||
|
"profile": "default"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
17
boards/OPENMV_N6/ulab_config.h
Normal file
17
boards/OPENMV_N6/ulab_config.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project.
|
||||||
|
* Copyright (c) 2013-2016 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
*
|
||||||
|
* Ulab config file.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __ULAB_CONFIG_H__
|
||||||
|
#define __ULAB_CONFIG_H__
|
||||||
|
// Override ulab defaults here.
|
||||||
|
#define ULAB_MAX_DIMS (4)
|
||||||
|
#define ULAB_SUPPORTS_COMPLEX (0)
|
||||||
|
#define ULAB_SCIPY_HAS_OPTIMIZE_MODULE (0)
|
||||||
|
#define ULAB_SCIPY_HAS_SPECIAL_MODULE (0)
|
||||||
|
#define ULAB_FFT_IS_NUMPY_COMPATIBLE (0)
|
||||||
|
#endif //__ULAB_CONFIG_H__
|
@ -70,6 +70,23 @@ Reset_Handler:
|
|||||||
/* Call the clock system initialization function.*/
|
/* Call the clock system initialization function.*/
|
||||||
bl SystemInit
|
bl SystemInit
|
||||||
|
|
||||||
|
/* Copy RAM functions from flash to ITCM */
|
||||||
|
ldr r0, =_ram_function_start // Destination start (RAM)
|
||||||
|
ldr r1, =_ram_function_end // Destination end (RAM)
|
||||||
|
ldr r2, =_ram_function_flash // Source start (Flash)
|
||||||
|
movs r3, #0
|
||||||
|
b LoopCopyRamFunc
|
||||||
|
|
||||||
|
CopyRamFunc:
|
||||||
|
ldr r4, [r2, r3]
|
||||||
|
str r4, [r0, r3]
|
||||||
|
adds r3, r3, #4
|
||||||
|
|
||||||
|
LoopCopyRamFunc:
|
||||||
|
adds r4, r0, r3
|
||||||
|
cmp r4, r1
|
||||||
|
bcc CopyRamFunc
|
||||||
|
|
||||||
/* Copy the data segment initializers from flash to SRAM */
|
/* Copy the data segment initializers from flash to SRAM */
|
||||||
ldr r0, =_sdata
|
ldr r0, =_sdata
|
||||||
ldr r1, =_edata
|
ldr r1, =_edata
|
||||||
|
@ -147,9 +147,25 @@ void SystemClock_Config(void) {
|
|||||||
//PeriphClkInit.CsiClockSelection = OMV_OSC_DCMIPP_SOURCE;
|
//PeriphClkInit.CsiClockSelection = OMV_OSC_DCMIPP_SOURCE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(OMV_OSC_MDF1_SOURCE)
|
||||||
|
PeriphClkInit.PeriphClockSelection |= RCC_PERIPHCLK_MDF1;
|
||||||
|
PeriphClkInit.Mdf1ClockSelection = OMV_OSC_MDF1_SOURCE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OMV_OSC_ADF1_SOURCE)
|
||||||
|
PeriphClkInit.PeriphClockSelection |= RCC_PERIPHCLK_ADF1;
|
||||||
|
PeriphClkInit.Adf1ClockSelection = OMV_OSC_ADF1_SOURCE;
|
||||||
|
#endif
|
||||||
|
|
||||||
PeriphClkInit.PeriphClockSelection |= RCC_PERIPHCLK_XSPI1;
|
PeriphClkInit.PeriphClockSelection |= RCC_PERIPHCLK_XSPI1;
|
||||||
PeriphClkInit.Xspi1ClockSelection = RCC_XSPI1CLKSOURCE_HCLK;
|
PeriphClkInit.Xspi1ClockSelection = RCC_XSPI1CLKSOURCE_HCLK;
|
||||||
|
|
||||||
|
PeriphClkInit.PeriphClockSelection |= RCC_PERIPHCLK_SDMMC1;
|
||||||
|
PeriphClkInit.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_HCLK;
|
||||||
|
|
||||||
|
PeriphClkInit.PeriphClockSelection |= RCC_PERIPHCLK_SDMMC2;
|
||||||
|
PeriphClkInit.Sdmmc2ClockSelection = RCC_SDMMC2CLKSOURCE_HCLK;
|
||||||
|
|
||||||
#if defined(OMV_RCC_IC0_SOURCE)
|
#if defined(OMV_RCC_IC0_SOURCE)
|
||||||
PeriphClkInit.ICSelection[RCC_IC0].ClockSelection = OMV_RCC_IC0_SOURCE;
|
PeriphClkInit.ICSelection[RCC_IC0].ClockSelection = OMV_RCC_IC0_SOURCE;
|
||||||
PeriphClkInit.ICSelection[RCC_IC0].ClockDivider = OMV_RCC_IC0_CLKDIV;
|
PeriphClkInit.ICSelection[RCC_IC0].ClockDivider = OMV_RCC_IC0_CLKDIV;
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
#define HAL_LPTIM_MODULE_ENABLED
|
#define HAL_LPTIM_MODULE_ENABLED
|
||||||
/*#define HAL_LTDC_MODULE_ENABLED */
|
/*#define HAL_LTDC_MODULE_ENABLED */
|
||||||
/*#define HAL_MCE_MODULE_ENABLED */
|
/*#define HAL_MCE_MODULE_ENABLED */
|
||||||
/*#define HAL_MDF_MODULE_ENABLED */
|
#define HAL_MDF_MODULE_ENABLED
|
||||||
/*#define HAL_MMC_MODULE_ENABLED */
|
/*#define HAL_MMC_MODULE_ENABLED */
|
||||||
/*#define HAL_NAND_MODULE_ENABLED */
|
/*#define HAL_NAND_MODULE_ENABLED */
|
||||||
/*#define HAL_NOR_MODULE_ENABLED */
|
/*#define HAL_NOR_MODULE_ENABLED */
|
||||||
@ -70,7 +70,7 @@
|
|||||||
#define HAL_RNG_MODULE_ENABLED
|
#define HAL_RNG_MODULE_ENABLED
|
||||||
#define HAL_RTC_MODULE_ENABLED
|
#define HAL_RTC_MODULE_ENABLED
|
||||||
/*#define HAL_SAI_MODULE_ENABLED */
|
/*#define HAL_SAI_MODULE_ENABLED */
|
||||||
/*#define HAL_SD_MODULE_ENABLED */
|
#define HAL_SD_MODULE_ENABLED
|
||||||
/*#define HAL_SDRAM_MODULE_ENABLED */
|
/*#define HAL_SDRAM_MODULE_ENABLED */
|
||||||
/*#define HAL_SMARTCARD_MODULE_ENABLED */
|
/*#define HAL_SMARTCARD_MODULE_ENABLED */
|
||||||
/*#define HAL_SMBUS_MODULE_ENABLED */
|
/*#define HAL_SMBUS_MODULE_ENABLED */
|
||||||
@ -416,6 +416,7 @@
|
|||||||
|
|
||||||
#ifdef HAL_RTC_MODULE_ENABLED
|
#ifdef HAL_RTC_MODULE_ENABLED
|
||||||
#include "stm32n6xx_hal_rtc.h"
|
#include "stm32n6xx_hal_rtc.h"
|
||||||
|
#include "stm32n6xx_ll_rtc.h"
|
||||||
#endif /* HAL_RTC_MODULE_ENABLED */
|
#endif /* HAL_RTC_MODULE_ENABLED */
|
||||||
|
|
||||||
#ifdef HAL_SAI_MODULE_ENABLED
|
#ifdef HAL_SAI_MODULE_ENABLED
|
||||||
|
@ -84,6 +84,7 @@
|
|||||||
|
|
||||||
#include "usbdbg.h"
|
#include "usbdbg.h"
|
||||||
#include "sdram.h"
|
#include "sdram.h"
|
||||||
|
#include "xspi_psram.h"
|
||||||
#include "fb_alloc.h"
|
#include "fb_alloc.h"
|
||||||
#include "dma_alloc.h"
|
#include "dma_alloc.h"
|
||||||
#include "file_utils.h"
|
#include "file_utils.h"
|
||||||
@ -162,6 +163,18 @@ int main(void) {
|
|||||||
storage_init();
|
storage_init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if OMV_XSPI_PSRAM_SIZE
|
||||||
|
if (xspi_psram_init() != 0) {
|
||||||
|
__fatal_error("Failed to init XSPI PSRAM!");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if OMV_XSPI_PSRAM_STARTUP_TEST
|
||||||
|
if (xspi_psram_test(true) == 0) {
|
||||||
|
__fatal_error("XSPI PSRAM test failed");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Basic sub-system init
|
// Basic sub-system init
|
||||||
led_init();
|
led_init();
|
||||||
pendsv_init();
|
pendsv_init();
|
||||||
@ -208,7 +221,9 @@ soft_reset:
|
|||||||
#if MICROPY_HW_ENABLE_CAN
|
#if MICROPY_HW_ENABLE_CAN
|
||||||
pyb_can_init0();
|
pyb_can_init0();
|
||||||
#endif
|
#endif
|
||||||
|
#if MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C
|
||||||
i2c_init0();
|
i2c_init0();
|
||||||
|
#endif
|
||||||
spi_init0();
|
spi_init0();
|
||||||
uart_init0();
|
uart_init0();
|
||||||
fb_alloc_init0();
|
fb_alloc_init0();
|
||||||
@ -263,7 +278,10 @@ soft_reset:
|
|||||||
#if MICROPY_PY_CSI
|
#if MICROPY_PY_CSI
|
||||||
// Initialize the csi.
|
// Initialize the csi.
|
||||||
if (first_soft_reset) {
|
if (first_soft_reset) {
|
||||||
omv_csi_init();
|
int ret = omv_csi_init();
|
||||||
|
if (ret != 0 && ret != OMV_CSI_ERROR_ISC_UNDETECTED) {
|
||||||
|
__fatal_error("Failed to init the CSI");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -289,13 +307,17 @@ soft_reset:
|
|||||||
|
|
||||||
// Init USB device to default setting if it was not already configured
|
// Init USB device to default setting if it was not already configured
|
||||||
if (!(pyb_usb_flags & PYB_USB_FLAG_USB_MODE_CALLED)) {
|
if (!(pyb_usb_flags & PYB_USB_FLAG_USB_MODE_CALLED)) {
|
||||||
|
uint8_t usb_mode = USBD_MODE_CDC_MSC;
|
||||||
|
#if MICROPY_HW_USB_HS
|
||||||
|
usb_mode |= USBD_MODE_HIGH_SPEED;
|
||||||
|
#endif
|
||||||
pyb_usb_dev_init(pyb_usb_dev_detect(), MICROPY_HW_USB_VID,
|
pyb_usb_dev_init(pyb_usb_dev_detect(), MICROPY_HW_USB_VID,
|
||||||
MICROPY_HW_USB_PID_CDC_MSC, USBD_MODE_CDC_MSC, 0, NULL, NULL);
|
MICROPY_HW_USB_PID, usb_mode, 0, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// report if SDRAM failed
|
// report if SDRAM failed
|
||||||
#if MICROPY_HW_SDRAM_SIZE
|
#if MICROPY_HW_SDRAM_SIZE
|
||||||
if (first_soft_reset && (!sdram_ok)) {
|
if (first_soft_reset && !sdram_ok) {
|
||||||
__fatal_error("Failed to init sdram!");
|
__fatal_error("Failed to init sdram!");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -364,7 +386,9 @@ soft_reset_exit:
|
|||||||
cyw43_deinit(&cyw43_state);
|
cyw43_deinit(&cyw43_state);
|
||||||
#endif
|
#endif
|
||||||
timer_deinit();
|
timer_deinit();
|
||||||
|
#if MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C
|
||||||
pyb_i2c_deinit_all();
|
pyb_i2c_deinit_all();
|
||||||
|
#endif
|
||||||
spi_deinit_all();
|
spi_deinit_all();
|
||||||
uart_deinit_all();
|
uart_deinit_all();
|
||||||
#if MICROPY_HW_ENABLE_CAN
|
#if MICROPY_HW_ENABLE_CAN
|
||||||
|
@ -47,21 +47,38 @@
|
|||||||
static CRC_HandleTypeDef hcrc;
|
static CRC_HandleTypeDef hcrc;
|
||||||
static SAI_HandleTypeDef hsai;
|
static SAI_HandleTypeDef hsai;
|
||||||
static DMA_HandleTypeDef hdma_sai_rx;
|
static DMA_HandleTypeDef hdma_sai_rx;
|
||||||
|
|
||||||
static PDM_Filter_Config_t PDM_FilterConfig[OMV_AUDIO_MAX_CHANNELS];
|
static PDM_Filter_Config_t PDM_FilterConfig[OMV_AUDIO_MAX_CHANNELS];
|
||||||
static PDM_Filter_Handler_t PDM_FilterHandler[OMV_AUDIO_MAX_CHANNELS];
|
static PDM_Filter_Handler_t PDM_FilterHandler[OMV_AUDIO_MAX_CHANNELS];
|
||||||
// NOTE: BDMA can only access D3 SRAM4 memory.
|
// NOTE: BDMA can only access D3 SRAM4 memory.
|
||||||
#define PDM_BUFFER_SIZE (16384)
|
#define PDM_BUFFER_SIZE (16384)
|
||||||
uint8_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED(PDM_BUFFER[PDM_BUFFER_SIZE], 32), ".d3_dma_buffer");
|
uint8_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED(PDM_BUFFER[PDM_BUFFER_SIZE], 32), ".d3_dma_buffer");
|
||||||
|
|
||||||
#elif defined(OMV_DFSDM)
|
#elif defined(OMV_DFSDM)
|
||||||
static DFSDM_Channel_HandleTypeDef hdfsdm;
|
static DFSDM_Channel_HandleTypeDef hdfsdm;
|
||||||
|
|
||||||
// NOTE: Only 1 filter is supported right now.
|
// NOTE: Only 1 filter is supported right now.
|
||||||
static DFSDM_Filter_HandleTypeDef hdfsdm_filter[OMV_AUDIO_MAX_CHANNELS];
|
static DFSDM_Filter_HandleTypeDef hdfsdm_filter[OMV_AUDIO_MAX_CHANNELS];
|
||||||
static DMA_HandleTypeDef hdma_filter[OMV_AUDIO_MAX_CHANNELS];
|
static DMA_HandleTypeDef hdma_filter[OMV_AUDIO_MAX_CHANNELS];
|
||||||
|
|
||||||
// NOTE: placed in D2 memory.
|
// NOTE: placed in D2 memory.
|
||||||
#define PDM_BUFFER_SIZE (512 * 2)
|
#define PDM_BUFFER_SIZE (512 * 2)
|
||||||
int32_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED(PDM_BUFFER[PDM_BUFFER_SIZE], 32), ".d2_dma_buffer");
|
int32_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED(PDM_BUFFER[PDM_BUFFER_SIZE], 32), ".d2_dma_buffer");
|
||||||
|
|
||||||
#define DFSDM_GAIN_FRAC_BITS (3)
|
#define DFSDM_GAIN_FRAC_BITS (3)
|
||||||
static int32_t dfsdm_gain = 1;
|
static int32_t dfsdm_gain = 1;
|
||||||
|
|
||||||
|
#elif defined(OMV_MDF)
|
||||||
|
static MDF_HandleTypeDef hmdf;
|
||||||
|
static MDF_FilterConfigTypeDef hmdf_filter[OMV_AUDIO_MAX_CHANNELS];
|
||||||
|
|
||||||
|
// NOTE: Only 1 filter is supported right now.
|
||||||
|
static DMA_QListTypeDef hdma_queue;
|
||||||
|
static DMA_NodeTypeDef OMV_ATTR_SECTION(OMV_ATTR_ALIGNED(hdma_node, 32), ".dma_buffer");
|
||||||
|
static DMA_HandleTypeDef hdma_filter[OMV_AUDIO_MAX_CHANNELS];
|
||||||
|
|
||||||
|
#define PDM_BUFFER_SIZE (512 * 2)
|
||||||
|
int32_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED(PDM_BUFFER[PDM_BUFFER_SIZE], 32), ".dma_buffer");
|
||||||
#else
|
#else
|
||||||
#error "No audio driver defined for this board"
|
#error "No audio driver defined for this board"
|
||||||
#endif
|
#endif
|
||||||
@ -84,20 +101,24 @@ void OMV_SAI_DMA_IRQHandler(void) {
|
|||||||
HAL_DMA_IRQHandler(hsai.hdmarx);
|
HAL_DMA_IRQHandler(hsai.hdmarx);
|
||||||
}
|
}
|
||||||
#elif defined(OMV_DFSDM)
|
#elif defined(OMV_DFSDM)
|
||||||
void OMV_DFSDM_FLT0_IRQHandler() {
|
void OMV_DFSDM_FLT0_IRQHandler(void) {
|
||||||
HAL_DFSDM_IRQHandler(&hdfsdm_filter[0]);
|
HAL_DFSDM_IRQHandler(&hdfsdm_filter[0]);
|
||||||
}
|
}
|
||||||
|
#elif defined(OMV_MDF)
|
||||||
|
void OMV_MDF_FLT0_IRQHandler(void) {
|
||||||
|
HAL_MDF_IRQHandler(&hmdf);
|
||||||
|
}
|
||||||
#endif // defined(OMV_SAI)
|
#endif // defined(OMV_SAI)
|
||||||
|
|
||||||
#if defined(OMV_SAI)
|
#if defined(OMV_SAI)
|
||||||
void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai)
|
void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai)
|
||||||
#elif defined(OMV_DFSDM)
|
#elif defined(OMV_DFSDM)
|
||||||
void HAL_DFSDM_FilterRegConvHalfCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
|
void HAL_DFSDM_FilterRegConvHalfCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
|
||||||
|
#elif defined(OMV_MDF)
|
||||||
|
void HAL_MDF_AcqHalfCpltCallback(MDF_HandleTypeDef *hmdf)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
xfer_status |= DMA_XFER_HALF;
|
xfer_status |= DMA_XFER_HALF;
|
||||||
uint32_t pdm_buffer_size_bytes = (sizeof(PDM_BUFFER[0]) * g_pdm_buffer_size);
|
|
||||||
SCB_InvalidateDCache_by_Addr((uint32_t *) (&PDM_BUFFER[0]), pdm_buffer_size_bytes);
|
|
||||||
if (MP_STATE_PORT(audio_callback) != mp_const_none) {
|
if (MP_STATE_PORT(audio_callback) != mp_const_none) {
|
||||||
mp_sched_schedule_node(&audio_task_sched_node, audio_task_callback);
|
mp_sched_schedule_node(&audio_task_sched_node, audio_task_callback);
|
||||||
}
|
}
|
||||||
@ -107,11 +128,11 @@ void HAL_DFSDM_FilterRegConvHalfCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_
|
|||||||
void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai)
|
void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai)
|
||||||
#elif defined(OMV_DFSDM)
|
#elif defined(OMV_DFSDM)
|
||||||
void HAL_DFSDM_FilterRegConvCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
|
void HAL_DFSDM_FilterRegConvCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
|
||||||
|
#elif defined(OMV_MDF)
|
||||||
|
void HAL_MDF_AcqCpltCallback(MDF_HandleTypeDef *hmdf)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
xfer_status |= DMA_XFER_FULL;
|
xfer_status |= DMA_XFER_FULL;
|
||||||
uint32_t pdm_buffer_size_bytes = (sizeof(PDM_BUFFER[0]) * g_pdm_buffer_size);
|
|
||||||
SCB_InvalidateDCache_by_Addr((uint32_t *) (&PDM_BUFFER[g_pdm_buffer_size]), pdm_buffer_size_bytes / 2);
|
|
||||||
if (MP_STATE_PORT(audio_callback) != mp_const_none) {
|
if (MP_STATE_PORT(audio_callback) != mp_const_none) {
|
||||||
mp_sched_schedule_node(&audio_task_sched_node, audio_task_callback);
|
mp_sched_schedule_node(&audio_task_sched_node, audio_task_callback);
|
||||||
}
|
}
|
||||||
@ -166,7 +187,9 @@ static mp_obj_t py_audio_init(uint n_args, const mp_obj_t *pos_args, mp_map_t *k
|
|||||||
// Default/max PDM buffer size;
|
// Default/max PDM buffer size;
|
||||||
g_pdm_buffer_size = PDM_BUFFER_SIZE;
|
g_pdm_buffer_size = PDM_BUFFER_SIZE;
|
||||||
|
|
||||||
#if defined(OMV_DFSDM)
|
#if defined(OMV_MDF)
|
||||||
|
uint32_t samples_per_channel = PDM_BUFFER_SIZE / 2; // Half a transfer
|
||||||
|
#elif defined(OMV_DFSDM)
|
||||||
uint32_t samples_per_channel = PDM_BUFFER_SIZE / 2; // Half a transfer
|
uint32_t samples_per_channel = PDM_BUFFER_SIZE / 2; // Half a transfer
|
||||||
dfsdm_gain = __USAT(fast_roundf(expf((gain_db / 20.0f) * M_LN10) * (1 << DFSDM_GAIN_FRAC_BITS)), 15);
|
dfsdm_gain = __USAT(fast_roundf(expf((gain_db / 20.0f) * M_LN10) * (1 << DFSDM_GAIN_FRAC_BITS)), 15);
|
||||||
#else
|
#else
|
||||||
@ -189,7 +212,7 @@ static mp_obj_t py_audio_init(uint n_args, const mp_obj_t *pos_args, mp_map_t *k
|
|||||||
}
|
}
|
||||||
samples_per_channel = args[ARG_samples].u_int;
|
samples_per_channel = args[ARG_samples].u_int;
|
||||||
// Recalculate the PDM buffer size for the requested samples.
|
// Recalculate the PDM buffer size for the requested samples.
|
||||||
#if defined(OMV_DFSDM)
|
#if defined(OMV_DFSDM) || defined(OMV_MDF)
|
||||||
g_pdm_buffer_size = samples_per_channel * 2;
|
g_pdm_buffer_size = samples_per_channel * 2;
|
||||||
#else
|
#else
|
||||||
g_pdm_buffer_size = (samples_per_channel * decimation_factor * g_channels) / 4;
|
g_pdm_buffer_size = (samples_per_channel * decimation_factor * g_channels) / 4;
|
||||||
@ -369,6 +392,96 @@ static mp_obj_t py_audio_init(uint n_args, const mp_obj_t *pos_args, mp_map_t *k
|
|||||||
|
|
||||||
NVIC_SetPriority(OMV_DFSDM_FLT0_IRQ, IRQ_PRI_DMA21);
|
NVIC_SetPriority(OMV_DFSDM_FLT0_IRQ, IRQ_PRI_DMA21);
|
||||||
HAL_NVIC_EnableIRQ(OMV_DFSDM_FLT0_IRQ);
|
HAL_NVIC_EnableIRQ(OMV_DFSDM_FLT0_IRQ);
|
||||||
|
#elif defined(OMV_MDF)
|
||||||
|
hmdf.Instance = OMV_MDF;
|
||||||
|
hmdf.Init.CommonParam.InterleavedFilters = 0;
|
||||||
|
hmdf.Init.CommonParam.ProcClockDivider = OMV_MDF_PROC_CLKDIV;
|
||||||
|
hmdf.Init.CommonParam.OutputClock.Activation = ENABLE;
|
||||||
|
hmdf.Init.CommonParam.OutputClock.Pins = MDF_OUTPUT_CLOCK_0;
|
||||||
|
hmdf.Init.CommonParam.OutputClock.Divider = OMV_MDF_CCKY_CLKDIV;
|
||||||
|
hmdf.Init.CommonParam.OutputClock.Trigger.Activation = DISABLE;
|
||||||
|
hmdf.Init.SerialInterface.Activation = ENABLE;
|
||||||
|
hmdf.Init.SerialInterface.Mode = MDF_SITF_LF_MASTER_SPI_MODE;
|
||||||
|
hmdf.Init.SerialInterface.ClockSource = MDF_SITF_CCK0_SOURCE;
|
||||||
|
hmdf.Init.SerialInterface.Threshold = 31;
|
||||||
|
hmdf.Init.FilterBistream = MDF_BITSTREAM0_FALLING;
|
||||||
|
if (HAL_MDF_Init(&hmdf) != HAL_OK) {
|
||||||
|
RAISE_OS_EXCEPTION("MDF init failed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
hmdf_filter[0].DataSource = MDF_DATA_SOURCE_BSMX;
|
||||||
|
hmdf_filter[0].Delay = 0;
|
||||||
|
hmdf_filter[0].CicMode = MDF_ONE_FILTER_SINC4;
|
||||||
|
hmdf_filter[0].DecimationRatio = 32;
|
||||||
|
hmdf_filter[0].Offset = 0;
|
||||||
|
hmdf_filter[0].Gain = gain_db / 3; // gain in steps of 3db
|
||||||
|
hmdf_filter[0].ReshapeFilter.Activation = ENABLE;
|
||||||
|
hmdf_filter[0].ReshapeFilter.DecimationRatio = MDF_RSF_DECIMATION_RATIO_4;
|
||||||
|
hmdf_filter[0].HighPassFilter.Activation = DISABLE; // Disabled for now.
|
||||||
|
hmdf_filter[0].HighPassFilter.CutOffFrequency = MDF_HPF_CUTOFF_0_000625FPCM;
|
||||||
|
hmdf_filter[0].Integrator.Activation = DISABLE;
|
||||||
|
hmdf_filter[0].SoundActivity.Activation = DISABLE;
|
||||||
|
hmdf_filter[0].AcquisitionMode = MDF_MODE_ASYNC_CONT;
|
||||||
|
hmdf_filter[0].FifoThreshold = MDF_FIFO_THRESHOLD_NOT_EMPTY;
|
||||||
|
hmdf_filter[0].DiscardSamples = 0;
|
||||||
|
|
||||||
|
DMA_NodeConfTypeDef dma_ncfg;
|
||||||
|
|
||||||
|
dma_ncfg.NodeType = DMA_GPDMA_LINEAR_NODE;
|
||||||
|
dma_ncfg.Init.Mode = DMA_NORMAL;
|
||||||
|
dma_ncfg.Init.Request = OMV_MDF_FLT0_DMA_REQUEST;
|
||||||
|
dma_ncfg.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
|
||||||
|
dma_ncfg.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||||
|
dma_ncfg.Init.SrcInc = DMA_SINC_FIXED;
|
||||||
|
dma_ncfg.Init.DestInc = DMA_DINC_INCREMENTED;
|
||||||
|
dma_ncfg.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
|
||||||
|
dma_ncfg.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD;
|
||||||
|
dma_ncfg.Init.SrcBurstLength = 1;
|
||||||
|
dma_ncfg.Init.DestBurstLength = 1;
|
||||||
|
dma_ncfg.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT1;
|
||||||
|
dma_ncfg.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
|
||||||
|
|
||||||
|
dma_ncfg.SrcSecure = DMA_CHANNEL_SRC_SEC;
|
||||||
|
dma_ncfg.DestSecure = DMA_CHANNEL_DEST_SEC;
|
||||||
|
dma_ncfg.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
|
||||||
|
dma_ncfg.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
|
||||||
|
dma_ncfg.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
|
||||||
|
|
||||||
|
if (HAL_DMAEx_List_BuildNode(&dma_ncfg, &hdma_node) != HAL_OK ||
|
||||||
|
HAL_DMAEx_List_InsertNode(&hdma_queue, NULL, &hdma_node) != HAL_OK ||
|
||||||
|
HAL_DMAEx_List_SetCircularMode(&hdma_queue) != HAL_OK) {
|
||||||
|
RAISE_OS_EXCEPTION("MDF DMA init failed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
hdma_filter[0].Instance = OMV_MDF_FLT0_DMA_STREAM;
|
||||||
|
hdma_filter[0].InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
|
||||||
|
hdma_filter[0].InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
|
||||||
|
hdma_filter[0].InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
|
||||||
|
hdma_filter[0].InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
|
||||||
|
hdma_filter[0].InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
|
||||||
|
|
||||||
|
if (HAL_DMAEx_List_Init(&hdma_filter[0]) != HAL_OK ||
|
||||||
|
HAL_DMAEx_List_LinkQ(&hdma_filter[0], &hdma_queue) != HAL_OK) {
|
||||||
|
RAISE_OS_EXCEPTION("MDF DMA init failed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
__HAL_LINKDMA(&hmdf, hdma, hdma_filter[0]);
|
||||||
|
|
||||||
|
if (HAL_DMA_ConfigChannelAttributes(&hdma_filter[0],
|
||||||
|
DMA_CHANNEL_PRIV | DMA_CHANNEL_SEC |
|
||||||
|
DMA_CHANNEL_SRC_SEC | DMA_CHANNEL_DEST_SEC) != HAL_OK) {
|
||||||
|
RAISE_OS_EXCEPTION("MDF DMA init failed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set DMA IRQ handle
|
||||||
|
dma_utils_set_irq_descr(OMV_MDF_FLT0_DMA_STREAM, &hdma_filter[0]);
|
||||||
|
|
||||||
|
// Configure and enable MDF Filter 0 DMA IRQ.
|
||||||
|
NVIC_SetPriority(OMV_MDF_FLT0_IRQ, IRQ_PRI_DMA21);
|
||||||
|
HAL_NVIC_EnableIRQ(OMV_MDF_FLT0_IRQ);
|
||||||
|
|
||||||
|
NVIC_SetPriority(OMV_MDF_FLT0_DMA_IRQ, IRQ_PRI_DMA21);
|
||||||
|
HAL_NVIC_EnableIRQ(OMV_MDF_FLT0_DMA_IRQ);
|
||||||
#endif // defined(OMV_SAI)
|
#endif // defined(OMV_SAI)
|
||||||
|
|
||||||
// Allocate global PCM buffer.
|
// Allocate global PCM buffer.
|
||||||
@ -399,6 +512,15 @@ void py_audio_deinit() {
|
|||||||
HAL_DMA_DeInit(&hdma_sai_rx);
|
HAL_DMA_DeInit(&hdma_sai_rx);
|
||||||
hdma_sai_rx.Instance = NULL;
|
hdma_sai_rx.Instance = NULL;
|
||||||
}
|
}
|
||||||
|
#elif defined(OMV_MDF)
|
||||||
|
if (hmdf.Instance != NULL) {
|
||||||
|
HAL_MDF_AcqStop_DMA(&hmdf);
|
||||||
|
HAL_MDF_DeInit(&hmdf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable IRQs
|
||||||
|
HAL_NVIC_DisableIRQ(OMV_MDF_FLT0_IRQ);
|
||||||
|
HAL_NVIC_DisableIRQ(OMV_MDF_FLT0_DMA_IRQ);
|
||||||
#elif defined(OMV_DFSDM)
|
#elif defined(OMV_DFSDM)
|
||||||
if (hdma_filter[0].Instance != NULL) {
|
if (hdma_filter[0].Instance != NULL) {
|
||||||
HAL_DFSDM_FilterRegularStop_DMA(&hdfsdm_filter[0]);
|
HAL_DFSDM_FilterRegularStop_DMA(&hdfsdm_filter[0]);
|
||||||
@ -438,6 +560,10 @@ static void audio_task_callback(mp_sched_node_t *node) {
|
|||||||
for (int i = 0; i < g_channels; i++) {
|
for (int i = 0; i < g_channels; i++) {
|
||||||
PDM_Filter(&((uint8_t *) PDM_BUFFER)[i], &pcmbuf[i], &PDM_FilterHandler[i]);
|
PDM_Filter(&((uint8_t *) PDM_BUFFER)[i], &pcmbuf[i], &PDM_FilterHandler[i]);
|
||||||
}
|
}
|
||||||
|
#elif defined(OMV_MDF)
|
||||||
|
for (int i = 0; i < g_pdm_buffer_size / 2; i++) {
|
||||||
|
pcmbuf[i] = PDM_BUFFER[i] >> 16;
|
||||||
|
}
|
||||||
#elif defined(OMV_DFSDM)
|
#elif defined(OMV_DFSDM)
|
||||||
for (int i = 0; i < g_pdm_buffer_size / 2; i++) {
|
for (int i = 0; i < g_pdm_buffer_size / 2; i++) {
|
||||||
pcmbuf[i] = __SSAT_ASR((PDM_BUFFER[i] >> 8) * dfsdm_gain, 16, DFSDM_GAIN_FRAC_BITS);
|
pcmbuf[i] = __SSAT_ASR((PDM_BUFFER[i] >> 8) * dfsdm_gain, 16, DFSDM_GAIN_FRAC_BITS);
|
||||||
@ -453,6 +579,10 @@ static void audio_task_callback(mp_sched_node_t *node) {
|
|||||||
for (int i = 0; i < g_channels; i++) {
|
for (int i = 0; i < g_channels; i++) {
|
||||||
PDM_Filter(&((uint8_t *) PDM_BUFFER)[g_pdm_buffer_size / 2 + i], &pcmbuf[i], &PDM_FilterHandler[i]);
|
PDM_Filter(&((uint8_t *) PDM_BUFFER)[g_pdm_buffer_size / 2 + i], &pcmbuf[i], &PDM_FilterHandler[i]);
|
||||||
}
|
}
|
||||||
|
#elif defined(OMV_MDF)
|
||||||
|
for (int i = 0; i < g_pdm_buffer_size / 2; i++) {
|
||||||
|
pcmbuf[i] = PDM_BUFFER[g_pdm_buffer_size / 2 + i] >> 16;
|
||||||
|
}
|
||||||
#elif defined(OMV_DFSDM)
|
#elif defined(OMV_DFSDM)
|
||||||
for (int i = 0; i < g_pdm_buffer_size / 2; i++) {
|
for (int i = 0; i < g_pdm_buffer_size / 2; i++) {
|
||||||
pcmbuf[i] = __SSAT_ASR((PDM_BUFFER[g_pdm_buffer_size / 2 + i] >> 8) * dfsdm_gain, 16, DFSDM_GAIN_FRAC_BITS);
|
pcmbuf[i] = __SSAT_ASR((PDM_BUFFER[g_pdm_buffer_size / 2 + i] >> 8) * dfsdm_gain, 16, DFSDM_GAIN_FRAC_BITS);
|
||||||
@ -480,6 +610,15 @@ static mp_obj_t py_audio_start_streaming(mp_obj_t callback_obj) {
|
|||||||
MP_STATE_PORT(audio_callback) = mp_const_none;
|
MP_STATE_PORT(audio_callback) = mp_const_none;
|
||||||
RAISE_OS_EXCEPTION("SAI DMA transfer failed!");
|
RAISE_OS_EXCEPTION("SAI DMA transfer failed!");
|
||||||
}
|
}
|
||||||
|
#elif defined(OMV_MDF)
|
||||||
|
MDF_DmaConfigTypeDef dma_config = {
|
||||||
|
.Address = (uint32_t) PDM_BUFFER,
|
||||||
|
.DataLength = sizeof(PDM_BUFFER[0]) * g_pdm_buffer_size, // in bytes
|
||||||
|
.MsbOnly = DISABLE,
|
||||||
|
};
|
||||||
|
if (HAL_MDF_AcqStart_DMA(&hmdf, &hmdf_filter[0], &dma_config) != HAL_OK) {
|
||||||
|
RAISE_OS_EXCEPTION("MDF DMA transfer failed!");
|
||||||
|
}
|
||||||
#elif defined(OMV_DFSDM)
|
#elif defined(OMV_DFSDM)
|
||||||
// Start DMA transfer
|
// Start DMA transfer
|
||||||
if (HAL_DFSDM_FilterRegularStart_DMA(&hdfsdm_filter[0], PDM_BUFFER, g_pdm_buffer_size) != HAL_OK) {
|
if (HAL_DFSDM_FilterRegularStart_DMA(&hdfsdm_filter[0], PDM_BUFFER, g_pdm_buffer_size) != HAL_OK) {
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include "py/mphal.h"
|
#include "py/mphal.h"
|
||||||
#include "irq.h"
|
#include "irq.h"
|
||||||
#include "omv_boardconfig.h"
|
#include "omv_boardconfig.h"
|
||||||
@ -42,18 +43,48 @@
|
|||||||
#include "omv_csi.h"
|
#include "omv_csi.h"
|
||||||
#include "dma_utils.h"
|
#include "dma_utils.h"
|
||||||
|
|
||||||
#define MDMA_BUFFER_SIZE (64)
|
#if defined(DMA2)
|
||||||
#define DMA_MAX_XFER_SIZE (0xFFFFU * 4U)
|
#define USE_DMA (1)
|
||||||
#define DMA_LENGTH_ALIGNMENT (16)
|
#define DMA_MAX_TRANSFER (0xFFFFU * 4U)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
||||||
|
#define USE_MDMA (1)
|
||||||
|
#define MDMA_BUFFER_SIZE (64)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(DCMIPP)
|
||||||
|
#define USE_DCMI (1)
|
||||||
|
#define DCMI_IS_ACTIVE() (DCMI->CR & DCMI_CR_ENABLE)
|
||||||
|
#else
|
||||||
|
#define USE_DCMIPP (1)
|
||||||
|
// NOTE using PIPE1.
|
||||||
|
#define DCMI_IS_ACTIVE() (DCMIPP->P1FCTCR & DCMIPP_P1FCTCR_CPTREQ)
|
||||||
|
#define DCMIPP_PIPE (DCMIPP_PIPE1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LINE_WIDTH_ALIGNMENT (16)
|
||||||
|
|
||||||
extern uint8_t _line_buf;
|
extern uint8_t _line_buf;
|
||||||
extern uint32_t hal_get_exti_gpio(uint32_t line);
|
extern uint32_t hal_get_exti_gpio(uint32_t line);
|
||||||
|
|
||||||
|
#if USE_DCMI
|
||||||
void DCMI_IRQHandler(void) {
|
void DCMI_IRQHandler(void) {
|
||||||
HAL_DCMI_IRQHandler(&csi.dcmi);
|
HAL_DCMI_IRQHandler(&csi.dcmi);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
#if USE_DCMIPP
|
||||||
|
void CSI_IRQHandler(void) {
|
||||||
|
HAL_DCMIPP_CSI_IRQHandler(&csi.dcmi);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DCMIPP_IRQHandler(void) {
|
||||||
|
HAL_DCMIPP_IRQHandler(&csi.dcmi);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_MDMA
|
||||||
void omv_csi_mdma_irq_handler(void) {
|
void omv_csi_mdma_irq_handler(void) {
|
||||||
if (MDMA->GISR0 & (1 << OMV_MDMA_CHANNEL_DCMI_0)) {
|
if (MDMA->GISR0 & (1 << OMV_MDMA_CHANNEL_DCMI_0)) {
|
||||||
HAL_MDMA_IRQHandler(&csi.mdma0);
|
HAL_MDMA_IRQHandler(&csi.mdma0);
|
||||||
@ -64,6 +95,7 @@ void omv_csi_mdma_irq_handler(void) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if USE_DMA
|
||||||
static int omv_csi_dma_config() {
|
static int omv_csi_dma_config() {
|
||||||
// DMA Stream configuration
|
// DMA Stream configuration
|
||||||
csi.dma.Instance = DMA2_Stream1;
|
csi.dma.Instance = DMA2_Stream1;
|
||||||
@ -96,13 +128,14 @@ static int omv_csi_dma_config() {
|
|||||||
// Configure the DMA IRQ Channel
|
// Configure the DMA IRQ Channel
|
||||||
NVIC_SetPriority(DMA2_Stream1_IRQn, IRQ_PRI_DMA21);
|
NVIC_SetPriority(DMA2_Stream1_IRQn, IRQ_PRI_DMA21);
|
||||||
|
|
||||||
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
#if USE_MDMA
|
||||||
csi.mdma0.Instance = MDMA_CHAN_TO_INSTANCE(OMV_MDMA_CHANNEL_DCMI_0);
|
csi.mdma0.Instance = MDMA_CHAN_TO_INSTANCE(OMV_MDMA_CHANNEL_DCMI_0);
|
||||||
csi.mdma1.Instance = MDMA_CHAN_TO_INSTANCE(OMV_MDMA_CHANNEL_DCMI_1);
|
csi.mdma1.Instance = MDMA_CHAN_TO_INSTANCE(OMV_MDMA_CHANNEL_DCMI_1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void omv_csi_init0() {
|
void omv_csi_init0() {
|
||||||
omv_csi_abort(&csi, true, false);
|
omv_csi_abort(&csi, true, false);
|
||||||
@ -145,7 +178,6 @@ int omv_csi_init() {
|
|||||||
|
|
||||||
// Configure the csi external clock (XCLK).
|
// Configure the csi external clock (XCLK).
|
||||||
if (omv_csi_set_clk_frequency(OMV_CSI_CLK_FREQUENCY) != 0) {
|
if (omv_csi_set_clk_frequency(OMV_CSI_CLK_FREQUENCY) != 0) {
|
||||||
// Failed to initialize the csi clock.
|
|
||||||
return OMV_CSI_ERROR_TIM_INIT_FAILED;
|
return OMV_CSI_ERROR_TIM_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,26 +185,24 @@ int omv_csi_init() {
|
|||||||
for (uint32_t i = 0, n_buses = OMV_ARRAY_SIZE(buses); i < n_buses; i++) {
|
for (uint32_t i = 0, n_buses = OMV_ARRAY_SIZE(buses); i < n_buses; i++) {
|
||||||
uint32_t id = buses[i][0], speed = buses[i][1];
|
uint32_t id = buses[i][0], speed = buses[i][1];
|
||||||
if ((init_ret = omv_csi_probe_init(id, speed)) == 0) {
|
if ((init_ret = omv_csi_probe_init(id, speed)) == 0) {
|
||||||
// Sensor was detected on the current bus.
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
omv_i2c_deinit(&csi.i2c_bus);
|
omv_i2c_deinit(&csi.i2c_bus);
|
||||||
// Scan the next bus or fail if this is the last one.
|
// Scan the next bus or fail if this is the last one.
|
||||||
if ((i + 1) == n_buses) {
|
if ((i + 1) == n_buses) {
|
||||||
// Sensor probe/init failed.
|
|
||||||
return init_ret;
|
return init_ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the DCMI DMA Stream
|
// Configure the DCMI DMA Stream
|
||||||
|
#if USE_DMA
|
||||||
if (omv_csi_dma_config() != 0) {
|
if (omv_csi_dma_config() != 0) {
|
||||||
// DMA problem
|
|
||||||
return OMV_CSI_ERROR_DMA_INIT_FAILED;
|
return OMV_CSI_ERROR_DMA_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Configure the DCMI interface.
|
// Configure the DCMI interface.
|
||||||
if (omv_csi_config(OMV_CSI_CONFIG_INIT) != 0) {
|
if (omv_csi_config(OMV_CSI_CONFIG_INIT) != 0) {
|
||||||
// DCMI config failed
|
|
||||||
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +218,22 @@ int omv_csi_init() {
|
|||||||
|
|
||||||
int omv_csi_config(omv_csi_config_t config) {
|
int omv_csi_config(omv_csi_config_t config) {
|
||||||
if (config == OMV_CSI_CONFIG_INIT) {
|
if (config == OMV_CSI_CONFIG_INIT) {
|
||||||
// Configure DCMI.
|
// Configure DCMI/PP.
|
||||||
|
#if USE_DCMIPP
|
||||||
|
// Initialize the DCMIPP
|
||||||
|
csi.dcmi.Instance = DCMIPP;
|
||||||
|
if (HAL_DCMIPP_Init(&csi.dcmi) != HAL_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure and enable DCMI IRQ Channel
|
||||||
|
NVIC_SetPriority(DCMIPP_IRQn, IRQ_PRI_DCMI);
|
||||||
|
HAL_NVIC_EnableIRQ(DCMIPP_IRQn);
|
||||||
|
|
||||||
|
// Configure and enable CSI IRQ Channel
|
||||||
|
NVIC_SetPriority(CSI_IRQn, IRQ_PRI_DCMI);
|
||||||
|
HAL_NVIC_EnableIRQ(CSI_IRQn);
|
||||||
|
#else
|
||||||
csi.dcmi.Instance = DCMI;
|
csi.dcmi.Instance = DCMI;
|
||||||
csi.dcmi.Init.VSPolarity = csi.vsync_pol ? DCMI_VSPOLARITY_HIGH : DCMI_VSPOLARITY_LOW;
|
csi.dcmi.Init.VSPolarity = csi.vsync_pol ? DCMI_VSPOLARITY_HIGH : DCMI_VSPOLARITY_LOW;
|
||||||
csi.dcmi.Init.HSPolarity = csi.hsync_pol ? DCMI_HSPOLARITY_HIGH : DCMI_HSPOLARITY_LOW;
|
csi.dcmi.Init.HSPolarity = csi.hsync_pol ? DCMI_HSPOLARITY_HIGH : DCMI_HSPOLARITY_LOW;
|
||||||
@ -197,10 +242,6 @@ int omv_csi_config(omv_csi_config_t config) {
|
|||||||
csi.dcmi.Init.CaptureRate = DCMI_CR_ALL_FRAME;
|
csi.dcmi.Init.CaptureRate = DCMI_CR_ALL_FRAME;
|
||||||
csi.dcmi.Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B;
|
csi.dcmi.Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B;
|
||||||
csi.dcmi.Init.JPEGMode = DCMI_JPEG_DISABLE;
|
csi.dcmi.Init.JPEGMode = DCMI_JPEG_DISABLE;
|
||||||
#if defined(STM32F7) || defined(STM32H7)
|
|
||||||
csi.dcmi.Init.ByteSelectMode = DCMI_BSM_ALL;
|
|
||||||
csi.dcmi.Init.LineSelectMode = DCMI_LSM_ALL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Link the DMA handle to the DCMI handle
|
// Link the DMA handle to the DCMI handle
|
||||||
__HAL_LINKDMA(&csi.dcmi, DMA_Handle, csi.dma);
|
__HAL_LINKDMA(&csi.dcmi, DMA_Handle, csi.dma);
|
||||||
@ -214,26 +255,153 @@ int omv_csi_config(omv_csi_config_t config) {
|
|||||||
// Configure and enable DCMI IRQ Channel
|
// Configure and enable DCMI IRQ Channel
|
||||||
NVIC_SetPriority(DCMI_IRQn, IRQ_PRI_DCMI);
|
NVIC_SetPriority(DCMI_IRQn, IRQ_PRI_DCMI);
|
||||||
HAL_NVIC_EnableIRQ(DCMI_IRQn);
|
HAL_NVIC_EnableIRQ(DCMI_IRQn);
|
||||||
|
#endif
|
||||||
} else if (config == OMV_CSI_CONFIG_PIXFORMAT) {
|
} else if (config == OMV_CSI_CONFIG_PIXFORMAT) {
|
||||||
|
#if USE_DCMI
|
||||||
DCMI->CR &= ~(DCMI_CR_JPEG_Msk << DCMI_CR_JPEG_Pos);
|
DCMI->CR &= ~(DCMI_CR_JPEG_Msk << DCMI_CR_JPEG_Pos);
|
||||||
DCMI->CR |= (csi.pixformat == PIXFORMAT_JPEG) ? DCMI_JPEG_ENABLE : DCMI_JPEG_DISABLE;
|
DCMI->CR |= (csi.pixformat == PIXFORMAT_JPEG) ? DCMI_JPEG_ENABLE : DCMI_JPEG_DISABLE;
|
||||||
|
#else
|
||||||
|
// Select and configure the DCMIPP source.
|
||||||
|
if (csi.mipi_if) {
|
||||||
|
DCMIPP_CSI_ConfTypeDef scfg = {
|
||||||
|
.NumberOfLanes = DCMIPP_CSI_TWO_DATA_LANES,
|
||||||
|
.DataLaneMapping = DCMIPP_CSI_PHYSICAL_DATA_LANES,
|
||||||
|
.PHYBitrate = (csi.mipi_brate == 850) ? DCMIPP_CSI_PHY_BT_850 : DCMIPP_CSI_PHY_BT_1200,
|
||||||
|
};
|
||||||
|
if (HAL_DCMIPP_CSI_SetConfig(&csi.dcmi, &scfg) != HAL_OK) {
|
||||||
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
|
}
|
||||||
|
// Configure CSI virtual channel and pipe.
|
||||||
|
DCMIPP_CSI_PIPE_ConfTypeDef pcfg = {
|
||||||
|
.DataTypeMode = DCMIPP_DTMODE_DTIDA,
|
||||||
|
.DataTypeIDA = DCMIPP_DT_RAW10,
|
||||||
|
.DataTypeIDB = DCMIPP_DT_RAW10,
|
||||||
|
};
|
||||||
|
if (HAL_DCMIPP_CSI_SetVCConfig(&csi.dcmi, DCMIPP_VIRTUAL_CHANNEL0,
|
||||||
|
DCMIPP_CSI_DT_BPP10) != HAL_OK) {
|
||||||
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
|
}
|
||||||
|
if (HAL_DCMIPP_CSI_PIPE_SetConfig(&csi.dcmi, DCMIPP_PIPE, &pcfg) != HAL_OK) {
|
||||||
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DCMIPP_ParallelConfTypeDef scfg = {
|
||||||
|
.SynchroMode = DCMIPP_SYNCHRO_HARDWARE,
|
||||||
|
.ExtendedDataMode = DCMIPP_INTERFACE_8BITS,
|
||||||
|
.VSPolarity = csi.vsync_pol ? DCMIPP_VSPOLARITY_HIGH : DCMIPP_VSPOLARITY_LOW,
|
||||||
|
.HSPolarity = csi.hsync_pol ? DCMIPP_HSPOLARITY_HIGH : DCMIPP_HSPOLARITY_LOW,
|
||||||
|
.PCKPolarity = csi.pixck_pol ? DCMIPP_PCKPOLARITY_RISING : DCMIPP_PCKPOLARITY_FALLING,
|
||||||
|
};
|
||||||
|
if (csi.raw_output) {
|
||||||
|
scfg.Format = DCMIPP_FORMAT_RAW8;
|
||||||
|
} else if (csi.pixformat == PIXFORMAT_RGB565) {
|
||||||
|
scfg.Format = DCMIPP_FORMAT_RGB565;
|
||||||
|
scfg.SwapCycles = DCMIPP_SWAPCYCLES_ENABLE;
|
||||||
|
} else if (csi.pixformat == PIXFORMAT_GRAYSCALE) {
|
||||||
|
scfg.Format = (csi.mono_bpp == 1) ? DCMIPP_FORMAT_MONOCHROME_8B : DCMIPP_FORMAT_YUV422;
|
||||||
|
} else {
|
||||||
|
return OMV_CSI_ERROR_PIXFORMAT_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
if (HAL_DCMIPP_PARALLEL_SetConfig(&csi.dcmi, &scfg) != HAL_OK) {
|
||||||
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the pixel processing pipeline.
|
||||||
|
DCMIPP_PipeConfTypeDef pcfg = { .FrameRate = DCMIPP_FRAME_RATE_ALL };
|
||||||
|
if (csi.pixformat == PIXFORMAT_RGB565) {
|
||||||
|
pcfg.PixelPackerFormat = DCMIPP_PIXEL_PACKER_FORMAT_RGB565_1;
|
||||||
|
} else if (csi.pixformat == PIXFORMAT_GRAYSCALE) {
|
||||||
|
pcfg.PixelPackerFormat = DCMIPP_PIXEL_PACKER_FORMAT_MONO_Y8_G8_1;
|
||||||
|
} else {
|
||||||
|
return OMV_CSI_ERROR_PIXFORMAT_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
if (HAL_DCMIPP_PIPE_SetConfig(&csi.dcmi, DCMIPP_PIPE, &pcfg) != HAL_OK) {
|
||||||
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap RGB enabled.
|
||||||
|
if (csi.yuv_swap) {
|
||||||
|
HAL_DCMIPP_PIPE_EnableYUVSwap(&csi.dcmi, DCMIPP_PIPE);
|
||||||
|
}
|
||||||
|
// Swap YUV if enabled.
|
||||||
|
if (csi.rgb_swap) {
|
||||||
|
HAL_DCMIPP_PIPE_EnableRedBlueSwap(&csi.dcmi, DCMIPP_PIPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure debayer.
|
||||||
|
if (csi.raw_output && csi.pixformat != PIXFORMAT_BAYER) {
|
||||||
|
|
||||||
|
DCMIPP_RawBayer2RGBConfTypeDef rawcfg = {
|
||||||
|
.RawBayerType = DCMIPP_RAWBAYER_BGGR,
|
||||||
|
.VLineStrength = DCMIPP_RAWBAYER_ALGO_NONE,
|
||||||
|
.HLineStrength = DCMIPP_RAWBAYER_ALGO_NONE,
|
||||||
|
.PeakStrength = DCMIPP_RAWBAYER_ALGO_NONE,
|
||||||
|
.EdgeStrength = DCMIPP_RAWBAYER_ALGO_NONE,
|
||||||
|
};
|
||||||
|
if (HAL_DCMIPP_PIPE_SetISPRawBayer2RGBConfig(&csi.dcmi, DCMIPP_PIPE, &rawcfg) != HAL_OK ||
|
||||||
|
HAL_DCMIPP_PIPE_EnableISPRawBayer2RGB(&csi.dcmi, DCMIPP_PIPE) != HAL_OK) {
|
||||||
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
DCMIPP_ExposureConfTypeDef expcfg = {
|
||||||
|
.ShiftRed = 0,
|
||||||
|
.MultiplierRed = 128,
|
||||||
|
.ShiftGreen = 0,
|
||||||
|
.MultiplierGreen = 128,
|
||||||
|
.ShiftBlue = 0,
|
||||||
|
.MultiplierBlue = 128,
|
||||||
|
};
|
||||||
|
if (HAL_DCMIPP_PIPE_SetISPExposureConfig(&csi.dcmi, DCMIPP_PIPE, &expcfg) != HAL_OK ||
|
||||||
|
HAL_DCMIPP_PIPE_EnableISPExposure(&csi.dcmi, DCMIPP_PIPE) != HAL_OK) {
|
||||||
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t statsrc[] = {
|
||||||
|
DCMIPP_STAT_EXT_SOURCE_PRE_BLKLVL_R,
|
||||||
|
DCMIPP_STAT_EXT_SOURCE_PRE_BLKLVL_G,
|
||||||
|
DCMIPP_STAT_EXT_SOURCE_PRE_BLKLVL_B
|
||||||
|
};
|
||||||
|
DCMIPP_StatisticExtractionConfTypeDef statcfg[3];
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 3; i++) {
|
||||||
|
statcfg[i].Source = statsrc[i];
|
||||||
|
statcfg[i].Mode = DCMIPP_STAT_EXT_MODE_AVERAGE;
|
||||||
|
statcfg[i].Bins = DCMIPP_STAT_EXT_AVER_MODE_ALL_PIXELS; //NOEXT16;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = DCMIPP_STATEXT_MODULE1; i <= DCMIPP_STATEXT_MODULE3; i++) {
|
||||||
|
if (HAL_DCMIPP_PIPE_SetISPStatisticExtractionConfig(&csi.dcmi,
|
||||||
|
DCMIPP_PIPE, i,
|
||||||
|
&statcfg[i - DCMIPP_STATEXT_MODULE1]) != HAL_OK) {
|
||||||
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAL_DCMIPP_PIPE_EnableISPStatisticExtraction(&csi.dcmi, DCMIPP_PIPE, i) != HAL_OK) {
|
||||||
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the DCMI from generating more DMA requests, and disable the DMA.
|
// Stop the DCMI from generating more DMA requests, and disable the DMA.
|
||||||
int omv_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq) {
|
int omv_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq) {
|
||||||
if (DCMI->CR & DCMI_CR_ENABLE) {
|
if (DCMI_IS_ACTIVE()) {
|
||||||
|
#if USE_DCMI
|
||||||
DCMI->CR &= ~DCMI_CR_ENABLE;
|
DCMI->CR &= ~DCMI_CR_ENABLE;
|
||||||
|
#endif
|
||||||
|
#if USE_DMA
|
||||||
if (in_irq) {
|
if (in_irq) {
|
||||||
HAL_DMA_Abort_IT(&csi->dma);
|
HAL_DMA_Abort_IT(&csi->dma);
|
||||||
} else {
|
} else {
|
||||||
HAL_DMA_Abort(&csi->dma);
|
HAL_DMA_Abort(&csi->dma);
|
||||||
}
|
}
|
||||||
HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
|
HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
|
||||||
|
#endif
|
||||||
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
#if USE_MDMA
|
||||||
if (!in_irq) {
|
if (!in_irq) {
|
||||||
HAL_MDMA_Abort(&csi->mdma0);
|
HAL_MDMA_Abort(&csi->mdma0);
|
||||||
HAL_MDMA_Abort(&csi->mdma1);
|
HAL_MDMA_Abort(&csi->mdma1);
|
||||||
@ -241,10 +409,12 @@ int omv_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq) {
|
|||||||
HAL_MDMA_DeInit(&csi->mdma0);
|
HAL_MDMA_DeInit(&csi->mdma0);
|
||||||
HAL_MDMA_DeInit(&csi->mdma1);
|
HAL_MDMA_DeInit(&csi->mdma1);
|
||||||
#endif
|
#endif
|
||||||
|
#if USE_DCMI
|
||||||
__HAL_DCMI_DISABLE_IT(&csi->dcmi, DCMI_IT_FRAME);
|
__HAL_DCMI_DISABLE_IT(&csi->dcmi, DCMI_IT_FRAME);
|
||||||
__HAL_DCMI_CLEAR_FLAG(&csi->dcmi, DCMI_FLAG_FRAMERI);
|
__HAL_DCMI_CLEAR_FLAG(&csi->dcmi, DCMI_FLAG_FRAMERI);
|
||||||
|
#else
|
||||||
|
HAL_DCMIPP_PIPE_Stop(&csi->dcmi, DCMIPP_PIPE);
|
||||||
|
#endif
|
||||||
csi->first_line = false;
|
csi->first_line = false;
|
||||||
csi->drop_frame = false;
|
csi->drop_frame = false;
|
||||||
csi->last_frame_ms = 0;
|
csi->last_frame_ms = 0;
|
||||||
@ -341,8 +511,10 @@ int omv_csi_shutdown(int enable) {
|
|||||||
omv_gpio_write(OMV_CSI_POWER_PIN, 0);
|
omv_gpio_write(OMV_CSI_POWER_PIN, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#if USE_DCMI
|
||||||
HAL_NVIC_DisableIRQ(DCMI_IRQn);
|
HAL_NVIC_DisableIRQ(DCMI_IRQn);
|
||||||
HAL_DCMI_DeInit(&csi.dcmi);
|
HAL_DCMI_DeInit(&csi.dcmi);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#if defined(OMV_CSI_POWER_PIN)
|
#if defined(OMV_CSI_POWER_PIN)
|
||||||
if (csi.power_pol == OMV_CSI_ACTIVE_HIGH) {
|
if (csi.power_pol == OMV_CSI_ACTIVE_HIGH) {
|
||||||
@ -379,6 +551,7 @@ int omv_csi_set_vsync_callback(vsync_cb_t vsync_cb) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if USE_DCMI
|
||||||
// If the image is cropped by more than 1 word in width, align the line start to a word
|
// If the image is cropped by more than 1 word in width, align the line start to a word
|
||||||
// address to improve copy performance. Do not crop by more than 1 word as this will
|
// address to improve copy performance. Do not crop by more than 1 word as this will
|
||||||
// result in less time between DMA transfers complete interrupts on 16-byte boundaries.
|
// result in less time between DMA transfers complete interrupts on 16-byte boundaries.
|
||||||
@ -394,11 +567,15 @@ static uint32_t get_dcmi_hw_crop(uint32_t bytes_per_pixel) {
|
|||||||
|
|
||||||
return x_crop;
|
return x_crop;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_DCMI
|
||||||
void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi) {
|
void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi) {
|
||||||
|
#else
|
||||||
|
void HAL_DCMIPP_PIPE_FrameEventCallback(DCMIPP_HandleTypeDef *dcmipp, uint32_t pipe) {
|
||||||
|
#endif
|
||||||
framebuffer_t *fb = csi.fb;
|
framebuffer_t *fb = csi.fb;
|
||||||
|
#if USE_MDMA
|
||||||
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
|
||||||
// Clear out any stale flags.
|
// Clear out any stale flags.
|
||||||
DMA2->LIFCR = DMA_FLAG_TCIF1_5 | DMA_FLAG_HTIF1_5;
|
DMA2->LIFCR = DMA_FLAG_TCIF1_5 | DMA_FLAG_HTIF1_5;
|
||||||
// Re-enable the DMA IRQ to catch the next start line.
|
// Re-enable the DMA IRQ to catch the next start line.
|
||||||
@ -422,31 +599,23 @@ void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi) {
|
|||||||
if (csi.frame_callback) {
|
if (csi.frame_callback) {
|
||||||
csi.frame_callback();
|
csi.frame_callback();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
#if USE_DCMIPP
|
||||||
int omv_csi_dma_memcpy(void *dma, void *dst, void *src, int bpp, bool transposed) {
|
// Get the destination buffer address.
|
||||||
framebuffer_t *fb = csi.fb;
|
vbuffer_t *buffer = framebuffer_get_tail(fb, FB_PEEK);
|
||||||
MDMA_HandleTypeDef *handle = dma;
|
if (buffer == NULL) {
|
||||||
|
if (!csi.mipi_if) {
|
||||||
// Drop the frame if MDMA is not keeping up as the image will be corrupted.
|
HAL_DCMIPP_PIPE_Stop(dcmipp, pipe);
|
||||||
if (handle->Instance->CCR & MDMA_CCR_EN) {
|
} else {
|
||||||
csi.drop_frame = true;
|
HAL_DCMIPP_CSI_PIPE_Stop(dcmipp, pipe, DCMIPP_VIRTUAL_CHANNEL0);
|
||||||
return 0;
|
}
|
||||||
|
} else {
|
||||||
|
HAL_DCMIPP_PIPE_SetMemoryAddress(dcmipp, pipe, DCMIPP_MEMORY_ADDRESS_0, (uint32_t) buffer->data);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
// If MDMA is still running, HAL_MDMA_Start() will start a new transfer.
|
|
||||||
__HAL_UNLOCK(handle);
|
|
||||||
handle->State = HAL_MDMA_STATE_READY;
|
|
||||||
HAL_MDMA_Start(handle,
|
|
||||||
(uint32_t) src,
|
|
||||||
(uint32_t) dst,
|
|
||||||
transposed ? bpp : (fb->u * bpp),
|
|
||||||
transposed ? fb->u : 1);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
#if USE_DCMI
|
||||||
// This function is called after each line transfer is complete, with a pointer to the
|
// This function is called after each line transfer is complete, with a pointer to the
|
||||||
// buffer that was used. At this point, the DMA transfers the next line to the next buffer.
|
// buffer that was used. At this point, the DMA transfers the next line to the next buffer.
|
||||||
// Using line buffers allows performing post-processing before writing the frame to the
|
// Using line buffers allows performing post-processing before writing the frame to the
|
||||||
@ -458,7 +627,7 @@ void DCMI_DMAConvCpltUser(uint32_t addr) {
|
|||||||
omv_csi_throttle_framerate();
|
omv_csi_throttle_framerate();
|
||||||
|
|
||||||
if (csi.drop_frame) {
|
if (csi.drop_frame) {
|
||||||
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
#if USE_MDMA
|
||||||
if (!csi.transpose) {
|
if (!csi.transpose) {
|
||||||
HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
|
HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
|
||||||
}
|
}
|
||||||
@ -493,7 +662,7 @@ void DCMI_DMAConvCpltUser(uint32_t addr) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
#if USE_MDMA
|
||||||
// DCMI_DMAConvCpltUser is called with the other MAR register.
|
// DCMI_DMAConvCpltUser is called with the other MAR register.
|
||||||
// So, we have to fix the address in full MDMA offload mode.
|
// So, we have to fix the address in full MDMA offload mode.
|
||||||
if (!csi.transpose) {
|
if (!csi.transpose) {
|
||||||
@ -510,7 +679,7 @@ void DCMI_DMAConvCpltUser(uint32_t addr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For all non-JPEG and non-transposed modes image capture can be completely offload to MDMA.
|
// For all non-JPEG and non-transposed modes image capture can be completely offload to MDMA.
|
||||||
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
#if USE_MDMA
|
||||||
if (!csi.transpose) {
|
if (!csi.transpose) {
|
||||||
// NOTE: MDMA is started here, not in FRAME/VSYNC callbacks, to maximize the time before
|
// NOTE: MDMA is started here, not in FRAME/VSYNC callbacks, to maximize the time before
|
||||||
// the frame has to be dropped.
|
// the frame has to be dropped.
|
||||||
@ -536,17 +705,18 @@ void DCMI_DMAConvCpltUser(uint32_t addr) {
|
|||||||
dst += bytes_per_pixel * buffer->offset++;
|
dst += bytes_per_pixel * buffer->offset++;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
#if USE_MDMA
|
||||||
// Two MDMA channels are used to maximize the time available for each channel to finish the transfer.
|
// Two MDMA channels are used to maximize the time available for each channel to finish the transfer.
|
||||||
omv_csi_copy_line((buffer->offset % 2) ? &csi.mdma1 : &csi.mdma0, src, dst);
|
omv_csi_copy_line((buffer->offset % 2) ? &csi.mdma1 : &csi.mdma0, src, dst);
|
||||||
#else
|
#else
|
||||||
omv_csi_copy_line(NULL, src, dst);
|
omv_csi_copy_line(NULL, src, dst);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
#if USE_MDMA
|
||||||
// Configures an MDMA channel to completely offload the CPU in copying one line of pixels.
|
// Configures an MDMA channel to completely offload the CPU in copying one line of pixels.
|
||||||
static void mdma_config(MDMA_InitTypeDef *init, omv_csi_t *csi, uint32_t bytes_per_pixel) {
|
static void omv_csi_mdma_config(omv_csi_t *csi, MDMA_InitTypeDef *init, uint32_t bytes_per_pixel) {
|
||||||
framebuffer_t *fb = csi->fb;
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
init->Request = MDMA_REQUEST_SW;
|
init->Request = MDMA_REQUEST_SW;
|
||||||
@ -618,6 +788,97 @@ static void mdma_config(MDMA_InitTypeDef *init, omv_csi_t *csi, uint32_t bytes_p
|
|||||||
init->SourceDataSize = MDMA_SRC_DATASIZE_BYTE;
|
init->SourceDataSize = MDMA_SRC_DATASIZE_BYTE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void omv_csi_mdma_enable(omv_csi_t *csi, uint32_t bytes_per_pixel) {
|
||||||
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
|
omv_csi_mdma_config(csi, &csi->mdma0.Init, bytes_per_pixel);
|
||||||
|
memcpy(&csi->mdma1.Init, &csi->mdma0.Init, sizeof(MDMA_InitTypeDef));
|
||||||
|
HAL_MDMA_Init(&csi->mdma0);
|
||||||
|
|
||||||
|
// If we are not transposing the image we can fully offload image capture from the CPU.
|
||||||
|
if (!csi->transpose) {
|
||||||
|
// MDMA will trigger on each TC from DMA and transfer one line to the frame buffer.
|
||||||
|
csi->mdma1.Init.Request = MDMA_REQUEST_DMA2_Stream1_TC;
|
||||||
|
csi->mdma1.Init.TransferTriggerMode = MDMA_BLOCK_TRANSFER;
|
||||||
|
// We setup MDMA to repeatedly reset itself to transfer the same line buffer.
|
||||||
|
csi->mdma1.Init.SourceBlockAddressOffset = -(fb->u * bytes_per_pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
HAL_MDMA_Init(&csi->mdma1);
|
||||||
|
if (!csi->transpose) {
|
||||||
|
HAL_MDMA_ConfigPostRequestMask(&csi->mdma1, (uint32_t) &DMA2->LIFCR, DMA_FLAG_TCIF1_5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_csi_dma_memcpy(void *dma, void *dst, void *src, int bpp, bool transposed) {
|
||||||
|
framebuffer_t *fb = csi.fb;
|
||||||
|
MDMA_HandleTypeDef *handle = dma;
|
||||||
|
|
||||||
|
// Drop the frame if MDMA is not keeping up as the image will be corrupted.
|
||||||
|
if (handle->Instance->CCR & MDMA_CCR_EN) {
|
||||||
|
csi.drop_frame = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If MDMA is still running, HAL_MDMA_Start() will start a new transfer.
|
||||||
|
__HAL_UNLOCK(handle);
|
||||||
|
handle->State = HAL_MDMA_STATE_READY;
|
||||||
|
HAL_MDMA_Start(handle,
|
||||||
|
(uint32_t) src,
|
||||||
|
(uint32_t) dst,
|
||||||
|
transposed ? bpp : (fb->u * bpp),
|
||||||
|
transposed ? fb->u : 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_DCMIPP
|
||||||
|
void omv_csi_update_awb(omv_csi_t *csi, uint32_t n_pixels) {
|
||||||
|
uint32_t avg[3];
|
||||||
|
uint32_t shift[3];
|
||||||
|
uint32_t multi[3];
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
// DCMIPP_STATEXT_MODULE1
|
||||||
|
HAL_DCMIPP_PIPE_GetISPAccumulatedStatisticsCounter(&csi->dcmi, DCMIPP_PIPE, i + 1, &avg[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Averages are collected from bayer components (4R 2G 4B).
|
||||||
|
avg[0] = OMV_MAX((avg[0] * 256 * 4) / n_pixels, 1);
|
||||||
|
avg[1] = OMV_MAX((avg[1] * 256 * 2) / n_pixels, 1);
|
||||||
|
avg[2] = OMV_MAX((avg[2] * 256 * 4) / n_pixels, 1);
|
||||||
|
|
||||||
|
// Compute global luminance
|
||||||
|
float luminance = avg[0] * 0.299 + avg[1] * 0.587 + avg[2] * 0.114;
|
||||||
|
//printf("Luminance: %f AVG_R: %lu, AVG_G: %lu, AVG_B: %lu\n", (double) luminance, avg[0], avg[1], avg[2]);
|
||||||
|
|
||||||
|
if (csi->ioctl) {
|
||||||
|
omv_csi_ioctl(OMV_CSI_IOCTL_UPDATE_AGC_AEC, fast_floorf(luminance));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate average and exposure factors for each channel (R, G, B)
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
shift[i] = 0;
|
||||||
|
multi[i] = roundf((luminance * 128.0f / avg[i]));
|
||||||
|
while (multi[i] >= 255.0f && shift[i] < 7) {
|
||||||
|
multi[i] /= 2;
|
||||||
|
shift[i]++;
|
||||||
|
}
|
||||||
|
//printf("Channel %d: Expf: %lu Shift: %lu, Multi: %lu\n", i, expf, shift[i], multi[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure RGB exposure settings.
|
||||||
|
DCMIPP_ExposureConfTypeDef expcfg = {
|
||||||
|
.ShiftRed = shift[0],
|
||||||
|
.MultiplierRed = multi[0],
|
||||||
|
.ShiftGreen = shift[1],
|
||||||
|
.MultiplierGreen = multi[1],
|
||||||
|
.ShiftBlue = shift[2],
|
||||||
|
.MultiplierBlue = multi[2],
|
||||||
|
};
|
||||||
|
HAL_DCMIPP_PIPE_SetISPExposureConfig(&csi->dcmi, DCMIPP_PIPE, &expcfg);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This is the default snapshot function, which can be replaced in omv_csi_init functions.
|
// This is the default snapshot function, which can be replaced in omv_csi_init functions.
|
||||||
@ -625,6 +886,14 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
uint32_t length = 0;
|
uint32_t length = 0;
|
||||||
framebuffer_t *fb = csi->fb;
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
|
if (csi->pixformat == PIXFORMAT_INVALID) {
|
||||||
|
return OMV_CSI_ERROR_INVALID_PIXFORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (csi->framesize == OMV_CSI_FRAMESIZE_INVALID) {
|
||||||
|
return OMV_CSI_ERROR_INVALID_FRAMESIZE;
|
||||||
|
}
|
||||||
|
|
||||||
// Compress the framebuffer for the IDE preview, if not the first frame, the
|
// Compress the framebuffer for the IDE preview, if not the first frame, the
|
||||||
// framebuffer is enabled, and the image sensor doesn't support JPEG encoding.
|
// framebuffer is enabled, and the image sensor doesn't support JPEG encoding.
|
||||||
framebuffer_update_jpeg_buffer(fb);
|
framebuffer_update_jpeg_buffer(fb);
|
||||||
@ -638,83 +907,59 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
uint32_t w = fb->u;
|
uint32_t w = fb->u;
|
||||||
uint32_t h = fb->v;
|
uint32_t h = fb->v;
|
||||||
|
|
||||||
|
// TODO
|
||||||
// If DCMI_DMAConvCpltUser() happens before framebuffer_free_current_buffer(); below then the
|
// If DCMI_DMAConvCpltUser() happens before framebuffer_free_current_buffer(); below then the
|
||||||
// transfer is stopped and it will be re-enabled again right afterwards in the single vbuffer
|
// transfer is stopped and it will be re-enabled again right afterwards in the single vbuffer
|
||||||
// case. We know the transfer was stopped by checking DCMI_CR_ENABLE.
|
// case.
|
||||||
framebuffer_free_current_buffer(fb);
|
framebuffer_free_current_buffer(fb);
|
||||||
|
|
||||||
// Configure and start the capture.
|
// Configure and start the capture.
|
||||||
if (!(DCMI->CR & DCMI_CR_ENABLE)) {
|
if (!DCMI_IS_ACTIVE()) {
|
||||||
framebuffer_setup_buffers(fb);
|
framebuffer_setup_buffers(fb);
|
||||||
|
|
||||||
// Setup the size and address of the transfer
|
|
||||||
uint32_t bytes_per_pixel = omv_csi_get_src_bpp();
|
|
||||||
|
|
||||||
// Error out if the pixformat is not set.
|
|
||||||
if (!bytes_per_pixel) {
|
|
||||||
return OMV_CSI_ERROR_INVALID_PIXFORMAT;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t x_crop = get_dcmi_hw_crop(bytes_per_pixel);
|
|
||||||
uint32_t dma_line_width_bytes = resolution[csi->framesize][0] * bytes_per_pixel;
|
|
||||||
|
|
||||||
// Shrink the captured pixel count by one word to allow cropping to fix alignment.
|
|
||||||
if (x_crop) {
|
|
||||||
dma_line_width_bytes -= sizeof(uint32_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
length = dma_line_width_bytes * h;
|
|
||||||
|
|
||||||
// Error out if the transfer size is not compatible with DMA transfer restrictions.
|
|
||||||
if ((!dma_line_width_bytes)
|
|
||||||
|| (dma_line_width_bytes % sizeof(uint32_t))
|
|
||||||
|| (dma_line_width_bytes > (OMV_LINE_BUF_SIZE / 2))
|
|
||||||
|| (!length)
|
|
||||||
|| (length % DMA_LENGTH_ALIGNMENT)) {
|
|
||||||
return OMV_CSI_ERROR_INVALID_FRAMESIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the destination buffer address.
|
// Get the destination buffer address.
|
||||||
vbuffer_t *buffer = framebuffer_get_tail(fb, FB_PEEK);
|
vbuffer_t *buffer = framebuffer_get_tail(fb, FB_PEEK);
|
||||||
|
if (buffer == NULL) {
|
||||||
if ((csi->pixformat == PIXFORMAT_JPEG) && (csi->jpg_format == 3) && (!buffer)) {
|
|
||||||
return OMV_CSI_ERROR_FRAMEBUFFER_ERROR;
|
return OMV_CSI_ERROR_FRAMEBUFFER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
#if USE_DCMI
|
||||||
// The code below will enable MDMA data transfer from the DCMI line buffer for non-JPEG modes.
|
// Setup the size and address of the transfer
|
||||||
if (csi->pixformat != PIXFORMAT_JPEG) {
|
uint32_t bytes_per_pixel = omv_csi_get_src_bpp();
|
||||||
mdma_config(&csi->mdma0.Init, csi, bytes_per_pixel);
|
uint32_t x_crop = get_dcmi_hw_crop(bytes_per_pixel);
|
||||||
memcpy(&csi->mdma1.Init, &csi->mdma0.Init, sizeof(MDMA_InitTypeDef));
|
uint32_t line_width_bytes = resolution[csi->framesize][0] * bytes_per_pixel;
|
||||||
HAL_MDMA_Init(&csi->mdma0);
|
|
||||||
|
|
||||||
// If we are not transposing the image we can fully offload image capture from the CPU.
|
// Shrink the captured pixel count by one word to allow cropping to fix alignment.
|
||||||
if (!csi->transpose) {
|
if (x_crop) {
|
||||||
// MDMA will trigger on each TC from DMA and transfer one line to the frame buffer.
|
line_width_bytes -= sizeof(uint32_t);
|
||||||
csi->mdma1.Init.Request = MDMA_REQUEST_DMA2_Stream1_TC;
|
}
|
||||||
csi->mdma1.Init.TransferTriggerMode = MDMA_BLOCK_TRANSFER;
|
|
||||||
// We setup MDMA to repeatedly reset itself to transfer the same line buffer.
|
length = line_width_bytes * h;
|
||||||
csi->mdma1.Init.SourceBlockAddressOffset = -(fb->u * bytes_per_pixel);
|
|
||||||
|
// Error out if the transfer size is not compatible with DMA transfer restrictions.
|
||||||
HAL_MDMA_Init(&csi->mdma1);
|
if ((!line_width_bytes) ||
|
||||||
HAL_MDMA_ConfigPostRequestMask(&csi->mdma1, (uint32_t) &DMA2->LIFCR, DMA_FLAG_TCIF1_5);
|
(line_width_bytes % sizeof(uint32_t)) ||
|
||||||
} else {
|
(line_width_bytes > (OMV_LINE_BUF_SIZE / 2)) ||
|
||||||
HAL_MDMA_Init(&csi->mdma1);
|
(!length) || (length % LINE_WIDTH_ALIGNMENT)) {
|
||||||
}
|
return OMV_CSI_ERROR_INVALID_FRAMESIZE;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
HAL_DCMI_DisableCrop(&csi->dcmi);
|
HAL_DCMI_DisableCrop(&csi->dcmi);
|
||||||
if (csi->pixformat != PIXFORMAT_JPEG) {
|
if (csi->pixformat != PIXFORMAT_JPEG) {
|
||||||
// Vertically crop the image. Horizontal cropping is done in software.
|
// Vertically crop the image. Horizontal cropping is done in software.
|
||||||
HAL_DCMI_ConfigCrop(&csi->dcmi, x_crop, fb->y, dma_line_width_bytes - 1, h - 1);
|
HAL_DCMI_ConfigCrop(&csi->dcmi, x_crop, fb->y, line_width_bytes - 1, h - 1);
|
||||||
HAL_DCMI_EnableCrop(&csi->dcmi);
|
HAL_DCMI_EnableCrop(&csi->dcmi);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the circular, current target, and double buffer mode flags which get set by the below calls.
|
#if USE_MDMA
|
||||||
((DMA_Stream_TypeDef *) csi->dma.Instance)->CR &= ~(DMA_SxCR_CIRC | DMA_SxCR_CT | DMA_SxCR_DBM);
|
// Enable MDMA transfer from the DCMI line buffer for non-JPEG modes.
|
||||||
|
if (csi->pixformat != PIXFORMAT_JPEG) {
|
||||||
|
omv_csi_mdma_enable(csi, bytes_per_pixel);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Enable the DMA IRQ before starting the transfer.
|
// Reset the DMA state and re-enable it.
|
||||||
|
((DMA_Stream_TypeDef *) csi->dma.Instance)->CR &= ~(DMA_SxCR_CIRC | DMA_SxCR_CT | DMA_SxCR_DBM);
|
||||||
HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
|
HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
|
||||||
|
|
||||||
// HAL_DCMI_Start_DMA and HAL_DCMI_Start_DMA_MB both perform circular transfers,
|
// HAL_DCMI_Start_DMA and HAL_DCMI_Start_DMA_MB both perform circular transfers,
|
||||||
@ -722,27 +967,66 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
if ((csi->pixformat == PIXFORMAT_JPEG) && (csi->jpg_format == 3)) {
|
if ((csi->pixformat == PIXFORMAT_JPEG) && (csi->jpg_format == 3)) {
|
||||||
// Start a one-shot transfer to the framebuffer, used only for JPEG mode 3.
|
// Start a one-shot transfer to the framebuffer, used only for JPEG mode 3.
|
||||||
uint32_t size = framebuffer_get_buffer_size(fb);
|
uint32_t size = framebuffer_get_buffer_size(fb);
|
||||||
length = IM_MIN(size, (DMA_MAX_XFER_SIZE * 2U));
|
length = IM_MIN(size, (DMA_MAX_TRANSFER * 2U));
|
||||||
HAL_DCMI_Start_DMA(&csi->dcmi, DCMI_MODE_SNAPSHOT,
|
HAL_DCMI_Start_DMA(&csi->dcmi, DCMI_MODE_SNAPSHOT,
|
||||||
(uint32_t) buffer->data, length / sizeof(uint32_t));
|
(uint32_t) buffer->data, length / sizeof(uint32_t));
|
||||||
// HAL_DCMI_Start_DMA splits bigger transfers.
|
// HAL_DCMI_Start_DMA splits bigger transfers.
|
||||||
if (length > DMA_MAX_XFER_SIZE) {
|
if (length > DMA_MAX_TRANSFER) {
|
||||||
length /= 2;
|
length /= 2;
|
||||||
}
|
}
|
||||||
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
#if USE_MDMA
|
||||||
} else if ((csi->pixformat != PIXFORMAT_JPEG) && (!csi->transpose)) {
|
} else if ((csi->pixformat != PIXFORMAT_JPEG) && (!csi->transpose)) {
|
||||||
// Start an MDMA transfer, which completely offloads the capture to MDMA.
|
// Start an MDMA transfer, which completely offloads the capture to MDMA.
|
||||||
// DMA to circular mode writing the same line over and over again.
|
// DMA to circular mode writing the same line over and over again.
|
||||||
((DMA_Stream_TypeDef *) csi->dma.Instance)->CR |= DMA_SxCR_CIRC;
|
((DMA_Stream_TypeDef *) csi->dma.Instance)->CR |= DMA_SxCR_CIRC;
|
||||||
// DCMI will transfer to same line and MDMA will move to final location.
|
// DCMI will transfer to same line and MDMA will move to final location.
|
||||||
HAL_DCMI_Start_DMA(&csi->dcmi, DCMI_MODE_CONTINUOUS,
|
HAL_DCMI_Start_DMA(&csi->dcmi, DCMI_MODE_CONTINUOUS,
|
||||||
(uint32_t) &_line_buf, dma_line_width_bytes / sizeof(uint32_t));
|
(uint32_t) &_line_buf, line_width_bytes / sizeof(uint32_t));
|
||||||
#endif
|
#endif // USE_MDMA
|
||||||
} else {
|
} else {
|
||||||
// Start a multibuffer (line by line) transfer.
|
// Start a multibuffer (line by line) transfer.
|
||||||
HAL_DCMI_Start_DMA_MB(&csi->dcmi, DCMI_MODE_CONTINUOUS,
|
HAL_DCMI_Start_DMA_MB(&csi->dcmi, DCMI_MODE_CONTINUOUS,
|
||||||
(uint32_t) &_line_buf, length / sizeof(uint32_t), h);
|
(uint32_t) &_line_buf, length / sizeof(uint32_t), h);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
uint32_t bytes_per_pixel = omv_csi_get_dst_bpp();
|
||||||
|
uint32_t line_width_bytes = fb->u * bytes_per_pixel;
|
||||||
|
|
||||||
|
if (!line_width_bytes ||
|
||||||
|
line_width_bytes % LINE_WIDTH_ALIGNMENT) {
|
||||||
|
return OMV_CSI_ERROR_INVALID_FRAMESIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure crop
|
||||||
|
DCMIPP_CropConfTypeDef ccfg = {
|
||||||
|
.HStart = fb->x,
|
||||||
|
.VStart = fb->y,
|
||||||
|
.HSize = fb->u,
|
||||||
|
.VSize = fb->v,
|
||||||
|
};
|
||||||
|
if (HAL_DCMIPP_PIPE_SetCropConfig(&csi->dcmi, DCMIPP_PIPE, &ccfg) != HAL_OK ||
|
||||||
|
HAL_DCMIPP_PIPE_EnableCrop(&csi->dcmi, DCMIPP_PIPE) != HAL_OK) {
|
||||||
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set output pitch
|
||||||
|
if (HAL_DCMIPP_PIPE_SetPitch(&csi->dcmi, DCMIPP_PIPE, line_width_bytes) != HAL_OK) {
|
||||||
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the DCMIPP
|
||||||
|
if (!csi->mipi_if) {
|
||||||
|
if (HAL_DCMIPP_PIPE_Start(&csi->dcmi, DCMIPP_PIPE, (uint32_t) buffer->data,
|
||||||
|
DCMIPP_MODE_CONTINUOUS) != HAL_OK) {
|
||||||
|
return OMV_CSI_ERROR_CAPTURE_FAILED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (HAL_DCMIPP_CSI_PIPE_Start(&csi->dcmi, DCMIPP_PIPE, DCMIPP_VIRTUAL_CHANNEL0,
|
||||||
|
(uint32_t) buffer->data, DCMIPP_MODE_CONTINUOUS) != HAL_OK) {
|
||||||
|
return OMV_CSI_ERROR_CAPTURE_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // USE_DCMI
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger the camera if FSYNC is enabled.
|
// Trigger the camera if FSYNC is enabled.
|
||||||
@ -752,14 +1036,16 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if USE_DCMI
|
||||||
// In JPEG mode, enable the end of frame interrupt.
|
// In JPEG mode, enable the end of frame interrupt.
|
||||||
if (DCMI->CR & DCMI_JPEG_ENABLE) {
|
if (DCMI->CR & DCMI_JPEG_ENABLE) {
|
||||||
__HAL_DCMI_ENABLE_IT(&csi->dcmi, DCMI_IT_FRAME);
|
__HAL_DCMI_ENABLE_IT(&csi->dcmi, DCMI_IT_FRAME);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
framebuffer_flags_t fb_flags = FB_NO_FLAGS;
|
framebuffer_flags_t fb_flags = FB_NO_FLAGS;
|
||||||
|
|
||||||
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
#if USE_MDMA
|
||||||
// csi->mdma0.State will be HAL_MDMA_STATE_RESET if the MDMA is not initialized.
|
// csi->mdma0.State will be HAL_MDMA_STATE_RESET if the MDMA is not initialized.
|
||||||
if (csi->mdma0.State != HAL_MDMA_STATE_RESET) {
|
if (csi->mdma0.State != HAL_MDMA_STATE_RESET) {
|
||||||
fb_flags = FB_INVALIDATE;
|
fb_flags = FB_INVALIDATE;
|
||||||
@ -772,21 +1058,21 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
__WFI();
|
__WFI();
|
||||||
if ((HAL_GetTick() - tick_start) > OMV_CSI_TIMEOUT_MS) {
|
if ((HAL_GetTick() - tick_start) > OMV_CSI_TIMEOUT_MS) {
|
||||||
omv_csi_abort(csi, true, false);
|
omv_csi_abort(csi, true, false);
|
||||||
|
|
||||||
#if defined(OMV_CSI_FSYNC_PIN)
|
#if defined(OMV_CSI_FSYNC_PIN)
|
||||||
if (csi->frame_sync) {
|
if (csi->frame_sync) {
|
||||||
omv_gpio_write(OMV_CSI_FSYNC_PIN, 0);
|
omv_gpio_write(OMV_CSI_FSYNC_PIN, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return OMV_CSI_ERROR_CAPTURE_TIMEOUT;
|
return OMV_CSI_ERROR_CAPTURE_TIMEOUT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if USE_DMA
|
||||||
// In JPEG 3 mode, the transfer must be aborted as it waits for data indefinitely.
|
// In JPEG 3 mode, the transfer must be aborted as it waits for data indefinitely.
|
||||||
if ((csi->pixformat == PIXFORMAT_JPEG) && (csi->jpg_format == 3)) {
|
if ((csi->pixformat == PIXFORMAT_JPEG) && (csi->jpg_format == 3)) {
|
||||||
omv_csi_abort(csi, true, false);
|
omv_csi_abort(csi, true, false);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// We're done receiving data.
|
// We're done receiving data.
|
||||||
#if defined(OMV_CSI_FSYNC_PIN)
|
#if defined(OMV_CSI_FSYNC_PIN)
|
||||||
@ -837,10 +1123,12 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
// Offset is the number of length-size transfers performed.
|
// Offset is the number of length-size transfers performed.
|
||||||
size = buffer->offset * length;
|
size = buffer->offset * length;
|
||||||
// The DMA counter holds the number of bytes per transfer.
|
// The DMA counter holds the number of bytes per transfer.
|
||||||
|
#if USE_DMA
|
||||||
if (__HAL_DMA_GET_COUNTER(&csi->dma)) {
|
if (__HAL_DMA_GET_COUNTER(&csi->dma)) {
|
||||||
// Add in the uncompleted transfer length.
|
// Add in the uncompleted transfer length.
|
||||||
size += ((length / sizeof(uint32_t)) - __HAL_DMA_GET_COUNTER(&csi->dma)) * sizeof(uint32_t);
|
size += ((length / sizeof(uint32_t)) - __HAL_DMA_GET_COUNTER(&csi->dma)) * sizeof(uint32_t);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
// Clean trailing data after 0xFFD9 at the end of the jpeg byte stream.
|
// Clean trailing data after 0xFFD9 at the end of the jpeg byte stream.
|
||||||
fb->pixfmt = PIXFORMAT_JPEG;
|
fb->pixfmt = PIXFORMAT_JPEG;
|
||||||
@ -853,5 +1141,10 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
|
|
||||||
// Set the user image.
|
// Set the user image.
|
||||||
framebuffer_init_image(fb, image);
|
framebuffer_init_image(fb, image);
|
||||||
|
#if USE_DCMIPP
|
||||||
|
if (csi->raw_output) {
|
||||||
|
omv_csi_update_awb(csi, w * h);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -34,11 +34,23 @@
|
|||||||
#include "omv_boardconfig.h"
|
#include "omv_boardconfig.h"
|
||||||
#include "omv_gpio.h"
|
#include "omv_gpio.h"
|
||||||
|
|
||||||
|
#if defined(STM32N6)
|
||||||
|
// EXTI lines 0 to 15 have single IRQs.
|
||||||
|
#define MAX_SINGLE_IRQ_LINE (16)
|
||||||
|
#else
|
||||||
|
// EXTI lines 0 to 4 have single IRQs.
|
||||||
|
#define MAX_SINGLE_IRQ_LINE (5)
|
||||||
|
#endif
|
||||||
|
|
||||||
static omv_gpio_irq_descr_t gpio_irq_descr_table[16] = {{0}};
|
static omv_gpio_irq_descr_t gpio_irq_descr_table[16] = {{0}};
|
||||||
|
|
||||||
// Returns the port number configured in EXTI_CR for this line.
|
// Returns the port number configured in EXTI_CR for this line.
|
||||||
static uint32_t omv_gpio_irq_get_gpio(uint32_t line) {
|
static uint32_t omv_gpio_irq_get_gpio(uint32_t line) {
|
||||||
|
#if defined(STM32N6)
|
||||||
|
return (EXTI->EXTICR[line >> 2] >> (8 * (line & 3))) & 0x0F;
|
||||||
|
#else
|
||||||
return (SYSCFG->EXTICR[line >> 2] >> (4 * (line & 3))) & 0x0F;
|
return (SYSCFG->EXTICR[line >> 2] >> (4 * (line & 3))) & 0x0F;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns pin number.
|
// Returns pin number.
|
||||||
@ -67,12 +79,48 @@ static uint32_t omv_gpio_irq_get_irqn(omv_gpio_t pin) {
|
|||||||
case 4:
|
case 4:
|
||||||
exti_irqn = EXTI4_IRQn;
|
exti_irqn = EXTI4_IRQn;
|
||||||
break;
|
break;
|
||||||
|
#if defined(STM32N6)
|
||||||
|
case 5:
|
||||||
|
exti_irqn = EXTI5_IRQn;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
exti_irqn = EXTI6_IRQn;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
exti_irqn = EXTI7_IRQn;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
exti_irqn = EXTI8_IRQn;
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
exti_irqn = EXTI9_IRQn;
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
exti_irqn = EXTI10_IRQn;
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
exti_irqn = EXTI11_IRQn;
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
exti_irqn = EXTI12_IRQn;
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
exti_irqn = EXTI13_IRQn;
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
exti_irqn = EXTI14_IRQn;
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
exti_irqn = EXTI15_IRQn;
|
||||||
|
break;
|
||||||
|
#else
|
||||||
case 5 ... 9:
|
case 5 ... 9:
|
||||||
exti_irqn = EXTI9_5_IRQn;
|
exti_irqn = EXTI9_5_IRQn;
|
||||||
break;
|
break;
|
||||||
case 10 ... 15:
|
case 10 ... 15:
|
||||||
exti_irqn = EXTI15_10_IRQn;
|
exti_irqn = EXTI15_10_IRQn;
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -87,8 +135,7 @@ static inline bool omv_gpio_irq_enabled(omv_gpio_irq_descr_t *gpio_irq_descr, ui
|
|||||||
}
|
}
|
||||||
|
|
||||||
void omv_gpio_irq_handler(uint32_t line) {
|
void omv_gpio_irq_handler(uint32_t line) {
|
||||||
if (line < 5) {
|
if (line < MAX_SINGLE_IRQ_LINE) {
|
||||||
// EXTI lines 0 to 4 have single IRQs.
|
|
||||||
omv_gpio_irq_descr_t *gpio_irq_descr = &gpio_irq_descr_table[line];
|
omv_gpio_irq_descr_t *gpio_irq_descr = &gpio_irq_descr_table[line];
|
||||||
if (omv_gpio_irq_enabled(gpio_irq_descr, line)) {
|
if (omv_gpio_irq_enabled(gpio_irq_descr, line)) {
|
||||||
__HAL_GPIO_EXTI_CLEAR_FLAG(1 << line);
|
__HAL_GPIO_EXTI_CLEAR_FLAG(1 << line);
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
// If an I2C handle is already defined in MicroPython, reuse that handle to allow
|
// If an I2C handle is already defined in MicroPython, reuse that handle to allow
|
||||||
// MicroPython to process I2C IRQs, otherwise define a new handle and handle IRQs here.
|
// MicroPython to process I2C IRQs, otherwise define a new handle and handle IRQs here.
|
||||||
#if defined(I2C1)
|
#if defined(I2C1)
|
||||||
#if defined(MICROPY_HW_I2C1_SCL)
|
#if MICROPY_PY_PYB_LEGACY && defined(MICROPY_HW_I2C1_SCL)
|
||||||
extern I2C_HandleTypeDef I2CHandle1;
|
extern I2C_HandleTypeDef I2CHandle1;
|
||||||
#else
|
#else
|
||||||
static I2C_HandleTypeDef I2CHandle1;
|
static I2C_HandleTypeDef I2CHandle1;
|
||||||
@ -53,7 +53,7 @@ void I2C1_ER_IRQHandler(void) {
|
|||||||
#endif // I2C1
|
#endif // I2C1
|
||||||
|
|
||||||
#if defined(I2C2)
|
#if defined(I2C2)
|
||||||
#if defined(MICROPY_HW_I2C2_SCL)
|
#if MICROPY_PY_PYB_LEGACY && defined(MICROPY_HW_I2C2_SCL)
|
||||||
extern I2C_HandleTypeDef I2CHandle2;
|
extern I2C_HandleTypeDef I2CHandle2;
|
||||||
#else
|
#else
|
||||||
static I2C_HandleTypeDef I2CHandle2;
|
static I2C_HandleTypeDef I2CHandle2;
|
||||||
@ -67,7 +67,7 @@ void I2C2_ER_IRQHandler(void) {
|
|||||||
#endif // I2C2
|
#endif // I2C2
|
||||||
|
|
||||||
#if defined(I2C3)
|
#if defined(I2C3)
|
||||||
#if defined(MICROPY_HW_I2C3_SCL)
|
#if MICROPY_PY_PYB_LEGACY && defined(MICROPY_HW_I2C3_SCL)
|
||||||
extern I2C_HandleTypeDef I2CHandle3;
|
extern I2C_HandleTypeDef I2CHandle3;
|
||||||
#else
|
#else
|
||||||
static I2C_HandleTypeDef I2CHandle3;
|
static I2C_HandleTypeDef I2CHandle3;
|
||||||
@ -81,7 +81,7 @@ void I2C3_ER_IRQHandler(void) {
|
|||||||
#endif // I2C3
|
#endif // I2C3
|
||||||
|
|
||||||
#if defined(I2C4)
|
#if defined(I2C4)
|
||||||
#if defined(MICROPY_HW_I2C4_SCL)
|
#if MICROPY_PY_PYB_LEGACY && defined(MICROPY_HW_I2C4_SCL)
|
||||||
extern I2C_HandleTypeDef I2CHandle4;
|
extern I2C_HandleTypeDef I2CHandle4;
|
||||||
#else
|
#else
|
||||||
static I2C_HandleTypeDef I2CHandle4;
|
static I2C_HandleTypeDef I2CHandle4;
|
||||||
@ -101,6 +101,8 @@ static const uint32_t omv_i2c_timing[OMV_I2C_SPEED_MAX] = {
|
|||||||
0x1090699B, 0x70330309, 0x50100103,
|
0x1090699B, 0x70330309, 0x50100103,
|
||||||
#elif defined(STM32H7)
|
#elif defined(STM32H7)
|
||||||
0x20D09DE7, 0x40900C22, 0x4030040B,
|
0x20D09DE7, 0x40900C22, 0x4030040B,
|
||||||
|
#elif defined(STM32N6)
|
||||||
|
0x10C0ECFF, 0x00602173, 0x00300B29,
|
||||||
#else
|
#else
|
||||||
#error "no I2C timings for this MCU"
|
#error "no I2C timings for this MCU"
|
||||||
#endif
|
#endif
|
||||||
@ -188,6 +190,9 @@ int omv_i2c_init(omv_i2c_t *i2c, uint32_t bus_id, uint32_t speed) {
|
|||||||
assert_param(speed != OMV_I2C_SPEED_FAST);
|
assert_param(speed != OMV_I2C_SPEED_FAST);
|
||||||
#else
|
#else
|
||||||
if (speed == OMV_I2C_SPEED_FAST) {
|
if (speed == OMV_I2C_SPEED_FAST) {
|
||||||
|
#if defined(STM32N6)
|
||||||
|
HAL_I2CEx_ConfigFastModePlus(i2c->inst, I2C_FASTMODEPLUS_ENABLE);
|
||||||
|
#else
|
||||||
// Enable FAST mode plus.
|
// Enable FAST mode plus.
|
||||||
switch (bus_id) {
|
switch (bus_id) {
|
||||||
#if defined(I2C_FASTMODEPLUS_I2C1)
|
#if defined(I2C_FASTMODEPLUS_I2C1)
|
||||||
@ -211,6 +216,7 @@ int omv_i2c_init(omv_i2c_t *i2c, uint32_t bus_id, uint32_t speed) {
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif // defined(STM32N6)
|
||||||
}
|
}
|
||||||
#endif // !defined(IS_I2C_FASTMODEPLUS)
|
#endif // !defined(IS_I2C_FASTMODEPLUS)
|
||||||
|
|
||||||
@ -301,7 +307,8 @@ int omv_i2c_scan(omv_i2c_t *i2c, uint8_t *list, uint8_t size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if defined(STM32H7)
|
|
||||||
|
#if defined(STM32H7) || defined(STM32N6)
|
||||||
// After a failed scan the bus can get stuck. Re-initializing the bus fixes
|
// After a failed scan the bus can get stuck. Re-initializing the bus fixes
|
||||||
// it, but it seems disabling and re-enabling the bus is all that's needed.
|
// it, but it seems disabling and re-enabling the bus is all that's needed.
|
||||||
if (idx == 0) {
|
if (idx == 0) {
|
||||||
|
@ -108,6 +108,17 @@ typedef I2C_HandleTypeDef *omv_i2c_dev_t;
|
|||||||
#define OMV_SPI_MAX_16BIT_XFER (65536U - 8U)
|
#define OMV_SPI_MAX_16BIT_XFER (65536U - 8U)
|
||||||
#define OMV_SPI_MAX_TIMEOUT (HAL_MAX_DELAY)
|
#define OMV_SPI_MAX_TIMEOUT (HAL_MAX_DELAY)
|
||||||
|
|
||||||
|
#if defined(STM32N6)
|
||||||
|
#define OMV_SPI_PORT_BITS \
|
||||||
|
struct { \
|
||||||
|
IRQn_Type irqn; \
|
||||||
|
SPI_HandleTypeDef *descr; \
|
||||||
|
DMA_QListTypeDef dma_queue_tx; \
|
||||||
|
DMA_QListTypeDef dma_queue_rx; \
|
||||||
|
DMA_HandleTypeDef dma_descr_tx; \
|
||||||
|
DMA_HandleTypeDef dma_descr_rx; \
|
||||||
|
};
|
||||||
|
#else
|
||||||
#define OMV_SPI_PORT_BITS \
|
#define OMV_SPI_PORT_BITS \
|
||||||
struct { \
|
struct { \
|
||||||
IRQn_Type irqn; \
|
IRQn_Type irqn; \
|
||||||
@ -115,9 +126,9 @@ typedef I2C_HandleTypeDef *omv_i2c_dev_t;
|
|||||||
DMA_HandleTypeDef dma_descr_tx; \
|
DMA_HandleTypeDef dma_descr_tx; \
|
||||||
DMA_HandleTypeDef dma_descr_rx; \
|
DMA_HandleTypeDef dma_descr_rx; \
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
// omv_csi_t port-specific fields.
|
// omv_csi_t port-specific fields.
|
||||||
#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
|
|
||||||
#if defined(STM32H7)
|
#if defined(STM32H7)
|
||||||
#define OMV_CSI_PORT_BITS_MDMA \
|
#define OMV_CSI_PORT_BITS_MDMA \
|
||||||
MDMA_HandleTypeDef mdma0; \
|
MDMA_HandleTypeDef mdma0; \
|
||||||
@ -125,6 +136,14 @@ typedef I2C_HandleTypeDef *omv_i2c_dev_t;
|
|||||||
#else
|
#else
|
||||||
#define OMV_CSI_PORT_BITS_MDMA
|
#define OMV_CSI_PORT_BITS_MDMA
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(STM32N6)
|
||||||
|
#define OMV_CSI_PORT_BITS \
|
||||||
|
struct { \
|
||||||
|
TIM_HandleTypeDef tim; \
|
||||||
|
DCMIPP_HandleTypeDef dcmi; \
|
||||||
|
};
|
||||||
|
#else
|
||||||
#define OMV_CSI_PORT_BITS \
|
#define OMV_CSI_PORT_BITS \
|
||||||
struct { \
|
struct { \
|
||||||
TIM_HandleTypeDef tim; \
|
TIM_HandleTypeDef tim; \
|
||||||
|
@ -28,16 +28,23 @@ MCU_SERIES := $(shell echo $(MCU) | cut -c6-7 | tr '[:upper:]' '[:lower:]')
|
|||||||
MCU_LOWER := $(shell echo $(MCU) | tr '[:upper:]' '[:lower:]')
|
MCU_LOWER := $(shell echo $(MCU) | tr '[:upper:]' '[:lower:]')
|
||||||
HAL_DIR := lib/stm32/$(MCU_SERIES)
|
HAL_DIR := lib/stm32/$(MCU_SERIES)
|
||||||
CMSIS_INC := st
|
CMSIS_INC := st
|
||||||
|
CUBE_DIR := $(TOOLS_DIR)/st/cubeprog/bin/
|
||||||
|
|
||||||
SIGN_TOOL = $(TOOLS_DIR)/st/cubeprog/bin/STM32MP_SigningTool_CLI
|
SIGN_TOOL = $(CUBE_DIR)STM32MP_SigningTool_CLI
|
||||||
PROG_TOOL = $(TOOLS_DIR)/st/cubeprog/bin/STM32_Programmer.sh
|
PROG_TOOL = $(CUBE_DIR)STM32_Programmer_CLI
|
||||||
STLDR_DIR = $(TOOLS_DIR)/st/cubeprog/bin/ExternalLoader/
|
STLDR_DIR = $(CUBE_DIR)ExternalLoader/
|
||||||
|
|
||||||
|
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),n6))
|
||||||
|
STEDGE_ARGS ?= --stedge-args "--target stm32n6"
|
||||||
|
STEDGE_DIR = tools/st/stedgeai
|
||||||
|
STEDGE_TOOLS = $(STEDGE_DIR)/stedgeai.stamp
|
||||||
|
endif
|
||||||
|
|
||||||
ROMFS_IMAGE := $(FW_DIR)/romfs.stamp
|
ROMFS_IMAGE := $(FW_DIR)/romfs.stamp
|
||||||
ROMFS_CONFIG := $(OMV_BOARD_CONFIG_DIR)/romfs.json
|
ROMFS_CONFIG := $(OMV_BOARD_CONFIG_DIR)/romfs.json
|
||||||
|
|
||||||
# Compiler Flags
|
# Compiler Flags
|
||||||
CFLAGS += -std=gnu99 \
|
CFLAGS += -std=gnu11 \
|
||||||
-Wall \
|
-Wall \
|
||||||
-Werror \
|
-Werror \
|
||||||
-Warray-bounds \
|
-Warray-bounds \
|
||||||
@ -76,6 +83,15 @@ LDFLAGS = -mthumb \
|
|||||||
-Wl,-T$(BUILD)/$(LDSCRIPT).lds \
|
-Wl,-T$(BUILD)/$(LDSCRIPT).lds \
|
||||||
-Wl,-Map=$(BUILD)/$(FIRMWARE).map
|
-Wl,-Map=$(BUILD)/$(FIRMWARE).map
|
||||||
|
|
||||||
|
LDSCRIPT_FLAGS += -I$(COMMON_DIR) \
|
||||||
|
-I$(OMV_BOARD_CONFIG_DIR)
|
||||||
|
|
||||||
|
ifneq ($(OMV_RAMFUNC_OBJS),)
|
||||||
|
LDSCRIPT_FLAGS += -DOMV_RAMFUNC_EXC="$(addprefix *,$(OMV_RAMFUNC_OBJS))"
|
||||||
|
LDSCRIPT_FLAGS += -DOMV_RAMFUNC_INC="$(foreach obj,$(OMV_RAMFUNC_OBJS),*$(obj)(.text.* .rodata.*);)"
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
OMV_CFLAGS += -I$(TOP_DIR)
|
OMV_CFLAGS += -I$(TOP_DIR)
|
||||||
OMV_CFLAGS += -I$(TOP_DIR)/modules
|
OMV_CFLAGS += -I$(TOP_DIR)/modules
|
||||||
OMV_CFLAGS += -I$(TOP_DIR)/$(LIBPDM_DIR)
|
OMV_CFLAGS += -I$(TOP_DIR)/$(LIBPDM_DIR)
|
||||||
@ -127,6 +143,7 @@ include common/common.mk
|
|||||||
include drivers/drivers.mk
|
include drivers/drivers.mk
|
||||||
include lib/imlib/imlib.mk
|
include lib/imlib/imlib.mk
|
||||||
include lib/tflm/tflm.mk
|
include lib/tflm/tflm.mk
|
||||||
|
include lib/stai/stai.mk
|
||||||
include ports/ports.mk
|
include ports/ports.mk
|
||||||
include common/micropy.mk
|
include common/micropy.mk
|
||||||
|
|
||||||
@ -176,6 +193,7 @@ MPY_FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/,\
|
|||||||
sdcard.o \
|
sdcard.o \
|
||||||
sdram.o \
|
sdram.o \
|
||||||
sdio.o \
|
sdio.o \
|
||||||
|
xspi.o \
|
||||||
vfs_rom_ioctl.o \
|
vfs_rom_ioctl.o \
|
||||||
fatfs_port.o \
|
fatfs_port.o \
|
||||||
extint.o \
|
extint.o \
|
||||||
@ -191,11 +209,6 @@ MPY_FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/,\
|
|||||||
usbdev/**/src/*.o \
|
usbdev/**/src/*.o \
|
||||||
)
|
)
|
||||||
|
|
||||||
# CubeAI objects
|
|
||||||
ifeq ($(CUBEAI), 1)
|
|
||||||
include $(TOP_DIR)/$(CUBEAI_DIR)/cube.mk
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Libraries
|
# Libraries
|
||||||
ifeq ($(MICROPY_PY_AUDIO), 1)
|
ifeq ($(MICROPY_PY_AUDIO), 1)
|
||||||
LIBS += $(TOP_DIR)/$(LIBPDM_DIR)/libPDMFilter_CM7_GCC_wc32.a
|
LIBS += $(TOP_DIR)/$(LIBPDM_DIR)/libPDMFilter_CM7_GCC_wc32.a
|
||||||
@ -209,6 +222,10 @@ ifeq ($(MICROPY_PY_ML_TFLM), 1)
|
|||||||
LIBS += $(TOP_DIR)/$(TENSORFLOW_DIR)/libtflm/lib/libtflm-$(CPU)+fp-release.a
|
LIBS += $(TOP_DIR)/$(TENSORFLOW_DIR)/libtflm/lib/libtflm-$(CPU)+fp-release.a
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CUBEAI), 1)
|
||||||
|
include $(TOP_DIR)/$(CUBEAI_DIR)/cube.mk
|
||||||
|
endif
|
||||||
|
|
||||||
###################################################
|
###################################################
|
||||||
all: $(ROMFS_IMAGE)
|
all: $(ROMFS_IMAGE)
|
||||||
ifeq ($(OMV_ENABLE_BL), 1)
|
ifeq ($(OMV_ENABLE_BL), 1)
|
||||||
@ -216,16 +233,18 @@ ifeq ($(OMV_ENABLE_BL), 1)
|
|||||||
endif
|
endif
|
||||||
$(SIZE) $(FW_DIR)/$(FIRMWARE).elf
|
$(SIZE) $(FW_DIR)/$(FIRMWARE).elf
|
||||||
|
|
||||||
|
$(STEDGE_TOOLS):
|
||||||
|
@bash -c "source tools/ci.sh && ci_install_stedgeai $(STEDGE_DIR)"
|
||||||
|
|
||||||
# This target builds MicroPython.
|
# This target builds MicroPython.
|
||||||
MICROPYTHON: | FIRM_DIRS
|
MICROPYTHON: $(STEDGE_TOOLS) | FIRM_DIRS
|
||||||
$(MAKE) -C $(MICROPY_DIR)/ports/$(PORT) BUILD=$(BUILD)/$(MICROPY_DIR) $(MPY_MKARGS)
|
$(MAKE) -C $(MICROPY_DIR)/ports/$(PORT) BUILD=$(BUILD)/$(MICROPY_DIR) $(MPY_MKARGS)
|
||||||
|
|
||||||
$(OMV_FIRM_OBJ): | MICROPYTHON
|
$(OMV_FIRM_OBJ): | MICROPYTHON
|
||||||
|
|
||||||
# This target builds the firmware.
|
# This target builds the firmware.
|
||||||
$(FIRMWARE): $(OMV_FIRM_OBJ)
|
$(FIRMWARE): $(OMV_FIRM_OBJ)
|
||||||
$(CPP) -P -E -I$(COMMON_DIR) -I$(OMV_BOARD_CONFIG_DIR) \
|
$(CPP) -P -E $(LDSCRIPT_FLAGS) ports/$(PORT)/$(LDSCRIPT).ld.S > $(BUILD)/$(LDSCRIPT).lds
|
||||||
ports/$(PORT)/$(LDSCRIPT).ld.S > $(BUILD)/$(LDSCRIPT).lds
|
|
||||||
$(CC) $(LDFLAGS) $(OMV_FIRM_OBJ) $(MPY_FIRM_OBJ) -o $(FW_DIR)/$(FIRMWARE).elf $(LIBS) -lm
|
$(CC) $(LDFLAGS) $(OMV_FIRM_OBJ) $(MPY_FIRM_OBJ) -o $(FW_DIR)/$(FIRMWARE).elf $(LIBS) -lm
|
||||||
$(OBJCOPY) -Obinary $(FW_DIR)/$(FIRMWARE).elf $(FW_DIR)/$(FIRMWARE).bin
|
$(OBJCOPY) -Obinary $(FW_DIR)/$(FIRMWARE).elf $(FW_DIR)/$(FIRMWARE).bin
|
||||||
$(PYTHON) $(MKDFU) -D $(DFU_DEVICE) \
|
$(PYTHON) $(MKDFU) -D $(DFU_DEVICE) \
|
||||||
@ -238,7 +257,7 @@ ifeq ($(OMV_ENABLE_BL), 1)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# This target builds the bootloader.
|
# This target builds the bootloader.
|
||||||
$(BOOTLOADER): | FIRM_DIRS
|
$(BOOTLOADER): $(STEDGE_TOOLS) | FIRM_DIRS
|
||||||
ifeq ($(OMV_ENABLE_BL), 1)
|
ifeq ($(OMV_ENABLE_BL), 1)
|
||||||
$(MAKE) -C $(TOP_DIR)/$(BOOT_DIR) BUILD=$(BUILD)/$(BOOT_DIR)
|
$(MAKE) -C $(TOP_DIR)/$(BOOT_DIR) BUILD=$(BUILD)/$(BOOT_DIR)
|
||||||
$(OBJCOPY) -Obinary $(FW_DIR)/$(BOOTLOADER).elf $(FW_DIR)/$(BOOTLOADER).bin
|
$(OBJCOPY) -Obinary $(FW_DIR)/$(BOOTLOADER).elf $(FW_DIR)/$(BOOTLOADER).bin
|
||||||
@ -254,8 +273,10 @@ endif
|
|||||||
$(ROMFS_IMAGE): $(ROMFS_CONFIG) | $(FIRMWARE) $(BOOTLOADER)
|
$(ROMFS_IMAGE): $(ROMFS_CONFIG) | $(FIRMWARE) $(BOOTLOADER)
|
||||||
$(ECHO) "GEN romfs image"
|
$(ECHO) "GEN romfs image"
|
||||||
$(PYTHON) $(TOOLS_DIR)/$(MKROMFS) \
|
$(PYTHON) $(TOOLS_DIR)/$(MKROMFS) \
|
||||||
--top-dir $(TOP_DIR) --out-dir $(FW_DIR) \
|
--top-dir $(TOP_DIR) \
|
||||||
--build-dir $(BUILD) --config $(ROMFS_CONFIG)
|
--out-dir $(FW_DIR) \
|
||||||
|
--build-dir $(BUILD)/lib/models \
|
||||||
|
$(STEDGE_ARGS) --config $(ROMFS_CONFIG)
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
# Flash the bootloader
|
# Flash the bootloader
|
||||||
@ -274,7 +295,7 @@ flash_boot_dfu_util::
|
|||||||
flash_image_dfu_util::
|
flash_image_dfu_util::
|
||||||
dfu-util -a 0 -d $(DFU_DEVICE) -D $(FW_DIR)/$(FIRMWARE).dfu
|
dfu-util -a 0 -d $(DFU_DEVICE) -D $(FW_DIR)/$(FIRMWARE).dfu
|
||||||
|
|
||||||
deploy: $(FIRMWARE)
|
deploy: $(ROMFS_IMAGE)
|
||||||
$(PROG_TOOL) -c port=SWD mode=HOTPLUG ap=1 \
|
$(PROG_TOOL) -c port=SWD mode=HOTPLUG ap=1 \
|
||||||
-el $(STLDR_DIR)/$(OMV_PROG_STLDR) -w $(FW_DIR)/openmv.bin $(OMV_FIRM_BASE) -hardRst
|
-el $(STLDR_DIR)/$(OMV_PROG_STLDR) -w $(FW_DIR)/openmv.bin $(OMV_FIRM_BASE) -hardRst
|
||||||
|
|
||||||
|
@ -92,18 +92,14 @@ DEFINE_SPI_INSTANCE(6)
|
|||||||
{ OMV_SPI##spi_number##_DMA_RX_CHANNEL, { OMV_SPI##spi_number##_DMA_RX_REQUEST } }; \
|
{ OMV_SPI##spi_number##_DMA_RX_CHANNEL, { OMV_SPI##spi_number##_DMA_RX_REQUEST } }; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
static omv_spi_t *omv_spi_descr_all[6] = { NULL };
|
static omv_spi_t *omv_spi_descr_all[6] = { NULL };
|
||||||
|
#if defined(STM32N6)
|
||||||
|
static DMA_NodeTypeDef OMV_ATTR_SECTION(OMV_ATTR_ALIGNED(omv_dma_nodes_all[6 * 2], 32), ".dma_buffer");
|
||||||
|
#endif
|
||||||
|
|
||||||
static uint32_t omv_spi_clocksource(SPI_TypeDef *spi) {
|
static uint32_t omv_spi_clocksource(SPI_TypeDef *spi) {
|
||||||
#if defined(STM32H7)
|
#if defined(STM32F4) || defined(STM32F7)
|
||||||
if (spi == SPI1 || spi == SPI2 || spi == SPI3) {
|
|
||||||
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI123);
|
|
||||||
} else if (spi == SPI4 || spi == SPI5) {
|
|
||||||
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI45);
|
|
||||||
} else {
|
|
||||||
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI6);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (spi == SPI2) {
|
if (spi == SPI2) {
|
||||||
// SPI2 is on APB1
|
// SPI2 is on APB1
|
||||||
return HAL_RCC_GetPCLK1Freq();
|
return HAL_RCC_GetPCLK1Freq();
|
||||||
@ -114,6 +110,28 @@ static uint32_t omv_spi_clocksource(SPI_TypeDef *spi) {
|
|||||||
// SPI1, SPI4, SPI5 and SPI6 are on APB2
|
// SPI1, SPI4, SPI5 and SPI6 are on APB2
|
||||||
return HAL_RCC_GetPCLK2Freq();
|
return HAL_RCC_GetPCLK2Freq();
|
||||||
}
|
}
|
||||||
|
#elif defined(STM32H7)
|
||||||
|
if (spi == SPI1 || spi == SPI2 || spi == SPI3) {
|
||||||
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI123);
|
||||||
|
} else if (spi == SPI4 || spi == SPI5) {
|
||||||
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI45);
|
||||||
|
} else {
|
||||||
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI6);
|
||||||
|
}
|
||||||
|
#elif defined(STM32N6)
|
||||||
|
if (spi == SPI1) {
|
||||||
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI1);
|
||||||
|
} else if (spi == SPI2) {
|
||||||
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI2);
|
||||||
|
} else if (spi == SPI3) {
|
||||||
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI3);
|
||||||
|
} else if (spi == SPI4) {
|
||||||
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI4);
|
||||||
|
} else if (spi == SPI5) {
|
||||||
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI5);
|
||||||
|
} else {
|
||||||
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI6);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,7 +201,7 @@ static void omv_spi_callback(SPI_HandleTypeDef *hspi) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (spi->callback) {
|
if (spi->callback) {
|
||||||
uint8_t *buf = spi->descr->pRxBuffPtr ? spi->descr->pRxBuffPtr : spi->descr->pTxBuffPtr;
|
uint8_t *buf = (uint8_t *) (spi->descr->pRxBuffPtr ? spi->descr->pRxBuffPtr : spi->descr->pTxBuffPtr);
|
||||||
if (spi->dma_flags & OMV_SPI_DMA_DOUBLE) {
|
if (spi->dma_flags & OMV_SPI_DMA_DOUBLE) {
|
||||||
if (spi->xfer_flags & OMV_SPI_XFER_HALF) {
|
if (spi->xfer_flags & OMV_SPI_XFER_HALF) {
|
||||||
uint32_t size = spi->descr->RxXferSize ? spi->descr->RxXferSize : spi->descr->TxXferSize;
|
uint32_t size = spi->descr->RxXferSize ? spi->descr->RxXferSize : spi->descr->TxXferSize;
|
||||||
@ -197,7 +215,7 @@ static void omv_spi_callback(SPI_HandleTypeDef *hspi) {
|
|||||||
|
|
||||||
int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) {
|
int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) {
|
||||||
// No TX transfers in circular or double buffer mode.
|
// No TX transfers in circular or double buffer mode.
|
||||||
if ((spi->dma_flags & (OMV_SPI_DMA_CIRCULAR | OMV_SPI_DMA_DOUBLE)) && xfer->txbuf) {
|
if (xfer->txbuf && (spi->dma_flags & (OMV_SPI_DMA_CIRCULAR | OMV_SPI_DMA_DOUBLE))) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,40 +288,104 @@ int omv_spi_transfer_abort(omv_spi_t *spi) {
|
|||||||
|
|
||||||
static int omv_spi_dma_init(omv_spi_t *spi, uint32_t direction, omv_spi_config_t *config) {
|
static int omv_spi_dma_init(omv_spi_t *spi, uint32_t direction, omv_spi_config_t *config) {
|
||||||
DMA_HandleTypeDef *dma_descr;
|
DMA_HandleTypeDef *dma_descr;
|
||||||
|
|
||||||
if (direction == DMA_MEMORY_TO_PERIPH) {
|
if (direction == DMA_MEMORY_TO_PERIPH) {
|
||||||
dma_descr = &spi->dma_descr_tx;
|
dma_descr = &spi->dma_descr_tx;
|
||||||
} else {
|
} else {
|
||||||
dma_descr = &spi->dma_descr_rx;
|
dma_descr = &spi->dma_descr_rx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DMA_InitTypeDef *dma_init = &dma_descr->Init;
|
||||||
|
#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
|
||||||
// Configure the SPI DMA steam.
|
// Configure the SPI DMA steam.
|
||||||
dma_descr->Init.Mode = (config->dma_flags & OMV_SPI_DMA_CIRCULAR) ? DMA_CIRCULAR : DMA_NORMAL;
|
dma_init->Mode = (config->dma_flags & OMV_SPI_DMA_CIRCULAR) ? DMA_CIRCULAR : DMA_NORMAL;
|
||||||
dma_descr->Init.Priority = DMA_PRIORITY_HIGH;
|
dma_init->Priority = DMA_PRIORITY_HIGH;
|
||||||
dma_descr->Init.Direction = direction;
|
dma_init->Direction = direction;
|
||||||
// When the DMA is configured in direct mode (the FIFO is disabled), the source and
|
// 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).
|
// 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).
|
// Additionally, burst transfers are not possible (MBURST and PBURST are both ignored).
|
||||||
dma_descr->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
dma_init->FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||||
dma_descr->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
|
dma_init->FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
|
||||||
// Note MBURST and PBURST are ignored.
|
// Note MBURST and PBURST are ignored.
|
||||||
dma_descr->Init.MemBurst = DMA_MBURST_SINGLE;
|
dma_init->MemBurst = DMA_MBURST_SINGLE;
|
||||||
dma_descr->Init.PeriphBurst = DMA_PBURST_SINGLE;
|
dma_init->PeriphBurst = DMA_PBURST_SINGLE;
|
||||||
dma_descr->Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
|
dma_init->MemDataAlignment = DMA_MDATAALIGN_WORD;
|
||||||
#if defined(STM32H7)
|
#if defined(STM32H7)
|
||||||
dma_descr->Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
|
dma_init->PeriphDataAlignment = DMA_PDATAALIGN_WORD;
|
||||||
#else
|
#else
|
||||||
dma_descr->Init.PeriphDataAlignment = (config->datasize == 8) ? DMA_PDATAALIGN_BYTE : DMA_PDATAALIGN_HALFWORD;
|
dma_init->PeriphDataAlignment = (config->datasize == 8) ? DMA_PDATAALIGN_BYTE : DMA_PDATAALIGN_HALFWORD;
|
||||||
#endif
|
#endif
|
||||||
dma_descr->Init.MemInc = DMA_MINC_ENABLE;
|
dma_init->MemInc = DMA_MINC_ENABLE;
|
||||||
dma_descr->Init.PeriphInc = DMA_PINC_DISABLE;
|
dma_init->PeriphInc = DMA_PINC_DISABLE;
|
||||||
|
|
||||||
// Initialize the DMA stream
|
// Initialize the DMA stream
|
||||||
HAL_DMA_DeInit(dma_descr);
|
HAL_DMA_DeInit(dma_descr);
|
||||||
if (HAL_DMA_Init(dma_descr) != HAL_OK) {
|
if (HAL_DMA_Init(dma_descr) != HAL_OK) {
|
||||||
// Initialization Error
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
#elif defined(STM32N6)
|
||||||
|
// Configure the SPI DMA steam.
|
||||||
|
dma_init->Mode = DMA_NORMAL;
|
||||||
|
dma_init->Priority = DMA_HIGH_PRIORITY;
|
||||||
|
dma_init->BlkHWRequest = DMA_BREQ_SINGLE_BURST;
|
||||||
|
dma_init->Direction = direction;
|
||||||
|
dma_init->SrcInc = (direction == DMA_PERIPH_TO_MEMORY) ? DMA_SINC_FIXED : DMA_SINC_INCREMENTED;
|
||||||
|
dma_init->DestInc = (direction == DMA_MEMORY_TO_PERIPH) ? DMA_DINC_FIXED : DMA_DINC_INCREMENTED;
|
||||||
|
dma_init->SrcDataWidth = (config->datasize == 8) ? DMA_SRC_DATAWIDTH_BYTE : DMA_SRC_DATAWIDTH_WORD;
|
||||||
|
dma_init->DestDataWidth = (config->datasize == 8) ? DMA_DEST_DATAWIDTH_BYTE : DMA_DEST_DATAWIDTH_WORD;
|
||||||
|
dma_init->SrcBurstLength = 1;
|
||||||
|
dma_init->DestBurstLength = 1;
|
||||||
|
dma_init->TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
|
||||||
|
dma_init->TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT1;
|
||||||
|
|
||||||
|
// Initialize the DMA stream
|
||||||
|
if (!(config->dma_flags & OMV_SPI_DMA_CIRCULAR)) {
|
||||||
|
HAL_DMA_DeInit(dma_descr);
|
||||||
|
if (HAL_DMA_Init(dma_descr) != HAL_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DMA_NodeTypeDef *dma_node;
|
||||||
|
DMA_QListTypeDef *dma_queue;
|
||||||
|
|
||||||
|
DMA_NodeConfTypeDef dma_ncfg = {
|
||||||
|
.Init = *dma_init,
|
||||||
|
.NodeType = DMA_GPDMA_LINEAR_NODE,
|
||||||
|
.SrcSecure = DMA_CHANNEL_SRC_SEC,
|
||||||
|
.DestSecure = DMA_CHANNEL_DEST_SEC,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (direction == DMA_MEMORY_TO_PERIPH) {
|
||||||
|
dma_queue = &spi->dma_queue_tx;
|
||||||
|
dma_node = &omv_dma_nodes_all[(spi->id - 1) * 2 + 0];
|
||||||
|
} else {
|
||||||
|
dma_queue = &spi->dma_queue_rx;
|
||||||
|
dma_node = &omv_dma_nodes_all[(spi->id - 1) * 2 + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAL_DMAEx_List_BuildNode(&dma_ncfg, dma_node) != HAL_OK ||
|
||||||
|
HAL_DMAEx_List_InsertNode(dma_queue, NULL, dma_node) != HAL_OK ||
|
||||||
|
HAL_DMAEx_List_SetCircularMode(dma_queue) != HAL_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dma_descr->InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
|
||||||
|
dma_descr->InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
|
||||||
|
dma_descr->InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
|
||||||
|
dma_descr->InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
|
||||||
|
dma_descr->InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
|
||||||
|
|
||||||
|
if (HAL_DMAEx_List_Init(dma_descr) != HAL_OK ||
|
||||||
|
HAL_DMAEx_List_LinkQ(dma_descr, dma_queue) != HAL_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAL_DMA_ConfigChannelAttributes(dma_descr,
|
||||||
|
DMA_CHANNEL_PRIV | DMA_CHANNEL_SEC |
|
||||||
|
DMA_CHANNEL_SRC_SEC | DMA_CHANNEL_DEST_SEC) != HAL_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif // STM32N6
|
||||||
|
|
||||||
// Link the DMA handle to SPI handle.
|
// Link the DMA handle to SPI handle.
|
||||||
if (direction == DMA_MEMORY_TO_PERIPH) {
|
if (direction == DMA_MEMORY_TO_PERIPH) {
|
||||||
@ -311,6 +393,7 @@ static int omv_spi_dma_init(omv_spi_t *spi, uint32_t direction, omv_spi_config_t
|
|||||||
} else {
|
} else {
|
||||||
__HAL_LINKDMA(spi->descr, hdmarx, spi->dma_descr_rx);
|
__HAL_LINKDMA(spi->descr, hdmarx, spi->dma_descr_rx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the SPI handle used by the DMA channel's IRQ handler.
|
// Set the SPI handle used by the DMA channel's IRQ handler.
|
||||||
dma_utils_set_irq_descr(dma_descr->Instance, dma_descr);
|
dma_utils_set_irq_descr(dma_descr->Instance, dma_descr);
|
||||||
|
|
||||||
@ -336,9 +419,9 @@ static int omv_spi_bus_init(omv_spi_t *spi, omv_spi_config_t *config) {
|
|||||||
spi_descr->Init.CLKPhase = config->clk_pha;
|
spi_descr->Init.CLKPhase = config->clk_pha;
|
||||||
spi_descr->Init.CLKPolarity = config->clk_pol;
|
spi_descr->Init.CLKPolarity = config->clk_pol;
|
||||||
spi_descr->Init.BaudRatePrescaler = omv_spi_prescaler(spi_descr->Instance, config->baudrate);
|
spi_descr->Init.BaudRatePrescaler = omv_spi_prescaler(spi_descr->Instance, config->baudrate);
|
||||||
#if defined(STM32F7) || defined(STM32H7)
|
#if defined(STM32F7) || defined(STM32H7) || defined(STM32N6)
|
||||||
spi_descr->Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
|
spi_descr->Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
|
||||||
#if defined(STM32H7)
|
#if defined(STM32H7) || defined(STM32N6)
|
||||||
spi_descr->Init.NSSPolarity = (config->nss_pol == 0) ? SPI_NSS_POLARITY_LOW : SPI_NSS_POLARITY_HIGH;
|
spi_descr->Init.NSSPolarity = (config->nss_pol == 0) ? SPI_NSS_POLARITY_LOW : SPI_NSS_POLARITY_HIGH;
|
||||||
spi_descr->Init.FifoThreshold = SPI_FIFO_THRESHOLD_04DATA;
|
spi_descr->Init.FifoThreshold = SPI_FIFO_THRESHOLD_04DATA;
|
||||||
spi_descr->Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
|
spi_descr->Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
|
||||||
@ -356,7 +439,7 @@ static int omv_spi_bus_init(omv_spi_t *spi, omv_spi_config_t *config) {
|
|||||||
} else if (config->bus_mode == OMV_SPI_BUS_RX) {
|
} else if (config->bus_mode == OMV_SPI_BUS_RX) {
|
||||||
spi_descr->Init.Direction = SPI_DIRECTION_2LINES_RXONLY;
|
spi_descr->Init.Direction = SPI_DIRECTION_2LINES_RXONLY;
|
||||||
} else {
|
} else {
|
||||||
#if defined(STM32H7)
|
#if defined(STM32H7) || defined(STM32N6)
|
||||||
spi_descr->Init.Direction = SPI_DIRECTION_2LINES_TXONLY;
|
spi_descr->Init.Direction = SPI_DIRECTION_2LINES_TXONLY;
|
||||||
#else
|
#else
|
||||||
spi_descr->Init.Direction = SPI_DIRECTION_1LINE;
|
spi_descr->Init.Direction = SPI_DIRECTION_1LINE;
|
||||||
@ -407,11 +490,15 @@ int omv_spi_init(omv_spi_t *spi, omv_spi_config_t *config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config->dma_flags & (OMV_SPI_DMA_NORMAL | OMV_SPI_DMA_CIRCULAR)) {
|
if (config->dma_flags & (OMV_SPI_DMA_NORMAL | OMV_SPI_DMA_CIRCULAR)) {
|
||||||
|
int ret = 0;
|
||||||
if (config->bus_mode & OMV_SPI_BUS_TX) {
|
if (config->bus_mode & OMV_SPI_BUS_TX) {
|
||||||
omv_spi_dma_init(spi, DMA_MEMORY_TO_PERIPH, config);
|
ret |= omv_spi_dma_init(spi, DMA_MEMORY_TO_PERIPH, config);
|
||||||
}
|
}
|
||||||
if (config->bus_mode & OMV_SPI_BUS_RX) {
|
if (config->bus_mode & OMV_SPI_BUS_RX) {
|
||||||
omv_spi_dma_init(spi, DMA_PERIPH_TO_MEMORY, config);
|
ret |= omv_spi_dma_init(spi, DMA_PERIPH_TO_MEMORY, config);
|
||||||
|
}
|
||||||
|
if (ret != 0) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Configure and enable SPI IRQ channel.
|
// Configure and enable SPI IRQ channel.
|
||||||
|
@ -99,16 +99,28 @@ SECTIONS
|
|||||||
/* The program code and other data goes into FLASH */
|
/* The program code and other data goes into FLASH */
|
||||||
.text : ALIGN(4)
|
.text : ALIGN(4)
|
||||||
{
|
{
|
||||||
KEEP(*(.isr_vector))// ISR table
|
KEEP(*(.isr_vector))
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
*(.text) // .text sections (code)
|
#ifdef OMV_RAMFUNC_EXC
|
||||||
|
*(EXCLUDE_FILE(OMV_RAMFUNC_EXC) .text*)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
*(EXCLUDE_FILE(OMV_RAMFUNC_EXC) .rodata*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
#else
|
||||||
*(.text*) // .text* sections (code)
|
*(.text*) // .text* sections (code)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
*(.rodata) // .rodata sections (constants, strings, etc.)
|
|
||||||
. = ALIGN(4);
|
|
||||||
*(.rodata*) // .rodata* sections (constants, strings, etc.)
|
*(.rodata*) // .rodata* sections (constants, strings, etc.)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
#endif
|
||||||
|
} >FLASH_TEXT
|
||||||
|
|
||||||
|
.gnu.sgstubs :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_start_sg = .;
|
||||||
|
*(.gnu*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_end_sg = .;
|
||||||
} >FLASH_TEXT
|
} >FLASH_TEXT
|
||||||
|
|
||||||
/* The address used as the source for copying the initialized data section. */
|
/* The address used as the source for copying the initialized data section. */
|
||||||
@ -122,8 +134,6 @@ SECTIONS
|
|||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
*(.data*) // .data* sections
|
*(.data*) // .data* sections
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
*(.ram_function*)
|
|
||||||
. = ALIGN(4);
|
|
||||||
_edata = .; // Define a global symbol at data end
|
_edata = .; // Define a global symbol at data end
|
||||||
} >OMV_MAIN_MEMORY AT> FLASH_TEXT
|
} >OMV_MAIN_MEMORY AT> FLASH_TEXT
|
||||||
|
|
||||||
@ -150,6 +160,22 @@ SECTIONS
|
|||||||
} >OMV_CM4_BOOT_MEMORY
|
} >OMV_CM4_BOOT_MEMORY
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef OMV_RAMFUNC_MEMORY
|
||||||
|
.ram_function : ALIGN(4)
|
||||||
|
{
|
||||||
|
_ram_function_start = .;
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.ram_function*)
|
||||||
|
#ifdef OMV_RAMFUNC_INC
|
||||||
|
OMV_RAMFUNC_INC
|
||||||
|
#endif
|
||||||
|
. = ALIGN(4);
|
||||||
|
_ram_function_end = .;
|
||||||
|
} >OMV_RAMFUNC_MEMORY AT> FLASH_TEXT
|
||||||
|
|
||||||
|
_ram_function_flash = LOADADDR(.ram_function);
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "common.ld.S"
|
#include "common.ld.S"
|
||||||
|
|
||||||
.mp_etext :
|
.mp_etext :
|
||||||
|
@ -40,7 +40,8 @@
|
|||||||
#define MPU_REGION_NUMBER_MAX (MPU_REGION_NUMBER7)
|
#define MPU_REGION_NUMBER_MAX (MPU_REGION_NUMBER7)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MEM_ATTR_NORMAL_NON_CACHEABLE 0
|
#define MEMATTR_NORMAL_NCACHE 0
|
||||||
|
#define MEMATTR_NORMAL_WB_RA_WA 1
|
||||||
|
|
||||||
extern void SystemClock_Config(void);
|
extern void SystemClock_Config(void);
|
||||||
extern uint32_t omv_exti_get_gpio(uint32_t line);
|
extern uint32_t omv_exti_get_gpio(uint32_t line);
|
||||||
@ -68,17 +69,25 @@ void HAL_MspInit(void) {
|
|||||||
ARM_MPU_ClrRegion(i);
|
ARM_MPU_ClrRegion(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
ARM_MPU_SetMemAttr(MEM_ATTR_NORMAL_NON_CACHEABLE, ARM_MPU_ATTR(
|
ARM_MPU_SetMemAttr(MEMATTR_NORMAL_NCACHE, ARM_MPU_ATTR(
|
||||||
ARM_MPU_ATTR_NON_CACHEABLE,
|
ARM_MPU_ATTR_NON_CACHEABLE,
|
||||||
ARM_MPU_ATTR_NON_CACHEABLE));
|
ARM_MPU_ATTR_NON_CACHEABLE));
|
||||||
|
|
||||||
|
ARM_MPU_SetMemAttr(MEMATTR_NORMAL_WB_RA_WA, ARM_MPU_ATTR(
|
||||||
|
ARM_MPU_ATTR_MEMORY_(1, 1, 1, 1),
|
||||||
|
ARM_MPU_ATTR_MEMORY_(1, 1, 1, 1)));
|
||||||
|
|
||||||
|
MPU->RNR = 0;
|
||||||
|
MPU->RBAR = ARM_MPU_RBAR(0x90000000, ARM_MPU_SH_NON, 0, 1, 0); // RO-0, NP-1, XN-0
|
||||||
|
MPU->RLAR = ARM_MPU_RLAR(0x9FFFFFFF, MEMATTR_NORMAL_WB_RA_WA);
|
||||||
|
|
||||||
for (dma_memory_table_t const *buf = &_dma_memory_table_start; buf < &_dma_memory_table_end; buf++) {
|
for (dma_memory_table_t const *buf = &_dma_memory_table_start; buf < &_dma_memory_table_end; buf++) {
|
||||||
uint32_t region_base = buf->addr;
|
uint32_t region_base = buf->addr;
|
||||||
uint32_t region_size = buf->size;
|
uint32_t region_size = buf->size;
|
||||||
if (region_size) {
|
if (region_size) {
|
||||||
MPU->RNR = region_number--;
|
MPU->RNR = region_number--;
|
||||||
MPU->RBAR = ARM_MPU_RBAR(region_base, ARM_MPU_SH_NON, 0, 1, 0); // RO-0, NP-1, XN-0
|
MPU->RBAR = ARM_MPU_RBAR(region_base, ARM_MPU_SH_NON, 0, 1, 0); // RO-0, NP-1, XN-0
|
||||||
MPU->RLAR = ARM_MPU_RLAR(region_base + region_size - 1, MEM_ATTR_NORMAL_NON_CACHEABLE);
|
MPU->RLAR = ARM_MPU_RLAR(region_base + region_size - 1, MEMATTR_NORMAL_NCACHE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk);
|
ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk);
|
||||||
@ -131,6 +140,7 @@ void HAL_MspInit(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(SCB->CCR & (uint32_t) SCB_CCR_DC_Msk)) {
|
if (!(SCB->CCR & (uint32_t) SCB_CCR_DC_Msk)) {
|
||||||
|
// See ST Errata ES0620 - Rev 0.2 section 2.1.2
|
||||||
SCB_EnableDCache();
|
SCB_EnableDCache();
|
||||||
} else {
|
} else {
|
||||||
SCB_CleanInvalidateDCache();
|
SCB_CleanInvalidateDCache();
|
||||||
@ -178,6 +188,19 @@ void HAL_MspInit(void) {
|
|||||||
__HAL_RCC_GPIOQ_CLK_ENABLE();
|
__HAL_RCC_GPIOQ_CLK_ENABLE();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Enable low-power GPIO clocks.
|
||||||
|
#if defined(STM32N6)
|
||||||
|
__HAL_RCC_GPIOA_CLK_SLEEP_ENABLE();
|
||||||
|
__HAL_RCC_GPIOB_CLK_SLEEP_ENABLE();
|
||||||
|
__HAL_RCC_GPIOC_CLK_SLEEP_ENABLE();
|
||||||
|
__HAL_RCC_GPIOD_CLK_SLEEP_ENABLE();
|
||||||
|
__HAL_RCC_GPIOE_CLK_SLEEP_ENABLE();
|
||||||
|
__HAL_RCC_GPIOF_CLK_SLEEP_ENABLE();
|
||||||
|
__HAL_RCC_GPIOG_CLK_SLEEP_ENABLE();
|
||||||
|
__HAL_RCC_GPIOO_CLK_SLEEP_ENABLE();
|
||||||
|
__HAL_RCC_GPIOP_CLK_SLEEP_ENABLE();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Enable DMA clocks.
|
// Enable DMA clocks.
|
||||||
#if defined(__HAL_RCC_DMA1_CLK_ENABLE)
|
#if defined(__HAL_RCC_DMA1_CLK_ENABLE)
|
||||||
__HAL_RCC_DMA1_CLK_ENABLE();
|
__HAL_RCC_DMA1_CLK_ENABLE();
|
||||||
@ -199,6 +222,15 @@ void HAL_MspInit(void) {
|
|||||||
HAL_NVIC_EnableIRQ(MDMA_IRQn);
|
HAL_NVIC_EnableIRQ(MDMA_IRQn);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Enable SDMMCx clocks.
|
||||||
|
#if defined(STM32N6)
|
||||||
|
__HAL_RCC_SDMMC1_CLK_ENABLE();
|
||||||
|
__HAL_RCC_SDMMC1_CLK_SLEEP_ENABLE();
|
||||||
|
|
||||||
|
__HAL_RCC_SDMMC2_CLK_ENABLE();
|
||||||
|
__HAL_RCC_SDMMC2_CLK_SLEEP_ENABLE();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Setup AXI QoS
|
// Setup AXI QoS
|
||||||
#if defined(OMV_AXI_QOS_D2_AHB_R_PRI)
|
#if defined(OMV_AXI_QOS_D2_AHB_R_PRI)
|
||||||
OMV_AXI_QOS_D2_AHB_R_SET(OMV_AXI_QOS_D2_AHB_R_PRI);
|
OMV_AXI_QOS_D2_AHB_R_SET(OMV_AXI_QOS_D2_AHB_R_PRI);
|
||||||
@ -269,6 +301,33 @@ void HAL_MspInit(void) {
|
|||||||
HAL_SYSCFG_AnalogSwitchConfig(SYSCFG_SWITCH_PC2, SYSCFG_SWITCH_PC2_CLOSE);
|
HAL_SYSCFG_AnalogSwitchConfig(SYSCFG_SWITCH_PC2, SYSCFG_SWITCH_PC2_CLOSE);
|
||||||
HAL_SYSCFG_AnalogSwitchConfig(SYSCFG_SWITCH_PC3, SYSCFG_SWITCH_PC3_CLOSE);
|
HAL_SYSCFG_AnalogSwitchConfig(SYSCFG_SWITCH_PC3, SYSCFG_SWITCH_PC3_CLOSE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(STM32N6)
|
||||||
|
__HAL_RCC_RIFSC_CLK_ENABLE();
|
||||||
|
|
||||||
|
RIMC_MasterConfig_t RIMC_master = {
|
||||||
|
.MasterCID = RIF_CID_1,
|
||||||
|
.SecPriv = RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Array of master/peripheral index pairs [master_index, periph_index]
|
||||||
|
static const uint32_t rif_config_pairs[][2] = {
|
||||||
|
{ RIF_MASTER_INDEX_NPU, RIF_RISC_PERIPH_INDEX_NPU },
|
||||||
|
{ RIF_MASTER_INDEX_OTG1, RIF_RISC_PERIPH_INDEX_OTG1HS },
|
||||||
|
{ RIF_MASTER_INDEX_DMA2D, RIF_RISC_PERIPH_INDEX_DMA2D },
|
||||||
|
{ RIF_MASTER_INDEX_GPU2D, RIF_RISC_PERIPH_INDEX_GPU2D },
|
||||||
|
{ RIF_MASTER_INDEX_VENC, RIF_RISC_PERIPH_INDEX_VENC },
|
||||||
|
{ RIF_MASTER_INDEX_SDMMC1, RIF_RISC_PERIPH_INDEX_SDMMC1 },
|
||||||
|
{ RIF_MASTER_INDEX_SDMMC2, RIF_RISC_PERIPH_INDEX_SDMMC2 },
|
||||||
|
{ RIF_MASTER_INDEX_DCMIPP, RIF_RISC_PERIPH_INDEX_DCMIPP },
|
||||||
|
{ RIF_MASTER_INDEX_DCMIPP, RIF_RISC_PERIPH_INDEX_CSI },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < sizeof(rif_config_pairs) / sizeof(rif_config_pairs[0]); i++) {
|
||||||
|
HAL_RIF_RIMC_ConfigMasterAttributes(rif_config_pairs[i][0], &RIMC_master);
|
||||||
|
HAL_RIF_RISC_SetSlaveSecureAttributes(rif_config_pairs[i][1], RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c) {
|
void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c) {
|
||||||
@ -278,27 +337,31 @@ void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c) {
|
|||||||
if (0) {
|
if (0) {
|
||||||
#if defined(OMV_I2C1_ID)
|
#if defined(OMV_I2C1_ID)
|
||||||
} else if (hi2c->Instance == I2C1) {
|
} else if (hi2c->Instance == I2C1) {
|
||||||
__HAL_RCC_I2C1_CLK_ENABLE();
|
|
||||||
scl_pin = OMV_I2C1_SCL_PIN;
|
scl_pin = OMV_I2C1_SCL_PIN;
|
||||||
sda_pin = OMV_I2C1_SDA_PIN;
|
sda_pin = OMV_I2C1_SDA_PIN;
|
||||||
|
__HAL_RCC_I2C1_CLK_ENABLE();
|
||||||
|
__HAL_RCC_I2C1_CLK_SLEEP_ENABLE();
|
||||||
#endif
|
#endif
|
||||||
#if defined(OMV_I2C2_ID)
|
#if defined(OMV_I2C2_ID)
|
||||||
} else if (hi2c->Instance == I2C2) {
|
} else if (hi2c->Instance == I2C2) {
|
||||||
__HAL_RCC_I2C2_CLK_ENABLE();
|
|
||||||
scl_pin = OMV_I2C2_SCL_PIN;
|
scl_pin = OMV_I2C2_SCL_PIN;
|
||||||
sda_pin = OMV_I2C2_SDA_PIN;
|
sda_pin = OMV_I2C2_SDA_PIN;
|
||||||
|
__HAL_RCC_I2C2_CLK_ENABLE();
|
||||||
|
__HAL_RCC_I2C2_CLK_SLEEP_ENABLE();
|
||||||
#endif
|
#endif
|
||||||
#if defined(OMV_I2C3_ID)
|
#if defined(OMV_I2C3_ID)
|
||||||
} else if (hi2c->Instance == I2C3) {
|
} else if (hi2c->Instance == I2C3) {
|
||||||
__HAL_RCC_I2C3_CLK_ENABLE();
|
|
||||||
scl_pin = OMV_I2C3_SCL_PIN;
|
scl_pin = OMV_I2C3_SCL_PIN;
|
||||||
sda_pin = OMV_I2C3_SDA_PIN;
|
sda_pin = OMV_I2C3_SDA_PIN;
|
||||||
|
__HAL_RCC_I2C3_CLK_ENABLE();
|
||||||
|
__HAL_RCC_I2C3_CLK_SLEEP_ENABLE();
|
||||||
#endif
|
#endif
|
||||||
#if defined(OMV_I2C4_ID)
|
#if defined(OMV_I2C4_ID)
|
||||||
} else if (hi2c->Instance == I2C4) {
|
} else if (hi2c->Instance == I2C4) {
|
||||||
__HAL_RCC_I2C4_CLK_ENABLE();
|
|
||||||
scl_pin = OMV_I2C4_SCL_PIN;
|
scl_pin = OMV_I2C4_SCL_PIN;
|
||||||
sda_pin = OMV_I2C4_SDA_PIN;
|
sda_pin = OMV_I2C4_SDA_PIN;
|
||||||
|
__HAL_RCC_I2C4_CLK_ENABLE();
|
||||||
|
__HAL_RCC_I2C4_CLK_SLEEP_ENABLE();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,6 +405,7 @@ void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) {
|
|||||||
if (htim->Instance == OMV_CSI_TIM) {
|
if (htim->Instance == OMV_CSI_TIM) {
|
||||||
// Enable DCMI timer clock.
|
// Enable DCMI timer clock.
|
||||||
OMV_CSI_TIM_CLK_ENABLE();
|
OMV_CSI_TIM_CLK_ENABLE();
|
||||||
|
OMV_CSI_TIM_CLK_SLEEP_ENABLE();
|
||||||
// Timer GPIO configuration.
|
// Timer GPIO configuration.
|
||||||
omv_gpio_config(OMV_CSI_TIM_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_HIGH, -1);
|
omv_gpio_config(OMV_CSI_TIM_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_HIGH, -1);
|
||||||
#if defined(OMV_CSI_TIM_EXT_PIN)
|
#if defined(OMV_CSI_TIM_EXT_PIN)
|
||||||
@ -369,6 +433,7 @@ void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef *htim) {
|
|||||||
|
|
||||||
void HAL_DCMI_MspInit(DCMI_HandleTypeDef *hdcmi) {
|
void HAL_DCMI_MspInit(DCMI_HandleTypeDef *hdcmi) {
|
||||||
const omv_gpio_t dcmi_pins[] = {
|
const omv_gpio_t dcmi_pins[] = {
|
||||||
|
#ifdef OMV_CSI_D0_PIN
|
||||||
OMV_CSI_D0_PIN,
|
OMV_CSI_D0_PIN,
|
||||||
OMV_CSI_D1_PIN,
|
OMV_CSI_D1_PIN,
|
||||||
OMV_CSI_D2_PIN,
|
OMV_CSI_D2_PIN,
|
||||||
@ -380,18 +445,25 @@ void HAL_DCMI_MspInit(DCMI_HandleTypeDef *hdcmi) {
|
|||||||
OMV_CSI_HSYNC_PIN,
|
OMV_CSI_HSYNC_PIN,
|
||||||
OMV_CSI_VSYNC_PIN,
|
OMV_CSI_VSYNC_PIN,
|
||||||
OMV_CSI_PXCLK_PIN,
|
OMV_CSI_PXCLK_PIN,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// DCMI clock enable
|
// Enable DCMI clock.
|
||||||
__DCMI_CLK_ENABLE();
|
#if defined(PSSI)
|
||||||
|
__HAL_RCC_DCMI_PSSI_CLK_ENABLE();
|
||||||
// Configure VSYNC EXTI.
|
__HAL_RCC_DCMI_PSSI_CLK_SLEEP_ENABLE();
|
||||||
#if (DCMI_VSYNC_EXTI_SHARED == 1)
|
#else
|
||||||
if (exti_gpio == 0)
|
__HAL_RCC_DCMI_CLK_ENABLE();
|
||||||
|
__HAL_RCC_DCMI_CLK_SLEEP_ENABLE();
|
||||||
#endif
|
#endif
|
||||||
{
|
|
||||||
omv_gpio_config(OMV_CSI_VSYNC_PIN, OMV_GPIO_MODE_IT_BOTH, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_MAX, -1);
|
#ifdef OMV_CSI_VSYNC_PIN
|
||||||
}
|
// Configure VSYNC EXTI.
|
||||||
|
#if DCMI_VSYNC_EXTI_SHARED
|
||||||
|
if (exti_gpio == 0)
|
||||||
|
#endif // DCMI_VSYNC_EXTI_SHARED
|
||||||
|
omv_gpio_config(OMV_CSI_VSYNC_PIN, OMV_GPIO_MODE_IT_BOTH, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_MAX, -1);
|
||||||
|
#endif // OMV_CSI_VSYNC_PIN
|
||||||
|
|
||||||
// Configure DCMI pins.
|
// Configure DCMI pins.
|
||||||
for (int i = 0; i < OMV_ARRAY_SIZE(dcmi_pins); i++) {
|
for (int i = 0; i < OMV_ARRAY_SIZE(dcmi_pins); i++) {
|
||||||
@ -401,6 +473,7 @@ void HAL_DCMI_MspInit(DCMI_HandleTypeDef *hdcmi) {
|
|||||||
|
|
||||||
void HAL_DCMI_MspDeInit(DCMI_HandleTypeDef *hdcmi) {
|
void HAL_DCMI_MspDeInit(DCMI_HandleTypeDef *hdcmi) {
|
||||||
const omv_gpio_t dcmi_pins[] = {
|
const omv_gpio_t dcmi_pins[] = {
|
||||||
|
#ifdef OMV_CSI_D0_PIN
|
||||||
OMV_CSI_D0_PIN,
|
OMV_CSI_D0_PIN,
|
||||||
OMV_CSI_D1_PIN,
|
OMV_CSI_D1_PIN,
|
||||||
OMV_CSI_D2_PIN,
|
OMV_CSI_D2_PIN,
|
||||||
@ -412,10 +485,17 @@ void HAL_DCMI_MspDeInit(DCMI_HandleTypeDef *hdcmi) {
|
|||||||
OMV_CSI_HSYNC_PIN,
|
OMV_CSI_HSYNC_PIN,
|
||||||
OMV_CSI_VSYNC_PIN,
|
OMV_CSI_VSYNC_PIN,
|
||||||
OMV_CSI_PXCLK_PIN,
|
OMV_CSI_PXCLK_PIN,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// Disable DCMI clock.
|
// Disable DCMI clock.
|
||||||
__DCMI_CLK_DISABLE();
|
#if defined(PSSI)
|
||||||
|
__HAL_RCC_DCMI_PSSI_CLK_DISABLE();
|
||||||
|
__HAL_RCC_DCMI_PSSI_CLK_SLEEP_DISABLE();
|
||||||
|
#else
|
||||||
|
__HAL_RCC_DCMI_CLK_DISABLE();
|
||||||
|
__HAL_RCC_DCMI_CLK_SLEEP_DISABLE();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Deinit pins.
|
// Deinit pins.
|
||||||
for (int i = 0; i < OMV_ARRAY_SIZE(dcmi_pins); i++) {
|
for (int i = 0; i < OMV_ARRAY_SIZE(dcmi_pins); i++) {
|
||||||
@ -423,6 +503,85 @@ void HAL_DCMI_MspDeInit(DCMI_HandleTypeDef *hdcmi) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(DCMIPP)
|
||||||
|
void HAL_DCMIPP_MspInit(DCMIPP_HandleTypeDef *hdcmipp) {
|
||||||
|
const omv_gpio_t dcmi_pins[] = {
|
||||||
|
#ifdef OMV_CSI_D0_PIN
|
||||||
|
OMV_CSI_D0_PIN,
|
||||||
|
OMV_CSI_D1_PIN,
|
||||||
|
OMV_CSI_D2_PIN,
|
||||||
|
OMV_CSI_D3_PIN,
|
||||||
|
OMV_CSI_D4_PIN,
|
||||||
|
OMV_CSI_D5_PIN,
|
||||||
|
OMV_CSI_D6_PIN,
|
||||||
|
OMV_CSI_D7_PIN,
|
||||||
|
OMV_CSI_HSYNC_PIN,
|
||||||
|
OMV_CSI_VSYNC_PIN,
|
||||||
|
OMV_CSI_PXCLK_PIN,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// Enable DCMIPP clock.
|
||||||
|
__HAL_RCC_DCMIPP_CLK_ENABLE();
|
||||||
|
__HAL_RCC_DCMIPP_CLK_SLEEP_ENABLE();
|
||||||
|
__HAL_RCC_DCMIPP_FORCE_RESET();
|
||||||
|
__HAL_RCC_DCMIPP_RELEASE_RESET();
|
||||||
|
|
||||||
|
// Enable CSI clock
|
||||||
|
__HAL_RCC_CSI_CLK_ENABLE();
|
||||||
|
__HAL_RCC_CSI_CLK_SLEEP_ENABLE();
|
||||||
|
__HAL_RCC_CSI_FORCE_RESET();
|
||||||
|
__HAL_RCC_CSI_RELEASE_RESET();
|
||||||
|
|
||||||
|
#ifdef OMV_CSI_VSYNC_PIN
|
||||||
|
// Configure VSYNC EXTI.
|
||||||
|
#if DCMI_VSYNC_EXTI_SHARED
|
||||||
|
if (exti_gpio == 0)
|
||||||
|
#endif // DCMI_VSYNC_EXTI_SHARED
|
||||||
|
omv_gpio_config(OMV_CSI_VSYNC_PIN, OMV_GPIO_MODE_IT_BOTH, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_MAX, -1);
|
||||||
|
#endif // OMV_CSI_VSYNC_PIN
|
||||||
|
|
||||||
|
// Configure DCMI pins.
|
||||||
|
for (int i = 0; i < OMV_ARRAY_SIZE(dcmi_pins); i++) {
|
||||||
|
omv_gpio_config(dcmi_pins[i], OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_MAX, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HAL_DCMIPP_MspDeInit(DCMIPP_HandleTypeDef *hdcmipp) {
|
||||||
|
const omv_gpio_t dcmi_pins[] = {
|
||||||
|
#ifdef OMV_CSI_D0_PIN
|
||||||
|
OMV_CSI_D0_PIN,
|
||||||
|
OMV_CSI_D1_PIN,
|
||||||
|
OMV_CSI_D2_PIN,
|
||||||
|
OMV_CSI_D3_PIN,
|
||||||
|
OMV_CSI_D4_PIN,
|
||||||
|
OMV_CSI_D5_PIN,
|
||||||
|
OMV_CSI_D6_PIN,
|
||||||
|
OMV_CSI_D7_PIN,
|
||||||
|
OMV_CSI_HSYNC_PIN,
|
||||||
|
OMV_CSI_VSYNC_PIN,
|
||||||
|
OMV_CSI_PXCLK_PIN,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// Disable DCMI clock.
|
||||||
|
__HAL_RCC_DCMIPP_FORCE_RESET();
|
||||||
|
__HAL_RCC_DCMIPP_RELEASE_RESET();
|
||||||
|
__HAL_RCC_DCMIPP_CLK_DISABLE();
|
||||||
|
__HAL_RCC_DCMIPP_CLK_SLEEP_DISABLE();
|
||||||
|
|
||||||
|
__HAL_RCC_CSI_FORCE_RESET();
|
||||||
|
__HAL_RCC_CSI_RELEASE_RESET();
|
||||||
|
__HAL_RCC_CSI_CLK_DISABLE();
|
||||||
|
__HAL_RCC_CSI_CLK_SLEEP_DISABLE();
|
||||||
|
|
||||||
|
// Deinit pins.
|
||||||
|
for (int i = 0; i < OMV_ARRAY_SIZE(dcmi_pins); i++) {
|
||||||
|
omv_gpio_deinit(dcmi_pins[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) {
|
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
omv_gpio_t sclk_pin;
|
omv_gpio_t sclk_pin;
|
||||||
@ -437,6 +596,7 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) {
|
|||||||
#if defined(OMV_SPI1_ID)
|
#if defined(OMV_SPI1_ID)
|
||||||
} else if (hspi->Instance == SPI1) {
|
} else if (hspi->Instance == SPI1) {
|
||||||
__HAL_RCC_SPI1_CLK_ENABLE();
|
__HAL_RCC_SPI1_CLK_ENABLE();
|
||||||
|
__HAL_RCC_SPI1_CLK_SLEEP_ENABLE();
|
||||||
spi_pins = (spi_pins_t) {
|
spi_pins = (spi_pins_t) {
|
||||||
OMV_SPI1_SCLK_PIN, OMV_SPI1_MISO_PIN, OMV_SPI1_MOSI_PIN, OMV_SPI1_SSEL_PIN
|
OMV_SPI1_SCLK_PIN, OMV_SPI1_MISO_PIN, OMV_SPI1_MOSI_PIN, OMV_SPI1_SSEL_PIN
|
||||||
};
|
};
|
||||||
@ -444,6 +604,7 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) {
|
|||||||
#if defined(OMV_SPI2_ID)
|
#if defined(OMV_SPI2_ID)
|
||||||
} else if (hspi->Instance == SPI2) {
|
} else if (hspi->Instance == SPI2) {
|
||||||
__HAL_RCC_SPI2_CLK_ENABLE();
|
__HAL_RCC_SPI2_CLK_ENABLE();
|
||||||
|
__HAL_RCC_SPI2_CLK_SLEEP_ENABLE();
|
||||||
spi_pins = (spi_pins_t) {
|
spi_pins = (spi_pins_t) {
|
||||||
OMV_SPI2_SCLK_PIN, OMV_SPI2_MISO_PIN, OMV_SPI2_MOSI_PIN, OMV_SPI2_SSEL_PIN
|
OMV_SPI2_SCLK_PIN, OMV_SPI2_MISO_PIN, OMV_SPI2_MOSI_PIN, OMV_SPI2_SSEL_PIN
|
||||||
};
|
};
|
||||||
@ -451,6 +612,7 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) {
|
|||||||
#if defined(OMV_SPI3_ID)
|
#if defined(OMV_SPI3_ID)
|
||||||
} else if (hspi->Instance == SPI3) {
|
} else if (hspi->Instance == SPI3) {
|
||||||
__HAL_RCC_SPI3_CLK_ENABLE();
|
__HAL_RCC_SPI3_CLK_ENABLE();
|
||||||
|
__HAL_RCC_SPI3_CLK_SLEEP_ENABLE();
|
||||||
spi_pins = (spi_pins_t) {
|
spi_pins = (spi_pins_t) {
|
||||||
OMV_SPI3_SCLK_PIN, OMV_SPI3_MISO_PIN, OMV_SPI3_MOSI_PIN, OMV_SPI3_SSEL_PIN
|
OMV_SPI3_SCLK_PIN, OMV_SPI3_MISO_PIN, OMV_SPI3_MOSI_PIN, OMV_SPI3_SSEL_PIN
|
||||||
};
|
};
|
||||||
@ -458,6 +620,7 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) {
|
|||||||
#if defined(OMV_SPI4_ID)
|
#if defined(OMV_SPI4_ID)
|
||||||
} else if (hspi->Instance == SPI4) {
|
} else if (hspi->Instance == SPI4) {
|
||||||
__HAL_RCC_SPI4_CLK_ENABLE();
|
__HAL_RCC_SPI4_CLK_ENABLE();
|
||||||
|
__HAL_RCC_SPI4_CLK_SLEEP_ENABLE();
|
||||||
spi_pins = (spi_pins_t) {
|
spi_pins = (spi_pins_t) {
|
||||||
OMV_SPI4_SCLK_PIN, OMV_SPI4_MISO_PIN, OMV_SPI4_MOSI_PIN, OMV_SPI4_SSEL_PIN
|
OMV_SPI4_SCLK_PIN, OMV_SPI4_MISO_PIN, OMV_SPI4_MOSI_PIN, OMV_SPI4_SSEL_PIN
|
||||||
};
|
};
|
||||||
@ -465,6 +628,7 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) {
|
|||||||
#if defined(OMV_SPI5_ID)
|
#if defined(OMV_SPI5_ID)
|
||||||
} else if (hspi->Instance == SPI5) {
|
} else if (hspi->Instance == SPI5) {
|
||||||
__HAL_RCC_SPI5_CLK_ENABLE();
|
__HAL_RCC_SPI5_CLK_ENABLE();
|
||||||
|
__HAL_RCC_SPI5_CLK_SLEEP_ENABLE();
|
||||||
spi_pins = (spi_pins_t) {
|
spi_pins = (spi_pins_t) {
|
||||||
OMV_SPI5_SCLK_PIN, OMV_SPI5_MISO_PIN, OMV_SPI5_MOSI_PIN, OMV_SPI5_SSEL_PIN
|
OMV_SPI5_SCLK_PIN, OMV_SPI5_MISO_PIN, OMV_SPI5_MOSI_PIN, OMV_SPI5_SSEL_PIN
|
||||||
};
|
};
|
||||||
@ -472,6 +636,7 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) {
|
|||||||
#if defined(SPI6_ID)
|
#if defined(SPI6_ID)
|
||||||
} else if (hspi->Instance == SPI6) {
|
} else if (hspi->Instance == SPI6) {
|
||||||
__HAL_RCC_SPI6_CLK_ENABLE();
|
__HAL_RCC_SPI6_CLK_ENABLE();
|
||||||
|
__HAL_RCC_SPI6_CLK_SLEEP_ENABLE();
|
||||||
spi_pins = (spi_pins_t) {
|
spi_pins = (spi_pins_t) {
|
||||||
SPI6_SCLK_PIN, SPI6_MISO_PIN, SPI6_MOSI_PIN, SPI6_SSEL_PIN
|
SPI6_SCLK_PIN, SPI6_MISO_PIN, SPI6_MOSI_PIN, SPI6_SSEL_PIN
|
||||||
};
|
};
|
||||||
@ -480,7 +645,7 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(STM32H7)
|
#if defined(STM32H7) || defined(STM32N6)
|
||||||
omv_gpio_config(spi_pins.sclk_pin, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_HIGH, -1);
|
omv_gpio_config(spi_pins.sclk_pin, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_HIGH, -1);
|
||||||
#else
|
#else
|
||||||
// The STM32F4 and STM32F7 don't set the initial state of the clock line until transmitting the
|
// The STM32F4 and STM32F7 don't set the initial state of the clock line until transmitting the
|
||||||
@ -506,7 +671,7 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) {
|
|||||||
} else {
|
} else {
|
||||||
if (hspi->Init.Mode == SPI_MODE_MASTER) {
|
if (hspi->Init.Mode == SPI_MODE_MASTER) {
|
||||||
omv_gpio_config(spi_pins.ssel_pin, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_HIGH, -1);
|
omv_gpio_config(spi_pins.ssel_pin, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_HIGH, -1);
|
||||||
#if defined(STM32H7)
|
#if defined(STM32H7) || defined(STM32N6)
|
||||||
if (hspi->Init.NSSPolarity == SPI_NSS_POLARITY_LOW) {
|
if (hspi->Init.NSSPolarity == SPI_NSS_POLARITY_LOW) {
|
||||||
omv_gpio_write(spi_pins.ssel_pin, 1);
|
omv_gpio_write(spi_pins.ssel_pin, 1);
|
||||||
} else {
|
} else {
|
||||||
@ -616,7 +781,7 @@ void HAL_SAI_MspInit(SAI_HandleTypeDef *hsai) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HAL_SAI_MspDeInit(SAI_HandleTypeDef *hsai) {
|
void HAL_SAI_MspDeInit(SAI_HandleTypeDef *hsai) {
|
||||||
if (hsai->Instance == SAI4_Block_A) {
|
if (hsai->Instance == OMV_SAI) {
|
||||||
OMV_SAI_CLK_DISABLE();
|
OMV_SAI_CLK_DISABLE();
|
||||||
omv_gpio_deinit(OMV_SAI_CK_PIN);
|
omv_gpio_deinit(OMV_SAI_CK_PIN);
|
||||||
omv_gpio_deinit(OMV_SAI_D1_PIN);
|
omv_gpio_deinit(OMV_SAI_D1_PIN);
|
||||||
@ -638,23 +803,57 @@ void HAL_DFSDM_ChannelMspDeInit(DFSDM_Channel_HandleTypeDef *hdfsdm) {
|
|||||||
omv_gpio_deinit(OMV_DFSDM_D1_PIN);
|
omv_gpio_deinit(OMV_DFSDM_D1_PIN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#elif defined(OMV_MDF)
|
||||||
|
void HAL_MDF_MspInit(MDF_HandleTypeDef *hmdf) {
|
||||||
|
if (hmdf->Instance == OMV_MDF) {
|
||||||
|
if (IS_ADF_INSTANCE(hmdf->Instance)) {
|
||||||
|
__HAL_RCC_ADF1_CLK_ENABLE();
|
||||||
|
__HAL_RCC_ADF1_CLK_SLEEP_ENABLE();
|
||||||
|
} else {
|
||||||
|
__HAL_RCC_MDF1_CLK_ENABLE();
|
||||||
|
__HAL_RCC_MDF1_CLK_SLEEP_ENABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
omv_gpio_config(OMV_MDF_CK_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_LOW, -1);
|
||||||
|
omv_gpio_config(OMV_MDF_D1_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_LOW, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HAL_MDF_MspDeInit(MDF_HandleTypeDef *hmdf) {
|
||||||
|
if (hmdf->Instance == OMV_MDF) {
|
||||||
|
if (IS_ADF_INSTANCE(hmdf->Instance)) {
|
||||||
|
__HAL_RCC_ADF1_CLK_DISABLE();
|
||||||
|
__HAL_RCC_ADF1_CLK_SLEEP_DISABLE();
|
||||||
|
} else {
|
||||||
|
__HAL_RCC_MDF1_CLK_DISABLE();
|
||||||
|
__HAL_RCC_MDF1_CLK_SLEEP_DISABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
omv_gpio_deinit(OMV_MDF_CK_PIN);
|
||||||
|
omv_gpio_deinit(OMV_MDF_D1_PIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void HAL_CRC_MspInit(CRC_HandleTypeDef *hcrc) {
|
void HAL_CRC_MspInit(CRC_HandleTypeDef *hcrc) {
|
||||||
__HAL_RCC_CRC_CLK_ENABLE();
|
__HAL_RCC_CRC_CLK_ENABLE();
|
||||||
|
__HAL_RCC_CRC_CLK_SLEEP_ENABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HAL_CRC_MspDeInit(CRC_HandleTypeDef *hcrc) {
|
void HAL_CRC_MspDeInit(CRC_HandleTypeDef *hcrc) {
|
||||||
__HAL_RCC_CRC_CLK_DISABLE();
|
__HAL_RCC_CRC_CLK_DISABLE();
|
||||||
|
__HAL_RCC_CRC_CLK_SLEEP_DISABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HAL_DMA2D_MspInit(DMA2D_HandleTypeDef *hdma2d) {
|
void HAL_DMA2D_MspInit(DMA2D_HandleTypeDef *hdma2d) {
|
||||||
__HAL_RCC_DMA2D_CLK_ENABLE();
|
__HAL_RCC_DMA2D_CLK_ENABLE();
|
||||||
|
__HAL_RCC_DMA2D_CLK_SLEEP_ENABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HAL_DMA2D_MspDeInit(DMA2D_HandleTypeDef *hdma2d) {
|
void HAL_DMA2D_MspDeInit(DMA2D_HandleTypeDef *hdma2d) {
|
||||||
__HAL_RCC_DMA2D_FORCE_RESET();
|
__HAL_RCC_DMA2D_FORCE_RESET();
|
||||||
__HAL_RCC_DMA2D_RELEASE_RESET();
|
__HAL_RCC_DMA2D_RELEASE_RESET();
|
||||||
|
|
||||||
__HAL_RCC_DMA2D_CLK_DISABLE();
|
__HAL_RCC_DMA2D_CLK_DISABLE();
|
||||||
__HAL_RCC_DMA2D_CLK_SLEEP_DISABLE();
|
__HAL_RCC_DMA2D_CLK_SLEEP_DISABLE();
|
||||||
}
|
}
|
||||||
@ -689,6 +888,7 @@ void HAL_GFXMMU_MspDeInit(GFXMMU_HandleTypeDef *hgfxmmu) {
|
|||||||
#if (OMV_JPEG_CODEC_ENABLE == 1)
|
#if (OMV_JPEG_CODEC_ENABLE == 1)
|
||||||
void HAL_JPEG_MspInit(JPEG_HandleTypeDef *hjpeg) {
|
void HAL_JPEG_MspInit(JPEG_HandleTypeDef *hjpeg) {
|
||||||
__HAL_RCC_JPEG_CLK_ENABLE();
|
__HAL_RCC_JPEG_CLK_ENABLE();
|
||||||
|
__HAL_RCC_JPEG_CLK_SLEEP_ENABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HAL_JPEG_MspDeInit(JPEG_HandleTypeDef *hjpeg) {
|
void HAL_JPEG_MspDeInit(JPEG_HandleTypeDef *hjpeg) {
|
||||||
@ -809,6 +1009,99 @@ void HAL_LTDC_MspDeInit(LTDC_HandleTypeDef *hltdc) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(OMV_XSPI1_IO00_PIN)
|
||||||
|
void HAL_XSPI_MspInit(XSPI_HandleTypeDef *hxspi) {
|
||||||
|
const omv_gpio_t xspi_pins[] = {
|
||||||
|
OMV_XSPI1_IO00_PIN,
|
||||||
|
OMV_XSPI1_IO01_PIN,
|
||||||
|
OMV_XSPI1_IO02_PIN,
|
||||||
|
OMV_XSPI1_IO03_PIN,
|
||||||
|
OMV_XSPI1_IO04_PIN,
|
||||||
|
OMV_XSPI1_IO05_PIN,
|
||||||
|
OMV_XSPI1_IO06_PIN,
|
||||||
|
OMV_XSPI1_IO07_PIN,
|
||||||
|
OMV_XSPI1_IO08_PIN,
|
||||||
|
OMV_XSPI1_IO09_PIN,
|
||||||
|
OMV_XSPI1_IO10_PIN,
|
||||||
|
OMV_XSPI1_IO11_PIN,
|
||||||
|
OMV_XSPI1_IO12_PIN,
|
||||||
|
OMV_XSPI1_IO13_PIN,
|
||||||
|
OMV_XSPI1_IO14_PIN,
|
||||||
|
OMV_XSPI1_IO15_PIN,
|
||||||
|
OMV_XSPI1_NCS1_PIN,
|
||||||
|
OMV_XSPI1_DQS0_PIN,
|
||||||
|
OMV_XSPI1_DQS1_PIN,
|
||||||
|
OMV_XSPI1_CLKP_PIN,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reset and enable XSPI clock.
|
||||||
|
if (hxspi->Instance == XSPI1) {
|
||||||
|
__HAL_RCC_XSPI1_FORCE_RESET();
|
||||||
|
__HAL_RCC_XSPI1_RELEASE_RESET();
|
||||||
|
__HAL_RCC_XSPI1_CLK_ENABLE();
|
||||||
|
__HAL_RCC_XSPI1_CLK_SLEEP_ENABLE();
|
||||||
|
} else if (hxspi->Instance == XSPI2) {
|
||||||
|
__HAL_RCC_XSPI2_FORCE_RESET();
|
||||||
|
__HAL_RCC_XSPI2_RELEASE_RESET();
|
||||||
|
__HAL_RCC_XSPI2_CLK_ENABLE();
|
||||||
|
__HAL_RCC_XSPI2_CLK_SLEEP_ENABLE();
|
||||||
|
} else if (hxspi->Instance == XSPI3) {
|
||||||
|
__HAL_RCC_XSPI3_FORCE_RESET();
|
||||||
|
__HAL_RCC_XSPI3_RELEASE_RESET();
|
||||||
|
__HAL_RCC_XSPI3_CLK_ENABLE();
|
||||||
|
__HAL_RCC_XSPI3_CLK_SLEEP_ENABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < OMV_ARRAY_SIZE(xspi_pins); i++) {
|
||||||
|
omv_gpio_config(xspi_pins[i], OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MAX, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HAL_XSPI_MspDeInit(XSPI_HandleTypeDef *hxspi) {
|
||||||
|
const omv_gpio_t xspi_pins[] = {
|
||||||
|
OMV_XSPI1_IO00_PIN,
|
||||||
|
OMV_XSPI1_IO01_PIN,
|
||||||
|
OMV_XSPI1_IO02_PIN,
|
||||||
|
OMV_XSPI1_IO03_PIN,
|
||||||
|
OMV_XSPI1_IO04_PIN,
|
||||||
|
OMV_XSPI1_IO05_PIN,
|
||||||
|
OMV_XSPI1_IO06_PIN,
|
||||||
|
OMV_XSPI1_IO07_PIN,
|
||||||
|
OMV_XSPI1_IO08_PIN,
|
||||||
|
OMV_XSPI1_IO09_PIN,
|
||||||
|
OMV_XSPI1_IO10_PIN,
|
||||||
|
OMV_XSPI1_IO11_PIN,
|
||||||
|
OMV_XSPI1_IO12_PIN,
|
||||||
|
OMV_XSPI1_IO13_PIN,
|
||||||
|
OMV_XSPI1_IO14_PIN,
|
||||||
|
OMV_XSPI1_IO15_PIN,
|
||||||
|
OMV_XSPI1_NCS1_PIN,
|
||||||
|
OMV_XSPI1_DQS0_PIN,
|
||||||
|
OMV_XSPI1_DQS1_PIN,
|
||||||
|
OMV_XSPI1_CLKP_PIN,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reset and enable XSPI clock.
|
||||||
|
if (hxspi->Instance == XSPI1) {
|
||||||
|
__HAL_RCC_XSPI1_FORCE_RESET();
|
||||||
|
__HAL_RCC_XSPI1_RELEASE_RESET();
|
||||||
|
__HAL_RCC_XSPI1_CLK_DISABLE();
|
||||||
|
} else if (hxspi->Instance == XSPI2) {
|
||||||
|
__HAL_RCC_XSPI2_FORCE_RESET();
|
||||||
|
__HAL_RCC_XSPI2_RELEASE_RESET();
|
||||||
|
__HAL_RCC_XSPI2_CLK_DISABLE();
|
||||||
|
} else if (hxspi->Instance == XSPI3) {
|
||||||
|
__HAL_RCC_XSPI3_FORCE_RESET();
|
||||||
|
__HAL_RCC_XSPI3_RELEASE_RESET();
|
||||||
|
__HAL_RCC_XSPI3_CLK_DISABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < OMV_ARRAY_SIZE(xspi_pins); i++) {
|
||||||
|
omv_gpio_deinit(xspi_pins[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void HAL_MspDeInit(void) {
|
void HAL_MspDeInit(void) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
330
ports/stm32/xspi_psram.c
Normal file
330
ports/stm32/xspi_psram.c
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023-2024 OpenMV, LLC.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Any redistribution, use, or modification in source or binary form
|
||||||
|
* is done solely for personal benefit and not for any commercial
|
||||||
|
* purpose or for monetary gain. For commercial licensing options,
|
||||||
|
* please contact openmv@openmv.io
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR OR COPYRIGHT
|
||||||
|
* OWNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* STM32 XSPI PSRAM driver.
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include STM32_HAL_H
|
||||||
|
#include "omv_boardconfig.h"
|
||||||
|
|
||||||
|
#if defined(OMV_XSPI_PSRAM_ID)
|
||||||
|
|
||||||
|
#define XSPI_CMD_READ (0x00)
|
||||||
|
#define XSPI_CMD_READ_LATENCY (7)
|
||||||
|
#define XSPI_CMD_READ_LINEAR_BURST (0x20)
|
||||||
|
|
||||||
|
#define XSPI_CMD_WRITE (0x80)
|
||||||
|
#define XSPI_CMD_WRITE_LATENCY (7)
|
||||||
|
#define XSPI_CMD_WRITE_LINEAR_BURST (0xA0)
|
||||||
|
|
||||||
|
#define XSPI_CMD_READ_REG (0x40)
|
||||||
|
#define XSPI_CMD_WRITE_REG (0xC0)
|
||||||
|
|
||||||
|
#define XSPI_COMMAND_TIMEOUT (1000)
|
||||||
|
|
||||||
|
static XSPI_HandleTypeDef xspi;
|
||||||
|
|
||||||
|
static int xspi_psram_read_reg(XSPI_HandleTypeDef *xspi, uint32_t addr, uint8_t *data) {
|
||||||
|
XSPI_RegularCmdTypeDef command = {
|
||||||
|
.OperationType = HAL_XSPI_OPTYPE_COMMON_CFG,
|
||||||
|
.Instruction = XSPI_CMD_READ_REG,
|
||||||
|
.InstructionMode = HAL_XSPI_INSTRUCTION_8_LINES,
|
||||||
|
.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS,
|
||||||
|
.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE,
|
||||||
|
.Address = addr,
|
||||||
|
.AddressMode = HAL_XSPI_ADDRESS_8_LINES,
|
||||||
|
.AddressWidth = HAL_XSPI_ADDRESS_32_BITS,
|
||||||
|
.AddressDTRMode = HAL_XSPI_ADDRESS_DTR_ENABLE,
|
||||||
|
.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE,
|
||||||
|
.DataMode = HAL_XSPI_DATA_8_LINES,
|
||||||
|
.DataDTRMode = HAL_XSPI_DATA_DTR_ENABLE,
|
||||||
|
.DataLength = 2,
|
||||||
|
.DummyCycles = XSPI_CMD_READ_LATENCY - 1,
|
||||||
|
.DQSMode = HAL_XSPI_DQS_ENABLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint16_t regval = 0;
|
||||||
|
if (HAL_XSPI_Command(xspi, &command, XSPI_COMMAND_TIMEOUT) != HAL_OK ||
|
||||||
|
HAL_XSPI_Receive(xspi, (uint8_t *) ®val, XSPI_COMMAND_TIMEOUT) != HAL_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*data = (uint8_t) regval;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xspi_psram_write_reg(XSPI_HandleTypeDef *xspi, uint32_t addr, uint8_t data) {
|
||||||
|
XSPI_RegularCmdTypeDef command = {
|
||||||
|
.OperationType = HAL_XSPI_OPTYPE_COMMON_CFG,
|
||||||
|
.Instruction = XSPI_CMD_WRITE_REG,
|
||||||
|
.InstructionMode = HAL_XSPI_INSTRUCTION_8_LINES,
|
||||||
|
.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS,
|
||||||
|
.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE,
|
||||||
|
.Address = addr,
|
||||||
|
.AddressMode = HAL_XSPI_ADDRESS_8_LINES,
|
||||||
|
.AddressWidth = HAL_XSPI_ADDRESS_32_BITS,
|
||||||
|
.AddressDTRMode = HAL_XSPI_ADDRESS_DTR_ENABLE,
|
||||||
|
.DataMode = HAL_XSPI_DATA_8_LINES,
|
||||||
|
.DataDTRMode = HAL_XSPI_DATA_DTR_ENABLE,
|
||||||
|
.DataLength = 2,
|
||||||
|
.DummyCycles = 0,
|
||||||
|
.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE,
|
||||||
|
.DQSMode = HAL_XSPI_DQS_DISABLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint16_t regval = (data << 8) | data;
|
||||||
|
if (HAL_XSPI_Command(xspi, &command, XSPI_COMMAND_TIMEOUT) != HAL_OK ||
|
||||||
|
HAL_XSPI_Transmit(xspi, (uint8_t *) ®val, XSPI_COMMAND_TIMEOUT) != HAL_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xspi_psram_write_verify(XSPI_HandleTypeDef *xspi, uint32_t addr, uint8_t data) {
|
||||||
|
uint8_t reg = 0;
|
||||||
|
if (xspi_psram_write_reg(xspi, addr, data) != 0 ||
|
||||||
|
xspi_psram_read_reg(xspi, addr, ®) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return reg == data ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: Linear burst commands force read/write commands to do 2KByte Wrap(X8)/1K Word(X16)
|
||||||
|
static int xspi_psram_memory_map(XSPI_HandleTypeDef *xspi, uint32_t burst_enable) {
|
||||||
|
XSPI_RegularCmdTypeDef command = {
|
||||||
|
.InstructionMode = HAL_XSPI_INSTRUCTION_8_LINES,
|
||||||
|
.InstructionWidth = HAL_XSPI_INSTRUCTION_8_BITS,
|
||||||
|
.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE,
|
||||||
|
.AddressMode = HAL_XSPI_ADDRESS_8_LINES,
|
||||||
|
.AddressWidth = HAL_XSPI_ADDRESS_32_BITS,
|
||||||
|
.AddressDTRMode = HAL_XSPI_ADDRESS_DTR_ENABLE,
|
||||||
|
.DataMode = HAL_XSPI_DATA_16_LINES,
|
||||||
|
.DataDTRMode = HAL_XSPI_DATA_DTR_ENABLE,
|
||||||
|
.DataLength = 0,
|
||||||
|
.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE,
|
||||||
|
.DQSMode = HAL_XSPI_DQS_ENABLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize the write command
|
||||||
|
command.OperationType = HAL_XSPI_OPTYPE_WRITE_CFG;
|
||||||
|
command.Instruction = (burst_enable ? XSPI_CMD_WRITE_LINEAR_BURST : XSPI_CMD_WRITE);
|
||||||
|
command.DummyCycles = (XSPI_CMD_WRITE_LATENCY - 1U);
|
||||||
|
|
||||||
|
if (HAL_XSPI_Command(xspi, &command, XSPI_COMMAND_TIMEOUT) != HAL_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the read command
|
||||||
|
command.OperationType = HAL_XSPI_OPTYPE_READ_CFG;
|
||||||
|
command.Instruction = (burst_enable ? XSPI_CMD_READ_LINEAR_BURST : XSPI_CMD_READ);
|
||||||
|
command.DummyCycles = (XSPI_CMD_READ_LATENCY - 1U);
|
||||||
|
if (HAL_XSPI_Command(xspi, &command, XSPI_COMMAND_TIMEOUT) != HAL_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XSPI_MemoryMappedTypeDef mmap_config = {
|
||||||
|
.TimeoutPeriodClock = 0x34,
|
||||||
|
.TimeOutActivation = HAL_XSPI_TIMEOUT_COUNTER_DISABLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (HAL_XSPI_MemoryMapped(xspi, &mmap_config) != HAL_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xspi_psram_init() {
|
||||||
|
uint32_t xspi_clk = 0;
|
||||||
|
|
||||||
|
// Reset and enable XSPI clock.
|
||||||
|
if (OMV_XSPI_PSRAM_ID == 1) {
|
||||||
|
xspi_clk = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_XSPI1);
|
||||||
|
} else if (OMV_XSPI_PSRAM_ID == 2) {
|
||||||
|
xspi_clk = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_XSPI2);
|
||||||
|
} else if (OMV_XSPI_PSRAM_ID == 3) {
|
||||||
|
xspi_clk = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_XSPI3);
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&xspi, 0, sizeof(XSPI_HandleTypeDef));
|
||||||
|
xspi.Instance = XSPI1;
|
||||||
|
xspi.Init.FifoThresholdByte = 8;
|
||||||
|
xspi.Init.MemoryType = HAL_XSPI_MEMTYPE_APMEM_16BITS;
|
||||||
|
xspi.Init.MemoryMode = HAL_XSPI_SINGLE_MEM;
|
||||||
|
xspi.Init.MemorySize = __builtin_ctz(OMV_XSPI_PSRAM_SIZE) - 1;
|
||||||
|
xspi.Init.MemorySelect = HAL_XSPI_CSSEL_NCS1;
|
||||||
|
xspi.Init.ChipSelectHighTimeCycle = 1;
|
||||||
|
xspi.Init.ClockMode = HAL_XSPI_CLOCK_MODE_0;
|
||||||
|
xspi.Init.ClockPrescaler = (xspi_clk / OMV_XSPI_PSRAM_FREQUENCY) - 1;
|
||||||
|
xspi.Init.FreeRunningClock = HAL_XSPI_FREERUNCLK_DISABLE;
|
||||||
|
xspi.Init.SampleShifting = HAL_XSPI_SAMPLE_SHIFT_NONE;
|
||||||
|
xspi.Init.DelayHoldQuarterCycle = HAL_XSPI_DHQC_DISABLE;
|
||||||
|
xspi.Init.ChipSelectBoundary = HAL_XSPI_BONDARYOF_16KB;
|
||||||
|
xspi.Init.WrapSize = HAL_XSPI_WRAP_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
if (HAL_XSPI_Init(&xspi) != HAL_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read Latency=7 up to 200MHz
|
||||||
|
if (xspi_psram_write_verify(&xspi, 0, 0x30) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// Write Latency=7 up to 200MHz
|
||||||
|
if (xspi_psram_write_verify(&xspi, 4, 0x20) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// x16 | RBX | 2K Byte burst
|
||||||
|
if (xspi_psram_write_verify(&xspi, 8, 0x4B) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// Switch to memory-mapped mode.
|
||||||
|
if (xspi_psram_memory_map(&xspi, 1) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void __fatal_error(const char *msg);
|
||||||
|
#if __GNUC__ >= 11
|
||||||
|
// Prevent array bounds warnings when accessing SDRAM_START_ADDRESS as a memory pointer.
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||||
|
#pragma GCC diagnostic ignored "-Wstringop-overflow"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool __attribute__((optimize("Os"))) xspi_psram_test(bool exhaustive) {
|
||||||
|
uint8_t const pattern = 0xaa;
|
||||||
|
uint8_t const antipattern = 0x55;
|
||||||
|
volatile uint8_t *const mem_base = (uint8_t *) 0x90000000;
|
||||||
|
|
||||||
|
char error_buffer[1024];
|
||||||
|
uint32_t mem_size = OMV_XSPI_PSRAM_SIZE;
|
||||||
|
|
||||||
|
#if (__DCACHE_PRESENT == 1)
|
||||||
|
bool i_cache_disabled = false;
|
||||||
|
bool d_cache_disabled = false;
|
||||||
|
|
||||||
|
// Disable caches for testing.
|
||||||
|
if (SCB->CCR & (uint32_t) SCB_CCR_IC_Msk) {
|
||||||
|
SCB_DisableICache();
|
||||||
|
i_cache_disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SCB->CCR & (uint32_t) SCB_CCR_DC_Msk) {
|
||||||
|
SCB_DisableDCache();
|
||||||
|
d_cache_disabled = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Test data bus
|
||||||
|
for (uint32_t i = 0; i < 16; i++) {
|
||||||
|
*((volatile uint32_t *) mem_base) = (1 << i);
|
||||||
|
__DSB();
|
||||||
|
if (*((volatile uint32_t *) mem_base) != (1 << i)) {
|
||||||
|
snprintf(error_buffer, sizeof(error_buffer),
|
||||||
|
"Data bus test failed at 0x%p expected 0x%x found 0x%lx",
|
||||||
|
&mem_base[0], (1 << i), ((volatile uint32_t *) mem_base)[0]);
|
||||||
|
__fatal_error(error_buffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test address bus
|
||||||
|
for (uint32_t i = 1; i < mem_size; i <<= 1) {
|
||||||
|
mem_base[i] = pattern;
|
||||||
|
__DSB();
|
||||||
|
if (mem_base[i] != pattern) {
|
||||||
|
snprintf(error_buffer, sizeof(error_buffer),
|
||||||
|
"Address bus test failed at 0x%p expected 0x%x found 0x%x",
|
||||||
|
&mem_base[i], pattern, mem_base[i]);
|
||||||
|
__fatal_error(error_buffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for aliasing (overlapping addresses)
|
||||||
|
mem_base[0] = antipattern;
|
||||||
|
__DSB();
|
||||||
|
for (uint32_t i = 1; i < mem_size; i <<= 1) {
|
||||||
|
if (mem_base[i] != pattern) {
|
||||||
|
snprintf(error_buffer, sizeof(error_buffer),
|
||||||
|
"Address bus overlap at 0x%p expected 0x%x found 0x%x",
|
||||||
|
&mem_base[i], pattern, mem_base[i]);
|
||||||
|
__fatal_error(error_buffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_size = 512 * 1024;
|
||||||
|
// Test all RAM cells
|
||||||
|
if (exhaustive) {
|
||||||
|
// Write all memory first then compare, so even if the cache
|
||||||
|
// is enabled, it's not just writing and reading from cache.
|
||||||
|
// Note: This test should also detect refresh rate issues.
|
||||||
|
for (uint32_t i = 0; i < mem_size; i++) {
|
||||||
|
mem_base[i] = ((i % 2) ? pattern : antipattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < mem_size; i++) {
|
||||||
|
if (mem_base[i] != ((i % 2) ? pattern : antipattern)) {
|
||||||
|
snprintf(error_buffer, sizeof(error_buffer),
|
||||||
|
"Address bus slow test failed at 0x%p expected 0x%x found 0x%x",
|
||||||
|
&mem_base[i], ((i % 2) ? pattern : antipattern), mem_base[i]);
|
||||||
|
__fatal_error(error_buffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (__DCACHE_PRESENT == 1)
|
||||||
|
// Re-enable caches if they were enabled before the test started.
|
||||||
|
if (i_cache_disabled) {
|
||||||
|
SCB_EnableICache();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d_cache_disabled) {
|
||||||
|
SCB_EnableDCache();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __GNUC__ >= 11
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
36
ports/stm32/xspi_psram.h
Normal file
36
ports/stm32/xspi_psram.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023-2024 OpenMV, LLC.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Any redistribution, use, or modification in source or binary form
|
||||||
|
* is done solely for personal benefit and not for any commercial
|
||||||
|
* purpose or for monetary gain. For commercial licensing options,
|
||||||
|
* please contact openmv@openmv.io
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR OR COPYRIGHT
|
||||||
|
* OWNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* STM32 XSPI PSRAM driver.
|
||||||
|
*/
|
||||||
|
#ifndef __XSPI_PSRAM_H__
|
||||||
|
int xspi_psram_init();
|
||||||
|
bool xspi_psram_test(bool exhaustive);
|
||||||
|
#endif // __XSPI_PSRAM_H__
|
Loading…
Reference in New Issue
Block a user