gpio_ll_arch.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2024 Marian Buschsieweke
3  *
4  * This file is subject to the terms and conditions of the GNU Lesser
5  * General Public License v2.1. See the file LICENSE in the top level
6  * directory for more details.
7  */
8 
20 #ifndef GPIO_LL_ARCH_H
21 #define GPIO_LL_ARCH_H
22 
23 #include "cpu.h"
24 #include "periph_cpu.h"
25 
26 #ifdef __cplusplus
27 extern "C" {
28 #endif
29 
30 #ifndef DOXYGEN /* hide implementation specific details from Doxygen */
31 
32 /* the memory layout of all GPIO peripherals is compatible, but the location
33  * in the address space is pretty much random */
34 
35 #define GPIO_PORT_1 ((gpio_port_t)&PORT_1.base)
36 #define GPIO_PORT_2 ((gpio_port_t)&PORT_2.base)
37 #define GPIO_PORT_3 ((gpio_port_t)&PORT_3.base)
38 #define GPIO_PORT_4 ((gpio_port_t)&PORT_4.base)
39 #define GPIO_PORT_5 ((gpio_port_t)&PORT_5.base)
40 #define GPIO_PORT_6 ((gpio_port_t)&PORT_6.base)
41 /* Port 7 and 8 have different memory layout and are only available on F2xx/G2xx
42  * MCUs */
43 #if defined(CPU_FAM_MSP430_F2XX_G2XX)
44 # define GPIO_PORT_7 ((gpio_port_t)&PORT_7)
45 # define GPIO_PORT_8 ((gpio_port_t)&PORT_8)
46 #endif
47 
48 /* IMPORTANT IMPLEMENTATION INFO
49  * =============================
50  *
51  * - MSP430 F2xx/G2xx do have PORT 7 and PORT 8, but those have an incompatible
52  * memory layout compared to the other ports. Hence, they need extra handling.
53  * However, constant folding should get ride of the branch and overhead if the
54  * GPIO port is a compile time constant
55  * - MSP430 has bit manipulation instructions that work on memory. E.g.
56  * `BIC.B %[mask], @%[ptr]` will implement `*ptr &= ~(mask)` in a single
57  * instruction. Same for setting or XORing bits. Hence, the code below
58  * may often look like it is missing `irq_disable()` ... `irq_restore()`, but
59  * in fact will be atomic due to the MSP430 instruction set.
60  */
61 
63 
64 static inline uword_t gpio_ll_read(gpio_port_t port)
65 {
66 #if defined(CPU_FAM_MSP430_F2XX_G2XX)
67  if (port >= (uintptr_t)(&PORT_7)) {
68  const msp430_port_p7_p8_t *p = (void *)port;
69  return p->IN;
70  }
71 #endif
72  const msp430_port_t *p = (void *)port;
73  return p->IN;
74 }
75 
76 static inline uword_t gpio_ll_read_output(gpio_port_t port)
77 {
78 #if defined(CPU_FAM_MSP430_F2XX_G2XX)
79  if (port >= (uintptr_t)(&PORT_7)) {
80  const msp430_port_p7_p8_t *p = (void *)port;
81  return p->OD;
82  }
83 #endif
84  const msp430_port_t *p = (void *)port;
85  return p->OD;
86 }
87 
88 static inline void gpio_ll_set(gpio_port_t port, uword_t mask)
89 {
90 #if defined(CPU_FAM_MSP430_F2XX_G2XX)
91  if (port >= (uintptr_t)(&PORT_7)) {
92  msp430_port_p7_p8_t *p = (void *)port;
93  p->OD |= mask;
94  return;
95  }
96 #endif
97  msp430_port_t *p = (void *)port;
98  p->OD |= mask;
99 }
100 
101 static inline void gpio_ll_clear(gpio_port_t port, uword_t mask)
102 {
103 #if defined(CPU_FAM_MSP430_F2XX_G2XX)
104  if (port >= (uintptr_t)(&PORT_7)) {
105  msp430_port_p7_p8_t *p = (void *)port;
106  p->OD &= ~(mask);
107  return;
108  }
109 #endif
110  msp430_port_t *p = (void *)port;
111  p->OD &= ~(mask);
112 }
113 
114 static inline void gpio_ll_toggle(gpio_port_t port, uword_t mask)
115 {
116 #if defined(CPU_FAM_MSP430_F2XX_G2XX)
117  if (port >= (uintptr_t)(&PORT_7)) {
118  msp430_port_p7_p8_t *p = (void *)port;
119  p->OD ^= mask;
120  return;
121  }
122 #endif
123  msp430_port_t *p = (void *)port;
124  p->OD ^= mask;
125 }
126 
127 static inline void gpio_ll_write(gpio_port_t port, uword_t value)
128 {
129 #if defined(CPU_FAM_MSP430_F2XX_G2XX)
130  if (port >= (uintptr_t)(&PORT_7)) {
131  msp430_port_p7_p8_t *p = (void *)port;
132  p->OD = value;
133  return;
134  }
135 #endif
136  msp430_port_t *p = (void *)port;
137  p->OD = value;
138 }
139 
140 static inline gpio_port_t gpio_get_port(gpio_t pin)
141 {
142  return gpio_port(gpio_get_pin_num(pin));
143 }
144 
145 static inline uint8_t gpio_get_pin_num(gpio_t pin)
146 {
147  return pin >> 8;
148 }
149 
150 static inline void gpio_ll_switch_dir_output(gpio_port_t port, uword_t outputs)
151 {
152 #if defined(CPU_FAM_MSP430_F2XX_G2XX)
153  if (port >= (uintptr_t)(&PORT_7)) {
154  msp430_port_p7_p8_t *p = (void *)port;
155  p->DIR |= outputs;
156  return;
157  }
158 #endif
159  msp430_port_t *p = (void *)port;
160  p->DIR |= outputs;
161 }
162 
163 static inline void gpio_ll_switch_dir_input(gpio_port_t port, uword_t inputs)
164 {
165 #if defined(CPU_FAM_MSP430_F2XX_G2XX)
166  if (port >= (uintptr_t)(&PORT_7)) {
167  msp430_port_p7_p8_t *p = (void *)port;
168  p->DIR &= ~(inputs);
169  return;
170  }
171 #endif
172  msp430_port_t *p = (void *)port;
173  p->DIR &= ~(inputs);
174 }
175 
176 static inline gpio_port_t gpio_port_pack_addr(void *addr)
177 {
178  return (gpio_port_t)addr;
179 }
180 
181 static inline void * gpio_port_unpack_addr(gpio_port_t port)
182 {
183  if (port < RAMSTART) {
184  return NULL;
185  }
186 
187  return (void *)port;
188 }
189 
190 static inline bool is_gpio_port_num_valid(uint_fast8_t num)
191 {
192 #if defined(CPU_FAM_MSP430_F2XX_G2XX)
193  return (num > 0) && (num <= 8);
194 #else
195  return (num > 0) && (num <= 6);
196 #endif
197 }
198 
200 
201 #endif /* DOXYGEN */
202 
203 #ifdef __cplusplus
204 }
205 #endif
206 
207 #endif /* GPIO_LL_ARCH_H */
static uint8_t gpio_get_pin_num(gpio_t pin)
Extract the pin number from a gpio_t
static void * gpio_port_unpack_addr(gpio_port_t port)
Extract a data pointer that was packed by gpio_port_pack_addr.
static void gpio_ll_set(gpio_port_t port, uword_t mask)
Perform an reg |= mask operation on the I/O register of the port.
gpio_port_t gpio_port(uword_t num)
Get the gpio_port_t value of the port number num.
static gpio_port_t gpio_port_pack_addr(void *addr)
Pack a pointer into a gpio_port_t.
static void gpio_ll_switch_dir_output(gpio_port_t port, uword_t pins)
Turn GPIO pins specified by pins (obtained from gpio_ll_prepare_switch_dir) to outputs.
static void gpio_ll_switch_dir_input(gpio_port_t port, uword_t pins)
Turn GPIO pins specified by pins (obtained from gpio_ll_prepare_switch_dir) to inputs.
static uword_t gpio_ll_read(gpio_port_t port)
Get the current input value of all GPIO pins of the given port as bitmask.
static gpio_port_t gpio_get_port(gpio_t pin)
Extract the gpio_port_t from a gpio_t
uword_t gpio_port_num(gpio_port_t port)
Get the number of the GPIO port port refers to.
static bool is_gpio_port_num_valid(uint_fast8_t num)
Check if the given number is a valid argument for gpio_port.
static uword_t gpio_ll_read_output(gpio_port_t port)
Get the current output value of all GPIO pins of the given port as bitmask.
static void gpio_ll_clear(gpio_port_t port, uword_t mask)
Perform an reg &= ~mask operation on the I/O register of the port.
static void gpio_ll_toggle(gpio_port_t port, uword_t mask)
Perform an reg ^= mask operation on the I/O register of the port.
static void gpio_ll_write(gpio_port_t port, uword_t state)
Perform a masked write operation on the I/O register of the port.
uintptr_t gpio_port_t
GPIO port type.
Definition: gpio_ll.h:87
uint< NUM > _t uword_t
Word sized unsigned integer.
Definition: architecture.h:70
msp430_port_p7_p8_t PORT_7
Register map of GPIO PORT 7.
#define RAMSTART
Lowest address of the RAM, peripherals are below.
Native CPU header.
GPIO Port 7/8 (different register layout than Ports 1-6)
Definition: msp430_regs.h:75
REG8 IN
input data
Definition: msp430_regs.h:76
REG8 OD
output data
Definition: msp430_regs.h:78
REG8 DIR
pin direction
Definition: msp430_regs.h:80
Common MSP GPIO Port Registers.
REG8 OD
output data
REG8 IN
input data
REG8 DIR
pin direction