Merge pull request #2648 from dhalbert/malloc-nrf-neopixel-write

cached heap buffer for neopixel_write
This commit is contained in:
Scott Shawcroft 2020-02-21 17:26:09 -08:00 committed by GitHub
commit bd9572c8a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 16 deletions

View File

@ -25,6 +25,7 @@
*/
#include "py/mphal.h"
#include "py/mpstate.h"
#include "shared-bindings/neopixel_write/__init__.h"
#include "nrf_pwm.h"
@ -97,6 +98,13 @@ static NRF_PWM_Type* find_free_pwm (void) {
return NULL;
}
static size_t pixels_pattern_heap_size = 0;
// Called during reset_port() to free the pattern buffer
void neopixel_write_reset(void) {
MP_STATE_VM(pixels_pattern_heap) = NULL;
pixels_pattern_heap_size = 0;
}
uint64_t next_start_tick_ms = 0;
uint32_t next_start_tick_us = 1000;
@ -119,10 +127,8 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout
// We need space for at least 10 pixels for Circuit Playground, but let's choose 24
// to handle larger NeoPixel rings without malloc'ing.
#define STACK_PIXELS 24
uint32_t pattern_size = PATTERN_SIZE(numBytes);
uint16_t* pixels_pattern = NULL;
bool pattern_on_heap = false;
// Use the stack to store STACK_PIXEL's worth of PWM data. uint32_t to ensure alignment.
// It is 3*STACK_PIXELS to handle RGB.
@ -138,16 +144,34 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout
} else {
uint8_t sd_en = 0;
(void) sd_softdevice_is_enabled(&sd_en);
if (sd_en) {
// If the soft device is enabled then we must use PWM to
// transmit. This takes a bunch of memory to do so raise an
// exception if we can't.
pixels_pattern = (uint16_t *) m_malloc(pattern_size, false);
} else {
pixels_pattern = (uint16_t *) m_malloc_maybe(pattern_size, false);
}
pattern_on_heap = true;
if (pixels_pattern_heap_size < pattern_size) {
// Current heap buffer is too small.
if (MP_STATE_VM(pixels_pattern_heap)) {
// Old pixels_pattern_heap will be gc'd; don't free it.
pixels_pattern = NULL;
pixels_pattern_heap_size = 0;
}
// realloc routines fall back to a plain malloc if the incoming ptr is NULL.
if (sd_en) {
// If the soft device is enabled then we must use PWM to
// transmit. This takes a bunch of memory to do so raise an
// exception if we can't.
MP_STATE_VM(pixels_pattern_heap) =
(uint16_t *) m_realloc(MP_STATE_VM(pixels_pattern_heap), pattern_size);
} else {
// Might return NULL.
MP_STATE_VM(pixels_pattern_heap) =
// true means move if necessary.
(uint16_t *) m_realloc_maybe(MP_STATE_VM(pixels_pattern_heap), pattern_size, true);
}
if (MP_STATE_VM(pixels_pattern_heap)) {
pixels_pattern_heap_size = pattern_size;
}
}
// Might be NULL, which means we failed to allocate.
pixels_pattern = MP_STATE_VM(pixels_pattern_heap);
}
}
@ -155,7 +179,7 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout
wait_until(next_start_tick_ms, next_start_tick_us);
// Use the identified device to choose the implementation
// If a PWM device is available use DMA
// If a PWM device is available and we have a buffer, use DMA.
if ( (pixels_pattern != NULL) && (pwm != NULL) ) {
uint16_t pos = 0; // bit position
@ -229,10 +253,6 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout
nrf_pwm_disable(pwm);
nrf_pwm_pins_set(pwm, (uint32_t[]) {0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL} );
if (pattern_on_heap) {
m_free(pixels_pattern);
}
} // End of DMA implementation
// ---------------------------------------------------------------------
else {

View File

@ -0,0 +1,32 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Lucian Copeland 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_STM32F4_COMMON_HAL_NEOPIXEL_WRITE_INIT_H
#define MICROPY_INCLUDED_STM32F4_COMMON_HAL_NEOPIXEL_WRITE_INIT_H
void neopixel_write_reset(void);
#endif // MICROPY_INCLUDED_STM32F4_COMMON_HAL_NEOPIXEL_WRITE_INIT_H

View File

@ -164,6 +164,7 @@
#define MICROPY_PORT_ROOT_POINTERS \
CIRCUITPY_COMMON_ROOT_POINTERS \
uint16_t* pixels_pattern_heap; \
ble_drv_evt_handler_entry_t* ble_drv_evt_handler_entries; \

View File

@ -47,6 +47,7 @@
#include "common-hal/pulseio/PulseOut.h"
#include "common-hal/pulseio/PulseIn.h"
#include "common-hal/rtc/RTC.h"
#include "common-hal/neopixel_write/__init__.h"
#include "tick.h"
#include "shared-bindings/rtc/__init__.h"
@ -103,6 +104,7 @@ void reset_port(void) {
i2c_reset();
spi_reset();
uart_reset();
neopixel_write_reset();
#if CIRCUITPY_AUDIOBUSIO
i2s_reset();