Skip to content

Commit bd9572c

Browse files
authored
Merge pull request #2648 from dhalbert/malloc-nrf-neopixel-write
cached heap buffer for neopixel_write
2 parents e9ade63 + f63b2c0 commit bd9572c

File tree

4 files changed

+71
-16
lines changed

4 files changed

+71
-16
lines changed

ports/nrf/common-hal/neopixel_write/__init__.c

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
*/
2626

2727
#include "py/mphal.h"
28+
#include "py/mpstate.h"
2829
#include "shared-bindings/neopixel_write/__init__.h"
2930
#include "nrf_pwm.h"
3031

@@ -97,6 +98,13 @@ static NRF_PWM_Type* find_free_pwm (void) {
9798
return NULL;
9899
}
99100

101+
static size_t pixels_pattern_heap_size = 0;
102+
// Called during reset_port() to free the pattern buffer
103+
void neopixel_write_reset(void) {
104+
MP_STATE_VM(pixels_pattern_heap) = NULL;
105+
pixels_pattern_heap_size = 0;
106+
}
107+
100108
uint64_t next_start_tick_ms = 0;
101109
uint32_t next_start_tick_us = 1000;
102110

@@ -119,10 +127,8 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout
119127
// We need space for at least 10 pixels for Circuit Playground, but let's choose 24
120128
// to handle larger NeoPixel rings without malloc'ing.
121129
#define STACK_PIXELS 24
122-
123130
uint32_t pattern_size = PATTERN_SIZE(numBytes);
124131
uint16_t* pixels_pattern = NULL;
125-
bool pattern_on_heap = false;
126132

127133
// Use the stack to store STACK_PIXEL's worth of PWM data. uint32_t to ensure alignment.
128134
// It is 3*STACK_PIXELS to handle RGB.
@@ -138,24 +144,42 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout
138144
} else {
139145
uint8_t sd_en = 0;
140146
(void) sd_softdevice_is_enabled(&sd_en);
141-
if (sd_en) {
142-
// If the soft device is enabled then we must use PWM to
143-
// transmit. This takes a bunch of memory to do so raise an
144-
// exception if we can't.
145-
pixels_pattern = (uint16_t *) m_malloc(pattern_size, false);
146-
} else {
147-
pixels_pattern = (uint16_t *) m_malloc_maybe(pattern_size, false);
148-
}
149147

150-
pattern_on_heap = true;
148+
if (pixels_pattern_heap_size < pattern_size) {
149+
// Current heap buffer is too small.
150+
if (MP_STATE_VM(pixels_pattern_heap)) {
151+
// Old pixels_pattern_heap will be gc'd; don't free it.
152+
pixels_pattern = NULL;
153+
pixels_pattern_heap_size = 0;
154+
}
155+
156+
// realloc routines fall back to a plain malloc if the incoming ptr is NULL.
157+
if (sd_en) {
158+
// If the soft device is enabled then we must use PWM to
159+
// transmit. This takes a bunch of memory to do so raise an
160+
// exception if we can't.
161+
MP_STATE_VM(pixels_pattern_heap) =
162+
(uint16_t *) m_realloc(MP_STATE_VM(pixels_pattern_heap), pattern_size);
163+
} else {
164+
// Might return NULL.
165+
MP_STATE_VM(pixels_pattern_heap) =
166+
// true means move if necessary.
167+
(uint16_t *) m_realloc_maybe(MP_STATE_VM(pixels_pattern_heap), pattern_size, true);
168+
}
169+
if (MP_STATE_VM(pixels_pattern_heap)) {
170+
pixels_pattern_heap_size = pattern_size;
171+
}
172+
}
173+
// Might be NULL, which means we failed to allocate.
174+
pixels_pattern = MP_STATE_VM(pixels_pattern_heap);
151175
}
152176
}
153177

154178
// Wait to make sure we don't append onto the last transmission.
155179
wait_until(next_start_tick_ms, next_start_tick_us);
156180

157181
// Use the identified device to choose the implementation
158-
// If a PWM device is available use DMA
182+
// If a PWM device is available and we have a buffer, use DMA.
159183
if ( (pixels_pattern != NULL) && (pwm != NULL) ) {
160184
uint16_t pos = 0; // bit position
161185

@@ -229,10 +253,6 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout
229253
nrf_pwm_disable(pwm);
230254
nrf_pwm_pins_set(pwm, (uint32_t[]) {0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL} );
231255

232-
if (pattern_on_heap) {
233-
m_free(pixels_pattern);
234-
}
235-
236256
} // End of DMA implementation
237257
// ---------------------------------------------------------------------
238258
else {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2019 Lucian Copeland for Adafruit Industries
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#ifndef MICROPY_INCLUDED_STM32F4_COMMON_HAL_NEOPIXEL_WRITE_INIT_H
28+
#define MICROPY_INCLUDED_STM32F4_COMMON_HAL_NEOPIXEL_WRITE_INIT_H
29+
30+
void neopixel_write_reset(void);
31+
32+
#endif // MICROPY_INCLUDED_STM32F4_COMMON_HAL_NEOPIXEL_WRITE_INIT_H

ports/nrf/mpconfigport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@
164164

165165
#define MICROPY_PORT_ROOT_POINTERS \
166166
CIRCUITPY_COMMON_ROOT_POINTERS \
167+
uint16_t* pixels_pattern_heap; \
167168
ble_drv_evt_handler_entry_t* ble_drv_evt_handler_entries; \
168169

169170

ports/nrf/supervisor/port.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include "common-hal/pulseio/PulseOut.h"
4848
#include "common-hal/pulseio/PulseIn.h"
4949
#include "common-hal/rtc/RTC.h"
50+
#include "common-hal/neopixel_write/__init__.h"
5051
#include "tick.h"
5152

5253
#include "shared-bindings/rtc/__init__.h"
@@ -103,6 +104,7 @@ void reset_port(void) {
103104
i2c_reset();
104105
spi_reset();
105106
uart_reset();
107+
neopixel_write_reset();
106108

107109
#if CIRCUITPY_AUDIOBUSIO
108110
i2s_reset();

0 commit comments

Comments
 (0)