alif: Add initial port to Alif Ensemble MCUs.

This commit adds the beginning of a new alif port with support for Alif
Ensemble MCUs.  See https://alifsemi.com/

Supported features of this port added by this commit:
- UART REPL.
- TinyUSB support, for REPL and MSC.
- Octal SPI flash support, for filesystem.
- machine.Pin support.

General notes about the port:
- It uses make, similar to other bare-metal ports here.
- The toolchain is the standard arm-none-eabi- toolchain.
- Flashing a board can be done using either the built-in serial bootloader,
  or JLink (both supported here).
- There are two required submodules (one for drivers/SDK, one for security
  tools), both of which are open source and on GitHub.
- No special hardware or software is needed for development, just a board
  connected over USB.

OpenMV have generously sponsored the development of this port.

Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
This commit is contained in:
Damien George
2023-12-12 00:11:46 +11:00
parent b8a9cdf067
commit ccc5935234
31 changed files with 2740 additions and 0 deletions

261
ports/alif/Makefile Normal file
View File

@@ -0,0 +1,261 @@
################################################################################
# Initial setup of Makefile environment
BOARD ?= ALIF_ENSEMBLE
BOARD_DIR ?= boards/$(BOARD)
BUILD ?= build-$(BOARD)
ifeq ($(wildcard $(BOARD_DIR)/.),)
$(error Invalid BOARD specified: $(BOARD_DIR))
endif
include ../../py/mkenv.mk
include mpconfigport.mk
include $(BOARD_DIR)/mpconfigboard.mk
# qstr definitions (must come before including py.mk)
QSTR_DEFS += qstrdefsport.h
# include py core make definitions
include $(TOP)/py/py.mk
include $(TOP)/extmod/extmod.mk
################################################################################
# Project specific settings and compiler/linker flags
CROSS_COMPILE ?= arm-none-eabi-
GIT_SUBMODULES += lib/tinyusb lib/alif_ensemble-cmsis-dfp lib/alif-security-toolkit
PORT ?= /dev/ttyACM0
ALIF_TOOLS ?= ../../lib/alif-security-toolkit/toolkit
ALIF_DFP_REL_TOP ?= lib/alif_ensemble-cmsis-dfp
ALIF_DFP_REL_HERE ?= $(TOP)/lib/alif_ensemble-cmsis-dfp
CMSIS_DIR ?= $(TOP)/lib/cmsis/inc
MCU_CORE ?= M55_HP
ALIF_CONFIG ?= mcu/$(MCU_CORE)_cfg.json
LD_FILE ?= mcu/ensemble.ld.S
INC += -I.
INC += -I$(TOP)
INC += -I$(BUILD)
INC += -I$(BOARD_DIR)
INC += -I$(CMSIS_DIR)
INC += -I$(ALIF_DFP_REL_HERE)/drivers/include/
INC += -I$(ALIF_DFP_REL_HERE)/ospi_xip/source/ospi
INC += -I$(ALIF_DFP_REL_HERE)/Device/common/config/
INC += -I$(ALIF_DFP_REL_HERE)/Device/common/include/
INC += -I$(ALIF_DFP_REL_HERE)/Device/core/$(MCU_CORE)/config/
INC += -I$(ALIF_DFP_REL_HERE)/Device/core/$(MCU_CORE)/include/
INC += -I$(ALIF_DFP_REL_HERE)/Device/$(MCU_SERIES)/$(MCU_VARIANT)/
INC += -I$(TOP)/lib/tinyusb/src
INC += -Itinyusb_port
GEN_PIN_MKPINS = mcu/make-pins.py
GEN_PIN_PREFIX = mcu/pins_prefix.c
GEN_PINS_BOARD_CSV = $(BOARD_DIR)/pins.csv
GEN_PINS_SRC = $(BUILD)/pins_board.c
GEN_PINS_HDR = $(HEADER_BUILD)/pins_board.h
CFLAGS_FPU += -mfloat-abi=hard -mfpu=fpv5-d16
CFLAGS_CORTEX_M55 += -mthumb -mcpu=cortex-m55 -mtune=cortex-m55 $(CFLAGS_FPU)
CFLAGS += $(INC) -Wall -Werror -std=c99 $(CFLAGS_CORTEX_M55) -nostdlib
CFLAGS += -Wdouble-promotion -Wfloat-conversion
CFLAGS += -fdata-sections -ffunction-sections
CFLAGS += -D$(MCU_CORE) -DCORE_$(MCU_CORE) -DALIF_CMSIS_H="\"$(MCU_CORE).h\""
ifeq ($(MICROPY_FLOAT_IMPL),float)
CFLAGS += -fsingle-precision-constant
CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_FLOAT
else
CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_DOUBLE
endif
AFLAGS = -mthumb -march=armv8.1-m.main $(CFLAGS_FPU)
LDFLAGS += -nostdlib
LDFLAGS += -T$(BUILD)/ensemble.ld -Map=$@.map --cref --gc-sections
LDFLAGS += --wrap=dcd_event_handler
# Tune for Debugging or Optimization
ifeq ($(DEBUG), 1)
CFLAGS += -Og -ggdb3
# Disable text compression in debug builds
MICROPY_ROM_TEXT_COMPRESSION = 0
else
CFLAGS += -O2 -DNDEBUG
endif
LIBS += "$(shell $(CC) $(CFLAGS) -print-libgcc-file-name)"
JLINK_CMD = '\
ExitOnError 1\n\
Device $(JLINK_DEV)\n\
SelectInterface SWD\n\
Speed auto\n\
Connect\n\
Reset\n\
ShowHWStatus\n\
LoadFile "$(BUILD)/firmware_toc.bin",0x8057f1c0\n\
LoadFile "$(BUILD)/firmware.bin",0x80000000\n\
Reset\n\
Exit'
################################################################################
# Source files and libraries
SRC_O += \
shared/runtime/gchelper_thumb2.o
SRC_C = \
alif_flash.c \
fatfs_port.c \
machine_pin.c \
main.c \
modalif.c \
mphalport.c \
mpuart.c \
msc_disk.c \
ospi_flash.c \
pendsv.c \
usbd.c \
$(wildcard $(BOARD_DIR)/*.c)
ifeq ($(MICROPY_FLOAT_IMPL),float)
LIBM_SRC_C += $(SRC_LIB_LIBM_C)
LIBM_SRC_C += $(SRC_LIB_LIBM_SQRT_HW_C)
$(BUILD)/lib/libm/%.o: CFLAGS += -Wno-maybe-uninitialized
else
LIBM_SRC_C += $(SRC_LIB_LIBM_DBL_C)
LIBM_SRC_C += $(SRC_LIB_LIBM_DBL_SQRT_HW_C)
$(BUILD)/lib/libm_dbl/%.o: CFLAGS += -Wno-maybe-uninitialized
endif
SHARED_SRC_C += $(addprefix shared/,\
libc/string0.c \
netutils/dhcpserver.c \
netutils/netutils.c \
netutils/trace.c \
readline/readline.c \
runtime/gchelper_native.c \
runtime/interrupt_char.c \
runtime/mpirq.c \
runtime/pyexec.c \
runtime/softtimer.c \
runtime/stdout_helpers.c \
runtime/sys_stdio_mphal.c \
timeutils/timeutils.c \
tinyusb/mp_usbd.c \
tinyusb/mp_usbd_cdc.c \
tinyusb/mp_usbd_descriptor.c \
)
DRIVERS_SRC_C += $(addprefix drivers/,\
bus/softspi.c \
bus/softqspi.c \
memory/spiflash.c \
dht/dht.c \
)
TINYUSB_SRC_C += \
lib/tinyusb/src/tusb.c \
lib/tinyusb/src/class/cdc/cdc_device.c \
lib/tinyusb/src/class/msc/msc_device.c \
lib/tinyusb/src/common/tusb_fifo.c \
lib/tinyusb/src/device/usbd.c \
lib/tinyusb/src/device/usbd_control.c \
tinyusb_port/tusb_alif_dcd.c \
ALIF_SRC_C += $(addprefix $(ALIF_DFP_REL_TOP)/,\
Device/common/source/clk.c \
Device/common/source/mpu_M55.c \
Device/common/source/system_M55.c \
Device/common/source/system_utils.c \
Device/core/$(MCU_CORE)/source/startup_$(MCU_CORE).c \
drivers/source/pinconf.c \
drivers/source/uart.c \
ospi_xip/source/ospi/ospi_drv.c \
)
$(BUILD)/tinyusb_port/tusb_alif_dcd.o: CFLAGS += -Wno-unused-variable -DTUSB_ALIF_NO_IRQ_CFG=1
# List of sources for qstr extraction
SRC_QSTR += $(SRC_C) $(SHARED_SRC_C) $(GEN_PINS_SRC)
OBJ += $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_O))
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(LIBM_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SHARED_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(TINYUSB_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(ALIF_SRC_C:.c=.o))
OBJ += $(GEN_PINS_SRC:.c=.o)
################################################################################
# Main targets
.DELETE_ON_ERROR:
.PHONY: all
all: $(BUILD)/firmware_toc.bin
$(BUILD)/ensemble.ld: $(LD_FILE)
$(ECHO) "Preprocess linker script $@"
$(Q)$(CPP) -P -E $(CFLAGS) $^ > $@
$(BUILD)/firmware.elf: $(OBJ) $(BUILD)/ensemble.ld
$(ECHO) "Link $@"
$(Q)$(LD) $(LDFLAGS) -o $@ $(OBJ) $(LIBS)
$(Q)$(SIZE) $@
$(BUILD)/firmware.bin: $(BUILD)/firmware.elf
$(Q)$(OBJCOPY) -Obinary $^ $(BUILD)/firmware.bin
$(BUILD)/firmware_toc.bin: $(BUILD)/firmware.bin
$(Q)python $(ALIF_TOOLS)/app-gen-toc.py \
--filename $(abspath $(BUILD)/$(ALIF_TOC_CONFIG)) \
--output-dir $(BUILD) \
--firmware-dir $(BUILD) \
--output $@
.PHONY: deploy
deploy: $(BUILD)/firmware_toc.bin
$(ECHO) "Writing $< to the board"
$(Q)python $(ALIF_TOOLS)/app-write-mram.py \
--cfg-part $(ALIF_TOOLKIT_CFG_PART) \
--port $(PORT) \
--pad \
--images file:$(BUILD)/application_package.ds
.PHONY: deploy-jlink
deploy-jlink: $(BUILD)/firmware_toc.bin
$(Q)echo -e $(JLINK_CMD) | $(JLINK_EXE)
.PHONY: maintenance
maintenance:
$(Q)python $(ALIF_TOOLS)/maintenance.py \
--cfg-part $(ALIF_TOOLKIT_CFG_PART) \
--port $(PORT)
.PHONY: update-system-package
update-system-package:
$(Q)python $(ALIF_TOOLS)/updateSystemPackage.py \
--cfg-part $(ALIF_TOOLKIT_CFG_PART) \
--port $(PORT)
################################################################################
# Remaining make rules
# Use a pattern rule here so that make will only call make-pins.py once to make
# both pins_board.c and pins_board.h
$(BUILD)/%_board.c $(HEADER_BUILD)/%_board.h: $(BOARD_DIR)/%.csv $(GEN_PIN_MKPINS) $(GEN_PIN_PREFIX) | $(HEADER_BUILD)
$(ECHO) "GEN $@"
$(Q)$(PYTHON) $(GEN_PIN_MKPINS) \
--board-csv $(GEN_PINS_BOARD_CSV) \
--prefix $(GEN_PIN_PREFIX) \
--output-source $(GEN_PINS_SRC) \
--output-header $(GEN_PINS_HDR)
include $(TOP)/py/mkrules.mk

21
ports/alif/README.md Normal file
View File

@@ -0,0 +1,21 @@
MicroPython port to Alif Ensemble MCUs
======================================
This is a port of MicroPython to the Alif Ensemble series of microcontrollers.
Initial development of this Alif port was sponsored by OpenMV LLC.
Features currently supported:
- UART REPL.
- TinyUSB with CDC and MSC device support.
- Octal SPI flash with XIP mode.
- machine.Pin support with named pins.
- machine.UART, machine.SPI, machine.I2C, machine.RTC peripherals.
- WiFi and Bluetooth using cyw43.
- Dual core support of the HE and HP cores using Open-AMP.
- Low power modes.
The following more advanced features will follow later:
- Ethernet support.
- SDRAM support.
- Other machine modules.

160
ports/alif/alif_flash.c Normal file
View File

@@ -0,0 +1,160 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/mphal.h"
#include "py/runtime.h"
#include "extmod/vfs.h"
#include "modalif.h"
#include "ospi_flash.h"
typedef struct _alif_flash_obj_t {
mp_obj_base_t base;
uint32_t flash_base_addr;
uint32_t flash_size;
} alif_flash_obj_t;
static alif_flash_obj_t alif_flash_obj = {
.base = { &alif_flash_type },
.flash_base_addr = MICROPY_HW_FLASH_STORAGE_BASE_ADDR,
.flash_size = MICROPY_HW_FLASH_STORAGE_BYTES,
};
static mp_obj_t alif_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
// Parse arguments
enum { ARG_start, ARG_len };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if (args[ARG_start].u_int == -1 && args[ARG_len].u_int == -1) {
// Default singleton object that accesses entire flash
return MP_OBJ_FROM_PTR(&alif_flash_obj);
}
alif_flash_obj_t *self = mp_obj_malloc(alif_flash_obj_t, &alif_flash_type);
mp_int_t start = args[ARG_start].u_int;
if (start == -1) {
start = 0;
} else if (!(0 <= start && start < MICROPY_HW_FLASH_STORAGE_BYTES && start % MICROPY_HW_FLASH_BLOCK_SIZE_BYTES == 0)) {
mp_raise_ValueError(NULL);
}
mp_int_t len = args[ARG_len].u_int;
if (len == -1) {
len = MICROPY_HW_FLASH_STORAGE_BYTES - start;
} else if (!(0 < len && start + len <= MICROPY_HW_FLASH_STORAGE_BYTES && len % MICROPY_HW_FLASH_BLOCK_SIZE_BYTES == 0)) {
mp_raise_ValueError(NULL);
}
self->flash_base_addr = MICROPY_HW_FLASH_STORAGE_BASE_ADDR + start;
self->flash_size = len;
return MP_OBJ_FROM_PTR(self);
}
static mp_obj_t alif_flash_readblocks(size_t n_args, const mp_obj_t *args) {
alif_flash_obj_t *self = MP_OBJ_TO_PTR(args[0]);
uint32_t offset = mp_obj_get_int(args[1]) * MICROPY_HW_FLASH_BLOCK_SIZE_BYTES;
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_WRITE);
if (n_args == 4) {
offset += mp_obj_get_int(args[3]);
}
int ret = ospi_flash_read(self->flash_base_addr + offset, bufinfo.len, bufinfo.buf);
mp_event_handle_nowait();
return MP_OBJ_NEW_SMALL_INT(ret);
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alif_flash_readblocks_obj, 3, 4, alif_flash_readblocks);
static mp_obj_t alif_flash_writeblocks(size_t n_args, const mp_obj_t *args) {
alif_flash_obj_t *self = MP_OBJ_TO_PTR(args[0]);
uint32_t offset = mp_obj_get_int(args[1]) * MICROPY_HW_FLASH_BLOCK_SIZE_BYTES;
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
if (n_args == 3) {
uint32_t addr = self->flash_base_addr + offset;
int32_t len = bufinfo.len;
while (len > 0) {
int ret = ospi_flash_erase_sector(addr);
mp_event_handle_nowait();
if (ret < 0) {
return MP_OBJ_NEW_SMALL_INT(ret);
}
addr += MICROPY_HW_FLASH_BLOCK_SIZE_BYTES;
len -= MICROPY_HW_FLASH_BLOCK_SIZE_BYTES;
}
} else {
offset += mp_obj_get_int(args[3]);
}
int ret = ospi_flash_write(self->flash_base_addr + offset, bufinfo.len, bufinfo.buf);
mp_event_handle_nowait();
return MP_OBJ_NEW_SMALL_INT(ret);
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alif_flash_writeblocks_obj, 3, 4, alif_flash_writeblocks);
static mp_obj_t alif_flash_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_in) {
alif_flash_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_int_t cmd = mp_obj_get_int(cmd_in);
switch (cmd) {
case MP_BLOCKDEV_IOCTL_INIT:
return MP_OBJ_NEW_SMALL_INT(0);
case MP_BLOCKDEV_IOCTL_DEINIT:
return MP_OBJ_NEW_SMALL_INT(0);
case MP_BLOCKDEV_IOCTL_SYNC:
return MP_OBJ_NEW_SMALL_INT(0);
case MP_BLOCKDEV_IOCTL_BLOCK_COUNT:
return MP_OBJ_NEW_SMALL_INT(self->flash_size / MICROPY_HW_FLASH_BLOCK_SIZE_BYTES);
case MP_BLOCKDEV_IOCTL_BLOCK_SIZE:
return MP_OBJ_NEW_SMALL_INT(MICROPY_HW_FLASH_BLOCK_SIZE_BYTES);
case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: {
uint32_t offset = mp_obj_get_int(arg_in) * MICROPY_HW_FLASH_BLOCK_SIZE_BYTES;
int ret = ospi_flash_erase_sector(self->flash_base_addr + offset);
return MP_OBJ_NEW_SMALL_INT(ret);
}
default:
return mp_const_none;
}
}
static MP_DEFINE_CONST_FUN_OBJ_3(alif_flash_ioctl_obj, alif_flash_ioctl);
static const mp_rom_map_elem_t alif_flash_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&alif_flash_readblocks_obj) },
{ MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&alif_flash_writeblocks_obj) },
{ MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&alif_flash_ioctl_obj) },
};
static MP_DEFINE_CONST_DICT(alif_flash_locals_dict, alif_flash_locals_dict_table);
MP_DEFINE_CONST_OBJ_TYPE(
alif_flash_type,
MP_QSTR_Flash,
MP_TYPE_FLAG_NONE,
make_new, alif_flash_make_new,
locals_dict, &alif_flash_locals_dict
);

View File

@@ -0,0 +1,5 @@
freeze("$(PORT_DIR)/modules")
include("$(MPY_DIR)/extmod/asyncio")
require("dht")
require("neopixel")
require("onewire")

38
ports/alif/fatfs_port.c Normal file
View File

@@ -0,0 +1,38 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "lib/oofatfs/ff.h"
DWORD get_fattime(void) {
// TODO
int year = 2024;
int month = 1;
int day = 1;
int hour = 0;
int min = 0;
int sec = 0;
return ((year - 1980) << 25) | (month << 21) | (day << 16) | (hour << 11) | (min << 5) | (sec / 2);
}

84
ports/alif/irq.h Normal file
View File

@@ -0,0 +1,84 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013-2023 Damien P. George
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_ALIF_IRQ_H
#define MICROPY_INCLUDED_ALIF_IRQ_H
#include <stdint.h>
#include ALIF_CMSIS_H
// IRQ priority definitions.
//
// The M55-HP CPU has __NVIC_PRIO_BITS==8 bits for setting the IRQ priority.
// It uses NVIC_SetPriorityGrouping(0) which is 7 bits for preempt priority
// and 1 bit for the sub-priority.
//
// Lower number implies higher interrupt priority.
#define NVIC_PRIORITYGROUP_7 ((uint32_t)0x00000000U)
#define IRQ_PRI_SYSTEM_TICK NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 0, 0)
#define IRQ_PRI_QUIET_TIMING NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 1, 0)
#define IRQ_PRI_UART_REPL NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 1, 0)
#define IRQ_PRI_USB NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 5, 0)
#define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 127, 0)
// these states correspond to values from query_irq, enable_irq and disable_irq
#define IRQ_STATE_DISABLED (0x00000001)
#define IRQ_STATE_ENABLED (0x00000000)
static inline uint32_t query_irq(void) {
return __get_PRIMASK();
}
static inline void enable_irq(uint32_t state) {
__set_PRIMASK(state);
}
static inline uint32_t disable_irq(void) {
uint32_t state = __get_PRIMASK();
__disable_irq();
return state;
}
// irqs with a priority value greater or equal to "pri" will be disabled
static inline uint32_t raise_irq_pri(uint32_t pri) {
uint32_t basepri = __get_BASEPRI();
// If non-zero, the processor does not process any exception with a
// priority value greater than or equal to BASEPRI.
// When writing to BASEPRI_MAX the write goes to BASEPRI only if either:
// - Rn is non-zero and the current BASEPRI value is 0
// - Rn is non-zero and less than the current BASEPRI value
pri <<= (8 - __NVIC_PRIO_BITS);
__ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory");
return basepri;
}
// "basepri" should be the value returned from raise_irq_pri
static inline void restore_irq_pri(uint32_t basepri) {
__set_BASEPRI(basepri);
}
#endif // MICROPY_INCLUDED_ALIF_IRQ_H

298
ports/alif/machine_pin.c Normal file
View File

@@ -0,0 +1,298 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/runtime.h"
#include "py/mphal.h"
#include "extmod/modmachine.h"
#include "extmod/virtpin.h"
#include "shared/runtime/mpirq.h"
extern const mp_obj_dict_t machine_pin_cpu_pins_locals_dict;
extern const mp_obj_dict_t machine_pin_board_pins_locals_dict;
static const machine_pin_obj_t *machine_pin_find_named(const mp_obj_dict_t *named_pins, mp_obj_t name) {
const mp_map_t *named_map = &named_pins->map;
mp_map_elem_t *named_elem = mp_map_lookup((mp_map_t *)named_map, name, MP_MAP_LOOKUP);
if (named_elem != NULL && named_elem->value != NULL) {
return MP_OBJ_TO_PTR(named_elem->value);
}
return NULL;
}
const machine_pin_obj_t *machine_pin_find(mp_obj_t pin) {
// Is already a object of the proper type
if (mp_obj_is_type(pin, &machine_pin_type)) {
return MP_OBJ_TO_PTR(pin);
}
if (mp_obj_is_str(pin)) {
// Try to find the pin in the board pins first.
const machine_pin_obj_t *self = machine_pin_find_named(&machine_pin_board_pins_locals_dict, pin);
if (self != NULL) {
return self;
}
// If not found, try to find the pin in the cpu pins.
self = machine_pin_find_named(&machine_pin_cpu_pins_locals_dict, pin);
if (self != NULL) {
return self;
}
// Pin name not found.
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("unknown named pin \"%s\""), mp_obj_str_get_str(pin));
}
mp_raise_ValueError(MP_ERROR_TEXT("invalid pin"));
}
static void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_pin_obj_t *self = self_in;
uint8_t alt_func, pad_ctrl;
pinconf_get(self->port, self->pin, &alt_func, &pad_ctrl);
qstr mode_qst;
if (gpio_get_direction(self->gpio, self->pin) == GPIO_PIN_DIR_INPUT) {
mode_qst = MP_QSTR_IN;
} else {
if (pad_ctrl & PADCTRL_DRIVER_OPEN_DRAIN) {
mode_qst = MP_QSTR_OPEN_DRAIN;
} else {
mode_qst = MP_QSTR_OUT;
}
}
mp_printf(print, "Pin(%q, mode=%q", self->name, mode_qst);
uint8_t pad_ctrl_pull = pad_ctrl & (PADCTRL_DRIVER_DISABLED_PULL_DOWN | PADCTRL_DRIVER_DISABLED_PULL_UP);
if (pad_ctrl_pull == PADCTRL_DRIVER_DISABLED_PULL_UP) {
mp_printf(print, ", pull=%q", MP_QSTR_PULL_UP);
} else if (pad_ctrl_pull == PADCTRL_DRIVER_DISABLED_PULL_DOWN) {
mp_printf(print, ", pull=%q", MP_QSTR_PULL_DOWN);
}
if (alt_func != PINMUX_ALTERNATE_FUNCTION_0) {
mp_printf(print, ", alt=%u", alt_func);
}
mp_printf(print, ")");
}
enum {
ARG_mode, ARG_pull, ARG_value, ARG_alt
};
static const mp_arg_t allowed_args[] = {
{MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE}},
{MP_QSTR_pull, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE}},
{MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE}},
{MP_QSTR_alt, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0}},
};
static mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
// parse args
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
// get initial value of pin (only valid for OUT and OPEN_DRAIN modes)
int value = -1;
if (args[ARG_value].u_obj != mp_const_none) {
value = mp_obj_is_true(args[ARG_value].u_obj);
}
// configure mode
if (args[ARG_mode].u_obj != mp_const_none) {
mp_int_t mode = mp_obj_get_int(args[ARG_mode].u_obj);
if (mode == MP_HAL_PIN_MODE_INPUT) {
mp_hal_pin_input(self);
} else if (mode == MP_HAL_PIN_MODE_OUTPUT) {
if (value != -1) {
// set initial output value before configuring mode
mp_hal_pin_write(self, value);
}
mp_hal_pin_output(self);
} else if (mode == MP_HAL_PIN_MODE_OPEN_DRAIN) {
if (value != -1) {
// set initial output value before configuring mode
mp_hal_pin_write(self, value);
}
mp_hal_pin_open_drain(self);
}
}
// Configure pull (unconditionally because None means no-pull).
uint32_t pull = 0;
if (args[ARG_pull].u_obj != mp_const_none) {
pull = mp_obj_get_int(args[ARG_pull].u_obj);
}
uint8_t alt_func;
uint8_t pad_ctrl;
pinconf_get(self->port, self->pin, &alt_func, &pad_ctrl);
alt_func = PINMUX_ALTERNATE_FUNCTION_0;
pad_ctrl |= PADCTRL_READ_ENABLE;
pad_ctrl &= ~(PADCTRL_DRIVER_DISABLED_PULL_DOWN | PADCTRL_DRIVER_DISABLED_PULL_UP);
if (pull & MP_HAL_PIN_PULL_UP) {
pad_ctrl |= PADCTRL_DRIVER_DISABLED_PULL_UP;
}
if (pull & MP_HAL_PIN_PULL_DOWN) {
pad_ctrl |= PADCTRL_DRIVER_DISABLED_PULL_DOWN;
}
pinconf_set(self->port, self->pin, alt_func, pad_ctrl);
return mp_const_none;
}
// constructor(id, ...)
mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
const machine_pin_obj_t *self = machine_pin_find(args[0]);
if (n_args > 1 || n_kw > 0) {
// pin mode given, so configure this GPIO
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
machine_pin_obj_init_helper(self, n_args - 1, args + 1, &kw_args);
}
return MP_OBJ_FROM_PTR(self);
}
// fast method for getting/setting pin value
static mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
machine_pin_obj_t *self = self_in;
if (n_args == 0) {
// get pin
return MP_OBJ_NEW_SMALL_INT(mp_hal_pin_read(self));
} else {
// set pin
bool value = mp_obj_is_true(args[0]);
mp_hal_pin_write(self, value);
return mp_const_none;
}
}
// pin.init(mode, pull)
static mp_obj_t machine_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
}
MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_obj_init);
// pin.value([value])
static mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) {
return machine_pin_call(args[0], n_args - 1, 0, args + 1);
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value);
// pin.low()
static mp_obj_t machine_pin_low(mp_obj_t self_in) {
machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_hal_pin_low(self);
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_low_obj, machine_pin_low);
// pin.high()
static mp_obj_t machine_pin_high(mp_obj_t self_in) {
machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_hal_pin_high(self);
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_high_obj, machine_pin_high);
// pin.toggle()
static mp_obj_t machine_pin_toggle(mp_obj_t self_in) {
machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
gpio_toggle_value(self->gpio, self->pin);
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_toggle_obj, machine_pin_toggle);
static MP_DEFINE_CONST_OBJ_TYPE(
pin_cpu_pins_obj_type,
MP_QSTR_cpu,
MP_TYPE_FLAG_NONE,
locals_dict, &machine_pin_cpu_pins_locals_dict
);
static MP_DEFINE_CONST_OBJ_TYPE(
pin_board_pins_obj_type,
MP_QSTR_board,
MP_TYPE_FLAG_NONE,
locals_dict, &machine_pin_board_pins_locals_dict
);
static const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
// instance methods
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) },
{ MP_ROM_QSTR(MP_QSTR_low), MP_ROM_PTR(&machine_pin_low_obj) },
{ MP_ROM_QSTR(MP_QSTR_high), MP_ROM_PTR(&machine_pin_high_obj) },
{ MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&machine_pin_low_obj) },
{ MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&machine_pin_high_obj) },
{ MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&machine_pin_toggle_obj) },
// class attributes
{ MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&pin_board_pins_obj_type) },
{ MP_ROM_QSTR(MP_QSTR_cpu), MP_ROM_PTR(&pin_cpu_pins_obj_type) },
// class constants
{ MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(MP_HAL_PIN_MODE_INPUT) },
{ MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(MP_HAL_PIN_MODE_OUTPUT) },
{ MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(MP_HAL_PIN_MODE_OPEN_DRAIN) },
{ MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(MP_HAL_PIN_PULL_UP) },
{ MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(MP_HAL_PIN_PULL_DOWN) },
};
static MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table);
static mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
(void)errcode;
machine_pin_obj_t *self = self_in;
switch (request) {
case MP_PIN_READ: {
return mp_hal_pin_read(self);
}
case MP_PIN_WRITE: {
mp_hal_pin_write(self, arg);
return 0;
}
}
return -1;
}
static const mp_pin_p_t pin_pin_p = {
.ioctl = pin_ioctl,
};
MP_DEFINE_CONST_OBJ_TYPE(
machine_pin_type,
MP_QSTR_Pin,
MP_TYPE_FLAG_NONE,
make_new, mp_pin_make_new,
print, machine_pin_print,
call, machine_pin_call,
protocol, &pin_pin_p,
locals_dict, &machine_pin_locals_dict
);
mp_hal_pin_obj_t mp_hal_get_pin_obj(mp_obj_t obj) {
return machine_pin_find(obj);
}

145
ports/alif/main.c Normal file
View File

@@ -0,0 +1,145 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#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/tinyusb/mp_usbd.h"
#include "tusb.h"
#include "mpuart.h"
#include "ospi_flash.h"
#include "pendsv.h"
extern uint8_t __StackTop, __StackLimit;
extern uint8_t __GcHeapStart, __GcHeapEnd;
NORETURN void panic(const char *msg) {
mp_hal_stdout_tx_strn("\nFATAL ERROR:\n", 14);
mp_hal_stdout_tx_strn(msg, strlen(msg));
for (;;) {
*(volatile uint32_t *)0x4900C000 ^= 9;
for (volatile uint delay = 0; delay < 10000000; delay++) {
}
}
}
void _start(void) {
SysTick_Config(SystemCoreClock / 1000);
MICROPY_BOARD_STARTUP();
pendsv_init();
MICROPY_BOARD_EARLY_INIT();
#if MICROPY_HW_ENABLE_UART_REPL
mp_uart_init();
#endif
if (ospi_flash_init() != 0) {
MICROPY_BOARD_FATAL_ERROR("ospi_init failed");
}
#if MICROPY_HW_ENABLE_USBDEV
NVIC_ClearPendingIRQ(USB_IRQ_IRQn);
NVIC_SetPriority(USB_IRQ_IRQn, IRQ_PRI_USB);
#endif
// Initialise stack extents and GC heap.
mp_stack_set_top(&__StackTop);
mp_stack_set_limit(&__StackTop - &__StackLimit - 1024);
gc_init(&__GcHeapStart, &__GcHeapEnd);
for (;;) {
// Initialise MicroPython runtime.
mp_init();
// Initialise sub-systems.
readline_init0();
// Execute _boot.py to set up the filesystem.
pyexec_frozen_module("_boot.py", false);
// Execute user scripts.
int ret = pyexec_file_if_exists("boot.py");
#if MICROPY_HW_ENABLE_USBDEV
mp_usbd_init();
#endif
if (ret & PYEXEC_FORCED_EXIT) {
goto soft_reset_exit;
}
if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL && ret != 0) {
ret = pyexec_file_if_exists("main.py");
if (ret & PYEXEC_FORCED_EXIT) {
goto soft_reset_exit;
}
}
for (;;) {
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
if (pyexec_raw_repl() != 0) {
break;
}
} else {
if (pyexec_friendly_repl() != 0) {
break;
}
}
}
soft_reset_exit:
mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n");
gc_sweep_all();
mp_deinit();
}
}
void gc_collect(void) {
gc_collect_start();
gc_helper_collect_regs_and_stack();
gc_collect_end();
}
void nlr_jump_fail(void *val) {
mp_printf(&mp_plat_print, "FATAL: uncaught exception %p\n", val);
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(val));
for (;;) {
__WFE();
}
}
#ifndef NDEBUG
void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) {
printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line);
panic("Assertion failed");
}
#endif

View File

@@ -0,0 +1,14 @@
{
"USER_APP": {
"binary": "firmware.bin",
"mramAddress": "0x80000000",
"version": "1.0.0",
"cpu_id": "M55_HP",
"flags": ["boot"],
"signed": false
},
"DEVICE": {
"binary": "app-device-config.json",
"version" : "0.5.00"
}
}

View File

@@ -0,0 +1,165 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2023 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
// Entry Point
ENTRY(Reset_Handler)
MEMORY
{
ROM (rx) : ORIGIN = 0x80000000, LENGTH = 0x0057F000
ITCM (rwx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
#ifdef CORE_M55_HP
DTCM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00100000
#else
DTCM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00040000
#endif
SRAM0 (rwx) : ORIGIN = 0x02000000, LENGTH = 0x00400000
SRAM1 (rwx) : ORIGIN = 0x08000000, LENGTH = 0x00280000
}
__STACK_SIZE = 0x00004000;
__HEAP_SIZE = 0x00004000;
__MP_HEAP_SIZE = 0x00040000;
SECTIONS
{
.text : ALIGN(16)
{
KEEP(*(.vectors))
. = ALIGN(4);
*(.text*)
. = ALIGN(4);
*(.rodata*)
. = ALIGN(16);
} > ROM
.copy.table : ALIGN(4)
{
__copy_table_start__ = .;
LONG ( LOADADDR(.data) )
LONG ( ADDR(.data) )
LONG ( SIZEOF(.data)/4 )
__copy_table_end__ = .;
. = ALIGN(16);
} > ROM
.zero.table : ALIGN(4)
{
__zero_table_start__ = .;
LONG (ADDR(.bss))
LONG (SIZEOF(.bss)/4)
LONG (ADDR(.bss.sram0))
LONG (SIZEOF(.bss.sram0)/4)
__zero_table_end__ = .;
. = ALIGN(16);
} > ROM
.data : ALIGN(8)
{
*(.data)
. = ALIGN(8);
*(.data.*)
. = ALIGN(16);
} > DTCM AT > ROM
/* Peripherals in expansion master 0 (USB, Ethernet, SD/MMC)
are by default configured as non-secure, so they don't
have access to DTCMs. This can be fixed in the ToC by allowing
access to DTCMs to all bus masters, for now these peripherals
should place buffers in regular SRAM */
.bss.sram0 (NOLOAD) : ALIGN(4)
{
* (.bss.sram0*)
} > SRAM0
.bss : ALIGN(4)
{
__bss_start__ = .;
*(.bss)
. = ALIGN(4);
*(.bss.*)
. = ALIGN(4);
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > DTCM
.heap (NOLOAD) : ALIGN(4)
{
__end__ = .;
PROVIDE(end = .);
. = . + __HEAP_SIZE;
. = ALIGN(4);
__HeapLimit = .;
/* MicroPython GC heap */
. = ALIGN(16);
__GcHeapStart = .;
. = . + __MP_HEAP_SIZE;
__GcHeapEnd = .;
} > DTCM
.stack (NOLOAD) : ALIGN(4)
{
__StackLimit = .;
. = . + __STACK_SIZE;
. = ALIGN(4);
__StackTop = .;
} > DTCM
PROVIDE(__stack = __StackTop);
.init_fini_arrays : ALIGN(16)
{
KEEP(*(.init))
KEEP(*(.fini))
. = ALIGN(4);
/* preinit data */
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP(*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
/* init data */
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
/* finit data */
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);
KEEP(*(.eh_frame*))
. = ALIGN(16);
} > ROM
/* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
}

64
ports/alif/mcu/make-pins.py Executable file
View File

@@ -0,0 +1,64 @@
#!/usr/bin/env python
import os
import re
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../../../tools"))
import boardgen
NUM_PORTS = 16
NUM_PINS_PER_PORT = 8
class AlifPin(boardgen.Pin):
# Emit the struct which contains the pin instance.
def definition(self):
port, pin = self.name()[1:].split("_")
base = "LPGPIO_BASE" if port == "15" else "GPIO{}_BASE".format(port)
return (
"{{ "
".base = {{ .type = &machine_pin_type }}, "
".gpio = (GPIO_Type *){base}, "
".port = PORT_{port}, "
".pin = PIN_{pin}, "
".name = MP_QSTR_P{port}_{pin} "
"}}".format(port=port, pin=pin, base=base)
)
# Alif cpu names must be "Pn_m".
@staticmethod
def validate_cpu_pin_name(cpu_pin_name):
boardgen.Pin.validate_cpu_pin_name(cpu_pin_name)
if not (m := re.match("P([0-9]){1,2}_([0-9])", cpu_pin_name)):
raise boardgen.PinGeneratorError(
"Invalid cpu pin name '{}', must be 'Pn_m'".format(cpu_pin_name)
)
port = int(m.group(1))
pin = int(m.group(2))
if not (0 <= port < NUM_PORTS and 0 <= pin < NUM_PINS_PER_PORT):
raise boardgen.PinGeneratorError("Unknown cpu pin '{}'".format(cpu_pin_name))
class AlifPinGenerator(boardgen.PinGenerator):
def __init__(self):
# Use custom pin type above.
super().__init__(pin_type=AlifPin)
# Pre-define the pins (i.e. don't require them to be listed in pins.csv).
for i in range(NUM_PORTS):
for j in range(NUM_PINS_PER_PORT):
self.add_cpu_pin("P{}_{}".format(i, j))
# Only use pre-defined cpu pins (do not let board.csv create them).
def find_pin_by_cpu_pin_name(self, cpu_pin_name, create=True):
return super().find_pin_by_cpu_pin_name(cpu_pin_name, create=False)
def cpu_table_size(self):
return "{} * {}".format(NUM_PORTS, NUM_PINS_PER_PORT)
if __name__ == "__main__":
AlifPinGenerator().main()

View File

@@ -0,0 +1,2 @@
#include "py/mphal.h"
#include "extmod/modmachine.h"

46
ports/alif/modalif.c Normal file
View File

@@ -0,0 +1,46 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/mphal.h"
#include "py/runtime.h"
#include "modalif.h"
static const mp_rom_map_elem_t alif_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_alif) },
{ MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&alif_flash_type) },
#if MICROPY_HW_USB_MSC
// Attribute to indicate USB MSC is enabled.
{ MP_ROM_QSTR(MP_QSTR_usb_msc), MP_ROM_TRUE },
#endif
};
static MP_DEFINE_CONST_DICT(alif_module_globals, alif_module_globals_table);
const mp_obj_module_t mp_module_alif = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&alif_module_globals,
};
MP_REGISTER_MODULE(MP_QSTR_alif, mp_module_alif);

33
ports/alif/modalif.h Normal file
View File

@@ -0,0 +1,33 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_ALIF_MODALIF_H
#define MICROPY_INCLUDED_ALIF_MODALIF_H
#include "py/obj.h"
extern const mp_obj_type_t alif_flash_type;
#endif // MICROPY_INCLUDED_ALIF_MODALIF_H

79
ports/alif/modmachine.c Normal file
View File

@@ -0,0 +1,79 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
// This file is never compiled standalone, it's included directly from
// extmod/modmachine.c via MICROPY_PY_MACHINE_INCLUDEFILE.
#define MICROPY_PY_MACHINE_EXTRA_GLOBALS \
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, \
static void mp_machine_idle(void) {
mp_event_wait_indefinite();
}
static mp_obj_t mp_machine_unique_id(void) {
return mp_obj_new_bytes((const uint8_t *)"ABCD", 4);
}
NORETURN static void mp_machine_reset(void) {
NVIC_SystemReset();
}
NORETURN void mp_machine_bootloader(size_t n_args, const mp_obj_t *args) {
__disable_irq();
MICROPY_BOARD_ENTER_BOOTLOADER(n_args, args);
while (1) {
;
}
}
static mp_int_t mp_machine_reset_cause(void) {
// TODO
return 0;
}
static mp_obj_t mp_machine_get_freq(void) {
return MP_OBJ_NEW_SMALL_INT(SystemCoreClock);
}
static void mp_machine_set_freq(size_t n_args, const mp_obj_t *args) {
mp_raise_NotImplementedError(NULL);
}
static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) {
mp_int_t delay = -1;
if (n_args == 1) {
delay = mp_obj_get_int(args[0]);
}
mp_hal_delay_ms(delay);
}
NORETURN static void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args) {
mp_machine_lightsleep(n_args, args);
mp_machine_reset();
}

View File

@@ -0,0 +1,23 @@
import sys, os, alif
bdev = alif.Flash()
if hasattr(alif, "usb_msc"):
try:
# This may fail on VfsFat construction, or mount.
os.mount(os.VfsFat(bdev), "/flash")
except:
os.VfsFat.mkfs(bdev)
os.mount(os.VfsFat(bdev), "/flash")
else:
try:
os.mount(os.VfsLfs2(bdev, progsize=256), "/flash")
except:
os.VfsLfs2.mkfs(bdev, progsize=256)
os.mount(os.VfsLfs2(bdev, progsize=256), "/flash")
sys.path.append("/flash")
sys.path.append("/flash/lib")
os.chdir("/flash")
del sys, os, alif, bdev

155
ports/alif/mpconfigport.h Normal file
View File

@@ -0,0 +1,155 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
// Options controlling how MicroPython is built, overriding defaults in py/mpconfig.h
#include <stdint.h>
#include <alloca.h> // for alloca()
// board specific definitions
#include "mpconfigboard.h"
#ifndef MICROPY_CONFIG_ROM_LEVEL
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES)
#endif
#define MICROPY_HW_ENABLE_UART_REPL (1) // useful if there is no USB
#define MICROPY_HW_ENABLE_USBDEV (1)
#ifndef MICROPY_HW_USB_PRODUCT_FS_STRING
#define MICROPY_HW_USB_PRODUCT_FS_STRING "Board in HS mode"
#endif
#define MICROPY_HW_USB_CDC (1)
#define MICROPY_HW_USB_CDC_TX_TIMEOUT (500)
#ifndef MICROPY_HW_USB_MSC
#define MICROPY_HW_USB_MSC (0)
#endif
#ifndef MICROPY_HW_USB_VID
#define MICROPY_HW_USB_VID (0xf055)
#endif
#ifndef MICROPY_HW_USB_PID
#define MICROPY_HW_USB_PID (0x9802) // interface has CDC only
#endif
#define MICROPY_HW_FLASH_BLOCK_SIZE_BYTES (4096)
// Memory allocation policies
#ifndef MICROPY_ALLOC_GC_STACK_SIZE
#define MICROPY_ALLOC_GC_STACK_SIZE (128)
#endif
#define MICROPY_ALLOC_PATH_MAX (128)
#define MICROPY_QSTR_BYTES_IN_HASH (1)
// MicroPython emitters
#define MICROPY_PERSISTENT_CODE_LOAD (1)
#define MICROPY_EMIT_THUMB (1)
#define MICROPY_EMIT_THUMB_ARMV7M (1)
#define MICROPY_EMIT_INLINE_THUMB (1)
#define MICROPY_EMIT_INLINE_THUMB_FLOAT (1)
// Optimisations
#define MICROPY_OPT_COMPUTED_GOTO (1)
// Python internal features
#define MICROPY_READER_VFS (1)
#define MICROPY_ENABLE_GC (1)
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#define MICROPY_SCHEDULER_DEPTH (8)
#define MICROPY_SCHEDULER_STATIC_NODES (1)
#define MICROPY_USE_INTERNAL_ERRNO (1)
// Fine control over Python builtins, classes, modules, etc
#define MICROPY_PY_SYS_PLATFORM "alif"
// Extended modules
#define MICROPY_EPOCH_IS_1970 (1)
#define MICROPY_PY_OS_DUPTERM (1)
#define MICROPY_PY_OS_SEP (1)
#define MICROPY_PY_OS_SYNC (1)
#define MICROPY_PY_OS_UNAME (1)
#define MICROPY_PY_TIME (1)
#define MICROPY_PY_MACHINE (1)
#define MICROPY_PY_MACHINE_INCLUDEFILE "ports/alif/modmachine.c"
#define MICROPY_PY_MACHINE_RESET (1)
#define MICROPY_PY_MACHINE_BOOTLOADER (1)
#define MICROPY_PY_MACHINE_BARE_METAL_FUNCS (1)
#define MICROPY_PY_MACHINE_DISABLE_IRQ_ENABLE_IRQ (1)
#define MICROPY_PY_MACHINE_DHT_READINTO (1)
#define MICROPY_PY_MACHINE_PULSE (1)
#define MICROPY_PY_MACHINE_SOFTI2C (1)
#define MICROPY_PY_MACHINE_SOFTSPI (1)
#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_VFS (1)
// fatfs configuration
#define MICROPY_FATFS_ENABLE_LFN (1)
#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
#define MICROPY_FATFS_RPATH (2)
#if MICROPY_HW_USB_MSC
#define MICROPY_FATFS_USE_LABEL (1)
#define MICROPY_FATFS_MULTI_PARTITION (1)
// Set FatFS block size to flash sector size to avoid caching
// the flash sector in memory to support smaller block sizes.
#define MICROPY_FATFS_MAX_SS (MICROPY_HW_FLASH_BLOCK_SIZE_BYTES)
#endif
#define MP_STATE_PORT MP_STATE_VM
// Miscellaneous settings
// We need an implementation of the log2 function which is not a macro
#define MP_NEED_LOG2 (1)
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p) | 1))
#define MP_SSIZE_MAX (0x7fffffff)
// Assume that if we already defined the obj repr then we also defined these items
#ifndef MICROPY_OBJ_REPR
typedef intptr_t mp_int_t; // must be pointer size
typedef uintptr_t mp_uint_t; // must be pointer size
typedef intptr_t mp_off_t;
#endif
// Board configuration settings.
#ifndef MICROPY_BOARD_STARTUP
#define MICROPY_BOARD_STARTUP()
#endif
#ifndef MICROPY_BOARD_EARLY_INIT
#define MICROPY_BOARD_EARLY_INIT()
#endif
#ifndef MICROPY_BOARD_FATAL_ERROR
extern void panic(const char *);
#define MICROPY_BOARD_FATAL_ERROR panic
#endif
#ifndef MICROPY_BOARD_ENTER_BOOTLOADER
#define MICROPY_BOARD_ENTER_BOOTLOADER(nargs, args)
#endif

View File

@@ -0,0 +1,12 @@
# Enable/disable extra modules and features
# MicroPython feature configurations
MICROPY_ROM_TEXT_COMPRESSION ?= 1
MICROPY_FLOAT_IMPL ?= double
# VFS support.
MICROPY_VFS_FAT ?= 1
MICROPY_VFS_LFS2 ?= 1
# File containing description of content to be frozen into firmware.
FROZEN_MANIFEST ?= boards/manifest.py

152
ports/alif/mphalport.c Normal file
View File

@@ -0,0 +1,152 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2023 Damien P. George
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/mphal.h"
#include "py/ringbuf.h"
#include "py/runtime.h"
#include "py/stream.h"
#include "extmod/misc.h"
#include "shared/runtime/interrupt_char.h"
#include "shared/timeutils/timeutils.h"
#include "shared/tinyusb/mp_usbd.h"
#include "shared/tinyusb/mp_usbd_cdc.h"
#include "tusb.h"
#include "mpuart.h"
#ifndef MICROPY_HW_STDIN_BUFFER_LEN
#define MICROPY_HW_STDIN_BUFFER_LEN 512
#endif
static uint8_t stdin_ringbuf_array[MICROPY_HW_STDIN_BUFFER_LEN];
ringbuf_t stdin_ringbuf = { stdin_ringbuf_array, sizeof(stdin_ringbuf_array) };
uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
uintptr_t ret = 0;
#if MICROPY_HW_USB_CDC
ret |= mp_usbd_cdc_poll_interfaces(poll_flags);
#endif
#if MICROPY_HW_ENABLE_UART_REPL
if (poll_flags & MP_STREAM_POLL_WR) {
ret |= MP_STREAM_POLL_WR;
}
#endif
#if MICROPY_PY_OS_DUPTERM
ret |= mp_os_dupterm_poll(poll_flags);
#endif
return ret;
}
// Receive single character
int mp_hal_stdin_rx_chr(void) {
for (;;) {
#if MICROPY_HW_USB_CDC
mp_usbd_cdc_poll_interfaces(0);
#endif
int c = ringbuf_get(&stdin_ringbuf);
if (c != -1) {
return c;
}
#if MICROPY_PY_OS_DUPTERM
int dupterm_c = mp_os_dupterm_rx_chr();
if (dupterm_c >= 0) {
return dupterm_c;
}
#endif
mp_event_wait_indefinite();
}
}
// Send string of given length
mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) {
mp_uint_t ret = len;
bool did_write = false;
#if MICROPY_HW_ENABLE_UART_REPL
mp_uart_write_strn(str, len);
did_write = true;
#endif
#if MICROPY_HW_USB_CDC
mp_uint_t cdc_res = mp_usbd_cdc_tx_strn(str, len);
if (cdc_res > 0) {
did_write = true;
ret = MIN(cdc_res, ret);
}
#endif
#if MICROPY_PY_OS_DUPTERM
int dupterm_res = mp_os_dupterm_tx_strn(str, len);
if (dupterm_res >= 0) {
did_write = true;
ret = MIN((mp_uint_t)dupterm_res, ret);
}
#endif
return did_write ? ret : 0;
}
static uint32_t volatile ticks_ms;
void SysTick_Handler(void) {
++ticks_ms;
}
mp_uint_t mp_hal_ticks_cpu(void) {
if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) {
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
#if defined(__CORTEX_M) && __CORTEX_M == 7
// on Cortex-M7 we must unlock the DWT before writing to its registers
DWT->LAR = 0xc5acce55;
#endif
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
return DWT->CYCCNT;
}
mp_uint_t mp_hal_ticks_us(void) {
return ticks_ms / 1000;
}
mp_uint_t mp_hal_ticks_ms(void) {
return ticks_ms;
}
void mp_hal_delay_us(mp_uint_t us) {
mp_hal_delay_ms(us / 1000);
}
void mp_hal_delay_ms(mp_uint_t ms) {
uint32_t t0 = mp_hal_ticks_ms();
while ((mp_hal_ticks_ms() - t0) < ms) {
__WFI();
}
}
uint64_t mp_hal_time_ns(void) {
return 0;
}

152
ports/alif/mphalport.h Normal file
View File

@@ -0,0 +1,152 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/ringbuf.h"
#include "shared/runtime/interrupt_char.h"
#include "irq.h"
#include ALIF_CMSIS_H
#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq()
#define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state)
// For regular code that wants to prevent "background tasks" from running.
// These background tasks (LWIP, Bluetooth) run in PENDSV context.
#define MICROPY_PY_PENDSV_ENTER uint32_t atomic_state = raise_irq_pri(IRQ_PRI_PENDSV);
#define MICROPY_PY_PENDSV_REENTER atomic_state = raise_irq_pri(IRQ_PRI_PENDSV);
#define MICROPY_PY_PENDSV_EXIT restore_irq_pri(atomic_state);
// Port level Wait-for-Event macro
//
// Do not use this macro directly, include py/runtime.h and
// call mp_event_wait_indefinite() or mp_event_wait_ms(timeout)
#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) \
do { \
if ((TIMEOUT_MS) < 0) { \
__WFE(); \
} else { \
/* TODO */ \
__WFE(); \
} \
} while (0)
// TODO requires mods to py/emitglue.c for this to be picked up
#define MP_HAL_CLEAN_DCACHE(addr, size) \
(SCB_CleanDCache_by_Addr((uint32_t *)((uint32_t)addr & ~0x1f), \
((uint32_t)((uint8_t *)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f)))
extern ringbuf_t stdin_ringbuf;
// TODO
#define mp_hal_quiet_timing_enter() 0
#define mp_hal_quiet_timing_exit(x) (void)x
#define mp_hal_delay_us_fast mp_hal_delay_us
/******************************************************************************/
// C-level pin HAL
#include "py/obj.h"
#include "gpio.h"
#include "pinconf.h"
#define MP_HAL_PIN_FMT "%q"
#define MP_HAL_PIN_MODE_INPUT (0)
#define MP_HAL_PIN_MODE_OUTPUT (1)
#define MP_HAL_PIN_MODE_OPEN_DRAIN (2)
#define MP_HAL_PIN_PULL_NONE (0)
#define MP_HAL_PIN_PULL_UP (1)
#define MP_HAL_PIN_PULL_DOWN (2)
#define mp_hal_pin_obj_t const machine_pin_obj_t *
typedef struct _machine_pin_obj_t {
mp_obj_base_t base;
GPIO_Type *gpio;
uint8_t port;
uint8_t pin;
qstr name;
} machine_pin_obj_t;
mp_hal_pin_obj_t mp_hal_get_pin_obj(mp_obj_t pin_in);
static inline qstr mp_hal_pin_name(mp_hal_pin_obj_t pin) {
return pin->name;
}
static inline void mp_hal_pin_input(mp_hal_pin_obj_t pin) {
uint8_t alt_func = PINMUX_ALTERNATE_FUNCTION_0;
uint8_t pad_ctrl = PADCTRL_READ_ENABLE;
pinconf_set(pin->port, pin->pin, alt_func, pad_ctrl);
gpio_set_direction_input(pin->gpio, pin->pin);
}
static inline void mp_hal_pin_output(mp_hal_pin_obj_t pin) {
uint8_t alt_func = PINMUX_ALTERNATE_FUNCTION_0;
uint8_t pad_ctrl = PADCTRL_READ_ENABLE;
pinconf_set(pin->port, pin->pin, alt_func, pad_ctrl);
gpio_set_direction_output(pin->gpio, pin->pin);
}
static inline void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin) {
uint8_t alt_func = PINMUX_ALTERNATE_FUNCTION_0;
uint8_t pad_ctrl = PADCTRL_DRIVER_OPEN_DRAIN | PADCTRL_READ_ENABLE;
pinconf_set(pin->port, pin->pin, alt_func, pad_ctrl);
gpio_set_direction_output(pin->gpio, pin->pin);
}
static inline void mp_hal_pin_low(mp_hal_pin_obj_t pin) {
gpio_set_value_low(pin->gpio, pin->pin);
}
static inline void mp_hal_pin_high(mp_hal_pin_obj_t pin) {
gpio_set_value_high(pin->gpio, pin->pin);
}
static inline int mp_hal_pin_read(mp_hal_pin_obj_t pin) {
return gpio_get_value(pin->gpio, pin->pin);
}
static inline void mp_hal_pin_write(mp_hal_pin_obj_t pin, int v) {
if (v) {
mp_hal_pin_high(pin);
} else {
mp_hal_pin_low(pin);
}
}
static inline void mp_hal_pin_od_low(mp_hal_pin_obj_t pin) {
mp_hal_pin_low(pin);
}
static inline void mp_hal_pin_od_high(mp_hal_pin_obj_t pin) {
mp_hal_pin_high(pin);
}
static inline void mp_hal_wake_main_task_from_isr(void) {
// Defined for tinyusb support, nothing needs to be done here.
}
// Include all the pin definitions.
#include "genhdr/pins_board.h"

113
ports/alif/mpuart.c Normal file
View File

@@ -0,0 +1,113 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <string.h>
#include "py/runtime.h"
#include "py/mphal.h"
#include "mpuart.h"
#if MICROPY_HW_ENABLE_UART_REPL
#include "pinconf.h"
#include "sys_ctrl_uart.h"
#include "uart.h"
#define TX_PORT PORT_12
#define TX_PIN PIN_2
#define RX_PORT PORT_12
#define RX_PIN PIN_1
#define UART_ID 4
#define UART_IRQN UART4_IRQ_IRQn
#define UART_PTR ((UART_Type *)UART4_BASE)
#define BAUDRATE 115200
#define SYST_PCLK 100000000
static UART_TRANSFER transfer;
void mp_uart_init(void) {
pinconf_set(TX_PORT, TX_PIN, PINMUX_ALTERNATE_FUNCTION_2, 0);
pinconf_set(RX_PORT, RX_PIN, PINMUX_ALTERNATE_FUNCTION_2, PADCTRL_READ_ENABLE);
select_uart_clock_syst_pclk(UART_ID);
enable_uart_clock(UART_ID);
uart_software_reset(UART_PTR);
uart_enable_fifo(UART_PTR);
uart_disable_tx_irq(UART_PTR);
uart_disable_rx_irq(UART_PTR);
uart_set_baudrate(UART_PTR, SYST_PCLK, BAUDRATE);
uart_set_data_parity_stop_bits(UART_PTR, UART_DATA_BITS_8, UART_PARITY_NONE, UART_STOP_BITS_1);
uart_set_flow_control(UART_PTR, UART_FLOW_CONTROL_NONE);
NVIC_ClearPendingIRQ(UART_IRQN);
NVIC_SetPriority(UART_IRQN, IRQ_PRI_UART_REPL);
NVIC_EnableIRQ(UART_IRQN);
uart_set_tx_trigger(UART_PTR, UART_TX_FIFO_EMPTY);
uart_set_rx_trigger(UART_PTR, UART_RX_ONE_CHAR_IN_FIFO);
uart_enable_rx_irq(UART_PTR);
}
void mp_uart_write_strn(const char *str, size_t len) {
memset(&transfer, 0, sizeof(transfer));
transfer.tx_buf = (uint8_t *)str;
transfer.tx_total_num = len;
transfer.tx_curr_cnt = 0U;
transfer.status = UART_TRANSFER_STATUS_NONE;
uart_enable_tx_irq(UART_PTR);
uint32_t start = mp_hal_ticks_ms();
while (transfer.status == UART_TRANSFER_STATUS_NONE) {
if (mp_hal_ticks_ms() - start > 10 * len) {
break;
}
__WFE();
}
uart_disable_tx_irq(UART_PTR);
}
void UART4_IRQHandler(void) {
if (UART_PTR->UART_RFL) {
for (;;) {
uint32_t rx_fifo_available_cnt = UART_PTR->UART_RFL;
if (rx_fifo_available_cnt == 0) {
break;
}
for (uint32_t i = 0; i < rx_fifo_available_cnt; ++i) {
int c = UART_PTR->UART_RBR;
#if MICROPY_KBD_EXCEPTION
if (c == mp_interrupt_char) {
mp_sched_keyboard_interrupt();
continue;
}
#endif
ringbuf_put(&stdin_ringbuf, c);
}
}
} else {
uart_irq_handler(UART_PTR, &transfer);
}
__SEV();
}
#endif

32
ports/alif/mpuart.h Normal file
View File

@@ -0,0 +1,32 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_ALIF2_UART_H
#define MICROPY_INCLUDED_ALIF2_UART_H
void mp_uart_init(void);
void mp_uart_write_strn(const char *str, size_t len);
#endif // MICROPY_INCLUDED_ALIF2_UART_H

151
ports/alif/msc_disk.c Normal file
View File

@@ -0,0 +1,151 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020-2021 Damien P. George
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/mpconfig.h"
#include "py/misc.h"
#include "ospi_flash.h"
#include "tusb.h"
#if CFG_TUD_MSC
#if MICROPY_FATFS_MAX_SS != MICROPY_HW_FLASH_BLOCK_SIZE_BYTES
#error MICROPY_FATFS_MAX_SS must be the same size as MICROPY_HW_FLASH_BLOCK_SIZE_BYTES
#endif
#define BLOCK_SIZE (MICROPY_HW_FLASH_BLOCK_SIZE_BYTES)
#define BLOCK_COUNT (MICROPY_HW_FLASH_STORAGE_BYTES / BLOCK_SIZE)
#define FLASH_BASE_ADDR (MICROPY_HW_FLASH_STORAGE_BASE_ADDR)
static bool ejected = false;
// Invoked on SCSI_CMD_INQUIRY.
// Fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively.
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
memcpy(vendor_id, MICROPY_HW_USB_MSC_INQUIRY_VENDOR_STRING, MIN(strlen(MICROPY_HW_USB_MSC_INQUIRY_VENDOR_STRING), 8));
memcpy(product_id, MICROPY_HW_USB_MSC_INQUIRY_PRODUCT_STRING, MIN(strlen(MICROPY_HW_USB_MSC_INQUIRY_PRODUCT_STRING), 16));
memcpy(product_rev, MICROPY_HW_USB_MSC_INQUIRY_REVISION_STRING, MIN(strlen(MICROPY_HW_USB_MSC_INQUIRY_REVISION_STRING), 4));
}
// Invoked on Test-Unit-Ready command.
// Return true allowing host to read/write this LUN (e.g SD card inserted).
bool tud_msc_test_unit_ready_cb(uint8_t lun) {
if (ejected) {
tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00);
return false;
}
return true;
}
// Invoked on SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size.
void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_size) {
*block_size = BLOCK_SIZE;
*block_count = BLOCK_COUNT;
}
// Invoked on Start-Stop-Unit command:
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) {
if (load_eject) {
if (start) {
// load disk storage
ejected = false;
} else {
// unload disk storage
ejected = true;
}
}
return true;
}
// Callback invoked on READ10 command.
// Copy disk's data to buffer (up to bufsize) and return number of read bytes.
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) {
uint32_t addr = FLASH_BASE_ADDR + lba * BLOCK_SIZE;
uint32_t block_count = bufsize / BLOCK_SIZE;
int ret = ospi_flash_read(addr, block_count * BLOCK_SIZE, buffer);
if (ret < 0) {
return ret;
}
return block_count * BLOCK_SIZE;
}
// Callback invoked on WRITE10 command.
// Process data in buffer to disk's storage and return number of written bytes.
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) {
if (bufsize < BLOCK_SIZE) {
// Workaround for issue with TinyUSB passing in a small buffer.
uint32_t addr = FLASH_BASE_ADDR + lba * BLOCK_SIZE + offset;
if (offset == 0) {
int ret = ospi_flash_erase_sector(addr);
if (ret < 0) {
return ret;
}
}
int ret = ospi_flash_write(addr, bufsize, buffer);
if (ret < 0) {
return ret;
}
return bufsize;
}
uint32_t addr = FLASH_BASE_ADDR + lba * BLOCK_SIZE;
uint32_t block_count = bufsize / BLOCK_SIZE;
for (uint32_t block = 0; block < block_count; ++block) {
int ret = ospi_flash_erase_sector(addr);
if (ret < 0) {
return ret;
}
ret = ospi_flash_write(addr, BLOCK_SIZE, buffer);
if (ret < 0) {
return ret;
}
addr += BLOCK_SIZE;
buffer += BLOCK_SIZE;
}
return block_count * BLOCK_SIZE;
}
// Callback invoked on a SCSI command that's not handled by TinyUSB.
int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer, uint16_t bufsize) {
int32_t resplen = 0;
switch (scsi_cmd[0]) {
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
// Sync the logical unit if needed.
break;
default:
// Set Sense = Invalid Command Operation
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
// negative means error -> tinyusb could stall and/or response with failed status
resplen = -1;
break;
}
return resplen;
}
#endif

265
ports/alif/ospi_flash.c Normal file
View File

@@ -0,0 +1,265 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/mperrno.h"
#include "py/mphal.h"
#include "ospi_flash.h"
#include "ospi_drv.h"
#include "pinconf.h"
#define CMD_RDSR (0x05)
#define CMD_WREN (0x06)
#define CMD_SEC_ERASE_32ADDR (0x21) // 4kiB sector erase with 32-bit address
#define CMD_WRVOL (0x81)
#define CMD_RD_DEVID (0x9f)
#define WAIT_SR_TIMEOUT (1000000)
// maximum bytes we can write in one SPI transfer
// limited by 256 byte FIFO buffer (can't go up to 256)
// need to use DMA to make this 256
#define PAGE_SIZE (128)
#define ISSI_MODE_OCTAL_DDR_DQS (0xe7)
// All OSPI1 pins use the same alternate function.
#define OSPI1_PIN_FUNCTION PINMUX_ALTERNATE_FUNCTION_1
typedef struct _mp_spiflash_t {
ospi_flash_cfg_t cfg;
} mp_spiflash_t;
static mp_spiflash_t global_flash;
// Alif version of this function can overwrite the destination buffer.
static void ospi_recv_blocking2(ospi_flash_cfg_t *ospi_cfg, uint32_t command, uint8_t *buffer) {
uint32_t val;
ospi_writel(ospi_cfg, data_reg, command);
ospi_writel(ospi_cfg, ser, ospi_cfg->ser);
ospi_cfg->rx_cnt = 0;
while (ospi_cfg->rx_cnt < ospi_cfg->rx_req) {
unsigned int timeout = 100000;
while (ospi_readl(ospi_cfg, rxflr) == 0) {
if (--timeout == 0) {
return;
}
}
val = ospi_readl(ospi_cfg, data_reg);
*buffer++ = (uint8_t)val;
ospi_cfg->rx_cnt++;
}
}
static int mp_spiflash_read_cmd(mp_spiflash_t *self, uint8_t cmd, size_t len, uint8_t *dest) {
ospi_setup_read(&self->cfg, 0, len, 8);
ospi_recv_blocking2(&self->cfg, cmd, dest);
return 0;
}
static int mp_spiflash_write_cmd(mp_spiflash_t *self, uint8_t cmd) {
ospi_setup_write(&self->cfg, 0);
ospi_send_blocking(&self->cfg, cmd);
return 0;
}
static int mp_spiflash_wait_sr(mp_spiflash_t *self, uint8_t mask, uint8_t val, uint32_t timeout) {
do {
uint8_t sr;
int ret = mp_spiflash_read_cmd(self, CMD_RDSR, 1, &sr);
if (ret != 0) {
return ret;
}
if ((sr & mask) == val) {
return 0; // success
}
} while (timeout--);
return -MP_ETIMEDOUT;
}
static int mp_spiflash_wait_wel1(mp_spiflash_t *self) {
return mp_spiflash_wait_sr(self, 2, 2, WAIT_SR_TIMEOUT);
}
static int mp_spiflash_wait_wip0(mp_spiflash_t *self) {
return mp_spiflash_wait_sr(self, 1, 0, WAIT_SR_TIMEOUT);
}
static uint32_t ospi_flash_read_id(mp_spiflash_t *self) {
uint8_t buf[8];
ospi_setup_read(&self->cfg, 0, 3, ospi_flash_settings.read_id_dummy_cycles);
ospi_recv_blocking2(&self->cfg, CMD_RD_DEVID, buf);
return buf[0] | buf[1] << 8 | buf[2] << 16;
}
static void ospi_flash_write_reg_sdr(mp_spiflash_t *self, uint8_t cmd, uint8_t addr, uint8_t value) {
mp_spiflash_write_cmd(self, CMD_WREN);
ospi_setup_write_sdr(&self->cfg, 6);
ospi_push(&self->cfg, cmd);
ospi_push(&self->cfg, 0x00);
ospi_push(&self->cfg, 0x00);
ospi_push(&self->cfg, addr);
ospi_send_blocking(&self->cfg, value);
}
int ospi_flash_init(void) {
mp_spiflash_t *self = &global_flash;
uint32_t pad_ctrl = PADCTRL_OUTPUT_DRIVE_STRENGTH_12MA | PADCTRL_SLEW_RATE_FAST | PADCTRL_READ_ENABLE;
pinconf_set(pin_OSPI1_CS->port, pin_OSPI1_CS->pin, OSPI1_PIN_FUNCTION, PADCTRL_OUTPUT_DRIVE_STRENGTH_12MA);
pinconf_set(pin_OSPI1_SCLK->port, pin_OSPI1_SCLK->pin, OSPI1_PIN_FUNCTION, PADCTRL_OUTPUT_DRIVE_STRENGTH_12MA | PADCTRL_SLEW_RATE_FAST);
pinconf_set(pin_OSPI1_D0->port, pin_OSPI1_D0->pin, OSPI1_PIN_FUNCTION, pad_ctrl);
pinconf_set(pin_OSPI1_D1->port, pin_OSPI1_D1->pin, OSPI1_PIN_FUNCTION, pad_ctrl);
pinconf_set(pin_OSPI1_D2->port, pin_OSPI1_D2->pin, OSPI1_PIN_FUNCTION, pad_ctrl);
pinconf_set(pin_OSPI1_D3->port, pin_OSPI1_D3->pin, OSPI1_PIN_FUNCTION, pad_ctrl);
#if defined(pin_OSPI1_D4)
pinconf_set(pin_OSPI1_D4->port, pin_OSPI1_D4->pin, OSPI1_PIN_FUNCTION, pad_ctrl);
pinconf_set(pin_OSPI1_D5->port, pin_OSPI1_D5->pin, OSPI1_PIN_FUNCTION, pad_ctrl);
pinconf_set(pin_OSPI1_D6->port, pin_OSPI1_D6->pin, OSPI1_PIN_FUNCTION, pad_ctrl);
pinconf_set(pin_OSPI1_D7->port, pin_OSPI1_D7->pin, OSPI1_PIN_FUNCTION, pad_ctrl);
#endif
#if defined(pin_OSPI1_RXDS)
pinconf_set(pin_OSPI1_RXDS->port, pin_OSPI1_RXDS->pin, OSPI1_PIN_FUNCTION, pad_ctrl);
#endif
#if defined(pin_OSPI1_RXDS)
if (pin_OSPI1_RXDS->port == PORT_10 && pin_OSPI1_RXDS->pin == PIN_7) {
// Alif: P5_6 is needed to support proper alt function selection of P10_7.
pinconf_set(PORT_5, PIN_6, OSPI1_PIN_FUNCTION, pad_ctrl);
}
#endif
// Reset the SPI flash.
mp_hal_pin_output(pin_OSPI1_RESET);
mp_hal_pin_low(pin_OSPI1_RESET);
mp_hal_delay_us(30);
mp_hal_pin_high(pin_OSPI1_RESET);
// Configure the OSPI peripheral.
self->cfg.regs = (ssi_regs_t *)OSPI1_BASE;
self->cfg.aes_regs = (aes_regs_t *)AES1_BASE;
self->cfg.xip_base = (volatile void *)OSPI1_XIP_BASE;
self->cfg.ser = 1;
self->cfg.addrlen = 8; // 32-bit address length
self->cfg.ospi_clock = ospi_flash_settings.freq_mhz;
self->cfg.ddr_en = 0;
self->cfg.wait_cycles = 0; // used only for ospi_xip_exit
ospi_init(&self->cfg);
if (ospi_flash_settings.is_oct && ospi_flash_settings.is_ddr) {
// Switch SPI flash to Octal DDR mode.
ospi_flash_write_reg_sdr(self, CMD_WRVOL, 0x00, ISSI_MODE_OCTAL_DDR_DQS);
self->cfg.ddr_en = 1;
}
// Check the device ID.
if (ospi_flash_read_id(self) != ospi_flash_settings.jedec_id) {
return -1;
}
return 0;
}
int ospi_flash_erase_sector(uint32_t addr) {
mp_spiflash_t *self = &global_flash;
mp_spiflash_write_cmd(self, CMD_WREN);
int ret = mp_spiflash_wait_wel1(self);
if (ret < 0) {
return ret;
}
ospi_setup_write(&self->cfg, 8 /* 32-bit addr len*/);
ospi_push(&self->cfg, CMD_SEC_ERASE_32ADDR);
ospi_send_blocking(&self->cfg, addr);
return mp_spiflash_wait_wip0(self);
}
int ospi_flash_read(uint32_t addr, uint32_t len, uint8_t *dest) {
// OSPI FIFO is limited to 256 bytes. Need DMA to get a longer read.
mp_spiflash_t *self = &global_flash;
while (len) {
uint32_t l = len;
if (l > 256) {
l = 256;
}
ospi_setup_read(&self->cfg, 8 /* 32-bit addr len*/, l, ospi_flash_settings.read_dummy_cycles);
ospi_push(&self->cfg, ospi_flash_settings.read_command);
ospi_recv_blocking2(&self->cfg, addr, dest);
addr += l;
len -= l;
dest += l;
}
return 0;
}
static int ospi_flash_write_page(uint32_t addr, uint32_t len, const uint8_t *src) {
mp_spiflash_t *self = &global_flash;
mp_spiflash_write_cmd(self, CMD_WREN);
int ret = mp_spiflash_wait_wel1(self);
if (ret < 0) {
return ret;
}
ospi_setup_write(&self->cfg, 8 /* 32-bit addr len*/);
ospi_push(&self->cfg, ospi_flash_settings.write_command);
ospi_push(&self->cfg, addr);
while (--len) {
ospi_push(&self->cfg, *src++);
}
ospi_send_blocking(&self->cfg, *src);
return mp_spiflash_wait_wip0(self);
}
int ospi_flash_write(uint32_t addr, uint32_t len, const uint8_t *src) {
int ret = 0;
uint32_t offset = addr & (PAGE_SIZE - 1);
while (len) {
size_t rest = PAGE_SIZE - offset;
if (rest > len) {
rest = len;
}
ret = ospi_flash_write_page(addr, rest, src);
if (ret != 0) {
break;
}
len -= rest;
addr += rest;
src += rest;
offset = 0;
}
return ret;
}

52
ports/alif/ospi_flash.h Normal file
View File

@@ -0,0 +1,52 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_ALIF_OSPI_FLASH_H
#define MICROPY_INCLUDED_ALIF_OSPI_FLASH_H
#include <stdbool.h>
#include <stdint.h>
typedef struct _ospi_flash_settings_t {
uint32_t jedec_id;
uint32_t freq_mhz;
bool is_quad : 1;
bool is_oct : 1;
bool is_ddr : 1;
uint8_t read_id_dummy_cycles;
uint8_t read_dummy_cycles;
uint8_t read_command;
uint8_t write_command;
} ospi_flash_settings_t;
// Provided by the board when it enables OSPI1.
extern const ospi_flash_settings_t ospi_flash_settings;
int ospi_flash_init(void);
int ospi_flash_erase_sector(uint32_t addr);
int ospi_flash_read(uint32_t addr, uint32_t len, uint8_t *dest);
int ospi_flash_write(uint32_t addr, uint32_t len, const uint8_t *src);
#endif // MICROPY_INCLUDED_ALIF_OSPI_FLASH_H

View File

@@ -0,0 +1,5 @@
// This file is needed by ospi_xip/source/ospi/ospi_drv.c.
#define OSPI_XIP_ENABLE_AES_DECRYPTION (0)
#define OSPI_XIP_RX_SAMPLE_DELAY (4)
#define OSPI_XIP_DDR_DRIVE_EDGE (1)
#define OSPI_XIP_RXDS_DELAY (12)

49
ports/alif/pendsv.c Normal file
View File

@@ -0,0 +1,49 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "pendsv.h"
#include "irq.h"
static pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS];
void pendsv_init(void) {
NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV);
}
void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) {
pendsv_dispatch_table[slot] = f;
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
}
void PendSV_Handler(void) {
for (size_t i = 0; i < PENDSV_DISPATCH_NUM_SLOTS; ++i) {
if (pendsv_dispatch_table[i] != NULL) {
pendsv_dispatch_t f = pendsv_dispatch_table[i];
pendsv_dispatch_table[i] = NULL;
f();
}
}
}

48
ports/alif/pendsv.h Normal file
View File

@@ -0,0 +1,48 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_ALIF_PENDSV_H
#define MICROPY_INCLUDED_ALIF_PENDSV_H
#include "py/mpconfig.h"
#ifndef MICROPY_BOARD_PENDSV_ENTRIES
#define MICROPY_BOARD_PENDSV_ENTRIES
#endif
enum {
PENDSV_DISPATCH_SOFT_TIMER,
MICROPY_BOARD_PENDSV_ENTRIES
PENDSV_DISPATCH_MAX
};
#define PENDSV_DISPATCH_NUM_SLOTS PENDSV_DISPATCH_MAX
typedef void (*pendsv_dispatch_t)(void);
void pendsv_init(void);
void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f);
#endif // MICROPY_INCLUDED_ALIF_PENDSV_H

View File

@@ -0,0 +1,2 @@
// qstrs specific to this port
// *FORMAT-OFF*

View File

@@ -0,0 +1,73 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef _ALIF_TUSB_CONFIG_H_
#define _ALIF_TUSB_CONFIG_H_
// --------------------------------------------------------------------+
// Board Specific Configuration
// --------------------------------------------------------------------+
#define CFG_TUSB_MCU OPT_MCU_NONE
// #define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED)
#define TUP_DCD_ENDPOINT_MAX 8
#define TUD_OPT_RHPORT 0
// --------------------------------------------------------------------
// COMMON CONFIGURATION
// --------------------------------------------------------------------
#define CFG_TUSB_OS OPT_OS_NONE
#define CFG_TUSB_DEBUG 0
// Enable Device stack
#define CFG_TUD_ENABLED 1
// Default is max speed that hardware controller could support with on-chip PHY
#define CFG_TUD_MAX_SPEED OPT_MODE_HIGH_SPEED
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
* into those specific section.
*/
#define CFG_TUSB_MEM_SECTION __attribute__((section(".bss.sram0")))
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(32)))
// --------------------------------------------------------------------
// DEVICE CONFIGURATION
// --------------------------------------------------------------------
#define CFG_TUD_ENDPOINT0_SIZE 64
// CDC Endpoint transfer buffer size, more is faster
#define CFG_TUD_CDC_EP_BUFSIZE (4096)
#define CFG_TUD_CDC_RX_BUFSIZE (4096)
#define CFG_TUD_CDC_TX_BUFSIZE (4096)
#include "shared/tinyusb/tusb_config.h"
#endif /* _ALIF_TUSB_CONFIG_H_ */

41
ports/alif/usbd.c Normal file
View File

@@ -0,0 +1,41 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 OpenMV LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/mpconfig.h"
#if MICROPY_HW_ENABLE_USBDEV
#include "shared/tinyusb/mp_usbd.h"
#include "tusb.h"
void mp_usbd_port_get_serial_number(char *serial_buf) {
// TODO
uint8_t id[8] = "ABCDEFGH";
MP_STATIC_ASSERT(sizeof(id) * 2 <= MICROPY_HW_USB_DESC_STR_MAX);
mp_usbd_hex_str(serial_buf, id, sizeof(id));
}
#endif