Skip to content

Commit

Permalink
Merge pull request RIOT-OS#20679 from maribu/cpu/msp430/periph_gpio_ll
Browse files Browse the repository at this point in the history
cpu/msp430: Implement periph_gpio_ll & periph_gpio_ll_irq
  • Loading branch information
maribu authored Aug 5, 2024
2 parents cf1bb15 + fc907f9 commit 3735cc1
Show file tree
Hide file tree
Showing 25 changed files with 826 additions and 151 deletions.
1 change: 1 addition & 0 deletions cpu/atmega_common/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ FEATURES_PROVIDED += periph_gpio periph_gpio_irq
FEATURES_PROVIDED += periph_gpio_ll
FEATURES_PROVIDED += periph_gpio_ll_input_pull_up
FEATURES_PROVIDED += periph_gpio_ll_irq
FEATURES_PROVIDED += periph_gpio_ll_irq_edge_triggered_both
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low
FEATURES_PROVIDED += periph_gpio_ll_irq_unmask
FEATURES_PROVIDED += periph_gpio_ll_switch_dir
Expand Down
1 change: 1 addition & 0 deletions cpu/esp32/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ FEATURES_PROVIDED += periph_gpio_ll_disconnect
FEATURES_PROVIDED += periph_gpio_ll_input_pull_down
FEATURES_PROVIDED += periph_gpio_ll_input_pull_up
FEATURES_PROVIDED += periph_gpio_ll_irq
FEATURES_PROVIDED += periph_gpio_ll_irq_edge_triggered_both
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_high
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low
FEATURES_PROVIDED += periph_gpio_ll_open_drain
Expand Down
1 change: 1 addition & 0 deletions cpu/gd32v/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ FEATURES_PROVIDED += periph_gpio_ll_disconnect
FEATURES_PROVIDED += periph_gpio_ll_input_pull_down
FEATURES_PROVIDED += periph_gpio_ll_input_pull_up
FEATURES_PROVIDED += periph_gpio_ll_irq
FEATURES_PROVIDED += periph_gpio_ll_irq_edge_triggered_both
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_high
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low
FEATURES_PROVIDED += periph_gpio_ll_open_drain
Expand Down
5 changes: 5 additions & 0 deletions cpu/msp430/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,10 @@ ifneq (,$(filter newlib,$(USEMODULE)))
DEFAULT_MODULE += newlib_nano
endif

ifneq (,$(filter periph_gpio,$(USEMODULE)))
# the legacy periph_gpio driver uses gpio_port from periph_gpio_ll
FEATURES_REQUIRED += periph_gpio_ll
endif

# Make calls to malloc and friends thread-safe
USEMODULE += malloc_thread_safe
6 changes: 6 additions & 0 deletions cpu/msp430/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ CPU_CORE = msp430

ifneq (,$(filter msp430f2% msp430g2%,$(CPU_MODEL)))
CPU_FAM := msp430_f2xx_g2xx
FEATURES_PROVIDED += periph_gpio_ll_input_pull_down
FEATURES_PROVIDED += periph_gpio_ll_input_pull_up
FEATURES_PROVIDED += periph_spi_reconfigure
endif

Expand All @@ -20,3 +22,7 @@ FEATURES_PROVIDED += periph_flashpage_in_address_space
FEATURES_PROVIDED += periph_flashpage_pagewise
FEATURES_PROVIDED += periph_pm
FEATURES_PROVIDED += periph_timer_query_freqs

FEATURES_PROVIDED += periph_gpio_ll
FEATURES_PROVIDED += periph_gpio_ll_irq
FEATURES_PROVIDED += periph_gpio_ll_switch_dir
6 changes: 5 additions & 1 deletion cpu/msp430/clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,9 +410,13 @@ void pm_set_lowest(void)
state |= OSCOFF;
}

/* write new state */
/* Write new state. This should not need NOPs before and after, but the
* assembler warning about possibly disabled IRQs cannot be disabled, so
* let's waste two instructions for less noise. */
__asm__ volatile(
"nop" "\n\t"
"mov.w %[state], SR" "\n\t"
"nop" "\n\t"
: /* no outputs */
: [state] "r"(state)
: "memory"
Expand Down
1 change: 0 additions & 1 deletion cpu/msp430/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
*/

#include "cpu.h"
#include "kernel_init.h"
#include "irq.h"
#include "sched.h"
#include "thread.h"
Expand Down
25 changes: 25 additions & 0 deletions cpu/msp430/include/f2xx_g2xx/msp430_regs.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,31 @@ extern "C" {
#define MSP430_USCI_B_FROM_USCI_A(usci_a) \
((msp430_usci_b_t *)((uintptr_t)(usci_a) + MSP430_USCI_A_B_OFFSET))

/**
* @brief GPIO Port 1/2 (with interrupt functionality)
*/
typedef struct {
msp430_port_t base; /**< common GPIO port registers */
REG8 IFG; /**< interrupt flag */
REG8 IES; /**< interrupt edge select */
REG8 IE; /**< interrupt enable */
REG8 SEL; /**< alternative function select */
REG8 REN; /**< pull resistor enable */
} msp430_port_p1_p2_t;

/**
* @brief GPIO Port 7/8 (different register layout than Ports 1-6)
*/
typedef struct {
REG8 IN; /**< input data */
uint8_t _padding1; /**< unrelated I/O */
REG8 OD; /**< output data */
uint8_t _padding2; /**< unrelated I/O */
REG8 DIR; /**< pin direction */
uint8_t _padding3; /**< unrelated I/O */
REG8 SEL; /**< alternative function select */
} msp430_port_p7_p8_t;

/**
* @brief Universal Serial Control Interface Type A (USCI_A) Registers
*/
Expand Down
10 changes: 10 additions & 0 deletions cpu/msp430/include/f2xx_g2xx/periph_cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,16 @@ typedef struct {
const msp430_usci_spi_params_t *spi; /**< The SPI configuration to use */
} spi_conf_t;

/**
* @brief Register map of GPIO PORT 7
*/
extern msp430_port_p7_p8_t PORT_7;

/**
* @brief Register map of GPIO PORT 8
*/
extern msp430_port_p7_p8_t PORT_8;

/**
* @brief Acquire and initialize USCI for use a SPI/UART peripheral
*
Expand Down
208 changes: 208 additions & 0 deletions cpu/msp430/include/gpio_ll_arch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
/*
* Copyright (C) 2024 Marian Buschsieweke
*
* 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_ll
* @{
*
* @file
* @brief CPU specific part of the Peripheral GPIO Low-Level API
*
* @author Marian Buschsieweke <[email protected]>
*/

#ifndef GPIO_LL_ARCH_H
#define GPIO_LL_ARCH_H

#include "cpu.h"
#include "periph_cpu.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifndef DOXYGEN /* hide implementation specific details from Doxygen */

/* the memory layout of all GPIO peripherals is compatible, but the location
* in the address space is pretty much random */

#define GPIO_PORT_1 ((gpio_port_t)&PORT_1.base)
#define GPIO_PORT_2 ((gpio_port_t)&PORT_2.base)
#define GPIO_PORT_3 ((gpio_port_t)&PORT_3.base)
#define GPIO_PORT_4 ((gpio_port_t)&PORT_4.base)
#define GPIO_PORT_5 ((gpio_port_t)&PORT_5.base)
#define GPIO_PORT_6 ((gpio_port_t)&PORT_6.base)
/* Port 7 and 8 have different memory layout and are only available on F2xx/G2xx
* MCUs */
#if defined(CPU_FAM_MSP430_F2XX_G2XX)
# define GPIO_PORT_7 ((gpio_port_t)&PORT_7)
# define GPIO_PORT_8 ((gpio_port_t)&PORT_8)
#endif

/* IMPORTANT IMPLEMENTATION INFO
* =============================
*
* - MSP430 F2xx/G2xx do have PORT 7 and PORT 8, but those have an incompatible
* memory layout compared to the other ports. Hence, they need extra handling.
* However, constant folding should get ride of the branch and overhead if the
* GPIO port is a compile time constant
* - MSP430 has bit manipulation instructions that work on memory. E.g.
* `BIC.B %[mask], @%[ptr]` will implement `*ptr &= ~(mask)` in a single
* instruction. Same for setting or XORing bits. Hence, the code below
* may often look like it is missing `irq_disable()` ... `irq_restore()`, but
* in fact will be atomic due to the MSP430 instruction set.
*/

gpio_port_t gpio_port(uword_t num);

static inline uword_t gpio_ll_read(gpio_port_t port)
{
#if defined(CPU_FAM_MSP430_F2XX_G2XX)
if (port >= (uintptr_t)(&PORT_7)) {
const msp430_port_p7_p8_t *p = (void *)port;
return p->IN;
}
#endif
const msp430_port_t *p = (void *)port;
return p->IN;
}

static inline uword_t gpio_ll_read_output(gpio_port_t port)
{
#if defined(CPU_FAM_MSP430_F2XX_G2XX)
if (port >= (uintptr_t)(&PORT_7)) {
const msp430_port_p7_p8_t *p = (void *)port;
return p->OD;
}
#endif
const msp430_port_t *p = (void *)port;
return p->OD;
}

static inline void gpio_ll_set(gpio_port_t port, uword_t mask)
{
#if defined(CPU_FAM_MSP430_F2XX_G2XX)
if (port >= (uintptr_t)(&PORT_7)) {
msp430_port_p7_p8_t *p = (void *)port;
p->OD |= mask;
return;
}
#endif
msp430_port_t *p = (void *)port;
p->OD |= mask;
}

static inline void gpio_ll_clear(gpio_port_t port, uword_t mask)
{
#if defined(CPU_FAM_MSP430_F2XX_G2XX)
if (port >= (uintptr_t)(&PORT_7)) {
msp430_port_p7_p8_t *p = (void *)port;
p->OD &= ~(mask);
return;
}
#endif
msp430_port_t *p = (void *)port;
p->OD &= ~(mask);
}

static inline void gpio_ll_toggle(gpio_port_t port, uword_t mask)
{
#if defined(CPU_FAM_MSP430_F2XX_G2XX)
if (port >= (uintptr_t)(&PORT_7)) {
msp430_port_p7_p8_t *p = (void *)port;
p->OD ^= mask;
return;
}
#endif
msp430_port_t *p = (void *)port;
p->OD ^= mask;
}

static inline void gpio_ll_write(gpio_port_t port, uword_t value)
{
#if defined(CPU_FAM_MSP430_F2XX_G2XX)
if (port >= (uintptr_t)(&PORT_7)) {
msp430_port_p7_p8_t *p = (void *)port;
p->OD = value;
return;
}
#endif
msp430_port_t *p = (void *)port;
p->OD = value;
}

static inline gpio_port_t gpio_get_port(gpio_t pin)
{
return gpio_port(gpio_get_pin_num(pin));
}

static inline uint8_t gpio_get_pin_num(gpio_t pin)
{
return pin >> 8;
}

static inline void gpio_ll_switch_dir_output(gpio_port_t port, uword_t outputs)
{
#if defined(CPU_FAM_MSP430_F2XX_G2XX)
if (port >= (uintptr_t)(&PORT_7)) {
msp430_port_p7_p8_t *p = (void *)port;
p->DIR |= outputs;
return;
}
#endif
msp430_port_t *p = (void *)port;
p->DIR |= outputs;
}

static inline void gpio_ll_switch_dir_input(gpio_port_t port, uword_t inputs)
{
#if defined(CPU_FAM_MSP430_F2XX_G2XX)
if (port >= (uintptr_t)(&PORT_7)) {
msp430_port_p7_p8_t *p = (void *)port;
p->DIR &= ~(inputs);
return;
}
#endif
msp430_port_t *p = (void *)port;
p->DIR &= ~(inputs);
}

static inline gpio_port_t gpio_port_pack_addr(void *addr)
{
return (gpio_port_t)addr;
}

static inline void * gpio_port_unpack_addr(gpio_port_t port)
{
if (port < RAMSTART) {
return NULL;
}

return (void *)port;
}

static inline bool is_gpio_port_num_valid(uint_fast8_t num)
{
#if defined(CPU_FAM_MSP430_F2XX_G2XX)
return (num > 0) && (num <= 8);
#else
return (num > 0) && (num <= 6);
#endif
}

uword_t gpio_port_num(gpio_port_t port);

#endif /* DOXYGEN */

#ifdef __cplusplus
}
#endif

#endif /* GPIO_LL_ARCH_H */
/** @} */
Loading

0 comments on commit 3735cc1

Please sign in to comment.