784 lines
29 KiB
C
784 lines
29 KiB
C
/*
|
|
* Copyright (c) 2019-2021, Erich Styger
|
|
*
|
|
* Driver for GPIO pins
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "McuLibconfig.h"
|
|
#include "McuGPIO.h"
|
|
#include "McuUtility.h"
|
|
#include "McuLog.h"
|
|
#include <stddef.h>
|
|
#include <string.h> /* for memset */
|
|
#include <assert.h>
|
|
#if MCUGPIO_CONFIG_USE_FREERTOS_HEAP
|
|
#include "McuRTOS.h"
|
|
#else
|
|
#include <stdlib.h> /* for malloc()/free() */
|
|
#endif
|
|
#if McuLib_CONFIG_NXP_SDK_USED
|
|
#include "fsl_gpio.h"
|
|
#elif McuLib_CONFIG_CPU_IS_STM32
|
|
/* nothing special needed */
|
|
#endif
|
|
#if McuLib_CONFIG_CPU_IS_KINETIS
|
|
#include "fsl_port.h"
|
|
#elif McuLib_CONFIG_CPU_IS_LPC
|
|
#include "fsl_iocon.h"
|
|
#elif McuLib_CONFIG_CPU_IS_IMXRT
|
|
#include "fsl_iomuxc.h"
|
|
#elif McuLib_CONFIG_CPU_IS_STM32
|
|
#include "stm32f3xx_hal.h"
|
|
#elif McuLib_CONFIG_CPU_IS_ESP32
|
|
#include "driver/gpio.h"
|
|
#elif McuLib_CONFIG_CPU_IS_RPxxxx
|
|
#include "hardware/gpio.h"
|
|
#elif McuLib_CONFIG_CPU_IS_MCX
|
|
#include "fsl_port.h"
|
|
#endif
|
|
|
|
#if McuLib_CONFIG_CPU_IS_LPC && McuLib_CONFIG_CORTEX_M==0 /* LPC845 specific defines, not available in SDK */
|
|
#define McuGPIO_IOCON_PIO_CLKDIV0 0x00u /*!<@brief IOCONCLKDIV0 */
|
|
#define McuGPIO_IOCON_PIO_HYS_EN 0x20u /*!<@brief Enable hysteresis */
|
|
#define McuGPIO_IOCON_PIO_INV_DI 0x00u /*!<@brief Input not invert */
|
|
|
|
#define McuGPIO_IOCON_PIO_MODE_PULL_INACTIVE (0x0u<<3) /* Inactive (no pull-down/pull-up resistor enabled) */
|
|
#define McuGPIO_IOCON_PIO_MODE_PULL_DOWN (0x1u<<3) /* Pull-down enabled */
|
|
#define McuGPIO_IOCON_PIO_MODE_PULL_UP (0x2u<<3) /* Pull-up enabled */
|
|
#define McuGPIO_IOCON_PIO_MODE_PULL_REPEATER (0x3u<<3) /* Repeater mode */
|
|
|
|
#define McuGPIO_IOCON_PIO_OD_DI 0x00u /*!<@brief Disables Open-drain function */
|
|
#define McuGPIO_IOCON_PIO_SMODE_BYPASS 0x00u /*!<@brief Bypass input filter */
|
|
|
|
#define McuGPIO_IOCON_PIO_DEFAULTS \
|
|
/* Enable hysteresis */ \
|
|
McuGPIO_IOCON_PIO_HYS_EN | \
|
|
/* Input not invert */ \
|
|
McuGPIO_IOCON_PIO_INV_DI | \
|
|
/* Disables Open-drain function */ \
|
|
McuGPIO_IOCON_PIO_OD_DI | \
|
|
/* Bypass input filter */ \
|
|
McuGPIO_IOCON_PIO_SMODE_BYPASS | \
|
|
/* IOCONCLKDIV0 */ \
|
|
McuGPIO_IOCON_PIO_CLKDIV0
|
|
#endif
|
|
|
|
/* default configuration, used for initializing the config */
|
|
static const McuGPIO_Config_t defaultConfig =
|
|
{
|
|
.isInput = true,
|
|
.isHighOnInit = false,
|
|
.hw = {
|
|
#if McuLib_CONFIG_NXP_SDK_USED && !McuLib_CONFIG_IS_KINETIS_KE
|
|
.gpio = NULL,
|
|
#elif McuLib_CONFIG_CPU_IS_STM32
|
|
.gpio = NULL,
|
|
#elif McuLib_CONFIG_SDK_VERSION_USED==McuLib_CONFIG_SDK_LINUX
|
|
.name = "",
|
|
#endif
|
|
#if McuLib_CONFIG_CPU_IS_KINETIS
|
|
.port = 0,
|
|
#if McuLib_CONFIG_IS_KINETIS_KE
|
|
.portType = 0,
|
|
.portNum = 0,
|
|
#endif
|
|
#elif McuLib_CONFIG_CPU_IS_LPC && McuLib_CONFIG_CORTEX_M==0
|
|
.port = 0,
|
|
.iocon = -1,
|
|
#elif McuLib_CONFIG_CPU_IS_LPC
|
|
.port = 0,
|
|
#elif McuLib_CONFIG_CPU_IS_MCX
|
|
.port = NULL, /* e.g. PORT0 */
|
|
#endif
|
|
#if McuLib_CONFIG_CPU_IS_ESP32
|
|
.pin = GPIO_NUM_NC,
|
|
#else
|
|
.pin = 0,
|
|
#endif
|
|
.pull = McuGPIO_PULL_DISABLE,
|
|
}
|
|
};
|
|
|
|
typedef struct McuGPIO_t {
|
|
#if McuLib_CONFIG_CPU_IS_ESP32
|
|
bool isHigh; /* status of output pin, because we cannot toggle pin and we cannot read pin status if it is output pin */
|
|
#endif
|
|
#if McuLib_CONFIG_SDK_VERSION_USED==McuLib_CONFIG_SDK_LINUX
|
|
struct gpiod_line *line; /* will be requested with gpiod_chip_get_line() */
|
|
bool isHigh; /* status of output pin, because we cannot toggle pin and we cannot read pin status if it is output pin */
|
|
#endif
|
|
bool isInput;
|
|
McuGPIO_HwPin_t hw;
|
|
} McuGPIO_t;
|
|
|
|
void McuGPIO_GetDefaultConfig(McuGPIO_Config_t *config) {
|
|
assert(config!=NULL);
|
|
memcpy(config, &defaultConfig, sizeof(*config));
|
|
}
|
|
|
|
static void McuGPIO_ConfigurePin(McuGPIO_t *pin, bool isInput, bool isHighOnInit) {
|
|
#if McuLib_CONFIG_NXP_SDK_USED
|
|
gpio_pin_config_t pin_config; /* config for the SDK */
|
|
|
|
memset(&pin_config, 0, sizeof(pin_config)); /* init all fields */
|
|
if (isInput) {
|
|
#if McuLib_CONFIG_CPU_IS_IMXRT
|
|
pin_config.direction = kGPIO_DigitalInput;
|
|
#else
|
|
pin_config.pinDirection = kGPIO_DigitalInput;
|
|
#endif
|
|
} else {
|
|
#if McuLib_CONFIG_CPU_IS_IMXRT
|
|
pin_config.direction = kGPIO_DigitalOutput;
|
|
#else
|
|
pin_config.pinDirection = kGPIO_DigitalOutput;
|
|
#endif
|
|
}
|
|
#if McuLib_CONFIG_CPU_IS_IMXRT
|
|
pin_config.interruptMode = kGPIO_NoIntmode; /* no interrupts */
|
|
#endif
|
|
pin_config.outputLogic = isHighOnInit;
|
|
#if McuLib_CONFIG_IS_KINETIS_KE
|
|
GPIO_PinInit(pin->hw.portNum, pin->hw.pin, &pin_config);
|
|
#elif McuLib_CONFIG_CPU_IS_KINETIS
|
|
GPIO_PinInit(pin->hw.gpio, pin->hw.pin, &pin_config);
|
|
#elif McuLib_CONFIG_CPU_IS_LPC
|
|
GPIO_PinInit(pin->hw.gpio, pin->hw.port, pin->hw.pin, &pin_config);
|
|
#elif McuLib_CONFIG_CPU_IS_IMXRT
|
|
GPIO_PinInit(pin->hw.gpio, pin->hw.pin, &pin_config);
|
|
#elif McuLib_CONFIG_CPU_IS_MCX
|
|
GPIO_PinInit(pin->hw.gpio, pin->hw.pin, &pin_config);
|
|
#endif
|
|
#elif McuLib_CONFIG_CPU_IS_STM32
|
|
GPIO_InitTypeDef config;
|
|
|
|
/* setup initialization structure */
|
|
config.Alternate = 0; /* init */
|
|
if (isInput) {
|
|
config.Mode = GPIO_MODE_INPUT; /* configure as input pin */
|
|
} else {
|
|
config.Mode = GPIO_MODE_OUTPUT_PP; /* configure as push/pull output pin */
|
|
}
|
|
switch(pin->hw.pull) {
|
|
case McuGPIO_PULL_DISABLE: config.Pull = GPIO_NOPULL; break;
|
|
case McuGPIO_PULL_UP: config.Pull = GPIO_PULLUP; break;
|
|
case McuGPIO_PULL_DOWN: config.Pull = GPIO_PULLDOWN; break;
|
|
}
|
|
config.Speed = GPIO_SPEED_FREQ_LOW;
|
|
config.Pin = pin->hw.pin;
|
|
HAL_GPIO_Init(pin->hw.gpio, &config);
|
|
/* write default output level */
|
|
if (!isInput) {
|
|
HAL_GPIO_WritePin(pin->hw.gpio, pin->hw.pin, isHighOnInit?GPIO_PIN_SET:GPIO_PIN_RESET);
|
|
}
|
|
#elif McuLib_CONFIG_CPU_IS_ESP32
|
|
if (gpio_reset_pin(pin->hw.pin)!=ESP_OK) {
|
|
McuLog_fatal("failed resetting pin");
|
|
}
|
|
if (isInput) {
|
|
gpio_set_direction(pin->hw.pin, GPIO_MODE_INPUT);
|
|
} else {
|
|
gpio_set_direction(pin->hw.pin, GPIO_MODE_OUTPUT);
|
|
}
|
|
switch(pin->hw.pull) {
|
|
case McuGPIO_PULL_DISABLE: gpio_set_pull_mode(pin->hw.pin, GPIO_FLOATING); break;
|
|
case McuGPIO_PULL_UP: gpio_set_pull_mode(pin->hw.pin, GPIO_PULLUP_ONLY); break;
|
|
case McuGPIO_PULL_DOWN: gpio_set_pull_mode(pin->hw.pin, GPIO_PULLDOWN_ONLY); break;
|
|
}
|
|
if (!isInput) {
|
|
gpio_set_level(pin->hw.pin, isHighOnInit?1:0);
|
|
pin->isHigh = isHighOnInit;
|
|
}
|
|
#elif McuLib_CONFIG_CPU_IS_RPxxxx
|
|
if (!isInput) { /* set output level first */
|
|
gpio_put(pin->hw.pin, isHighOnInit); /* set initial logic level */
|
|
}
|
|
if (isInput) {
|
|
gpio_set_dir(pin->hw.pin, GPIO_IN);
|
|
} else {
|
|
gpio_set_dir(pin->hw.pin, GPIO_OUT);
|
|
}
|
|
#elif McuLib_CONFIG_SDK_VERSION_USED==McuLib_CONFIG_SDK_LINUX
|
|
pin->line = gpiod_chip_get_line(pin->hw.chip, pin->hw.pin);
|
|
if (isInput) {
|
|
gpiod_line_request_input(pin->line, pin->hw.name);
|
|
} else {
|
|
gpiod_line_request_output(pin->line, pin->hw.name, isHighOnInit);
|
|
}
|
|
if (!isInput) {
|
|
gpiod_line_set_value(pin->line, isHighOnInit?1:0);
|
|
pin->isHigh = isHighOnInit;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void McuGPIO_SetAsInput(McuGPIO_Handle_t gpio) {
|
|
McuGPIO_t *pin = (McuGPIO_t*)gpio;
|
|
|
|
assert(gpio!=NULL);
|
|
McuGPIO_ConfigurePin(pin, true, false /* don't care */);
|
|
pin->isInput = true;
|
|
}
|
|
|
|
void McuGPIO_SetAsOutput(McuGPIO_Handle_t gpio, bool setHigh) {
|
|
McuGPIO_t *pin = (McuGPIO_t*)gpio;
|
|
|
|
assert(gpio!=NULL);
|
|
McuGPIO_ConfigurePin(pin, false, setHigh);
|
|
pin->isInput = false;
|
|
}
|
|
|
|
bool McuGPIO_IsInput(McuGPIO_Handle_t gpio) {
|
|
McuGPIO_t *pin = (McuGPIO_t*)gpio;
|
|
return pin->isInput;
|
|
}
|
|
|
|
bool McuGPIO_IsOutput(McuGPIO_Handle_t gpio) {
|
|
McuGPIO_t *pin = (McuGPIO_t*)gpio;
|
|
return !pin->isInput;
|
|
}
|
|
|
|
#if McuLib_CONFIG_CPU_IS_IMXRT
|
|
void McuGPIO_SetMux(McuGPIO_HwPin_t *hw, uint32_t muxRegister, uint32_t muxMode, uint32_t inputRegister, uint32_t inputDaisy, uint32_t configRegister) {
|
|
hw->mux.muxRegister = muxRegister;
|
|
hw->mux.muxMode = muxMode;
|
|
hw->mux.inputRegister = inputRegister;
|
|
hw->mux.inputDaisy = inputDaisy;
|
|
hw->mux.configRegister = configRegister;
|
|
}
|
|
#endif
|
|
|
|
McuGPIO_Handle_t McuGPIO_InitGPIO(McuGPIO_Config_t *config) {
|
|
McuGPIO_t *handle;
|
|
|
|
assert(config!=NULL);
|
|
/* allocate memory for handle */
|
|
#if MCUGPIO_CONFIG_USE_FREERTOS_HEAP
|
|
handle = (McuGPIO_t*)pvPortMalloc(sizeof(McuGPIO_t)); /* get a new device descriptor */
|
|
#else
|
|
handle = (McuGPIO_t*)malloc(sizeof(McuGPIO_t)); /* get a new device descriptor */
|
|
#endif
|
|
assert(handle!=NULL);
|
|
if (handle!=NULL) { /* if malloc failed, will return NULL pointer */
|
|
memset(handle, 0, sizeof(McuGPIO_t)); /* init all fields */
|
|
handle->isInput = config->isInput;
|
|
memcpy(&handle->hw, &config->hw, sizeof(handle->hw)); /* copy hardware information */
|
|
}
|
|
#if McuLib_CONFIG_CPU_IS_RPxxxx
|
|
gpio_init(config->hw.pin);
|
|
#endif
|
|
McuGPIO_ConfigurePin(handle, config->isInput, config->isHighOnInit);
|
|
McuGPIO_SetPullResistor((McuGPIO_Handle_t)handle, config->hw.pull); /* GPIO muxing might be done with setting the pull registers, e.g. for LPC845 */
|
|
|
|
/* do the pin muxing */
|
|
#if McuLib_CONFIG_IS_KINETIS_KE
|
|
/* no pin muxing needed */
|
|
#elif McuLib_CONFIG_CPU_IS_KINETIS
|
|
PORT_SetPinMux(config->hw.port, config->hw.pin, kPORT_MuxAsGpio);
|
|
#elif McuLib_CONFIG_CPU_IS_LPC && McuLib_CONFIG_CORTEX_M==0 /* e.g. LPC845 */
|
|
/* nothing needed here, because IOCON_PinMuxSet() is already called with the McuGPIO_SetPullResistor() above. */
|
|
#elif McuLib_CONFIG_CPU_IS_LPC && McuLib_CONFIG_CORTEX_M==33 /* LPC55S69 for LPC55S16 */
|
|
#define _IOCON_PIO_DIGITAL_EN 0x0100u /*!<@brief Enables digital function */
|
|
#define _IOCON_PIO_FUNC0 0x00u /*!<@brief Selects pin function 0 */
|
|
#define _IOCON_PIO_INV_DI 0x00u /*!<@brief Input function is not inverted */
|
|
#define _IOCON_PIO_MODE_PULLUP 0x20u /*!<@brief Selects pull-up function */
|
|
#define _IOCON_PIO_OPENDRAIN_DI 0x00u /*!<@brief Open drain is disabled */
|
|
#define _IOCON_PIO_SLEW_STANDARD 0x00u /*!<@brief Standard mode, output slew rate control is enabled */
|
|
|
|
static const uint32_t port_pin_config = (
|
|
_IOCON_PIO_FUNC0 |
|
|
/* Selects pull-up function */
|
|
_IOCON_PIO_MODE_PULLUP |
|
|
/* Standard mode, output slew rate control is enabled */
|
|
_IOCON_PIO_SLEW_STANDARD |
|
|
/* Input function is not inverted */
|
|
_IOCON_PIO_INV_DI |
|
|
/* Enables digital function */
|
|
_IOCON_PIO_DIGITAL_EN |
|
|
/* Open drain is disabled */
|
|
_IOCON_PIO_OPENDRAIN_DI);
|
|
IOCON_PinMuxSet(IOCON, config->hw.port, config->hw.pin, port_pin_config);
|
|
#elif McuLib_CONFIG_CPU_IS_IMXRT
|
|
IOMUXC_SetPinMux( handle->hw.mux.muxRegister,
|
|
handle->hw.mux.muxMode,
|
|
handle->hw.mux.inputRegister,
|
|
handle->hw.mux.inputDaisy,
|
|
handle->hw.mux.configRegister,
|
|
0U);
|
|
#if McuLib_CONFIG_CPU_VARIANT==McuLib_CONFIG_CPU_VARIANT_NXP_IMXRT1064
|
|
/* GPIO1 and GPIO6 share same IO MUX function, configured in GPR26 */
|
|
if (handle->hw.gpio==GPIO1) {
|
|
IOMUXC_GPR->GPR26 &= ~(1<<handle->hw.pin); /* 0: GPIO1, 1: GPIO6 */
|
|
} else if (handle->hw.gpio==GPIO6) {
|
|
IOMUXC_GPR->GPR26 |= (1<<handle->hw.pin); /* 0: GPIO1, 1: GPIO6 */
|
|
|
|
/* GPIO2 and GPIO7 share same IO MUX function, configured in GPR27 */
|
|
} else if (handle->hw.gpio==GPIO2) {
|
|
IOMUXC_GPR->GPR27 &= (1<<handle->hw.pin); /* 0: GPIO2, 1: GPIO7 */
|
|
} else if (handle->hw.gpio==GPIO7) {
|
|
IOMUXC_GPR->GPR27 |= (1<<handle->hw.pin); /* 0: GPIO2, 1: GPIO7 */
|
|
|
|
/* GPIO3 and GPIO8 share same IO MUX function, configured in GPR28 */
|
|
} else if (handle->hw.gpio==GPIO3) {
|
|
IOMUXC_GPR->GPR28 &= (1<<handle->hw.pin); /* 0: GPIO3, 1: GPIO8 */
|
|
} else if (handle->hw.gpio==GPIO8) {
|
|
IOMUXC_GPR->GPR28 |= (1<<handle->hw.pin); /* 0: GPIO3, 1: GPIO8 */
|
|
|
|
/* GPIO4 and GPIO9 share same IO MUX function, configured in GPR29 */
|
|
} else if (handle->hw.gpio==GPIO4) {
|
|
IOMUXC_GPR->GPR29 &= (1<<handle->hw.pin); /* 0: GPIO4, 1: GPIO9 */
|
|
} else if (handle->hw.gpio==GPIO9) {
|
|
IOMUXC_GPR->GPR29 |= (1<<handle->hw.pin); /* 0: GPIO4, 1: GPIO9 */
|
|
}
|
|
#endif /* McuLib_CONFIG_CPU_VARIANT_NXP_IMXRT1064 */
|
|
#elif McuLib_CONFIG_CPU_IS_STM32
|
|
/* no muxing */
|
|
#elif McuLib_CONFIG_CPU_IS_ESP32
|
|
/* no muxing needed */
|
|
#elif McuLib_CONFIG_CPU_IS_RPxxxx
|
|
/* no muxing needed */
|
|
#elif McuLib_CONFIG_SDK_VERSION_USED==McuLib_CONFIG_SDK_LINUX
|
|
/* no muxing needed */
|
|
#endif
|
|
return (McuGPIO_Handle_t)handle;
|
|
}
|
|
|
|
McuGPIO_Handle_t McuGPIO_DeinitGPIO(McuGPIO_Handle_t gpio) {
|
|
assert(gpio!=NULL);
|
|
#if McuLib_CONFIG_SDK_VERSION_USED==McuLib_CONFIG_SDK_LINUX
|
|
McuGPIO_t *pin = (McuGPIO_t*)gpio;
|
|
gpiod_line_release(pin->line);
|
|
#elif McuLib_CONFIG_CPU_IS_RPxxxx
|
|
McuGPIO_t *pin = (McuGPIO_t*)gpio;
|
|
gpio_deinit(pin->hw.pin);
|
|
#endif
|
|
#if MCUGPIO_CONFIG_USE_FREERTOS_HEAP
|
|
vPortFree(gpio);
|
|
#else
|
|
free(gpio);
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
void McuGPIO_SetLow(McuGPIO_Handle_t gpio) {
|
|
assert(gpio!=NULL);
|
|
McuGPIO_t *pin = (McuGPIO_t*)gpio;
|
|
|
|
#if McuLib_CONFIG_CPU_IS_KINETIS
|
|
#if McuLib_CONFIG_SDK_VERSION < 250
|
|
GPIO_ClearPinsOutput(pin->hw.gpio, (1<<pin->hw.pin));
|
|
#elif McuLib_CONFIG_IS_KINETIS_KE
|
|
GPIO_PortClear(pin->hw.portNum, (1<<pin->hw.pin));
|
|
#else
|
|
GPIO_PortClear(pin->hw.gpio, (1<<pin->hw.pin));
|
|
#endif
|
|
#elif McuLib_CONFIG_CPU_IS_LPC
|
|
GPIO_PortClear(pin->hw.gpio, pin->hw.port, (1<<pin->hw.pin));
|
|
#elif McuLib_CONFIG_CPU_IS_IMXRT
|
|
GPIO_PinWrite(pin->hw.gpio, pin->hw.pin, 0U);
|
|
#elif McuLib_CONFIG_CPU_IS_STM32
|
|
HAL_GPIO_WritePin(pin->hw.gpio, pin->hw.pin, GPIO_PIN_RESET);
|
|
#elif McuLib_CONFIG_CPU_IS_ESP32
|
|
gpio_set_level(pin->hw.pin, 0); /* low */
|
|
pin->isHigh = false;
|
|
#elif McuLib_CONFIG_CPU_IS_RPxxxx
|
|
gpio_put(pin->hw.pin, 0);
|
|
#elif McuLib_CONFIG_SDK_VERSION_USED==McuLib_CONFIG_SDK_LINUX
|
|
gpiod_line_set_value(pin->line, 0);
|
|
pin->isHigh = false;
|
|
#elif McuLib_CONFIG_CPU_IS_MCX
|
|
GPIO_PinWrite(pin->hw.gpio, pin->hw.pin, 0);
|
|
#endif
|
|
}
|
|
|
|
void McuGPIO_SetHigh(McuGPIO_Handle_t gpio) {
|
|
assert(gpio!=NULL);
|
|
McuGPIO_t *pin = (McuGPIO_t*)gpio;
|
|
|
|
#if McuLib_CONFIG_CPU_IS_KINETIS
|
|
#if McuLib_CONFIG_SDK_VERSION < 250
|
|
GPIO_SetPinsOutput(pin->hw.gpio, (1<<pin->hw.pin));
|
|
#elif McuLib_CONFIG_IS_KINETIS_KE
|
|
GPIO_PortSet(pin->hw.portNum, (1<<pin->hw.pin));
|
|
#else
|
|
GPIO_PortSet(pin->hw.gpio, (1<<pin->hw.pin));
|
|
#endif
|
|
#elif McuLib_CONFIG_CPU_IS_LPC
|
|
GPIO_PortSet(pin->hw.gpio, pin->hw.port, (1<<pin->hw.pin));
|
|
#elif McuLib_CONFIG_CPU_IS_IMXRT
|
|
GPIO_PinWrite(pin->hw.gpio, pin->hw.pin, 1U);
|
|
#elif McuLib_CONFIG_CPU_IS_STM32
|
|
HAL_GPIO_WritePin(pin->hw.gpio, pin->hw.pin, GPIO_PIN_SET);
|
|
#elif McuLib_CONFIG_CPU_IS_ESP32
|
|
gpio_set_level(pin->hw.pin, 1); /* high */
|
|
pin->isHigh = true;
|
|
#elif McuLib_CONFIG_CPU_IS_RPxxxx
|
|
gpio_put(pin->hw.pin, 1);
|
|
#elif McuLib_CONFIG_SDK_VERSION_USED==McuLib_CONFIG_SDK_LINUX
|
|
gpiod_line_set_value(pin->line, 1);
|
|
pin->isHigh = true;
|
|
#elif McuLib_CONFIG_CPU_IS_MCX
|
|
GPIO_PinWrite(pin->hw.gpio, pin->hw.pin, 1);
|
|
#endif
|
|
}
|
|
|
|
void McuGPIO_Toggle(McuGPIO_Handle_t gpio) {
|
|
assert(gpio!=NULL);
|
|
McuGPIO_t *pin = (McuGPIO_t*)gpio;
|
|
|
|
#if McuLib_CONFIG_CPU_IS_KINETIS
|
|
#if McuLib_CONFIG_SDK_VERSION < 250
|
|
GPIO_TogglePinsOutput(pin->hw.gpio, (1<<pin->hw.pin));
|
|
#elif McuLib_CONFIG_IS_KINETIS_KE
|
|
GPIO_PortToggle(pin->hw.portNum, (1<<pin->hw.pin));
|
|
#else
|
|
GPIO_PortToggle(pin->hw.gpio, (1<<pin->hw.pin));
|
|
#endif
|
|
#elif McuLib_CONFIG_CPU_IS_LPC
|
|
GPIO_PortToggle(pin->hw.gpio, pin->hw.port, (1<<pin->hw.pin));
|
|
#elif McuLib_CONFIG_CPU_IS_IMXRT
|
|
GPIO_PortToggle(pin->hw.gpio, (1<<pin->hw.pin));
|
|
#elif McuLib_CONFIG_CPU_IS_STM32
|
|
HAL_GPIO_TogglePin(pin->hw.gpio, pin->hw.pin);
|
|
#elif McuLib_CONFIG_CPU_IS_ESP32
|
|
if (pin->isHigh) {
|
|
gpio_set_level(pin->hw.pin, 0);
|
|
pin->isHigh = false;
|
|
} else {
|
|
gpio_set_level(pin->hw.pin, 1);
|
|
pin->isHigh = true;
|
|
}
|
|
#elif McuLib_CONFIG_CPU_IS_RPxxxx
|
|
gpio_xor_mask(1<<pin->hw.pin);
|
|
#elif McuLib_CONFIG_SDK_VERSION_USED==McuLib_CONFIG_SDK_LINUX
|
|
if (pin->isHigh) {
|
|
gpiod_line_set_value(pin->line, 0);
|
|
pin->isHigh = false;
|
|
} else {
|
|
gpiod_line_set_value(pin->line, 1);
|
|
pin->isHigh = true;
|
|
}
|
|
#elif McuLib_CONFIG_CPU_IS_MCX
|
|
GPIO_PortToggle(pin->hw.gpio, 1<<pin->hw.pin);
|
|
#endif
|
|
}
|
|
|
|
void McuGPIO_SetValue(McuGPIO_Handle_t gpio, bool val) {
|
|
assert(gpio!=NULL);
|
|
McuGPIO_t *pin = (McuGPIO_t*)gpio;
|
|
|
|
if (val) { /* set to HIGH */
|
|
#if McuLib_CONFIG_CPU_IS_KINETIS
|
|
#if McuLib_CONFIG_SDK_VERSION < 250
|
|
GPIO_SetPinsOutput(pin->hw.gpio, (1<<pin->hw.pin));
|
|
#elif McuLib_CONFIG_IS_KINETIS_KE
|
|
GPIO_PortSet(pin->hw.portNum, (1<<pin->hw.pin));
|
|
#else
|
|
GPIO_PortSet(pin->hw.gpio, (1<<pin->hw.pin));
|
|
#endif
|
|
#elif McuLib_CONFIG_CPU_IS_LPC
|
|
GPIO_PortSet(pin->hw.gpio, pin->hw.port, (1<<pin->hw.pin));
|
|
#elif McuLib_CONFIG_CPU_IS_IMXRT
|
|
GPIO_PinWrite(pin->hw.gpio, pin->hw.pin, 1U);
|
|
#elif McuLib_CONFIG_CPU_IS_STM32
|
|
HAL_GPIO_WritePin(pin->hw.gpio, pin->hw.pin, GPIO_PIN_RESET);
|
|
#elif McuLib_CONFIG_CPU_IS_ESP32
|
|
gpio_set_level(pin->hw.pin, 1); /* high */
|
|
pin->isHigh = true;
|
|
#elif McuLib_CONFIG_CPU_IS_RPxxxx
|
|
gpio_put(pin->hw.pin, 1);
|
|
#elif McuLib_CONFIG_SDK_VERSION_USED==McuLib_CONFIG_SDK_LINUX
|
|
gpiod_line_set_value(pin->line, 0);
|
|
pin->isHigh = false;
|
|
#elif McuLib_CONFIG_CPU_IS_MCX
|
|
GPIO_PinWrite(pin->hw.gpio, pin->hw.pin, 1);
|
|
#endif
|
|
} else { /* set to LOW */
|
|
#if McuLib_CONFIG_CPU_IS_KINETIS
|
|
#if McuLib_CONFIG_SDK_VERSION < 250
|
|
GPIO_ClearPinsOutput(pin->hw.gpio, (1<<pin->hw.pin));
|
|
#elif McuLib_CONFIG_IS_KINETIS_KE
|
|
GPIO_PortClear(pin->hw.portNum, (1<<pin->hw.pin));
|
|
#else
|
|
GPIO_PortClear(pin->hw.gpio, (1<<pin->hw.pin));
|
|
#endif
|
|
#elif McuLib_CONFIG_CPU_IS_LPC
|
|
GPIO_PortClear(pin->hw.gpio, pin->hw.port, (1<<pin->hw.pin));
|
|
#elif McuLib_CONFIG_CPU_IS_IMXRT
|
|
GPIO_PinWrite(pin->hw.gpio, pin->hw.pin, 1U);
|
|
#elif McuLib_CONFIG_CPU_IS_STM32
|
|
HAL_GPIO_WritePin(pin->hw.gpio, pin->hw.pin, GPIO_PIN_SET);
|
|
#elif McuLib_CONFIG_CPU_IS_ESP32
|
|
gpio_set_level(pin->hw.pin, 0); /* low */
|
|
pin->isHigh = false;
|
|
#elif McuLib_CONFIG_CPU_IS_RPxxxx
|
|
gpio_put(pin->hw.pin, 0);
|
|
#elif McuLib_CONFIG_SDK_VERSION_USED==McuLib_CONFIG_SDK_LINUX
|
|
gpiod_line_set_value(pin->line, 1);
|
|
pin->isHigh = true;
|
|
#elif McuLib_CONFIG_CPU_IS_MCX
|
|
GPIO_PinWrite(pin->hw.gpio, pin->hw.pin, 0);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
bool McuGPIO_GetValue(McuGPIO_Handle_t gpio) {
|
|
return McuGPIO_IsHigh(gpio);
|
|
}
|
|
|
|
bool McuGPIO_IsHigh(McuGPIO_Handle_t gpio) {
|
|
assert(gpio!=NULL);
|
|
McuGPIO_t *pin = (McuGPIO_t*)gpio;
|
|
|
|
#if McuLib_CONFIG_CPU_IS_KINETIS
|
|
#if McuLib_CONFIG_SDK_VERSION < 250
|
|
return GPIO_ReadPinInput(pin->hw.gpio, pin->hw.pin)!=0;
|
|
#elif McuLib_CONFIG_IS_KINETIS_KE
|
|
return GPIO_PinRead(pin->hw.portNum, pin->hw.pin)!=0;
|
|
#else
|
|
return GPIO_PinRead(pin->hw.gpio, pin->hw.pin)!=0;
|
|
#endif
|
|
#elif McuLib_CONFIG_CPU_IS_LPC
|
|
return GPIO_PinRead(pin->hw.gpio, pin->hw.port, pin->hw.pin)!=0;
|
|
#elif McuLib_CONFIG_CPU_IS_IMXRT
|
|
return GPIO_PinRead(pin->hw.gpio, pin->hw.pin)!=0;
|
|
#elif McuLib_CONFIG_CPU_IS_STM32
|
|
return HAL_GPIO_ReadPin(pin->hw.gpio, pin->hw.pin);
|
|
#elif McuLib_CONFIG_CPU_IS_ESP32
|
|
if (pin->isInput) {
|
|
return gpio_get_level(pin->hw.pin);
|
|
} else { /* on ESP32, if pin is configured as output, gpio_get_level() always returns 0 */
|
|
return pin->isHigh;
|
|
}
|
|
#elif McuLib_CONFIG_CPU_IS_RPxxxx
|
|
return gpio_get(pin->hw.pin)!=0;
|
|
#elif McuLib_CONFIG_SDK_VERSION_USED==McuLib_CONFIG_SDK_LINUX
|
|
return gpiod_line_get_value(pin->line)!=0;
|
|
#elif McuLib_CONFIG_CPU_IS_MCX
|
|
return GPIO_PinRead(pin->hw.gpio, pin->hw.pin);
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
bool McuGPIO_IsLow(McuGPIO_Handle_t gpio) {
|
|
return !McuGPIO_IsHigh(gpio);
|
|
}
|
|
|
|
void McuGPIO_GetPinStatusString(McuGPIO_Handle_t gpio, unsigned char *buf, size_t bufSize) {
|
|
McuGPIO_t *pin = (McuGPIO_t*)gpio;
|
|
|
|
*buf = '\0';
|
|
if (McuGPIO_IsOutput(gpio)) {
|
|
McuUtility_strcat(buf, bufSize, (unsigned char*)"Out:");
|
|
} else {
|
|
McuUtility_strcat(buf, bufSize, (unsigned char*)"Inp:");
|
|
}
|
|
if (McuGPIO_IsHigh(gpio)) {
|
|
McuUtility_strcat(buf, bufSize, (unsigned char*)"H");
|
|
} else {
|
|
McuUtility_strcat(buf, bufSize, (unsigned char*)"L");
|
|
}
|
|
#if (McuLib_CONFIG_NXP_SDK_USED || McuLib_CONFIG_CPU_IS_STM32) && !McuLib_CONFIG_IS_KINETIS_KE
|
|
McuUtility_strcat(buf, bufSize, (unsigned char*)" gpio:0x");
|
|
McuUtility_strcatNum32Hex(buf, bufSize, (uint32_t)pin->hw.gpio); /* write address */
|
|
#endif
|
|
#if McuLib_CONFIG_CPU_IS_KINETIS
|
|
McuUtility_strcat(buf, bufSize, (unsigned char*)" port:0x");
|
|
McuUtility_strcatNum32Hex(buf, bufSize, (uint32_t)pin->hw.port); /* write address */
|
|
#elif McuLib_CONFIG_CPU_IS_LPC /* all LPC, including M33 and M0+ */
|
|
McuUtility_strcat(buf, bufSize, (unsigned char*)" port:");
|
|
McuUtility_strcatNum32u(buf, bufSize, (uint32_t)pin->hw.port); /* write port number */
|
|
#endif
|
|
McuUtility_strcat(buf, bufSize, (unsigned char*)" pin:");
|
|
McuUtility_strcatNum32u(buf, bufSize, (uint32_t)pin->hw.pin); /* write pin number */
|
|
#if McuLib_CONFIG_CPU_IS_LPC && McuLib_CONFIG_CORTEX_M==0
|
|
McuUtility_strcat(buf, bufSize, (unsigned char*)" iocon:");
|
|
McuUtility_strcatNum32u(buf, bufSize, (uint32_t)pin->hw.iocon); /* write IOCON number */
|
|
#endif
|
|
McuUtility_strcat(buf, bufSize, (unsigned char*)" pull:");
|
|
switch(pin->hw.pull) {
|
|
case McuGPIO_PULL_DISABLE:
|
|
McuUtility_strcat(buf, bufSize, (unsigned char*)"dis");
|
|
break;
|
|
case McuGPIO_PULL_UP:
|
|
McuUtility_strcat(buf, bufSize, (unsigned char*)"up ");
|
|
break;
|
|
case McuGPIO_PULL_DOWN:
|
|
McuUtility_strcat(buf, bufSize, (unsigned char*)"dwn");
|
|
break;
|
|
default:
|
|
McuUtility_strcat(buf, bufSize, (unsigned char*)"???");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void McuGPIO_SetPullResistor(McuGPIO_Handle_t gpio, McuGPIO_PullType pull) {
|
|
McuGPIO_t *pin = (McuGPIO_t*)gpio;
|
|
|
|
pin->hw.pull = pull;
|
|
#if McuLib_CONFIG_IS_KINETIS_KE
|
|
/* only pull-up */
|
|
if (pull == McuGPIO_PULL_DISABLE) {
|
|
PORT_SetPinPullUpEnable(pin->hw.port, pin->hw.portType, pin->hw.pin, false);
|
|
} else if (pull == McuGPIO_PULL_UP) {
|
|
PORT_SetPinPullUpEnable(pin->hw.port, pin->hw.portType, pin->hw.pin, true);
|
|
}
|
|
#elif McuLib_CONFIG_CPU_IS_KINETIS
|
|
/* mask out bits for Pull-Select, Pull-Enable and Interrupt status flags, then OR-ing the new flags */
|
|
if (pull == McuGPIO_PULL_DISABLE) {
|
|
pin->hw.port->PCR[pin->hw.pin] = ((pin->hw.port->PCR[pin->hw.pin] &
|
|
/* Mask bits to zero which are setting */
|
|
(~(PORT_PCR_PS_MASK | PORT_PCR_PE_MASK | PORT_PCR_ISF_MASK)))
|
|
| PORT_PCR_PE(0)); /* disable pull resistor */
|
|
} else if (pull == McuGPIO_PULL_UP) {
|
|
pin->hw.port->PCR[pin->hw.pin] = ((pin->hw.port->PCR[pin->hw.pin] &
|
|
/* Mask bits to zero which are setting */
|
|
(~(PORT_PCR_PS_MASK | PORT_PCR_PE_MASK | PORT_PCR_ISF_MASK)))
|
|
/* | PORT_PCR_PFE(1) */ /* enable passive filter */
|
|
| PORT_PCR_PS(1) /* pull select 1: pull-up */
|
|
| PORT_PCR_PE(1)); /* enable pull resistor */
|
|
} else if (pull == McuGPIO_PULL_DOWN) {
|
|
pin->hw.port->PCR[pin->hw.pin] = ((pin->hw.port->PCR[pin->hw.pin] &
|
|
/* Mask bits to zero which are setting */
|
|
(~(PORT_PCR_PS_MASK | PORT_PCR_PE_MASK | PORT_PCR_ISF_MASK)))
|
|
| PORT_PCR_PS(0) /* pull select 0: pull-down */
|
|
| PORT_PCR_PE(1)); /* enable pull resistor */
|
|
}
|
|
#elif McuLib_CONFIG_CPU_IS_LPC && McuLib_CONFIG_CORTEX_M==0 /* e.g. LPC845 */
|
|
uint32_t IOCON_config;
|
|
|
|
if (pull == McuGPIO_PULL_DISABLE) {
|
|
IOCON_config = ( McuGPIO_IOCON_PIO_MODE_PULL_INACTIVE | McuGPIO_IOCON_PIO_DEFAULTS);
|
|
} else if (pull == McuGPIO_PULL_UP) {
|
|
IOCON_config = ( McuGPIO_IOCON_PIO_MODE_PULL_UP | McuGPIO_IOCON_PIO_DEFAULTS);
|
|
} else if (pull == McuGPIO_PULL_DOWN) {
|
|
IOCON_config = ( McuGPIO_IOCON_PIO_MODE_PULL_DOWN | McuGPIO_IOCON_PIO_DEFAULTS);
|
|
} else {
|
|
IOCON_config = ( McuGPIO_IOCON_PIO_MODE_PULL_INACTIVE | McuGPIO_IOCON_PIO_DEFAULTS);
|
|
}
|
|
IOCON_PinMuxSet(IOCON, pin->hw.iocon, IOCON_config);
|
|
#elif McuLib_CONFIG_CPU_IS_LPC
|
|
uint32_t config;
|
|
|
|
/*! IOCON_PIO_MODE:
|
|
* MODE - Selects function mode (on-chip pull-up/pull-down resistor control).
|
|
* 0b00..Inactive. Inactive (no pull-down/pull-up resistor enabled).
|
|
* 0b01..Pull-down. Pull-down resistor enabled.
|
|
* 0b10..Pull-up. Pull-up resistor enabled.
|
|
* 0b11..Repeater. Repeater mode.
|
|
*/
|
|
if (pull == McuGPIO_PULL_DISABLE) {
|
|
config = IOCON_PIO_MODE(0b00); /* inactive */
|
|
} else if (pull == McuGPIO_PULL_UP) {
|
|
config = IOCON_PIO_MODE(0b10); /* pull-up */
|
|
} else if (pull == McuGPIO_PULL_DOWN) {
|
|
config = IOCON_PIO_MODE(0b01); /* pull-down */
|
|
} else { /* default */
|
|
config = IOCON_PIO_MODE(0b00); /* inactive */
|
|
}
|
|
IOCON->PIO[pin->hw.port][pin->hw.pin] = ((IOCON->PIO[pin->hw.port][pin->hw.pin] &
|
|
(~(IOCON_PIO_MODE_MASK))) /* Mask bits to zero which are setting */
|
|
| config); /* Select function mode (on-chip pull-up/pull-down resistor control) */
|
|
#elif McuLib_CONFIG_CPU_IS_IMXRT
|
|
if (pin->hw.mux.configRegister!=0) {
|
|
uint32_t configValue; /* configuration of IOMUXC SW_PAD_CTL (hw.mux.configRegister) */
|
|
|
|
configValue = *((volatile uint32_t *)pin->hw.mux.configRegister); /* read current config */
|
|
#if 0
|
|
configValue = (0<<16) /* Hysteresis enable field: 0: hysteresis disabled */
|
|
| (0b00<<14) /* pull-up/down: 00: 100k Ohm pull-down, 01: 47k pull-up, 10: 100k pull-up, 11: 22k pull-up */
|
|
| (0<<13) /* pull/keep select: 0: keeper, 1: pull */
|
|
| (0<<12) /* pull/keep enable: 0: disabled, 1: enabled */
|
|
| (0<<11) /* open drain: 0: disabled, 1: enabled */
|
|
| (0b00<<6) /* speed: 00: 50 MHz, 01: 100 MHz, 10: 100 MHz, 11: 200 MHz */
|
|
| (0b000<<3) /* drive strength: 000: disabled */
|
|
| (0<<0) /* slew rage: 0: slow slew rate, 1: fast slew rate */
|
|
;
|
|
#endif
|
|
/* masking out the bits we are going to set: */
|
|
configValue &= ~((0b11<<14) /* pull-up/down */
|
|
| (1<<13) /* pull/keep select: */
|
|
| (1<<12)); /* pull/keep enable */
|
|
if (pull == McuGPIO_PULL_DISABLE) {
|
|
configValue |= (0b00<<14) /* pull-up/down: 00: 100k Ohm pull-down, 01: 47k pull-up, 10: 100k pull-up, 11: 22k pull-up */
|
|
| (0<<13) /* pull/keep select: 0: keeper, 1: pull */
|
|
| (0<<12); /* pull/keep enable: 0: disabled, 1: enabled */
|
|
} else if (pull == McuGPIO_PULL_UP) { /* 100k pull-up */
|
|
configValue |= (0b10<<14) /* pull-up/down: 00: 100k Ohm pull-down, 01: 47k pull-up, 10: 100k pull-up, 11: 22k pull-up */
|
|
| (1<<13) /* pull/keep select: 0: keeper, 1: pull */
|
|
| (1<<12); /* pull/keep enable: 0: disabled, 1: enabled */
|
|
} else if (pull == McuGPIO_PULL_DOWN) { /* 100k pull-down */
|
|
configValue |= (0b00<<14) /* pull-up/down: 00: 100k Ohm pull-down, 01: 47k pull-up, 10: 100k pull-up, 11: 22k pull-up */
|
|
| (1<<13) /* pull/keep select: 0: keeper, 1: pull */
|
|
| (1<<12); /* pull/keep enable: 0: disabled, 1: enabled */
|
|
}
|
|
IOMUXC_SetPinConfig(pin->hw.mux.muxRegister,
|
|
pin->hw.mux.muxMode,
|
|
pin->hw.mux.inputRegister,
|
|
pin->hw.mux.inputDaisy,
|
|
pin->hw.mux.configRegister,
|
|
configValue);
|
|
}
|
|
#elif McuLib_CONFIG_CPU_IS_STM32
|
|
McuGPIO_ConfigurePin(pin, false /* don't care as only for output */, &pin->hw);
|
|
#elif McuLib_CONFIG_CPU_IS_ESP32
|
|
if (pull == McuGPIO_PULL_DISABLE) {
|
|
gpio_set_pull_mode(pin->hw.pin, GPIO_FLOATING);
|
|
} else if (pull == McuGPIO_PULL_UP) {
|
|
gpio_set_pull_mode(pin->hw.pin, GPIO_PULLUP_ONLY);
|
|
} else if (pull == McuGPIO_PULL_DOWN) {
|
|
gpio_set_pull_mode(pin->hw.pin, GPIO_PULLDOWN_ONLY);
|
|
}
|
|
#elif McuLib_CONFIG_CPU_IS_RPxxxx
|
|
if (pull == McuGPIO_PULL_DISABLE) {
|
|
gpio_disable_pulls(pin->hw.pin);
|
|
} else if (pull == McuGPIO_PULL_UP) {
|
|
gpio_pull_up(pin->hw.pin);
|
|
} else if (pull == McuGPIO_PULL_DOWN) {
|
|
gpio_pull_down(pin->hw.pin);
|
|
}
|
|
#elif McuLib_CONFIG_CPU_IS_MCX
|
|
port_pin_config_t config = {
|
|
.pullSelect=kPORT_PullDisable,
|
|
/* Low internal pull resistor value is selected. */
|
|
.pullValueSelect = kPORT_LowPullResistor,
|
|
/* Fast slew rate is configured */
|
|
.slewRate=kPORT_FastSlewRate,
|
|
/* Passive input filter is disabled */
|
|
.passiveFilterEnable=kPORT_PassiveFilterDisable,
|
|
/* Open drain output is disabled */
|
|
.openDrainEnable=kPORT_OpenDrainDisable,
|
|
/* Low drive strength is configured */
|
|
.driveStrength=kPORT_LowDriveStrength,
|
|
/* Pin is configured as PIO0_10 */
|
|
.mux=kPORT_MuxAlt0,
|
|
/* Digital input enabled */
|
|
.inputBuffer=kPORT_InputBufferEnable,
|
|
/* Digital input is not inverted */
|
|
.invertInput=kPORT_InputNormal,
|
|
/* Pin Control Register fields [15:0] are not locked */
|
|
.lockRegister=kPORT_UnlockRegister
|
|
};
|
|
if (pull == McuGPIO_PULL_DISABLE) {
|
|
config.pullSelect = kPORT_PullDisable; /* inactive */
|
|
} else if (pull == McuGPIO_PULL_UP) {
|
|
config.pullSelect = kPORT_PullUp; /* pull-up */
|
|
} else if (pull == McuGPIO_PULL_DOWN) {
|
|
config.pullSelect = kPORT_PullDown; /* pull-down */
|
|
} else { /* default */
|
|
config.pullSelect = kPORT_PullDisable; /* inactive */
|
|
}
|
|
PORT_SetPinConfig(pin->hw.port, pin->hw.pin, (const port_pin_config_t*)&config);
|
|
#endif
|
|
}
|
|
|
|
void McuGPIO_Init(void) {
|
|
/* nothing to do */
|
|
}
|
|
|
|
void McuGPIO_Deinit(void) {
|
|
/* nothing to do */
|
|
}
|