mirror of
https://github.com/paparazzi/paparazzi.git
synced 2026-05-26 16:30:07 +08:00
Module for transparent control of external GPIOs (#2564)
* GCC wrap example
* Rename pca95x4 to pca95xx
* Fix softi2c_spin hanging
Suspected cause is sys_time_usleep hanging when called from SPI,
because interrupts are disabled. But not confirmed. Adding LED
code fixes the hang, so cannot test.
Co-authored-by: Tom van Dijk <tomvand@users.noreply.github.com>
This commit is contained in:
@@ -20,7 +20,7 @@
|
||||
<define name="USE_$(MULTI_RANGER_I2C_DEV_UPPER)"/>
|
||||
<define name="VL53L1X_AUTO_INCR_ADDR"/>
|
||||
<file name="cf_deck_multi_ranger.c"/>
|
||||
<file name="pca95x4.c" dir="peripherals"/>
|
||||
<file name="pca95xx.c" dir="peripherals"/>
|
||||
<file name="vl53l1_platform.c" dir="peripherals"/>
|
||||
<file name="vl53l1x_api.c" dir="peripherals"/>
|
||||
<file name="vl53l1x_nonblocking.c" dir="peripherals"/>
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE module SYSTEM "module.dtd">
|
||||
<module name="gpio_ext_common" dir="gpio_ext" task="mcu">
|
||||
<doc>
|
||||
<description>
|
||||
Common functions for external GPIO
|
||||
|
||||
This module wraps calls to the gpio_x functions (GCC only!) and
|
||||
redirects calls with port GPIOEXTx to modules.
|
||||
|
||||
See gpio_ext_pca95xx as an example implementation.
|
||||
</description>
|
||||
</doc>
|
||||
<header>
|
||||
<file name="gpio_ext_common.h"/>
|
||||
</header>
|
||||
<makefile>
|
||||
<file name="gpio_ext_common.c"/>
|
||||
<flag name="LDFLAGS" value="Wl,-wrap,gpio_setup_output"/>
|
||||
<flag name="LDFLAGS" value="Wl,-wrap,gpio_setup_input"/>
|
||||
<flag name="LDFLAGS" value="Wl,-wrap,gpio_get"/>
|
||||
<flag name="LDFLAGS" value="Wl,-wrap,gpio_set"/>
|
||||
<flag name="LDFLAGS" value="Wl,-wrap,gpio_clear"/>
|
||||
<flag name="LDFLAGS" value="Wl,-wrap,gpio_toggle"/>
|
||||
<!-- Port and pin defines, made available globally -->
|
||||
<define name="GPIOEXT1" value="256"/>
|
||||
<define name="GPIOEXT2" value="257"/>
|
||||
<define name="GPIOEXT3" value="258"/>
|
||||
<define name="GPIOEXT4" value="259"/>
|
||||
<define name="GPIOEXT_NB" value="4"/>
|
||||
<define name="GPIOE0" value="1"/>
|
||||
<define name="GPIOE1" value="2"/>
|
||||
<define name="GPIOE2" value="4"/>
|
||||
<define name="GPIOE3" value="8"/>
|
||||
<define name="GPIOE4" value="16"/>
|
||||
<define name="GPIOE5" value="32"/>
|
||||
<define name="GPIOE6" value="64"/>
|
||||
<define name="GPIOE7" value="128"/>
|
||||
</makefile>
|
||||
</module>
|
||||
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE module SYSTEM "module.dtd">
|
||||
<module name="gpio_ext_pca95xx" dir="gpio_ext" task="mcu">
|
||||
<doc>
|
||||
<description>
|
||||
PCA95XX external GPIO peripheral
|
||||
|
||||
Uses the gpio_ext_common mechanism for transparent redirecting of gpio
|
||||
calls. Multiple PCA95XX can be used, on different I2C busses.
|
||||
Configuration and writing can be performed non-blocking (reading is
|
||||
always blocking).
|
||||
</description>
|
||||
<define name="GPIO_EXT_PROVIDERx" value="GPIO_EXT_PCA95XX" description="Set-up module as provider for port GPIOEXTx"/>
|
||||
<configure name="GPIO_EXT_PCA95XX_I2C_PERIPHx" value="softi2c0" description="I2C peripheral"/>
|
||||
<define name="GPIO_EXT_PCA95XX_I2C_ADDRESSx" value="0x82" description="I2C address of GPIO expander"/>
|
||||
<define name="GPIO_EXT_PCA95XX_BLOCKINGx" value="TRUE|FALSE" description="Whether write operations to this port should be blocking. (Note: reading is always blocking)."/>
|
||||
</doc>
|
||||
<autoload name="gpio_ext_common"/>
|
||||
<header>
|
||||
<file name="gpio_ext_pca95xx.h"/>
|
||||
</header>
|
||||
<makefile>
|
||||
<configure name="GPIO_EXT_PCA95XX_I2C_PERIPH1" default="undefined" case="upper|lower"/>
|
||||
<define name="GPIO_EXT_PCA95XX_I2C_PERIPH1" value="$(GPIO_EXT_PCA95XX_I2C_PERIPH1_LOWER)" cond="ifneq ($(GPIO_EXT_PCA95XX_I2C_PERIPH1),undefined)"/>
|
||||
<define name="USE_$(GPIO_EXT_PCA95XX_I2C_PERIPH1_UPPER)" cond="ifneq ($(GPIO_EXT_PCA95XX_I2C_PERIPH1),undefined)"/>
|
||||
|
||||
<configure name="GPIO_EXT_PCA95XX_I2C_PERIPH2" default="undefined" case="upper|lower"/>
|
||||
<define name="GPIO_EXT_PCA95XX_I2C_PERIPH2" value="$(GPIO_EXT_PCA95XX_I2C_PERIPH2_LOWER)" cond="ifneq ($(GPIO_EXT_PCA95XX_I2C_PERIPH2),undefined)"/>
|
||||
<define name="USE_$(GPIO_EXT_PCA95XX_I2C_PERIPH2_UPPER)" cond="ifneq ($(GPIO_EXT_PCA95XX_I2C_PERIPH2),undefined)"/>
|
||||
|
||||
<configure name="GPIO_EXT_PCA95XX_I2C_PERIPH3" default="undefined" case="upper|lower"/>
|
||||
<define name="GPIO_EXT_PCA95XX_I2C_PERIPH3" value="$(GPIO_EXT_PCA95XX_I2C_PERIPH3_LOWER)" cond="ifneq ($(GPIO_EXT_PCA95XX_I2C_PERIPH3),undefined)"/>
|
||||
<define name="USE_$(GPIO_EXT_PCA95XX_I2C_PERIPH3_UPPER)" cond="ifneq ($(GPIO_EXT_PCA95XX_I2C_PERIPH3),undefined)"/>
|
||||
|
||||
<configure name="GPIO_EXT_PCA95XX_I2C_PERIPH4" default="undefined" case="upper|lower"/>
|
||||
<define name="GPIO_EXT_PCA95XX_I2C_PERIPH4" value="$(GPIO_EXT_PCA95XX_I2C_PERIPH4_LOWER)" cond="ifneq ($(GPIO_EXT_PCA95XX_I2C_PERIPH4),undefined)"/>
|
||||
<define name="USE_$(GPIO_EXT_PCA95XX_I2C_PERIPH4_UPPER)" cond="ifneq ($(GPIO_EXT_PCA95XX_I2C_PERIPH4),undefined)"/>
|
||||
|
||||
<file name="gpio_ext_pca95xx.c"/>
|
||||
<file name="pca95xx.c" dir="peripherals"/>
|
||||
</makefile>
|
||||
</module>
|
||||
@@ -644,7 +644,7 @@ void softi2c_event(void) {
|
||||
|
||||
static void softi2c_spin(struct i2c_periph *p) {
|
||||
softi2c_device_event((struct softi2c_device *) p->reg_addr);
|
||||
sys_time_usleep(5); // For I2C timing.
|
||||
// sys_time_usleep(5); // For I2C timing. // TvD 2020-08-18: Hangs? Interrupt issue when called from SPI?
|
||||
}
|
||||
|
||||
static bool softi2c_idle(struct i2c_periph *p) {
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) Tom van Dijk <tomvand@users.noreply.github.com>
|
||||
*
|
||||
* This file is part of paparazzi
|
||||
*
|
||||
* paparazzi is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* paparazzi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with paparazzi; see the file COPYING. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file "modules/gpio_ext/gpio_ext_common.c"
|
||||
* @author Tom van Dijk <tomvand@users.noreply.github.com>
|
||||
* Common external GPIO functions.
|
||||
*/
|
||||
|
||||
#include "gpio_ext_common.h"
|
||||
|
||||
#include "generated/airframe.h"
|
||||
#include "generated/modules.h"
|
||||
#include "mcu_periph/gpio.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/* External GPIO providers */
|
||||
#define GPIO_EXT_NOT_PROVIDED NULL
|
||||
|
||||
#ifndef GPIO_EXT_PROVIDER1
|
||||
#define GPIO_EXT_PROVIDER1 GPIO_EXT_NOT_PROVIDED
|
||||
#endif
|
||||
#ifndef GPIO_EXT_PROVIDER2
|
||||
#define GPIO_EXT_PROVIDER2 GPIO_EXT_NOT_PROVIDED
|
||||
#endif
|
||||
#ifndef GPIO_EXT_PROVIDER3
|
||||
#define GPIO_EXT_PROVIDER3 GPIO_EXT_NOT_PROVIDED
|
||||
#endif
|
||||
#ifndef GPIO_EXT_PROVIDER4
|
||||
#define GPIO_EXT_PROVIDER4 GPIO_EXT_NOT_PROVIDED
|
||||
#endif
|
||||
|
||||
static struct gpio_ext_functions *gpio_ext_impl[GPIOEXT_NB] = {
|
||||
GPIO_EXT_PROVIDER1,
|
||||
GPIO_EXT_PROVIDER2,
|
||||
GPIO_EXT_PROVIDER3,
|
||||
GPIO_EXT_PROVIDER4,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* External GPIO implementation
|
||||
*/
|
||||
#define SAFE_CALL(_port, _fn, _args...) if(gpio_ext_impl[_port - GPIOEXT1] && gpio_ext_impl[_port - GPIOEXT1]->_fn) gpio_ext_impl[_port - GPIOEXT1]->_fn(_args);
|
||||
|
||||
// Wrapping functions
|
||||
void __wrap_gpio_setup_output(uint32_t port, uint32_t gpios);
|
||||
void __real_gpio_setup_output(uint32_t port, uint32_t gpios);
|
||||
void __wrap_gpio_setup_output(uint32_t port, uint32_t gpios) {
|
||||
if (port >= GPIOEXT1 && port < GPIOEXT1 + GPIOEXT_NB) {
|
||||
SAFE_CALL(port, setup_output, port, gpios);
|
||||
} else {
|
||||
__real_gpio_setup_output(port, gpios);
|
||||
}
|
||||
}
|
||||
|
||||
void __wrap_gpio_setup_input(uint32_t port, uint32_t gpios);
|
||||
void __real_gpio_setup_input(uint32_t port, uint32_t gpios);
|
||||
void __wrap_gpio_setup_input(uint32_t port, uint32_t gpios) {
|
||||
if (port >= GPIOEXT1 && port < GPIOEXT1 + GPIOEXT_NB) {
|
||||
SAFE_CALL(port, setup_input, port, gpios);
|
||||
} else {
|
||||
__real_gpio_setup_input(port, gpios);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t __wrap_gpio_get(uint32_t port, uint32_t gpios);
|
||||
uint32_t __real_gpio_get(uint32_t port, uint32_t gpios);
|
||||
uint32_t __wrap_gpio_get(uint32_t port, uint32_t gpios) {
|
||||
if (port >= GPIOEXT1 && port < GPIOEXT1 + GPIOEXT_NB) {
|
||||
if (gpio_ext_impl[port - GPIOEXT1] && gpio_ext_impl[port - GPIOEXT1]->get) {
|
||||
return gpio_ext_impl[port - GPIOEXT1]->get(port, gpios);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return __real_gpio_get(port, gpios);
|
||||
}
|
||||
}
|
||||
|
||||
void __wrap_gpio_set(uint32_t port, uint32_t gpios);
|
||||
void __real_gpio_set(uint32_t port, uint32_t gpios);
|
||||
void __wrap_gpio_set(uint32_t port, uint32_t gpios) {
|
||||
if (port >= GPIOEXT1 && port < GPIOEXT1 + GPIOEXT_NB) {
|
||||
SAFE_CALL(port, set, port, gpios);
|
||||
} else {
|
||||
__real_gpio_set(port, gpios);
|
||||
}
|
||||
}
|
||||
|
||||
void __wrap_gpio_clear(uint32_t port, uint32_t gpios);
|
||||
void __real_gpio_clear(uint32_t port, uint32_t gpios);
|
||||
void __wrap_gpio_clear(uint32_t port, uint32_t gpios) {
|
||||
if (port >= GPIOEXT1 && port < GPIOEXT1 + GPIOEXT_NB) {
|
||||
SAFE_CALL(port, clear, port, gpios);
|
||||
} else {
|
||||
__real_gpio_clear(port, gpios);
|
||||
}
|
||||
}
|
||||
|
||||
void __wrap_gpio_toggle(uint32_t port, uint32_t gpios);
|
||||
void __real_gpio_toggle(uint32_t port, uint32_t gpios);
|
||||
void __wrap_gpio_toggle(uint32_t port, uint32_t gpios) {
|
||||
if (port >= GPIOEXT1 && port < GPIOEXT1 + GPIOEXT_NB) {
|
||||
SAFE_CALL(port, toggle, port, gpios);
|
||||
} else {
|
||||
__real_gpio_toggle(port, gpios);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) Tom van Dijk <tomvand@users.noreply.github.com>
|
||||
*
|
||||
* This file is part of paparazzi
|
||||
*
|
||||
* paparazzi is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* paparazzi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with paparazzi; see the file COPYING. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file "modules/gpio_ext/gpio_ext_common.h"
|
||||
* @author Tom van Dijk <tomvand@users.noreply.github.com>
|
||||
* Common external GPIO functions.
|
||||
*/
|
||||
|
||||
#ifndef GPIO_EXT_COMMON_H
|
||||
#define GPIO_EXT_COMMON_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// External GPIO implementation struct
|
||||
struct gpio_ext_functions {
|
||||
void (*setup_output)(uint32_t port, uint32_t gpios);
|
||||
void (*setup_input)(uint32_t port, uint32_t gpios);
|
||||
uint32_t (*get)(uint32_t port, uint32_t gpios);
|
||||
void (*set)(uint32_t port, uint32_t gpios);
|
||||
void (*clear)(uint32_t port, uint32_t gpios);
|
||||
void (*toggle)(uint32_t port, uint32_t gpios);
|
||||
};
|
||||
|
||||
|
||||
#endif // GPIO_EXT_COMMON_H
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (C) Tom van Dijk <tomvand@users.noreply.github.com>
|
||||
*
|
||||
* This file is part of paparazzi
|
||||
*
|
||||
* paparazzi is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* paparazzi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with paparazzi; see the file COPYING. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file "modules/gpio_ext/gpio_ext_pca95xx.c"
|
||||
* @author Tom van Dijk <tomvand@users.noreply.github.com>
|
||||
* PCA95XX external GPIO peripheral
|
||||
*/
|
||||
|
||||
#include "modules/gpio_ext/gpio_ext_pca95xx.h"
|
||||
|
||||
#include "modules/gpio_ext/gpio_ext_common.h"
|
||||
#include "generated/airframe.h"
|
||||
#include "peripherals/pca95xx.h"
|
||||
#include "mcu_periph/i2c.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
#ifdef GPIO_EXT_PCA95XX_I2C_PERIPH1
|
||||
#define GPIO_EXT_PCA95XX_I2C_PERIPH1_PTR &(GPIO_EXT_PCA95XX_I2C_PERIPH1)
|
||||
#else
|
||||
#define GPIO_EXT_PCA95XX_I2C_PERIPH1_PTR NULL
|
||||
#endif
|
||||
#ifdef GPIO_EXT_PCA95XX_I2C_PERIPH2
|
||||
#define GPIO_EXT_PCA95XX_I2C_PERIPH2_PTR &(GPIO_EXT_PCA95XX_I2C_PERIPH2)
|
||||
#else
|
||||
#define GPIO_EXT_PCA95XX_I2C_PERIPH2_PTR NULL
|
||||
#endif
|
||||
#ifdef GPIO_EXT_PCA95XX_I2C_PERIPH3
|
||||
#define GPIO_EXT_PCA95XX_I2C_PERIPH3_PTR &(GPIO_EXT_PCA95XX_I2C_PERIPH3)
|
||||
#else
|
||||
#define GPIO_EXT_PCA95XX_I2C_PERIPH3_PTR NULL
|
||||
#endif
|
||||
#ifdef GPIO_EXT_PCA95XX_I2C_PERIPH4
|
||||
#define GPIO_EXT_PCA95XX_I2C_PERIPH4_PTR &(GPIO_EXT_PCA95XX_I2C_PERIPH4)
|
||||
#else
|
||||
#define GPIO_EXT_PCA95XX_I2C_PERIPH4_PTR NULL
|
||||
#endif
|
||||
static struct i2c_periph * const i2c_periph[] = {
|
||||
GPIO_EXT_PCA95XX_I2C_PERIPH1_PTR,
|
||||
GPIO_EXT_PCA95XX_I2C_PERIPH2_PTR,
|
||||
GPIO_EXT_PCA95XX_I2C_PERIPH3_PTR,
|
||||
GPIO_EXT_PCA95XX_I2C_PERIPH4_PTR,
|
||||
};
|
||||
|
||||
#ifndef GPIO_EXT_PCA95XX_I2C_ADDRESS1
|
||||
#define GPIO_EXT_PCA95XX_I2C_ADDRESS1 0x00
|
||||
#endif
|
||||
#ifndef GPIO_EXT_PCA95XX_I2C_ADDRESS2
|
||||
#define GPIO_EXT_PCA95XX_I2C_ADDRESS2 0x00
|
||||
#endif
|
||||
#ifndef GPIO_EXT_PCA95XX_I2C_ADDRESS3
|
||||
#define GPIO_EXT_PCA95XX_I2C_ADDRESS3 0x00
|
||||
#endif
|
||||
#ifndef GPIO_EXT_PCA95XX_I2C_ADDRESS4
|
||||
#define GPIO_EXT_PCA95XX_I2C_ADDRESS4 0x00
|
||||
#endif
|
||||
static const uint8_t i2c_addr[] = {
|
||||
GPIO_EXT_PCA95XX_I2C_ADDRESS1,
|
||||
GPIO_EXT_PCA95XX_I2C_ADDRESS2,
|
||||
GPIO_EXT_PCA95XX_I2C_ADDRESS3,
|
||||
GPIO_EXT_PCA95XX_I2C_ADDRESS4,
|
||||
};
|
||||
|
||||
#ifndef GPIO_EXT_PCA95XX_BLOCKING1
|
||||
#define GPIO_EXT_PCA95XX_BLOCKING1 TRUE
|
||||
#endif
|
||||
#ifndef GPIO_EXT_PCA95XX_BLOCKING2
|
||||
#define GPIO_EXT_PCA95XX_BLOCKING2 TRUE
|
||||
#endif
|
||||
#ifndef GPIO_EXT_PCA95XX_BLOCKING3
|
||||
#define GPIO_EXT_PCA95XX_BLOCKING3 TRUE
|
||||
#endif
|
||||
#ifndef GPIO_EXT_PCA95XX_BLOCKING4
|
||||
#define GPIO_EXT_PCA95XX_BLOCKING4 TRUE
|
||||
#endif
|
||||
static const bool blocking[] = {
|
||||
GPIO_EXT_PCA95XX_BLOCKING1,
|
||||
GPIO_EXT_PCA95XX_BLOCKING1,
|
||||
GPIO_EXT_PCA95XX_BLOCKING1,
|
||||
GPIO_EXT_PCA95XX_BLOCKING1,
|
||||
};
|
||||
|
||||
|
||||
static void gpio_ext_pca95xx_setup_output(uint32_t port, uint32_t gpios);
|
||||
static void gpio_ext_pca95xx_setup_input(uint32_t port, uint32_t gpios);
|
||||
static uint32_t gpio_ext_pca95xx_get(uint32_t port, uint32_t gpios);
|
||||
static void gpio_ext_pca95xx_set(uint32_t port, uint32_t gpios);
|
||||
static void gpio_ext_pca95xx_clear(uint32_t port, uint32_t gpios);
|
||||
static void gpio_ext_pca95xx_toggle(uint32_t port, uint32_t gpios);
|
||||
|
||||
|
||||
struct gpio_ext_functions pca95xx_functions = {
|
||||
gpio_ext_pca95xx_setup_output,
|
||||
gpio_ext_pca95xx_setup_input,
|
||||
gpio_ext_pca95xx_get,
|
||||
gpio_ext_pca95xx_set,
|
||||
gpio_ext_pca95xx_clear,
|
||||
gpio_ext_pca95xx_toggle,
|
||||
};
|
||||
|
||||
|
||||
struct gpio_ext_pca95xx_impl_t {
|
||||
struct pca95xx periph;
|
||||
uint8_t output_reg;
|
||||
uint8_t config_reg;
|
||||
bool initialized;
|
||||
};
|
||||
static struct gpio_ext_pca95xx_impl_t impl[GPIOEXT_NB]; // Initialized 0, so .initialized = false!
|
||||
|
||||
|
||||
static void gpio_ext_pca95xx_lazy_init(uint32_t port) {
|
||||
int i = port - GPIOEXT1;
|
||||
if (impl[i].initialized) return;
|
||||
/* Set up pca95xx implementation struct */
|
||||
impl[i].output_reg = 0xFF;
|
||||
impl[i].config_reg = 0xFF;
|
||||
/* Set up pca95xx peripheral */
|
||||
pca95xx_init(&impl[i].periph, i2c_periph[i], i2c_addr[i]);
|
||||
/* Configure pins as input (default) and wait for IC to wake up */
|
||||
do {
|
||||
pca95xx_configure(&impl[i].periph, 0xFF, true);
|
||||
} while (impl[i].periph.i2c_trans.status != I2CTransSuccess);
|
||||
/* Mark initialization complete */
|
||||
impl[i].initialized = true;
|
||||
}
|
||||
|
||||
|
||||
static void gpio_ext_pca95xx_setup_output(uint32_t port, uint32_t gpios) {
|
||||
gpio_ext_pca95xx_lazy_init(port);
|
||||
int i = port - GPIOEXT1;
|
||||
impl[i].config_reg &= ~gpios;
|
||||
pca95xx_configure(&impl[i].periph, impl[i].config_reg, blocking[i]);
|
||||
}
|
||||
|
||||
static void gpio_ext_pca95xx_setup_input(uint32_t port, uint32_t gpios) {
|
||||
gpio_ext_pca95xx_lazy_init(port);
|
||||
int i = port - GPIOEXT1;
|
||||
impl[i].config_reg |= gpios;
|
||||
pca95xx_configure(&impl[i].periph, impl[i].config_reg, blocking[i]);
|
||||
}
|
||||
|
||||
static uint32_t gpio_ext_pca95xx_get(uint32_t port, uint32_t gpios) {
|
||||
int i = port - GPIOEXT1;
|
||||
uint8_t result;
|
||||
pca95xx_get_input(&impl[i].periph, gpios, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void gpio_ext_pca95xx_set(uint32_t port, uint32_t gpios) {
|
||||
int i = port - GPIOEXT1;
|
||||
impl[i].output_reg |= gpios;
|
||||
pca95xx_set_output(&impl[i].periph, impl[i].output_reg, blocking[i]);
|
||||
}
|
||||
|
||||
static void gpio_ext_pca95xx_clear(uint32_t port, uint32_t gpios) {
|
||||
int i = port - GPIOEXT1;
|
||||
impl[i].output_reg &= ~gpios;
|
||||
pca95xx_set_output(&impl[i].periph, impl[i].output_reg, blocking[i]);
|
||||
}
|
||||
|
||||
static void gpio_ext_pca95xx_toggle(uint32_t port, uint32_t gpios) {
|
||||
int i = port - GPIOEXT1;
|
||||
impl[i].output_reg ^= gpios;
|
||||
pca95xx_set_output(&impl[i].periph, impl[i].output_reg, blocking[i]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) Tom van Dijk <tomvand@users.noreply.github.com>
|
||||
*
|
||||
* This file is part of paparazzi
|
||||
*
|
||||
* paparazzi is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* paparazzi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with paparazzi; see the file COPYING. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file "modules/gpio_ext/gpio_ext_pca95xx.h"
|
||||
* @author Tom van Dijk <tomvand@users.noreply.github.com>
|
||||
* PCA95XX external GPIO peripheral
|
||||
*/
|
||||
|
||||
#ifndef GPIO_EXT_PCA95XX_H
|
||||
#define GPIO_EXT_PCA95XX_H
|
||||
|
||||
#define GPIO_EXT_PCA95XX &pca95xx_functions
|
||||
|
||||
extern struct gpio_ext_functions pca95xx_functions;
|
||||
|
||||
#endif // GPIO_EXT_PCA95XX_H
|
||||
@@ -24,7 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "modules/range_finder/cf_deck_multi_ranger.h"
|
||||
#include "peripherals/pca95x4.h"
|
||||
#include "peripherals/pca95xx.h"
|
||||
#include "peripherals/vl53l1x_nonblocking.h"
|
||||
#include "peripherals/vl53l1x_api.h"
|
||||
#include "subsystems/abi.h"
|
||||
@@ -64,11 +64,11 @@
|
||||
#endif
|
||||
|
||||
// PCA I/O pins to enable sensors
|
||||
#define MULTI_RANGER_PIN_FRONT PCA95X4_P4
|
||||
#define MULTI_RANGER_PIN_BACK PCA95X4_P1
|
||||
#define MULTI_RANGER_PIN_RIGHT PCA95X4_P2
|
||||
#define MULTI_RANGER_PIN_LEFT PCA95X4_P6
|
||||
#define MULTI_RANGER_PIN_UP PCA95X4_P0
|
||||
#define MULTI_RANGER_PIN_FRONT PCA95XX_P4
|
||||
#define MULTI_RANGER_PIN_BACK PCA95XX_P1
|
||||
#define MULTI_RANGER_PIN_RIGHT PCA95XX_P2
|
||||
#define MULTI_RANGER_PIN_LEFT PCA95XX_P6
|
||||
#define MULTI_RANGER_PIN_UP PCA95XX_P0
|
||||
#define MULTI_RANGER_PIN_ALL (MULTI_RANGER_PIN_FRONT | MULTI_RANGER_PIN_BACK | MULTI_RANGER_PIN_RIGHT | MULTI_RANGER_PIN_LEFT | MULTI_RANGER_PIN_UP)
|
||||
|
||||
enum MultiRangerStatus {
|
||||
@@ -117,7 +117,7 @@ struct cf_deck_multi_ranger {
|
||||
// VL53L1X devices
|
||||
struct SingleRanger ranger[MULTI_RANGER_NB]; ///< sensor array
|
||||
// I/O expander
|
||||
struct pca95x4 pca;
|
||||
struct pca95xx pca;
|
||||
};
|
||||
|
||||
static struct cf_deck_multi_ranger multi_ranger;
|
||||
@@ -140,10 +140,10 @@ void multi_ranger_init(void)
|
||||
multi_ranger.status = MULTI_RANGER_UNINIT;
|
||||
|
||||
// init I/O expander
|
||||
pca95x4_init(&multi_ranger.pca, &(MULTI_RANGER_I2C_DEV), PCA95X4_DEFAULT_ADDRESS);
|
||||
pca95xx_init(&multi_ranger.pca, &(MULTI_RANGER_I2C_DEV), PCA95XX_DEFAULT_ADDRESS);
|
||||
#if MULTI_RANGER_EARLY_INIT
|
||||
pca95x4_configure(&multi_ranger.pca, ~(MULTI_RANGER_PIN_ALL), true); // configure output
|
||||
pca95x4_set_output(&multi_ranger.pca, ~(MULTI_RANGER_PIN_ALL), true); // select none
|
||||
pca95xx_configure(&multi_ranger.pca, ~(MULTI_RANGER_PIN_ALL), true); // configure output
|
||||
pca95xx_set_output(&multi_ranger.pca, ~(MULTI_RANGER_PIN_ALL), true); // select none
|
||||
#endif
|
||||
|
||||
// init vl53l1x array
|
||||
@@ -182,31 +182,31 @@ void multi_ranger_periodic(void)
|
||||
{
|
||||
switch (multi_ranger.status) {
|
||||
case MULTI_RANGER_UNINIT:
|
||||
pca95x4_configure(&multi_ranger.pca, ~(MULTI_RANGER_PIN_ALL), false); // configure output
|
||||
pca95xx_configure(&multi_ranger.pca, ~(MULTI_RANGER_PIN_ALL), false); // configure output
|
||||
multi_ranger.status++;
|
||||
break;
|
||||
case MULTI_RANGER_CONF_IO:
|
||||
pca95x4_set_output(&multi_ranger.pca, MULTI_RANGER_PIN_FRONT, false); // select front
|
||||
pca95xx_set_output(&multi_ranger.pca, MULTI_RANGER_PIN_FRONT, false); // select front
|
||||
multi_ranger.status++;
|
||||
break;
|
||||
case MULTI_RANGER_CONF_FRONT:
|
||||
multi_ranger_boot_device(&multi_ranger.ranger[MULTI_RANGER_FRONT].dev);
|
||||
pca95x4_set_output(&multi_ranger.pca, MULTI_RANGER_PIN_FRONT | MULTI_RANGER_PIN_BACK, false); // select back
|
||||
pca95xx_set_output(&multi_ranger.pca, MULTI_RANGER_PIN_FRONT | MULTI_RANGER_PIN_BACK, false); // select back
|
||||
multi_ranger.status++;
|
||||
break;
|
||||
case MULTI_RANGER_CONF_BACK:
|
||||
multi_ranger_boot_device(&multi_ranger.ranger[MULTI_RANGER_BACK].dev);
|
||||
pca95x4_set_output(&multi_ranger.pca, MULTI_RANGER_PIN_FRONT | MULTI_RANGER_PIN_BACK | MULTI_RANGER_PIN_RIGHT, false); // select right
|
||||
pca95xx_set_output(&multi_ranger.pca, MULTI_RANGER_PIN_FRONT | MULTI_RANGER_PIN_BACK | MULTI_RANGER_PIN_RIGHT, false); // select right
|
||||
multi_ranger.status++;
|
||||
break;
|
||||
case MULTI_RANGER_CONF_RIGHT:
|
||||
multi_ranger_boot_device(&multi_ranger.ranger[MULTI_RANGER_RIGHT].dev);
|
||||
pca95x4_set_output(&multi_ranger.pca, MULTI_RANGER_PIN_FRONT | MULTI_RANGER_PIN_BACK | MULTI_RANGER_PIN_RIGHT | MULTI_RANGER_PIN_LEFT, false); // select left
|
||||
pca95xx_set_output(&multi_ranger.pca, MULTI_RANGER_PIN_FRONT | MULTI_RANGER_PIN_BACK | MULTI_RANGER_PIN_RIGHT | MULTI_RANGER_PIN_LEFT, false); // select left
|
||||
multi_ranger.status++;
|
||||
break;
|
||||
case MULTI_RANGER_CONF_LEFT:
|
||||
multi_ranger_boot_device(&multi_ranger.ranger[MULTI_RANGER_LEFT].dev);
|
||||
pca95x4_set_output(&multi_ranger.pca, MULTI_RANGER_PIN_ALL, false); // select up
|
||||
pca95xx_set_output(&multi_ranger.pca, MULTI_RANGER_PIN_ALL, false); // select up
|
||||
multi_ranger.status++;
|
||||
break;
|
||||
case MULTI_RANGER_CONF_UP:
|
||||
|
||||
@@ -19,15 +19,15 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file peripherals/pca95x4.c
|
||||
* @file peripherals/pca95xx.c
|
||||
*
|
||||
* Driver for the 8-bit I/O expander based on i2c
|
||||
*/
|
||||
|
||||
#include "peripherals/pca95x4.h"
|
||||
#include "peripherals/pca95xx.h"
|
||||
|
||||
// Init function
|
||||
void pca95x4_init(struct pca95x4 *dev, struct i2c_periph *i2c_p, uint8_t addr)
|
||||
void pca95xx_init(struct pca95xx *dev, struct i2c_periph *i2c_p, uint8_t addr)
|
||||
{
|
||||
/* set i2c_peripheral */
|
||||
dev->i2c_p = i2c_p;
|
||||
@@ -39,7 +39,7 @@ void pca95x4_init(struct pca95x4 *dev, struct i2c_periph *i2c_p, uint8_t addr)
|
||||
}
|
||||
|
||||
// Configure function
|
||||
bool pca95x4_configure(struct pca95x4 *dev, uint8_t val, bool blocking)
|
||||
bool pca95xx_configure(struct pca95xx *dev, uint8_t val, bool blocking)
|
||||
{
|
||||
if (dev->i2c_trans.status != I2CTransDone &&
|
||||
dev->i2c_trans.status != I2CTransSuccess &&
|
||||
@@ -47,7 +47,7 @@ bool pca95x4_configure(struct pca95x4 *dev, uint8_t val, bool blocking)
|
||||
return false; // previous transaction not finished
|
||||
}
|
||||
// send config value
|
||||
dev->i2c_trans.buf[0] = PCA95X4_CONFIG_REG;
|
||||
dev->i2c_trans.buf[0] = PCA95XX_CONFIG_REG;
|
||||
dev->i2c_trans.buf[1] = val;
|
||||
if (blocking) {
|
||||
return i2c_blocking_transmit(dev->i2c_p, &dev->i2c_trans, dev->i2c_trans.slave_addr, 2);
|
||||
@@ -57,7 +57,7 @@ bool pca95x4_configure(struct pca95x4 *dev, uint8_t val, bool blocking)
|
||||
}
|
||||
|
||||
// Set output function
|
||||
bool pca95x4_set_output(struct pca95x4 *dev, uint8_t mask, bool blocking)
|
||||
bool pca95xx_set_output(struct pca95xx *dev, uint8_t mask, bool blocking)
|
||||
{
|
||||
if (dev->i2c_trans.status != I2CTransDone &&
|
||||
dev->i2c_trans.status != I2CTransSuccess &&
|
||||
@@ -65,7 +65,7 @@ bool pca95x4_set_output(struct pca95x4 *dev, uint8_t mask, bool blocking)
|
||||
return false; // previous transaction not finished
|
||||
}
|
||||
// send mask value
|
||||
dev->i2c_trans.buf[0] = PCA95X4_OUTPUT_REG;
|
||||
dev->i2c_trans.buf[0] = PCA95XX_OUTPUT_REG;
|
||||
dev->i2c_trans.buf[1] = mask;
|
||||
if (blocking) {
|
||||
return i2c_blocking_transmit(dev->i2c_p, &dev->i2c_trans, dev->i2c_trans.slave_addr, 2);
|
||||
@@ -74,3 +74,17 @@ bool pca95x4_set_output(struct pca95x4 *dev, uint8_t mask, bool blocking)
|
||||
}
|
||||
}
|
||||
|
||||
// Get input function
|
||||
bool pca95xx_get_input(struct pca95xx *dev, uint8_t mask, uint8_t *result) {
|
||||
if (dev->i2c_trans.status != I2CTransDone &&
|
||||
dev->i2c_trans.status != I2CTransSuccess &&
|
||||
dev->i2c_trans.status != I2CTransFailed) {
|
||||
return false; // previous transaction not finished
|
||||
}
|
||||
// get input register
|
||||
dev->i2c_trans.buf[0] = PCA95XX_INPUT_REG;
|
||||
bool ret = i2c_blocking_transceive(dev->i2c_p, &dev->i2c_trans, dev->i2c_trans.slave_addr, 1, 1);
|
||||
*result = dev->i2c_trans.buf[0] & mask;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -19,64 +19,73 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file peripherals/pca95x4.h
|
||||
* @file peripherals/pca95xx.h
|
||||
*
|
||||
* Driver for the 8-bit I/O expander based on i2c
|
||||
*/
|
||||
|
||||
#ifndef PCA95X4_H
|
||||
#define PCA95X4_H
|
||||
#ifndef PCA95XX_H
|
||||
#define PCA95XX_H
|
||||
|
||||
#include "std.h"
|
||||
#include "mcu_periph/i2c.h"
|
||||
|
||||
#define PCA95X4_DEFAULT_ADDRESS 0x40
|
||||
#define PCA95XX_DEFAULT_ADDRESS 0x40
|
||||
|
||||
#define PCA95X4_INPUT_REG (0x00)
|
||||
#define PCA95X4_OUTPUT_REG (0x01)
|
||||
#define PCA95X4_POL_REG (0x02)
|
||||
#define PCA95X4_CONFIG_REG (0x03)
|
||||
#define PCA95XX_INPUT_REG (0x00)
|
||||
#define PCA95XX_OUTPUT_REG (0x01)
|
||||
#define PCA95XX_POL_REG (0x02)
|
||||
#define PCA95XX_CONFIG_REG (0x03)
|
||||
|
||||
#define PCA95X4_P0 (1 << 0)
|
||||
#define PCA95X4_P1 (1 << 1)
|
||||
#define PCA95X4_P2 (1 << 2)
|
||||
#define PCA95X4_P3 (1 << 3)
|
||||
#define PCA95X4_P4 (1 << 4)
|
||||
#define PCA95X4_P5 (1 << 5)
|
||||
#define PCA95X4_P6 (1 << 6)
|
||||
#define PCA95X4_P7 (1 << 7)
|
||||
#define PCA95XX_P0 (1 << 0)
|
||||
#define PCA95XX_P1 (1 << 1)
|
||||
#define PCA95XX_P2 (1 << 2)
|
||||
#define PCA95XX_P3 (1 << 3)
|
||||
#define PCA95XX_P4 (1 << 4)
|
||||
#define PCA95XX_P5 (1 << 5)
|
||||
#define PCA95XX_P6 (1 << 6)
|
||||
#define PCA95XX_P7 (1 << 7)
|
||||
|
||||
#define PCA95X4_CLEAR_ALL 0x00
|
||||
#define PCA95XX_CLEAR_ALL 0x00
|
||||
|
||||
/** PCA95X4 structure
|
||||
/** PCA95XX structure
|
||||
*/
|
||||
struct pca95x4 {
|
||||
struct pca95xx {
|
||||
struct i2c_periph *i2c_p;
|
||||
struct i2c_transaction i2c_trans;
|
||||
};
|
||||
|
||||
/** Init PCA95X4
|
||||
* @param [in] dev address to pca95x4 device
|
||||
/** Init PCA95XX
|
||||
* @param [in] dev address to pca95xx device
|
||||
* @param [in] i2c_p addres of i2c bus
|
||||
* @param [in] addr i2c address
|
||||
*/
|
||||
extern void pca95x4_init(struct pca95x4 *dev, struct i2c_periph *i2c_p, uint8_t addr);
|
||||
extern void pca95xx_init(struct pca95xx *dev, struct i2c_periph *i2c_p, uint8_t addr);
|
||||
|
||||
/** Configure PCA95X4
|
||||
* @param [in] dev address to pca95x4 device
|
||||
/** Configure PCA95XX
|
||||
* @param [in] dev address to pca95xx device
|
||||
* @param [in] val value to write to confi register
|
||||
* @param [in] blocking true for blocking i2c transaction
|
||||
* @return false if i2c was not ready or transaction submit fails or timeout (blocking)
|
||||
*/
|
||||
extern bool pca95x4_configure(struct pca95x4 *dev, uint8_t val, bool blocking);
|
||||
extern bool pca95xx_configure(struct pca95xx *dev, uint8_t val, bool blocking);
|
||||
|
||||
/** Set output value
|
||||
* @param [in] dev address to pca95x4 device
|
||||
* @param [in] dev address to pca95xx device
|
||||
* @param [in] mask output pins to set
|
||||
* @param [in] blocking true for blocking i2c transaction
|
||||
* @return false if i2c was not ready or transaction submit fails or timeout (blocking)
|
||||
*/
|
||||
extern bool pca95x4_set_output(struct pca95x4 *dev, uint8_t mask, bool blocking);
|
||||
extern bool pca95xx_set_output(struct pca95xx *dev, uint8_t mask, bool blocking);
|
||||
|
||||
/** Get input value
|
||||
* @param [in] dev address to pca95xx device
|
||||
* @param [in] mask input pins
|
||||
* @param [out] input register with mask applied
|
||||
* Note: always blocking
|
||||
* @return false if i2c was not ready or transaction submit fails or timeout (blocking)
|
||||
*/
|
||||
extern bool pca95xx_get_input(struct pca95xx *dev, uint8_t mask, uint8_t *result);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user