hal: Add GPIO abstraction layer.

This commit is contained in:
iabdalkader 2023-06-06 21:45:37 +02:00
parent 93e5cead46
commit 13bc0fa66d
11 changed files with 443 additions and 4 deletions

@ -1 +1 @@
Subproject commit 84260c659ca1dfda9b94e5821b57dfdc005d9154
Subproject commit ad78d24e47cb1d0f7940c039d873f832bbcf7c0f

30
src/omv/common/omv_gpio.h Normal file
View File

@ -0,0 +1,30 @@
/*
* 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 abstraction layer.
*/
#ifndef __OMV_GPIO_H__
#define __OMV_GPIO_H__
#include <stdint.h>
#include <stdbool.h>
#include "omv_portconfig.h"
// Config options are defined in ports so they can be used
// directly to initialize peripherals without remapping them.
typedef void (*omv_gpio_callback_t)(omv_gpio_t pin, void *data);
void omv_gpio_init0(void);
void omv_gpio_config(omv_gpio_t pin, uint32_t mode, uint32_t pull, uint32_t speed, uint32_t af);
void omv_gpio_deinit(omv_gpio_t pin);
bool omv_gpio_read(omv_gpio_t pin);
void omv_gpio_write(omv_gpio_t pin, bool value);
void omv_gpio_irq_register(omv_gpio_t pin, omv_gpio_callback_t callback, void *data);
void omv_gpio_irq_enable(omv_gpio_t pin, bool enable);
void omv_gpio_clock_enable(omv_gpio_t pin, bool enable);
#endif // __OMV_GPIO_H__

View File

@ -0,0 +1,41 @@
/*
* 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 nrf.
*/
#include <stdint.h>
#include <stdbool.h>
#include "py/mphal.h"
#include "hal/nrf_gpio.h"
#include "omv_boardconfig.h"
#include "omv_gpio.h"
void omv_gpio_config(omv_gpio_t pin, uint32_t mode, uint32_t pull, uint32_t speed, uint32_t af)
{
(void) af; // Unsupported.
uint32_t input = (mode == OMV_GPIO_MODE_INPUT) ?
NRF_GPIO_PIN_INPUT_CONNECT : NRF_GPIO_PIN_INPUT_DISCONNECT;
nrf_gpio_cfg(pin, mode, input, pull, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE);
}
void omv_gpio_deinit(omv_gpio_t pin)
{
nrf_gpio_cfg_default(pin);
}
bool omv_gpio_read(omv_gpio_t pin)
{
return nrf_gpio_pin_read(pin);
}
void omv_gpio_write(omv_gpio_t pin, bool value)
{
nrf_gpio_pin_write(pin, value);
}

View File

@ -13,6 +13,19 @@
#include "nrfx_twi.h"
// GPIO speeds.
#define OMV_GPIO_SPEED_LOW 0
#define OMV_GPIO_SPEED_HIGH 0
// GPIO pull.
#define OMV_GPIO_PULL_NONE NRF_GPIO_PIN_NOPULL
#define OMV_GPIO_PULL_UP NRF_GPIO_PIN_PULLUP
#define OMV_GPIO_PULL_DOWN NRF_GPIO_PIN_PULLDOWN
// GPIO modes.
#define OMV_GPIO_MODE_INPUT NRF_GPIO_PIN_DIR_INPUT
#define OMV_GPIO_MODE_OUTPUT NRF_GPIO_PIN_DIR_OUTPUT
// omv_gpio_t definition
typedef uint32_t omv_gpio_t;

View File

@ -0,0 +1,51 @@
/*
* 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 rp2.
*/
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "py/mphal.h"
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "omv_boardconfig.h"
#include "omv_gpio.h"
void omv_gpio_config(omv_gpio_t pin, uint32_t mode, uint32_t pull, uint32_t speed, uint32_t af)
{
if (mode == OMV_GPIO_MODE_ALT) {
gpio_set_function(pin, af);
} else {
gpio_init(pin);
gpio_set_dir(pin, mode);
}
if (pull == OMV_GPIO_PULL_UP) {
gpio_pull_up(pin);
} else if (pull == OMV_GPIO_PULL_DOWN) {
gpio_pull_down(pin);
}
gpio_set_slew_rate(pin, speed);
}
void omv_gpio_deinit(omv_gpio_t pin)
{
gpio_deinit(pin);
}
bool omv_gpio_read(omv_gpio_t pin)
{
return gpio_get(pin);
}
void omv_gpio_write(omv_gpio_t pin, bool value)
{
gpio_put(pin, value);
}

View File

@ -174,6 +174,7 @@ target_sources(${MICROPY_TARGET} PRIVATE
${TOP_DIR}/${OMV_DIR}/ports/${PORT}/main.c
${TOP_DIR}/${OMV_DIR}/ports/${PORT}/cambus.c
${TOP_DIR}/${OMV_DIR}/ports/${PORT}/sensor.c
${TOP_DIR}/${OMV_DIR}/ports/${PORT}/omv_gpio.c
${OMV_USER_MODULES}
)

View File

@ -14,6 +14,20 @@
#include "pico/stdlib.h"
#include "hardware/i2c.h"
// GPIO speeds.
#define OMV_GPIO_SPEED_LOW GPIO_SLEW_RATE_SLOW
#define OMV_GPIO_SPEED_HIGH GPIO_SLEW_RATE_FAST
// GPIO pull.
#define OMV_GPIO_PULL_NONE 0
#define OMV_GPIO_PULL_UP 1
#define OMV_GPIO_PULL_DOWN 2
// GPIO modes.
#define OMV_GPIO_MODE_INPUT GPIO_IN
#define OMV_GPIO_MODE_OUTPUT GPIO_OUT
#define OMV_GPIO_MODE_ALT 3
// omv_gpio_t definition
typedef uint32_t omv_gpio_t;

View File

@ -79,6 +79,7 @@
#include "ini.h"
#include "omv_boardconfig.h"
#include "omv_gpio.h"
#if MICROPY_PY_LWIP
#include "lwip/init.h"
@ -385,6 +386,7 @@ soft_reset:
spi_init0();
uart_init0();
fb_alloc_init0();
omv_gpio_init0();
framebuffer_init0();
sensor_init0();
dma_alloc_init0();

View File

@ -0,0 +1,243 @@
/*
* 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 stm32.
*/
#include STM32_HAL_H
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "py/mphal.h"
#include "irq.h"
#include "omv_boardconfig.h"
#include "omv_gpio.h"
typedef struct _omv_exti_descr {
bool enabled;
uint32_t gpio;
uint32_t irqn;
omv_gpio_t pin;
void *data;
omv_gpio_callback_t callback;
} omv_exti_descr_t;
static omv_exti_descr_t exti_descr_table[16] = {{0}};
// Returns the port number configured in EXTI_CR for this line.
static uint32_t omv_exti_get_gpio(uint32_t line)
{
return (SYSCFG->EXTICR[line >> 2] >> (4 * (line & 3))) & 0x0F;
}
// Returns pin number.
static uint32_t omv_exti_get_line(omv_gpio_t pin)
{
return 31 - __CLZ(pin->pin);
}
// Returns the IRQ number of a an EXTI line.
static uint32_t omv_exti_get_irqn(omv_gpio_t pin)
{
uint32_t exti_irqn = 0;
uint32_t exti_line = omv_exti_get_line(pin);
switch (exti_line) {
case 0:
exti_irqn = EXTI0_IRQn;
break;
case 1:
exti_irqn = EXTI1_IRQn;
break;
case 2:
exti_irqn = EXTI2_IRQn;
break;
case 3:
exti_irqn = EXTI3_IRQn;
break;
case 4:
exti_irqn = EXTI4_IRQn;
break;
case 5 ... 9:
exti_irqn = EXTI9_5_IRQn;
break;
case 10 ... 15:
exti_irqn = EXTI15_10_IRQn;
break;
default:
break;
}
return exti_irqn;
}
static inline bool omv_exti_enabled(omv_exti_descr_t *exti_descr, uint32_t line)
{
return (exti_descr->enabled &&
exti_descr->callback &&
exti_descr->gpio == omv_exti_get_gpio(line));
}
void omv_exti_handler(uint32_t line)
{
if (line < 5) {
// EXTI lines 0 to 4 have single IRQs.
omv_exti_descr_t *exti_descr = &exti_descr_table[line];
if (omv_exti_enabled(exti_descr, line)) {
__HAL_GPIO_EXTI_CLEAR_FLAG(1 << line);
exti_descr->callback(exti_descr->pin, exti_descr->data);
}
} else {
size_t line_max = (line == 5) ? 10 : 16;
// EXTI lines 5 to 9 and 10 to 15 are multiplexed.
for (size_t i = line; i < line_max; i++) {
omv_exti_descr_t *exti_descr = &exti_descr_table[i];
if (__HAL_GPIO_EXTI_GET_FLAG(1 << i)
&& omv_exti_enabled(exti_descr, i)) {
__HAL_GPIO_EXTI_CLEAR_FLAG(1 << i);
exti_descr->callback(exti_descr->pin, exti_descr->data);
}
}
}
}
void omv_gpio_init0(void)
{
memset(exti_descr_table, 0, sizeof(exti_descr_table));
}
void omv_gpio_config(omv_gpio_t pin, uint32_t mode, uint32_t pull, uint32_t speed, uint32_t af)
{
GPIO_InitTypeDef gpio_config = {
.Pin = pin->pin,
.Mode = mode,
.Pull = pull,
.Speed = speed,
.Alternate = ((af == -1) ? pin->af : af),
};
HAL_GPIO_Init(pin->port, &gpio_config);
}
void omv_gpio_deinit(omv_gpio_t pin)
{
HAL_GPIO_DeInit(pin->port, pin->pin);
}
bool omv_gpio_read(omv_gpio_t pin)
{
return HAL_GPIO_ReadPin(pin->port, pin->pin);
}
void omv_gpio_write(omv_gpio_t pin, bool value)
{
HAL_GPIO_WritePin(pin->port, pin->pin, value);
}
void omv_gpio_irq_register(omv_gpio_t pin, omv_gpio_callback_t callback, void *data)
{
omv_exti_descr_t *exti_descr = NULL;
uint32_t exti_line = omv_exti_get_line(pin);
if (exti_line != 0) {
exti_descr = &exti_descr_table[exti_line];
exti_descr->enabled = true;
exti_descr->data = data;
exti_descr->gpio = omv_exti_get_gpio(exti_line);
exti_descr->pin = pin;
exti_descr->callback = callback;
}
}
void omv_gpio_irq_enable(omv_gpio_t pin, bool enable)
{
uint32_t exti_line = omv_exti_get_line(pin);
uint32_t exti_irqn = omv_exti_get_irqn(pin);
exti_descr_table[exti_line].enabled = enable;
if (!enable) {
HAL_NVIC_DisableIRQ(exti_irqn);
} else {
NVIC_SetPriority(exti_irqn, IRQ_PRI_EXTINT);
HAL_NVIC_EnableIRQ(exti_irqn);
}
}
void omv_gpio_clock_enable(omv_gpio_t pin, bool enable)
{
if (pin->port == GPIOA) {
if (enable) {
__HAL_RCC_GPIOA_CLK_ENABLE();
} else {
__HAL_RCC_GPIOA_CLK_DISABLE();
}
} else if (pin->port == GPIOB) {
if (enable) {
__HAL_RCC_GPIOB_CLK_ENABLE();
} else {
__HAL_RCC_GPIOB_CLK_DISABLE();
}
} else if (pin->port == GPIOC) {
if (enable) {
__HAL_RCC_GPIOC_CLK_ENABLE();
} else {
__HAL_RCC_GPIOC_CLK_DISABLE();
}
} else if (pin->port == GPIOD) {
if (enable) {
__HAL_RCC_GPIOD_CLK_ENABLE();
} else {
__HAL_RCC_GPIOD_CLK_DISABLE();
}
} else if (pin->port == GPIOE) {
if (enable) {
__HAL_RCC_GPIOE_CLK_ENABLE();
} else {
__HAL_RCC_GPIOE_CLK_DISABLE();
}
} else if (pin->port == GPIOF) {
if (enable) {
__HAL_RCC_GPIOF_CLK_ENABLE();
} else {
__HAL_RCC_GPIOF_CLK_DISABLE();
}
} else if (pin->port == GPIOG) {
if (enable) {
__HAL_RCC_GPIOG_CLK_ENABLE();
} else {
__HAL_RCC_GPIOG_CLK_DISABLE();
}
#if defined(__HAL_RCC_GPIOH_CLK_ENABLE)
} else if (pin->port == GPIOH) {
if (enable) {
__HAL_RCC_GPIOH_CLK_ENABLE();
} else {
__HAL_RCC_GPIOH_CLK_DISABLE();
}
#elif defined(__HAL_RCC_GPIOI_CLK_ENABLE)
} else if (pin->port == GPIOI) {
if (enable) {
__HAL_RCC_GPIOI_CLK_ENABLE();
} else {
__HAL_RCC_GPIOI_CLK_DISABLE();
}
#elif defined(__HAL_RCC_GPIOJ_CLK_ENABLE)
} else if (pin->port == GPIOJ) {
if (enable) {
__HAL_RCC_GPIOJ_CLK_ENABLE();
} else {
__HAL_RCC_GPIOJ_CLK_DISABLE();
}
#elif defined(__HAL_RCC_GPIOK_CLK_ENABLE)
} else if (pin->port == GPIOK) {
if (enable) {
__HAL_RCC_GPIOK_CLK_ENABLE();
} else {
__HAL_RCC_GPIOK_CLK_DISABLE();
}
#endif
}
}

View File

@ -12,14 +12,57 @@
#define __OMV_PORTCONFIG_H__
#include STM32_HAL_H
// GPIO speeds.
#define OMV_GPIO_SPEED_LOW GPIO_SPEED_FREQ_LOW
#define OMV_GPIO_SPEED_MED GPIO_SPEED_FREQ_MEDIUM
#define OMV_GPIO_SPEED_HIGH GPIO_SPEED_FREQ_HIGH
#define OMV_GPIO_SPEED_MAX GPIO_SPEED_FREQ_VERY_HIGH
// GPIO pull.
#define OMV_GPIO_PULL_NONE GPIO_NOPULL
#define OMV_GPIO_PULL_UP GPIO_PULLUP
#define OMV_GPIO_PULL_DOWN GPIO_PULLDOWN
// GPIO modes.
#define OMV_GPIO_MODE_INPUT GPIO_MODE_INPUT
#define OMV_GPIO_MODE_OUTPUT GPIO_MODE_OUTPUT_PP
#define OMV_GPIO_MODE_OUTPUT_OD GPIO_MODE_OUTPUT_OD
#define OMV_GPIO_MODE_ALT GPIO_MODE_AF_PP
#define OMV_GPIO_MODE_ALT_OD GPIO_MODE_AF_OD
#define OMV_GPIO_MODE_ANALOG GPIO_MODE_ANALOG
// GPIO IT modes.
#define OMV_GPIO_MODE_IT_FALL GPIO_MODE_IT_FALLING
#define OMV_GPIO_MODE_IT_RISE GPIO_MODE_IT_RISING
#define OMV_GPIO_MODE_IT_BOTH GPIO_MODE_IT_RISING_FALLING
// omv_gpio_t definition
typedef struct _omv_gpio {
uint32_t pin;
typedef struct {
GPIO_TypeDef *port;
} omv_gpio_t;
uint16_t pin;
uint16_t af;
} stm32_gpio_t;
typedef const stm32_gpio_t *omv_gpio_t;
// cambus/i2c definition
// This pointer will be set to its respective I2C handle which is defined in MicroPython along with
// IRQ handlers, if this I2C is enabled in Micropython, or defined and handled in stm32fxxx_hal_msp.c.
typedef I2C_HandleTypeDef *omv_cambus_t;
// For board config files.
// Dummy AF for pins defined as I/O
#define GPIO_NONE_GPIO (0)
#if OMV_GPIO_DEFINE_PINS
#define OMV_GPIO_DEFINE(port, pin, af, inst) \
const stm32_gpio_t omv_pin_##port##pin##_##inst = {GPIO##port, GPIO_PIN_##pin, GPIO_##af##_##inst};
#else
#define OMV_GPIO_DEFINE(port, pin, af, inst) \
extern stm32_gpio_t omv_pin_##port##pin##_##inst;
#endif
#include "omv_pins.h"
#endif // __OMV_PORTCONFIG_H__

View File

@ -567,6 +567,7 @@ UVC_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/ports/stm32/,\
soft_i2c.o \
cambus.o \
ulpi.o \
omv_gpio.o \
)
UVC_OBJ += $(wildcard $(BUILD)/$(LEPTON_DIR)/src/*.o)