diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index de921ec87f..2e31d5dfc1 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1722,6 +1722,14 @@ msgid "" "PWM frequency not writable when variable_frequency is False on construction." msgstr "" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice already in use" +msgstr "" + +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice channel A already in use" +msgstr "" + #: ports/mimxrt10xx/common-hal/displayio/ParallelBus.c #: ports/raspberrypi/common-hal/displayio/ParallelBus.c #: ports/stm/common-hal/displayio/ParallelBus.c @@ -1759,6 +1767,10 @@ msgstr "" msgid "Pin is input only" msgstr "" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "Pin must be on PWM Channel B" +msgstr "" + #: ports/atmel-samd/common-hal/countio/Counter.c msgid "Pin must support hardware interrupts" msgstr "" diff --git a/ports/raspberrypi/common-hal/countio/Counter.c b/ports/raspberrypi/common-hal/countio/Counter.c new file mode 100644 index 0000000000..69629a0848 --- /dev/null +++ b/ports/raspberrypi/common-hal/countio/Counter.c @@ -0,0 +1,103 @@ +#include "common-hal/countio/Counter.h" + +#include "py/runtime.h" +#include "py/mpstate.h" +#include "supervisor/shared/translate.h" + +#include "common-hal/pwmio/PWMOut.h" + +#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h" +#include "src/rp2_common/hardware_pwm/include/hardware/pwm.h" +#include "src/rp2_common/hardware_irq/include/hardware/irq.h" + + +void common_hal_countio_counter_construct(countio_counter_obj_t* self, + const mcu_pin_obj_t* pin_a) { + + if (pwm_gpio_to_channel(pin_a->number) != PWM_CHAN_B) { + mp_raise_RuntimeError(translate("Pin must be on PWM Channel B")); + } + + self->pin_a = pin_a->number; + self->slice_num = pwm_gpio_to_slice_num(self->pin_a); + + if (MP_STATE_PORT(counting)[self->slice_num] != NULL) { + mp_raise_RuntimeError(translate("PWM slice already in use")); + } + + uint8_t channel = pwm_gpio_to_channel(self->pin_a); + if (!pwmio_claim_slice_channels(self->slice_num)) { + mp_raise_RuntimeError(translate("PWM slice channel A already in use")); + } + + pwm_clear_irq(self->slice_num); + pwm_set_irq_enabled(self->slice_num, true); + irq_set_exclusive_handler(PWM_IRQ_WRAP, counter_interrupt_handler); + irq_set_enabled(PWM_IRQ_WRAP, true); + + pwm_config cfg = pwm_get_default_config(); + pwm_config_set_clkdiv_mode(&cfg, PWM_DIV_B_RISING); + pwm_init(self->slice_num, &cfg, false); + gpio_set_function(self->pin_a, GPIO_FUNC_PWM); + + claim_pin(pin_a); + + MP_STATE_PORT(counting)[self->slice_num] = self; + + self->count = 0; + pwm_set_enabled(self->slice_num, true); +} + +bool common_hal_countio_counter_deinited(countio_counter_obj_t* self) { + return self->pin_a == 0; +} + +void common_hal_countio_counter_deinit(countio_counter_obj_t* self) { + if (common_hal_countio_counter_deinited(self)) { + return; + } + + pwm_set_enabled(self->slice_num, false); + pwm_set_irq_enabled(self->slice_num, false); + + pwmio_release_slice_channels(self->slice_num); + + reset_pin_number(self->pin_a); + + MP_STATE_PORT(counting)[self->slice_num] = NULL; + self->pin_a = 0; + self->slice_num = 0; +} + +mp_int_t common_hal_countio_counter_get_count(countio_counter_obj_t* self) { + self->count += pwm_get_counter(self->slice_num); + pwm_set_counter(self->slice_num, 0); + return self->count; +} + +void common_hal_countio_counter_set_count(countio_counter_obj_t* self, + mp_int_t new_count) { + pwm_set_counter(self->slice_num, 0); + self->count = new_count; +} + +void common_hal_countio_counter_reset(countio_counter_obj_t* self){ + pwm_set_counter(self->slice_num, 0); + self->count = 0; +} + +void counter_interrupt_handler() { + uint32_t mask = pwm_get_irq_status_mask(); + + uint8_t i = 1, pos = 1; + while (!(i & mask)) { + i = i << 1; + ++pos; + } + + countio_counter_obj_t *self = MP_STATE_PORT(counting)[pos-1]; + if (self != NULL) { + pwm_clear_irq(self->slice_num); + self->count += 65536; + } +} diff --git a/ports/raspberrypi/common-hal/countio/Counter.h b/ports/raspberrypi/common-hal/countio/Counter.h new file mode 100644 index 0000000000..201034cf46 --- /dev/null +++ b/ports/raspberrypi/common-hal/countio/Counter.h @@ -0,0 +1,19 @@ + +#ifndef MICROPY_INCLUDED_RASPBERRRYPI_COMMON_HAL_COUNTIO_COUNTER_H +#define MICROPY_INCLUDED_RASPBERRRYPI_COMMON_HAL_COUNTIO_COUNTER_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + uint8_t pin_a; + uint8_t slice_num; + mp_int_t count; +} countio_counter_obj_t; + + +void counter_interrupt_handler(); + +#endif // MICROPY_INCLUDED_RASPBERRRYPI_COMMON_HAL_COUNTIO_COUNTER_H diff --git a/ports/raspberrypi/common-hal/countio/__init__.c b/ports/raspberrypi/common-hal/countio/__init__.c new file mode 100644 index 0000000000..b95b20d153 --- /dev/null +++ b/ports/raspberrypi/common-hal/countio/__init__.c @@ -0,0 +1 @@ +//No countio module functions diff --git a/ports/raspberrypi/common-hal/pwmio/PWMOut.c b/ports/raspberrypi/common-hal/pwmio/PWMOut.c index 9ca31a35ee..fd85fbf55b 100644 --- a/ports/raspberrypi/common-hal/pwmio/PWMOut.c +++ b/ports/raspberrypi/common-hal/pwmio/PWMOut.c @@ -61,6 +61,29 @@ static uint32_t _mask(uint8_t slice, uint8_t channel) { return 1 << (slice * CHANNELS_PER_SLICE + channel); } +bool pwmio_claim_slice_channels(uint8_t slice) { + uint32_t channel_use_mask_a = _mask(slice, 0); + uint32_t channel_use_mask_b = _mask(slice, 1); + + if ((channel_use & channel_use_mask_a) != 0) { + return false; + } + if ((channel_use & channel_use_mask_b) != 0) { + return false; + } + + channel_use |= channel_use_mask_a; + channel_use |= channel_use_mask_b; + return true; +} + +void pwmio_release_slice_channels(uint8_t slice) { + uint32_t channel_mask = _mask(slice, 0); + channel_use &= ~channel_mask; + channel_mask = _mask(slice, 1); + channel_use &= ~channel_mask; +} + void pwmout_never_reset(uint8_t slice, uint8_t channel) { never_reset_channel |= _mask(slice, channel); } diff --git a/ports/raspberrypi/common-hal/pwmio/PWMOut.h b/ports/raspberrypi/common-hal/pwmio/PWMOut.h index 8221bef179..41da810106 100644 --- a/ports/raspberrypi/common-hal/pwmio/PWMOut.h +++ b/ports/raspberrypi/common-hal/pwmio/PWMOut.h @@ -51,4 +51,8 @@ void pwmout_free(uint8_t slice, uint8_t channel); void pwmout_never_reset(uint8_t slice, uint8_t channel); void pwmout_reset_ok(uint8_t slice, uint8_t channel); +// Private API for countio to claim both channels on a slice +bool pwmio_claim_slice_channels(uint8_t slice); +void pwmio_release_slice_channels(uint8_t slice); + #endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PWMIO_PWMOUT_H diff --git a/ports/raspberrypi/mpconfigport.h b/ports/raspberrypi/mpconfigport.h index 4dd3d12684..dba008a94d 100644 --- a/ports/raspberrypi/mpconfigport.h +++ b/ports/raspberrypi/mpconfigport.h @@ -44,6 +44,7 @@ #include "py/circuitpy_mpconfig.h" #define MICROPY_PORT_ROOT_POINTERS \ + mp_obj_t counting[NUM_PWM_SLICES]; \ mp_obj_t playing_audio[NUM_DMA_CHANNELS]; \ CIRCUITPY_COMMON_ROOT_POINTERS; diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index 4e55b0a09e..4c149cb2b8 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -30,7 +30,6 @@ CIRCUITPY_PWMIO = 1 CIRCUITPY_RGBMATRIX = 1 # Things that need to be implemented. -CIRCUITPY_COUNTIO = 0 # Use PWM interally CIRCUITPY_FREQUENCYIO = 0 # Use PWM interally CIRCUITPY_I2CPERIPHERAL = 0 CIRCUITPY_NVM = 1