Skip to content

Commit 47e1abd

Browse files
committed
Add IncrementalEncoder for mimxrt1011
.. and write a general 'pin change interrupt' facility to power it This uses the same quadrature state machine as atmel-samd, nrf, and rp2040. The 1011 doesn't have a dedicated encoder peripheral, so we go the pin-change + software route.
1 parent e1f1647 commit 47e1abd

File tree

9 files changed

+238
-2
lines changed

9 files changed

+238
-2
lines changed

ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040

4141
#define IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_ALT5 5U
4242

43-
STATIC void pin_config(const mcu_pin_obj_t *pin, bool open_drain, digitalio_pull_t pull) {
43+
void pin_config(const mcu_pin_obj_t *pin, bool open_drain, digitalio_pull_t pull) {
4444
IOMUXC_SetPinConfig(0, 0, 0, 0, pin->cfg_reg,
4545
IOMUXC_SW_PAD_CTL_PAD_HYS(1)
4646
| IOMUXC_SW_PAD_CTL_PAD_PUS((pull == PULL_UP) ? 2 : 0)

ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,6 @@ typedef struct {
4040
digitalio_pull_t pull;
4141
} digitalio_digitalinout_obj_t;
4242

43+
void pin_config(const mcu_pin_obj_t *pin, bool open_drain, digitalio_pull_t pull);
44+
4345
#endif // MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_DIGITALIO_DIGITALINOUT_H

ports/mimxrt10xx/common-hal/microcontroller/Pin.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ void common_hal_reset_pin(const mcu_pin_obj_t *pin) {
8484
return;
8585
}
8686

87+
disable_pin_change_interrupt(pin);
8788
never_reset_pins[pin->mux_idx] = false;
8889
claimed_pins[pin->mux_idx] = false;
8990
*(uint32_t *)pin->mux_reg = pin->mux_reset;
@@ -116,3 +117,100 @@ void claim_pin(const mcu_pin_obj_t *pin) {
116117
void common_hal_mcu_pin_reset_number(uint8_t pin_no) {
117118
common_hal_reset_pin((mcu_pin_obj_t *)(mcu_pin_globals.map.table[pin_no].value));
118119
}
120+
121+
/* Array of GPIO peripheral base address. */
122+
static GPIO_Type *const s_gpioBases[] = GPIO_BASE_PTRS;
123+
static uint32_t GPIO_GetInstance(GPIO_Type *base) {
124+
uint32_t instance;
125+
126+
/* Find the instance index from base address mappings. */
127+
for (instance = 0U; instance < ARRAY_SIZE(s_gpioBases); instance++)
128+
{
129+
if (s_gpioBases[instance] == base) {
130+
break;
131+
}
132+
}
133+
134+
assert(instance < ARRAY_SIZE(s_gpioBases));
135+
136+
return instance;
137+
}
138+
139+
/* to find IRQ based on GPIO */
140+
static const IRQn_Type low_irqs[] = GPIO_COMBINED_LOW_IRQS;
141+
static const IRQn_Type high_irqs[] = GPIO_COMBINED_HIGH_IRQS;
142+
143+
typedef struct {
144+
gpio_change_interrupt_t *func;
145+
void *data;
146+
} pin_change_interrupt_data;
147+
148+
volatile static pin_change_interrupt_data pcid[MP_ARRAY_SIZE(s_gpioBases)][32];
149+
150+
void enable_pin_change_interrupt(const mcu_pin_obj_t *pin, gpio_change_interrupt_t func, void *data) {
151+
int instance = GPIO_GetInstance(pin->gpio);
152+
volatile pin_change_interrupt_data *pci = &pcid[instance][pin->number];
153+
common_hal_mcu_disable_interrupts();
154+
pci->data = data;
155+
pci->func = func;
156+
IRQn_Type irq = pin->number < 16 ? low_irqs[instance] : high_irqs[instance];
157+
if (irq != NotAvail_IRQn) {
158+
EnableIRQ(irq);
159+
}
160+
pin->gpio->IMR |= (1 << pin->number);
161+
common_hal_mcu_enable_interrupts();
162+
}
163+
164+
void disable_pin_change_interrupt(const mcu_pin_obj_t *pin) {
165+
volatile pin_change_interrupt_data *pci = &pcid[GPIO_GetInstance(pin->gpio)][pin->number];
166+
common_hal_mcu_disable_interrupts();
167+
pin->gpio->IMR &= ~(1 << pin->number);
168+
pci->data = NULL;
169+
pci->func = NULL;
170+
pin->gpio->ISR = (1 << pin->number); // acknowledge any pending interrupt
171+
common_hal_mcu_enable_interrupts();
172+
}
173+
174+
static void pin_change_interrupt_common(uint32_t isr, volatile pin_change_interrupt_data *pcr) {
175+
for (uint32_t i = 0; i < 32; i++) {
176+
if (isr & (1 << i)) {
177+
pin_change_interrupt_data cb = pcr[i];
178+
if (cb.func) {
179+
cb.func(cb.data);
180+
}
181+
}
182+
}
183+
}
184+
185+
#define GPIO_INTERRUPT_HANDLER(name, ptr, instance, offset) \
186+
void name(void); \
187+
__attribute__((used)) void name(void) { \
188+
uint32_t isr = ptr->ISR; \
189+
ptr->ISR = isr; \
190+
pin_change_interrupt_common(isr, pcid[instance]); \
191+
}
192+
193+
#if defined(GPIO1)
194+
GPIO_INTERRUPT_HANDLER(GPIO1_Combined_0_15_IRQHandler, GPIO1, 1, 0);
195+
GPIO_INTERRUPT_HANDLER(GPIO1_Combined_16_31_IRQHandler, GPIO1, 1, 16);
196+
#endif
197+
#if defined(GPIO2)
198+
GPIO_INTERRUPT_HANDLER(GPIO2_Combined_0_15_IRQHandler, GPIO2, 2, 0);
199+
GPIO_INTERRUPT_HANDLER(GPIO2_Combined_16_31_IRQHandler, GPIO2, 2, 16);
200+
#endif
201+
#if defined(GPIO3)
202+
GPIO_INTERRUPT_HANDLER(GPIO3_Combined_0_15_IRQHandler, GPIO3, 3, 0);
203+
GPIO_INTERRUPT_HANDLER(GPIO3_Combined_16_31_IRQHandler, GPIO3, 3, 16);
204+
#endif
205+
#if defined(GPIO4)
206+
GPIO_INTERRUPT_HANDLER(GPIO4_Combined_0_15_IRQHandler, GPIO4, 4, 0);
207+
GPIO_INTERRUPT_HANDLER(GPIO4_Combined_16_31_IRQHandler, GPIO4, 4, 16);
208+
#endif
209+
#if defined(GPIO5)
210+
GPIO_INTERRUPT_HANDLER(GPIO5_Combined_0_15_IRQHandler, GPIO5, 5, 0);
211+
GPIO_INTERRUPT_HANDLER(GPIO5_Combined_16_31_IRQHandler, GPIO5, 5, 16);
212+
#endif
213+
#if defined(GPIO6)
214+
GPIO_INTERRUPT_HANDLER(GPIO6_Combined_0_15_IRQHandler, GPIO6, 6, 0);
215+
GPIO_INTERRUPT_HANDLER(GPIO6_Combined_16_31_IRQHandler, GPIO6, 6, 16);
216+
#endif

ports/mimxrt10xx/common-hal/microcontroller/Pin.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,8 @@ extern const mcu_pin_obj_t *mimxrt10xx_reset_forbidden_pins[];
4545
// the port-default reset behavior.
4646
extern bool mimxrt10xx_board_reset_pin_number(const mcu_pin_obj_t *pin);
4747

48+
typedef void (gpio_change_interrupt_t)(void *data);
49+
void disable_pin_change_interrupt(const mcu_pin_obj_t *pin);
50+
void enable_pin_change_interrupt(const mcu_pin_obj_t *pin, gpio_change_interrupt_t func, void *data);
51+
4852
#endif // MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_MICROCONTROLLER_PIN_H
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2019 Nick Moore for Adafruit Industries
7+
* Copyright (c) 2023 Jeff Epler for Adafruit Industries
8+
*
9+
* Permission is hereby granted, free of charge, to any person obtaining a copy
10+
* of this software and associated documentation files (the "Software"), to deal
11+
* in the Software without restriction, including without limitation the rights
12+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
* copies of the Software, and to permit persons to whom the Software is
14+
* furnished to do so, subject to the following conditions:
15+
*
16+
* The above copyright notice and this permission notice shall be included in
17+
* all copies or substantial portions of the Software.
18+
*
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
* THE SOFTWARE.
26+
*/
27+
28+
#include "common-hal/digitalio/DigitalInOut.h"
29+
#include "common-hal/rotaryio/IncrementalEncoder.h"
30+
#include "shared-module/rotaryio/IncrementalEncoder.h"
31+
#include "shared-bindings/microcontroller/Pin.h"
32+
#include "shared-bindings/rotaryio/IncrementalEncoder.h"
33+
34+
#include "py/runtime.h"
35+
36+
#include "fsl_gpio.h"
37+
static void encoder_change(void *self_in) {
38+
rotaryio_incrementalencoder_obj_t *self = self_in;
39+
40+
bool value_a = GPIO_PinRead(self->pin_a->gpio, self->pin_a->number);
41+
bool value_b = GPIO_PinRead(self->pin_b->gpio, self->pin_b->number);
42+
uint8_t new_state = (value_a << 1) | value_b;
43+
shared_module_softencoder_state_update(self, new_state);
44+
}
45+
46+
void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencoder_obj_t *self,
47+
const mcu_pin_obj_t *pin_a, const mcu_pin_obj_t *pin_b) {
48+
49+
self->pin_a = pin_a;
50+
self->pin_b = pin_b;
51+
52+
// GPIO is always IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_ALT5 until proven otherwise
53+
#define IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_ALT5 5U
54+
IOMUXC_SetPinMux(pin_a->mux_reg, IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_ALT5, 0, 0, 0, 0);
55+
IOMUXC_SetPinMux(pin_b->mux_reg, IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_ALT5, 0, 0, 0, 0);
56+
57+
const gpio_pin_config_t config = { kGPIO_DigitalInput, 0, kGPIO_IntRisingOrFallingEdge };
58+
GPIO_PinInit(pin_a->gpio, pin_a->number, &config);
59+
GPIO_PinInit(pin_b->gpio, pin_b->number, &config);
60+
61+
enable_pin_change_interrupt(pin_a, encoder_change, self);
62+
enable_pin_change_interrupt(pin_b, encoder_change, self);
63+
64+
pin_config(pin_a, false, PULL_UP);
65+
pin_config(pin_b, false, PULL_UP);
66+
67+
claim_pin(pin_a);
68+
claim_pin(pin_b);
69+
}
70+
71+
bool common_hal_rotaryio_incrementalencoder_deinited(rotaryio_incrementalencoder_obj_t *self) {
72+
return !self->pin_a;
73+
}
74+
75+
void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_obj_t *self) {
76+
if (common_hal_rotaryio_incrementalencoder_deinited(self)) {
77+
return;
78+
}
79+
disable_pin_change_interrupt(self->pin_a);
80+
disable_pin_change_interrupt(self->pin_b);
81+
82+
common_hal_reset_pin(self->pin_a);
83+
common_hal_reset_pin(self->pin_b);
84+
85+
self->pin_a = NULL;
86+
self->pin_b = NULL;
87+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
7+
* Copyright (c) 2023 Jeff Epler for Adafruit Industries
8+
*
9+
* Permission is hereby granted, free of charge, to any person obtaining a copy
10+
* of this software and associated documentation files (the "Software"), to deal
11+
* in the Software without restriction, including without limitation the rights
12+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
* copies of the Software, and to permit persons to whom the Software is
14+
* furnished to do so, subject to the following conditions:
15+
*
16+
* The above copyright notice and this permission notice shall be included in
17+
* all copies or substantial portions of the Software.
18+
*
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
* THE SOFTWARE.
26+
*/
27+
28+
#pragma once
29+
30+
#include "common-hal/microcontroller/Pin.h"
31+
32+
#include "py/obj.h"
33+
34+
typedef struct {
35+
mp_obj_base_t base;
36+
const mcu_pin_obj_t *pin_a, *pin_b;
37+
uint8_t state; // <old A><old B>
38+
int8_t sub_count; // count intermediate transitions between detents
39+
int8_t divisor; // Number of quadrature edges required per count
40+
mp_int_t position;
41+
} rotaryio_incrementalencoder_obj_t;
42+
43+
44+
void incrementalencoder_interrupt_handler(uint8_t channel);

ports/mimxrt10xx/common-hal/rotaryio/__init__.c

Whitespace-only changes.

ports/mimxrt10xx/common-hal/rotaryio/__init__.h

Whitespace-only changes.

ports/mimxrt10xx/mpconfigport.mk

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ CIRCUITPY_I2CTARGET = 0
2020
CIRCUITPY_NVM = 0
2121
CIRCUITPY_PARALLELDISPLAY = 0
2222
CIRCUITPY_PULSEIO = 0
23-
CIRCUITPY_ROTARYIO = 0
23+
CIRCUITPY_ROTARYIO = 1
24+
CIRCUITPY_ROTARYIO_SOFTENCODER = 1
2425
CIRCUITPY_USB_MIDI = 1
2526
LONGINT_IMPL = MPZ
2627

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy