1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/lpc1768/periph/gpio.c
Marian Buschsieweke c2c2cc8592
drivers/periph_gpio: let gpio_read() return bool
Since https://github.com/RIOT-OS/RIOT/pull/20935 gpio_write()
uses a `bool` instead of an `int`. This does the same treatment for
`gpio_read()`.

This does indeed add an instruction to `gpio_read()` implementations.
However, users caring about an instruction more are better served with
`gpio_ll_read()` anyway. And `gpio_read() == 1` is often seen in
newcomer's code, which would now work as expected.
2024-10-23 13:24:09 +02:00

247 lines
5.7 KiB
C

/*
* Copyright (C) 2017 Bas Stottelaar <basstottelaar@gmail.com>
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
* details.
*/
/**
* @ingroup cpu_lpc1768
* @{
*
* @file
* @brief Low-level GPIO driver implementation
*
* @author Bas Stottelaar <basstottelaar@gmail.com>
*
* @}
*/
#include <assert.h>
#include "cpu.h"
#include "periph/gpio.h"
#ifdef MODULE_PERIPH_GPIO_IRQ
/**
* @brief Number of external interrupt lines.
*/
#define NUMOF_IRQS (32)
/**
* @brief Hold one interrupt context per interrupt line
*/
static gpio_isr_ctx_t isr_ctx[NUMOF_IRQS];
static gpio_flank_t isr_state[2][32];
#endif /* MODULE_PERIPH_GPIO_IRQ */
#define PIN_MASK (0x1f)
#define PORT_SHIFT (5U)
static inline int _pin(gpio_t pin)
{
return (pin & PIN_MASK);
}
static inline int _port(gpio_t pin)
{
return (pin >> PORT_SHIFT);
}
static inline LPC_GPIO_TypeDef *_base(gpio_t pin)
{
return (LPC_GPIO_TypeDef *) (LPC_GPIO_BASE + (_port(pin) * 0x20));
}
int gpio_init(gpio_t pin, gpio_mode_t mode)
{
/* check for valid pin */
if (pin == GPIO_UNDEF) {
return -1;
}
if (_port(pin) > 4 || _pin(pin) > 32) {
return -1;
}
/* enable gpio peripheral */
LPC_SC->PCONP |= (1 << 15);
/* pin as output or input */
LPC_GPIO_TypeDef *base = _base(pin);
base->FIODIR &= ~(1 << _pin(pin));
base->FIODIR |= ((mode & 0x01) << _pin(pin));
/* configure pin function */
int reg = 2 * _port(pin) + (_pin(pin) / 16);
int bit = (pin % 16) * 2;
((uint32_t *) &LPC_PINCON->PINSEL0)[reg] &= ~(0x03 << bit);
/* configure pull up/down */
((uint32_t *) &LPC_PINCON->PINMODE0)[reg] &= ~(0x03 << bit);
((uint32_t *) &LPC_PINCON->PINMODE0)[reg] |= (((mode >> 1) & 0x03) << bit);
/* configure open drain */
((uint32_t *) &LPC_PINCON->PINMODE_OD0)[_port(pin)] &= ~(1 << _pin(pin));
((uint32_t *) &LPC_PINCON->PINMODE_OD0)[_port(pin)] |= (((mode >> 3) & 0x01) << _pin(pin));
return 0;
}
bool gpio_read(gpio_t pin)
{
LPC_GPIO_TypeDef *base = _base(pin);
return (base->FIOPIN & (1 << _pin(pin))) ? 1 : 0;
}
void gpio_set(gpio_t pin)
{
LPC_GPIO_TypeDef *base = _base(pin);
base->FIOSET = (1 << _pin(pin));
}
void gpio_clear(gpio_t pin)
{
LPC_GPIO_TypeDef *base = _base(pin);
base->FIOCLR = (1 << _pin(pin));
}
void gpio_toggle(gpio_t pin)
{
LPC_GPIO_TypeDef *base = _base(pin);
base->FIOPIN ^= (1 << _pin(pin));
}
void gpio_write(gpio_t pin, bool value)
{
LPC_GPIO_TypeDef *base = _base(pin);
if (value) {
base->FIOSET = (1 << _pin(pin));
}
else {
base->FIOCLR = (1 << _pin(pin));
}
}
#ifdef MODULE_PERIPH_GPIO_IRQ
static inline void _configure_flank(gpio_t pin, gpio_flank_t flank)
{
switch (flank) {
case GPIO_RISING:
if (_port(pin) == 0) {
LPC_GPIOINT->IO0IntEnF &= ~(1 << _pin(pin));
LPC_GPIOINT->IO0IntEnR |= (1 << _pin(pin));
}
else {
LPC_GPIOINT->IO2IntEnF &= ~(1 << _pin(pin));
LPC_GPIOINT->IO2IntEnR |= (1 << _pin(pin));
}
break;
case GPIO_FALLING:
if (_port(pin) == 0) {
LPC_GPIOINT->IO0IntEnF |= (1 << _pin(pin));
LPC_GPIOINT->IO0IntEnR &= ~(1 << _pin(pin));
}
else {
LPC_GPIOINT->IO2IntEnF |= (1 << _pin(pin));
LPC_GPIOINT->IO2IntEnR &= ~(1 << _pin(pin));
}
break;
case GPIO_BOTH:
if (_port(pin) == 0) {
LPC_GPIOINT->IO0IntEnF |= 1 << _pin(pin);
LPC_GPIOINT->IO0IntEnR |= 1 << _pin(pin);
}
else {
LPC_GPIOINT->IO2IntEnF |= 1 << _pin(pin);
LPC_GPIOINT->IO2IntEnR |= 1 << _pin(pin);
}
break;
}
}
int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
gpio_cb_t cb, void *arg)
{
/* only certain pins can be used as interrupt pins */
if (_port(pin) != 0 && _port(pin) != 2) {
return -1;
}
/* initialize the pin */
int result = gpio_init(pin, mode);
if (result != 0) {
return result;
}
/* store interrupt callback */
isr_ctx[_pin(pin)].cb = cb;
isr_ctx[_pin(pin)].arg = arg;
/* need to store flank configuration for (re)enable irq */
isr_state[_port(pin) >> 1][_pin(pin)] = flank;
/* set flank configuration */
_configure_flank(pin, flank);
/* clear any pending requests and enable the interrupt */
NVIC_ClearPendingIRQ(EINT3_IRQn);
NVIC_EnableIRQ(EINT3_IRQn);
return 0;
}
void gpio_irq_enable(gpio_t pin)
{
assert(_port(pin) == 0 || _port(pin) == 2);
_configure_flank(pin, isr_state[_port(pin) >> 1][_pin(pin)]);
}
void gpio_irq_disable(gpio_t pin)
{
assert(_port(pin) == 0 || _port(pin) == 2);
if (_port(pin) == 0) {
LPC_GPIOINT->IO0IntEnF &= ~(1 << _pin(pin));
LPC_GPIOINT->IO0IntEnR &= ~(1 << _pin(pin));
}
else {
LPC_GPIOINT->IO2IntEnF &= ~(1 << _pin(pin));
LPC_GPIOINT->IO2IntEnR &= ~(1 << _pin(pin));
}
}
void isr_eint3(void)
{
/* combine all interrupts */
uint32_t status = LPC_GPIOINT->IO0IntStatF | LPC_GPIOINT->IO0IntStatR |
LPC_GPIOINT->IO2IntStatF | LPC_GPIOINT->IO2IntStatR;
/* invoke all handlers */
for (int i = 0; i < NUMOF_IRQS; i++) {
if (status & ((uint32_t)1 << i)) {
isr_ctx[i].cb(isr_ctx[i].arg);
LPC_GPIOINT->IO0IntClr |= (1 << i);
LPC_GPIOINT->IO2IntClr |= (1 << i);
}
}
cortexm_isr_end();
}
#endif /* MODULE_PERIPH_GPIO_IRQ */