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