Skip to content
This repository was archived by the owner on Nov 11, 2024. It is now read-only.

Commit 128a72b

Browse files
authored
POSSIBLY BREAKING change to uPort layer: add GPIO interrupt support. (#1189)
* POSSIBLY BREAKING change to uPort layer: add GPIO interrupt support. The GPIO portion of the port layer is updated to include GPIO interrupt support. Specifically, three new fields are added to the uPortGpioConfig_t structure that is passed to uPortGpioConfig(), allowing an interrupt callback and either edge or level (where supported) triggering to be configured. This is required for up-coming support of use of the Data Ready pin when reading from a GNSS device. This change is backwards compatible with existing ports in that there is also a uPortGpioInterruptSupported() function with a WEAK implementation that returns false; the ubxlib code will not attempt to use GPIO interrupts on platforms where uPortGpioInterruptSupported() returns false. Note that interrupts are not implemented for Windows and Linux (including Zephyr on Linux), since interrupts are not accessible on these platforms. The POSSIBLY BREAKING part of the change is that, if anyone has used uPortGpioConfig() in their application and passed into it a uPortGpioConfig_t structure that has NOT been assigned to U_PORT_GPIO_CONFIG_DEFAULT, the three new fields will be left floating and anything may happen. Please make sure that, if you have used uPortGpioConfig() in your application code, you have assigned your uPortGpioConfig_t to U_PORT_GPIO_CONFIG_DEFAULT on creation; all of the ubxlib code does this.
1 parent cf88bb6 commit 128a72b

File tree

13 files changed

+1024
-58
lines changed

13 files changed

+1024
-58
lines changed

port/api/u_port_gpio.h

+48-2
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,41 @@ typedef struct {
108108
last pin on GPIO chip 0 were pin 15 then the
109109
first pin on GPIO chip 1 would likely be pin 16,
110110
it could not be pin 0 again. */
111+
void (*pInterrupt)(void); /**< if non-NULL and interrupts are supported
112+
by the platform then the pin will be
113+
configured as an interrupt; NULL is the
114+
default. If you have your own port you
115+
only need to implement interrupt functionality
116+
if you wish to use the "data ready" feature
117+
of the GNSS interface, enabling this MCU to
118+
sleep while waiting for a response from
119+
a GNSS device; GPIO interrupts are otherwise
120+
not used within ubxlib. Note also that
121+
some platforms may require additional
122+
compile-time configuration for this to work,
123+
e.g. for STM32Cube it is necessary to make
124+
the correct HW interrupts available to
125+
this code, search for
126+
U_CFG_HW_EXTI_ to find out more; also,
127+
platforms may apply additional restrictions,
128+
e.g. an interrupt pin may not be able to
129+
be set as input/output (this is the case
130+
with ESP32), perhaps only certain pins
131+
can be set as interrupts, etc. */
132+
bool interruptActiveLow; /**< if true then the pin is assumed
133+
to be an active-low interrupt, else
134+
(the default) if is assumed to be an
135+
active-high interrupt; ignored if
136+
pInterrupt is NULL or interrupts are
137+
not supported by the platform. */
138+
bool interruptLevel; /**< if true then the pin will be configured
139+
as a level-triggered interrupt, else
140+
it will be configured as an edge-triggered
141+
interrupt (the default); ignored if
142+
pInterrupt is NULL or interrupts are not
143+
supported by the platform, not all platforms
144+
support level-triggered interrupts (e.g.
145+
STM32F4 does not). */
111146
} uPortGpioConfig_t;
112147

113148
/** Default values for the above.
@@ -117,7 +152,8 @@ typedef struct {
117152
U_PORT_GPIO_PULL_MODE_NONE, \
118153
U_PORT_GPIO_DRIVE_MODE_NORMAL, \
119154
U_PORT_GPIO_DRIVE_CAPABILITY_STRONG, \
120-
-1}
155+
-1, \
156+
NULL, false, false}
121157

122158
/** Compilers won't generally allow myConfig = #U_PORT_GPIO_CONFIG_DEFAULT;
123159
* to be done anywhere other than where myConfig is declared. This macro
@@ -128,7 +164,10 @@ typedef struct {
128164
(pConfig)->pullMode = U_PORT_GPIO_PULL_MODE_NONE; \
129165
(pConfig)->driveMode = U_PORT_GPIO_DRIVE_MODE_NORMAL; \
130166
(pConfig)->driveCapability = U_PORT_GPIO_DRIVE_CAPABILITY_STRONG; \
131-
(pConfig)->index = -1
167+
(pConfig)->index = -1; \
168+
(pConfig)->pInterrupt = NULL; \
169+
(pConfig)->interruptActiveLow = false; \
170+
(pConfig)->interruptLevel = false;
132171

133172
/* ----------------------------------------------------------------
134173
* FUNCTIONS
@@ -168,6 +207,13 @@ int32_t uPortGpioSet(int32_t pin, int32_t level);
168207
*/
169208
int32_t uPortGpioGet(int32_t pin);
170209

210+
/** Should return true if interrupts are supported; where not
211+
* supported a weak implementation will return false.
212+
*
213+
* @return true if interrupts are supported, else false.
214+
*/
215+
bool uPortGpioInterruptSupported();
216+
171217
#ifdef __cplusplus
172218
}
173219
#endif

port/platform/common/automation/DATABASE.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ The table below defines the instances of test hardware available on the `ubxlib`
5050
| 13.1.0| Nordic DK board (NRF52840) + EVK | NRF52840 | nrf52840dk_nrf52840 | Zephyr | | M10 | port at_client ubx_protocol gnss spartn | gnss | U_CFG_APP_GNSS_I2C=1 U_CFG_TEST_PIN_GNSS_RESET_N=29 U_CFG_TEST_UART_B=0 U_DEBUG_UTILS_DUMP_THREADS |
5151
| 13.1.1| Nordic DK board (NRF52840) + EVK | NRF52840 | nrf52840dk_nrf52840 | Zephyr | | | port at_client ubx_protocol spartn | short_range | U_CFG_TEST_UART_B=0 U_DEBUG_UTILS_DUMP_THREADS |
5252
| 13.1.2| Nordic DK board (NRF52840) + EVK, DT cfg | NRF52840 | ubx_evkninab3_nrf52840 | Zephyr | | | port | | U_CFG_APP_FILTER=zephyrPort. U_CFG_PPP_ENABLE U_CFG_TEST_UART_A=-1 U_CFG_TEST_PIN_A=-1 U_CFG_TEST_PIN_B=-1 U_CFG_TEST_PIN_C=-1 |
53-
| 14 | STM32F407 Discovery + EVK, Cat M1 | STM32F4 | | STM32Cube | | LEXI_R422 M9 | port device network sock security cell mqtt_client http_client gnss location || CMSIS_V2 U_CELL_CFG_TEST_CELL_DISABLE_MNO_PROFILE U_CFG_TEST_CELL_PWR_DISABLE U_CFG_TEST_GNSS_ASSIST_NOW U_GNSS_MGA_TEST_HAS_FLASH U_LOCATION_TEST_DISABLE U_CFG_1V8_SIM_WORKAROUND HSE_VALUE=8000000U U_CFG_APP_GNSS_SPI=2 U_CFG_APP_PIN_GNSS_SPI_MOSI=0x1F U_CFG_APP_PIN_GNSS_SPI_MISO=0x1E U_CFG_APP_PIN_GNSS_SPI_CLK=0x1D U_CFG_APP_PIN_GNSS_SPI_SELECT=0x1C U_CFG_TEST_PIN_GNSS_RESET_N=0x40 U_CFG_TEST_PIN_C=0x3F U_CFG_APP_GNSS_UART=-1 U_CFG_APP_PIN_GNSS_ENABLE_POWER=-1 U_CFG_TEST_UART_A=-1 U_CFG_APP_PIN_C030_ENABLE_3V3=-1 U_CFG_APP_PIN_CELL_RESET=-1 U_CFG_APP_CELL_UART=3 U_CFG_APP_PIN_CELL_TXD=0x38 U_CFG_APP_PIN_CELL_RXD=0x39 U_CFG_APP_PIN_CELL_RTS=-1 U_CFG_APP_PIN_CELL_CTS=-1 U_DEBUG_UTILS_DUMP_THREADS |
53+
| 14 | STM32F407 Discovery + EVK, Cat M1 | STM32F4 | | STM32Cube | | LEXI_R422 M9 | port device network sock security cell mqtt_client http_client gnss location || CMSIS_V2 U_CELL_CFG_TEST_CELL_DISABLE_MNO_PROFILE U_CFG_TEST_CELL_PWR_DISABLE U_CFG_TEST_GNSS_ASSIST_NOW U_GNSS_MGA_TEST_HAS_FLASH U_LOCATION_TEST_DISABLE U_CFG_1V8_SIM_WORKAROUND HSE_VALUE=8000000U U_CFG_APP_GNSS_SPI=2 U_CFG_APP_PIN_GNSS_SPI_MOSI=0x1F U_CFG_APP_PIN_GNSS_SPI_MISO=0x1E U_CFG_APP_PIN_GNSS_SPI_CLK=0x1D U_CFG_APP_PIN_GNSS_SPI_SELECT=0x1C U_CFG_TEST_PIN_GNSS_RESET_N=0x40 U_CFG_TEST_PIN_C=0x3F U_CFG_APP_GNSS_UART=-1 U_CFG_APP_PIN_GNSS_ENABLE_POWER=-1 U_CFG_HW_EXTI_8_AVAILABLE=1 U_CFG_HW_EXTI_15_AVAILABLE=1 U_CFG_TEST_UART_A=-1 U_CFG_APP_PIN_C030_ENABLE_3V3=-1 U_CFG_APP_PIN_CELL_RESET=-1 U_CFG_APP_CELL_UART=3 U_CFG_APP_PIN_CELL_TXD=0x38 U_CFG_APP_PIN_CELL_RXD=0x39 U_CFG_APP_PIN_CELL_RTS=-1 U_CFG_APP_PIN_CELL_CTS=-1 U_DEBUG_UTILS_DUMP_THREADS |
5454
| 15.1 | Nordic DK board (NRF52840) + EVK | NRF52840 | nrf52840dk_nrf52840 | Zephyr | | M9 | port device network ble short_range gnss | | U_CFG_TEST_UART_A=-1 U_CFG_APP_GNSS_SPI=3 U_CFG_APP_PIN_GNSS_SPI_SELECT=29 U_CFG_TEST_PIN_GNSS_RESET_N=37 U_GNSS_MGA_TEST_HAS_FLASH U_BLE_TEST_CFG_REMOTE_SPS_CENTRAL=2462ABB6CC42p U_DEBUG_UTILS_DUMP_THREADS |
5555
| 16 | STM32F407 Discovery | STM32F4 | | STM32Cube | | M10 | port ubx_protocol gnss spartn geofence | gnss | U_CFG_GEOFENCE HSE_VALUE=8000000U U_PORT_TEST_DISABLE_I2C U_GNSS_MGA_TEST_DISABLE_DATABASE U_CFG_APP_GNSS_I2C=1 U_CFG_TEST_PIN_GNSS_RESET_N=0x40 U_CFG_APP_GNSS_UART=-1 U_CFG_APP_PIN_GNSS_ENABLE_POWER=-1 U_CFG_TEST_PIN_A=-1 U_CFG_TEST_PIN_B=-1 U_CFG_TEST_PIN_C=-1 U_CFG_TEST_UART_A=-1 U_CFG_APP_PIN_C030_ENABLE_3V3=-1 U_CFG_APP_PIN_CELL_RESET=-1 U_DEBUG_UTILS_DUMP_THREADS |
5656
| 17.1.0| Nordic NRF5340 DK board | NRF5340 | nrf5340dk_nrf5340_cpuapp | Zephyr | | M9 | port device network ble short_range lib_common ubx_protocol gnss spartn || U_CFG_APP_GNSS_SPI=2 U_CFG_APP_SPI_MAX_SEGMENT_SIZE=32 U_CFG_APP_PIN_GNSS_SPI_SELECT=46 U_CFG_TEST_PIN_GNSS_RESET_N=37 U_GNSS_MGA_TEST_HAS_FLASH U_CFG_BLE_MODULE_INTERNAL U_BLE_TEST_CFG_REMOTE_SPS_CENTRAL=2462ABB6CC42p U_BLE_TEST_CFG_REMOTE_SPS_PERIPHERAL=2462ABB6EAC6p U_CFG_APP_SHORT_RANGE_ROLE=1 U_DEBUG_UTILS_DUMP_THREADS |

port/platform/esp-idf/src/u_port_gpio.c

+65-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@
3636
* COMPILE-TIME MACROS
3737
* -------------------------------------------------------------- */
3838

39+
#ifndef U_PORT_GPIO_ESPIDF_INTERRUPT_FLAGS
40+
/** The type of interrupt handler to use: low or medium should be fine.
41+
*/
42+
# define U_PORT_GPIO_ESPIDF_INTERRUPT_FLAGS ESP_INTR_FLAG_LOWMED
43+
#endif
44+
3945
/* ----------------------------------------------------------------
4046
* TYPES
4147
* -------------------------------------------------------------- */
@@ -44,10 +50,22 @@
4450
* VARIABLES
4551
* -------------------------------------------------------------- */
4652

53+
/** Keep track of whether we installed the ISR service (otherwise
54+
* ESP-IDF prints error messages when we blindly call
55+
* gpio_isr_handler_remove().
56+
*/
57+
static bool gIsrServiceInstalled = false;
58+
4759
/* ----------------------------------------------------------------
4860
* STATIC FUNCTIONS
4961
* -------------------------------------------------------------- */
5062

63+
// ISR handler function; just calls pArg.
64+
static void isrHandler(void *pArg)
65+
{
66+
((void (*)()) pArg)();
67+
}
68+
5169
/* ----------------------------------------------------------------
5270
* PUBLIC FUNCTIONS
5371
* -------------------------------------------------------------- */
@@ -58,10 +76,24 @@ int32_t uPortGpioConfig(uPortGpioConfig_t *pConfig)
5876
uErrorCode_t errorCode = U_ERROR_COMMON_INVALID_PARAMETER;
5977
bool badConfig = false;
6078
gpio_config_t config;
79+
esp_err_t espErr;
6180

6281
if (pConfig != NULL) {
63-
// Set the things that won't change
82+
// Set interrupt type
6483
config.intr_type = GPIO_INTR_DISABLE;
84+
if (pConfig->pInterrupt != NULL) {
85+
if (pConfig->interruptLevel) {
86+
config.intr_type = GPIO_INTR_HIGH_LEVEL;
87+
if (pConfig->interruptActiveLow) {
88+
config.intr_type = GPIO_INTR_LOW_LEVEL;
89+
}
90+
} else {
91+
config.intr_type = GPIO_INTR_POSEDGE;
92+
if (pConfig->interruptActiveLow) {
93+
config.intr_type = GPIO_INTR_NEGEDGE;
94+
}
95+
}
96+
}
6597

6698
// Set the direction and drive mode
6799
switch (pConfig->direction) {
@@ -124,6 +156,32 @@ int32_t uPortGpioConfig(uPortGpioConfig_t *pConfig)
124156
// It's not an output pin so we're done
125157
errorCode = U_ERROR_COMMON_SUCCESS;
126158
}
159+
if (errorCode == U_ERROR_COMMON_SUCCESS) {
160+
if (pConfig->pInterrupt != NULL) {
161+
// Set up the interrupt
162+
errorCode = U_ERROR_COMMON_PLATFORM;
163+
espErr = ESP_OK;
164+
if (!gIsrServiceInstalled) {
165+
espErr = gpio_install_isr_service(U_PORT_GPIO_ESPIDF_INTERRUPT_FLAGS);
166+
}
167+
// Note: ESP_ERR_INVALID_STATE means that the service is already
168+
// installed (might have been done by the application for other reasons)
169+
if ((espErr == ESP_OK) || (espErr == ESP_ERR_INVALID_STATE)) {
170+
gIsrServiceInstalled = true;
171+
if (gpio_isr_handler_add((gpio_num_t) pConfig->pin,
172+
isrHandler,
173+
pConfig->pInterrupt) == ESP_OK) {
174+
errorCode = U_ERROR_COMMON_SUCCESS;
175+
}
176+
}
177+
} else {
178+
if (gIsrServiceInstalled) {
179+
// If an interrupt is NOT requested then, in case it had been
180+
// previously, blindly call the "remove" function
181+
gpio_isr_handler_remove((gpio_num_t) pConfig->pin);
182+
}
183+
}
184+
}
127185
}
128186
}
129187
}
@@ -156,4 +214,10 @@ int32_t uPortGpioGet(int32_t pin)
156214
return gpio_get_level((gpio_num_t) pin);
157215
}
158216

217+
// Interrupt support.
218+
bool uPortGpioInterruptSupported()
219+
{
220+
return true;
221+
}
222+
159223
// End of file

port/platform/linux/src/u_port_gpio.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,9 @@ U_WEAK int32_t uPortGpioConfig(uPortGpioConfig_t *pConfig)
146146
if ((pConfig != NULL) &&
147147
(pConfig->pin >= 0) && (pConfig->pin < sizeof(gPinIndex) / sizeof(gPinIndex[0])) &&
148148
// Needs to be a signed compare or an index of -1 fails the test below
149-
(pConfig->index < (int32_t) (sizeof(gpGpioChip) / sizeof(gpGpioChip[0])))) {
149+
(pConfig->index < (int32_t) (sizeof(gpGpioChip) / sizeof(gpGpioChip[0]))) &&
150+
// Interrupts not supported
151+
(pConfig->pInterrupt == NULL)) {
150152
index = pConfig->index;
151153
if (index < 0) {
152154
index = U_PORT_GPIO_CHIP_INDEX_DEFAULT;

port/platform/stm32cube/mcu/stm32f4/cfg/u_cfg_hw_platform_specific.h

+118
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
* Some of the values may be configured for your hardware,
2929
* others are fixed inside the STM32F4 chip; each section describes
3030
* which is the case.
31+
*
3132
* Note that "UART" is used throughout this code, rather than
3233
* switching between "UART" and "USART" and having to
3334
* remember which number UART/USART is which.
@@ -271,6 +272,123 @@
271272
*/
272273
#define U_CFG_HW_UART8_DMA_CHANNEL 5
273274

275+
/* ----------------------------------------------------------------
276+
* COMPILE-TIME MACROS FOR STM32F4: EXTI (INTERRUPTS NEED FOR GPIO)
277+
* -------------------------------------------------------------- */
278+
279+
/** In order to support use of a GPIO line as an interrupt, the
280+
* relevant interrupt function needs to be made available to ubxlib.
281+
* For STM32F4 there are 16 interrupts available where EXTI 0 serves
282+
* pin 0 on any of the GPIO ports (A to I), EXTI 1 serves pin 1 on
283+
* any of the GPIO ports, etc, up to EXTI 15 serving pins 15.
284+
*
285+
* The only usage of GPIO interrupts by ubxlib is if a Data Ready
286+
* pin is to be used with a GNSS device; one EXTI interrupt is
287+
* required for each GNSS device where this is the case.
288+
*
289+
* So if, for instance, you want to use pin B5 as your Data Ready
290+
* pin, you would need to make sure that U_CFG_HW_EXTI_5_AVAILABLE,
291+
* the EXTI for GPIO pin 5, was set to 1; the uPortGpio driver
292+
* here will then set the relevant SYSCFG_EXTI register to indicate
293+
* that EXTI5 is to monitor port B: hence pin B5, et voila.
294+
*/
295+
296+
#ifndef U_CFG_HW_EXTI_0_AVAILABLE
297+
/** Whether EXTI 0 is available to ubxlib.
298+
*/
299+
# define U_CFG_HW_EXTI_0_AVAILABLE 0
300+
#endif
301+
302+
#ifndef U_CFG_HW_EXTI_1_AVAILABLE
303+
/** Whether EXTI 1 is available to ubxlib.
304+
*/
305+
# define U_CFG_HW_EXTI_1_AVAILABLE 0
306+
#endif
307+
308+
#ifndef U_CFG_HW_EXTI_2_AVAILABLE
309+
/** Whether EXTI 2 is available to ubxlib.
310+
*/
311+
# define U_CFG_HW_EXTI_2_AVAILABLE 0
312+
#endif
313+
314+
#ifndef U_CFG_HW_EXTI_3_AVAILABLE
315+
/** Whether EXTI 3 is available to ubxlib.
316+
*/
317+
# define U_CFG_HW_EXTI_3_AVAILABLE 0
318+
#endif
319+
320+
#ifndef U_CFG_HW_EXTI_4_AVAILABLE
321+
/** Whether EXTI 4 is available to ubxlib.
322+
*/
323+
# define U_CFG_HW_EXTI_4_AVAILABLE 0
324+
#endif
325+
326+
#ifndef U_CFG_HW_EXTI_5_AVAILABLE
327+
/** Whether EXTI 5 is available to ubxlib.
328+
*/
329+
# define U_CFG_HW_EXTI_5_AVAILABLE 0
330+
#endif
331+
332+
#ifndef U_CFG_HW_EXTI_6_AVAILABLE
333+
/** Whether EXTI 6 is available to ubxlib.
334+
*/
335+
# define U_CFG_HW_EXTI_6_AVAILABLE 0
336+
#endif
337+
338+
#ifndef U_CFG_HW_EXTI_7_AVAILABLE
339+
/** Whether EXTI 7 is available to ubxlib.
340+
*/
341+
# define U_CFG_HW_EXTI_7_AVAILABLE 0
342+
#endif
343+
344+
#ifndef U_CFG_HW_EXTI_8_AVAILABLE
345+
/** Whether EXTI 8 is available to ubxlib.
346+
*/
347+
# define U_CFG_HW_EXTI_8_AVAILABLE 0
348+
#endif
349+
350+
#ifndef U_CFG_HW_EXTI_9_AVAILABLE
351+
/** Whether EXTI 9 is available to ubxlib.
352+
*/
353+
# define U_CFG_HW_EXTI_9_AVAILABLE 0
354+
#endif
355+
356+
#ifndef U_CFG_HW_EXTI_10_AVAILABLE
357+
/** Whether EXTI 10 is available to ubxlib.
358+
*/
359+
# define U_CFG_HW_EXTI_10_AVAILABLE 0
360+
#endif
361+
362+
#ifndef U_CFG_HW_EXTI_11_AVAILABLE
363+
/** Whether EXTI 11 is available to ubxlib.
364+
*/
365+
# define U_CFG_HW_EXTI_11_AVAILABLE 0
366+
#endif
367+
368+
#ifndef U_CFG_HW_EXTI_12_AVAILABLE
369+
/** Whether EXTI 12 is available to ubxlib.
370+
*/
371+
# define U_CFG_HW_EXTI_12_AVAILABLE 0
372+
#endif
373+
374+
#ifndef U_CFG_HW_EXTI_13_AVAILABLE
375+
/** Whether EXTI 13 is available to ubxlib.
376+
*/
377+
# define U_CFG_HW_EXTI_13_AVAILABLE 0
378+
#endif
379+
380+
#ifndef U_CFG_HW_EXTI_14_AVAILABLE
381+
/** Whether EXTI 14 is available to ubxlib.
382+
*/
383+
# define U_CFG_HW_EXTI_14_AVAILABLE 0
384+
#endif
385+
386+
#ifndef U_CFG_HW_EXTI_15_AVAILABLE
387+
/** Whether EXTI 15 is available to ubxlib.
388+
*/
389+
# define U_CFG_HW_EXTI_15_AVAILABLE 0
390+
#endif
391+
274392
#endif // _U_CFG_HW_PLATFORM_SPECIFIC_H_
275393

276394
// End of file

0 commit comments

Comments
 (0)