@@ -224,6 +224,30 @@ static void _send_pixels(busdisplay_busdisplay_obj_t *self, uint8_t *pixels, uin
224224 self -> bus .send (self -> bus .bus , DISPLAY_DATA , CHIP_SELECT_UNTOUCHED , pixels , length );
225225}
226226
227+ // Whether the bus sends in the background. Always false without async SPI, so that code is
228+ // left out. Not a local variable: GCC would then compile the refresh loop twice.
229+ #define SEND_ASYNC (self ) (CIRCUITPY_BUSIO_SPI_ASYNC && (self)->bus.send_async != NULL)
230+
231+ // The data half of _send_pixels, handed to the bus without waiting for it to be sent.
232+ static void _send_pixels_async (busdisplay_busdisplay_obj_t * self , uint8_t * pixels , uint32_t length ) {
233+ if (!self -> bus .data_as_commands ) {
234+ self -> bus .send (self -> bus .bus , DISPLAY_COMMAND , CHIP_SELECT_TOGGLE_EVERY_BYTE , & self -> write_ram_command , 1 );
235+ }
236+ self -> bus .send_async (self -> bus .bus , DISPLAY_DATA , CHIP_SELECT_UNTOUCHED , pixels , length );
237+ }
238+
239+ // Call only with the bus transaction closed: a background task may use the same bus.
240+ static void _run_background_tasks (void ) {
241+ // Run background tasks so they can run during an explicit refresh.
242+ // Auto-refresh won't run background tasks here because it is a background task itself.
243+ RUN_BACKGROUND_TASKS ;
244+
245+ // Run USB background tasks so they can run during an implicit refresh.
246+ #if CIRCUITPY_TINYUSB
247+ usb_background ();
248+ #endif
249+ }
250+
227251static bool _refresh_area (busdisplay_busdisplay_obj_t * self , const displayio_area_t * area ) {
228252 uint16_t buffer_size = CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE / sizeof (uint32_t ); // In uint32_ts
229253
@@ -272,8 +296,11 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are
272296 // Allocated and shared as a uint32_t array so the compiler knows the
273297 // alignment everywhere.
274298 uint32_t mask_length = (pixels_per_buffer / 32 ) + 1 ;
275- uint32_t buffer [buffer_size ];
299+ // With an asynchronous bus, one buffer is composited while the other is being sent.
300+ uint32_t buffers [SEND_ASYNC (self ) ? 2 : 1 ][buffer_size ];
276301 uint32_t mask [mask_length ];
302+ uint8_t fill_index = 0 ;
303+ bool sending = false;
277304
278305 displayio_area_t subrectangle = clipped ;
279306 subrectangle .next = NULL ;
@@ -294,33 +321,45 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are
294321 subrectangle_size_bytes = displayio_area_size (& subrectangle ) / (8 / self -> core .colorspace .depth );
295322 }
296323
324+ uint32_t * buffer = buffers [fill_index ];
297325 memset (mask , 0 , mask_length * sizeof (mask [0 ]));
298326 memset (buffer , 0 , buffer_size * sizeof (buffer [0 ]));
299327
300328 displayio_display_core_fill_area (& self -> core , & subrectangle , mask , buffer );
301329
330+ // The previous strip must be sent before the region commands for this one.
331+ if (sending ) {
332+ displayio_display_bus_flush (& self -> bus );
333+ displayio_display_bus_end_transaction (& self -> bus );
334+ sending = false;
335+ _run_background_tasks ();
336+ }
337+
302338 displayio_display_bus_set_region_to_update (& self -> bus , & self -> core , & subrectangle );
303339
304340 // Can't acquire display bus; skip the rest of the data.
305341 if (!displayio_display_bus_begin_transaction (& self -> bus )) {
306342 return false;
307343 }
308- _send_pixels (self , (uint8_t * )buffer , subrectangle_size_bytes );
309- displayio_display_bus_end_transaction (& self -> bus );
344+ if (SEND_ASYNC (self )) {
345+ _send_pixels_async (self , (uint8_t * )buffer , subrectangle_size_bytes );
346+ sending = true;
347+ fill_index ^= 1 ;
348+ } else {
349+ _send_pixels (self , (uint8_t * )buffer , subrectangle_size_bytes );
350+ displayio_display_bus_end_transaction (& self -> bus );
351+ }
310352 subrectangle .y1 = subrectangle .y2 ;
311-
312- // Run background tasks so they can run during an explicit refresh.
313- // Auto-refresh won't run background tasks here because it is a background task itself.
314- RUN_BACKGROUND_TASKS ;
315-
316- // Run USB background tasks so they can run during an implicit refresh.
317- #if CIRCUITPY_TINYUSB
318- usb_background ();
319- #endif
353+ if (!sending ) {
354+ _run_background_tasks ();
355+ }
320356 }
321357
322358 // Drain any remaining asynchronous transfers.
323359 displayio_display_bus_flush (& self -> bus );
360+ if (sending ) {
361+ displayio_display_bus_end_transaction (& self -> bus );
362+ }
324363
325364 return true;
326365}
0 commit comments