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+
100108uint64_t next_start_tick_ms = 0 ;
101109uint32_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 {
0 commit comments