Skip to content

Commit 514b73b

Browse files
authored
Merge pull request #4254 from gamblor21/rp2040_countio
Rp2040 countio
2 parents 1d8933d + 98075c5 commit 514b73b

File tree

8 files changed

+163
-1
lines changed

8 files changed

+163
-1
lines changed

locale/circuitpython.pot

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1722,6 +1722,14 @@ msgid ""
17221722
"PWM frequency not writable when variable_frequency is False on construction."
17231723
msgstr ""
17241724

1725+
#: ports/raspberrypi/common-hal/countio/Counter.c
1726+
msgid "PWM slice already in use"
1727+
msgstr ""
1728+
1729+
#: ports/raspberrypi/common-hal/countio/Counter.c
1730+
msgid "PWM slice channel A already in use"
1731+
msgstr ""
1732+
17251733
#: ports/mimxrt10xx/common-hal/displayio/ParallelBus.c
17261734
#: ports/raspberrypi/common-hal/displayio/ParallelBus.c
17271735
#: ports/stm/common-hal/displayio/ParallelBus.c
@@ -1759,6 +1767,10 @@ msgstr ""
17591767
msgid "Pin is input only"
17601768
msgstr ""
17611769

1770+
#: ports/raspberrypi/common-hal/countio/Counter.c
1771+
msgid "Pin must be on PWM Channel B"
1772+
msgstr ""
1773+
17621774
#: ports/atmel-samd/common-hal/countio/Counter.c
17631775
msgid "Pin must support hardware interrupts"
17641776
msgstr ""
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#include "common-hal/countio/Counter.h"
2+
3+
#include "py/runtime.h"
4+
#include "py/mpstate.h"
5+
#include "supervisor/shared/translate.h"
6+
7+
#include "common-hal/pwmio/PWMOut.h"
8+
9+
#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h"
10+
#include "src/rp2_common/hardware_pwm/include/hardware/pwm.h"
11+
#include "src/rp2_common/hardware_irq/include/hardware/irq.h"
12+
13+
14+
void common_hal_countio_counter_construct(countio_counter_obj_t* self,
15+
const mcu_pin_obj_t* pin_a) {
16+
17+
if (pwm_gpio_to_channel(pin_a->number) != PWM_CHAN_B) {
18+
mp_raise_RuntimeError(translate("Pin must be on PWM Channel B"));
19+
}
20+
21+
self->pin_a = pin_a->number;
22+
self->slice_num = pwm_gpio_to_slice_num(self->pin_a);
23+
24+
if (MP_STATE_PORT(counting)[self->slice_num] != NULL) {
25+
mp_raise_RuntimeError(translate("PWM slice already in use"));
26+
}
27+
28+
uint8_t channel = pwm_gpio_to_channel(self->pin_a);
29+
if (!pwmio_claim_slice_channels(self->slice_num)) {
30+
mp_raise_RuntimeError(translate("PWM slice channel A already in use"));
31+
}
32+
33+
pwm_clear_irq(self->slice_num);
34+
pwm_set_irq_enabled(self->slice_num, true);
35+
irq_set_exclusive_handler(PWM_IRQ_WRAP, counter_interrupt_handler);
36+
irq_set_enabled(PWM_IRQ_WRAP, true);
37+
38+
pwm_config cfg = pwm_get_default_config();
39+
pwm_config_set_clkdiv_mode(&cfg, PWM_DIV_B_RISING);
40+
pwm_init(self->slice_num, &cfg, false);
41+
gpio_set_function(self->pin_a, GPIO_FUNC_PWM);
42+
43+
claim_pin(pin_a);
44+
45+
MP_STATE_PORT(counting)[self->slice_num] = self;
46+
47+
self->count = 0;
48+
pwm_set_enabled(self->slice_num, true);
49+
}
50+
51+
bool common_hal_countio_counter_deinited(countio_counter_obj_t* self) {
52+
return self->pin_a == 0;
53+
}
54+
55+
void common_hal_countio_counter_deinit(countio_counter_obj_t* self) {
56+
if (common_hal_countio_counter_deinited(self)) {
57+
return;
58+
}
59+
60+
pwm_set_enabled(self->slice_num, false);
61+
pwm_set_irq_enabled(self->slice_num, false);
62+
63+
pwmio_release_slice_channels(self->slice_num);
64+
65+
reset_pin_number(self->pin_a);
66+
67+
MP_STATE_PORT(counting)[self->slice_num] = NULL;
68+
self->pin_a = 0;
69+
self->slice_num = 0;
70+
}
71+
72+
mp_int_t common_hal_countio_counter_get_count(countio_counter_obj_t* self) {
73+
self->count += pwm_get_counter(self->slice_num);
74+
pwm_set_counter(self->slice_num, 0);
75+
return self->count;
76+
}
77+
78+
void common_hal_countio_counter_set_count(countio_counter_obj_t* self,
79+
mp_int_t new_count) {
80+
pwm_set_counter(self->slice_num, 0);
81+
self->count = new_count;
82+
}
83+
84+
void common_hal_countio_counter_reset(countio_counter_obj_t* self){
85+
pwm_set_counter(self->slice_num, 0);
86+
self->count = 0;
87+
}
88+
89+
void counter_interrupt_handler() {
90+
uint32_t mask = pwm_get_irq_status_mask();
91+
92+
uint8_t i = 1, pos = 1;
93+
while (!(i & mask)) {
94+
i = i << 1;
95+
++pos;
96+
}
97+
98+
countio_counter_obj_t *self = MP_STATE_PORT(counting)[pos-1];
99+
if (self != NULL) {
100+
pwm_clear_irq(self->slice_num);
101+
self->count += 65536;
102+
}
103+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
#ifndef MICROPY_INCLUDED_RASPBERRRYPI_COMMON_HAL_COUNTIO_COUNTER_H
3+
#define MICROPY_INCLUDED_RASPBERRRYPI_COMMON_HAL_COUNTIO_COUNTER_H
4+
5+
#include "common-hal/microcontroller/Pin.h"
6+
7+
#include "py/obj.h"
8+
9+
typedef struct {
10+
mp_obj_base_t base;
11+
uint8_t pin_a;
12+
uint8_t slice_num;
13+
mp_int_t count;
14+
} countio_counter_obj_t;
15+
16+
17+
void counter_interrupt_handler();
18+
19+
#endif // MICROPY_INCLUDED_RASPBERRRYPI_COMMON_HAL_COUNTIO_COUNTER_H
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//No countio module functions

ports/raspberrypi/common-hal/pwmio/PWMOut.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,29 @@ static uint32_t _mask(uint8_t slice, uint8_t channel) {
6161
return 1 << (slice * CHANNELS_PER_SLICE + channel);
6262
}
6363

64+
bool pwmio_claim_slice_channels(uint8_t slice) {
65+
uint32_t channel_use_mask_a = _mask(slice, 0);
66+
uint32_t channel_use_mask_b = _mask(slice, 1);
67+
68+
if ((channel_use & channel_use_mask_a) != 0) {
69+
return false;
70+
}
71+
if ((channel_use & channel_use_mask_b) != 0) {
72+
return false;
73+
}
74+
75+
channel_use |= channel_use_mask_a;
76+
channel_use |= channel_use_mask_b;
77+
return true;
78+
}
79+
80+
void pwmio_release_slice_channels(uint8_t slice) {
81+
uint32_t channel_mask = _mask(slice, 0);
82+
channel_use &= ~channel_mask;
83+
channel_mask = _mask(slice, 1);
84+
channel_use &= ~channel_mask;
85+
}
86+
6487
void pwmout_never_reset(uint8_t slice, uint8_t channel) {
6588
never_reset_channel |= _mask(slice, channel);
6689
}

ports/raspberrypi/common-hal/pwmio/PWMOut.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,8 @@ void pwmout_free(uint8_t slice, uint8_t channel);
5151
void pwmout_never_reset(uint8_t slice, uint8_t channel);
5252
void pwmout_reset_ok(uint8_t slice, uint8_t channel);
5353

54+
// Private API for countio to claim both channels on a slice
55+
bool pwmio_claim_slice_channels(uint8_t slice);
56+
void pwmio_release_slice_channels(uint8_t slice);
57+
5458
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PWMIO_PWMOUT_H

ports/raspberrypi/mpconfigport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "py/circuitpy_mpconfig.h"
4545

4646
#define MICROPY_PORT_ROOT_POINTERS \
47+
mp_obj_t counting[NUM_PWM_SLICES]; \
4748
mp_obj_t playing_audio[NUM_DMA_CHANNELS]; \
4849
CIRCUITPY_COMMON_ROOT_POINTERS;
4950

ports/raspberrypi/mpconfigport.mk

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ CIRCUITPY_PWMIO = 1
3030
CIRCUITPY_RGBMATRIX = 1
3131

3232
# Things that need to be implemented.
33-
CIRCUITPY_COUNTIO = 0 # Use PWM interally
3433
CIRCUITPY_FREQUENCYIO = 0 # Use PWM interally
3534
CIRCUITPY_I2CPERIPHERAL = 0
3635
CIRCUITPY_NVM = 1

0 commit comments

Comments
 (0)