Enable protomatter on RP2040 builds

Also found a race condition between timer_disable and redraw, which
would happen if I debugger-paused inside common_hal_rgbmatrix_timer_disable
or put a delay or print inside it.  That's what pausing inside reconstruct
fixes.

So that the "right timer" can be chosen, `timer_allocate` now gets the `self`
pointer.  It's guaranteed at this point that the pin information is accurate,
so you can e.g., find a PWM unit related to the pins themselves.
This required touching each port to add the parameter even though it's
unused everywhere but raspberrypi.
This commit is contained in:
Jeff Epler 2021-02-11 16:37:34 -06:00
parent aae10fb37f
commit ff1942cff6
16 changed files with 183 additions and 38 deletions

@ -1 +1 @@
Subproject commit 5e925cea7a55273e375a6129761cb29b4e750d4f
Subproject commit 78cde804759c2e910f393b077368dc9fe1f6a630

View File

@ -31,7 +31,7 @@
#include "samd/timers.h"
#include "timer_handler.h"
void *common_hal_rgbmatrix_timer_allocate() {
void *common_hal_rgbmatrix_timer_allocate(rgbmatrix_rgbmatrix_obj_t *self) {
uint8_t timer_index = find_free_timer();
if (timer_index == 0xff) {
return NULL;

View File

@ -27,7 +27,9 @@
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_RGBMATRIX_RGBMATRIX_H
#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_RGBMATRIX_RGBMATRIX_H
void *common_hal_rgbmatrix_timer_allocate(void);
#include "shared-module/rgbmatrix/RGBMatrix.h"
void *common_hal_rgbmatrix_timer_allocate(rgbmatrix_rgbmatrix_obj_t *self);
void common_hal_rgbmatrix_timer_enable(void*);
void common_hal_rgbmatrix_timer_disable(void*);
void common_hal_rgbmatrix_timer_free(void*);

View File

@ -32,7 +32,7 @@
extern void _PM_IRQ_HANDLER(void);
void *common_hal_rgbmatrix_timer_allocate() {
void *common_hal_rgbmatrix_timer_allocate(rgbmatrix_rgbmatrix_obj_t *self) {
nrfx_timer_t *timer = nrf_peripherals_allocate_timer_or_throw();
nrf_peripherals_timer_never_reset(timer);
return timer->p_reg;

View File

@ -27,7 +27,9 @@
#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_RGBMATRIX_RGBMATRIX_H
#define MICROPY_INCLUDED_NRF_COMMON_HAL_RGBMATRIX_RGBMATRIX_H
void *common_hal_rgbmatrix_timer_allocate(void);
#include "shared-module/rgbmatrix/RGBMatrix.h"
void *common_hal_rgbmatrix_timer_allocate(rgbmatrix_rgbmatrix_obj_t *self);
void common_hal_rgbmatrix_timer_enable(void*);
void common_hal_rgbmatrix_timer_disable(void*);
void common_hal_rgbmatrix_timer_free(void*);

View File

@ -49,14 +49,22 @@ static uint32_t _mask(uint8_t slice, uint8_t channel) {
return 1 << (slice * CHANNELS_PER_SLICE + channel);
}
void pwmout_never_reset(uint8_t slice, uint8_t channel) {
never_reset_channel |= _mask(slice, channel);
}
void pwmout_reset_ok(uint8_t slice, uint8_t channel) {
never_reset_channel &= ~_mask(slice, channel);
}
void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self) {
never_reset_channel |= _mask(self->slice, self->channel);
pwmout_never_reset(self->slice, self->channel);
never_reset_pin_number(self->pin->number);
}
void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self) {
never_reset_channel &= ~_mask(self->slice, self->channel);
pwmout_reset_ok(self->slice, self->channel);
}
void pwmout_reset(void) {
@ -80,21 +88,7 @@ void pwmout_reset(void) {
}
}
pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t* self,
const mcu_pin_obj_t* pin,
uint16_t duty,
uint32_t frequency,
bool variable_frequency) {
self->pin = pin;
self->variable_frequency = variable_frequency;
self->duty_cycle = duty;
if (frequency == 0 || frequency > (common_hal_mcu_processor_get_frequency() / 2)) {
return PWMOUT_INVALID_FREQUENCY;
}
uint8_t slice = pwm_gpio_to_slice_num(pin->number);
uint8_t channel = pwm_gpio_to_channel(pin->number);
pwmout_result_t pwmout_allocate(uint8_t slice, uint8_t channel, bool variable_frequency, uint32_t frequency) {
uint32_t channel_use_mask = _mask(slice, channel);
// Check the channel first.
@ -116,14 +110,39 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t* self,
return PWMOUT_ALL_TIMERS_ON_PIN_IN_USE;
}
}
self->slice = slice;
self->channel = channel;
channel_use |= channel_use_mask;
if (variable_frequency) {
slice_variable_frequency |= 1 << slice;
}
return PWMOUT_OK;
}
pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t* self,
const mcu_pin_obj_t* pin,
uint16_t duty,
uint32_t frequency,
bool variable_frequency) {
self->pin = pin;
self->variable_frequency = variable_frequency;
self->duty_cycle = duty;
if (frequency == 0 || frequency > (common_hal_mcu_processor_get_frequency() / 2)) {
return PWMOUT_INVALID_FREQUENCY;
}
uint8_t slice = pwm_gpio_to_slice_num(pin->number);
uint8_t channel = pwm_gpio_to_channel(pin->number);
int r = pwmout_allocate(slice, channel, variable_frequency, frequency);
if (r != PWMOUT_OK) {
return r;
}
self->slice = slice;
self->channel = channel;
if (target_slice_frequencies[slice] != frequency) {
// Reset the counter and compare values.
pwm_hw->slice[slice].ctr = PWM_CH0_CTR_RESET;
@ -144,20 +163,23 @@ bool common_hal_pwmio_pwmout_deinited(pwmio_pwmout_obj_t* self) {
return self->pin == NULL;
}
void pwmout_free(uint8_t slice, uint8_t channel) {
uint32_t channel_mask = _mask(slice, channel);
channel_use &= ~channel_mask;
never_reset_channel &= ~channel_mask;
uint32_t slice_mask = ((1 << CHANNELS_PER_SLICE) - 1) << (slice * CHANNELS_PER_SLICE + channel);
if ((channel_use & slice_mask) == 0) {
target_slice_frequencies[slice] = 0;
slice_variable_frequency &= ~(1 << slice);
pwm_set_enabled(slice, false);
}
}
void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t* self) {
if (common_hal_pwmio_pwmout_deinited(self)) {
return;
}
uint32_t channel_mask = _mask(self->slice, self->channel);
channel_use &= ~channel_mask;
never_reset_channel &= ~channel_mask;
uint32_t slice_mask = ((1 << CHANNELS_PER_SLICE) - 1) << (self->slice * CHANNELS_PER_SLICE + self->channel);
if ((channel_use & slice_mask) == 0) {
target_slice_frequencies[self->slice] = 0;
slice_variable_frequency &= ~(1 << self->slice);
pwm_set_enabled(self->slice, false);
}
pwmout_free(self->slice, self->channel);
reset_pin_number(self->pin->number);
self->pin = NULL;
}

View File

@ -45,5 +45,10 @@ typedef struct {
void pwmout_reset(void);
// Private API for AudioPWMOut.
void pwmio_pwmout_set_top(pwmio_pwmout_obj_t* self, uint32_t top);
// Private APIs for RGBMatrix
enum pwmout_result_t pwmout_allocate(uint8_t slice, uint8_t channel, bool variable_frequency, uint32_t frequency);
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);
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PWMIO_PWMOUT_H

View File

@ -0,0 +1,70 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Jeff Epler for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stddef.h>
#include "py/mphal.h"
#include "common-hal/rgbmatrix/RGBMatrix.h"
#include "shared-bindings/pwmio/PWMOut.h"
#include "shared-module/rgbmatrix/RGBMatrix.h"
#include "src/rp2_common/hardware_pwm/include/hardware/pwm.h"
void *common_hal_rgbmatrix_timer_allocate(rgbmatrix_rgbmatrix_obj_t *self) {
// Choose a PWM channel based on the first RGB pin
uint8_t slice = pwm_gpio_to_slice_num(self->rgb_pins[0]);
uint8_t channel = pwm_gpio_to_channel(self->rgb_pins[0]);
int result = pwmout_allocate(slice, channel, true, 125000000/3);
if (result == PWMOUT_OK) {
// return value must be nonzero (but slice and channel can both be
// zero), so set bit 16...
pwmout_never_reset(slice, channel);
return (void*)(intptr_t)(slice | (channel << 8) | 0x10000);
}
return NULL;
}
void common_hal_rgbmatrix_timer_enable(void* ptr) {
int8_t slice = ((intptr_t)ptr) & 0xff;
pwm_set_enabled(slice, false);
pwm_clear_irq(slice);
pwm_set_enabled(slice, true);
}
void common_hal_rgbmatrix_timer_disable(void* ptr) {
int8_t slice = ((intptr_t)ptr) & 0xff;
pwm_set_enabled(slice, false);
}
void common_hal_rgbmatrix_timer_free(void* ptr) {
intptr_t value = (intptr_t)ptr;
uint8_t slice = value & 0xff;
uint8_t channel = value >> 8;
pwm_set_enabled(slice, false);
pwmout_free(slice, channel);
return;
}

View File

@ -0,0 +1,37 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Jeff Epler for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_RGBMATRIX_RGBMATRIX_H
#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_RGBMATRIX_RGBMATRIX_H
#include "shared-module/rgbmatrix/RGBMatrix.h"
void *common_hal_rgbmatrix_timer_allocate(rgbmatrix_rgbmatrix_obj_t *self);
void common_hal_rgbmatrix_timer_enable(void*);
void common_hal_rgbmatrix_timer_disable(void*);
void common_hal_rgbmatrix_timer_free(void*);
#endif

View File

@ -23,8 +23,10 @@ else
CIRCUITPY_NEOPIXEL_WRITE = 0
endif
CIRCUITPY_FRAMEBUFFERIO = 1
CIRCUITPY_FULL_BUILD = 1
CIRCUITPY_PWMIO = 1
CIRCUITPY_RGBMATRIX = 1
# Things that need to be implemented.
CIRCUITPY_COUNTIO = 0 # Use PWM interally

View File

@ -33,7 +33,7 @@
extern void _PM_IRQ_HANDLER(void);
void *common_hal_rgbmatrix_timer_allocate() {
void *common_hal_rgbmatrix_timer_allocate(rgbmatrix_rgbmatrix_obj_t *self) {
TIM_TypeDef * timer = stm_peripherals_find_timer();
stm_peripherals_timer_reserve(timer);
stm_peripherals_timer_never_reset(timer);

View File

@ -27,7 +27,9 @@
#ifndef MICROPY_INCLUDED_STM_COMMON_HAL_RGBMATRIX_RGBMATRIX_H
#define MICROPY_INCLUDED_STM_COMMON_HAL_RGBMATRIX_RGBMATRIX_H
void *common_hal_rgbmatrix_timer_allocate(void);
#include "shared-module/rgbmatrix/RGBMatrix.h"
void *common_hal_rgbmatrix_timer_allocate(rgbmatrix_rgbmatrix_obj_t *self);
void common_hal_rgbmatrix_timer_enable(void*);
void common_hal_rgbmatrix_timer_disable(void*);
void common_hal_rgbmatrix_timer_free(void*);

View File

@ -32,7 +32,7 @@
extern const mp_obj_type_t pwmio_pwmout_type;
typedef enum {
typedef enum pwmout_result_t {
PWMOUT_OK,
PWMOUT_INVALID_PIN,
PWMOUT_INVALID_FREQUENCY,

View File

@ -56,7 +56,7 @@ void common_hal_rgbmatrix_rgbmatrix_construct(rgbmatrix_rgbmatrix_obj_t *self, i
self->tile = tile;
self->serpentine = serpentine;
self->timer = timer ? timer : common_hal_rgbmatrix_timer_allocate();
self->timer = timer ? timer : common_hal_rgbmatrix_timer_allocate(self);
if (self->timer == NULL) {
mp_raise_ValueError(translate("No timer available"));
}
@ -68,6 +68,8 @@ void common_hal_rgbmatrix_rgbmatrix_construct(rgbmatrix_rgbmatrix_obj_t *self, i
}
void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, mp_obj_t framebuffer) {
self->paused = 1;
common_hal_rgbmatrix_timer_disable(self->timer);
if (framebuffer) {
self->framebuffer = framebuffer;

View File

@ -26,6 +26,7 @@
#pragma once
#include "py/obj.h"
#include "lib/protomatter/src/core.h"
extern const mp_obj_type_t rgbmatrix_RGBMatrix_type;