From f72c4d75dee4aaa6e4a0013496861c08c0e61371 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Thu, 27 May 2021 20:07:49 +0200 Subject: [PATCH] Add RP2040 port and Pico and Nano board files. --- src/hal/cmsis/include/core_cm0plus.h | 1087 +++++++++++++++++ src/hal/cmsis/include/rpi/RP2040.h | 109 ++ src/hal/cmsis/include/rpi/system_RP2040.h | 65 + src/hal/cmsis/src/rpi/system_RP2040.c | 52 + src/micropython | 2 +- .../imlib_config.h | 153 +++ .../ARDUINO_NANO_RP2040_CONNECT/manifest.py | 3 + .../omv_boardconfig.cmake | 12 + .../omv_boardconfig.h | 191 +++ .../omv_boardconfig.mk | 1 + .../ARDUINO_NANO_RP2040_CONNECT/ulab_config.h | 12 + src/omv/boards/PICO/imlib_config.h | 153 +++ src/omv/boards/PICO/manifest.py | 2 + src/omv/boards/PICO/omv_boardconfig.cmake | 12 + src/omv/boards/PICO/omv_boardconfig.h | 192 +++ src/omv/boards/PICO/omv_boardconfig.mk | 1 + src/omv/boards/PICO/ulab_config.h | 12 + src/omv/ports/rp2/cambus.c | 145 +++ src/omv/ports/rp2/dcmi.pio | 57 + src/omv/ports/rp2/main.c | 326 +++++ src/omv/ports/rp2/modules/py_audio.c | 207 ++++ src/omv/ports/rp2/modules/py_audio.h | 14 + src/omv/ports/rp2/omv_portconfig.cmake | 253 ++++ src/omv/ports/rp2/omv_portconfig.h | 23 + src/omv/ports/rp2/omv_portconfig.mk | 31 + src/omv/ports/rp2/pdm.pio | 56 + src/omv/ports/rp2/rp2.ld.S | 265 ++++ src/omv/ports/rp2/sensor.c | 1077 ++++++++++++++++ 28 files changed, 4512 insertions(+), 1 deletion(-) create mode 100644 src/hal/cmsis/include/core_cm0plus.h create mode 100644 src/hal/cmsis/include/rpi/RP2040.h create mode 100644 src/hal/cmsis/include/rpi/system_RP2040.h create mode 100644 src/hal/cmsis/src/rpi/system_RP2040.c create mode 100644 src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/imlib_config.h create mode 100644 src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/manifest.py create mode 100644 src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/omv_boardconfig.cmake create mode 100644 src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/omv_boardconfig.h create mode 100755 src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/omv_boardconfig.mk create mode 100644 src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/ulab_config.h create mode 100644 src/omv/boards/PICO/imlib_config.h create mode 100644 src/omv/boards/PICO/manifest.py create mode 100644 src/omv/boards/PICO/omv_boardconfig.cmake create mode 100644 src/omv/boards/PICO/omv_boardconfig.h create mode 100755 src/omv/boards/PICO/omv_boardconfig.mk create mode 100644 src/omv/boards/PICO/ulab_config.h create mode 100644 src/omv/ports/rp2/cambus.c create mode 100644 src/omv/ports/rp2/dcmi.pio create mode 100644 src/omv/ports/rp2/main.c create mode 100644 src/omv/ports/rp2/modules/py_audio.c create mode 100644 src/omv/ports/rp2/modules/py_audio.h create mode 100644 src/omv/ports/rp2/omv_portconfig.cmake create mode 100644 src/omv/ports/rp2/omv_portconfig.h create mode 100644 src/omv/ports/rp2/omv_portconfig.mk create mode 100644 src/omv/ports/rp2/pdm.pio create mode 100644 src/omv/ports/rp2/rp2.ld.S create mode 100644 src/omv/ports/rp2/sensor.c diff --git a/src/hal/cmsis/include/core_cm0plus.h b/src/hal/cmsis/include/core_cm0plus.h new file mode 100644 index 000000000..4e7179a61 --- /dev/null +++ b/src/hal/cmsis/include/core_cm0plus.h @@ -0,0 +1,1087 @@ +/**************************************************************************//** + * @file core_cm0plus.h + * @brief CMSIS Cortex-M0+ Core Peripheral Access Layer Header File + * @version V5.0.9 + * @date 21. August 2019 + ******************************************************************************/ +/* + * Copyright (c) 2009-2019 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined (__clang__) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CM0PLUS_H_GENERIC +#define __CORE_CM0PLUS_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
+ Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
+ Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
+ Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup Cortex-M0+ + @{ + */ + +#include "cmsis_version.h" + +/* CMSIS CM0+ definitions */ +#define __CM0PLUS_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ +#define __CM0PLUS_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ +#define __CM0PLUS_CMSIS_VERSION ((__CM0PLUS_CMSIS_VERSION_MAIN << 16U) | \ + __CM0PLUS_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ + +#define __CORTEX_M (0U) /*!< Cortex-M Core */ + +/** __FPU_USED indicates whether an FPU is used or not. + This core does not support an FPU at all +*/ +#define __FPU_USED 0U + +#if defined ( __CC_ARM ) + #if defined __TARGET_FPU_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_FP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __ICCARM__ ) + #if defined __ARMVFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TI_ARM__ ) + #if defined __TI_VFP_SUPPORT__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TASKING__ ) + #if defined __FPU_VFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#endif + +#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM0PLUS_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_CM0PLUS_H_DEPENDANT +#define __CORE_CM0PLUS_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __CM0PLUS_REV + #define __CM0PLUS_REV 0x0000U + #warning "__CM0PLUS_REV not defined in device header file; using default!" + #endif + + #ifndef __MPU_PRESENT + #define __MPU_PRESENT 0U + #warning "__MPU_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __VTOR_PRESENT + #define __VTOR_PRESENT 0U + #warning "__VTOR_PRESENT not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 2U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group Cortex-M0+ */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + - Core MPU Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:28; /*!< bit: 0..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t _reserved1:3; /*!< bit: 25..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ + uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */ + uint32_t _reserved1:30; /*!< bit: 2..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +#define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ +#define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[1U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[31U]; + __IOM uint32_t ICER[1U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RESERVED1[31U]; + __IOM uint32_t ISPR[1U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[31U]; + __IOM uint32_t ICPR[1U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[31U]; + uint32_t RESERVED4[64U]; + __IOM uint32_t IP[8U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register */ +} NVIC_Type; + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) + __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ +#else + uint32_t RESERVED0; +#endif + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + uint32_t RESERVED1; + __IOM uint32_t SHP[2U]; /*!< Offset: 0x01C (R/W) System Handlers Priority Registers. [0] is RESERVED */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */ +#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) +/* SCB Interrupt Control State Register Definitions */ +#define SCB_VTOR_TBLOFF_Pos 8U /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0xFFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ +#endif + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */ +#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_MPU Memory Protection Unit (MPU) + \brief Type definitions for the Memory Protection Unit (MPU) + @{ + */ + +/** + \brief Structure type to access the Memory Protection Unit (MPU). + */ +typedef struct +{ + __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ + __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ + __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region RNRber Register */ + __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ + __IOM uint32_t RASR; /*!< Offset: 0x010 (R/W) MPU Region Attribute and Size Register */ +} MPU_Type; + +#define MPU_TYPE_RALIASES 1U + +/* MPU Type Register Definitions */ +#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ +#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ + +#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ +#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ + +#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ +#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ + +/* MPU Control Register Definitions */ +#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ +#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ + +#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ +#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ + +#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ +#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ + +/* MPU Region Number Register Definitions */ +#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ +#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ + +/* MPU Region Base Address Register Definitions */ +#define MPU_RBAR_ADDR_Pos 8U /*!< MPU RBAR: ADDR Position */ +#define MPU_RBAR_ADDR_Msk (0xFFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */ + +#define MPU_RBAR_VALID_Pos 4U /*!< MPU RBAR: VALID Position */ +#define MPU_RBAR_VALID_Msk (1UL << MPU_RBAR_VALID_Pos) /*!< MPU RBAR: VALID Mask */ + +#define MPU_RBAR_REGION_Pos 0U /*!< MPU RBAR: REGION Position */ +#define MPU_RBAR_REGION_Msk (0xFUL /*<< MPU_RBAR_REGION_Pos*/) /*!< MPU RBAR: REGION Mask */ + +/* MPU Region Attribute and Size Register Definitions */ +#define MPU_RASR_ATTRS_Pos 16U /*!< MPU RASR: MPU Region Attribute field Position */ +#define MPU_RASR_ATTRS_Msk (0xFFFFUL << MPU_RASR_ATTRS_Pos) /*!< MPU RASR: MPU Region Attribute field Mask */ + +#define MPU_RASR_XN_Pos 28U /*!< MPU RASR: ATTRS.XN Position */ +#define MPU_RASR_XN_Msk (1UL << MPU_RASR_XN_Pos) /*!< MPU RASR: ATTRS.XN Mask */ + +#define MPU_RASR_AP_Pos 24U /*!< MPU RASR: ATTRS.AP Position */ +#define MPU_RASR_AP_Msk (0x7UL << MPU_RASR_AP_Pos) /*!< MPU RASR: ATTRS.AP Mask */ + +#define MPU_RASR_TEX_Pos 19U /*!< MPU RASR: ATTRS.TEX Position */ +#define MPU_RASR_TEX_Msk (0x7UL << MPU_RASR_TEX_Pos) /*!< MPU RASR: ATTRS.TEX Mask */ + +#define MPU_RASR_S_Pos 18U /*!< MPU RASR: ATTRS.S Position */ +#define MPU_RASR_S_Msk (1UL << MPU_RASR_S_Pos) /*!< MPU RASR: ATTRS.S Mask */ + +#define MPU_RASR_C_Pos 17U /*!< MPU RASR: ATTRS.C Position */ +#define MPU_RASR_C_Msk (1UL << MPU_RASR_C_Pos) /*!< MPU RASR: ATTRS.C Mask */ + +#define MPU_RASR_B_Pos 16U /*!< MPU RASR: ATTRS.B Position */ +#define MPU_RASR_B_Msk (1UL << MPU_RASR_B_Pos) /*!< MPU RASR: ATTRS.B Mask */ + +#define MPU_RASR_SRD_Pos 8U /*!< MPU RASR: Sub-Region Disable Position */ +#define MPU_RASR_SRD_Msk (0xFFUL << MPU_RASR_SRD_Pos) /*!< MPU RASR: Sub-Region Disable Mask */ + +#define MPU_RASR_SIZE_Pos 1U /*!< MPU RASR: Region Size Field Position */ +#define MPU_RASR_SIZE_Msk (0x1FUL << MPU_RASR_SIZE_Pos) /*!< MPU RASR: Region Size Field Mask */ + +#define MPU_RASR_ENABLE_Pos 0U /*!< MPU RASR: Region enable bit Position */ +#define MPU_RASR_ENABLE_Msk (1UL /*<< MPU_RASR_ENABLE_Pos*/) /*!< MPU RASR: Region enable bit Disable Mask */ + +/*@} end of group CMSIS_MPU */ +#endif + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief Cortex-M0+ Core Debug Registers (DCB registers, SHCSR, and DFSR) are only accessible over DAP and not via processor. + Therefore they are not covered by the Cortex-M0+ header file. + @{ + */ +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. This parameter is interpreted as an uint32_t type. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of Core Hardware */ +#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ +#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ +#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ +#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + +#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ +#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ +#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ + #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ +#endif + +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +#ifdef CMSIS_NVIC_VIRTUAL + #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE + #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" + #endif + #include CMSIS_NVIC_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping + #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping + #define NVIC_EnableIRQ __NVIC_EnableIRQ + #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ + #define NVIC_DisableIRQ __NVIC_DisableIRQ + #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ + #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ + #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ +/*#define NVIC_GetActive __NVIC_GetActive not available for Cortex-M0+ */ + #define NVIC_SetPriority __NVIC_SetPriority + #define NVIC_GetPriority __NVIC_GetPriority + #define NVIC_SystemReset __NVIC_SystemReset +#endif /* CMSIS_NVIC_VIRTUAL */ + +#ifdef CMSIS_VECTAB_VIRTUAL + #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE + #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" + #endif + #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE +#else + #define NVIC_SetVector __NVIC_SetVector + #define NVIC_GetVector __NVIC_GetVector +#endif /* (CMSIS_VECTAB_VIRTUAL) */ + +#define NVIC_USER_IRQ_OFFSET 16 + + +/* The following EXC_RETURN values are saved the LR on exception entry */ +#define EXC_RETURN_HANDLER (0xFFFFFFF1UL) /* return to Handler mode, uses MSP after return */ +#define EXC_RETURN_THREAD_MSP (0xFFFFFFF9UL) /* return to Thread mode, uses MSP after return */ +#define EXC_RETURN_THREAD_PSP (0xFFFFFFFDUL) /* return to Thread mode, uses PSP after return */ + + +/* Interrupt Priorities are WORD accessible only under Armv6-M */ +/* The following MACROS handle generation of the register offset and byte masks */ +#define _BIT_SHIFT(IRQn) ( ((((uint32_t)(int32_t)(IRQn)) ) & 0x03UL) * 8UL) +#define _SHP_IDX(IRQn) ( (((((uint32_t)(int32_t)(IRQn)) & 0x0FUL)-8UL) >> 2UL) ) +#define _IP_IDX(IRQn) ( (((uint32_t)(int32_t)(IRQn)) >> 2UL) ) + +#define __NVIC_SetPriorityGrouping(X) (void)(X) +#define __NVIC_GetPriorityGrouping() (0U) + +/** + \brief Enable Interrupt + \details Enables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + __COMPILER_BARRIER(); + NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __COMPILER_BARRIER(); + } +} + + +/** + \brief Get Interrupt Enable status + \details Returns a device specific interrupt enable status from the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt is not enabled. + \return 1 Interrupt is enabled. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[0U] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Disable Interrupt + \details Disables a device specific interrupt in the NVIC interrupt controller. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } +} + + +/** + \brief Get Pending Interrupt + \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. + \param [in] IRQn Device specific interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + \note IRQn must not be negative. + */ +__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of a device specific interrupt in the NVIC pending register. + \param [in] IRQn Device specific interrupt number. + \note IRQn must not be negative. + */ +__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + } +} + + +/** + \brief Set Interrupt Priority + \details Sets the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + \note The priority cannot be set for every processor exception. + */ +__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } + else + { + SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of a device specific interrupt or a processor exception. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief Encode Priority + \details Encodes the priority for an interrupt with the given priority group, + preemptive priority value, and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. + \param [in] PriorityGroup Used priority group. + \param [in] PreemptPriority Preemptive priority value (starting from 0). + \param [in] SubPriority Subpriority value (starting from 0). + \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). + */ +__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + return ( + ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | + ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) + ); +} + + +/** + \brief Decode Priority + \details Decodes an interrupt priority value with a given priority group to + preemptive priority value and subpriority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). + \param [in] PriorityGroup Used priority group. + \param [out] pPreemptPriority Preemptive priority value (starting from 0). + \param [out] pSubPriority Subpriority value (starting from 0). + */ +__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); + SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); + + *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); + *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); +} + + +/** + \brief Set Interrupt Vector + \details Sets an interrupt vector in SRAM based interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + VTOR must been relocated to SRAM before. + If VTOR is not present address 0 must be mapped to SRAM. + \param [in] IRQn Interrupt number + \param [in] vector Address of interrupt handler function + */ +__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) + uint32_t *vectors = (uint32_t *)SCB->VTOR; + vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET] = vector; +#else + uint32_t *vectors = (uint32_t *)(NVIC_USER_IRQ_OFFSET << 2); /* point to 1st user interrupt */ + *(vectors + (int32_t)IRQn) = vector; /* use pointer arithmetic to access vector */ +#endif + /* ARM Application Note 321 states that the M0+ does not require the architectural barrier */ +} + + +/** + \brief Get Interrupt Vector + \details Reads an interrupt vector from interrupt vector table. + The interrupt number can be positive to specify a device specific interrupt, + or negative to specify a processor exception. + \param [in] IRQn Interrupt number. + \return Address of interrupt handler function + */ +__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) +{ +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) + uint32_t *vectors = (uint32_t *)SCB->VTOR; + return vectors[(int32_t)IRQn + NVIC_USER_IRQ_OFFSET]; +#else + uint32_t *vectors = (uint32_t *)(NVIC_USER_IRQ_OFFSET << 2); /* point to 1st user interrupt */ + return *(vectors + (int32_t)IRQn); /* use pointer arithmetic to access vector */ +#endif +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + SCB_AIRCR_SYSRESETREQ_Msk); + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +/*@} end of CMSIS_Core_NVICFunctions */ + +/* ########################## MPU functions #################################### */ + +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) + +#include "mpu_armv7.h" + +#endif + +/* ########################## FPU functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_FpuFunctions FPU Functions + \brief Function that provides FPU type. + @{ + */ + +/** + \brief get FPU type + \details returns the FPU type + \returns + - \b 0: No FPU + - \b 1: Single precision FPU + - \b 2: Double + Single precision FPU + */ +__STATIC_INLINE uint32_t SCB_GetFPUType(void) +{ + return 0U; /* No FPU */ +} + + +/*@} end of CMSIS_Core_FpuFunctions */ + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM0PLUS_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/src/hal/cmsis/include/rpi/RP2040.h b/src/hal/cmsis/include/rpi/RP2040.h new file mode 100644 index 000000000..a29b9e095 --- /dev/null +++ b/src/hal/cmsis/include/rpi/RP2040.h @@ -0,0 +1,109 @@ +/*************************************************************************//** + * @file RP2040.h + * @brief CMSIS-Core(M) Device Peripheral Access Layer Header File for + * Device RP2040 + * @version V1.0.0 + * @date 5. May 2021 + *****************************************************************************/ +/* + * Copyright (c) 2009-2021 Arm Limited. All rights reserved. + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _CMSIS_RP2040_H_ +#define _CMSIS_RP2040_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* =========================================================================================================================== */ +/* ================ Interrupt Number Definition ================ */ +/* =========================================================================================================================== */ + +typedef enum +{ + /* ======================================= ARM Cortex-M0+ Specific Interrupt Numbers ======================================= */ + Reset_IRQn = -15, /*!< -15 Reset Vector, invoked on Power up and warm reset */ + NonMaskableInt_IRQn = -14, /*!< -14 Non maskable Interrupt, cannot be stopped or preempted */ + HardFault_IRQn = -13, /*!< -13 Hard Fault, all classes of Fault */ + SVCall_IRQn = -5, /*!< -5 System Service Call via SVC instruction */ + PendSV_IRQn = -2, /*!< -2 Pendable request for system service */ + SysTick_IRQn = -1, /*!< -1 System Tick Timer */ + /* =========================================== RP2040 Specific Interrupt Numbers =========================================== */ + TIMER_IRQ_0_IRQn = 0, /*!< 0 TIMER_IRQ_0 */ + TIMER_IRQ_1_IRQn = 1, /*!< 1 TIMER_IRQ_1 */ + TIMER_IRQ_2_IRQn = 2, /*!< 2 TIMER_IRQ_2 */ + TIMER_IRQ_3_IRQn = 3, /*!< 3 TIMER_IRQ_3 */ + PWM_IRQ_WRAP_IRQn = 4, /*!< 4 PWM_IRQ_WRAP */ + USBCTRL_IRQ_IRQn = 5, /*!< 5 USBCTRL_IRQ */ + XIP_IRQ_IRQn = 6, /*!< 6 XIP_IRQ */ + PIO0_IRQ_0_IRQn = 7, /*!< 7 PIO0_IRQ_0 */ + PIO0_IRQ_1_IRQn = 8, /*!< 8 PIO0_IRQ_1 */ + PIO1_IRQ_0_IRQn = 9, /*!< 9 PIO1_IRQ_0 */ + PIO1_IRQ_1_IRQn = 10, /*!< 10 PIO1_IRQ_1 */ + DMA_IRQ_0_IRQn = 11, /*!< 11 DMA_IRQ_0 */ + DMA_IRQ_1_IRQn = 12, /*!< 12 DMA_IRQ_1 */ + IO_IRQ_BANK0_IRQn = 13, /*!< 13 IO_IRQ_BANK0 */ + IO_IRQ_QSPI_IRQn = 14, /*!< 14 IO_IRQ_QSPI */ + SIO_IRQ_PROC0_IRQn = 15, /*!< 15 SIO_IRQ_PROC0 */ + SIO_IRQ_PROC1_IRQn = 16, /*!< 16 SIO_IRQ_PROC1 */ + CLOCKS_IRQ_IRQn = 17, /*!< 17 CLOCKS_IRQ */ + SPI0_IRQ_IRQn = 18, /*!< 18 SPI0_IRQ */ + SPI1_IRQ_IRQn = 19, /*!< 19 SPI1_IRQ */ + UART0_IRQ_IRQn = 20, /*!< 20 UART0_IRQ */ + UART1_IRQ_IRQn = 21, /*!< 21 UART1_IRQ */ + ADC_IRQ_FIFO_IRQn = 22, /*!< 22 ADC_IRQ_FIFO */ + I2C0_IRQ_IRQn = 23, /*!< 23 I2C0_IRQ */ + I2C1_IRQ_IRQn = 24, /*!< 24 I2C1_IRQ */ + RTC_IRQ_IRQn = 25 /*!< 25 RTC_IRQ */ +} IRQn_Type; + +/* =========================================================================================================================== */ +/* ================ Processor and Core Peripheral Section ================ */ +/* =========================================================================================================================== */ + +/* ========================== Configuration of the ARM Cortex-M0+ Processor and Core Peripherals =========================== */ +#define __CM0PLUS_REV 0x0001U /*!< CM0PLUS Core Revision */ +#define __NVIC_PRIO_BITS 2 /*!< Number of Bits used for Priority Levels */ +#define __Vendor_SysTickConfig 0 /*!< Set to 1 if different SysTick Config is used */ +#define __VTOR_PRESENT 1 /*!< Set to 1 if CPU supports Vector Table Offset Register */ +#define __MPU_PRESENT 1 /*!< MPU present */ +#define __FPU_PRESENT 0 /*!< FPU present */ + +/** @} */ /* End of group Configuration_of_CMSIS */ + +#include "core_cm0plus.h" /*!< ARM Cortex-M0+ processor and core peripherals */ +#include "system_RP2040.h" /*!< RP2040 System */ + +#ifndef __IM /*!< Fallback for older CMSIS versions */ +#define __IM __I +#endif +#ifndef __OM /*!< Fallback for older CMSIS versions */ +#define __OM __O +#endif +#ifndef __IOM /*!< Fallback for older CMSIS versions */ +#define __IOM __IO +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _CMSIS_RP2040_H */ diff --git a/src/hal/cmsis/include/rpi/system_RP2040.h b/src/hal/cmsis/include/rpi/system_RP2040.h new file mode 100644 index 000000000..30881ccc6 --- /dev/null +++ b/src/hal/cmsis/include/rpi/system_RP2040.h @@ -0,0 +1,65 @@ +/*************************************************************************//** + * @file system_RP2040.h + * @brief CMSIS-Core(M) Device Peripheral Access Layer Header File for + * Device RP2040 + * @version V1.0.0 + * @date 5. May 2021 + *****************************************************************************/ +/* + * Copyright (c) 2009-2021 Arm Limited. All rights reserved. + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _CMSIS_SYSTEM_RP2040_H +#define _CMSIS_SYSTEM_RP2040_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + \brief Exception / Interrupt Handler Function Prototype +*/ +typedef void(*VECTOR_TABLE_Type)(void); + +/** + \brief System Clock Frequency (Core Clock) +*/ +extern uint32_t SystemCoreClock; + +/** + \brief Setup the microcontroller system. + + Initialize the System and update the SystemCoreClock variable. + */ +extern void SystemInit (void); + + +/** + \brief Update SystemCoreClock variable. + + Updates the SystemCoreClock with current core Clock retrieved from cpu registers. + */ +extern void SystemCoreClockUpdate (void); + +#ifdef __cplusplus +} +#endif + +#endif /* _CMSIS_SYSTEM_RP2040_H */ diff --git a/src/hal/cmsis/src/rpi/system_RP2040.c b/src/hal/cmsis/src/rpi/system_RP2040.c new file mode 100644 index 000000000..055a0752c --- /dev/null +++ b/src/hal/cmsis/src/rpi/system_RP2040.c @@ -0,0 +1,52 @@ +/*************************************************************************//** + * @file system_RP2040.c + * @brief CMSIS-Core(M) Device Peripheral Access Layer Header File for + * Device RP2040 + * @version V1.0.0 + * @date 5. May 2021 + *****************************************************************************/ +/* + * Copyright (c) 2009-2021 Arm Limited. All rights reserved. + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "RP2040.h" +#include "hardware/clocks.h" + +/*--------------------------------------------------------------------------- + System Core Clock Variable + *---------------------------------------------------------------------------*/ +uint32_t SystemCoreClock; /* System Clock Frequency (Core Clock)*/ + +/*--------------------------------------------------------------------------- + System Core Clock function + *---------------------------------------------------------------------------*/ +void SystemCoreClockUpdate (void) +{ + SystemCoreClock = clock_get_hz(clk_sys); +} + +/*--------------------------------------------------------------------------- + System initialization function + *---------------------------------------------------------------------------*/ +void __attribute__((constructor)) SystemInit (void) +{ + SystemCoreClockUpdate(); +} \ No newline at end of file diff --git a/src/micropython b/src/micropython index b814ad51d..750d095c0 160000 --- a/src/micropython +++ b/src/micropython @@ -1 +1 @@ -Subproject commit b814ad51d6b51b94fb7dab01dc111d5053d98a82 +Subproject commit 750d095c0d0790e988a0047e992a54a43bf45d2c diff --git a/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/imlib_config.h b/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/imlib_config.h new file mode 100644 index 000000000..9f27e2ec7 --- /dev/null +++ b/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/imlib_config.h @@ -0,0 +1,153 @@ +/* + * This file is part of the OpenMV project. + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * 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 +// Not filesystem yet +//#define IMLIB_ENABLE_IMAGE_FILE_IO + +// Enable LAB LUT +//#define IMLIB_ENABLE_LAB_LUT + +// Enable YUV LUT +//#define IMLIB_ENABLE_YUV_LUT + +// Enable mean pooling +//#define IMLIB_ENABLE_MEAN_POOLING + +// Enable midpoint pooling +//#define IMLIB_ENABLE_MIDPOINT_POOLING + +// 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 cartoon() +// #define IMLIB_ENABLE_CARTOON + +// 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 + +// 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 CMSIS NN +// #if !defined(CUBEAI) +// #define IMLIB_ENABLE_CNN +// #endif + +// Enable Tensor Flow +#if !defined(CUBEAI) +//#define IMLIB_ENABLE_TF +#endif + +// Enable FAST (20+ KBs). +// #define IMLIB_ENABLE_FAST + +// Enable find_template() +//#define IMLIB_FIND_TEMPLATE + +// Enable find_lbp() +//#define IMLIB_ENABLE_FIND_LBP + +// Enable find_keypoints() +//#define IMLIB_ENABLE_FIND_KEYPOINTS + +// 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 STM32 DMA2D +//#define IMLIB_ENABLE_DMA2D + +#endif //__IMLIB_CONFIG_H__ diff --git a/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/manifest.py b/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/manifest.py new file mode 100644 index 000000000..138aa580f --- /dev/null +++ b/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/manifest.py @@ -0,0 +1,3 @@ +freeze ("$(PORT_DIR)/modules") +include("$(MPY_DIR)/extmod/uasyncio/manifest.py") +freeze ("$(MPY_LIB_DIR)/", "lsm6dsox.py") diff --git a/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/omv_boardconfig.cmake b/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/omv_boardconfig.cmake new file mode 100644 index 000000000..26a2df4cb --- /dev/null +++ b/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/omv_boardconfig.cmake @@ -0,0 +1,12 @@ +set(MICROPY_PY_SENSOR 0) +set(MICROPY_PY_ULAB 1) +set(MICROPY_PY_WINC1500 0) +set(MICROPY_PY_LWIP 0) +set(MICROPY_PY_NETWORK_CYW43 0) +set(MICROPY_PY_BLUETOOTH 0) +set(MICROPY_BLUETOOTH_NIMBLE 0) +set(MICROPY_PY_AUDIO 1) +set(MICROPY_PY_MICRO_SPEECH 0) +set(MICROPY_PY_LCD 0) +set(MICROPY_PY_TV 0) +set(MICROPY_PY_BUZZER 0) diff --git a/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/omv_boardconfig.h b/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/omv_boardconfig.h new file mode 100644 index 000000000..37ac0af85 --- /dev/null +++ b/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/omv_boardconfig.h @@ -0,0 +1,191 @@ +/* + * This file is part of the OpenMV project. + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * 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_ARCH_STR "PICO M0" // 33 chars max +#define OMV_BOARD_TYPE "PICO" + +#ifndef LINKER_SCRIPT +extern unsigned char *OMV_UNIQUE_ID_ADDR; +#endif +#define OMV_UNIQUE_ID_SIZE 2 // 2 words + +#define OMV_XCLK_MCO (0U) +#define OMV_XCLK_TIM (1U) + +// Sensor external clock source. +#define OMV_XCLK_SOURCE (OMV_XCLK_TIM) + +// Sensor external clock timer frequency. +// TODO Not actually used right now, frequency is hardcoded. +#define OMV_XCLK_FREQUENCY (12500000) + +// RAW buffer size +#define OMV_RAW_BUF_SIZE (151*1024) + +// Enable hardware JPEG +#define OMV_HARDWARE_JPEG (0) + +// Enable sensor drivers +#define OMV_ENABLE_OV2640 (0) +#define OMV_ENABLE_OV5640 (0) +#define OMV_ENABLE_OV7670 (1) +#define OMV_ENABLE_OV7690 (0) +#define OMV_ENABLE_OV7725 (0) +#define OMV_ENABLE_OV9650 (0) +#define OMV_ENABLE_MT9V034 (0) +#define OMV_ENABLE_LEPTON (0) +#define OMV_ENABLE_HM01B0 (0) + +// Set which OV767x sensor is used +#define OMV_OV7670_VERSION (70) + +// OV7670 clock divider +#define OMV_OV7670_CLKRC (0x00) + +// FIR Module +#define OMV_ENABLE_FIR_MLX90621 (0) +#define OMV_ENABLE_FIR_MLX90640 (0) +#define OMV_ENABLE_FIR_MLX90641 (0) +#define OMV_ENABLE_FIR_AMG8833 (1) +#define OMV_ENABLE_FIR_LEPTON (0) + +// Enable sensor features +#define OMV_ENABLE_OV5640_AF (0) + +// Enable WiFi debug +#define OMV_ENABLE_WIFIDBG (0) + +// Enable self-tests on first boot +#define OMV_ENABLE_SELFTEST (0) + +// If buffer size is bigger than this threshold, the quality is reduced. +// This is only used for JPEG images sent to the IDE not normal compression. +#define JPEG_QUALITY_THRESH (160*120) + +// Low and high JPEG QS. +#define JPEG_QUALITY_LOW 35 +#define JPEG_QUALITY_HIGH 60 + +// FB Heap Block Size +#define OMV_UMM_BLOCK_SIZE 16 + +// Core VBAT for selftests +#define OMV_CORE_VBAT "3.3" + +// USB IRQn. +#define OMV_USB_IRQN (USBCTRL_IRQ_IRQn) + +// Linker script constants (see the linker script template port/x.ld.S). +#define OMV_FB_MEMORY RAM // Framebuffer, fb_alloc +#define OMV_MAIN_MEMORY RAM // data, bss and heap memory +#define OMV_STACK_MEMORY RAM // stack memory + +#define OMV_FB_SIZE (151K) // FB memory: header + QVGA/GS image +#define OMV_FB_ALLOC_SIZE (12K) // minimum fb alloc size +#define OMV_STACK_SIZE (8K) +#define OMV_HEAP_SIZE (32 * 1024) // MicroPython's heap +#define OMV_JPEG_BUF_SIZE (20 * 1024) // IDE JPEG buffer (header + data). + +// GP LED +#define LED_PIN (6) + +// FIR I2C +#define FIR_I2C_ID (0) +#define FIR_I2C_SCL_PIN (27) +#define FIR_I2C_SDA_PIN (26) +#define FIR_I2C_SPEED (CAMBUS_SPEED_FULL) + +// ISC I2C +#define ISC_I2C_ID (0) +#define ISC_I2C_SCL_PIN (27) +#define ISC_I2C_SDA_PIN (26) +#define ISC_I2C_SPEED (CAMBUS_SPEED_STANDARD) + +// I2C0 +#define I2C0_ID (0) +#define I2C0_SCL_PIN (27) +#define I2C0_SDA_PIN (26) +#define I2C0_SPEED (CAMBUS_SPEED_FULL) + +// I2C1 +#define I2C1_ID (1) +#define I2C1_SCL_PIN (7) +#define I2C1_SDA_PIN (6) +#define I2C1_SPEED (CAMBUS_SPEED_FULL) + +#define LCD_SPI (spi0) +#define LCD_MOSI_PIN (7) +#define LCD_SCLK_PIN (6) + +#define LCD_RST_PIN (4) +#define LCD_RST_PIN_WRITE(bit) gpio_put(LCD_RST_PIN, bit); + +#define LCD_RS_PIN (25) +#define LCD_RS_PIN_WRITE(bit) gpio_put(LCD_RS_PIN, bit); + +#define LCD_CS_PIN (5) +#define LCD_CS_PIN_WRITE(bit) gpio_put(LCD_CS_PIN, bit); + +// AUDIO config. +#define PDM_PIO (pio1) +#define PDM_SM (0) +#define PDM_DMA (1) +#define PDM_DMA_IRQ (DMA_IRQ_1) +#define PDM_DMA_CHANNEL (0) + +#define PDM_CLK_PIN (23) +#define PDM_DIN_PIN (22) + +// DCMI config. +#define DCMI_PIO (pio0) +#define DCMI_SM (0) +#define DCMI_DMA (0) +#define DCMI_DMA_IRQ (DMA_IRQ_0) +#define DCMI_DMA_CHANNEL (0) + +#define DCMI_PWDN_PIN (0) +#define DCMI_RESET_PIN (1) + +#define DCMI_D0_PIN (15) +#define DCMI_D1_PIN (16) +#define DCMI_D2_PIN (17) +#define DCMI_D3_PIN (18) +#define DCMI_D4_PIN (19) +#define DCMI_D5_PIN (20) +#define DCMI_D6_PIN (21) +#define DCMI_D7_PIN (22) // This pin is missing + +#define DCMI_XCLK_PIN (28) + +#define DCMI_PXCLK_PIN (29) +#define DCMI_HSYNC_PIN (12) +#define DCMI_VSYNC_PIN (13) + +#if defined(DCMI_RESET_PIN) +#define DCMI_RESET_LOW() gpio_put(DCMI_RESET_PIN, 0) +#define DCMI_RESET_HIGH() gpio_put(DCMI_RESET_PIN, 1) +#else +#define DCMI_RESET_LOW() +#define DCMI_RESET_HIGH() +#endif + +#if defined(DCMI_PWDN_PIN) +#define DCMI_PWDN_LOW() gpio_put(DCMI_PWDN_PIN, 0) +#define DCMI_PWDN_HIGH() gpio_put(DCMI_PWDN_PIN, 1) +#else +#define DCMI_PWDN_LOW() +#define DCMI_PWDN_HIGH() +#endif + +#endif //__OMV_BOARDCONFIG_H__ diff --git a/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/omv_boardconfig.mk b/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/omv_boardconfig.mk new file mode 100755 index 000000000..7d62f97c9 --- /dev/null +++ b/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/omv_boardconfig.mk @@ -0,0 +1 @@ +PORT=rp2 diff --git a/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/ulab_config.h b/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/ulab_config.h new file mode 100644 index 000000000..21f758a2f --- /dev/null +++ b/src/omv/boards/ARDUINO_NANO_RP2040_CONNECT/ulab_config.h @@ -0,0 +1,12 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013-2016 Kwabena W. Agyeman + * 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. +#endif //__ULAB_CONFIG_H__ diff --git a/src/omv/boards/PICO/imlib_config.h b/src/omv/boards/PICO/imlib_config.h new file mode 100644 index 000000000..9f27e2ec7 --- /dev/null +++ b/src/omv/boards/PICO/imlib_config.h @@ -0,0 +1,153 @@ +/* + * This file is part of the OpenMV project. + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * 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 +// Not filesystem yet +//#define IMLIB_ENABLE_IMAGE_FILE_IO + +// Enable LAB LUT +//#define IMLIB_ENABLE_LAB_LUT + +// Enable YUV LUT +//#define IMLIB_ENABLE_YUV_LUT + +// Enable mean pooling +//#define IMLIB_ENABLE_MEAN_POOLING + +// Enable midpoint pooling +//#define IMLIB_ENABLE_MIDPOINT_POOLING + +// 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 cartoon() +// #define IMLIB_ENABLE_CARTOON + +// 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 + +// 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 CMSIS NN +// #if !defined(CUBEAI) +// #define IMLIB_ENABLE_CNN +// #endif + +// Enable Tensor Flow +#if !defined(CUBEAI) +//#define IMLIB_ENABLE_TF +#endif + +// Enable FAST (20+ KBs). +// #define IMLIB_ENABLE_FAST + +// Enable find_template() +//#define IMLIB_FIND_TEMPLATE + +// Enable find_lbp() +//#define IMLIB_ENABLE_FIND_LBP + +// Enable find_keypoints() +//#define IMLIB_ENABLE_FIND_KEYPOINTS + +// 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 STM32 DMA2D +//#define IMLIB_ENABLE_DMA2D + +#endif //__IMLIB_CONFIG_H__ diff --git a/src/omv/boards/PICO/manifest.py b/src/omv/boards/PICO/manifest.py new file mode 100644 index 000000000..442ba7b04 --- /dev/null +++ b/src/omv/boards/PICO/manifest.py @@ -0,0 +1,2 @@ +freeze ("$(PORT_DIR)/modules") +include("$(MPY_DIR)/extmod/uasyncio/manifest.py") diff --git a/src/omv/boards/PICO/omv_boardconfig.cmake b/src/omv/boards/PICO/omv_boardconfig.cmake new file mode 100644 index 000000000..2d06228cc --- /dev/null +++ b/src/omv/boards/PICO/omv_boardconfig.cmake @@ -0,0 +1,12 @@ +set(MICROPY_PY_SENSOR 1) +set(MICROPY_PY_ULAB 1) +set(MICROPY_PY_WINC1500 0) +set(MICROPY_PY_LWIP 0) +set(MICROPY_PY_NETWORK_CYW43 0) +set(MICROPY_PY_BLUETOOTH 0) +set(MICROPY_BLUETOOTH_NIMBLE 0) +set(MICROPY_PY_AUDIO 0) +set(MICROPY_PY_MICRO_SPEECH 0) +set(MICROPY_PY_LCD 0) +set(MICROPY_PY_TV 0) +set(MICROPY_PY_BUZZER 0) diff --git a/src/omv/boards/PICO/omv_boardconfig.h b/src/omv/boards/PICO/omv_boardconfig.h new file mode 100644 index 000000000..83eafbb32 --- /dev/null +++ b/src/omv/boards/PICO/omv_boardconfig.h @@ -0,0 +1,192 @@ +/* + * This file is part of the OpenMV project. + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * 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_ARCH_STR "PICO M0" // 33 chars max +#define OMV_BOARD_TYPE "PICO" + +#ifndef LINKER_SCRIPT +extern unsigned char *OMV_UNIQUE_ID_ADDR; +#endif +#define OMV_UNIQUE_ID_SIZE 2 // 2 words + +#define OMV_XCLK_MCO (0U) +#define OMV_XCLK_TIM (1U) + +// Sensor external clock source. +#define OMV_XCLK_SOURCE (OMV_XCLK_TIM) + +// Sensor external clock timer frequency. +// TODO Not actually used right now, frequency is hardcoded. +#define OMV_XCLK_FREQUENCY (12500000) + +// RAW buffer size +#define OMV_RAW_BUF_SIZE (151*1024) + +// Enable hardware JPEG +#define OMV_HARDWARE_JPEG (0) + +// Enable sensor drivers +#define OMV_ENABLE_OV2640 (0) +#define OMV_ENABLE_OV5640 (0) +#define OMV_ENABLE_OV7670 (1) +#define OMV_ENABLE_OV7690 (0) +#define OMV_ENABLE_OV7725 (0) +#define OMV_ENABLE_OV9650 (0) +#define OMV_ENABLE_MT9V034 (0) +#define OMV_ENABLE_LEPTON (0) +#define OMV_ENABLE_HM01B0 (0) + +// Set which OV767x sensor is used +#define OMV_OV7670_VERSION (70) + +// OV7670 clock divider +#define OMV_OV7670_CLKRC (0x00) + +// FIR Module +#define OMV_ENABLE_FIR_MLX90621 (0) +#define OMV_ENABLE_FIR_MLX90640 (0) +#define OMV_ENABLE_FIR_MLX90641 (0) +#define OMV_ENABLE_FIR_AMG8833 (1) +#define OMV_ENABLE_FIR_LEPTON (0) + +// Enable sensor features +#define OMV_ENABLE_OV5640_AF (0) + +// Enable WiFi debug +#define OMV_ENABLE_WIFIDBG (0) + +// Enable self-tests on first boot +#define OMV_ENABLE_SELFTEST (0) + +// If buffer size is bigger than this threshold, the quality is reduced. +// This is only used for JPEG images sent to the IDE not normal compression. +#define JPEG_QUALITY_THRESH (160*120) + +// Low and high JPEG QS. +#define JPEG_QUALITY_LOW 35 +#define JPEG_QUALITY_HIGH 60 + +// FB Heap Block Size +#define OMV_UMM_BLOCK_SIZE 16 + +// Core VBAT for selftests +#define OMV_CORE_VBAT "3.3" + +// USB IRQn. +#define OMV_USB_IRQN (USBCTRL_IRQ_IRQn) + +// Linker script constants (see the linker script template port/x.ld.S). +#define OMV_FB_MEMORY RAM // Framebuffer, fb_alloc +#define OMV_MAIN_MEMORY RAM // data, bss and heap memory +#define OMV_STACK_MEMORY RAM // stack memory + +#define OMV_FB_SIZE (151K) // FB memory: header + QVGA/GS image +#define OMV_FB_ALLOC_SIZE (12K) // minimum fb alloc size +#define OMV_STACK_SIZE (8K) +#define OMV_HEAP_SIZE (32 * 1024) // MicroPython's heap +#define OMV_JPEG_BUF_SIZE (20 * 1024) // IDE JPEG buffer (header + data). + +// GP LED +#define LED_PIN (25) + +// FIR I2C +#define FIR_I2C_ID (0) +#define FIR_I2C_SCL_PIN (27) +#define FIR_I2C_SDA_PIN (26) +#define FIR_I2C_SPEED (CAMBUS_SPEED_FULL) + +// ISC I2C +#define ISC_I2C_ID (1) +#define ISC_I2C_SCL_PIN (15) +#define ISC_I2C_SDA_PIN (14) +#define ISC_I2C_SPEED (CAMBUS_SPEED_STANDARD) + +// I2C0 +#define I2C0_ID (0) +#define I2C0_SCL_PIN (27) +#define I2C0_SDA_PIN (26) +#define I2C0_SPEED (CAMBUS_SPEED_FULL) + +// I2C1 +#define I2C1_ID (1) +#define I2C1_SCL_PIN (15) +#define I2C1_SDA_PIN (14) +#define I2C1_SPEED (CAMBUS_SPEED_FULL) + +#define LCD_SPI (spi0) +#define LCD_MOSI_PIN (19) +#define LCD_SCLK_PIN (18) + +#define LCD_RST_PIN (20) +#define LCD_RST_PIN_WRITE(bit) gpio_put(LCD_RST_PIN, bit); + +#define LCD_RS_PIN (21) +#define LCD_RS_PIN_WRITE(bit) gpio_put(LCD_RS_PIN, bit); + +#define LCD_CS_PIN (17) +#define LCD_CS_PIN_WRITE(bit) gpio_put(LCD_CS_PIN, bit); + +// AUDIO config. +//#define PDM_PIO (pio1) +//#define PDM_SM (0) +//#define PDM_DMA (1) +//#define PDM_DMA_IRQ (DMA_IRQ_1) +//#define PDM_DMA_CHANNEL (0) +// +//#define PDM_CLK_PIN (23) +//#define PDM_DIN_PIN (22) + +// DCMI config. +#define DCMI_PIO (pio0) +#define DCMI_SM (0) +#define DCMI_DMA (0) +#define DCMI_DMA_IRQ (DMA_IRQ_0) +#define DCMI_DMA_CHANNEL (0) + +#define DCMI_PWDN_PIN (0) +#define DCMI_RESET_PIN (1) + +#define DCMI_D0_PIN (2) +#define DCMI_D1_PIN (3) +#define DCMI_D2_PIN (4) +#define DCMI_D3_PIN (5) +#define DCMI_D4_PIN (6) +#define DCMI_D5_PIN (7) +#define DCMI_D6_PIN (8) +#define DCMI_D7_PIN (9) + +// TODO: These are hard-coded in dcmi.pio need to fix. +#define DCMI_PXCLK_PIN (11) +#define DCMI_HSYNC_PIN (12) +#define DCMI_VSYNC_PIN (13) + +#define DCMI_XCLK_PIN (10) + +#if defined(DCMI_RESET_PIN) +#define DCMI_RESET_LOW() gpio_put(DCMI_RESET_PIN, 0) +#define DCMI_RESET_HIGH() gpio_put(DCMI_RESET_PIN, 1) +#else +#define DCMI_RESET_LOW() +#define DCMI_RESET_HIGH() +#endif + +#if defined(DCMI_PWDN_PIN) +#define DCMI_PWDN_LOW() gpio_put(DCMI_PWDN_PIN, 0) +#define DCMI_PWDN_HIGH() gpio_put(DCMI_PWDN_PIN, 1) +#else +#define DCMI_PWDN_LOW() +#define DCMI_PWDN_HIGH() +#endif + +#endif //__OMV_BOARDCONFIG_H__ diff --git a/src/omv/boards/PICO/omv_boardconfig.mk b/src/omv/boards/PICO/omv_boardconfig.mk new file mode 100755 index 000000000..7d62f97c9 --- /dev/null +++ b/src/omv/boards/PICO/omv_boardconfig.mk @@ -0,0 +1 @@ +PORT=rp2 diff --git a/src/omv/boards/PICO/ulab_config.h b/src/omv/boards/PICO/ulab_config.h new file mode 100644 index 000000000..21f758a2f --- /dev/null +++ b/src/omv/boards/PICO/ulab_config.h @@ -0,0 +1,12 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013-2016 Kwabena W. Agyeman + * 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. +#endif //__ULAB_CONFIG_H__ diff --git a/src/omv/ports/rp2/cambus.c b/src/omv/ports/rp2/cambus.c new file mode 100644 index 000000000..a0c7c96f5 --- /dev/null +++ b/src/omv/ports/rp2/cambus.c @@ -0,0 +1,145 @@ +#include +#include +#include "py/mphal.h" + +#include "pico/time.h" +#include "pico/stdlib.h" +#include "hardware/i2c.h" +#include "omv_boardconfig.h" +#include "cambus.h" + +#define I2C_TIMEOUT (100*1000) +#define I2C_SCAN_TIMEOUT (10*1000) + +int cambus_init(cambus_t *bus, uint32_t bus_id, uint32_t speed) +{ + bus->id = bus_id; + bus->initialized = false; + + switch (speed) { + case CAMBUS_SPEED_STANDARD: + bus->speed = 100 * 1000; ///< 100 kbps + break; + case CAMBUS_SPEED_FULL: + bus->speed = 250 * 1000; ///< 250 kbps + break; + case CAMBUS_SPEED_FAST: + bus->speed = 400 * 1000; ///< 400 kbps + break; + default: + return -1; + } + + switch (bus_id) { + case 0: { + bus->i2c = i2c0; + bus->scl_pin = I2C0_SCL_PIN; + bus->sda_pin = I2C0_SDA_PIN; + break; + } + case 1: { + bus->i2c = i2c1; + bus->scl_pin = I2C1_SCL_PIN; + bus->sda_pin = I2C1_SDA_PIN; + break; + } + default: + return -1; + } + + i2c_init(bus->i2c, bus->speed); + gpio_set_function(bus->scl_pin, GPIO_FUNC_I2C); + gpio_set_function(bus->sda_pin, GPIO_FUNC_I2C); + + bus->initialized = true; + return 0; +} + +int cambus_deinit(cambus_t *bus) +{ + if (bus->initialized) { + i2c_deinit(bus->i2c); + bus->initialized = false; + } + return 0; +} + +int cambus_scan(cambus_t *bus) +{ + for (uint8_t addr=0x09, rxdata; addr<=0x77; addr++) { + if (i2c_read_timeout_us(bus->i2c, addr, &rxdata, 1, false, I2C_SCAN_TIMEOUT) >= 0) { + return (addr << 1); + } + } + return 0; +} + +int cambus_readb(cambus_t *bus, uint8_t slv_addr, uint8_t reg_addr, uint8_t *reg_data) +{ + int bytes = 0; + slv_addr = slv_addr >> 1; + + bytes += i2c_write_timeout_us(bus->i2c, slv_addr, ®_addr, 1, false, I2C_TIMEOUT); + bytes += i2c_read_timeout_us(bus->i2c, slv_addr, reg_data, 1, false, I2C_TIMEOUT); + + return (bytes == 2) ? 0 : -1; +} + +int cambus_writeb(cambus_t *bus, uint8_t slv_addr, uint8_t reg_addr, uint8_t reg_data) +{ + int bytes = 0; + slv_addr = slv_addr >> 1; + + uint8_t buf[] = {reg_addr, reg_data}; + bytes = i2c_write_timeout_us(bus->i2c, slv_addr, buf, 2, false, I2C_TIMEOUT); + + return (bytes == 2) ? 0 : -1; +} + +int cambus_read_bytes(cambus_t *bus, uint8_t slv_addr, uint8_t *buf, int len, uint32_t flags) +{ + int bytes = 0; + slv_addr = slv_addr >> 1; + bool nostop = false; + + if (flags & CAMBUS_XFER_NO_STOP) { + nostop = true; + } + + bytes = i2c_read_timeout_us(bus->i2c, slv_addr, buf, len, nostop, I2C_TIMEOUT); + + return (bytes == len) ? 0 : -1; +} + +int cambus_write_bytes(cambus_t *bus, uint8_t slv_addr, uint8_t *buf, int len, uint32_t flags) +{ + int bytes = 0; + slv_addr = slv_addr >> 1; + bool nostop = false; + + if (flags & CAMBUS_XFER_NO_STOP) { + nostop = true; + } + + bytes = i2c_write_timeout_us(bus->i2c, slv_addr, buf, len, nostop, I2C_TIMEOUT); + + return (bytes == len) ? 0 : -1; +} + +int cambus_pulse_scl(cambus_t *bus) +{ + cambus_deinit(bus); + + // Configure SCL as GPIO + gpio_init(bus->scl_pin); + gpio_set_dir(bus->scl_pin, GPIO_OUT); + + // Pulse SCL to recover stuck device. + for (int i=0; i<10000; i++) { + gpio_put(bus->scl_pin, 1); + mp_hal_delay_us(10); + gpio_put(bus->scl_pin, 0); + mp_hal_delay_us(10); + } + return 0; +} diff --git a/src/omv/ports/rp2/dcmi.pio b/src/omv/ports/rp2/dcmi.pio new file mode 100644 index 000000000..af42c0fcd --- /dev/null +++ b/src/omv/ports/rp2/dcmi.pio @@ -0,0 +1,57 @@ +; This file is part of the OpenMV project. +; +; Copyright (c) 2013-2021 Ibrahim Abdelkader +; Copyright (c) 2013-2021 Kwabena W. Agyeman +; +; This work is licensed under the MIT license, see the file LICENSE for details. +; Image Sensor PIO program. + +.define public PXCLK 11 +.define public HSYNC 12 +.define public VSYNC 13 + +.program dcmi_default +.wrap_target + pull block ; Read number of lines in OSR + mov y, osr ; Copy OSR to Y + pull block ; Read line width in bytes in OSR + + wait 1 gpio VSYNC ; Wait for VSYNC to go low + wait 0 gpio VSYNC + +line_loop: + mov x, osr ; Copy line width from OSR to X + wait 0 gpio HSYNC ; Wait for HSYNC to go high + wait 1 gpio HSYNC + +pixels_loop: + wait 0 gpio PXCLK + wait 1 gpio PXCLK + in pins 8 + jmp x-- pixels_loop ; Keep reading pixels while x != 0 + jmp y-- line_loop ; Keep reading lines while y != 0 +.wrap + +.program dcmi_odd_byte +.wrap_target + pull block ; Read number of lines in OSR + mov y, osr ; Copy OSR to Y + pull block ; Read line width in bytes in OSR + + wait 1 gpio VSYNC ; Wait for VSYNC to go low + wait 0 gpio VSYNC + +line_loop: + mov x, osr ; Copy line width from OSR to X + wait 0 gpio HSYNC ; Wait for HSYNC to go high + wait 1 gpio HSYNC + +pixels_loop: + wait 0 gpio PXCLK + wait 1 gpio PXCLK + in pins 8 + wait 0 gpio PXCLK + wait 1 gpio PXCLK + jmp x-- pixels_loop ; Keep reading pixels while x != 0 + jmp y-- line_loop ; Keep reading lines while y != 0 +.wrap diff --git a/src/omv/ports/rp2/main.c b/src/omv/ports/rp2/main.c new file mode 100644 index 000000000..073570b8e --- /dev/null +++ b/src/omv/ports/rp2/main.c @@ -0,0 +1,326 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/compile.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "py/stackctrl.h" +#include "lib/mp-readline/readline.h" +#include "lib/utils/gchelper.h" +#include "lib/utils/pyexec.h" +#include "tusb.h" +#include "uart.h" +#include "modmachine.h" +#include "modrp2.h" +#include "genhdr/mpversion.h" +#include "pendsv.h" + +#include "pico/stdlib.h" +#include "pico/binary_info.h" +#include "hardware/rtc.h" +#include "hardware/structs/rosc.h" +#include "pico/unique_id.h" + +#include "omv_boardconfig.h" +#include "framebuffer.h" +#include "cambus.h" +#include "sensor.h" +#include "usbdbg.h" +#include "py_fir.h" +#if MICROPY_PY_AUDIO +#include "py_audio.h" +#endif + +extern uint8_t __StackTop, __StackBottom; +static char OMV_ATTR_SECTION(OMV_ATTR_ALIGNED(gc_heap[OMV_HEAP_SIZE], 4), ".heap"); + +uint8_t *OMV_UNIQUE_ID_ADDR; +static pico_unique_board_id_t OMV_ATTR_ALIGNED(pico_unique_id, 4); + +// Embed version info in the binary in machine readable form +bi_decl(bi_program_version_string(MICROPY_GIT_TAG)); + +// Add a section to the picotool output similar to program features, but for frozen modules +// (it will aggregate BINARY_INFO_ID_MP_FROZEN binary info) +bi_decl(bi_program_feature_group_with_flags(BINARY_INFO_TAG_MICROPYTHON, + BINARY_INFO_ID_MP_FROZEN, "frozen modules", + BI_NAMED_GROUP_SEPARATE_COMMAS | BI_NAMED_GROUP_SORT_ALPHA)); + +void __fatal_error() +{ + gpio_init(LED_PIN); + gpio_set_dir(LED_PIN, GPIO_OUT); + + while (true) { + gpio_put(LED_PIN, 1); + sleep_ms(100); + gpio_put(LED_PIN, 0); + sleep_ms(100); + } +} + +void exec_boot_script(const char *path, bool interruptible) +{ + nlr_buf_t nlr; + bool interrupted = false; + if (nlr_push(&nlr) == 0) { + // Enable IDE interrupts if allowed. + if (interruptible) { + usbdbg_set_irq_enabled(true); + usbdbg_set_script_running(true); + } + + // Parse, compile and execute the script. + pyexec_file_if_exists(path); + nlr_pop(); + } else { + interrupted = true; + } + + // Disable IDE interrupts + usbdbg_set_irq_enabled(false); + usbdbg_set_script_running(false); + + if (interrupted) { + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } +} + + +int main(int argc, char **argv) { + bool first_soft_reset = true; + + #if MICROPY_HW_ENABLE_UART_REPL + bi_decl(bi_program_feature("UART REPL")) + setup_default_uart(); + mp_uart_init(); + #endif + + #if MICROPY_HW_ENABLE_USBDEV + bi_decl(bi_program_feature("USB REPL")) + #endif + + #if MICROPY_PY_THREAD + bi_decl(bi_program_feature("thread support")) + mp_thread_init(); + #endif + + // Start and initialise the RTC + datetime_t t = { + .year = 2021, + .month = 1, + .day = 1, + .dotw = 5, // 0 is Sunday, so 5 is Friday + .hour = 0, + .min = 0, + .sec = 0, + }; + rtc_init(); + rtc_set_datetime(&t); + + // Set board unique ID from flash for USB debugging. + OMV_UNIQUE_ID_ADDR = pico_unique_id.id; + pico_get_unique_board_id(&pico_unique_id); + +soft_reset: + // Initialise stack extents and GC heap. + mp_stack_set_top(&__StackTop); + mp_stack_set_limit(&__StackTop - &__StackBottom - 256); + gc_init(&gc_heap[0], &gc_heap[MP_ARRAY_SIZE(gc_heap)]); + + // Initialise MicroPython runtime. + mp_init(); + mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib)); + mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0); + + // Initialise sub-systems. + mp_hal_init(); + readline_init0(); + machine_pin_init(); + rp2_pio_init(); + + pendsv_init(); + usbdbg_init(); + + fb_alloc_init0(); + framebuffer_init0(); + + py_fir_init0(); + + #if MICROPY_PY_SENSOR + if (sensor_init() != 0) { + printf("sensor init failed!\n"); + } + #endif + + // Execute _boot.py to set up the filesystem. + pyexec_frozen_module("_boot.py"); + + // Execute user scripts. + exec_boot_script("boot.py", false); + + if (first_soft_reset) { + exec_boot_script("main.py", true); + } + + // If there's no script ready, just re-exec REPL + while (!usbdbg_script_ready()) { + nlr_buf_t nlr; + + if (nlr_push(&nlr) == 0) { + // enable IDE interrupt + usbdbg_set_irq_enabled(true); + + // run REPL + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if (pyexec_raw_repl() != 0) { + break; + } + } else { + if (pyexec_friendly_repl() != 0) { + break; + } + } + + nlr_pop(); + } + } + + if (usbdbg_script_ready()) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + // Enable IDE interrupt + usbdbg_set_irq_enabled(true); + // Execute the script. + pyexec_str(usbdbg_get_script()); + nlr_pop(); + } else { + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } + } + + usbdbg_wait_for_command(1000); + + usbdbg_set_irq_enabled(false); + + #if MICROPY_PY_AUDIO + py_audio_deinit(); + #endif + rp2_pio_deinit(); + machine_pin_deinit(); + gc_sweep_all(); + mp_deinit(); + first_soft_reset = false; + goto soft_reset; + return 0; +} + +void gc_collect(void) { + gc_collect_start(); + gc_helper_collect_regs_and_stack(); + #if MICROPY_PY_THREAD + mp_thread_gc_others(); + #endif + gc_collect_end(); +} + +void nlr_jump_fail(void *val) { + printf("FATAL: uncaught exception %p\n", val); + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(val)); + for (;;) { + __breakpoint(); + } +} + +#ifndef NDEBUG +void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) { + printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); + panic("Assertion failed"); +} +#endif + +#define POLY (0xD5) + +uint8_t rosc_random_u8(size_t cycles) { + static uint8_t r; + for (size_t i = 0; i < cycles; ++i) { + r = ((r << 1) | rosc_hw->randombit) ^ (r & 0x80 ? POLY : 0); + mp_hal_delay_us_fast(1); + } + return r; +} + +uint32_t rosc_random_u32(void) { + uint32_t value = 0; + for (size_t i = 0; i < 4; ++i) { + value = value << 8 | rosc_random_u8(32); + } + return value; +} + +const char rp2_help_text[] = + "Welcome to MicroPython!\n" + "\n" + "For online help please visit https://micropython.org/help/.\n" + "\n" + "For access to the hardware use the 'machine' module. RP2 specific commands\n" + "are in the 'rp2' module.\n" + "\n" + "Quick overview of some objects:\n" + " machine.Pin(pin) -- get a pin, eg machine.Pin(0)\n" + " machine.Pin(pin, m, [p]) -- get a pin and configure it for IO mode m, pull mode p\n" + " methods: init(..), value([v]), high(), low(), irq(handler)\n" + " machine.ADC(pin) -- make an analog object from a pin\n" + " methods: read_u16()\n" + " machine.PWM(pin) -- make a PWM object from a pin\n" + " methods: deinit(), freq([f]), duty_u16([d]), duty_ns([d])\n" + " machine.I2C(id) -- create an I2C object (id=0,1)\n" + " methods: readfrom(addr, buf, stop=True), writeto(addr, buf, stop=True)\n" + " readfrom_mem(addr, memaddr, arg), writeto_mem(addr, memaddr, arg)\n" + " machine.SPI(id, baudrate=1000000) -- create an SPI object (id=0,1)\n" + " methods: read(nbytes, write=0x00), write(buf), write_readinto(wr_buf, rd_buf)\n" + " machine.Timer(freq, callback) -- create a software timer object\n" + " eg: machine.Timer(freq=1, callback=lambda t:print(t))\n" + "\n" + "Pins are numbered 0-29, and 26-29 have ADC capabilities\n" + "Pin IO modes are: Pin.IN, Pin.OUT, Pin.ALT\n" + "Pin pull modes are: Pin.PULL_UP, Pin.PULL_DOWN\n" + "\n" + "Useful control commands:\n" + " CTRL-C -- interrupt a running program\n" + " CTRL-D -- on a blank line, do a soft reset of the board\n" + " CTRL-E -- on a blank line, enter paste mode\n" + "\n" + "For further help on a specific object, type help(obj)\n" + "For a list of available modules, type help('modules')\n" +; + diff --git a/src/omv/ports/rp2/modules/py_audio.c b/src/omv/ports/rp2/modules/py_audio.c new file mode 100644 index 000000000..9d1ebca6d --- /dev/null +++ b/src/omv/ports/rp2/modules/py_audio.c @@ -0,0 +1,207 @@ +/* + * This file is part of the OpenMV project. + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Audio Python module. + */ +#include +#include +#include "py/obj.h" +#include "py/objarray.h" +#include "py/nlr.h" +#include "py/mphal.h" +#include "py/binary.h" +#include "pendsv.h" +#include "runtime.h" + +#include "omv_boardconfig.h" +#if MICROPY_PY_AUDIO + +#include "py_audio.h" +#include "py_assert.h" +#include "py_helper.h" + +#include "hardware/pio.h" +#include "hardware/dma.h" +#include "hardware/irq.h" +#include "hardware/clocks.h" +#include "pdm.pio.h" +#include "OpenPDMFilter.h" + +#define PDM_DEFAULT_GAIN (16) +#define PDM_BUFFER_SIZE (512) +#define RAISE_OS_EXCEPTION(msg) mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT(msg)) + +static mp_obj_array_t *g_pcmbuf = NULL; +static mp_obj_t g_audio_callback = mp_const_none; +static uint32_t g_buf_index = 0; +static uint32_t g_decimation = 64; +static uint8_t PDM_BUFFERS[2][PDM_BUFFER_SIZE]; + +// OpenPDM filter used to convert PDM into PCM +static TPDMFilter_InitStruct pdm_filter; + +// Pendsv dispatch callback. +static void audio_pendsv_callback(void) +{ + // Call user callback + mp_call_function_1(g_audio_callback, MP_OBJ_FROM_PTR(g_pcmbuf)); +} + +static void dma_irq_handler() +{ + // Clear the interrupt request. + dma_irqn_acknowledge_channel(PDM_DMA, PDM_DMA_CHANNEL); + + // Set next buffer and retrigger the DMA channel. + dma_channel_set_write_addr(PDM_DMA_CHANNEL, PDM_BUFFERS[g_buf_index ^ 1], true); + + // Convert PDM to PCM samples. + // TODO: should run this in PendSV context instead. + if (g_decimation == 64) { + Open_PDM_Filter_64(PDM_BUFFERS[g_buf_index], g_pcmbuf->items, 1, &pdm_filter); + } else { + Open_PDM_Filter_128(PDM_BUFFERS[g_buf_index], g_pcmbuf->items, 1, &pdm_filter); + } + + // Schedule audio callback. + pendsv_schedule_dispatch(PENDSV_DISPATCH_AUDIO, audio_pendsv_callback); + + // Swap buffers + g_buf_index ^= 1; +} + +static mp_obj_t py_audio_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + // Read Args. + uint32_t channels = py_helper_keyword_int(n_args, args, 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_channels), 1); + uint32_t frequency = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_frequency), 16000); + int gain = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_gain_db), PDM_DEFAULT_GAIN); + + // Sanity checks + if (channels != 1) { + RAISE_OS_EXCEPTION("Invalid number of channels! Expected 1."); + } + + if (!(frequency == 16000 || frequency == 32000 || frequency == 48000)) { + RAISE_OS_EXCEPTION("Invalid number of channels! Expected 16K, 32K or 48K."); + } + + uint32_t g_decimation = (frequency == 16000) ? 128 : 64; + uint32_t n_samples = (PDM_BUFFER_SIZE * 8) / g_decimation; + + // Initialize OpenPDM filter. + pdm_filter.Fs = frequency; + pdm_filter.nSamples = n_samples; + pdm_filter.LP_HZ = frequency / 2; + pdm_filter.HP_HZ = 10; + pdm_filter.In_MicChannels = channels; + pdm_filter.Out_MicChannels = channels; + pdm_filter.Decimation = g_decimation; + pdm_filter.filterGain = gain; + Open_PDM_Filter_Init(&pdm_filter); + + // Configure PIO state machine + float clkDiv = (float) clock_get_hz(clk_sys) / frequency / g_decimation / 2; + uint offset = pio_add_program(PDM_PIO, &pdm_pio_program); + pdm_pio_program_init(PDM_PIO, PDM_SM, offset, PDM_CLK_PIN, PDM_DIN_PIN, clkDiv); + + // Wait for microphone + mp_hal_delay_ms(100); + + // Configure DMA for transferring PIO rx buffer to raw buffers + dma_channel_config c = dma_channel_get_default_config(PDM_DMA_CHANNEL); + channel_config_set_read_increment(&c, false); + channel_config_set_write_increment(&c, true); + channel_config_set_dreq(&c, pio_get_dreq(PDM_PIO, PDM_SM, false)); + channel_config_set_transfer_data_size(&c, DMA_SIZE_8); + + // Configure DMA channel without starting. + dma_channel_configure(PDM_DMA_CHANNEL, &c, + PDM_BUFFERS[0], // Destinatinon pointer + &PDM_PIO->rxf[PDM_SM], // Source pointer + sizeof(PDM_BUFFERS[0]), // Number of transfers + false // Don't start immediately + ); + + // Set new DMA IRQ handler. + // Disable IRQs. + irq_set_enabled(PDM_DMA_IRQ, false); + + // Clear DMA interrupts. + dma_irqn_acknowledge_channel(PDM_DMA, PDM_DMA_CHANNEL); + + // Remove current handler if any. + irq_handler_t irq_handler = irq_get_exclusive_handler(PDM_DMA_IRQ); + if (irq_handler != NULL) { + irq_remove_handler(PDM_DMA_IRQ, irq_handler); + } + + // Set new exclusive IRQ handler. + irq_set_exclusive_handler(PDM_DMA_IRQ, dma_irq_handler); + // Or set shared IRQ handler, but this needs to be called once. + // irq_add_shared_handler(PDM_DMA_IRQ, dma_irq_handler, PICO_DEFAULT_IRQ_PRIORITY); + + // Re-enable IRQs. + irq_set_enabled(PDM_DMA_IRQ, true); + dma_irqn_set_channel_enabled(PDM_DMA, PDM_DMA_CHANNEL, true); + + // Allocate global PCM buffer. + g_pcmbuf = mp_obj_new_bytearray_by_ref(n_samples * sizeof(int16_t), m_new(int16_t, n_samples)); + + return mp_const_none; +} + +void py_audio_deinit() +{ + // Disable PDM and IRQ + dma_channel_abort(PDM_DMA_CHANNEL); + dma_irqn_set_channel_enabled(PDM_DMA, PDM_DMA_CHANNEL, false); + + g_pcmbuf = NULL; + g_buf_index = 0; + g_audio_callback = mp_const_none; +} + +static mp_obj_t py_audio_start_streaming(mp_obj_t callback_obj) +{ + g_audio_callback = callback_obj; + + if (!mp_obj_is_callable(g_audio_callback)) { + g_audio_callback = mp_const_none; + RAISE_OS_EXCEPTION("Invalid callback object!"); + } + + dma_channel_start(PDM_DMA_CHANNEL); + return mp_const_none; +} + +static mp_obj_t py_audio_stop_streaming() +{ + py_audio_deinit(); + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_audio_init_obj, 0, py_audio_init); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_audio_start_streaming_obj, py_audio_start_streaming); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_audio_stop_streaming_obj, py_audio_stop_streaming); + +static const mp_rom_map_elem_t globals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audio) }, + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&py_audio_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_start_streaming), MP_ROM_PTR(&py_audio_start_streaming_obj)}, + { MP_ROM_QSTR(MP_QSTR_stop_streaming), MP_ROM_PTR(&py_audio_stop_streaming_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table); + +const mp_obj_module_t audio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_t)&globals_dict, +}; + +#endif //MICROPY_PY_AUDIO diff --git a/src/omv/ports/rp2/modules/py_audio.h b/src/omv/ports/rp2/modules/py_audio.h new file mode 100644 index 000000000..be2726726 --- /dev/null +++ b/src/omv/ports/rp2/modules/py_audio.h @@ -0,0 +1,14 @@ +/* + * This file is part of the OpenMV project. + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Audio Python module. + */ +#ifndef __PY_AUDIO_H__ +#define __PY_AUDIO_H__ +void py_audio_deinit(); +#endif // __PY_AUDIO_H__ diff --git a/src/omv/ports/rp2/omv_portconfig.cmake b/src/omv/ports/rp2/omv_portconfig.cmake new file mode 100644 index 000000000..790dd62e7 --- /dev/null +++ b/src/omv/ports/rp2/omv_portconfig.cmake @@ -0,0 +1,253 @@ +# Need to redefine these variables here. +set(TOP_DIR $ENV{TOP_DIR}) +set(TARGET $ENV{TARGET}) +set(PORT rp2) +set(BUILD ${TOP_DIR}/build) +set(FW_DIR ${BUILD}/bin) +set(OMV_DIR omv) +set(UVC_DIR uvc) +set(CM4_DIR cm4) +set(BOOTLDR_DIR bootloader) +set(CUBEAI_DIR stm32cubeai) +set(CMSIS_DIR hal/cmsis) +#set(MICROPY_DIR micropython) +set(LEPTON_DIR drivers/lepton) +set(LSM6DS3_DIR drivers/lsm6ds3) +set(WINC1500_DIR drivers/winc1500) +set(MLX90621_DIR drivers/mlx90621) +set(MLX90640_DIR drivers/mlx90640) +set(MLX90641_DIR drivers/mlx90641) +set(OPENPDM_DIR ${TOP_DIR}/lib/openpdm) +set(TENSORFLOW_DIR ${TOP_DIR}/lib/libtf) +set(OMV_BOARD_CONFIG_DIR ${TOP_DIR}/${OMV_DIR}/boards/${TARGET}/) +#set(MP_BOARD_CONFIG_DIR ${TOP_DIR}/${MICROPY_DIR}/ports/${PORT}/boards/${TARGET}/ +set(MPY_LIB_DIR ${TOP_DIR}/../scripts/libraries) +set(FROZEN_MANIFEST ${OMV_BOARD_CONFIG_DIR}/manifest.py) +set(OMV_COMMON_DIR ${TOP_DIR}/${OMV_DIR}/common) +set(PORT_DIR ${TOP_DIR}/${OMV_DIR}/ports/${PORT}) + +# Include board cmake fragment +include(${OMV_BOARD_CONFIG_DIR}/omv_boardconfig.cmake) + +target_compile_definitions(${MICROPY_TARGET} PRIVATE + ARM_MATH_CM0PLUS + ${OMV_BOARD_MODULES_DEFINITIONS} +) + +#target_compile_options(${MICROPY_TARGET} PRIVATE +#) + +# Generate DCMI PIO header +pico_generate_pio_header(${MICROPY_TARGET} + ${TOP_DIR}/${OMV_DIR}/ports/${PORT}/dcmi.pio +) + +# Linker script +add_custom_command( + OUTPUT ${FW_DIR}/rp2.ld + COMMENT "Preprocessing linker script" + COMMAND "${CMAKE_C_COMPILER}" -P -E -I ${OMV_BOARD_CONFIG_DIR} -DLINKER_SCRIPT ${PORT_DIR}/rp2.ld.S > ${FW_DIR}/rp2.ld + DEPENDS ${OMV_BOARD_CONFIG_DIR}/omv_boardconfig.h ${PORT_DIR}/rp2.ld.S + VERBATIM +) +add_custom_target( + LinkerScript + ALL DEPENDS ${FW_DIR}/rp2.ld + VERBATIM +) +pico_set_linker_script(${MICROPY_TARGET} ${FW_DIR}/rp2.ld) + +# Add OMV qstr sources +file(GLOB OMV_SRC_QSTR1 ${TOP_DIR}/${OMV_DIR}/modules/*.c) +file(GLOB OMV_SRC_QSTR2 ${TOP_DIR}/${OMV_DIR}/ports/${PORT}/modules/*.c) +list(APPEND MICROPY_SOURCE_QSTR ${OMV_SRC_QSTR1} ${OMV_SRC_QSTR2}) + +# Override manifest file +set(MICROPY_FROZEN_MANIFEST ${FROZEN_MANIFEST}) + +target_include_directories(${MICROPY_TARGET} PRIVATE + ${TOP_DIR}/${CMSIS_DIR}/include/ + ${TOP_DIR}/${CMSIS_DIR}/include/rpi/ + + ${MICROPY_DIR}/py/ + ${MICROPY_DIR}/lib/oofatfs/ + ${MICROPY_DIR}/lib/tinyusb/src/ + + ${TOP_DIR}/${OMV_DIR}/ + ${TOP_DIR}/${OMV_DIR}/alloc/ + ${TOP_DIR}/${OMV_DIR}/common/ + ${TOP_DIR}/${OMV_DIR}/imlib/ + ${TOP_DIR}/${OMV_DIR}/modules/ + ${TOP_DIR}/${OMV_DIR}/sensors/ + ${TOP_DIR}/${OMV_DIR}/ports/${PORT}/ + ${TOP_DIR}/${OMV_DIR}/ports/${PORT}/modules/ + + ${TOP_DIR}/${LEPTON_DIR}/include/ + ${TOP_DIR}/${LSM6DS3_DIR}/include/ + ${TOP_DIR}/${WINC1500_DIR}/include/ + ${TOP_DIR}/${MLX90621_DIR}/include/ + ${TOP_DIR}/${MLX90640_DIR}/include/ + ${TOP_DIR}/${MLX90641_DIR}/include/ + ${OMV_BOARD_CONFIG_DIR} +) + +target_sources(${MICROPY_TARGET} PRIVATE + ${TOP_DIR}/${OMV_DIR}/alloc/xalloc.c + ${TOP_DIR}/${OMV_DIR}/alloc/fb_alloc.c + ${TOP_DIR}/${OMV_DIR}/alloc/umm_malloc.c + ${TOP_DIR}/${OMV_DIR}/alloc/dma_alloc.c + ${TOP_DIR}/${OMV_DIR}/alloc/unaligned_memcpy.c + + ${TOP_DIR}/${OMV_DIR}/common/array.c + ${TOP_DIR}/${OMV_DIR}/common/ff_wrapper.c + ${TOP_DIR}/${OMV_DIR}/common/ini.c + ${TOP_DIR}/${OMV_DIR}/common/ringbuf.c + ${TOP_DIR}/${OMV_DIR}/common/trace.c + ${TOP_DIR}/${OMV_DIR}/common/mutex.c + ${TOP_DIR}/${OMV_DIR}/common/usbdbg.c + + ${TOP_DIR}/${OMV_DIR}/sensors/ov2640.c + ${TOP_DIR}/${OMV_DIR}/sensors/ov5640.c + ${TOP_DIR}/${OMV_DIR}/sensors/ov7670.c + ${TOP_DIR}/${OMV_DIR}/sensors/ov7690.c + ${TOP_DIR}/${OMV_DIR}/sensors/ov7725.c + ${TOP_DIR}/${OMV_DIR}/sensors/ov9650.c + ${TOP_DIR}/${OMV_DIR}/sensors/mt9v034.c + ${TOP_DIR}/${OMV_DIR}/sensors/mt9m114.c + ${TOP_DIR}/${OMV_DIR}/sensors/lepton.c + ${TOP_DIR}/${OMV_DIR}/sensors/hm01b0.c + ${TOP_DIR}/${OMV_DIR}/sensors/gc2145.c + + ${TOP_DIR}/${OMV_DIR}/modules/py_clock.c + ${TOP_DIR}/${OMV_DIR}/modules/py_gif.c + ${TOP_DIR}/${OMV_DIR}/modules/py_helper.c + ${TOP_DIR}/${OMV_DIR}/modules/py_image.c + ${TOP_DIR}/${OMV_DIR}/modules/py_imageio.c + ${TOP_DIR}/${OMV_DIR}/modules/py_mjpeg.c + ${TOP_DIR}/${OMV_DIR}/modules/py_omv.c + ${TOP_DIR}/${OMV_DIR}/modules/py_sensor.c + ${TOP_DIR}/${OMV_DIR}/modules/py_tf.c + ${TOP_DIR}/${OMV_DIR}/modules/py_fir.c + + ${TOP_DIR}/${OMV_DIR}/imlib/agast.c + ${TOP_DIR}/${OMV_DIR}/imlib/apriltag.c + ${TOP_DIR}/${OMV_DIR}/imlib/bayer.c + ${TOP_DIR}/${OMV_DIR}/imlib/binary.c + ${TOP_DIR}/${OMV_DIR}/imlib/blob.c + ${TOP_DIR}/${OMV_DIR}/imlib/bmp.c + ${TOP_DIR}/${OMV_DIR}/imlib/clahe.c + ${TOP_DIR}/${OMV_DIR}/imlib/collections.c + ${TOP_DIR}/${OMV_DIR}/imlib/dmtx.c + ${TOP_DIR}/${OMV_DIR}/imlib/draw.c + ${TOP_DIR}/${OMV_DIR}/imlib/edge.c + ${TOP_DIR}/${OMV_DIR}/imlib/eye.c + ${TOP_DIR}/${OMV_DIR}/imlib/fast.c + ${TOP_DIR}/${OMV_DIR}/imlib/fft.c + ${TOP_DIR}/${OMV_DIR}/imlib/filter.c + ${TOP_DIR}/${OMV_DIR}/imlib/fmath.c + ${TOP_DIR}/${OMV_DIR}/imlib/font.c + ${TOP_DIR}/${OMV_DIR}/imlib/framebuffer.c + ${TOP_DIR}/${OMV_DIR}/imlib/fsort.c + ${TOP_DIR}/${OMV_DIR}/imlib/gif.c + ${TOP_DIR}/${OMV_DIR}/imlib/haar.c + ${TOP_DIR}/${OMV_DIR}/imlib/hog.c + ${TOP_DIR}/${OMV_DIR}/imlib/hough.c + ${TOP_DIR}/${OMV_DIR}/imlib/imlib.c + ${TOP_DIR}/${OMV_DIR}/imlib/integral.c + ${TOP_DIR}/${OMV_DIR}/imlib/integral_mw.c + ${TOP_DIR}/${OMV_DIR}/imlib/jpeg.c + ${TOP_DIR}/${OMV_DIR}/imlib/kmeans.c + ${TOP_DIR}/${OMV_DIR}/imlib/lab_tab.c + ${TOP_DIR}/${OMV_DIR}/imlib/lbp.c + ${TOP_DIR}/${OMV_DIR}/imlib/line.c + ${TOP_DIR}/${OMV_DIR}/imlib/lsd.c + ${TOP_DIR}/${OMV_DIR}/imlib/mathop.c + ${TOP_DIR}/${OMV_DIR}/imlib/mjpeg.c + ${TOP_DIR}/${OMV_DIR}/imlib/orb.c + ${TOP_DIR}/${OMV_DIR}/imlib/phasecorrelation.c + ${TOP_DIR}/${OMV_DIR}/imlib/point.c + ${TOP_DIR}/${OMV_DIR}/imlib/pool.c + ${TOP_DIR}/${OMV_DIR}/imlib/ppm.c + ${TOP_DIR}/${OMV_DIR}/imlib/qrcode.c + ${TOP_DIR}/${OMV_DIR}/imlib/qsort.c + ${TOP_DIR}/${OMV_DIR}/imlib/rainbow_tab.c + ${TOP_DIR}/${OMV_DIR}/imlib/rectangle.c + ${TOP_DIR}/${OMV_DIR}/imlib/selective_search.c + ${TOP_DIR}/${OMV_DIR}/imlib/sincos_tab.c + ${TOP_DIR}/${OMV_DIR}/imlib/stats.c + ${TOP_DIR}/${OMV_DIR}/imlib/template.c + ${TOP_DIR}/${OMV_DIR}/imlib/xyz_tab.c + ${TOP_DIR}/${OMV_DIR}/imlib/zbar.c + + ${TOP_DIR}/${OMV_DIR}/ports/${PORT}/main.c + ${TOP_DIR}/${OMV_DIR}/ports/${PORT}/cambus.c + ${TOP_DIR}/${OMV_DIR}/ports/${PORT}/sensor.c +) + +if(MICROPY_PY_SENSOR) + target_compile_definitions(${MICROPY_TARGET} PRIVATE + MICROPY_PY_SENSOR=1 + ) +endif() + +if(MICROPY_PY_AUDIO) + target_include_directories(${MICROPY_TARGET} PRIVATE + ${OPENPDM_DIR}/ + ) + + set(AUDIO_SOURCES + ${OPENPDM_DIR}/OpenPDMFilter.c + ${TOP_DIR}/${OMV_DIR}/ports/${PORT}/modules/py_audio.c + ) + + target_sources(${MICROPY_TARGET} PRIVATE ${AUDIO_SOURCES}) + + target_compile_definitions(${MICROPY_TARGET} PRIVATE + MICROPY_PY_AUDIO=1 + #USE_LUT + ) + + pico_generate_pio_header(${MICROPY_TARGET} + ${TOP_DIR}/${OMV_DIR}/ports/${PORT}/pdm.pio + ) +endif() + +if(MICROPY_PY_ULAB) + set(MICROPY_ULAB_DIR "${MICROPY_DIR}/extmod/ulab") + + target_include_directories(${MICROPY_TARGET} PRIVATE + ${MICROPY_ULAB_DIR}/code/ + ) + + set(ULAB_SOURCES + ${MICROPY_ULAB_DIR}/code/scipy/optimize/optimize.c + ${MICROPY_ULAB_DIR}/code/scipy/signal/signal.c + ${MICROPY_ULAB_DIR}/code/scipy/special/special.c + ${MICROPY_ULAB_DIR}/code/ndarray_operators.c + ${MICROPY_ULAB_DIR}/code/ulab_tools.c + ${MICROPY_ULAB_DIR}/code/ndarray.c + ${MICROPY_ULAB_DIR}/code/numpy/approx/approx.c + ${MICROPY_ULAB_DIR}/code/numpy/compare/compare.c + ${MICROPY_ULAB_DIR}/code/ulab_create.c + ${MICROPY_ULAB_DIR}/code/numpy/fft/fft.c + ${MICROPY_ULAB_DIR}/code/numpy/fft/fft_tools.c + ${MICROPY_ULAB_DIR}/code/numpy/filter/filter.c + ${MICROPY_ULAB_DIR}/code/numpy/linalg/linalg.c + ${MICROPY_ULAB_DIR}/code/numpy/linalg/linalg_tools.c + ${MICROPY_ULAB_DIR}/code/numpy/numerical/numerical.c + ${MICROPY_ULAB_DIR}/code/numpy/poly/poly.c + ${MICROPY_ULAB_DIR}/code/numpy/vector/vector.c + ${MICROPY_ULAB_DIR}/code/user/user.c + ${MICROPY_ULAB_DIR}/code/numpy/numpy.c + ${MICROPY_ULAB_DIR}/code/scipy/scipy.c + ${MICROPY_ULAB_DIR}/code/ulab.c + ) + + target_sources(${MICROPY_TARGET} PRIVATE ${ULAB_SOURCES}) + list(APPEND MICROPY_SOURCE_QSTR ${ULAB_SOURCES}) + + target_compile_definitions(${MICROPY_TARGET} PRIVATE + MICROPY_PY_ULAB=1 + ULAB_CONFIG_FILE="${OMV_BOARD_CONFIG_DIR}/ulab_config.h" + ) +endif() diff --git a/src/omv/ports/rp2/omv_portconfig.h b/src/omv/ports/rp2/omv_portconfig.h new file mode 100644 index 000000000..5041c9a76 --- /dev/null +++ b/src/omv/ports/rp2/omv_portconfig.h @@ -0,0 +1,23 @@ +/* + * This file is part of the OpenMV project. + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * OpenMV RP2 port abstraction layer. + */ +#ifndef __OMV_PORTCONFIG_H__ +#define __OMV_PORTCONFIG_H__ + +#include "pico/stdlib.h" +#include "hardware/i2c.h" + +// omv_gpio_t definition +typedef uint32_t omv_gpio_t; + +// cambus/i2c definition +typedef i2c_inst_t *omv_cambus_t; + +#endif // __OMV_PORTCONFIG_H__ diff --git a/src/omv/ports/rp2/omv_portconfig.mk b/src/omv/ports/rp2/omv_portconfig.mk new file mode 100644 index 000000000..5f619c7e4 --- /dev/null +++ b/src/omv/ports/rp2/omv_portconfig.mk @@ -0,0 +1,31 @@ +# This file is part of the OpenMV project. +# +# Copyright (c) 2013-2019 Ibrahim Abdelkader +# Copyright (c) 2013-2019 Kwabena W. Agyeman +# +# This work is licensed under the MIT license, see the file LICENSE for details. +# +# RP2 Makefile. +# This just invokes make in MicroPython RP2 port with OpenMV's cmake arg. + +export PORT +export TARGET +export TOP_DIR + +MICROPY_ARGS += BOARD=$(TARGET) BUILD=$(FW_DIR) OMV_CMAKE=$(TOP_DIR)/$(OMV_DIR)/ports/$(PORT)/omv_portconfig.cmake + +################################################### +all: $(OPENMV) + +$(BUILD): + $(MKDIR) -p $@ + +$(FIRMWARE): | $(BUILD) + $(MAKE) -C $(MICROPY_DIR)/ports/$(PORT) $(MICROPY_ARGS) + +# This target generates the firmware image. +$(OPENMV): $(FIRMWARE) + $(SIZE) $(FW_DIR)/$(FIRMWARE).elf + +size: + $(SIZE) --format=SysV $(FW_DIR)/$(FIRMWARE).elf diff --git a/src/omv/ports/rp2/pdm.pio b/src/omv/ports/rp2/pdm.pio new file mode 100644 index 000000000..c2229b72e --- /dev/null +++ b/src/omv/ports/rp2/pdm.pio @@ -0,0 +1,56 @@ +; Copyright (c) 2019 Arduino LLC. All right reserved. +; +; This library is free software; you can redistribute it and/or +; modify it under the terms of the GNU Lesser General Public +; License as published by the Free Software Foundation; either +; version 2.1 of the License, or (at your option) any later version. +; +; This library is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +; See the GNU Lesser General Public License for more details. +; +; You should have received a copy of the GNU Lesser General Public +; License along with this library; if not, write to the Free Software +; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +.program pdm_pio +.side_set 1 +.wrap_target + + ; prova a cambiare edge + + ;sample on falling edge + push iffull noblock side 1 + ;nop side 1 + ;nop side 0 + in pins, 1 side 0 + ;nop side 0 + +.wrap + +% c-sdk { +#include "hardware/gpio.h" + +static inline void pdm_pio_program_init(PIO pio, uint sm, uint offset, uint clkPin, uint dataPin, float clkDiv) { + pio_sm_config c = pdm_pio_program_get_default_config(offset); + sm_config_set_sideset(&c, 1, false, false); + //sm_config_set_in_shift(&c, false, true, 8); + sm_config_set_in_shift(&c, false, false, 8); + + sm_config_set_in_pins(&c, dataPin); + sm_config_set_sideset_pins(&c, clkPin); + sm_config_set_clkdiv(&c, clkDiv); + + pio_sm_set_consecutive_pindirs(pio, sm, dataPin, 1, false); + pio_sm_set_consecutive_pindirs(pio, sm, clkPin, 1, true); + pio_sm_set_pins_with_mask(pio, sm, 0, (1u << clkPin) ); + //pio_gpio_init(pio, dataPin); + pio_gpio_init(pio, clkPin); + + pio_sm_init(pio, sm, offset, &c); + pio_sm_set_enabled(pio, sm, true); +} + + +%} diff --git a/src/omv/ports/rp2/rp2.ld.S b/src/omv/ports/rp2/rp2.ld.S new file mode 100644 index 000000000..c4448dc29 --- /dev/null +++ b/src/omv/ports/rp2/rp2.ld.S @@ -0,0 +1,265 @@ +/* + * This file is part of the OpenMV project. + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Linker script for RP2040 Devices. + */ + +/* Entry Point */ + +ENTRY(_entry_point) + +#include "omv_boardconfig.h" + +MEMORY +{ + FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 2048k + RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k + SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k + SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k +} + +SECTIONS +{ + /* Second stage bootloader is prepended to the image. It must be 256 bytes big + and checksummed. It is usually built by the boot_stage2 target + in the Raspberry Pi Pico SDK + */ + + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + .boot2 : { + __boot2_start__ = .; + KEEP (*(.boot2)) + __boot2_end__ = .; + } > FLASH + + ASSERT(__boot2_end__ - __boot2_start__ == 256, + "ERROR: Pico second stage bootloader must be 256 bytes in size") + + /* The second stage will always enter the image at the start of .text. + The debugger will use the ELF entry point, which is the _entry_point + symbol if present, otherwise defaults to start of .text. + This can be used to transfer control back to the bootrom on debugger + launches only, to perform proper flash setup. + */ + + .text : { + __logical_binary_start = .; + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.reset)) + /* TODO revisit this now memset/memcpy/float in ROM */ + /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from + * FLASH ... we will include any thing excluded here in .data below by default */ + *(.init) + /* Change for MicroPython... excluse gc.c, parse.c, vm.c from flash */ + *(EXCLUDE_FILE(*libgcc.a: *libc.a: *lib_a-mem*.o *libm.a: *gc.c.obj *vm.c.obj *parse.c.obj) .text*) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.eh_frame*) + . = ALIGN(4); + } > FLASH + + .rodata : { + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) + . = ALIGN(4); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > FLASH + __binary_info_end = .; + . = ALIGN(4); + + /* End of .text-like segments */ + __etext = .; + + .ram_vector_table (COPY): { + *(.ram_vector_table) + } > RAM + + .data : { + __data_start__ = .; + *(vtable) + + *(.time_critical*) + + /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ + *(.text*) + . = ALIGN(4); + *(.rodata*) + . = ALIGN(4); + + _ram_start = .; + *(.data*) + + . = ALIGN(4); + *(.after_data.*) + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__mutex_array_start = .); + KEEP(*(SORT(.mutex_array.*))) + KEEP(*(.mutex_array)) + PROVIDE_HIDDEN (__mutex_array_end = .); + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(SORT(.preinit_array.*))) + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.jcr) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + } > RAM AT> FLASH + + .uninitialized_data (COPY): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + + .bss : { + . = ALIGN(4); + __bss_start__ = .; + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + _ebss = .; + } > RAM + + /* Main framebuffer memory */ + .fb_memory (NOLOAD) : + { + . = ALIGN(4); + _fb_base = .; + . = . + OMV_FB_SIZE + OMV_FB_ALLOC_SIZE; + + . = ALIGN(4); + _fballoc = .; + . = ALIGN(4); + + #if !defined(OMV_JPEG_MEMORY) + _jpeg_buf = .; // IDE JPEG buffer + . = . + OMV_JPEG_BUF_SIZE; + . = ALIGN(4); + #endif + } >OMV_FB_MEMORY + + .heap (COPY): + { + __end__ = .; + end = __end__; + *(.heap*) + __HeapLimit = .; + } > RAM + + /* Start and end symbols must be word-aligned */ + .scratch_x : { + __scratch_x_start__ = .; + *(.scratch_x.*) + . = ALIGN(4); + __scratch_x_end__ = .; + } > SCRATCH_X AT > FLASH + __scratch_x_source__ = LOADADDR(.scratch_x); + + .scratch_y : { + __scratch_y_start__ = .; + *(.scratch_y.*) + . = ALIGN(4); + __scratch_y_end__ = .; + } > SCRATCH_Y AT > FLASH + __scratch_y_source__ = LOADADDR(.scratch_y); + + /* .stack*_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later + * + * stack1 section may be empty/missing if platform_launch_core1 is not used */ + + /* by default we put core 0 stack at the end of scratch Y, so that if core 1 + * stack is not used then all of SCRATCH_X is free. + */ + .stack1_dummy (COPY): + { + *(.stack1*) + } > SCRATCH_X + .stack_dummy (COPY): + { + *(.stack*) + } > SCRATCH_Y + + .flash_end : { + __flash_binary_end = .; + } > FLASH + + /* stack limit is poorly named, but historically is maximum heap ptr */ + __StackLimit = ORIGIN(RAM) + LENGTH(RAM); + __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); + __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); + __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); + __StackBottom = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") + + ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary") + /* todo assert on extra code */ +} + diff --git a/src/omv/ports/rp2/sensor.c b/src/omv/ports/rp2/sensor.c new file mode 100644 index 000000000..7df45a639 --- /dev/null +++ b/src/omv/ports/rp2/sensor.c @@ -0,0 +1,1077 @@ +/* + * This file is part of the OpenMV project. + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Sensor abstraction layer for nRF port. + */ +#include +#include +#include +#include +#include "py/mphal.h" + +#include "cambus.h" +#include "sensor.h" +#include "ov2640.h" +#include "ov5640.h" +#include "ov7725.h" +#include "ov7690.h" +#include "ov7670.h" +#include "ov9650.h" +#include "mt9v034.h" +#include "lepton.h" +#include "hm01b0.h" +#include "framebuffer.h" + +#include "pico/time.h" +#include "pico/stdlib.h" +#include "hardware/pwm.h" +#include "hardware/pio.h" +#include "hardware/dma.h" +#include "hardware/irq.h" +#include "omv_boardconfig.h" +#include "unaligned_memcpy.h" +#include "dcmi.pio.h" + +sensor_t sensor = {0}; +extern void __fatal_error(const char *msg); +static void dma_irq_handler(); + +const int resolution[][2] = { + {0, 0 }, + // C/SIF Resolutions + {88, 72 }, /* QQCIF */ + {176, 144 }, /* QCIF */ + {352, 288 }, /* CIF */ + {88, 60 }, /* QQSIF */ + {176, 120 }, /* QSIF */ + {352, 240 }, /* SIF */ + // VGA Resolutions + {40, 30 }, /* QQQQVGA */ + {80, 60 }, /* QQQVGA */ + {160, 120 }, /* QQVGA */ + {320, 240 }, /* QVGA */ + {640, 480 }, /* VGA */ + {30, 20 }, /* HQQQQVGA */ + {60, 40 }, /* HQQQVGA */ + {120, 80 }, /* HQQVGA */ + {240, 160 }, /* HQVGA */ + {480, 320 }, /* HVGA */ + // FFT Resolutions + {64, 32 }, /* 64x32 */ + {64, 64 }, /* 64x64 */ + {128, 64 }, /* 128x64 */ + {128, 128 }, /* 128x128 */ + // Himax Resolutions + {160, 160 }, /* 160x160 */ + {320, 320 }, /* 320x320 */ + // Other + {128, 160 }, /* LCD */ + {128, 160 }, /* QQVGA2 */ + {720, 480 }, /* WVGA */ + {752, 480 }, /* WVGA2 */ + {800, 600 }, /* SVGA */ + {1024, 768 }, /* XGA */ + {1280, 768 }, /* WXGA */ + {1280, 1024}, /* SXGA */ + {1280, 960 }, /* SXGAM */ + {1600, 1200}, /* UXGA */ + {1280, 720 }, /* HD */ + {1920, 1080}, /* FHD */ + {2560, 1440}, /* QHD */ + {2048, 1536}, /* QXGA */ + {2560, 1600}, /* WQXGA */ + {2592, 1944}, /* WQXGA2 */ +}; + +static int extclk_config(int frequency) +{ + uint32_t p = 4; + + // Allocate pin to the PWM + gpio_set_function(DCMI_XCLK_PIN, GPIO_FUNC_PWM); + + // Find out which PWM slice is connected to the GPIO + uint slice_num = pwm_gpio_to_slice_num(DCMI_XCLK_PIN); + + // Set period to p cycles + pwm_set_wrap(slice_num, p-1); + + // Set channel A 50% duty cycle. + pwm_set_chan_level(slice_num, PWM_CHAN_A, p/2); + + // Set sysclk divider + // f = 125000000 / (p * (1 + (p/16))) + pwm_set_clkdiv_int_frac(slice_num, 1, p); + + // Set the PWM running + pwm_set_enabled(slice_num, true); + + return 0; +} + +static void dma_config(int w, int h, int bpp, uint32_t *capture_buf, bool rev_bytes) +{ + dma_channel_abort(DCMI_DMA_CHANNEL); + dma_irqn_set_channel_enabled(DCMI_DMA, DCMI_DMA_CHANNEL, false); + + dma_channel_config c = dma_channel_get_default_config(DCMI_DMA_CHANNEL); + channel_config_set_read_increment(&c, false); + channel_config_set_write_increment(&c, true); + channel_config_set_dreq(&c, pio_get_dreq(DCMI_PIO, DCMI_SM, false)); + channel_config_set_bswap(&c, rev_bytes); + + dma_channel_configure(DCMI_DMA_CHANNEL, &c, + capture_buf, // Destinatinon pointer. + &DCMI_PIO->rxf[DCMI_SM], // Source pointer. + (w*h*bpp)>>2, // Number of transfers in words. + true // Start immediately, will block on SM. + ); + + // Re-enable DMA IRQs. + dma_irqn_set_channel_enabled(DCMI_DMA, DCMI_DMA_CHANNEL, true); +} + +static int dcmi_config(uint32_t pixformat) +{ + uint offset; + pio_sm_config config; + + pio_sm_set_enabled(DCMI_PIO, DCMI_SM, false); + pio_sm_clear_fifos(DCMI_PIO, DCMI_SM); + + for(uint i=DCMI_D0_PIN; ibpp = -1; +} + +int sensor_init() +{ + int init_ret = 0; + + // PIXCLK + gpio_init(DCMI_PXCLK_PIN); + gpio_set_dir(DCMI_PXCLK_PIN, GPIO_IN); + + // HSYNC + gpio_init(DCMI_HSYNC_PIN); + gpio_set_dir(DCMI_HSYNC_PIN, GPIO_IN); + + // VSYNC + gpio_init(DCMI_VSYNC_PIN); + gpio_set_dir(DCMI_VSYNC_PIN, GPIO_IN); + + #if defined(DCMI_PWDN_PIN) + gpio_init(DCMI_PWDN_PIN); + gpio_set_dir(DCMI_PWDN_PIN, GPIO_OUT); + gpio_pull_down(DCMI_PWDN_PIN); + DCMI_PWDN_HIGH(); + #endif + + #if defined(DCMI_RESET_PIN) + gpio_init(DCMI_RESET_PIN); + gpio_set_dir(DCMI_RESET_PIN, GPIO_OUT); + gpio_pull_up(DCMI_RESET_PIN); + DCMI_RESET_HIGH(); + #endif + + /* Do a power cycle */ + DCMI_PWDN_HIGH(); + mp_hal_delay_ms(10); + + DCMI_PWDN_LOW(); + mp_hal_delay_ms(10); + + // Configure the sensor external clock (XCLK) to XCLK_FREQ. + #if (OMV_XCLK_SOURCE == OMV_XCLK_TIM) + // Configure external clock timer. + if (extclk_config(OMV_XCLK_FREQUENCY) != 0) { + // Timer problem + return -1; + } + #elif (OMV_XCLK_SOURCE == OMV_XCLK_OSC) + // An external oscillator is used for the sensor clock. + // Nothing to do. + #else + #error "OMV_XCLK_SOURCE is not set!" + #endif + + /* Reset the sesnor state */ + memset(&sensor, 0, sizeof(sensor_t)); + + /* Some sensors have different reset polarities, and we can't know which sensor + is connected before initializing cambus and probing the sensor, which in turn + requires pulling the sensor out of the reset state. So we try to probe the + sensor with both polarities to determine line state. */ + sensor.pwdn_pol = ACTIVE_HIGH; + sensor.reset_pol = ACTIVE_HIGH; + + /* Reset the sensor */ + DCMI_RESET_HIGH(); + mp_hal_delay_ms(10); + + DCMI_RESET_LOW(); + mp_hal_delay_ms(10); + + // Initialize the camera bus. + cambus_init(&sensor.bus, ISC_I2C_ID, ISC_I2C_SPEED); + mp_hal_delay_ms(10); + + /* Probe the sensor */ + sensor.slv_addr = cambus_scan(&sensor.bus); + if (sensor.slv_addr == 0) { + /* Sensor has been held in reset, + so the reset line is active low */ + sensor.reset_pol = ACTIVE_LOW; + + /* Pull the sensor out of the reset state */ + DCMI_RESET_HIGH(); + mp_hal_delay_ms(10); + + /* Probe again to set the slave addr */ + sensor.slv_addr = cambus_scan(&sensor.bus); + if (sensor.slv_addr == 0) { + sensor.pwdn_pol = ACTIVE_LOW; + + DCMI_PWDN_HIGH(); + mp_hal_delay_ms(10); + + sensor.slv_addr = cambus_scan(&sensor.bus); + if (sensor.slv_addr == 0) { + sensor.reset_pol = ACTIVE_HIGH; + + DCMI_RESET_LOW(); + mp_hal_delay_ms(10); + + sensor.slv_addr = cambus_scan(&sensor.bus); + if (sensor.slv_addr == 0) { + return -2; + } + } + } + } + + // Clear sensor chip ID. + sensor.chip_id = 0; + + // Set default snapshot function. + sensor.snapshot = sensor_snapshot; + + switch (sensor.slv_addr) { + #if (OMV_ENABLE_OV2640 == 1) + case OV2640_SLV_ADDR: // Or OV9650. + cambus_readb(&sensor.bus, sensor.slv_addr, OV_CHIP_ID, &sensor.chip_id); + break; + #endif // (OMV_ENABLE_OV2640 == 1) + + #if (OMV_ENABLE_OV5640 == 1) + case OV5640_SLV_ADDR: + cambus_readb2(&sensor.bus, sensor.slv_addr, OV5640_CHIP_ID, &sensor.chip_id); + break; + #endif // (OMV_ENABLE_OV5640 == 1) + + #if (OMV_ENABLE_OV7725 == 1) || (OMV_ENABLE_OV7670 == 1) || (OMV_ENABLE_OV7690 == 1) + case OV7725_SLV_ADDR: // Or OV7690 or OV7670. + cambus_readb(&sensor.bus, sensor.slv_addr, OV_CHIP_ID, &sensor.chip_id); + break; + #endif //(OMV_ENABLE_OV7725 == 1) || (OMV_ENABLE_OV7670 == 1) || (OMV_ENABLE_OV7690 == 1) + + #if (OMV_ENABLE_MT9V034 == 1) + case MT9V034_SLV_ADDR: + cambus_readb(&sensor.bus, sensor.slv_addr, ON_CHIP_ID, &sensor.chip_id); + break; + #endif //(OMV_ENABLE_MT9V034 == 1) + + #if (OMV_ENABLE_MT9M114 == 1) + case MT9M114_SLV_ADDR: + cambus_readw2(&sensor.bus, sensor.slv_addr, ON_CHIP_ID, &sensor.chip_id_w); + break; + #endif // (OMV_ENABLE_MT9M114 == 1) + + #if (OMV_ENABLE_LEPTON == 1) + case LEPTON_SLV_ADDR: + sensor.chip_id = LEPTON_ID; + break; + #endif // (OMV_ENABLE_LEPTON == 1) + + #if (OMV_ENABLE_HM01B0 == 1) + case HM01B0_SLV_ADDR: + cambus_readb2(&sensor.bus, sensor.slv_addr, HIMAX_CHIP_ID, &sensor.chip_id); + break; + #endif //(OMV_ENABLE_HM01B0 == 1) + default: + return -3; + break; + } + + switch (sensor.chip_id) { + #if (OMV_ENABLE_OV2640 == 1) + case OV2640_ID: + if (extclk_config(OV2640_XCLK_FREQ) != 0) { + return -3; + } + init_ret = ov2640_init(&sensor); + break; + #endif // (OMV_ENABLE_OV2640 == 1) + + #if (OMV_ENABLE_OV5640 == 1) + case OV5640_ID: + if (extclk_config(OV5640_XCLK_FREQ) != 0) { + return -3; + } + init_ret = ov5640_init(&sensor); + break; + #endif // (OMV_ENABLE_OV5640 == 1) + + #if (OMV_ENABLE_OV7670 == 1) + case OV7670_ID: + init_ret = ov7670_init(&sensor); + break; + #endif // (OMV_ENABLE_OV7670 == 1) + + #if (OMV_ENABLE_OV7690 == 1) + case OV7690_ID: + if (extclk_config(OV7690_XCLK_FREQ) != 0) { + return -3; + } + init_ret = ov7690_init(&sensor); + break; + #endif // (OMV_ENABLE_OV7690 == 1) + + #if (OMV_ENABLE_OV7725 == 1) + case OV7725_ID: + init_ret = ov7725_init(&sensor); + break; + #endif // (OMV_ENABLE_OV7725 == 1) + + #if (OMV_ENABLE_OV9650 == 1) + case OV9650_ID: + init_ret = ov9650_init(&sensor); + break; + #endif // (OMV_ENABLE_OV9650 == 1) + + #if (OMV_ENABLE_MT9V034 == 1) + case MT9V034_ID: + if (extclk_config(MT9V034_XCLK_FREQ) != 0) { + return -3; + } + init_ret = mt9v034_init(&sensor); + break; + #endif //(OMV_ENABLE_MT9V034 == 1) + + #if (OMV_ENABLE_MT9M114 == 1) + case MT9M114_ID: + if (extclk_config(MT9M114_XCLK_FREQ) != 0) { + return -3; + } + init_ret = mt9m114_init(&sensor); + break; + #endif //(OMV_ENABLE_MT9M114 == 1) + + #if (OMV_ENABLE_LEPTON == 1) + case LEPTON_ID: + if (extclk_config(LEPTON_XCLK_FREQ) != 0) { + return -3; + } + init_ret = lepton_init(&sensor); + break; + #endif // (OMV_ENABLE_LEPTON == 1) + + #if (OMV_ENABLE_HM01B0 == 1) + case HM01B0_ID: + init_ret = hm01b0_init(&sensor); + break; + #endif //(OMV_ENABLE_HM01B0 == 1) + + default: + return -3; + break; + } + + if (init_ret != 0 ) { + // Sensor init failed. + return -4; + } + + // Set default color palette. + sensor.color_palette = rainbow_table; + + // Disable VSYNC IRQ and callback + sensor_set_vsync_callback(NULL); + + // Set new DMA IRQ handler. + // Disable IRQs. + irq_set_enabled(DCMI_DMA_IRQ, false); + + // Clear DMA interrupts. + dma_irqn_acknowledge_channel(DCMI_DMA, DCMI_DMA_CHANNEL); + + // Remove current handler if any + irq_handler_t irq_handler = irq_get_exclusive_handler(DCMI_DMA_IRQ); + if (irq_handler != NULL) { + irq_remove_handler(DCMI_DMA_IRQ, irq_handler); + } + + // Set new exclusive IRQ handler. + irq_set_exclusive_handler(DCMI_DMA_IRQ, dma_irq_handler); + // Or set shared IRQ handler, but this needs to be called once. + // irq_add_shared_handler(DCMI_DMA_IRQ, dma_irq_handler, PICO_DEFAULT_IRQ_PRIORITY); + + irq_set_enabled(DCMI_DMA_IRQ, true); + + /* All good! */ + sensor.detected = true; + + return 0; +} + +int sensor_reset() +{ + dcmi_abort(); + + // Reset the sensor state + sensor.sde = 0; + sensor.pixformat = 0; + sensor.framesize = 0; + sensor.framerate = 0; + sensor.gainceiling = 0; + sensor.hmirror = false; + sensor.vflip = false; + sensor.transpose = false; + #if MICROPY_PY_IMU + sensor.auto_rotation = sensor.chip_id == OV7690_ID; + #else + sensor.auto_rotation = false; + #endif // MICROPY_PY_IMU + sensor.vsync_callback= NULL; + sensor.frame_callback= NULL; + + // Reset default color palette. + sensor.color_palette = rainbow_table; + + // Restore shutdown state on reset. + sensor_shutdown(false); + + // Hard-reset the sensor + if (sensor.reset_pol == ACTIVE_HIGH) { + DCMI_RESET_HIGH(); + mp_hal_delay_ms(10); + DCMI_RESET_LOW(); + } else { + DCMI_RESET_LOW(); + mp_hal_delay_ms(10); + DCMI_RESET_HIGH(); + } + mp_hal_delay_ms(20); + + // Call sensor-specific reset function + if (sensor.reset(&sensor) != 0) { + return -1; + } + + // Reset framebuffers + framebuffer_reset_buffers(); + return 0; +} + +int sensor_get_id() +{ + return sensor.chip_id; +} + +bool sensor_is_detected() +{ + return sensor.detected; +} + +int sensor_sleep(int enable) +{ + if (sensor.sleep == NULL + || sensor.sleep(&sensor, enable) != 0) { + // Operation not supported + return -1; + } + return 0; +} + +int sensor_shutdown(int enable) +{ + int ret = 0; + if (enable) { + if (sensor.pwdn_pol == ACTIVE_HIGH) { + DCMI_PWDN_HIGH(); + } else { + DCMI_PWDN_LOW(); + } + } else { + if (sensor.pwdn_pol == ACTIVE_HIGH) { + DCMI_PWDN_LOW(); + } else { + DCMI_PWDN_HIGH(); + } + } + + mp_hal_delay_ms(10); + return ret; +} + +int sensor_read_reg(uint16_t reg_addr) +{ + if (sensor.read_reg == NULL) { + // Operation not supported + return -1; + } + return sensor.read_reg(&sensor, reg_addr); +} + +int sensor_write_reg(uint16_t reg_addr, uint16_t reg_data) +{ + if (sensor.write_reg == NULL) { + // Operation not supported + return -1; + } + return sensor.write_reg(&sensor, reg_addr, reg_data); +} + +int sensor_set_pixformat(pixformat_t pixformat) +{ + if (sensor.pixformat == pixformat) { + // No change + return 0; + } + + // Flush previous frame. + framebuffer_update_jpeg_buffer(); + + if (sensor.set_pixformat == NULL + || sensor.set_pixformat(&sensor, pixformat) != 0) { + // Operation not supported + return -1; + } + + // wait for the camera to settle + mp_hal_delay_ms(100); + + // Set pixel format + sensor.pixformat = pixformat; + + // Skip the first frame. + MAIN_FB()->bpp = -1; + + // Reconfigure PIO DCMI program. + dcmi_config(pixformat); + + return 0; +} + +int sensor_set_framesize(framesize_t framesize) +{ + if (sensor.framesize == framesize) { + // No change + return 0; + } + + // Flush previous frame. + framebuffer_update_jpeg_buffer(); + + // Call the sensor specific function + if (sensor.set_framesize == NULL + || sensor.set_framesize(&sensor, framesize) != 0) { + // Operation not supported + return -1; + } + + // wait for the camera to settle + mp_hal_delay_ms(100); + + // Set framebuffer size + sensor.framesize = framesize; + + // Skip the first frame. + MAIN_FB()->bpp = -1; + + // Set MAIN FB x offset, y offset, width, height, backup width, and backup height. + MAIN_FB()->x = 0; + MAIN_FB()->y = 0; + MAIN_FB()->w = MAIN_FB()->u = resolution[framesize][0]; + MAIN_FB()->h = MAIN_FB()->v = resolution[framesize][1]; + + // Pickout a good buffer count for the user. + framebuffer_auto_adjust_buffers(); + return 0; +} + +int sensor_set_framerate(int framerate) +{ + if (sensor.framerate == framerate) { + // No change + return 0; + } + + // Call the sensor specific function + if (sensor.set_framerate == NULL + || sensor.set_framerate(&sensor, framerate) != 0) { + // Operation not supported + return -1; + } + + return 0; +} + +int sensor_set_windowing(int x, int y, int w, int h) +{ + return -1; +} + +int sensor_set_contrast(int level) +{ + if (sensor.set_contrast != NULL) { + return sensor.set_contrast(&sensor, level); + } + return -1; +} + +int sensor_set_brightness(int level) +{ + if (sensor.set_brightness != NULL) { + return sensor.set_brightness(&sensor, level); + } + return -1; +} + +int sensor_set_saturation(int level) +{ + if (sensor.set_saturation != NULL) { + return sensor.set_saturation(&sensor, level); + } + return -1; +} + +int sensor_set_gainceiling(gainceiling_t gainceiling) +{ + if (sensor.gainceiling == gainceiling) { + /* no change */ + return 0; + } + + /* call the sensor specific function */ + if (sensor.set_gainceiling == NULL + || sensor.set_gainceiling(&sensor, gainceiling) != 0) { + /* operation not supported */ + return -1; + } + + sensor.gainceiling = gainceiling; + return 0; +} + +int sensor_set_quality(int qs) +{ + /* call the sensor specific function */ + if (sensor.set_quality == NULL + || sensor.set_quality(&sensor, qs) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_set_colorbar(int enable) +{ + /* call the sensor specific function */ + if (sensor.set_colorbar == NULL + || sensor.set_colorbar(&sensor, enable) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_set_auto_gain(int enable, float gain_db, float gain_db_ceiling) +{ + /* call the sensor specific function */ + if (sensor.set_auto_gain == NULL + || sensor.set_auto_gain(&sensor, enable, gain_db, gain_db_ceiling) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_get_gain_db(float *gain_db) +{ + /* call the sensor specific function */ + if (sensor.get_gain_db == NULL + || sensor.get_gain_db(&sensor, gain_db) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_set_auto_exposure(int enable, int exposure_us) +{ + /* call the sensor specific function */ + if (sensor.set_auto_exposure == NULL + || sensor.set_auto_exposure(&sensor, enable, exposure_us) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_get_exposure_us(int *exposure_us) +{ + /* call the sensor specific function */ + if (sensor.get_exposure_us == NULL + || sensor.get_exposure_us(&sensor, exposure_us) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_set_auto_whitebal(int enable, float r_gain_db, float g_gain_db, float b_gain_db) +{ + /* call the sensor specific function */ + if (sensor.set_auto_whitebal == NULL + || sensor.set_auto_whitebal(&sensor, enable, r_gain_db, g_gain_db, b_gain_db) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_get_rgb_gain_db(float *r_gain_db, float *g_gain_db, float *b_gain_db) +{ + /* call the sensor specific function */ + if (sensor.get_rgb_gain_db == NULL + || sensor.get_rgb_gain_db(&sensor, r_gain_db, g_gain_db, b_gain_db) != 0) { + /* operation not supported */ + return -1; + } + return 0; +} + +int sensor_set_hmirror(int enable) +{ + if (sensor.hmirror == ((bool) enable)) { + /* no change */ + return 0; + } + + /* call the sensor specific function */ + if (sensor.set_hmirror == NULL + || sensor.set_hmirror(&sensor, enable) != 0) { + /* operation not supported */ + return -1; + } + sensor.hmirror = enable; + mp_hal_delay_ms(100); // wait for the camera to settle + return 0; +} + +bool sensor_get_hmirror() +{ + return sensor.hmirror; +} + +int sensor_set_vflip(int enable) +{ + if (sensor.vflip == ((bool) enable)) { + /* no change */ + return 0; + } + + /* call the sensor specific function */ + if (sensor.set_vflip == NULL + || sensor.set_vflip(&sensor, enable) != 0) { + /* operation not supported */ + return -1; + } + sensor.vflip = enable; + mp_hal_delay_ms(100); // wait for the camera to settle + return 0; +} + +bool sensor_get_vflip() +{ + return sensor.vflip; +} + +int sensor_set_transpose(bool enable) +{ + if (sensor.transpose == enable) { + /* no change */ + return 0; + } + + if (sensor.pixformat == PIXFORMAT_JPEG) { + return -1; + } + + sensor.transpose = enable; + return 0; +} + +bool sensor_get_transpose() +{ + return sensor.transpose; +} + +int sensor_set_auto_rotation(bool enable) +{ + if (sensor.auto_rotation == enable) { + /* no change */ + return 0; + } + + if (sensor.pixformat == PIXFORMAT_JPEG) { + return -1; + } + + sensor.auto_rotation = enable; + return 0; +} + +bool sensor_get_auto_rotation() +{ + return sensor.auto_rotation; +} + +int sensor_set_framebuffers(int count) +{ + // Flush previous frame. + framebuffer_update_jpeg_buffer(); + + return framebuffer_set_buffers(count); +} + +int sensor_set_special_effect(sde_t sde) +{ + if (sensor.sde == sde) { + /* no change */ + return 0; + } + + /* call the sensor specific function */ + if (sensor.set_special_effect == NULL + || sensor.set_special_effect(&sensor, sde) != 0) { + /* operation not supported */ + return -1; + } + + sensor.sde = sde; + return 0; +} + +int sensor_set_lens_correction(int enable, int radi, int coef) +{ + /* call the sensor specific function */ + if (sensor.set_lens_correction == NULL + || sensor.set_lens_correction(&sensor, enable, radi, coef) != 0) { + /* operation not supported */ + return -1; + } + + return 0; +} + +int sensor_ioctl(int request, ... /* arg */) +{ + int ret = -1; + + if (sensor.ioctl != NULL) { + va_list ap; + va_start(ap, request); + /* call the sensor specific function */ + ret = sensor.ioctl(&sensor, request, ap); + va_end(ap); + } + + return ret; +} + +int sensor_set_vsync_callback(vsync_cb_t vsync_cb) +{ + sensor.vsync_callback = vsync_cb; + if (sensor.vsync_callback == NULL) { + // Disable VSYNC EXTI IRQ + } else { + // Enable VSYNC EXTI IRQ + } + return 0; +} + +int sensor_set_frame_callback(frame_cb_t vsync_cb) +{ + sensor.frame_callback = vsync_cb; + return 0; +} + +int sensor_set_color_palette(const uint16_t *color_palette) +{ + sensor.color_palette = color_palette; + return 0; +} + +const uint16_t *sensor_get_color_palette() +{ + return sensor.color_palette; +} + +void VsyncExtiCallback() +{ + if (sensor.vsync_callback != NULL) { + //sensor.vsync_callback(HAL_GPIO_ReadPin(DCMI_VSYNC_PORT, DCMI_VSYNC_PIN)); + } +} + +// To make the user experience better we automatically shrink the size of the MAIN_FB() to fit +// within the RAM we have onboard the system. +int sensor_check_buffsize() +{ + uint32_t bpp; + uint32_t size = framebuffer_get_buffer_size(); + + switch (sensor.pixformat) { + case PIXFORMAT_GRAYSCALE: + case PIXFORMAT_BAYER: + bpp = 1; + break; + case PIXFORMAT_RGB565: + case PIXFORMAT_YUV422: + bpp = 2; + break; + default: + return -1; + } + + // This driver doesn't support windowing or anything like that. + if ((MAIN_FB()->u * MAIN_FB()->v * bpp) > size) { + return -1; + } + + return 0; +} + +static void dma_irq_handler() +{ + // Clear the interrupt request. + dma_irqn_acknowledge_channel(DCMI_DMA, DCMI_DMA_CHANNEL); + + framebuffer_get_tail(FB_NO_FLAGS); + vbuffer_t *buffer = framebuffer_get_tail(FB_PEEK); + if (buffer != NULL) { + // Set next buffer and retrigger the DMA channel. + dma_channel_set_write_addr(DCMI_DMA_CHANNEL, buffer->data, true); + + // Unblock the state machine + pio_sm_restart(DCMI_PIO, DCMI_SM); + pio_sm_clear_fifos(DCMI_PIO, DCMI_SM); + pio_sm_put_blocking(DCMI_PIO, DCMI_SM, (MAIN_FB()->v - 1)); + pio_sm_put_blocking(DCMI_PIO, DCMI_SM, (MAIN_FB()->u * MAIN_FB()->bpp) - 1); + } +} + +// This is the default snapshot function, which can be replaced in sensor_init functions. +int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags) +{ + // Compress the framebuffer for the IDE preview. + framebuffer_update_jpeg_buffer(); + + if (sensor_check_buffsize() != 0) { + return -1; + } + + // Free the current FB head. + framebuffer_free_current_buffer(); + + switch (sensor->pixformat) { + case PIXFORMAT_BAYER: + case PIXFORMAT_GRAYSCALE: + MAIN_FB()->bpp = 1; + break; + case PIXFORMAT_YUV422: + case PIXFORMAT_RGB565: + MAIN_FB()->bpp = 2; + break; + default: + return -1; + } + + vbuffer_t *buffer = framebuffer_get_head(FB_NO_FLAGS); + + // If there's no ready buffer in the fifo, and the DMA is Not currently + // transferring a new buffer, reconfigure and restart the DMA transfer. + if (buffer == NULL && !dma_channel_is_busy(DCMI_DMA_CHANNEL)) { + buffer = framebuffer_get_tail(FB_PEEK); + if (buffer == NULL) { + return -1; + } + + // Configure the DMA on the first frame, for later frames only the write is changed. + dma_config(MAIN_FB()->u, MAIN_FB()->v, MAIN_FB()->bpp, (void *) buffer->data, + (SENSOR_HW_FLAGS_GET(sensor, SENSOR_HW_FLAGS_RGB565_REV) && MAIN_FB()->bpp == 2)); + + // Unblock the state machine + pio_sm_put_blocking(DCMI_PIO, DCMI_SM, (MAIN_FB()->v - 1)); + pio_sm_put_blocking(DCMI_PIO, DCMI_SM, (MAIN_FB()->u * MAIN_FB()->bpp) - 1); + } + + // Wait for the DMA to finish the transfer. + for (mp_uint_t ticks = mp_hal_ticks_ms(); buffer == NULL;) { + buffer = framebuffer_get_head(FB_NO_FLAGS); + if ((mp_hal_ticks_ms() - ticks) > 3000) { + dcmi_abort(); + return -1; + } + } + + MAIN_FB()->w = MAIN_FB()->u; + MAIN_FB()->h = MAIN_FB()->v; + + // Set the user image. + if (image != NULL) { + image->w = MAIN_FB()->w; + image->h = MAIN_FB()->h; + image->bpp = MAIN_FB()->bpp; + image->pixels = buffer->data; + } + + return 0; +}