Compare commits
14 commits
510c733482
...
7155be1a75
| Author | SHA1 | Date | |
|---|---|---|---|
| 7155be1a75 | |||
| e4506e5a57 | |||
|
|
eadf2ee814 | ||
|
|
d87532b044 | ||
|
|
68943a8fcd | ||
|
|
5ad5f33a16 | ||
|
|
429d625ba7 | ||
|
|
98a2da6da4 | ||
|
|
b0e9d045f8 | ||
|
|
40d0971635 | ||
|
|
1faaec39b3 | ||
|
|
67ac7d48d4 | ||
|
|
a6dec45c38 | ||
|
|
4430d1ceb5 |
8 changed files with 219 additions and 52 deletions
6
.github/workflows/githubci.yml
vendored
6
.github/workflows/githubci.yml
vendored
|
|
@ -12,11 +12,11 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/setup-python@v1
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.8'
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: adafruit/ci-arduino
|
||||
path: ci
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
name=Adafruit Protomatter
|
||||
version=1.6.1
|
||||
version=1.6.2
|
||||
author=Adafruit
|
||||
maintainer=Adafruit <info@adafruit.com>
|
||||
sentence=A library for Adafruit RGB LED matrices.
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ _PM_CUSTOM_BLAST If defined, instructs core code to not compile
|
|||
#include "esp32-s2.h"
|
||||
#include "esp32-s3.h"
|
||||
#include "esp32-c3.h"
|
||||
#include "esp32-c6.h"
|
||||
#include "nrf52.h"
|
||||
#include "rp2040.h"
|
||||
#include "samd-common.h"
|
||||
|
|
|
|||
57
src/arch/esp32-c6.h
Normal file
57
src/arch/esp32-c6.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*!
|
||||
* @file esp32-c3.h
|
||||
*
|
||||
* Part of Adafruit's Protomatter library for HUB75-style RGB LED matrices.
|
||||
* This file contains ESP32-C3-SPECIFIC CODE.
|
||||
*
|
||||
* Adafruit invests time and resources providing this open source code,
|
||||
* please support Adafruit and open-source hardware by purchasing
|
||||
* products from Adafruit!
|
||||
*
|
||||
* Written by Phil "Paint Your Dragon" Burgess and Jeff Epler for
|
||||
* Adafruit Industries, with contributions from the open source community.
|
||||
*
|
||||
* BSD license, all text here must be included in any redistribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// NOTE: there is some intentional repetition in the macros and functions
|
||||
// for some ESP32 variants. Previously they were all one file, but complex
|
||||
// preprocessor directives were turning into spaghetti. THEREFORE, if making
|
||||
// a change or bugfix in one variant-specific header, check the others to
|
||||
// see if the same should be applied!
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C6)
|
||||
|
||||
#define _PM_portOutRegister(pin) (volatile uint32_t *)&GPIO.out
|
||||
#define _PM_portSetRegister(pin) (volatile uint32_t *)&GPIO.out_w1ts
|
||||
#define _PM_portClearRegister(pin) (volatile uint32_t *)&GPIO.out_w1tc
|
||||
|
||||
#define _PM_portBitMask(pin) (1U << ((pin)&31))
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define _PM_byteOffset(pin) ((pin & 31) / 8)
|
||||
#define _PM_wordOffset(pin) ((pin & 31) / 16)
|
||||
#else
|
||||
#define _PM_byteOffset(pin) (3 - ((pin & 31) / 8))
|
||||
#define _PM_wordOffset(pin) (1 - ((pin & 31) / 16))
|
||||
#endif
|
||||
|
||||
// No special peripheral setup on ESP32C3, just use common timer init...
|
||||
#define _PM_timerInit(core) _PM_esp32commonTimerInit(core);
|
||||
|
||||
#if defined(ARDUINO) // COMPILING FOR ARDUINO ------------------------------
|
||||
// Return current count value (timer enabled or not).
|
||||
// Timer must be previously initialized.
|
||||
// This function is the same on all ESP32 parts EXCEPT S3.
|
||||
IRAM_ATTR inline uint32_t _PM_timerGetCount(Protomatter_core *core) {
|
||||
return (uint32_t)timerRead((hw_timer_t *)core->timer);
|
||||
}
|
||||
|
||||
#elif defined(CIRCUITPY) // COMPILING FOR CIRCUITPYTHON --------------------
|
||||
|
||||
#endif // END CIRCUITPYTHON ------------------------------------------------
|
||||
|
||||
#endif // END ESP32C3
|
||||
|
|
@ -20,6 +20,8 @@
|
|||
#if defined(ESP32) || \
|
||||
defined(ESP_PLATFORM) // *All* ESP32 variants (OG, S2, S3, etc.)
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "esp_idf_version.h"
|
||||
|
||||
// NOTE: there is some intentional repetition in the macros and functions
|
||||
|
|
@ -28,7 +30,6 @@
|
|||
// a change or bugfix in one variant-specific header, check the others to
|
||||
// see if the same should be applied!
|
||||
|
||||
#include "driver/timer.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
|
||||
// As currently written, only one instance of the Protomatter_core struct
|
||||
|
|
@ -39,7 +40,13 @@ Protomatter_core *_PM_protoPtr;
|
|||
|
||||
#if defined(ARDUINO) // COMPILING FOR ARDUINO ------------------------------
|
||||
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
#define _PM_timerNum 0 // Timer #0 (can be 0-3)
|
||||
static hw_timer_t *_PM_esp32timer = NULL;
|
||||
#define _PM_TIMER_DEFAULT &_PM_esp32timer
|
||||
#else
|
||||
#define _PM_TIMER_DEFAULT ((void *)-1) // some non-NULL but non valid pointer
|
||||
#endif
|
||||
|
||||
// The following defines and functions are common to all ESP32 variants in
|
||||
// the Arduino platform. Anything unique to one variant (or a subset of
|
||||
|
|
@ -48,16 +55,7 @@ Protomatter_core *_PM_protoPtr;
|
|||
// started down that path, it's okay, but move the code out of here and
|
||||
// into the variant-specific headers.
|
||||
|
||||
// This is the default aforementioned singular timer. IN THEORY, other
|
||||
// timers could be used, IF an Arduino sketch passes the address of its
|
||||
// own hw_timer_t* to the Protomatter constructor and initializes that
|
||||
// timer using ESP32's timerBegin(). All of the timer-related functions
|
||||
// below pass around a handle rather than accessing _PM_esp32timer directly,
|
||||
// in case that's ever actually used in the future.
|
||||
static hw_timer_t *_PM_esp32timer = NULL;
|
||||
#define _PM_TIMER_DEFAULT &_PM_esp32timer
|
||||
|
||||
extern IRAM_ATTR void _PM_row_handler(Protomatter_core *core); // In core.c
|
||||
extern void _PM_row_handler(Protomatter_core *core); // In core.c
|
||||
|
||||
// Timer interrupt handler. This, _PM_row_handler() and any functions
|
||||
// called by _PM_row_handler() should all have the IRAM_ATTR attribute
|
||||
|
|
@ -71,9 +69,15 @@ IRAM_ATTR static void _PM_esp32timerCallback(void) {
|
|||
// Set timer period, initialize count value to zero, enable timer.
|
||||
IRAM_ATTR inline void _PM_timerStart(Protomatter_core *core, uint32_t period) {
|
||||
hw_timer_t *timer = (hw_timer_t *)core->timer;
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
timerAlarmWrite(timer, period, true);
|
||||
timerAlarmEnable(timer);
|
||||
timerStart(timer);
|
||||
#else
|
||||
timerWrite(timer, 0);
|
||||
timerAlarm(timer, period ? period : 1, true, 0);
|
||||
timerStart(timer);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Disable timer and return current count value.
|
||||
|
|
@ -87,11 +91,19 @@ IRAM_ATTR uint32_t _PM_timerStop(Protomatter_core *core) {
|
|||
// that's common to all ESP32 variants; code in variant-specific files might
|
||||
// set up its own special peripherals, then call this.
|
||||
void _PM_esp32commonTimerInit(Protomatter_core *core) {
|
||||
hw_timer_t *timer = (hw_timer_t *)core->timer; // pointer-to-pointer
|
||||
if (timer == _PM_TIMER_DEFAULT) {
|
||||
hw_timer_t *timer_in = (hw_timer_t *)core->timer;
|
||||
if (!timer_in || timer_in == _PM_TIMER_DEFAULT) {
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
core->timer = timerBegin(_PM_timerNum, 2, true); // 1:2 prescale, count up
|
||||
#else
|
||||
core->timer = timerBegin(_PM_timerFreq);
|
||||
#endif
|
||||
}
|
||||
timerAttachInterrupt(timer, &_PM_esp32timerCallback, true);
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
timerAttachInterrupt(core->timer, &_PM_esp32timerCallback, true);
|
||||
#else
|
||||
timerAttachInterrupt(core->timer, _PM_esp32timerCallback);
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif defined(CIRCUITPY) // COMPILING FOR CIRCUITPYTHON --------------------
|
||||
|
|
@ -106,7 +118,12 @@ void _PM_esp32commonTimerInit(Protomatter_core *core) {
|
|||
#include "driver/gpio.h"
|
||||
#include "esp_idf_version.h"
|
||||
#include "hal/timer_ll.h"
|
||||
#include "peripherals/timer.h"
|
||||
#if ESP_IDF_VERSION_MAJOR == 5
|
||||
#include "driver/gptimer.h"
|
||||
#include "esp_memory_utils.h"
|
||||
#else
|
||||
#include "driver/timer.h"
|
||||
#endif
|
||||
|
||||
#define _PM_TIMER_DEFAULT NULL
|
||||
#define _PM_pinOutput(pin) gpio_set_direction((pin), GPIO_MODE_OUTPUT)
|
||||
|
|
@ -118,8 +135,24 @@ void _PM_esp32commonTimerInit(Protomatter_core *core) {
|
|||
// (RAM-resident functions). This isn't really the ISR itself, but a
|
||||
// callback invoked by the real ISR (in arduino-esp32's esp32-hal-timer.c)
|
||||
// which takes care of interrupt status bits & such.
|
||||
#if ESP_IDF_VERSION_MAJOR == 5
|
||||
// This is "private" for now. We link to it anyway because there isn't a more
|
||||
// public method yet.
|
||||
extern bool spi_flash_cache_enabled(void);
|
||||
static IRAM_ATTR bool
|
||||
_PM_esp32timerCallback(gptimer_handle_t timer,
|
||||
const gptimer_alarm_event_data_t *event, void *unused) {
|
||||
#else
|
||||
static IRAM_ATTR bool _PM_esp32timerCallback(void *unused) {
|
||||
#endif
|
||||
#if ESP_IDF_VERSION_MAJOR == 5
|
||||
// Some functions and data used by _PM_row_handler may exist in external flash
|
||||
// or PSRAM so we can't run them when their access is disabled (through the
|
||||
// flash cache.)
|
||||
if (_PM_protoPtr && spi_flash_cache_enabled()) {
|
||||
#else
|
||||
if (_PM_protoPtr) {
|
||||
#endif
|
||||
_PM_row_handler(_PM_protoPtr); // In core.c
|
||||
}
|
||||
return false;
|
||||
|
|
@ -127,14 +160,16 @@ static IRAM_ATTR bool _PM_esp32timerCallback(void *unused) {
|
|||
|
||||
// Set timer period, initialize count value to zero, enable timer.
|
||||
#if (ESP_IDF_VERSION_MAJOR == 5)
|
||||
static IRAM_ATTR void _PM_timerStart(Protomatter_core *core, uint32_t period) {
|
||||
timer_index_t *timer = (timer_index_t *)core->timer;
|
||||
timer_ll_enable_counter(timer->hw, timer->idx, false);
|
||||
timer_ll_set_reload_value(timer->hw, timer->idx, 0);
|
||||
timer_ll_trigger_soft_reload(timer->hw, timer->idx);
|
||||
timer_ll_set_alarm_value(timer->hw, timer->idx, period);
|
||||
timer_ll_enable_alarm(timer->hw, timer->idx, true);
|
||||
timer_ll_enable_counter(timer->hw, timer->idx, true);
|
||||
IRAM_ATTR void _PM_timerStart(Protomatter_core *core, uint32_t period) {
|
||||
gptimer_handle_t timer = (gptimer_handle_t)core->timer;
|
||||
|
||||
gptimer_alarm_config_t alarm_config = {
|
||||
.reload_count = 0, // counter will reload with 0 on alarm event
|
||||
.alarm_count = period, // period in ms
|
||||
.flags.auto_reload_on_alarm = true, // enable auto-reload
|
||||
};
|
||||
gptimer_set_alarm_action(timer, &alarm_config);
|
||||
gptimer_start(timer);
|
||||
}
|
||||
#else
|
||||
IRAM_ATTR void _PM_timerStart(Protomatter_core *core, uint32_t period) {
|
||||
|
|
@ -150,10 +185,11 @@ IRAM_ATTR void _PM_timerStart(Protomatter_core *core, uint32_t period) {
|
|||
// Disable timer and return current count value.
|
||||
// Timer must be previously initialized.
|
||||
IRAM_ATTR uint32_t _PM_timerStop(Protomatter_core *core) {
|
||||
timer_index_t *timer = (timer_index_t *)core->timer;
|
||||
#if (ESP_IDF_VERSION_MAJOR == 5)
|
||||
timer_ll_enable_counter(timer->hw, timer->idx, false);
|
||||
gptimer_handle_t timer = (gptimer_handle_t)core->timer;
|
||||
gptimer_stop(timer);
|
||||
#else
|
||||
timer_index_t *timer = (timer_index_t *)core->timer;
|
||||
timer_ll_set_counter_enable(timer->hw, timer->idx, false);
|
||||
#endif
|
||||
return _PM_timerGetCount(core);
|
||||
|
|
@ -161,10 +197,17 @@ IRAM_ATTR uint32_t _PM_timerStop(Protomatter_core *core) {
|
|||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
IRAM_ATTR uint32_t _PM_timerGetCount(Protomatter_core *core) {
|
||||
#if (ESP_IDF_VERSION_MAJOR == 5)
|
||||
gptimer_handle_t timer = (gptimer_handle_t)core->timer;
|
||||
uint64_t raw_count;
|
||||
gptimer_get_raw_count(timer, &raw_count);
|
||||
return (uint32_t)raw_count;
|
||||
#else
|
||||
timer_index_t *timer = (timer_index_t *)core->timer;
|
||||
uint64_t result;
|
||||
timer_ll_get_counter_value(timer->hw, timer->idx, &result);
|
||||
return (uint32_t)result;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -172,6 +215,16 @@ IRAM_ATTR uint32_t _PM_timerGetCount(Protomatter_core *core) {
|
|||
// that's common to all ESP32 variants; code in variant-specific files might
|
||||
// set up its own special peripherals, then call this.
|
||||
static void _PM_esp32commonTimerInit(Protomatter_core *core) {
|
||||
|
||||
#if (ESP_IDF_VERSION_MAJOR == 5)
|
||||
gptimer_handle_t timer = (gptimer_handle_t)core->timer;
|
||||
gptimer_event_callbacks_t cbs = {
|
||||
.on_alarm = _PM_esp32timerCallback, // register user callback
|
||||
};
|
||||
gptimer_register_event_callbacks(timer, &cbs, NULL);
|
||||
|
||||
gptimer_enable(timer);
|
||||
#else
|
||||
timer_index_t *timer = (timer_index_t *)core->timer;
|
||||
const timer_config_t config = {
|
||||
.alarm_en = false,
|
||||
|
|
@ -186,6 +239,7 @@ static void _PM_esp32commonTimerInit(Protomatter_core *core) {
|
|||
timer_isr_callback_add(timer->group, timer->idx, _PM_esp32timerCallback, NULL,
|
||||
0);
|
||||
timer_enable_intr(timer->group, timer->idx);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // END CIRCUITPYTHON ------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ IRAM_ATTR inline uint32_t _PM_timerGetCount(Protomatter_core *core) {
|
|||
#else
|
||||
#include <driver/periph_ctrl.h>
|
||||
#endif
|
||||
#include <driver/gpio.h>
|
||||
#include <esp_private/gdma.h>
|
||||
#include <esp_rom_gpio.h>
|
||||
#include <hal/dma_types.h>
|
||||
|
|
@ -296,8 +297,14 @@ IRAM_ATTR static void blast_byte(Protomatter_core *core, uint8_t *data) {
|
|||
// Timer was cleared to 0 before calling blast_byte(), so this
|
||||
// is the state of the timer immediately after DMA started:
|
||||
uint64_t value;
|
||||
|
||||
#if (ESP_IDF_VERSION_MAJOR == 5)
|
||||
gptimer_handle_t timer = (gptimer_handle_t)core->timer;
|
||||
gptimer_get_raw_count(timer, &value);
|
||||
#else
|
||||
timer_index_t *timer = (timer_index_t *)core->timer;
|
||||
timer_get_counter_value(timer->group, timer->idx, &value);
|
||||
#endif
|
||||
dmaSetupTime = (uint32_t)value;
|
||||
// See notes near top of this file for what's done with this info.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -240,10 +240,10 @@ uint32_t _PM_timerStop(Protomatter_core *core) {
|
|||
#define _PM_clockHoldLow asm("nop; nop; nop;");
|
||||
#define _PM_clockHoldHigh asm("nop; nop; nop;");
|
||||
#elif (F_CPU >= 175000000)
|
||||
#define _PM_clockHoldLow asm("nop; nop;");
|
||||
#define _PM_clockHoldLow asm("nop; nop; nop;");
|
||||
#define _PM_clockHoldHigh asm("nop;");
|
||||
#elif (F_CPU >= 125000000)
|
||||
#define _PM_clockHoldLow asm("nop;");
|
||||
#define _PM_clockHoldLow asm("nop; nop; nop;");
|
||||
#define _PM_clockHoldHigh asm("nop;");
|
||||
#elif (F_CPU >= 100000000)
|
||||
#define _PM_clockHoldLow asm("nop;");
|
||||
|
|
|
|||
|
|
@ -47,6 +47,21 @@
|
|||
|
||||
#define F_CPU (120000000)
|
||||
|
||||
// Enable high output driver strength on one pin. Arduino does this by
|
||||
// default on pinMode(OUTPUT), but CircuitPython requires the motions...
|
||||
static void _hi_drive(uint8_t pin) {
|
||||
// For Arduino testing only:
|
||||
// pin = g_APinDescription[pin].ulPort * 32 + g_APinDescription[pin].ulPin;
|
||||
|
||||
// Input, pull-up and peripheral MUX are disabled as we're only using
|
||||
// vanilla PORT writes on Protomatter GPIO.
|
||||
PORT->Group[pin / 32].WRCONFIG.reg =
|
||||
(pin & 16)
|
||||
? PORT_WRCONFIG_WRPINCFG | PORT_WRCONFIG_DRVSTR |
|
||||
PORT_WRCONFIG_HWSEL | (1 << (pin & 15))
|
||||
: PORT_WRCONFIG_WRPINCFG | PORT_WRCONFIG_DRVSTR | (1 << (pin & 15));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// Other port register lookups go here
|
||||
|
|
@ -157,6 +172,20 @@ void _PM_timerInit(Protomatter_core *core) {
|
|||
NVIC_EnableIRQ(timer[timerNum].IRQn);
|
||||
|
||||
// Timer is configured but NOT enabled by default
|
||||
|
||||
#if defined(CIRCUITPY) // See notes earlier; Arduino doesn't need this.
|
||||
// Enable high drive strength on all Protomatter pins. TBH this is kind
|
||||
// of a jerky place to do this (it's not actually related to the timer
|
||||
// peripheral) but Protomatter doesn't really have a spot for it.
|
||||
uint8_t i;
|
||||
for (i = 0; i < core->parallel * 6; i++)
|
||||
_hi_drive(core->rgbPins[i]);
|
||||
for (i = 0; i < core->numAddressLines; i++)
|
||||
_hi_drive(core->addr[i].pin);
|
||||
_hi_drive(core->clockPin);
|
||||
_hi_drive(core->latch.pin);
|
||||
_hi_drive(core->oe.pin);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Set timer period, initialize count value to zero, enable timer.
|
||||
|
|
@ -294,20 +323,27 @@ static void blast_byte(Protomatter_core *core, uint8_t *data) {
|
|||
// clock are all within the same byte of a PORT register, else we'd be
|
||||
// in the word- or long-blasting functions now. So we just need an
|
||||
// 8-bit pointer to the PORT:
|
||||
uint8_t *toggle = (uint8_t *)core->toggleReg + core->portOffset;
|
||||
volatile uint8_t *toggle =
|
||||
(volatile uint8_t *)core->toggleReg + core->portOffset;
|
||||
uint8_t bucket, clock = core->clockMask;
|
||||
// Pointer list must be distinct vars, not an array, else slow.
|
||||
uint8_t *ptr0 = (_PM_duty == _PM_maxDuty) ? toggle : &bucket;
|
||||
uint8_t *ptr1 = (_PM_duty == (_PM_maxDuty - 1)) ? toggle : &bucket;
|
||||
uint8_t *ptr2 = (_PM_duty == (_PM_maxDuty - 2)) ? toggle : &bucket;
|
||||
volatile uint8_t *ptr0 =
|
||||
(_PM_duty == _PM_maxDuty) ? toggle : (volatile uint8_t *)&bucket;
|
||||
volatile uint8_t *ptr1 =
|
||||
(_PM_duty == (_PM_maxDuty - 1)) ? toggle : (volatile uint8_t *)&bucket;
|
||||
volatile uint8_t *ptr2 =
|
||||
(_PM_duty == (_PM_maxDuty - 2)) ? toggle : (volatile uint8_t *)&bucket;
|
||||
#if _PM_maxDuty >= 3
|
||||
uint8_t *ptr3 = (_PM_duty == (_PM_maxDuty - 3)) ? toggle : &bucket;
|
||||
volatile uint8_t *ptr3 =
|
||||
(_PM_duty == (_PM_maxDuty - 3)) ? toggle : (volatile uint8_t *)&bucket;
|
||||
#endif
|
||||
#if _PM_maxDuty >= 4
|
||||
uint8_t *ptr4 = (_PM_duty == (_PM_maxDuty - 4)) ? toggle : &bucket;
|
||||
volatile uint8_t *ptr4 =
|
||||
(_PM_duty == (_PM_maxDuty - 4)) ? toggle : (volatile uint8_t *)&bucket;
|
||||
#endif
|
||||
#if _PM_maxDuty >= 5
|
||||
uint8_t *ptr5 = (_PM_duty == (_PM_maxDuty - 5)) ? toggle : &bucket;
|
||||
volatile uint8_t *ptr5 =
|
||||
(_PM_duty == (_PM_maxDuty - 5)) ? toggle : (volatile uint8_t *)&bucket;
|
||||
#endif
|
||||
uint16_t chunks = core->chainBits / 8;
|
||||
|
||||
|
|
@ -329,19 +365,25 @@ static void blast_byte(Protomatter_core *core, uint8_t *data) {
|
|||
|
||||
// This is a copypasta of blast_byte() with types changed to uint16_t.
|
||||
static void blast_word(Protomatter_core *core, uint16_t *data) {
|
||||
uint16_t *toggle = (uint16_t *)core->toggleReg + core->portOffset;
|
||||
volatile uint16_t *toggle = (uint16_t *)core->toggleReg + core->portOffset;
|
||||
uint16_t bucket, clock = core->clockMask;
|
||||
uint16_t *ptr0 = (_PM_duty == _PM_maxDuty) ? toggle : &bucket;
|
||||
uint16_t *ptr1 = (_PM_duty == (_PM_maxDuty - 1)) ? toggle : &bucket;
|
||||
uint16_t *ptr2 = (_PM_duty == (_PM_maxDuty - 2)) ? toggle : &bucket;
|
||||
volatile uint16_t *ptr0 =
|
||||
(_PM_duty == _PM_maxDuty) ? toggle : (volatile uint16_t *)&bucket;
|
||||
volatile uint16_t *ptr1 =
|
||||
(_PM_duty == (_PM_maxDuty - 1)) ? toggle : (volatile uint16_t *)&bucket;
|
||||
volatile uint16_t *ptr2 =
|
||||
(_PM_duty == (_PM_maxDuty - 2)) ? toggle : (volatile uint16_t *)&bucket;
|
||||
#if _PM_maxDuty >= 3
|
||||
uint16_t *ptr3 = (_PM_duty == (_PM_maxDuty - 3)) ? toggle : &bucket;
|
||||
volatile uint16_t *ptr3 =
|
||||
(_PM_duty == (_PM_maxDuty - 3)) ? toggle : (volatile uint16_t *)&bucket;
|
||||
#endif
|
||||
#if _PM_maxDuty >= 4
|
||||
uint16_t *ptr4 = (_PM_duty == (_PM_maxDuty - 4)) ? toggle : &bucket;
|
||||
volatile uint16_t *ptr4 =
|
||||
(_PM_duty == (_PM_maxDuty - 4)) ? toggle : (volatile uint16_t *)&bucket;
|
||||
#endif
|
||||
#if _PM_maxDuty >= 5
|
||||
uint16_t *ptr5 = (_PM_duty == (_PM_maxDuty - 5)) ? toggle : &bucket;
|
||||
volatile uint16_t *ptr5 =
|
||||
(_PM_duty == (_PM_maxDuty - 5)) ? toggle : (volatile uint16_t *)&bucket;
|
||||
#endif
|
||||
uint16_t chunks = core->chainBits / 8;
|
||||
do {
|
||||
|
|
@ -353,19 +395,25 @@ static void blast_word(Protomatter_core *core, uint16_t *data) {
|
|||
|
||||
// This is a copypasta of blast_byte() with types changed to uint32_t.
|
||||
static void blast_long(Protomatter_core *core, uint32_t *data) {
|
||||
uint32_t *toggle = (uint32_t *)core->toggleReg;
|
||||
volatile uint32_t *toggle = (uint32_t *)core->toggleReg;
|
||||
uint32_t bucket, clock = core->clockMask;
|
||||
uint32_t *ptr0 = (_PM_duty == _PM_maxDuty) ? toggle : &bucket;
|
||||
uint32_t *ptr1 = (_PM_duty == (_PM_maxDuty - 1)) ? toggle : &bucket;
|
||||
uint32_t *ptr2 = (_PM_duty == (_PM_maxDuty - 2)) ? toggle : &bucket;
|
||||
volatile uint32_t *ptr0 =
|
||||
(_PM_duty == _PM_maxDuty) ? toggle : (volatile uint32_t *)&bucket;
|
||||
volatile uint32_t *ptr1 =
|
||||
(_PM_duty == (_PM_maxDuty - 1)) ? toggle : (volatile uint32_t *)&bucket;
|
||||
volatile uint32_t *ptr2 =
|
||||
(_PM_duty == (_PM_maxDuty - 2)) ? toggle : (volatile uint32_t *)&bucket;
|
||||
#if _PM_maxDuty >= 3
|
||||
uint32_t *ptr3 = (_PM_duty == (_PM_maxDuty - 3)) ? toggle : &bucket;
|
||||
volatile uint32_t *ptr3 =
|
||||
(_PM_duty == (_PM_maxDuty - 3)) ? toggle : (volatile uint32_t *)&bucket;
|
||||
#endif
|
||||
#if _PM_maxDuty >= 4
|
||||
uint32_t *ptr4 = (_PM_duty == (_PM_maxDuty - 4)) ? toggle : &bucket;
|
||||
volatile uint32_t *ptr4 =
|
||||
(_PM_duty == (_PM_maxDuty - 4)) ? toggle : (volatile uint32_t *)&bucket;
|
||||
#endif
|
||||
#if _PM_maxDuty >= 5
|
||||
uint32_t *ptr5 = (_PM_duty == (_PM_maxDuty - 5)) ? toggle : &bucket;
|
||||
volatile uint32_t *ptr5 =
|
||||
(_PM_duty == (_PM_maxDuty - 5)) ? toggle : (volatile uint32_t *)&bucket;
|
||||
#endif
|
||||
uint16_t chunks = core->chainBits / 8;
|
||||
do {
|
||||
|
|
|
|||
Loading…
Reference in a new issue