mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
ports/mimxrt: Add MIMXRT OMV port.
This commit is contained in:
parent
9e6efd28c9
commit
a7033e1b3a
@ -1 +1 @@
|
|||||||
Subproject commit 832393b522acfaca4ccc60a8ee200087aa6ca345
|
Subproject commit 93d0a29efaa830f3be2ab5b7dd47110c814ca9d4
|
||||||
366
src/omv/ports/mimxrt/main.c
Normal file
366
src/omv/ports/mimxrt/main.c
Normal file
@ -0,0 +1,366 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
* Copyright (c) 2023 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
*
|
||||||
|
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
*
|
||||||
|
* main function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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 "shared/readline/readline.h"
|
||||||
|
#include "shared/runtime/gchelper.h"
|
||||||
|
#include "shared/runtime/pyexec.h"
|
||||||
|
#include "shared/runtime/softtimer.h"
|
||||||
|
#include "ticks.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
#include "led.h"
|
||||||
|
#include "pendsv.h"
|
||||||
|
#include "modmachine.h"
|
||||||
|
#include "sdcard.h"
|
||||||
|
#include "systick.h"
|
||||||
|
#include "modmimxrt.h"
|
||||||
|
|
||||||
|
#if MICROPY_PY_LWIP
|
||||||
|
#include "lwip/init.h"
|
||||||
|
#include "lwip/apps/mdns.h"
|
||||||
|
#if MICROPY_PY_NETWORK_CYW43
|
||||||
|
#include "lib/cyw43-driver/src/cyw43.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MICROPY_PY_BLUETOOTH
|
||||||
|
#include "mpbthciport.h"
|
||||||
|
#include "extmod/modbluetooth.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MICROPY_PY_NETWORK
|
||||||
|
#include "extmod/modnetwork.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "extmod/vfs.h"
|
||||||
|
#include "extmod/vfs_fat.h"
|
||||||
|
#include "common/factoryreset.h"
|
||||||
|
|
||||||
|
#include "omv_boardconfig.h"
|
||||||
|
#include "framebuffer.h"
|
||||||
|
#include "sensor.h"
|
||||||
|
#include "usbdbg.h"
|
||||||
|
#include "tinyusb_debug.h"
|
||||||
|
#include "fb_alloc.h"
|
||||||
|
#include "dma_alloc.h"
|
||||||
|
#include "ff_wrapper.h"
|
||||||
|
#include "mimxrt_hal.h"
|
||||||
|
|
||||||
|
extern uint8_t _sstack, _estack, _heap_start, _heap_end;
|
||||||
|
|
||||||
|
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, true);
|
||||||
|
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(void) {
|
||||||
|
bool sdcard_mounted = false;
|
||||||
|
bool first_soft_reset = true;
|
||||||
|
|
||||||
|
mimxrt_hal_init();
|
||||||
|
ticks_init();
|
||||||
|
led_init();
|
||||||
|
pendsv_init();
|
||||||
|
|
||||||
|
soft_reset:
|
||||||
|
#if defined(MICROPY_HW_LED1)
|
||||||
|
led_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Initialise stack extents and GC heap.
|
||||||
|
mp_stack_set_top(&_estack);
|
||||||
|
mp_stack_set_limit(&_estack - &_sstack - 1024);
|
||||||
|
gc_init(&_heap_start, &_heap_end);
|
||||||
|
|
||||||
|
// Initialise MicroPython runtime.
|
||||||
|
mp_init();
|
||||||
|
|
||||||
|
// Initialise low-level sub-systems.
|
||||||
|
#if MICROPY_PY_LCD
|
||||||
|
py_lcd_init0();
|
||||||
|
#endif
|
||||||
|
//py_fir_init0();
|
||||||
|
#if MICROPY_PY_TV
|
||||||
|
py_tv_init0();
|
||||||
|
#endif
|
||||||
|
#if MICROPY_PY_BUZZER
|
||||||
|
py_buzzer_init0();
|
||||||
|
#endif // MICROPY_PY_BUZZER
|
||||||
|
imlib_init_all();
|
||||||
|
readline_init0();
|
||||||
|
#if MICROPY_HW_ENABLE_CAN
|
||||||
|
can_init0();
|
||||||
|
#endif
|
||||||
|
fb_alloc_init0();
|
||||||
|
framebuffer_init0();
|
||||||
|
sensor_init0();
|
||||||
|
//dma_alloc_init0();
|
||||||
|
#ifdef IMLIB_ENABLE_IMAGE_FILE_IO
|
||||||
|
file_buffer_init0();
|
||||||
|
#endif
|
||||||
|
#if MICROPY_HW_ENABLE_SERVO
|
||||||
|
servo_init();
|
||||||
|
#endif
|
||||||
|
usbdbg_init();
|
||||||
|
machine_adc_init();
|
||||||
|
#if MICROPY_PY_MACHINE_SDCARD
|
||||||
|
machine_sdcard_init0();
|
||||||
|
sdcard_init_pins(&mimxrt_sdcard_objs[MICROPY_HW_SDCARD_SDMMC - 1]);
|
||||||
|
#endif
|
||||||
|
#if MICROPY_PY_MACHINE_I2S
|
||||||
|
machine_i2s_init0();
|
||||||
|
#endif
|
||||||
|
machine_rtc_start();
|
||||||
|
|
||||||
|
#if MICROPY_PY_LWIP
|
||||||
|
// lwIP doesn't allow to reinitialise itself by subsequent calls to this function
|
||||||
|
// because the system timeout list (next_timeout) is only ever reset by BSS clearing.
|
||||||
|
// So for now we only init the lwIP stack once on power-up.
|
||||||
|
if (first_soft_reset) {
|
||||||
|
lwip_init();
|
||||||
|
#if LWIP_MDNS_RESPONDER
|
||||||
|
mdns_resp_init();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
systick_enable_dispatch(SYSTICK_DISPATCH_LWIP, mod_network_lwip_poll_wrapper);
|
||||||
|
#endif
|
||||||
|
#if MICROPY_PY_BLUETOOTH
|
||||||
|
mp_bluetooth_hci_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MICROPY_PY_NETWORK_CYW43
|
||||||
|
if (first_soft_reset) {
|
||||||
|
cyw43_init(&cyw43_state);
|
||||||
|
uint8_t buf[8];
|
||||||
|
memcpy(&buf[0], "PYBD", 4);
|
||||||
|
mp_hal_get_mac_ascii(MP_HAL_MAC_WLAN0, 8, 4, (char *)&buf[4]);
|
||||||
|
cyw43_wifi_ap_set_ssid(&cyw43_state, 8, buf);
|
||||||
|
cyw43_wifi_ap_set_password(&cyw43_state, 8, (const uint8_t *)"pybd0123");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MICROPY_PY_NETWORK
|
||||||
|
mod_network_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MICROPY_PY_SENSOR
|
||||||
|
if (first_soft_reset
|
||||||
|
&& sensor_init() != 0) {
|
||||||
|
printf("sensor init failed!\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Mount or create a fresh filesystem.
|
||||||
|
mp_obj_t mount_point = MP_OBJ_NEW_QSTR(MP_QSTR__slash_);
|
||||||
|
#if MICROPY_PY_MACHINE_SDCARD
|
||||||
|
if (sdcard_detect(&mimxrt_sdcard_objs[MICROPY_HW_SDCARD_SDMMC - 1])) {
|
||||||
|
mp_obj_t args[] = { MP_OBJ_NEW_SMALL_INT(MICROPY_HW_SDCARD_SDMMC) };
|
||||||
|
mp_obj_t bdev = MP_OBJ_TYPE_GET_SLOT(&machine_sdcard_type, make_new)(&machine_sdcard_type, 1, 0, args);
|
||||||
|
if (mp_vfs_mount_and_chdir_protected(bdev, mount_point) == 0) {
|
||||||
|
mimxrt_msc_medium = &machine_sdcard_type;
|
||||||
|
sdcard_mounted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (sdcard_mounted == false) {
|
||||||
|
mp_obj_t bdev = MP_OBJ_TYPE_GET_SLOT(&mimxrt_flash_type, make_new)(&mimxrt_flash_type, 0, 0, NULL);
|
||||||
|
if (mp_vfs_mount_and_chdir_protected(bdev, mount_point) == 0) {
|
||||||
|
mimxrt_msc_medium = &mimxrt_flash_type;
|
||||||
|
} else {
|
||||||
|
// Create a fresh filesystem.
|
||||||
|
fs_user_mount_t *vfs = MP_OBJ_TYPE_GET_SLOT(&mp_fat_vfs_type, make_new)(&mp_fat_vfs_type, 1, 0, &bdev);
|
||||||
|
if (factoryreset_create_filesystem(vfs) == 0) {
|
||||||
|
if (mp_vfs_mount_and_chdir_protected(bdev, mount_point) == 0) {
|
||||||
|
mimxrt_msc_medium = &mimxrt_flash_type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deferred tusb_init to allow the filesystem to be mounted/created before MSC.
|
||||||
|
if (!tusb_inited()) {
|
||||||
|
tusb_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(), true);
|
||||||
|
// Disable IDE interrupts
|
||||||
|
usbdbg_set_irq_enabled(false);
|
||||||
|
nlr_pop();
|
||||||
|
} else {
|
||||||
|
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usbdbg_is_busy() && nlr_push(&nlr) == 0) {
|
||||||
|
// Enable IDE interrupt
|
||||||
|
usbdbg_set_irq_enabled(true);
|
||||||
|
// Wait for the current command to finish.
|
||||||
|
usbdbg_wait_for_command(1000);
|
||||||
|
// Disable IDE interrupts
|
||||||
|
usbdbg_set_irq_enabled(false);
|
||||||
|
nlr_pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n");
|
||||||
|
machine_pin_irq_deinit();
|
||||||
|
#if MICROPY_PY_LWIP
|
||||||
|
systick_disable_dispatch(SYSTICK_DISPATCH_LWIP);
|
||||||
|
#endif
|
||||||
|
#if MICROPY_PY_BLUETOOTH
|
||||||
|
mp_bluetooth_deinit();
|
||||||
|
#endif
|
||||||
|
#if MICROPY_PY_NETWORK
|
||||||
|
mod_network_deinit();
|
||||||
|
#endif
|
||||||
|
#if MICROPY_PY_MACHINE_I2S
|
||||||
|
machine_i2s_deinit_all();
|
||||||
|
#endif
|
||||||
|
machine_pwm_deinit_all();
|
||||||
|
soft_timer_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();
|
||||||
|
gc_collect_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void nlr_jump_fail(void *val) {
|
||||||
|
for (;;) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fatal_error()
|
||||||
|
{
|
||||||
|
nlr_jump_fail(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) {
|
||||||
|
mp_printf(MP_PYTHON_PRINTER, "Assertion '%s' failed, at file %s:%d\n", expr, file, line);
|
||||||
|
for (;;) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char mimxrt_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. \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())\n"
|
||||||
|
"\n"
|
||||||
|
" Pins are numbered board specific, either 0-n, or 'D0'-'Dn', or 'A0' - 'An',\n"
|
||||||
|
" according to the boards's pinout sheet.\n"
|
||||||
|
" Pin IO modes are: Pin.IN, Pin.OUT, Pin.OPEN_DRAIN\n"
|
||||||
|
" Pin pull modes are: Pin.PULL_UP, Pin.PULL_UP_47K, Pin.PULL_UP_22K, Pin.PULL_DOWN, Pin.PULL_HOLD\n"
|
||||||
|
" machine.ADC(pin) -- make an analog object from a pin\n"
|
||||||
|
" methods: read_u16()\n"
|
||||||
|
" machine.UART(id, baudrate=115200) -- create an UART object (id=1 - 8, board-specific)\n"
|
||||||
|
" methods: init(), write(buf), any()\n"
|
||||||
|
" buf=read(n), readinto(buf), buf=readline()\n"
|
||||||
|
" The RX and TX pins are fixed and board-specific.\n"
|
||||||
|
" machine.SoftI2C() -- create a Soft I2C object\n"
|
||||||
|
" machine.I2C(id) -- create a HW I2C object\n"
|
||||||
|
" methods: readfrom(addr, buf, stop=True), writeto(addr, buf, stop=True)\n"
|
||||||
|
" readfrom_mem(addr, memaddr, arg), writeto_mem(addr, memaddr, arg)\n"
|
||||||
|
" SoftI2C allows to use any pin for sda and scl, HW I2C id's and pins are fixed\n"
|
||||||
|
" machine.SoftSPI(baudrate=1000000) -- create a Soft SPI object\n"
|
||||||
|
" machine.SPI(id, baudrate=1000000) -- create a HW SPI object\n"
|
||||||
|
" methods: read(nbytes, write=0x00), write(buf), write_readinto(wr_buf, rd_buf)\n"
|
||||||
|
" SoftSPI allows to use any pin for SPI, HW SPI id's and pins are fixed\n"
|
||||||
|
" machine.Timer(id, freq, callback) -- create a hardware timer object (id=0,1,2)\n"
|
||||||
|
" eg: machine.Timer(freq=1, callback=lambda t:print(t))\n"
|
||||||
|
" machine.RTC() -- create a Real Time Clock object\n"
|
||||||
|
" methods: init(), datetime([dateime_tuple]), now()\n"
|
||||||
|
" machine.PWM(pin, freq, duty_u16[, kw_opts]) -- create a PWM object\n"
|
||||||
|
" methods: init(), duty_u16([value]), duty_ns([value]), freq([value])\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"
|
||||||
|
;
|
||||||
250
src/omv/ports/mimxrt/mimxrt.ld.S
Normal file
250
src/omv/ports/mimxrt/mimxrt.ld.S
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
* Copyright (c) 2023 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
*
|
||||||
|
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
*
|
||||||
|
* Linker script for MIMXRT Devices.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Entry Point */
|
||||||
|
ENTRY(Reset_Handler)
|
||||||
|
|
||||||
|
#include "omv_boardconfig.h"
|
||||||
|
|
||||||
|
/* Specify the memory areas */
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
FLASH (rx): ORIGIN = OMV_FLASH_ORIGIN, LENGTH = OMV_FLASH_LENGTH
|
||||||
|
FLASH_FCB (RX): ORIGIN = OMV_FLASH_APP_ORIGIN + 0x0000, LENGTH = 0x00001000
|
||||||
|
FLASH_IVT (RX): ORIGIN = OMV_FLASH_APP_ORIGIN + 0x1000, LENGTH = 0x00001000
|
||||||
|
FLASH_ISR (RX): ORIGIN = OMV_FLASH_APP_ORIGIN + 0x2000, LENGTH = 0x00001000
|
||||||
|
FLASH_TEXT (RX): ORIGIN = OMV_FLASH_TXT_ORIGIN, LENGTH = OMV_FLASH_TXT_LENGTH
|
||||||
|
FLASH_VFS (RX): ORIGIN = OMV_FLASH_FFS_ORIGIN, LENGTH = OMV_FLASH_FFS_LENGTH
|
||||||
|
#if defined(OMV_ITCM1_ORIGIN)
|
||||||
|
ITCM1 (RWX): ORIGIN = OMV_ITCM1_ORIGIN, LENGTH = OMV_ITCM1_LENGTH
|
||||||
|
#endif
|
||||||
|
#if defined(OMV_ITCM2_ORIGIN)
|
||||||
|
ITCM2 (RWX): ORIGIN = OMV_ITCM2_ORIGIN, LENGTH = OMV_ITCM2_LENGTH
|
||||||
|
#endif
|
||||||
|
#if defined(OMV_DTCM_ORIGIN)
|
||||||
|
DTCM (RWX): ORIGIN = OMV_DTCM_ORIGIN, LENGTH = OMV_DTCM_LENGTH
|
||||||
|
#endif
|
||||||
|
#if defined(OMV_OCRM1_ORIGIN)
|
||||||
|
OCRM1 (RWX): ORIGIN = OMV_OCRM1_ORIGIN, LENGTH = OMV_OCRM1_LENGTH
|
||||||
|
#endif
|
||||||
|
#if defined(OMV_OCRM2_ORIGIN)
|
||||||
|
OCRM2 (RWX): ORIGIN = OMV_OCRM2_ORIGIN, LENGTH = OMV_OCRM2_LENGTH
|
||||||
|
#endif
|
||||||
|
#if defined(OMV_DRAM_ORIGIN)
|
||||||
|
DRAM (RWX): ORIGIN = OMV_DRAM_ORIGIN, LENGTH = OMV_DRAM_LENGTH
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
_start = main;
|
||||||
|
__flash_start = ORIGIN(FLASH);
|
||||||
|
__sdram_start = ORIGIN(DRAM);
|
||||||
|
__vfs_start = ORIGIN(FLASH_VFS);
|
||||||
|
__vfs_end = ORIGIN(FLASH_VFS) + LENGTH(FLASH_VFS);
|
||||||
|
|
||||||
|
// FlexRAM configuration addresses and settings
|
||||||
|
__iomux_gpr14_adr = 0x400AC038;
|
||||||
|
__iomux_gpr16_adr = 0x400AC040;
|
||||||
|
__iomux_gpr17_adr = 0x400AC044;
|
||||||
|
__iomux_gpr17_value = OMV_FLEXRAM_CONFIG;
|
||||||
|
|
||||||
|
#if defined(OMV_JPEG_MEMORY)
|
||||||
|
#if !defined(OMV_JPEG_MEMORY_OFFSET)
|
||||||
|
#define OMV_JPEG_MEMORY_OFFSET (0)
|
||||||
|
#endif
|
||||||
|
_jpeg_buf = ORIGIN(OMV_JPEG_MEMORY) + OMV_JPEG_MEMORY_OFFSET;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OMV_VOSPI_MEMORY)
|
||||||
|
#if !defined(OMV_VOSPI_MEMORY_OFFSET)
|
||||||
|
#define OMV_VOSPI_MEMORY_OFFSET (0)
|
||||||
|
#endif
|
||||||
|
_vospi_buf = ORIGIN(OMV_VOSPI_MEMORY) + OMV_VOSPI_MEMORY_OFFSET;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Location of filesystem flash storage
|
||||||
|
// Not used in MIMXRT port.
|
||||||
|
// _micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FFS);
|
||||||
|
// _micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FFS) + LENGTH(FLASH_FFS);
|
||||||
|
|
||||||
|
/* Define output sections */
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.fcb :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
__FLASH_BASE = .;
|
||||||
|
KEEP(* (.boot_hdr.conf)) /* flash config section */
|
||||||
|
. = ALIGN(4);
|
||||||
|
} > FLASH_FCB
|
||||||
|
|
||||||
|
.ivt :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
KEEP(* (.boot_hdr.ivt)) /* ivt section */
|
||||||
|
KEEP(* (.boot_hdr.boot_data)) /* boot section */
|
||||||
|
KEEP(* (.boot_hdr.dcd_data)) /* dcd section */
|
||||||
|
. = ALIGN(4);
|
||||||
|
} > FLASH_IVT
|
||||||
|
|
||||||
|
/* The startup code goes first into internal RAM */
|
||||||
|
.isr :
|
||||||
|
{
|
||||||
|
__VECTOR_TABLE = .;
|
||||||
|
__Vectors = .;
|
||||||
|
. = ALIGN(4);
|
||||||
|
KEEP(*(.isr_vector)) /* Startup code */
|
||||||
|
. = ALIGN(4);
|
||||||
|
} > FLASH_ISR
|
||||||
|
|
||||||
|
/* The program code and other data goes into internal RAM */
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(EXCLUDE_FILE(*fsl_flexspi.o *gc.o *vm.o *parse*.o *runtime*.o *map.o *mpirq.o ) .text*)
|
||||||
|
*(.rodata)
|
||||||
|
*(.rodata*)
|
||||||
|
*(.glue_7)
|
||||||
|
*(.glue_7t)
|
||||||
|
*(.eh_frame)
|
||||||
|
KEEP (*(.init))
|
||||||
|
KEEP (*(.fini))
|
||||||
|
. = ALIGN(4);
|
||||||
|
} > FLASH_TEXT
|
||||||
|
|
||||||
|
.ARM :
|
||||||
|
{
|
||||||
|
__exidx_start = .;
|
||||||
|
*(.ARM.exidx*)
|
||||||
|
__exidx_end = .;
|
||||||
|
} > FLASH_TEXT
|
||||||
|
|
||||||
|
__etext = .; /* define a global symbol at end of code */
|
||||||
|
|
||||||
|
/* Initialized data sections */
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_ram_start = .;
|
||||||
|
__DATA_RAM = .;
|
||||||
|
__data_start__ = .; /* create a global symbol at data start */
|
||||||
|
*(m_usb_dma_init_data)
|
||||||
|
*(.data) /* .data sections */
|
||||||
|
*(.data*) /* .data* sections */
|
||||||
|
KEEP(*(.jcr*))
|
||||||
|
. = ALIGN(4);
|
||||||
|
__data_end__ = .; /* define a global symbol at data end */
|
||||||
|
} > OMV_MAIN_MEMORY AT> FLASH_TEXT
|
||||||
|
|
||||||
|
.ram_function :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
__ram_function_start__ = .;
|
||||||
|
*(.ram_functions*)
|
||||||
|
*(.text*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
__ram_function_end__ = .;
|
||||||
|
} > OMV_RAMFUNC_MEMORY AT> FLASH_TEXT
|
||||||
|
|
||||||
|
/* Uninitialized data section */
|
||||||
|
.bss (NOLOAD) :
|
||||||
|
{
|
||||||
|
/* This is used by the startup in order to initialize the .bss section */
|
||||||
|
. = ALIGN(4);
|
||||||
|
__START_BSS = .;
|
||||||
|
__bss_start__ = .;
|
||||||
|
*(m_usb_dma_noninit_data)
|
||||||
|
*(.bss)
|
||||||
|
*(.bss*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_ebss = .;
|
||||||
|
__bss_end__ = .;
|
||||||
|
__END_BSS = .;
|
||||||
|
} > OMV_MAIN_MEMORY
|
||||||
|
|
||||||
|
._heap (NOLOAD) :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_heap_start = .;
|
||||||
|
. = . + OMV_HEAP_SIZE;
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
_heap_end = .;
|
||||||
|
|
||||||
|
} > OMV_MAIN_MEMORY
|
||||||
|
|
||||||
|
._stack (NOLOAD) :
|
||||||
|
{
|
||||||
|
. = ALIGN(8);
|
||||||
|
_sstack = .;
|
||||||
|
. = . + OMV_STACK_SIZE;
|
||||||
|
|
||||||
|
. = ALIGN(8);
|
||||||
|
_estack = .;
|
||||||
|
__stack = .;
|
||||||
|
} >OMV_STACK_MEMORY
|
||||||
|
|
||||||
|
/* Main framebuffer memory */
|
||||||
|
.fb_memory (NOLOAD) :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_fb_base = .;
|
||||||
|
. += OMV_FB_SIZE;
|
||||||
|
|
||||||
|
_fb_end = .;
|
||||||
|
. += OMV_FB_ALLOC_SIZE;
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
_fballoc = .;
|
||||||
|
. = ALIGN(4);
|
||||||
|
} >OMV_FB_MEMORY
|
||||||
|
|
||||||
|
#if defined(OMV_FB_OVERLAY_MEMORY)
|
||||||
|
.fb_overlay_memory (NOLOAD) :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_fballoc_overlay_start = .;
|
||||||
|
. = . + OMV_FB_OVERLAY_SIZE;
|
||||||
|
_fballoc_overlay_end = .;
|
||||||
|
} >OMV_FB_OVERLAY_MEMORY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Misc DMA buffers section */
|
||||||
|
.dma_memory (NOLOAD) :
|
||||||
|
{
|
||||||
|
. = ALIGN(8);
|
||||||
|
_line_buf = .; // Image line buffer.
|
||||||
|
. = . + OMV_LINE_BUF_SIZE;
|
||||||
|
|
||||||
|
. = ALIGN(16);
|
||||||
|
_msc_buf = .; // USB MSC bot data (2K)
|
||||||
|
. = . + OMV_MSC_BUF_SIZE;
|
||||||
|
|
||||||
|
. = ALIGN(16);
|
||||||
|
_vfs_buf = .; // VFS sturct + FATFS file buffer (around 624 bytes)
|
||||||
|
. = . + OMV_VFS_BUF_SIZE;
|
||||||
|
|
||||||
|
. = ALIGN(16);
|
||||||
|
_fir_lepton_buf = .; // FIR Lepton Packet Double Buffer (328 bytes)
|
||||||
|
. = . + OMV_FIR_LEPTON_BUF_SIZE;
|
||||||
|
|
||||||
|
#if !defined(OMV_JPEG_MEMORY)
|
||||||
|
. = ALIGN(16);
|
||||||
|
_jpeg_buf = .; // IDE JPEG buffer
|
||||||
|
. = . + OMV_JPEG_BUF_SIZE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
. = ALIGN(16);
|
||||||
|
*(.dma_buffer)
|
||||||
|
} >OMV_DMA_MEMORY
|
||||||
|
|
||||||
|
.ARM.attributes 0 : { *(.ARM.attributes) }
|
||||||
|
}
|
||||||
254
src/omv/ports/mimxrt/mimxrt_hal.c
Normal file
254
src/omv/ports/mimxrt/mimxrt_hal.c
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
* Copyright (c) 2023 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
*
|
||||||
|
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
*
|
||||||
|
* MIMXRT HAL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "fsl_gpio.h"
|
||||||
|
#include "fsl_csi.h"
|
||||||
|
#include "fsl_iomuxc.h"
|
||||||
|
#include "fsl_clock.h"
|
||||||
|
#include "fsl_lpuart.h"
|
||||||
|
#include "fsl_lpi2c.h"
|
||||||
|
#include "fsl_romapi.h"
|
||||||
|
#include "fsl_dmamux.h"
|
||||||
|
#include "fsl_usb_phy.h"
|
||||||
|
#include "fsl_device_registers.h"
|
||||||
|
#include CLOCK_CONFIG_H
|
||||||
|
#include "irq.h"
|
||||||
|
|
||||||
|
#include "omv_boardconfig.h"
|
||||||
|
// Define pin objects in this file.
|
||||||
|
#define OMV_GPIO_DEFINE_PINS (1)
|
||||||
|
#include "omv_gpio.h"
|
||||||
|
#include "mimxrt_hal.h"
|
||||||
|
|
||||||
|
const uint8_t dcd_data[] = {0};
|
||||||
|
|
||||||
|
void mimxrt_hal_init()
|
||||||
|
{
|
||||||
|
// Configure and enable clocks.
|
||||||
|
BOARD_BootClockRUN();
|
||||||
|
SystemCoreClockUpdate();
|
||||||
|
|
||||||
|
// Default priority grouping.
|
||||||
|
NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
|
||||||
|
|
||||||
|
// Configure Systick at 1Hz.
|
||||||
|
SysTick_Config(SystemCoreClock / 1000);
|
||||||
|
NVIC_SetPriority(SysTick_IRQn, IRQ_PRI_SYSTICK);
|
||||||
|
|
||||||
|
// Enable I/O clocks.
|
||||||
|
CLOCK_EnableClock(kCLOCK_Iomuxc);
|
||||||
|
CLOCK_EnableClock(kCLOCK_IomuxcSnvs);
|
||||||
|
|
||||||
|
// Enable I cache and D cache
|
||||||
|
SCB_EnableDCache();
|
||||||
|
SCB_EnableICache();
|
||||||
|
|
||||||
|
// SDRAM
|
||||||
|
#ifdef OMV_SDRAM_SIZE
|
||||||
|
extern void mimxrt_sdram_init(void);
|
||||||
|
mimxrt_sdram_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Configure USB physical
|
||||||
|
usb_phy_config_struct_t phyConfig = {
|
||||||
|
OMV_USB_PHY_D_CAL,
|
||||||
|
OMV_USB_PHY_TXCAL45DP,
|
||||||
|
OMV_USB_PHY_TXCAL45DM,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (OMV_USB_PHY_ID == kUSB_ControllerEhci0) {
|
||||||
|
CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
|
||||||
|
CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U);
|
||||||
|
} else {
|
||||||
|
CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
|
||||||
|
CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, 480000000U);
|
||||||
|
}
|
||||||
|
USB_EhciPhyInit(OMV_USB_PHY_ID, BOARD_XTAL0_CLK_HZ, &phyConfig);
|
||||||
|
NVIC_SetPriority(USB_OTG1_IRQn, IRQ_PRI_OTG_HS);
|
||||||
|
|
||||||
|
// Configure shared IO multiplexers.
|
||||||
|
#if defined(OMV_IOMUXC_GPR26_CONFIG)
|
||||||
|
IOMUXC_GPR->GPR26 = ((IOMUXC_GPR->GPR26 &
|
||||||
|
(~(OMV_IOMUXC_GPR26_CONFIG)))
|
||||||
|
| IOMUXC_GPR_GPR26_GPIO_MUX1_GPIO_SEL(0x00U)
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#if defined(OMV_IOMUXC_GPR27_CONFIG)
|
||||||
|
IOMUXC_GPR->GPR27 = ((IOMUXC_GPR->GPR27 &
|
||||||
|
(~(OMV_IOMUXC_GPR27_CONFIG)))
|
||||||
|
| IOMUXC_GPR_GPR27_GPIO_MUX2_GPIO_SEL(0x00U)
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Confgure and enable EDMA
|
||||||
|
edma_config_t edma_config = {0};
|
||||||
|
EDMA_GetDefaultConfig(&edma_config);
|
||||||
|
EDMA_Init(DMA0, &edma_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mimxrt_hal_bootloader()
|
||||||
|
{
|
||||||
|
#if FSL_ROM_HAS_RUNBOOTLOADER_API
|
||||||
|
// Enter ROM bootloader, with primary image active.
|
||||||
|
uint32_t arg = 0xEB000000;
|
||||||
|
ROM_RunBootloader(&arg);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int mimxrt_hal_csi_init(CSI_Type *inst)
|
||||||
|
{
|
||||||
|
CLOCK_EnableClock(kCLOCK_Csi);
|
||||||
|
|
||||||
|
// Configure DCMI pins.
|
||||||
|
omv_gpio_config(DCMI_D0_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1);
|
||||||
|
omv_gpio_config(DCMI_D1_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1);
|
||||||
|
omv_gpio_config(DCMI_D2_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1);
|
||||||
|
omv_gpio_config(DCMI_D3_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1);
|
||||||
|
omv_gpio_config(DCMI_D4_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1);
|
||||||
|
omv_gpio_config(DCMI_D5_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1);
|
||||||
|
omv_gpio_config(DCMI_D6_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1);
|
||||||
|
omv_gpio_config(DCMI_D7_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1);
|
||||||
|
|
||||||
|
omv_gpio_config(DCMI_MCLK_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1);
|
||||||
|
omv_gpio_config(DCMI_HSYNC_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1);
|
||||||
|
omv_gpio_config(DCMI_VSYNC_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1);
|
||||||
|
omv_gpio_config(DCMI_PXCLK_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1);
|
||||||
|
|
||||||
|
// Configure DCMI GPIOs
|
||||||
|
#if defined(DCMI_RESET_PIN)
|
||||||
|
omv_gpio_config(DCMI_RESET_PIN, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_DOWN, OMV_GPIO_SPEED_LOW, -1);
|
||||||
|
#endif
|
||||||
|
#if defined(DCMI_FSYNC_PIN)
|
||||||
|
omv_gpio_config(DCMI_FSYNC_PIN, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_DOWN, OMV_GPIO_SPEED_LOW, -1);
|
||||||
|
#endif
|
||||||
|
#if defined(DCMI_POWER_PIN)
|
||||||
|
omv_gpio_config(DCMI_POWER_PIN, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_LOW, -1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Configure IRQ priority.
|
||||||
|
NVIC_SetPriority(CSI_IRQn, IRQ_PRI_CSI);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mimxrt_hal_i2c_init(uint32_t bus_id)
|
||||||
|
{
|
||||||
|
omv_gpio_t scl_pin = NULL;
|
||||||
|
omv_gpio_t sda_pin = NULL;
|
||||||
|
|
||||||
|
switch (bus_id) {
|
||||||
|
#if defined(LPI2C1_ID)
|
||||||
|
case LPI2C1_ID: {
|
||||||
|
scl_pin = LPI2C1_SCL_PIN;
|
||||||
|
sda_pin = LPI2C1_SDA_PIN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(LPI2C2_ID)
|
||||||
|
case LPI2C2_ID: {
|
||||||
|
scl_pin = LPI2C2_SCL_PIN;
|
||||||
|
sda_pin = LPI2C2_SDA_PIN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(LPI2C3_ID)
|
||||||
|
case LPI2C3_ID: {
|
||||||
|
scl_pin = LPI2C3_SCL_PIN;
|
||||||
|
sda_pin = LPI2C3_SDA_PIN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(LPI2C4_ID)
|
||||||
|
case LPI2C4_ID: {
|
||||||
|
scl_pin = LPI2C4_SCL_PIN;
|
||||||
|
sda_pin = LPI2C4_SDA_PIN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
omv_gpio_config(scl_pin, OMV_GPIO_MODE_ALT_OD, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_LOW, -1);
|
||||||
|
omv_gpio_config(sda_pin, OMV_GPIO_MODE_ALT_OD, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_LOW, -1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mimxrt_hal_spi_init(uint32_t bus_id, bool nss_enable, uint32_t nss_pol)
|
||||||
|
{
|
||||||
|
typedef struct {
|
||||||
|
omv_gpio_t sclk_pin;
|
||||||
|
omv_gpio_t miso_pin;
|
||||||
|
omv_gpio_t mosi_pin;
|
||||||
|
omv_gpio_t ssel_pin;
|
||||||
|
} spi_pins_t;
|
||||||
|
|
||||||
|
spi_pins_t spi_pins = { NULL, NULL, NULL, NULL };
|
||||||
|
|
||||||
|
switch (bus_id) {
|
||||||
|
#if defined(LPSPI1_ID)
|
||||||
|
case LPSPI1_ID: {
|
||||||
|
spi_pins = (spi_pins_t) { LPSPI1_SCLK_PIN, LPSPI1_MISO_PIN, LPSPI1_MOSI_PIN, LPSPI1_SSEL_PIN };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(LPSPI4_ID)
|
||||||
|
case LPSPI4_ID: {
|
||||||
|
spi_pins = (spi_pins_t) { LPSPI4_SCLK_PIN, LPSPI4_MISO_PIN, LPSPI4_MOSI_PIN, LPSPI4_SSEL_PIN };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
omv_gpio_config(spi_pins.sclk_pin, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1);
|
||||||
|
omv_gpio_config(spi_pins.miso_pin, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1);
|
||||||
|
omv_gpio_config(spi_pins.mosi_pin, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_MED, -1);
|
||||||
|
if (nss_enable) {
|
||||||
|
omv_gpio_config(spi_pins.ssel_pin, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_MED, -1);
|
||||||
|
} else {
|
||||||
|
omv_gpio_config(spi_pins.ssel_pin, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_MED, -1);
|
||||||
|
if (nss_pol == OMV_SPI_NSS_LOW) {
|
||||||
|
omv_gpio_write(spi_pins.ssel_pin, 1);
|
||||||
|
} else {
|
||||||
|
omv_gpio_write(spi_pins.ssel_pin, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSI_IRQHandler(void)
|
||||||
|
{
|
||||||
|
uint32_t csisr = CSI_REG_SR(CSI);
|
||||||
|
extern void sensor_sof_callback();
|
||||||
|
extern void sensor_line_callback(uint32_t);
|
||||||
|
|
||||||
|
// Clear interrupt flags.
|
||||||
|
CSI_REG_SR(CSI) = csisr;
|
||||||
|
|
||||||
|
if (csisr & CSI_SR_SOF_INT_MASK) {
|
||||||
|
// Clear the FIFO and re/enable DMA.
|
||||||
|
CSI_REG_CR3(CSI) |= (CSI_CR3_DMA_REFLASH_RFF_MASK | CSI_CR3_DMA_REQ_EN_RFF_MASK);
|
||||||
|
sensor_sof_callback();
|
||||||
|
} else if (csisr & CSI_SR_DMA_TSF_DONE_FB1_MASK) {
|
||||||
|
sensor_line_callback(CSI_REG_DMASA_FB1(CSI));
|
||||||
|
} else if (csisr & CSI_SR_DMA_TSF_DONE_FB2_MASK) {
|
||||||
|
sensor_line_callback(CSI_REG_DMASA_FB2(CSI));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate
|
||||||
|
// overlapping exception return operation might vector to incorrect interrupt
|
||||||
|
#if defined __CORTEX_M && (__CORTEX_M >= 4U)
|
||||||
|
__DSB();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
19
src/omv/ports/mimxrt/mimxrt_hal.h
Normal file
19
src/omv/ports/mimxrt/mimxrt_hal.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
* Copyright (c) 2023 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
*
|
||||||
|
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
*
|
||||||
|
* MIMXRT HAL.
|
||||||
|
*/
|
||||||
|
#ifndef __MIMXRT_HAL_H__
|
||||||
|
#define __MIMXRT_HAL_H__
|
||||||
|
|
||||||
|
void mimxrt_hal_init();
|
||||||
|
void mimxrt_hal_bootloader();
|
||||||
|
int mimxrt_hal_csi_init(CSI_Type *inst);
|
||||||
|
int mimxrt_hal_i2c_init(uint32_t bus_id);
|
||||||
|
int mimxrt_hal_spi_init(uint32_t bus_id, bool nss_enable, uint32_t nss_pol);
|
||||||
|
#endif //__MIMXRT_HAL_H__
|
||||||
193
src/omv/ports/mimxrt/omv_gpio.c
Normal file
193
src/omv/ports/mimxrt/omv_gpio.c
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
* Copyright (c) 2023 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
*
|
||||||
|
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
*
|
||||||
|
* GPIO port for imxrt.
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "py/mphal.h"
|
||||||
|
|
||||||
|
#include "fsl_gpio.h"
|
||||||
|
#include "fsl_iomuxc.h"
|
||||||
|
|
||||||
|
#include "mimxrt_hal.h"
|
||||||
|
#include "omv_boardconfig.h"
|
||||||
|
#include "omv_gpio.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#define IOMUXC_SET_REG(base, reg, val) *((volatile uint32_t *) ((((uint32_t) base) << 16) | reg)) = (val)
|
||||||
|
|
||||||
|
extern omv_gpio_irq_descr_t *const gpio_irq_descr_table[MIMXRT_PAD_COUNT];
|
||||||
|
|
||||||
|
static uint32_t omv_gpio_irq_get_gpio(omv_gpio_t pin)
|
||||||
|
{
|
||||||
|
const imxrt_pad_t *pad = pin->pad;
|
||||||
|
GPIO_Type *gpio_all[] = GPIO_BASE_PTRS;
|
||||||
|
|
||||||
|
for (size_t i = 1; i < OMV_ARRAY_SIZE(gpio_all); i++) {
|
||||||
|
if (pad->port == gpio_all[i]) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t omv_gpio_irq_get_irqn(omv_gpio_t pin)
|
||||||
|
{
|
||||||
|
const imxrt_pad_t *pad = pin->pad;
|
||||||
|
uint32_t gpio = omv_gpio_irq_get_gpio(pin);
|
||||||
|
uint8_t low_irqs[] = GPIO_COMBINED_LOW_IRQS;
|
||||||
|
uint8_t high_irqs[] = GPIO_COMBINED_HIGH_IRQS;
|
||||||
|
return (pad->pin < 16) ? low_irqs[gpio] : high_irqs[gpio];
|
||||||
|
}
|
||||||
|
|
||||||
|
static omv_gpio_irq_descr_t *omv_gpio_irq_get_descr(omv_gpio_t pin)
|
||||||
|
{
|
||||||
|
const imxrt_pad_t *pad = pin->pad;
|
||||||
|
uint32_t gpio = omv_gpio_irq_get_gpio(pin);
|
||||||
|
if (gpio && gpio_irq_descr_table[gpio]) {
|
||||||
|
return &gpio_irq_descr_table[gpio][pad->pin];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const imxrt_pad_af_t *omv_gpio_find_af(omv_gpio_t pin, uint32_t af)
|
||||||
|
{
|
||||||
|
static const imxrt_pad_af_t af_gpio = {5, 0, 0};
|
||||||
|
if (af == 5) {
|
||||||
|
return &af_gpio;
|
||||||
|
}
|
||||||
|
|
||||||
|
const imxrt_pad_t *pad = pin->pad;
|
||||||
|
for (size_t i = 0; i < pad->af_count; i++) {
|
||||||
|
if (af == pad->af_list[i].idx) {
|
||||||
|
return &pad->af_list[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void omv_gpio_config(omv_gpio_t pin, uint32_t mode, uint32_t pull, uint32_t speed, uint32_t af)
|
||||||
|
{
|
||||||
|
const imxrt_pad_t *pad = pin->pad;
|
||||||
|
af = ((af == -1) ? pin->af : af);
|
||||||
|
const imxrt_pad_af_t *pad_af = omv_gpio_find_af(pin, af);
|
||||||
|
|
||||||
|
if (pad_af == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t pad_config = (mode | pull | speed) & 0x1FFFF;
|
||||||
|
uint16_t mux_config = IOMUXC_MUX_CTL(MUX_MODE, af) | IOMUXC_MUX_CTL(SION, pin->sion);
|
||||||
|
|
||||||
|
IOMUXC_SET_REG(pad->iomux_base, pad->mux_register, mux_config);
|
||||||
|
if (pad_af->input_register) {
|
||||||
|
// Input register always uses IOMUXC_BASE
|
||||||
|
uint32_t iomux_base = ((uint32_t) IOMUXC_BASE) >> 16;
|
||||||
|
IOMUXC_SET_REG(iomux_base, pad_af->input_register, pad_af->input_daisy);
|
||||||
|
}
|
||||||
|
IOMUXC_SET_REG(pad->iomux_base, pad->cfg_register, pad_config);
|
||||||
|
|
||||||
|
// If pad was configured for GPIO module, set the pin config.
|
||||||
|
gpio_pin_config_t pin_config = { 0 };
|
||||||
|
switch (mode) {
|
||||||
|
case OMV_GPIO_MODE_ALT:
|
||||||
|
case OMV_GPIO_MODE_ALT_OD: {
|
||||||
|
// No GPIO config.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case OMV_GPIO_MODE_INPUT: {
|
||||||
|
pin_config.direction = kGPIO_DigitalInput;
|
||||||
|
GPIO_PinInit(pad->port, pad->pin, &pin_config);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OMV_GPIO_MODE_OUTPUT:
|
||||||
|
case OMV_GPIO_MODE_OUTPUT_OD: {
|
||||||
|
pin_config.direction = kGPIO_DigitalOutput;
|
||||||
|
pin_config.outputLogic = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OMV_GPIO_MODE_IT_FALL: {
|
||||||
|
pin_config.interruptMode = kGPIO_IntFallingEdge;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OMV_GPIO_MODE_IT_RISE: {
|
||||||
|
pin_config.interruptMode = kGPIO_IntRisingEdge;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OMV_GPIO_MODE_IT_BOTH: {
|
||||||
|
pin_config.interruptMode = kGPIO_IntRisingOrFallingEdge;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GPIO_PinInit(pad->port, pad->pin, &pin_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
void omv_gpio_deinit(omv_gpio_t pin)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool omv_gpio_read(omv_gpio_t pin)
|
||||||
|
{
|
||||||
|
const imxrt_pad_t *pad = pin->pad;
|
||||||
|
return GPIO_PinRead(pad->port, pad->pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void omv_gpio_write(omv_gpio_t pin, bool value)
|
||||||
|
{
|
||||||
|
const imxrt_pad_t *pad = pin->pad;
|
||||||
|
GPIO_PinWrite(pad->port, pad->pin, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void omv_gpio_irq_register(omv_gpio_t pin, omv_gpio_callback_t callback, void *data)
|
||||||
|
{
|
||||||
|
omv_gpio_irq_descr_t *irq_descr = omv_gpio_irq_get_descr(pin);
|
||||||
|
if (irq_descr) {
|
||||||
|
irq_descr->enabled = true;
|
||||||
|
irq_descr->data = data;
|
||||||
|
irq_descr->callback = callback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void omv_gpio_irq_enable(omv_gpio_t pin, bool enable)
|
||||||
|
{
|
||||||
|
const imxrt_pad_t *pad = pin->pad;
|
||||||
|
uint32_t irqn = omv_gpio_irq_get_irqn(pin);
|
||||||
|
omv_gpio_irq_descr_t *irq_descr = omv_gpio_irq_get_descr(pin);
|
||||||
|
|
||||||
|
if (irq_descr == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enable) {
|
||||||
|
GPIO_PortDisableInterrupts(pad->port, 1U << pad->pin);
|
||||||
|
GPIO_PortClearInterruptFlags(pad->port, ~(0U));
|
||||||
|
DisableIRQ(irqn);
|
||||||
|
} else {
|
||||||
|
GPIO_PortClearInterruptFlags(pad->port, ~(0U));
|
||||||
|
GPIO_PortEnableInterrupts(pad->port, 1U << pad->pin);
|
||||||
|
NVIC_SetPriority(irqn, IRQ_PRI_EXTINT);
|
||||||
|
EnableIRQ(irqn);
|
||||||
|
}
|
||||||
|
irq_descr->enabled = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void omv_gpio_irq_handler(GPIO_Type *gpio, uint32_t gpio_nr, uint32_t pin_nr)
|
||||||
|
{
|
||||||
|
omv_gpio_irq_descr_t *irq_descr = NULL;
|
||||||
|
if (gpio_irq_descr_table[gpio_nr]) {
|
||||||
|
irq_descr = &gpio_irq_descr_table[gpio_nr][pin_nr];
|
||||||
|
if (irq_descr->enabled && irq_descr->callback) {
|
||||||
|
irq_descr->callback(irq_descr->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
309
src/omv/ports/mimxrt/omv_i2c.c
Normal file
309
src/omv/ports/mimxrt/omv_i2c.c
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
* Copyright (c) 2023 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
*
|
||||||
|
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
*
|
||||||
|
* I2C port for mimxrt.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "py/mphal.h"
|
||||||
|
|
||||||
|
#include "fsl_gpio.h"
|
||||||
|
#include "fsl_lpi2c.h"
|
||||||
|
#include "fsl_iomuxc.h"
|
||||||
|
#include CLOCK_CONFIG_H
|
||||||
|
|
||||||
|
#include "omv_portconfig.h"
|
||||||
|
#include "omv_boardconfig.h"
|
||||||
|
#include "mimxrt_hal.h"
|
||||||
|
#include "omv_gpio.h"
|
||||||
|
#include "omv_i2c.h"
|
||||||
|
|
||||||
|
#define I2C_TIMEOUT (3*1000)
|
||||||
|
#define I2C_SCAN_TIMEOUT (1*1000)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
volatile uint32_t flags;
|
||||||
|
volatile status_t error;
|
||||||
|
} lpi2c_transfer_status_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LPI2C_TRANSFER_COMPLETE = (1 << 0),
|
||||||
|
LPI2C_TRANSFER_ERROR = (1 << 1),
|
||||||
|
} lpi2c_xfer_flags_t;
|
||||||
|
|
||||||
|
int omv_i2c_init(omv_i2c_t *i2c, uint32_t bus_id, uint32_t speed)
|
||||||
|
{
|
||||||
|
i2c->id = bus_id;
|
||||||
|
i2c->initialized = false;
|
||||||
|
|
||||||
|
switch (speed) {
|
||||||
|
case OMV_I2C_SPEED_STANDARD:
|
||||||
|
i2c->speed = 100 * 1000; ///< 100 kbps
|
||||||
|
break;
|
||||||
|
case OMV_I2C_SPEED_FULL:
|
||||||
|
i2c->speed = 400 * 1000; ///< 400 kbps
|
||||||
|
break;
|
||||||
|
case OMV_I2C_SPEED_FAST:
|
||||||
|
i2c->speed = 1000 * 1000; ///< 1000 kbps
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (bus_id) {
|
||||||
|
case LPI2C1_ID: {
|
||||||
|
i2c->inst = LPI2C1;
|
||||||
|
i2c->scl_pin = LPI2C1_SCL_PIN;
|
||||||
|
i2c->sda_pin = LPI2C1_SDA_PIN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#if defined(LPI2C2_ID)
|
||||||
|
case LPI2C2_ID: {
|
||||||
|
i2c->inst = LPI2C2;
|
||||||
|
i2c->scl_pin = LPI2C2_SCL_PIN;
|
||||||
|
i2c->sda_pin = LPI2C2_SDA_PIN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(LPI2C3_ID)
|
||||||
|
case LPI2C3_ID: {
|
||||||
|
i2c->inst = LPI2C3;
|
||||||
|
i2c->scl_pin = LPI2C3_SCL_PIN;
|
||||||
|
i2c->sda_pin = LPI2C3_SDA_PIN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(LPI2C4_ID)
|
||||||
|
case LPI2C4_ID: {
|
||||||
|
i2c->inst = LPI2C4;
|
||||||
|
i2c->scl_pin = LPI2C4_SCL_PIN;
|
||||||
|
i2c->sda_pin = LPI2C4_SDA_PIN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
lpi2c_master_config_t lpi2c_config = {0};
|
||||||
|
LPI2C_MasterGetDefaultConfig(&lpi2c_config);
|
||||||
|
|
||||||
|
lpi2c_config.ignoreAck = true;
|
||||||
|
lpi2c_config.baudRate_Hz = i2c->speed;
|
||||||
|
|
||||||
|
mimxrt_hal_i2c_init(bus_id);
|
||||||
|
LPI2C_MasterInit(i2c->inst, &lpi2c_config, BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT);
|
||||||
|
i2c->initialized = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_i2c_deinit(omv_i2c_t *i2c)
|
||||||
|
{
|
||||||
|
if (i2c->initialized) {
|
||||||
|
// TODO
|
||||||
|
i2c->initialized = false;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_i2c_scan(omv_i2c_t *i2c, uint8_t *list, uint8_t size)
|
||||||
|
{
|
||||||
|
uint32_t idx = 0;
|
||||||
|
lpi2c_master_transfer_t xfer = {0};
|
||||||
|
xfer.direction = kLPI2C_Write;
|
||||||
|
xfer.flags = kLPI2C_TransferDefaultFlag;
|
||||||
|
|
||||||
|
for (uint8_t addr=0x20; addr<0x78; addr++) {
|
||||||
|
xfer.slaveAddress = addr;
|
||||||
|
if (LPI2C_MasterTransferBlocking(i2c->inst, &xfer) == kStatus_Success) {
|
||||||
|
if (list == NULL || size == 0) {
|
||||||
|
return (addr << 1);
|
||||||
|
} else if (idx < size) {
|
||||||
|
list[idx++] = (addr << 1);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_i2c_enable(omv_i2c_t *i2c, bool enable)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_i2c_gencall(omv_i2c_t *i2c, uint8_t cmd)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
ret |= omv_i2c_write_bytes(i2c, 0, &cmd, 1, OMV_I2C_XFER_NO_FLAGS);
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_i2c_readb(omv_i2c_t *i2c, uint8_t slv_addr, uint8_t reg_addr, uint8_t *reg_data)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
ret |= omv_i2c_write_bytes(i2c, slv_addr, ®_addr, 1, OMV_I2C_XFER_NO_FLAGS);
|
||||||
|
ret |= omv_i2c_read_bytes(i2c, slv_addr, reg_data, 1, OMV_I2C_XFER_NO_FLAGS);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_i2c_writeb(omv_i2c_t *i2c, uint8_t slv_addr, uint8_t reg_addr, uint8_t reg_data)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
uint8_t buf[] = {reg_addr, reg_data};
|
||||||
|
ret |= omv_i2c_write_bytes(i2c, slv_addr, buf, 2, OMV_I2C_XFER_NO_FLAGS);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_i2c_readb2(omv_i2c_t *i2c, uint8_t slv_addr, uint16_t reg_addr, uint8_t *reg_data)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
uint8_t buf[] = {(reg_addr >> 8), reg_addr};
|
||||||
|
ret |= omv_i2c_write_bytes(i2c, slv_addr, buf, 2, OMV_I2C_XFER_NO_STOP);
|
||||||
|
ret |= omv_i2c_read_bytes(i2c, slv_addr, reg_data, 1, OMV_I2C_XFER_NO_FLAGS);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_i2c_writeb2(omv_i2c_t *i2c, uint8_t slv_addr, uint16_t reg_addr, uint8_t reg_data)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
uint8_t buf[] = {(reg_addr >> 8), reg_addr, reg_data};
|
||||||
|
ret |= omv_i2c_write_bytes(i2c, slv_addr, buf, 3, OMV_I2C_XFER_NO_FLAGS);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_i2c_readw(omv_i2c_t *i2c, uint8_t slv_addr, uint8_t reg_addr, uint16_t *reg_data)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
ret |= omv_i2c_write_bytes(i2c, slv_addr, ®_addr, 1, OMV_I2C_XFER_NO_STOP);
|
||||||
|
ret |= omv_i2c_read_bytes(i2c, slv_addr, (uint8_t *) reg_data, 2, OMV_I2C_XFER_NO_FLAGS);
|
||||||
|
*reg_data = (*reg_data << 8) | (*reg_data >> 8);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_i2c_writew(omv_i2c_t *i2c, uint8_t slv_addr, uint8_t reg_addr, uint16_t reg_data)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
uint8_t buf[] = {reg_addr, (reg_data >> 8), reg_data};
|
||||||
|
ret |= omv_i2c_write_bytes(i2c, slv_addr, buf, 3, OMV_I2C_XFER_NO_FLAGS);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_i2c_readw2(omv_i2c_t *i2c, uint8_t slv_addr, uint16_t reg_addr, uint16_t *reg_data)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
uint8_t buf[] = {(reg_addr >> 8), reg_addr};
|
||||||
|
ret |= omv_i2c_write_bytes(i2c, slv_addr, buf, 2, OMV_I2C_XFER_NO_STOP);
|
||||||
|
ret |= omv_i2c_read_bytes(i2c, slv_addr, (uint8_t *) reg_data, 2, OMV_I2C_XFER_NO_FLAGS);
|
||||||
|
*reg_data = (*reg_data << 8) | (*reg_data >> 8);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_i2c_writew2(omv_i2c_t *i2c, uint8_t slv_addr, uint16_t reg_addr, uint16_t reg_data)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
uint8_t buf[] = {(reg_addr >> 8), reg_addr, (reg_data >> 8), reg_data};
|
||||||
|
ret |= omv_i2c_write_bytes(i2c, slv_addr, buf, 4, OMV_I2C_XFER_NO_FLAGS);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lpi2c_transfer_callback(LPI2C_Type *base,
|
||||||
|
lpi2c_master_handle_t *handle, status_t status, void *data)
|
||||||
|
{
|
||||||
|
lpi2c_transfer_status_t *xfer_status = (lpi2c_transfer_status_t *) data;
|
||||||
|
xfer_status->flags |= LPI2C_TRANSFER_COMPLETE;
|
||||||
|
if (status != kStatus_Success) {
|
||||||
|
xfer_status->flags |= LPI2C_TRANSFER_ERROR;
|
||||||
|
xfer_status->error = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int omv_i2c_transfer_timeout(omv_i2c_t *i2c, lpi2c_master_transfer_t *transfer)
|
||||||
|
{
|
||||||
|
lpi2c_master_handle_t lpi2c_handle;
|
||||||
|
lpi2c_transfer_status_t xfer_status = {0};
|
||||||
|
|
||||||
|
// Create the handle, needed for non-blocking mode.
|
||||||
|
LPI2C_MasterTransferCreateHandle(i2c->inst, &lpi2c_handle, lpi2c_transfer_callback, &xfer_status);
|
||||||
|
|
||||||
|
// Start non-blocking transfer.
|
||||||
|
if (LPI2C_MasterTransferNonBlocking(i2c->inst, &lpi2c_handle, transfer) != kStatus_Success) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the transfer to finish.
|
||||||
|
mp_uint_t tick_start = mp_hal_ticks_ms();
|
||||||
|
while (!(xfer_status.flags & LPI2C_TRANSFER_COMPLETE)) {
|
||||||
|
if ((mp_hal_ticks_ms() - tick_start) >= I2C_TIMEOUT) {
|
||||||
|
xfer_status.flags |= LPI2C_TRANSFER_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
MICROPY_EVENT_POLL_HOOK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terminate non-blocking transfer.
|
||||||
|
if (xfer_status.flags & LPI2C_TRANSFER_ERROR) {
|
||||||
|
LPI2C_MasterTransferAbort(i2c->inst, &lpi2c_handle);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_i2c_read_bytes(omv_i2c_t *i2c, uint8_t slv_addr, uint8_t *buf, int len, uint32_t flags)
|
||||||
|
{
|
||||||
|
lpi2c_master_transfer_t xfer = {
|
||||||
|
.data = buf,
|
||||||
|
.dataSize = len,
|
||||||
|
.flags = kLPI2C_TransferDefaultFlag,
|
||||||
|
.direction = kLPI2C_Read,
|
||||||
|
.subaddress = 0,
|
||||||
|
.subaddressSize = 0,
|
||||||
|
.slaveAddress = (slv_addr >> 1)
|
||||||
|
};
|
||||||
|
if (flags & (OMV_I2C_XFER_NO_STOP | OMV_I2C_XFER_SUSPEND)) {
|
||||||
|
xfer.flags |= kLPI2C_TransferNoStopFlag;
|
||||||
|
}
|
||||||
|
return omv_i2c_transfer_timeout(i2c, &xfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_i2c_write_bytes(omv_i2c_t *i2c, uint8_t slv_addr, uint8_t *buf, int len, uint32_t flags)
|
||||||
|
{
|
||||||
|
lpi2c_master_transfer_t xfer = {
|
||||||
|
.data = buf,
|
||||||
|
.dataSize = len,
|
||||||
|
.flags = kLPI2C_TransferDefaultFlag,
|
||||||
|
.direction = kLPI2C_Write,
|
||||||
|
.subaddress = 0,
|
||||||
|
.subaddressSize = 0,
|
||||||
|
.slaveAddress = (slv_addr >> 1)
|
||||||
|
};
|
||||||
|
if (flags & (OMV_I2C_XFER_NO_STOP | OMV_I2C_XFER_SUSPEND)) {
|
||||||
|
xfer.flags |= kLPI2C_TransferNoStopFlag;
|
||||||
|
}
|
||||||
|
return omv_i2c_transfer_timeout(i2c, &xfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_i2c_pulse_scl(omv_i2c_t *i2c)
|
||||||
|
{
|
||||||
|
if (i2c->initialized && i2c->scl_pin) {
|
||||||
|
omv_i2c_deinit(i2c);
|
||||||
|
omv_gpio_config(i2c->scl_pin, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_LOW, -1);
|
||||||
|
// Pulse SCL to recover stuck device.
|
||||||
|
for (int i=0; i<10000; i++) {
|
||||||
|
omv_gpio_write(i2c->scl_pin, 1);
|
||||||
|
mp_hal_delay_us(10);
|
||||||
|
omv_gpio_write(i2c->scl_pin, 0);
|
||||||
|
mp_hal_delay_us(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
121
src/omv/ports/mimxrt/omv_portconfig.h
Normal file
121
src/omv/ports/mimxrt/omv_portconfig.h
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
* Copyright (c) 2023 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
*
|
||||||
|
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
*
|
||||||
|
* OpenMV MIMXRT port abstraction layer.
|
||||||
|
*/
|
||||||
|
#ifndef __OMV_PORTCONFIG_H__
|
||||||
|
#define __OMV_PORTCONFIG_H__
|
||||||
|
|
||||||
|
#include "fsl_gpio.h"
|
||||||
|
#include "fsl_lpi2c.h"
|
||||||
|
#include "fsl_lpspi.h"
|
||||||
|
#include "fsl_iomuxc.h"
|
||||||
|
#include "fsl_edma.h"
|
||||||
|
#include "fsl_lpspi_edma.h"
|
||||||
|
|
||||||
|
#define IOMUXC_PAD_CTL(opt, val) (IOMUXC_SW_PAD_CTL_PAD_##opt(val))
|
||||||
|
#define IOMUXC_MUX_CTL(opt, val) (IOMUXC_SW_MUX_CTL_PAD_##opt(val))
|
||||||
|
|
||||||
|
// omv_gpio_t definitions
|
||||||
|
|
||||||
|
// GPIO speeds.
|
||||||
|
#define OMV_GPIO_SPEED_LOW ((1 << 17) | IOMUXC_PAD_CTL(SPEED, 0U) | IOMUXC_PAD_CTL(SRE, 0U)) // 50MHz
|
||||||
|
#define OMV_GPIO_SPEED_MED ((2 << 17) | IOMUXC_PAD_CTL(SPEED, 1U) | IOMUXC_PAD_CTL(SRE, 0U)) // 100MHz
|
||||||
|
#define OMV_GPIO_SPEED_HIGH ((3 << 17) | IOMUXC_PAD_CTL(SPEED, 2U) | IOMUXC_PAD_CTL(SRE, 1U)) // 150MHz
|
||||||
|
#define OMV_GPIO_SPEED_MAX ((4 << 17) | IOMUXC_PAD_CTL(SPEED, 3U) | IOMUXC_PAD_CTL(SRE, 1U)) // 200MHz
|
||||||
|
|
||||||
|
// GPIO pull.
|
||||||
|
#define OMV_GPIO_PULL_NONE ((1 << 17) | IOMUXC_PAD_CTL(PKE, 0U) | IOMUXC_PAD_CTL(PUE, 0) | IOMUXC_PAD_CTL(PUS, 0))
|
||||||
|
#define OMV_GPIO_PULL_UP ((2 << 17) | IOMUXC_PAD_CTL(PKE, 1U) | IOMUXC_PAD_CTL(PUE, 1) | IOMUXC_PAD_CTL(PUS, 2))
|
||||||
|
#define OMV_GPIO_PULL_DOWN ((3 << 17) | IOMUXC_PAD_CTL(PKE, 1U) | IOMUXC_PAD_CTL(PUE, 1) | IOMUXC_PAD_CTL(PUS, 0))
|
||||||
|
|
||||||
|
// GPIO modes.
|
||||||
|
#define OMV_GPIO_MODE_INPUT ((1 << 17) | IOMUXC_PAD_CTL(DSE, 0U) | IOMUXC_PAD_CTL(HYS, 1U) | IOMUXC_PAD_CTL(ODE, 0U))
|
||||||
|
#define OMV_GPIO_MODE_OUTPUT ((2 << 17) | IOMUXC_PAD_CTL(DSE, 6U) | IOMUXC_PAD_CTL(HYS, 0U) | IOMUXC_PAD_CTL(ODE, 0U))
|
||||||
|
#define OMV_GPIO_MODE_OUTPUT_OD ((3 << 17) | IOMUXC_PAD_CTL(DSE, 6U) | IOMUXC_PAD_CTL(HYS, 0U) | IOMUXC_PAD_CTL(ODE, 1U))
|
||||||
|
#define OMV_GPIO_MODE_ALT ((4 << 17) | IOMUXC_PAD_CTL(DSE, 6U) | IOMUXC_PAD_CTL(HYS, 0U) | IOMUXC_PAD_CTL(ODE, 0U))
|
||||||
|
#define OMV_GPIO_MODE_ALT_OD ((5 << 17) | IOMUXC_PAD_CTL(DSE, 6U) | IOMUXC_PAD_CTL(HYS, 0U) | IOMUXC_PAD_CTL(ODE, 1U))
|
||||||
|
|
||||||
|
// GPIO IT modes.
|
||||||
|
#define OMV_GPIO_MODE_IT_FALL ((6 << 17) | IOMUXC_PAD_CTL(DSE, 0U) | IOMUXC_PAD_CTL(HYS, 1U))
|
||||||
|
#define OMV_GPIO_MODE_IT_RISE ((7 << 17) | IOMUXC_PAD_CTL(DSE, 0U) | IOMUXC_PAD_CTL(HYS, 1U))
|
||||||
|
#define OMV_GPIO_MODE_IT_BOTH ((8 << 17) | IOMUXC_PAD_CTL(DSE, 0U) | IOMUXC_PAD_CTL(HYS, 1U))
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t idx;
|
||||||
|
uint16_t input_register;
|
||||||
|
uint8_t input_daisy;
|
||||||
|
} imxrt_pad_af_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GPIO_Type *port;
|
||||||
|
uint8_t pin;
|
||||||
|
uint16_t iomux_base;
|
||||||
|
uint16_t mux_register;
|
||||||
|
uint16_t cfg_register;
|
||||||
|
uint8_t af_count;
|
||||||
|
const imxrt_pad_af_t *af_list;
|
||||||
|
} imxrt_pad_t;
|
||||||
|
#include "mimxrt_pads.h"
|
||||||
|
|
||||||
|
typedef struct _omv_gpio {
|
||||||
|
const imxrt_pad_t *pad; // IMXRT pad.
|
||||||
|
uint8_t af; // Default AF.
|
||||||
|
uint8_t sion; // Software input on.
|
||||||
|
} imxrt_gpio_t;
|
||||||
|
|
||||||
|
typedef const imxrt_gpio_t *omv_gpio_t;
|
||||||
|
|
||||||
|
// For board config files.
|
||||||
|
#if OMV_GPIO_DEFINE_PINS
|
||||||
|
#define OMV_GPIO_DEFINE(pin, pad, af, sion) \
|
||||||
|
const imxrt_gpio_t omv_pin_##pin = {&imxrt_pad_##pad, pad##_AF_##af, sion};
|
||||||
|
#else
|
||||||
|
#define OMV_GPIO_DEFINE(pin, pad, af, sion) \
|
||||||
|
extern const imxrt_gpio_t omv_pin_##pin;
|
||||||
|
#endif
|
||||||
|
#include "omv_pins.h"
|
||||||
|
|
||||||
|
// omv_i2c_t definitions
|
||||||
|
typedef LPI2C_Type *omv_i2c_dev_t;
|
||||||
|
|
||||||
|
// omv_spi_t definitions
|
||||||
|
#define OMV_SPI_MODE_SLAVE (0)
|
||||||
|
#define OMV_SPI_MODE_MASTER (1)
|
||||||
|
|
||||||
|
#define OMV_SPI_LSB_FIRST (kLPSPI_LsbFirst)
|
||||||
|
#define OMV_SPI_MSB_FIRST (kLPSPI_MsbFirst)
|
||||||
|
|
||||||
|
#define OMV_SPI_BUS_TX (1 << 0)
|
||||||
|
#define OMV_SPI_BUS_RX (1 << 1)
|
||||||
|
#define OMV_SPI_BUS_TX_RX (OMV_SPI_BUS_TX | OMV_SPI_BUS_RX)
|
||||||
|
|
||||||
|
#define OMV_SPI_CPOL_LOW (kLPSPI_ClockPolarityActiveLow)
|
||||||
|
#define OMV_SPI_CPOL_HIGH (kLPSPI_ClockPolarityActiveHigh)
|
||||||
|
|
||||||
|
#define OMV_SPI_CPHA_1EDGE (kLPSPI_ClockPhaseFirstEdge)
|
||||||
|
#define OMV_SPI_CPHA_2EDGE (kLPSPI_ClockPhaseSecondEdge)
|
||||||
|
|
||||||
|
#define OMV_SPI_NSS_LOW (kLPSPI_PcsActiveLow)
|
||||||
|
#define OMV_SPI_NSS_HIGH (kLPSPI_PcsActiveHigh)
|
||||||
|
|
||||||
|
#define OMV_SPI_PORT_BITS \
|
||||||
|
struct { \
|
||||||
|
LPSPI_Type *inst; \
|
||||||
|
edma_handle_t dma_descr_tx; \
|
||||||
|
edma_handle_t dma_descr_rx; \
|
||||||
|
union { \
|
||||||
|
lpspi_slave_handle_t descr_slave; \
|
||||||
|
lpspi_master_handle_t descr_master; \
|
||||||
|
lpspi_slave_edma_handle_t descr_slave_edma; \
|
||||||
|
lpspi_master_edma_handle_t descr_master_edma; \
|
||||||
|
}; \
|
||||||
|
lpspi_transfer_t xfer_descr; \
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __OMV_PORTCONFIG_H__
|
||||||
637
src/omv/ports/mimxrt/omv_portconfig.mk
Normal file
637
src/omv/ports/mimxrt/omv_portconfig.mk
Normal file
@ -0,0 +1,637 @@
|
|||||||
|
# Set startup and system files based on MCU.
|
||||||
|
SYSTEM ?= mimxrt/system_$(MCU_SERIES)
|
||||||
|
STARTUP ?= mimxrt/startup_$(MCU_SERIES)
|
||||||
|
LDSCRIPT ?= mimxrt
|
||||||
|
|
||||||
|
# Compiler Flags
|
||||||
|
# TODO: -Wdouble-promotion
|
||||||
|
CFLAGS += -std=gnu99 -Wall -Werror -Warray-bounds -nostartfiles -fdata-sections -ffunction-sections \
|
||||||
|
-fno-inline-small-functions -mfloat-abi=$(FABI) -mthumb -mcpu=$(CPU) -mtune=$(CPU) -mfpu=$(FPU)
|
||||||
|
# TODO: FIX HSE
|
||||||
|
CFLAGS += -DCPU_$(MCU_VARIANT)\
|
||||||
|
-D$(TARGET)\
|
||||||
|
-D$(ARM_MATH) -DARM_NN_TRUNCATE\
|
||||||
|
-D__FPU_PRESENT=1 -D__VFP_FP__\
|
||||||
|
-DHSE_VALUE=$(OMV_HSE_VALUE) \
|
||||||
|
-DMICROPY_PY_MACHINE_SDCARD=1 \
|
||||||
|
-DXIP_EXTERNAL_FLASH=1 \
|
||||||
|
-DXIP_BOOT_HEADER_ENABLE=1 \
|
||||||
|
-DFSL_SDK_ENABLE_DRIVER_CACHE_CONTROL=1 \
|
||||||
|
-DCFG_TUSB_MCU=OPT_MCU_MIMXRT \
|
||||||
|
-DCPU_HEADER_H='<$(MCU_SERIES).h>' \
|
||||||
|
-DCLOCK_CONFIG_H='<boards/$(MCU_SERIES)_clock_config.h>' \
|
||||||
|
-DCSI_DRIVER_FRAG_MODE=1\
|
||||||
|
-D__START=main\
|
||||||
|
-D__STARTUP_CLEAR_BSS\
|
||||||
|
-D__STARTUP_INITIALIZE_RAMFUNCTION\
|
||||||
|
$(OMV_BOARD_EXTRA_CFLAGS)\
|
||||||
|
|
||||||
|
HAL_CFLAGS += -I$(TOP_DIR)/$(CMSIS_DIR)/include/
|
||||||
|
HAL_CFLAGS += -I$(TOP_DIR)/$(CMSIS_DIR)/include/mimxrt
|
||||||
|
HAL_CFLAGS += -I$(TOP_DIR)/$(HAL_DIR)/
|
||||||
|
HAL_CFLAGS += -I$(TOP_DIR)/$(HAL_DIR)/drivers
|
||||||
|
|
||||||
|
MPY_CFLAGS += -I$(MP_BOARD_CONFIG_DIR)
|
||||||
|
MPY_CFLAGS += -I$(BUILD)/$(MICROPY_DIR)/
|
||||||
|
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/
|
||||||
|
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/py/
|
||||||
|
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/lib/oofatfs
|
||||||
|
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/lib/tinyusb/src
|
||||||
|
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/lib/lwip/src/include/
|
||||||
|
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/ports/mimxrt/
|
||||||
|
MPY_CFLAGS += -I$(TOP_DIR)/$(MICROPY_DIR)/ports/mimxrt/lwip_inc/
|
||||||
|
|
||||||
|
ifeq ($(MICROPY_PY_LWIP), 0)
|
||||||
|
MICROPY_ARGS += MICROPY_PY_LWIP=0 MICROPY_PY_USSL=0
|
||||||
|
else
|
||||||
|
MPY_CFLAGS += -DMICROPY_PY_USSL=1 -DMICROPY_SSL_MBEDTLS=1
|
||||||
|
MICROPY_ARGS += MICROPY_PY_USSL=1 MICROPY_SSL_MBEDTLS=1
|
||||||
|
endif
|
||||||
|
MICROPY_ARGS += MCU_DIR=$(TOP_DIR)/$(HAL_DIR) CMSIS_DIR=$(TOP_DIR)/$(CMSIS_DIR)\
|
||||||
|
SUPPORTS_HARDWARE_FP_SINGLE=1 MICROPY_VFS_LFS2=0
|
||||||
|
|
||||||
|
OMV_CFLAGS += -I$(OMV_BOARD_CONFIG_DIR)
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/alloc/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/common/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/imlib/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/modules/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/sensors/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/templates/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/ports/$(PORT)/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(OMV_DIR)/ports/$(PORT)/modules/
|
||||||
|
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(LEPTON_DIR)/include/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(LSM6DS3_DIR)/include/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(LSM6DSOX_DIR)/include/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(VL53L5CX_DIR)/include/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(WINC1500_DIR)/include/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(MLX90621_DIR)/include/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(MLX90640_DIR)/include/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(MLX90641_DIR)/include/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(PIXART_DIR)/include/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(TENSORFLOW_DIR)/
|
||||||
|
OMV_CFLAGS += -I$(BUILD)/$(TENSORFLOW_DIR)/
|
||||||
|
OMV_CFLAGS += -I$(TOP_DIR)/$(LIBPDM_DIR)/
|
||||||
|
|
||||||
|
ifeq ($(OMV_ENABLE_UVC), 1)
|
||||||
|
UVC_CFLAGS := $(CFLAGS) $(HAL_CFLAGS)
|
||||||
|
UVC_CFLAGS += -I$(OMV_BOARD_CONFIG_DIR)
|
||||||
|
UVC_CFLAGS += -I$(TOP_DIR)/$(UVC_DIR)/include/
|
||||||
|
UVC_CFLAGS += $(OMV_CFLAGS) $(MPY_CFLAGS)
|
||||||
|
# Linker Flags
|
||||||
|
UVC_LDFLAGS = -mcpu=$(CPU) -mabi=aapcs-linux -mthumb -mfpu=$(FPU) -mfloat-abi=hard -nostdlib \
|
||||||
|
-Wl,--print-memory-usage -Wl,--gc-sections -Wl,-T$(BUILD)/$(UVC_DIR)/$(LD_SCRIPT).lds
|
||||||
|
endif
|
||||||
|
|
||||||
|
CFLAGS += $(HAL_CFLAGS) $(MPY_CFLAGS) $(OMV_CFLAGS)
|
||||||
|
# Linker Flags
|
||||||
|
LDFLAGS = -mcpu=$(CPU) -mabi=aapcs-linux -mthumb -mfpu=$(FPU) -mfloat-abi=hard -nostdlib \
|
||||||
|
-Wl,--print-memory-usage -Wl,--gc-sections -Wl,-T$(BUILD)/$(LDSCRIPT).lds
|
||||||
|
|
||||||
|
#------------- Libraries ----------------#
|
||||||
|
LIBS += $(TOP_DIR)/$(TENSORFLOW_DIR)/$(CPU)/libtf*.a
|
||||||
|
ifeq ($(MICROPY_PY_AUDIO), 1)
|
||||||
|
LIBS += $(TOP_DIR)/$(LIBPDM_DIR)/libPDMFilter_CM7_GCC_wc32.a
|
||||||
|
endif
|
||||||
|
|
||||||
|
#------------- Firmware Objects ----------------#
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(CMSIS_DIR)/src/dsp/CommonTables/*.o)
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(CMSIS_DIR)/src/dsp/FastMathFunctions/*.o)
|
||||||
|
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(HAL_DIR)/drivers/*.o)
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(LEPTON_DIR)/src/*.o)
|
||||||
|
ifeq ($(MICROPY_PY_IMU), 1)
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(LSM6DS3_DIR)/src/*.o)
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(LSM6DSOX_DIR)/src/*.o)
|
||||||
|
endif
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(MLX90621_DIR)/src/*.o)
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(MLX90640_DIR)/src/*.o)
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(MLX90641_DIR)/src/*.o)
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(VL53L5CX_DIR)/src/*.o)
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(PIXART_DIR)/src/*.o)
|
||||||
|
|
||||||
|
#------------- OpenMV Objects ----------------#
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(CMSIS_DIR)/src/, \
|
||||||
|
$(STARTUP).o \
|
||||||
|
$(SYSTEM).o \
|
||||||
|
)
|
||||||
|
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/alloc/, \
|
||||||
|
xalloc.o \
|
||||||
|
fb_alloc.o \
|
||||||
|
umm_malloc.o \
|
||||||
|
unaligned_memcpy.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/common/, \
|
||||||
|
array.o \
|
||||||
|
ff_wrapper.o \
|
||||||
|
ini.o \
|
||||||
|
ringbuf.o \
|
||||||
|
trace.o \
|
||||||
|
mutex.o \
|
||||||
|
vospi.o \
|
||||||
|
usbdbg.o \
|
||||||
|
tinyusb_debug.o \
|
||||||
|
sensor_utils.o \
|
||||||
|
factoryreset.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/sensors/, \
|
||||||
|
ov2640.o \
|
||||||
|
ov5640.o \
|
||||||
|
ov7670.o \
|
||||||
|
ov7690.o \
|
||||||
|
ov7725.o \
|
||||||
|
ov9650.o \
|
||||||
|
mt9v0xx.o \
|
||||||
|
mt9m114.o \
|
||||||
|
lepton.o \
|
||||||
|
hm01b0.o \
|
||||||
|
hm0360.o \
|
||||||
|
gc2145.o \
|
||||||
|
paj6100.o \
|
||||||
|
frogeye2020.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/imlib/, \
|
||||||
|
agast.o \
|
||||||
|
apriltag.o \
|
||||||
|
bayer.o \
|
||||||
|
binary.o \
|
||||||
|
blob.o \
|
||||||
|
bmp.o \
|
||||||
|
clahe.o \
|
||||||
|
collections.o \
|
||||||
|
dmtx.o \
|
||||||
|
draw.o \
|
||||||
|
edge.o \
|
||||||
|
eye.o \
|
||||||
|
fast.o \
|
||||||
|
fft.o \
|
||||||
|
filter.o \
|
||||||
|
fmath.o \
|
||||||
|
font.o \
|
||||||
|
framebuffer.o \
|
||||||
|
fsort.o \
|
||||||
|
gif.o \
|
||||||
|
haar.o \
|
||||||
|
hog.o \
|
||||||
|
hough.o \
|
||||||
|
imlib.o \
|
||||||
|
integral.o \
|
||||||
|
integral_mw.o \
|
||||||
|
jpegd.o \
|
||||||
|
jpeg.o \
|
||||||
|
lodepng.o \
|
||||||
|
png.o \
|
||||||
|
kmeans.o \
|
||||||
|
lab_tab.o \
|
||||||
|
lbp.o \
|
||||||
|
line.o \
|
||||||
|
lsd.o \
|
||||||
|
mathop.o \
|
||||||
|
mjpeg.o \
|
||||||
|
orb.o \
|
||||||
|
phasecorrelation.o \
|
||||||
|
point.o \
|
||||||
|
pool.o \
|
||||||
|
ppm.o \
|
||||||
|
qrcode.o \
|
||||||
|
qsort.o \
|
||||||
|
rainbow_tab.o \
|
||||||
|
rectangle.o \
|
||||||
|
selective_search.o \
|
||||||
|
sincos_tab.o \
|
||||||
|
stats.o \
|
||||||
|
stereo.o \
|
||||||
|
template.o \
|
||||||
|
xyz_tab.o \
|
||||||
|
yuv.o \
|
||||||
|
zbar.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(TENSORFLOW_DIR)/*.o)
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(OMV_DIR)/ports/$(PORT)/*.o)
|
||||||
|
|
||||||
|
#------------- MicroPy Objects -------------------#
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(MICROPY_DIR)/modules/*.o)
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(MICROPY_DIR)/ports/$(PORT)/modules/*.o)
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(MICROPY_DIR)/py/*.o)
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(MICROPY_DIR)/boards/$(TARGET)/*.o)
|
||||||
|
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/,\
|
||||||
|
boards/$(MCU_SERIES)_clock_config.o \
|
||||||
|
dma_manager.o \
|
||||||
|
eth.o \
|
||||||
|
fatfs_port.o \
|
||||||
|
frozen_content.o \
|
||||||
|
flash.o \
|
||||||
|
led.o \
|
||||||
|
machine_adc.o \
|
||||||
|
machine_bitstream.o \
|
||||||
|
machine_i2c.o \
|
||||||
|
machine_i2s.o \
|
||||||
|
machine_led.o \
|
||||||
|
machine_pin.o \
|
||||||
|
machine_rtc.o \
|
||||||
|
machine_sdcard.o \
|
||||||
|
machine_spi.o \
|
||||||
|
machine_uart.o \
|
||||||
|
machine_wdt.o \
|
||||||
|
mbedtls/mbedtls_port.o \
|
||||||
|
mimxrt_flash.o \
|
||||||
|
mimxrt_sdram.o \
|
||||||
|
modmachine.o \
|
||||||
|
modmimxrt.o \
|
||||||
|
modutime.o \
|
||||||
|
mpnetworkport.o \
|
||||||
|
msc_disk.o \
|
||||||
|
network_lan.o \
|
||||||
|
mphalport.o \
|
||||||
|
pendsv.o \
|
||||||
|
pin.o \
|
||||||
|
pins_gen.o \
|
||||||
|
sdcard.o \
|
||||||
|
sdio.o \
|
||||||
|
systick.o \
|
||||||
|
ticks.o \
|
||||||
|
tusb_port.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/hal/,\
|
||||||
|
pwm_backport.o \
|
||||||
|
flexspi_nor_flash.o \
|
||||||
|
qspi_nor_flash_config.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
ifeq ($(MICROPY_PY_LWIP), 1)
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/hal/,\
|
||||||
|
phy/mdio/enet/fsl_enet_mdio.o \
|
||||||
|
phy/device/phydp83825/fsl_phydp83825.o \
|
||||||
|
phy/device/phydp83848/fsl_phydp83848.o \
|
||||||
|
phy/device/phyksz8081/fsl_phyksz8081.o \
|
||||||
|
phy/device/phylan8720/fsl_phylan8720.o \
|
||||||
|
phy/device/phyrtl8211f/fsl_phyrtl8211f.o\
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/shared/,\
|
||||||
|
libc/printf.o \
|
||||||
|
libc/string0.o \
|
||||||
|
netutils/netutils.o \
|
||||||
|
netutils/trace.o \
|
||||||
|
netutils/dhcpserver.o \
|
||||||
|
runtime/gchelper_thumb2.o \
|
||||||
|
runtime/gchelper_native.o \
|
||||||
|
runtime/interrupt_char.o \
|
||||||
|
runtime/mpirq.o \
|
||||||
|
runtime/pyexec.o \
|
||||||
|
runtime/stdout_helpers.o \
|
||||||
|
runtime/sys_stdio_mphal.o \
|
||||||
|
runtime/softtimer.o \
|
||||||
|
timeutils/timeutils.o \
|
||||||
|
readline/readline.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/lib/libm/,\
|
||||||
|
math.o \
|
||||||
|
roundf.o \
|
||||||
|
asinfacosf.o \
|
||||||
|
atanf.o \
|
||||||
|
atan2f.o \
|
||||||
|
fmodf.o \
|
||||||
|
log1pf.o \
|
||||||
|
acoshf.o \
|
||||||
|
asinhf.o \
|
||||||
|
atanhf.o \
|
||||||
|
kf_rem_pio2.o \
|
||||||
|
kf_sin.o \
|
||||||
|
kf_cos.o \
|
||||||
|
kf_tan.o \
|
||||||
|
ef_rem_pio2.o \
|
||||||
|
erf_lgamma.o \
|
||||||
|
sf_sin.o \
|
||||||
|
sf_cos.o \
|
||||||
|
sf_tan.o \
|
||||||
|
sf_frexp.o \
|
||||||
|
sf_modf.o \
|
||||||
|
sf_ldexp.o \
|
||||||
|
sf_erf.o \
|
||||||
|
wf_lgamma.o \
|
||||||
|
wf_tgamma.o \
|
||||||
|
nearbyintf.o \
|
||||||
|
thumb_vfp_sqrtf.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(MICROPY_DIR)/lib/mbedtls/library/*.o)
|
||||||
|
FIRM_OBJ += $(wildcard $(BUILD)/$(MICROPY_DIR)/lib/mbedtls_errors/*.o)
|
||||||
|
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/lib/tinyusb/src/, \
|
||||||
|
class/cdc/cdc_device.o \
|
||||||
|
class/dfu/dfu_rt_device.o \
|
||||||
|
class/hid/hid_device.o \
|
||||||
|
class/midi/midi_device.o \
|
||||||
|
class/msc/msc_device.o \
|
||||||
|
class/usbtmc/usbtmc_device.o \
|
||||||
|
class/vendor/vendor_device.o \
|
||||||
|
common/tusb_fifo.o \
|
||||||
|
device/usbd.o \
|
||||||
|
device/usbd_control.o \
|
||||||
|
tusb.o \
|
||||||
|
portable/chipidea/ci_hs/dcd_ci_hs.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/extmod/,\
|
||||||
|
machine_bitstream.o \
|
||||||
|
machine_i2c.o \
|
||||||
|
machine_mem.o \
|
||||||
|
machine_pinbase.o \
|
||||||
|
machine_pulse.o \
|
||||||
|
machine_pwm.o \
|
||||||
|
machine_signal.o \
|
||||||
|
machine_spi.o \
|
||||||
|
machine_timer.o \
|
||||||
|
modframebuf.o \
|
||||||
|
modnetwork.o \
|
||||||
|
modonewire.o \
|
||||||
|
moduasyncio.o \
|
||||||
|
modubinascii.o \
|
||||||
|
moducryptolib.o \
|
||||||
|
moductypes.o \
|
||||||
|
moduhashlib.o \
|
||||||
|
moduheapq.o \
|
||||||
|
modujson.o \
|
||||||
|
moduos.o \
|
||||||
|
moduplatform.o \
|
||||||
|
modurandom.o \
|
||||||
|
modure.o \
|
||||||
|
moduselect.o \
|
||||||
|
modusocket.o \
|
||||||
|
modussl_axtls.o \
|
||||||
|
modussl_mbedtls.o \
|
||||||
|
modutimeq.o \
|
||||||
|
moduzlib.o \
|
||||||
|
uos_dupterm.o \
|
||||||
|
utime_mphal.o \
|
||||||
|
vfs_blockdev.o \
|
||||||
|
vfs_fat_diskio.o \
|
||||||
|
vfs_fat_file.o \
|
||||||
|
vfs_fat.o \
|
||||||
|
vfs.o \
|
||||||
|
vfs_posix_file.o \
|
||||||
|
vfs_posix.o \
|
||||||
|
vfs_reader.o \
|
||||||
|
virtpin.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/lib/oofatfs/,\
|
||||||
|
ff.o \
|
||||||
|
ffunicode.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/drivers/,\
|
||||||
|
bus/softspi.o \
|
||||||
|
dht/dht.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
ifeq ($(MICROPY_PY_ULAB), 1)
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/modules/ulab/,\
|
||||||
|
code/ndarray.o \
|
||||||
|
code/ndarray_operators.o \
|
||||||
|
code/ndarray_properties.o \
|
||||||
|
code/numpy/approx.o \
|
||||||
|
code/numpy/carray/carray.o \
|
||||||
|
code/numpy/carray/carray_tools.o \
|
||||||
|
code/numpy/compare.o \
|
||||||
|
code/numpy/create.o \
|
||||||
|
code/numpy/fft/fft.o \
|
||||||
|
code/numpy/fft/fft_tools.o \
|
||||||
|
code/numpy/filter.o \
|
||||||
|
code/numpy/io/io.o \
|
||||||
|
code/numpy/linalg/linalg.o \
|
||||||
|
code/numpy/linalg/linalg_tools.o \
|
||||||
|
code/numpy/ndarray/ndarray_iter.o \
|
||||||
|
code/numpy/numerical.o \
|
||||||
|
code/numpy/numpy.o \
|
||||||
|
code/numpy/poly.o \
|
||||||
|
code/numpy/stats.o \
|
||||||
|
code/numpy/transform.o \
|
||||||
|
code/numpy/vector.o \
|
||||||
|
code/scipy/linalg/linalg.o \
|
||||||
|
code/scipy/optimize/optimize.o \
|
||||||
|
code/scipy/scipy.o \
|
||||||
|
code/scipy/signal/signal.o \
|
||||||
|
code/scipy/special/special.o \
|
||||||
|
code/ulab.o \
|
||||||
|
code/ulab_tools.o \
|
||||||
|
code/user/user.o \
|
||||||
|
code/utils/utils.o \
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(MICROPY_PY_LWIP), 1)
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/,\
|
||||||
|
lib/lwip/src/core/*.o \
|
||||||
|
lib/lwip/src/core/*/*.o \
|
||||||
|
lib/lwip/src/netif/*.o \
|
||||||
|
lib/lwip/src/apps/*/*.o \
|
||||||
|
extmod/modlwip.o \
|
||||||
|
extmod/moduwebsocket.o \
|
||||||
|
extmod/modwebrepl.o \
|
||||||
|
extmod/network_lwip.o \
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(MICROPY_PY_NETWORK_CYW43), 1)
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/,\
|
||||||
|
lib/cyw43-driver/src/*.o \
|
||||||
|
extmod/network_cyw43.o \
|
||||||
|
)
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/drivers/,\
|
||||||
|
cyw43/cywbt.o \
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(MICROPY_BLUETOOTH_NIMBLE),1)
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/lib/mynewt-nimble/,\
|
||||||
|
ext/tinycrypt/src/*.o \
|
||||||
|
nimble/host/services/gap/src/*.o \
|
||||||
|
nimble/host/services/gatt/src/*.o \
|
||||||
|
nimble/host/src/*.o \
|
||||||
|
nimble/host/util/src/*.o \
|
||||||
|
nimble/transport/uart/src/*.o \
|
||||||
|
porting/nimble/src/*.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/,\
|
||||||
|
mpbthciport.o \
|
||||||
|
mpnimbleport.o \
|
||||||
|
extmod/nimble/modbluetooth_nimble.o \
|
||||||
|
extmod/nimble/nimble/nimble_npl_os.o \
|
||||||
|
extmod/nimble/hal/hal_uart.o \
|
||||||
|
extmod/modbluetooth.o \
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(OMV_ENABLE_UVC), 1)
|
||||||
|
UVC = uvc
|
||||||
|
# UVC object files
|
||||||
|
UVC_OBJ += $(wildcard $(BUILD)/$(UVC_DIR)/src/*.o)
|
||||||
|
UVC_OBJ += $(wildcard $(BUILD)/$(HAL_DIR)/drivers/*.o)
|
||||||
|
UVC_OBJ += $(addprefix $(BUILD)/$(CMSIS_DIR)/src/,\
|
||||||
|
$(STARTUP).o \
|
||||||
|
$(SYSTEM).o \
|
||||||
|
)
|
||||||
|
|
||||||
|
UVC_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/alloc/, \
|
||||||
|
fb_alloc.o \
|
||||||
|
unaligned_memcpy.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
UVC_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/common/, \
|
||||||
|
array.o \
|
||||||
|
trace.o \
|
||||||
|
mutex.o \
|
||||||
|
vospi.o \
|
||||||
|
sensor_utils.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
UVC_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/sensors/, \
|
||||||
|
ov2640.o \
|
||||||
|
ov5640.o \
|
||||||
|
ov7690.o \
|
||||||
|
ov7670.o \
|
||||||
|
ov7725.o \
|
||||||
|
ov9650.o \
|
||||||
|
mt9v0xx.o \
|
||||||
|
mt9m114.o \
|
||||||
|
lepton.o \
|
||||||
|
hm01b0.o \
|
||||||
|
hm0360.o \
|
||||||
|
gc2145.o \
|
||||||
|
paj6100.o \
|
||||||
|
frogeye2020.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
UVC_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/imlib/,\
|
||||||
|
lab_tab.o \
|
||||||
|
xyz_tab.o \
|
||||||
|
rainbow_tab.o \
|
||||||
|
jpeg.o \
|
||||||
|
fmath.o \
|
||||||
|
imlib.o \
|
||||||
|
framebuffer.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
UVC_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/ports/$(PORT),\
|
||||||
|
sensor.o \
|
||||||
|
soft_i2c.o \
|
||||||
|
ulpi.o \
|
||||||
|
omv_spi.o \
|
||||||
|
omv_i2c.o \
|
||||||
|
omv_gpio.o \
|
||||||
|
mimxrt_hal.o \
|
||||||
|
)
|
||||||
|
|
||||||
|
UVC_OBJ += $(wildcard $(BUILD)/$(LEPTON_DIR)/src/*.o)
|
||||||
|
ifeq ($(MICROPY_PY_IMU), 1)
|
||||||
|
UVC_OBJ += $(wildcard $(BUILD)/$(LSM6DS3_DIR)/src/*.o)
|
||||||
|
UVC_OBJ += $(wildcard $(BUILD)/$(LSM6DSOX_DIR)/src/*.o)
|
||||||
|
endif
|
||||||
|
UVC_OBJ += $(wildcard $(BUILD)/$(MLX90621_DIR)/src/*.o)
|
||||||
|
UVC_OBJ += $(wildcard $(BUILD)/$(MLX90640_DIR)/src/*.o)
|
||||||
|
UVC_OBJ += $(wildcard $(BUILD)/$(MLX90641_DIR)/src/*.o)
|
||||||
|
UVC_OBJ += $(wildcard $(BUILD)/$(VL53L5CX_DIR)/src/*.o)
|
||||||
|
UVC_OBJ += $(wildcard $(BUILD)/$(PIXART_DIR)/src/*.o)
|
||||||
|
endif
|
||||||
|
|
||||||
|
###################################################
|
||||||
|
#Export Variables
|
||||||
|
export Q
|
||||||
|
export CC
|
||||||
|
export AS
|
||||||
|
export LD
|
||||||
|
export AR
|
||||||
|
export SIZE
|
||||||
|
export OBJCOPY
|
||||||
|
export OBJDUMP
|
||||||
|
export MKDIR
|
||||||
|
export ECHO
|
||||||
|
export CFLAGS
|
||||||
|
export AFLAGS
|
||||||
|
export LDFLAGS
|
||||||
|
export TOP_DIR
|
||||||
|
export BUILD
|
||||||
|
export TOOLS
|
||||||
|
export TARGET
|
||||||
|
export STARTUP
|
||||||
|
export SYSTEM
|
||||||
|
export FROZEN_MANIFEST
|
||||||
|
export PORT
|
||||||
|
export HAL_DIR
|
||||||
|
export CMSIS_DIR
|
||||||
|
export PYTHON
|
||||||
|
export TFLITE2C
|
||||||
|
###################################################
|
||||||
|
all: $(OPENMV)
|
||||||
|
|
||||||
|
$(BUILD):
|
||||||
|
$(MKDIR) -p $@
|
||||||
|
|
||||||
|
$(FW_DIR):
|
||||||
|
$(MKDIR) -p $@
|
||||||
|
|
||||||
|
FIRMWARE_OBJS: | $(BUILD) $(FW_DIR)
|
||||||
|
$(MAKE) -C $(CMSIS_DIR) BUILD=$(BUILD)/$(CMSIS_DIR) CFLAGS="$(CFLAGS) -fno-strict-aliasing -MMD"
|
||||||
|
$(MAKE) -C $(TENSORFLOW_DIR) BUILD=$(BUILD)/$(TENSORFLOW_DIR) CFLAGS="$(CFLAGS) -MMD"
|
||||||
|
$(MAKE) -C $(MICROPY_DIR)/ports/$(PORT) BUILD=$(BUILD)/$(MICROPY_DIR) $(MICROPY_ARGS)
|
||||||
|
$(MAKE) -C $(HAL_DIR) BUILD=$(BUILD)/$(HAL_DIR) CFLAGS="$(CFLAGS) -MMD"
|
||||||
|
$(MAKE) -C $(LEPTON_DIR) BUILD=$(BUILD)/$(LEPTON_DIR) CFLAGS="$(CFLAGS) -MMD"
|
||||||
|
ifeq ($(MICROPY_PY_IMU), 1)
|
||||||
|
$(MAKE) -C $(LSM6DS3_DIR) BUILD=$(BUILD)/$(LSM6DS3_DIR) CFLAGS="$(CFLAGS) -MMD"
|
||||||
|
$(MAKE) -C $(LSM6DSOX_DIR) BUILD=$(BUILD)/$(LSM6DSOX_DIR) CFLAGS="$(CFLAGS) -MMD"
|
||||||
|
endif
|
||||||
|
$(MAKE) -C $(MLX90621_DIR) BUILD=$(BUILD)/$(MLX90621_DIR) CFLAGS="$(CFLAGS) -MMD"
|
||||||
|
$(MAKE) -C $(MLX90640_DIR) BUILD=$(BUILD)/$(MLX90640_DIR) CFLAGS="$(CFLAGS) -MMD"
|
||||||
|
$(MAKE) -C $(MLX90641_DIR) BUILD=$(BUILD)/$(MLX90641_DIR) CFLAGS="$(CFLAGS) -MMD"
|
||||||
|
$(MAKE) -C $(VL53L5CX_DIR) BUILD=$(BUILD)/$(VL53L5CX_DIR) CFLAGS="$(CFLAGS) -MMD"
|
||||||
|
$(MAKE) -C $(PIXART_DIR) BUILD=$(BUILD)/$(PIXART_DIR) CFLAGS="$(CFLAGS) -MMD"
|
||||||
|
$(MAKE) -C $(OMV_DIR) BUILD=$(BUILD)/$(OMV_DIR) CFLAGS="$(CFLAGS) -MMD"
|
||||||
|
ifeq ($(OMV_ENABLE_UVC), 1)
|
||||||
|
UVC_OBJS: FIRMWARE_OBJS
|
||||||
|
$(MAKE) -C $(UVC_DIR) BUILD=$(BUILD)/$(UVC_DIR) CFLAGS="$(UVC_CFLAGS) -MMD"
|
||||||
|
endif
|
||||||
|
|
||||||
|
# This target generates the main/app firmware image located at 0x08010000
|
||||||
|
$(FIRMWARE): FIRMWARE_OBJS
|
||||||
|
$(CPP) -P -E -DLINKER_SCRIPT -I$(OMV_BOARD_CONFIG_DIR) $(OMV_DIR)/ports/$(PORT)/$(LDSCRIPT).ld.S > $(BUILD)/$(LDSCRIPT).lds
|
||||||
|
$(CC) $(LDFLAGS) $(FIRM_OBJ) -o $(FW_DIR)/$(FIRMWARE).elf $(LIBS) -lgcc
|
||||||
|
$(OBJCOPY) -Obinary -R .big_const* $(FW_DIR)/$(FIRMWARE).elf $(FW_DIR)/$(FIRMWARE).bin
|
||||||
|
# $(PYTHON) $(MKDFU) -D $(DFU_DEVICE) -b $(MAIN_APP_ADDR):$(FW_DIR)/$(FIRMWARE).bin $(FW_DIR)/$(FIRMWARE).dfu
|
||||||
|
|
||||||
|
ifeq ($(OMV_ENABLE_UVC), 1)
|
||||||
|
# This target generates the UVC firmware.
|
||||||
|
$(UVC): FIRMWARE_OBJS UVC_OBJS
|
||||||
|
$(CPP) -P -E -I$(OMV_BOARD_CONFIG_DIR) $(UVC_DIR)/$(LD_SCRIPT).ld.S > $(BUILD)/$(UVC_DIR)/$(LD_SCRIPT).lds
|
||||||
|
$(CC) $(UVC_LDFLAGS) $(UVC_OBJ) -o $(FW_DIR)/$(UVC).elf -lgcc
|
||||||
|
$(OBJCOPY) -Obinary $(FW_DIR)/$(UVC).elf $(FW_DIR)/$(UVC).bin
|
||||||
|
$(PYTHON) $(MKDFU) -D $(DFU_DEVICE) -b $(MAIN_APP_ADDR):$(FW_DIR)/$(UVC).bin $(FW_DIR)/$(UVC).dfu
|
||||||
|
endif
|
||||||
|
|
||||||
|
# This target generates the uvc and firmware images.
|
||||||
|
$(OPENMV): $(UVC) $(FIRMWARE)
|
||||||
|
$(SIZE) $(FW_DIR)/$(FIRMWARE).elf
|
||||||
|
|
||||||
|
size:
|
||||||
|
$(SIZE) --format=SysV $(FW_DIR)/$(FIRMWARE).elf
|
||||||
|
|
||||||
|
# Flash the main firmware image
|
||||||
|
flash_image::
|
||||||
|
$(PYDFU) -u $(FW_DIR)/$(FIRMWARE).dfu
|
||||||
|
|
||||||
|
# Flash the main firmware image using dfu_util
|
||||||
|
flash_image_dfu_util::
|
||||||
|
dfu-util -a 0 -d $(DFU_DEVICE) -D $(FW_DIR)/$(FIRMWARE).dfu
|
||||||
238
src/omv/ports/mimxrt/omv_spi.c
Normal file
238
src/omv/ports/mimxrt/omv_spi.c
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
* Copyright (c) 2023 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
*
|
||||||
|
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
*
|
||||||
|
* OMV SPI bus port for mimxrt.
|
||||||
|
*/
|
||||||
|
#include "omv_boardconfig.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "py/mphal.h"
|
||||||
|
|
||||||
|
#include "fsl_gpio.h"
|
||||||
|
#include "fsl_lpspi.h"
|
||||||
|
#include "fsl_iomuxc.h"
|
||||||
|
#include "fsl_lpspi_edma.h"
|
||||||
|
#include "fsl_dmamux.h"
|
||||||
|
#include CLOCK_CONFIG_H
|
||||||
|
|
||||||
|
#include "mimxrt_hal.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "omv_spi.h"
|
||||||
|
|
||||||
|
typedef struct dma_descr {
|
||||||
|
DMA_Type *dma_inst;
|
||||||
|
DMAMUX_Type *dma_mux;
|
||||||
|
uint32_t channel;
|
||||||
|
uint32_t request;
|
||||||
|
} dma_descr_t;
|
||||||
|
|
||||||
|
typedef struct omv_spi_descr {
|
||||||
|
LPSPI_Type *inst;
|
||||||
|
omv_gpio_t cs;
|
||||||
|
dma_descr_t dma_descr_tx;
|
||||||
|
dma_descr_t dma_descr_rx;
|
||||||
|
} omv_spi_descr_t;
|
||||||
|
|
||||||
|
static const omv_spi_descr_t omv_spi_descr_all[] = {
|
||||||
|
#if defined(LPSPI1_ID)
|
||||||
|
{ LPSPI1, LPSPI1_SSEL_PIN,
|
||||||
|
{ DMA0, DMAMUX, LPSPI1_DMA_TX_CHANNEL, kDmaRequestMuxLPSPI1Tx },
|
||||||
|
{ DMA0, DMAMUX, LPSPI1_DMA_RX_CHANNEL, kDmaRequestMuxLPSPI1Rx } },
|
||||||
|
#else
|
||||||
|
{ NULL, NULL, { NULL, NULL, 0, 0 }, { NULL, NULL, 0, 0 } },
|
||||||
|
#endif
|
||||||
|
#if defined(LPSPI2_ID)
|
||||||
|
{ LPSPI2, LPSPI2_SSEL_PIN,
|
||||||
|
{ DMA0, DMAMUX, LPSPI2_DMA_TX_CHANNEL, kDmaRequestMuxLPSPI2Tx },
|
||||||
|
{ DMA0, DMAMUX, LPSPI2_DMA_RX_CHANNEL, kDmaRequestMuxLPSPI2Rx } },
|
||||||
|
#else
|
||||||
|
{ NULL, NULL, { NULL, NULL, 0, 0 }, { NULL, NULL, 0, 0 } },
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(LPSPI3_ID)
|
||||||
|
{ LPSPI3, LPSPI3_SSEL_PIN,
|
||||||
|
{ DMA0, DMAMUX, LPSPI3_DMA_TX_CHANNEL, kDmaRequestMuxLPSPI3Tx },
|
||||||
|
{ DMA0, DMAMUX, LPSPI3_DMA_RX_CHANNEL, kDmaRequestMuxLPSPI3Rx } },
|
||||||
|
#else
|
||||||
|
{ NULL, NULL, { NULL, NULL, 0, 0 }, { NULL, NULL, 0, 0 } },
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(LPSPI4_ID)
|
||||||
|
{ LPSPI4, LPSPI4_SSEL_PIN,
|
||||||
|
{ DMA0, DMAMUX, LPSPI4_DMA_TX_CHANNEL, kDmaRequestMuxLPSPI4Tx },
|
||||||
|
{ DMA0, DMAMUX, LPSPI4_DMA_RX_CHANNEL, kDmaRequestMuxLPSPI4Rx } },
|
||||||
|
#else
|
||||||
|
{ NULL, NULL, { NULL, NULL, 0, 0 }, { NULL, NULL, 0, 0 } },
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static void spi_master_callback(LPSPI_Type *base, void *handle, status_t status, void *user)
|
||||||
|
{
|
||||||
|
omv_spi_t *spi = (omv_spi_t *) user;
|
||||||
|
|
||||||
|
if (status == kStatus_Success) {
|
||||||
|
spi->xfer_flags |= OMV_SPI_XFER_COMPLETE;
|
||||||
|
} else {
|
||||||
|
spi->xfer_flags |= OMV_SPI_XFER_FAILED;
|
||||||
|
spi->xfer_error = status;
|
||||||
|
if (spi->xfer_flags & OMV_SPI_XFER_DMA) {
|
||||||
|
LPSPI_MasterTransferAbortEDMA(spi->inst, &spi->descr_master_edma);
|
||||||
|
} else {
|
||||||
|
LPSPI_MasterTransferAbort(spi->inst, &spi->descr_master);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spi->callback) {
|
||||||
|
spi->callback(spi, spi->userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t flags = (OMV_SPI_XFER_DMA | OMV_SPI_XFER_CIRCULAR | OMV_SPI_XFER_COMPLETE);
|
||||||
|
if ((spi->xfer_flags & flags) == flags) {
|
||||||
|
// Restart transfer for circular transfers.
|
||||||
|
spi->xfer_flags &= ~(OMV_SPI_XFER_COMPLETE);
|
||||||
|
LPSPI_MasterTransferEDMA(spi->inst, &spi->descr_master_edma, &spi->xfer_descr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer)
|
||||||
|
{
|
||||||
|
spi->callback = xfer->callback;
|
||||||
|
spi->userdata = xfer->userdata;
|
||||||
|
spi->xfer_flags = xfer->flags;
|
||||||
|
// Duplicate & stash transfer in spi struct, to avoid recreating
|
||||||
|
// it for circular transfers. NOTE: If circular transfers ever
|
||||||
|
// works this can be removed.
|
||||||
|
spi->xfer_descr.txData = xfer->txbuf;
|
||||||
|
spi->xfer_descr.rxData = xfer->rxbuf;
|
||||||
|
spi->xfer_descr.dataSize = xfer->size;
|
||||||
|
spi->xfer_descr.configFlags = kLPSPI_MasterPcs0 | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap;
|
||||||
|
spi->xfer_flags &= ~(OMV_SPI_XFER_FAILED | OMV_SPI_XFER_COMPLETE);
|
||||||
|
|
||||||
|
if (spi->xfer_flags & OMV_SPI_XFER_DMA) {
|
||||||
|
// DMA transfer (circular or one-shot)
|
||||||
|
if (LPSPI_MasterTransferEDMA(spi->inst, &spi->descr_master_edma, &spi->xfer_descr) != kStatus_Success) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (spi->xfer_flags & (OMV_SPI_XFER_BLOCKING | OMV_SPI_XFER_NONBLOCK)) {
|
||||||
|
// Use non-blocking mode for both non-blocking and blocking
|
||||||
|
// transfers, this way we can control the timeout better.
|
||||||
|
if (LPSPI_MasterTransferNonBlocking(spi->inst, &spi->descr_master, &spi->xfer_descr) != kStatus_Success) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-blocking transfetr, return immediately and the user
|
||||||
|
// callback will be called when the transfer is done.
|
||||||
|
if (spi->xfer_flags & OMV_SPI_XFER_NONBLOCK) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blocking transfetr, wait for transfer complete or timeout.
|
||||||
|
mp_uint_t start = mp_hal_ticks_ms();
|
||||||
|
while (!(spi->xfer_flags & OMV_SPI_XFER_COMPLETE)) {
|
||||||
|
if ((spi->xfer_flags & OMV_SPI_XFER_FAILED) ||
|
||||||
|
((mp_hal_ticks_ms() - start) > xfer->timeout)) {
|
||||||
|
LPSPI_MasterTransferAbort(spi->inst, &spi->descr_master);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
MICROPY_EVENT_POLL_HOOK
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_spi_transfer_abort(omv_spi_t *spi)
|
||||||
|
{
|
||||||
|
LPSPI_MasterTransferAbortEDMA(spi->inst, &spi->descr_master_edma);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int omv_spi_dma_init(edma_handle_t *dma_handle, const dma_descr_t *dma_descr)
|
||||||
|
{
|
||||||
|
DMAMUX_SetSource(dma_descr->dma_mux, dma_descr->channel, dma_descr->request);
|
||||||
|
DMAMUX_EnableChannel(dma_descr->dma_mux, dma_descr->channel);
|
||||||
|
EDMA_CreateHandle(dma_handle, dma_descr->dma_inst, dma_descr->channel);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_spi_init(omv_spi_t *spi, omv_spi_config_t *config)
|
||||||
|
{
|
||||||
|
// Configure clocks, pins and DMA MUX.
|
||||||
|
mimxrt_hal_spi_init(config->id, config->nss_enable, config->nss_pol);
|
||||||
|
|
||||||
|
const omv_spi_descr_t *spi_descr = &omv_spi_descr_all[config->id - 1];
|
||||||
|
if (spi_descr->inst == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(spi, 0, sizeof(omv_spi_t));
|
||||||
|
spi->id = config->id;
|
||||||
|
spi->inst = spi_descr->inst;
|
||||||
|
spi->cs = spi_descr->cs;
|
||||||
|
spi->dma_enabled = config->dma_enable;
|
||||||
|
|
||||||
|
lpspi_master_config_t spi_config;
|
||||||
|
LPSPI_MasterGetDefaultConfig(&spi_config);
|
||||||
|
|
||||||
|
spi_config.whichPcs = kLPSPI_Pcs0;
|
||||||
|
spi_config.baudRate = config->baudrate;
|
||||||
|
spi_config.bitsPerFrame = config->datasize;
|
||||||
|
spi_config.direction = config->bit_order;
|
||||||
|
spi_config.pcsActiveHighOrLow = config->nss_pol;
|
||||||
|
spi_config.cpol = config->clk_pol;
|
||||||
|
spi_config.cpha = config->clk_pha;
|
||||||
|
spi_config.dataOutConfig = config->data_retained ? kLpspiDataOutRetained : kLpspiDataOutTristate;
|
||||||
|
LPSPI_MasterInit(spi->inst, &spi_config, BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT);
|
||||||
|
|
||||||
|
if (config->dma_enable) {
|
||||||
|
// Configure DMA.
|
||||||
|
// Note the FSL driver doesn't support half-duplex, so the both
|
||||||
|
// TX/RX channels, descriptors etc... must be initialized.
|
||||||
|
omv_spi_dma_init(&spi->dma_descr_tx, &spi_descr->dma_descr_tx);
|
||||||
|
omv_spi_dma_init(&spi->dma_descr_rx, &spi_descr->dma_descr_rx);
|
||||||
|
|
||||||
|
// Link TX/RX DMA descriptors to SPI descriptor.
|
||||||
|
LPSPI_MasterTransferCreateHandleEDMA(
|
||||||
|
spi->inst,
|
||||||
|
&spi->descr_master_edma,
|
||||||
|
(lpspi_master_edma_transfer_callback_t) spi_master_callback,
|
||||||
|
spi,
|
||||||
|
&spi->dma_descr_rx,
|
||||||
|
&spi->dma_descr_tx);
|
||||||
|
} else {
|
||||||
|
LPSPI_MasterTransferCreateHandle(
|
||||||
|
spi->inst,
|
||||||
|
&spi->descr_master,
|
||||||
|
(lpspi_master_transfer_callback_t) spi_master_callback,
|
||||||
|
spi);
|
||||||
|
}
|
||||||
|
spi->initialized = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_spi_deinit(omv_spi_t *spi)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_spi_default_config(omv_spi_config_t *config, uint32_t bus_id)
|
||||||
|
{
|
||||||
|
config->id = bus_id;
|
||||||
|
config->baudrate = 10000000;
|
||||||
|
config->datasize = 8;
|
||||||
|
config->spi_mode = OMV_SPI_MODE_MASTER;
|
||||||
|
config->bus_mode = OMV_SPI_BUS_TX_RX;
|
||||||
|
config->bit_order = OMV_SPI_MSB_FIRST;
|
||||||
|
config->clk_pol = OMV_SPI_CPOL_HIGH;
|
||||||
|
config->clk_pha = OMV_SPI_CPHA_2EDGE;
|
||||||
|
config->nss_pol = OMV_SPI_NSS_LOW;
|
||||||
|
config->nss_enable = true;
|
||||||
|
config->dma_enable = false;
|
||||||
|
config->data_retained = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
379
src/omv/ports/mimxrt/sensor.c
Normal file
379
src/omv/ports/mimxrt/sensor.c
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2023 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
* Copyright (c) 2013-2023 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
*
|
||||||
|
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
*
|
||||||
|
* Sensor abstraction layer for nRF port.
|
||||||
|
*/
|
||||||
|
#if MICROPY_PY_SENSOR
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "py/mphal.h"
|
||||||
|
|
||||||
|
#include "fsl_csi.h"
|
||||||
|
#include "mimxrt_hal.h"
|
||||||
|
|
||||||
|
#include "omv_boardconfig.h"
|
||||||
|
#include "omv_gpio.h"
|
||||||
|
#include "omv_i2c.h"
|
||||||
|
#include "sensor.h"
|
||||||
|
#include "framebuffer.h"
|
||||||
|
#include "unaligned_memcpy.h"
|
||||||
|
|
||||||
|
// Sensor struct.
|
||||||
|
sensor_t sensor = {};
|
||||||
|
extern uint8_t _line_buf[OMV_LINE_BUF_SIZE];
|
||||||
|
|
||||||
|
#define CSI_IRQ_FLAGS ( CSI_CR1_SOF_INTEN_MASK \
|
||||||
|
| CSI_CR1_FB2_DMA_DONE_INTEN_MASK \
|
||||||
|
| CSI_CR1_FB1_DMA_DONE_INTEN_MASK )
|
||||||
|
//CSI_CR1_RF_OR_INTEN_MASK
|
||||||
|
|
||||||
|
#define copy_line(dstp, srcp) \
|
||||||
|
for (int i = MAIN_FB()->u, h = MAIN_FB()->v; i; i--) { \
|
||||||
|
*dstp = *srcp++; \
|
||||||
|
dstp += h; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define copy_line_rev(dstp, srcp) \
|
||||||
|
for (int i = MAIN_FB()->u, h = MAIN_FB()->v; i; i--) { \
|
||||||
|
*dstp = __REV16(*srcp++); \
|
||||||
|
dstp += h; \
|
||||||
|
}
|
||||||
|
|
||||||
|
void sensor_init0()
|
||||||
|
{
|
||||||
|
sensor_abort();
|
||||||
|
|
||||||
|
// Re-init I2C to reset the bus state after soft reset, which
|
||||||
|
// could have interrupted the bus in the middle of a transfer.
|
||||||
|
if (sensor.i2c_bus.initialized) {
|
||||||
|
// Reinitialize the bus using the last used id and speed.
|
||||||
|
omv_i2c_init(&sensor.i2c_bus, sensor.i2c_bus.id, sensor.i2c_bus.speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable VSYNC IRQ and callback
|
||||||
|
sensor_set_vsync_callback(NULL);
|
||||||
|
|
||||||
|
// Disable Frame callback.
|
||||||
|
sensor_set_frame_callback(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sensor_init()
|
||||||
|
{
|
||||||
|
int init_ret = 0;
|
||||||
|
|
||||||
|
mimxrt_hal_csi_init(CSI);
|
||||||
|
|
||||||
|
#if defined(DCMI_POWER_PIN)
|
||||||
|
omv_gpio_write(DCMI_POWER_PIN, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(DCMI_RESET_PIN)
|
||||||
|
omv_gpio_write(DCMI_RESET_PIN, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Reset the sesnor state
|
||||||
|
memset(&sensor, 0, sizeof(sensor_t));
|
||||||
|
|
||||||
|
// Set default snapshot function.
|
||||||
|
// Some sensors need to call snapshot from init.
|
||||||
|
sensor.snapshot = sensor_snapshot;
|
||||||
|
|
||||||
|
// Configure the sensor external clock (XCLK).
|
||||||
|
if (sensor_set_xclk_frequency(OMV_XCLK_FREQUENCY) != 0) {
|
||||||
|
// Failed to initialize the sensor clock.
|
||||||
|
return SENSOR_ERROR_TIM_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect and initialize the image sensor.
|
||||||
|
if ((init_ret = sensor_probe_init(ISC_I2C_ID, ISC_I2C_SPEED)) != 0) {
|
||||||
|
// Sensor probe/init failed.
|
||||||
|
return init_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set default color palette.
|
||||||
|
sensor.color_palette = rainbow_table;
|
||||||
|
|
||||||
|
// Disable VSYNC IRQ and callback
|
||||||
|
sensor_set_vsync_callback(NULL);
|
||||||
|
|
||||||
|
// Disable Frame callback.
|
||||||
|
sensor_set_frame_callback(NULL);
|
||||||
|
|
||||||
|
// All good!
|
||||||
|
sensor.detected = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sensor_dcmi_config(uint32_t pixformat)
|
||||||
|
{
|
||||||
|
CSI_Reset(CSI);
|
||||||
|
NVIC_DisableIRQ(CSI_IRQn);
|
||||||
|
|
||||||
|
// CSI mode: HSYNC, VSYNC, and PIXCLK signals are used.
|
||||||
|
CSI_REG_CR1(CSI) |= CSI_CR1_GCLK_MODE(1U);
|
||||||
|
// Synchronous FIFO clear.
|
||||||
|
// RXFIFO and STATFIFO are cleared on every SOF.
|
||||||
|
CSI_REG_CR1(CSI) |= CSI_CR1_FCC_MASK;
|
||||||
|
|
||||||
|
// Configure VSYNC, HSYNC and PIXCLK signals.
|
||||||
|
CSI_REG_CR1(CSI) |= CSI_CR1_EXT_VSYNC_MASK;
|
||||||
|
CSI_REG_CR1(CSI) |= !sensor.hw_flags.vsync ? CSI_CR1_SOF_POL_MASK : 0;
|
||||||
|
CSI_REG_CR1(CSI) |= !sensor.hw_flags.hsync ? CSI_CR1_HSYNC_POL_MASK : 0;
|
||||||
|
CSI_REG_CR1(CSI) |= sensor.hw_flags.pixck ? CSI_CR1_REDGE_MASK : 0;
|
||||||
|
|
||||||
|
// Stride config: No stride.
|
||||||
|
CSI_REG_FBUF_PARA(CSI) = 0;
|
||||||
|
// Reset frame counter
|
||||||
|
CSI_REG_CR3(CSI) |= CSI_CR3_FRMCNT_RST_MASK;
|
||||||
|
|
||||||
|
// Configure CSI FIFO depth and DMA burst size.
|
||||||
|
CSI_REG_CR2(CSI) |= CSI_CR2_DMA_BURST_TYPE_RFF(3U);
|
||||||
|
CSI_REG_CR3(CSI) |= 7U << CSI_CR3_RxFF_LEVEL_SHIFT;
|
||||||
|
|
||||||
|
// Configure DMA buffers.
|
||||||
|
CSI_REG_DMASA_FB1(CSI) = (uint32_t) (&_line_buf[OMV_LINE_BUF_SIZE * 0]);
|
||||||
|
CSI_REG_DMASA_FB2(CSI) = (uint32_t) (&_line_buf[OMV_LINE_BUF_SIZE / 2]);
|
||||||
|
|
||||||
|
// Write to memory from first completed frame.
|
||||||
|
// DMA CSI addr switch at dma transfer done.
|
||||||
|
CSI_REG_CR18(CSI) |= CSI_CR18_MASK_OPTION(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sensor_abort()
|
||||||
|
{
|
||||||
|
NVIC_DisableIRQ(CSI_IRQn);
|
||||||
|
CSI_DisableInterrupts(CSI, CSI_IRQ_FLAGS);
|
||||||
|
CSI_REG_CR18(CSI) &= ~(CSI_CR18_CSI_ENABLE_MASK | CSI_CR3_DMA_REQ_EN_RFF_MASK);
|
||||||
|
framebuffer_reset_buffers();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sensor_set_xclk_frequency(uint32_t frequency)
|
||||||
|
{
|
||||||
|
if (frequency == 24000000) {
|
||||||
|
CLOCK_SetDiv(kCLOCK_CsiDiv, 0);
|
||||||
|
} else if (frequency == 12000000) {
|
||||||
|
CLOCK_SetDiv(kCLOCK_CsiDiv, 1);
|
||||||
|
} else if (frequency == 8000000) {
|
||||||
|
CLOCK_SetDiv(kCLOCK_CsiDiv, 2);
|
||||||
|
} else if (frequency == 6000000) {
|
||||||
|
CLOCK_SetDiv(kCLOCK_CsiDiv, 3);
|
||||||
|
} else if (frequency == 4000000) {
|
||||||
|
CLOCK_SetDiv(kCLOCK_CsiDiv, 5);
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sensor_get_xclk_frequency()
|
||||||
|
{
|
||||||
|
return 24000000 / (CLOCK_GetDiv(kCLOCK_CsiDiv) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sensor_sof_callback()
|
||||||
|
{
|
||||||
|
// Get current framebuffer.
|
||||||
|
vbuffer_t *buffer = framebuffer_get_tail(FB_PEEK);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
sensor_abort();
|
||||||
|
} if (buffer->offset < MAIN_FB()->v) {
|
||||||
|
// Missed a few lines, reset buffer state and continue.
|
||||||
|
buffer->reset_state = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sensor_line_callback(uint32_t addr)
|
||||||
|
{
|
||||||
|
// Get current framebuffer.
|
||||||
|
vbuffer_t *buffer = framebuffer_get_tail(FB_PEEK);
|
||||||
|
|
||||||
|
// Copy from DMA buffer to framebuffer.
|
||||||
|
uint32_t bytes_per_pixel = sensor_get_src_bpp();
|
||||||
|
uint8_t *src = ((uint8_t *) addr) + (MAIN_FB()->x * bytes_per_pixel);
|
||||||
|
uint8_t *dst = buffer->data;
|
||||||
|
|
||||||
|
// Adjust BPP for Grayscale.
|
||||||
|
if (sensor.pixformat == PIXFORMAT_GRAYSCALE) {
|
||||||
|
bytes_per_pixel = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sensor.transpose) {
|
||||||
|
dst += bytes_per_pixel * buffer->offset;
|
||||||
|
} else {
|
||||||
|
dst += MAIN_FB()->u * bytes_per_pixel * buffer->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement per line, per pixel cropping, and image transposing (for image rotation) in
|
||||||
|
// in software using the CPU to transfer the image from the line buffers to the frame buffer.
|
||||||
|
uint16_t *src16 = (uint16_t *) src;
|
||||||
|
uint16_t *dst16 = (uint16_t *) dst;
|
||||||
|
|
||||||
|
switch (sensor.pixformat) {
|
||||||
|
case PIXFORMAT_BAYER:
|
||||||
|
#if (OMV_ENABLE_SENSOR_EDMA == 1)
|
||||||
|
edma_memcpy(buffer, dst, src, sizeof(uint8_t), sensor.transpose);
|
||||||
|
#else
|
||||||
|
if (!sensor.transpose) {
|
||||||
|
unaligned_memcpy(dst, src, MAIN_FB()->u);
|
||||||
|
} else {
|
||||||
|
copy_line(dst, src);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case PIXFORMAT_GRAYSCALE:
|
||||||
|
#if (OMV_ENABLE_SENSOR_EDMA == 1)
|
||||||
|
edma_memcpy(buffer, dst, src, sizeof(uint8_t), sensor.transpose);
|
||||||
|
#else
|
||||||
|
if (sensor.hw_flags.gs_bpp == 1) {
|
||||||
|
// 1BPP GRAYSCALE.
|
||||||
|
if (!sensor.transpose) {
|
||||||
|
unaligned_memcpy(dst, src, MAIN_FB()->u);
|
||||||
|
} else {
|
||||||
|
copy_line(dst, src);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Extract Y channel from YUV.
|
||||||
|
if (!sensor.transpose) {
|
||||||
|
unaligned_2_to_1_memcpy(dst, src16, MAIN_FB()->u);
|
||||||
|
} else {
|
||||||
|
copy_line(dst, src16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case PIXFORMAT_RGB565:
|
||||||
|
case PIXFORMAT_YUV422:
|
||||||
|
#if (OMV_ENABLE_SENSOR_EDMA == 1)
|
||||||
|
edma_memcpy(buffer, dst16, src16, sizeof(uint16_t), sensor.transpose);
|
||||||
|
#else
|
||||||
|
if ((sensor.pixformat == PIXFORMAT_RGB565 && sensor.hw_flags.rgb_swap)
|
||||||
|
|| (sensor.pixformat == PIXFORMAT_YUV422 && sensor.hw_flags.yuv_swap)) {
|
||||||
|
if (!sensor.transpose) {
|
||||||
|
unaligned_memcpy_rev16(dst16, src16, MAIN_FB()->u);
|
||||||
|
} else {
|
||||||
|
copy_line_rev(dst16, src16);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!sensor.transpose) {
|
||||||
|
unaligned_memcpy(dst16, src16, MAIN_FB()->u * sizeof(uint16_t));
|
||||||
|
} else {
|
||||||
|
copy_line(dst16, src16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++buffer->offset == MAIN_FB()->v) {
|
||||||
|
// Release the current framebuffer.
|
||||||
|
framebuffer_get_tail(FB_NO_FLAGS);
|
||||||
|
CSI_REG_CR3(CSI) &= ~CSI_CR3_DMA_REQ_EN_RFF_MASK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
// Used to restore MAIN_FB's width and height.
|
||||||
|
uint32_t w = MAIN_FB()->u;
|
||||||
|
uint32_t h = MAIN_FB()->v;
|
||||||
|
|
||||||
|
if (sensor->pixformat == PIXFORMAT_INVALID) {
|
||||||
|
return SENSOR_ERROR_INVALID_PIXFORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sensor->framesize == FRAMESIZE_INVALID) {
|
||||||
|
return SENSOR_ERROR_INVALID_FRAMESIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sensor_check_framebuffer_size() != 0) {
|
||||||
|
return SENSOR_ERROR_FRAMEBUFFER_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compress the framebuffer for the IDE preview.
|
||||||
|
framebuffer_update_jpeg_buffer();
|
||||||
|
|
||||||
|
// Free the current FB head.
|
||||||
|
framebuffer_free_current_buffer();
|
||||||
|
|
||||||
|
// If the DMA is Not currently transferring a new buffer,
|
||||||
|
// reconfigure and restart the CSI transfer.
|
||||||
|
if (!(CSI->CR18 & CSI_CR18_CSI_ENABLE_MASK)) {
|
||||||
|
framebuffer_setup_buffers();
|
||||||
|
|
||||||
|
vbuffer_t *buffer = framebuffer_get_tail(FB_PEEK);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
return SENSOR_ERROR_FRAMEBUFFER_ERROR;
|
||||||
|
}
|
||||||
|
// Re/configure and re/start the CSI.
|
||||||
|
uint32_t bytes_per_pixel = sensor_get_src_bpp();
|
||||||
|
uint32_t dma_line_bytes = resolution[sensor->framesize][0] * bytes_per_pixel;
|
||||||
|
CSI_REG_IMAG_PARA(CSI) =
|
||||||
|
(dma_line_bytes << CSI_IMAG_PARA_IMAGE_WIDTH_SHIFT ) |
|
||||||
|
(1 << CSI_IMAG_PARA_IMAGE_HEIGHT_SHIFT);
|
||||||
|
|
||||||
|
// Configure and enable CSI interrupts.
|
||||||
|
CSI_EnableInterrupts(CSI, CSI_IRQ_FLAGS);
|
||||||
|
NVIC_EnableIRQ(CSI_IRQn);
|
||||||
|
|
||||||
|
// Enable CSI
|
||||||
|
CSI_REG_CR18(CSI) |= CSI_CR18_CSI_ENABLE_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
vbuffer_t *buffer = framebuffer_get_head(FB_NO_FLAGS);
|
||||||
|
// 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) {
|
||||||
|
sensor_abort();
|
||||||
|
return SENSOR_ERROR_CAPTURE_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sensor->transpose) {
|
||||||
|
MAIN_FB()->w = w;
|
||||||
|
MAIN_FB()->h = h;
|
||||||
|
} else {
|
||||||
|
MAIN_FB()->w = h;
|
||||||
|
MAIN_FB()->h = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix the BPP.
|
||||||
|
switch (sensor->pixformat) {
|
||||||
|
case PIXFORMAT_GRAYSCALE:
|
||||||
|
MAIN_FB()->pixfmt = PIXFORMAT_GRAYSCALE;
|
||||||
|
break;
|
||||||
|
case PIXFORMAT_RGB565:
|
||||||
|
MAIN_FB()->pixfmt = PIXFORMAT_RGB565;
|
||||||
|
break;
|
||||||
|
case PIXFORMAT_BAYER:
|
||||||
|
MAIN_FB()->pixfmt = PIXFORMAT_BAYER;
|
||||||
|
MAIN_FB()->subfmt_id = sensor->hw_flags.bayer;
|
||||||
|
break;
|
||||||
|
case PIXFORMAT_YUV422: {
|
||||||
|
bool yuv_order = sensor->hw_flags.yuv_order == SENSOR_HW_FLAGS_YUV422;
|
||||||
|
int even = yuv_order ? PIXFORMAT_YUV422 : PIXFORMAT_YVU422;
|
||||||
|
int odd = yuv_order ? PIXFORMAT_YVU422 : PIXFORMAT_YUV422;
|
||||||
|
MAIN_FB()->pixfmt = (MAIN_FB()->x % 2) ? odd : even;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the user image.
|
||||||
|
framebuffer_init_image(image);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
121
tools/imxrt_pins_gen.py
Normal file
121
tools/imxrt_pins_gen.py
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# This file is part of the OpenMV project.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2023 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
# Copyright (c) 2023 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
#
|
||||||
|
# This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import argparse
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
def parse_header_file(file_path):
|
||||||
|
pads = defaultdict(dict)
|
||||||
|
gpios = {}
|
||||||
|
for i in range(0, 11):
|
||||||
|
gpios[i] = 0
|
||||||
|
|
||||||
|
af_pattern = "\s([0x]*[0-9a-fA-F]+)U*,*" * 5
|
||||||
|
pad_pattern = [
|
||||||
|
re.compile("#define IOMUXC_GPIO_(\w+_\d\d)_([a-zA-Z0-9]+)_(\w+)" + af_pattern),
|
||||||
|
re.compile("#define IOMUXC_SNVS_(PMIC\w+_REQ)_([a-zA-Z0-9]+)_(\w+)"+ af_pattern),
|
||||||
|
re.compile("#define IOMUXC_SNVS_(WAKEUP)_([a-zA-Z0-9]+)_*(\w*)"+ af_pattern)
|
||||||
|
]
|
||||||
|
with open(file_path, "r") as file:
|
||||||
|
for line in file:
|
||||||
|
for r in pad_pattern:
|
||||||
|
match = re.match(r, line)
|
||||||
|
if match:
|
||||||
|
match = match.groups()
|
||||||
|
if (match[1].startswith("GPIO")):
|
||||||
|
gpios[int(match[1][4:])] += 1
|
||||||
|
pads[match[0]][int(match[-4], 16)] = match[1:]
|
||||||
|
break
|
||||||
|
return pads, gpios
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description = "Usage: python gen_iomux_pins.py <fsl_iomuxc.h>.")
|
||||||
|
parser.add_argument("--iomux", action = "store", help = "Input iomux header files.", required=True)
|
||||||
|
parser.add_argument("--header", action = "store_true", help = "Generate header file.", required=False, default=False)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
print("// THIS FILE IS AUTO-GENERATED DO NOT EDIT.\n")
|
||||||
|
print("/*")
|
||||||
|
print(" * This file is part of the OpenMV project.")
|
||||||
|
print(" *")
|
||||||
|
print(" * Copyright (c) 2023 Ibrahim Abdelkader <iabdalkader@openmv.io>")
|
||||||
|
print(" * Copyright (c) 2023 Kwabena W. Agyeman <kwagyeman@openmv.io>")
|
||||||
|
print(" *")
|
||||||
|
print(" * This work is licensed under the MIT license, see the file LICENSE for details.")
|
||||||
|
print(" */")
|
||||||
|
|
||||||
|
pads, gpios = parse_header_file(args.iomux)
|
||||||
|
|
||||||
|
if (args.header):
|
||||||
|
# Generate the header file
|
||||||
|
print("#ifndef __IMXRT_PADS_H__")
|
||||||
|
print("#define __IMXRT_PADS_H__\n")
|
||||||
|
print("#define MIMXRT_PAD_COUNT {:d}\n".format(len(pads)))
|
||||||
|
|
||||||
|
for pad_name, pad_afs in pads.items():
|
||||||
|
af_gpio = pad_afs[5] # GPIO AF is always 5
|
||||||
|
for af_idx, af in pad_afs.items():
|
||||||
|
if af_idx == 5:
|
||||||
|
af_name = "GPIO"
|
||||||
|
elif af[0] in ["ENET", "ENET2", "SEMC"]:
|
||||||
|
af_name = "_".join(af[0:2])
|
||||||
|
else:
|
||||||
|
af_name = af[0]
|
||||||
|
print("#define {:s}_AF_{:s} {:s}".format(pad_name, af_name, af[-4]))
|
||||||
|
print()
|
||||||
|
|
||||||
|
for pad_name, pad_afs in pads.items():
|
||||||
|
afs_count = len(pad_afs.keys()) - 1 # remove gpio AF.
|
||||||
|
print("extern const imxrt_pad_t imxrt_pad_{:s};".format(pad_name))
|
||||||
|
|
||||||
|
print("#endif // __IMXRT_PADS_H__")
|
||||||
|
else:
|
||||||
|
print("#include \"omv_gpio.h\"")
|
||||||
|
print("#include \"fsl_gpio.h\"")
|
||||||
|
print("#include \"fsl_iomuxc.h\"")
|
||||||
|
print("#include \"mimxrt_pads.h\"")
|
||||||
|
|
||||||
|
print()
|
||||||
|
irq_handlers_list = []
|
||||||
|
for port, pin_count in gpios.items():
|
||||||
|
if (pin_count):
|
||||||
|
print("static omv_gpio_irq_descr_t gpio_irq_descr_gpio{:d}[{:d}] = {{ NULL }};".format(port, pin_count))
|
||||||
|
irq_handlers_list.append(" [{:d}] = gpio_irq_descr_gpio{:d},\n".format(port, port))
|
||||||
|
print()
|
||||||
|
print("omv_gpio_irq_descr_t *const gpio_irq_descr_table[{:d}] = {{\n{:s}}};".format(
|
||||||
|
len(gpios.keys()), "".join(irq_handlers_list)))
|
||||||
|
|
||||||
|
# Generate the C file
|
||||||
|
reg_mask = lambda r: int(r, 16) & 0x0000FFFF
|
||||||
|
reg_base = lambda r: (int(r, 16) & 0xFFFF0000) >> 16
|
||||||
|
for pad_name, pad_afs in pads.items():
|
||||||
|
print()
|
||||||
|
pad_afs_list = []
|
||||||
|
for af_idx, af in pad_afs.items():
|
||||||
|
if (af_idx == 5):
|
||||||
|
continue
|
||||||
|
mux_reg, mux_mode, input_reg, input_daisy, config_reg = af[-5:]
|
||||||
|
pad_afs_list.append("\n {{ {:d}, 0x{:04X}, {:d} }}, // {:s}".format(
|
||||||
|
af_idx, reg_mask(input_reg), int(input_daisy, 16), af[0]))
|
||||||
|
print("static const imxrt_pad_af_t imxrt_pad_{:s}_AF[{:d}] = {{{:s}\n}};".format(
|
||||||
|
pad_name, len(pad_afs_list), "".join(pad_afs_list)))
|
||||||
|
|
||||||
|
# GPIO AF is always 5, use it to get mux_reg and config_reg which
|
||||||
|
# are the same for all AFs, and 0, 0, for input register/daisy
|
||||||
|
gpio, pin, mux_reg, mux_mode, input_reg, input_daisy, config_reg = pad_afs[5][-7:]
|
||||||
|
afs_count = len(pad_afs.keys()) - 1 # remove GPIO AF.
|
||||||
|
print("const imxrt_pad_t imxrt_pad_{:s} ="
|
||||||
|
" {{ {:s}, {:d}, 0x{:04X}, 0x{:04X}, 0x{:04X}, {:d}, imxrt_pad_{:s}_AF }};".
|
||||||
|
format(pad_name, gpio, int(pin[2:]), reg_base(mux_reg),
|
||||||
|
reg_mask(mux_reg), reg_mask(config_reg), afs_count, pad_name))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Reference in New Issue
Block a user