25
25
*/
26
26
27
27
#include "py/mphal.h"
28
+ #include "py/mpstate.h"
28
29
#include "shared-bindings/neopixel_write/__init__.h"
29
30
#include "nrf_pwm.h"
30
31
@@ -97,6 +98,13 @@ static NRF_PWM_Type* find_free_pwm (void) {
97
98
return NULL ;
98
99
}
99
100
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
+
100
108
uint64_t next_start_tick_ms = 0 ;
101
109
uint32_t next_start_tick_us = 1000 ;
102
110
@@ -119,10 +127,8 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout
119
127
// We need space for at least 10 pixels for Circuit Playground, but let's choose 24
120
128
// to handle larger NeoPixel rings without malloc'ing.
121
129
#define STACK_PIXELS 24
122
-
123
130
uint32_t pattern_size = PATTERN_SIZE (numBytes );
124
131
uint16_t * pixels_pattern = NULL ;
125
- bool pattern_on_heap = false;
126
132
127
133
// Use the stack to store STACK_PIXEL's worth of PWM data. uint32_t to ensure alignment.
128
134
// It is 3*STACK_PIXELS to handle RGB.
@@ -138,24 +144,42 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout
138
144
} else {
139
145
uint8_t sd_en = 0 ;
140
146
(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
- }
149
147
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 );
151
175
}
152
176
}
153
177
154
178
// Wait to make sure we don't append onto the last transmission.
155
179
wait_until (next_start_tick_ms , next_start_tick_us );
156
180
157
181
// 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.
159
183
if ( (pixels_pattern != NULL ) && (pwm != NULL ) ) {
160
184
uint16_t pos = 0 ; // bit position
161
185
@@ -229,10 +253,6 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout
229
253
nrf_pwm_disable (pwm );
230
254
nrf_pwm_pins_set (pwm , (uint32_t []) {0xFFFFFFFFUL , 0xFFFFFFFFUL , 0xFFFFFFFFUL , 0xFFFFFFFFUL } );
231
255
232
- if (pattern_on_heap ) {
233
- m_free (pixels_pattern );
234
- }
235
-
236
256
} // End of DMA implementation
237
257
// ---------------------------------------------------------------------
238
258
else {
0 commit comments