1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/msp430/periph/gpio.c
Marian Buschsieweke 45b353c6ef
cpu/msp430: make use of vendor header files
The MSP430 vendor files already provide macros containing register
constants and symbols (provided via linker scripts) containing addresses
of peripheral registers. So lets make use of that rather than
maintaining a long list of constants.
2023-07-04 20:21:05 +02:00

234 lines
4.7 KiB
C

/*
* Copyright (C) 2015 Freie Universität Berlin
*
* 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_msp430
* @ingroup drivers_periph_gpio
* @{
*
* @file
* @brief Low-level GPIO driver implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include "bitarithm.h"
#include "container.h"
#include "cpu.h"
#include "periph/gpio.h"
/**
* @brief Number of possible interrupt lines: 2 ports * 8 pins
*/
#define ISR_NUMOF (16U)
/**
* @brief Number of pins on each port
*/
#define PINS_PER_PORT (8U)
static msp_port_t *_port(gpio_t pin)
{
switch (pin >> 8) {
case 1:
return &PORT_1.base;
case 2:
return &PORT_2.base;
case 3:
return &PORT_3.base;
case 4:
return &PORT_4.base;
case 5:
return &PORT_5.base;
case 6:
return &PORT_6.base;
default:
return NULL;
}
}
static inline uint8_t _pin(gpio_t pin)
{
return (uint8_t)(pin & 0xff);
}
static inline msp_port_p1_p2_t *_isr_port(gpio_t pin)
{
/* checking for (pin >> 8) <= 2 requires 6 byte of .text more than
* checking the resulting address */
msp_port_p1_p2_t *port = container_of(_port(pin), msp_port_p1_p2_t, base);
if ((port == &PORT_1) || (port == &PORT_2)) {
return port;
}
return NULL;
}
int gpio_init(gpio_t pin, gpio_mode_t mode)
{
msp_port_t *port = _port(pin);
/* check if port is valid and mode applicable */
if ((port == NULL) || ((mode != GPIO_IN) && (mode != GPIO_OUT))) {
return -1;
}
/* set pin direction */
if (mode == GPIO_OUT) {
port->DIR |= _pin(pin);
}
else {
port->DIR &= ~(_pin(pin));
}
return 0;
}
void gpio_periph_mode(gpio_t pin, bool enable)
{
REG8 *sel;
msp_port_p1_p2_t *isrport = _isr_port(pin);
if (isrport) {
sel = &(isrport->SEL);
}
else {
msp_port_p3_p6_t *port = container_of(_port(pin), msp_port_p3_p6_t, base);
if (port) {
sel = &(port->SEL);
}
else {
return;
}
}
if (enable) {
*sel |= _pin(pin);
}
else {
*sel &= ~(_pin(pin));
}
}
int gpio_read(gpio_t pin)
{
msp_port_t *port = _port(pin);
if (port->DIR & _pin(pin)) {
return (int)(port->OD & _pin(pin));
}
else {
return (int)(port->IN & _pin(pin));
}
}
void gpio_set(gpio_t pin)
{
_port(pin)->OD |= _pin(pin);
}
void gpio_clear(gpio_t pin)
{
_port(pin)->OD &= ~(_pin(pin));
}
void gpio_toggle(gpio_t pin)
{
_port(pin)->OD ^= _pin(pin);
}
void gpio_write(gpio_t pin, int value)
{
if (value) {
_port(pin)->OD |= _pin(pin);
}
else {
_port(pin)->OD &= ~(_pin(pin));
}
}
#ifdef MODULE_PERIPH_GPIO_IRQ
/**
* @brief Interrupt context for each interrupt line
*/
static gpio_isr_ctx_t isr_ctx[ISR_NUMOF];
static int _ctx(gpio_t pin)
{
int i = bitarithm_lsb(_pin(pin));
return (_port(pin) == &PORT_1.base) ? i : (i + 8);
}
int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
gpio_cb_t cb, void *arg)
{
msp_port_p1_p2_t *port = _isr_port(pin);
/* check if port, pull resistor and flank configuration are valid */
if ((port == NULL) || (flank == GPIO_BOTH)) {
return -1;
}
/* disable any activated interrupt */
port->IE &= ~(_pin(pin));
/* configure as input */
if (gpio_init(pin, mode) < 0) {
return -1;
}
/* save ISR context */
isr_ctx[_ctx(pin)].cb = cb;
isr_ctx[_ctx(pin)].arg = arg;
/* configure flank */
port->IES &= ~(_pin(pin));
port->IES |= (flank & _pin(pin));
/* clear pending interrupts and enable the IRQ */
port->IFG &= ~(_pin(pin));
gpio_irq_enable(pin);
return 0;
}
void gpio_irq_enable(gpio_t pin)
{
msp_port_p1_p2_t *port = _isr_port(pin);
if (port) {
port->IE |= _pin(pin);
}
}
void gpio_irq_disable(gpio_t pin)
{
msp_port_p1_p2_t *port = _isr_port(pin);
if (port) {
port->IE &= ~(_pin(pin));
}
}
static inline void isr_handler(msp_port_p1_p2_t *port, int ctx)
{
for (unsigned i = 0; i < PINS_PER_PORT; i++) {
if ((port->IE & (1 << i)) && (port->IFG & (1 << i))) {
port->IFG &= ~(1 << i);
isr_ctx[i + ctx].cb(isr_ctx[i + ctx].arg);
}
}
}
ISR(PORT1_VECTOR, isr_port1)
{
__enter_isr();
isr_handler(&PORT_1, 0);
__exit_isr();
}
ISR(PORT2_VECTOR, isr_port2)
{
__enter_isr();
isr_handler(&PORT_2, 8);
__exit_isr();
}
#endif /* MODULE_PERIPH_GPIO_IRQ */