@@ -426,6 +426,141 @@ STATIC mp_obj_t rp2pio_statemachine_write(size_t n_args, const mp_obj_t *pos_arg
426426}
427427MP_DEFINE_CONST_FUN_OBJ_KW (rp2pio_statemachine_write_obj , 2 , rp2pio_statemachine_write );
428428
429+ //| def background_write(self, once: Optional[ReadableBuffer]=None, *, loop: Optional[ReadableBuffer]=None) -> None:
430+ //| """Write data to the TX fifo in the background, with optional looping.
431+ //|
432+ //| First, if any previous ``once`` or ``loop`` buffer has not been started, this function blocks until they have.
433+ //| This means that any ``once`` or ``loop`` buffer will be written at least once.
434+ //| Then the ``once`` and/or ``loop`` buffers are queued. and the function returns.
435+ //| The ``once`` buffer (if specified) will be written just once.
436+ //| Finally, the ``loop`` buffer (if specified) will continue being looped indefinitely.
437+ //|
438+ //| Writes to the FIFO will match the input buffer's element size. For example, bytearray elements
439+ //| will perform 8 bit writes to the PIO FIFO. The RP2040's memory bus will duplicate the value into
440+ //| the other byte positions. So, pulling more data in the PIO assembly will read the duplicated values.
441+ //|
442+ //| To perform 16 or 32 bits writes into the FIFO use an `array.array` with a type code of the desired
443+ //| size, or use `memoryview.cast` to change the interpretation of an
444+ //| existing buffer. To send just part of a larger buffer, slice a `memoryview`
445+ //| of it.
446+ //|
447+ //| If a buffer is modified while it is being written out, the updated
448+ //| values will be used. However, because of interactions between CPU
449+ //| writes, DMA and the PIO FIFO are complex, it is difficult to predict
450+ //| the result of modifying multiple values. Instead, alternate between
451+ //| a pair of buffers.
452+ //|
453+ //| Having both a ``once`` and a ``loop`` parameter is to support a special case in PWM generation
454+ //| where a change in duty cycle requires a special transitional buffer to be used exactly once. Most
455+ //| use cases will probably only use one of ``once`` or ``loop``.
456+ //|
457+ //| :param ~Optional[circuitpython_typing.ReadableBuffer] once: Data to be written once
458+ //| :param ~Optional[circuitpython_typing.ReadableBuffer] loop: Data to be written repeatedly
459+ //| """
460+ //| ...
461+ //|
462+
463+ STATIC void fill_buf_info (sm_buf_info * info , mp_obj_t obj , size_t * stride_in_bytes ) {
464+ if (obj != mp_const_none ) {
465+ info -> obj = obj ;
466+ mp_get_buffer_raise (obj , & info -> info , MP_BUFFER_READ );
467+ size_t stride = mp_binary_get_size ('@' , info -> info .typecode , NULL );
468+ if (stride > 4 ) {
469+ mp_raise_ValueError (translate ("Buffer elements must be 4 bytes long or less" ));
470+ }
471+ if (* stride_in_bytes && stride != * stride_in_bytes ) {
472+ mp_raise_ValueError (translate ("Mismatched data size" ));
473+ }
474+ * stride_in_bytes = stride ;
475+ } else {
476+ memset (info , 0 , sizeof (* info ));
477+ }
478+ }
479+
480+ STATIC mp_obj_t rp2pio_statemachine_background_write (size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
481+ enum { ARG_once , ARG_loop };
482+ static const mp_arg_t allowed_args [] = {
483+ { MP_QSTR_once , MP_ARG_OBJ , {.u_obj = mp_const_none } },
484+ { MP_QSTR_loop , MP_ARG_OBJ | MP_ARG_KW_ONLY , {.u_obj = mp_const_none } },
485+ };
486+ rp2pio_statemachine_obj_t * self = MP_OBJ_TO_PTR (pos_args [0 ]);
487+ check_for_deinit (self );
488+ mp_arg_val_t args [MP_ARRAY_SIZE (allowed_args )];
489+ mp_arg_parse_all (n_args - 1 , pos_args + 1 , kw_args , MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
490+
491+ sm_buf_info once_info ;
492+ sm_buf_info loop_info ;
493+ size_t stride_in_bytes = 0 ;
494+ fill_buf_info (& once_info , args [ARG_once ].u_obj , & stride_in_bytes );
495+ fill_buf_info (& loop_info , args [ARG_loop ].u_obj , & stride_in_bytes );
496+ if (!stride_in_bytes ) {
497+ return mp_const_none ;
498+ }
499+
500+ bool ok = common_hal_rp2pio_statemachine_background_write (self , & once_info , & loop_info , stride_in_bytes );
501+
502+ if (mp_hal_is_interrupted ()) {
503+ return mp_const_none ;
504+ }
505+ if (!ok ) {
506+ mp_raise_OSError (MP_EIO );
507+ }
508+ return mp_const_none ;
509+ }
510+ MP_DEFINE_CONST_FUN_OBJ_KW (rp2pio_statemachine_background_write_obj , 1 , rp2pio_statemachine_background_write );
511+
512+ //| def stop_background_write(self) -> None:
513+ //| """Immediately stop a background write, if one is in progress. Items already in the TX FIFO are not affected."""
514+ //|
515+ STATIC mp_obj_t rp2pio_statemachine_obj_stop_background_write (mp_obj_t self_in ) {
516+ rp2pio_statemachine_obj_t * self = MP_OBJ_TO_PTR (self_in );
517+ bool ok = common_hal_rp2pio_statemachine_stop_background_write (self );
518+ if (mp_hal_is_interrupted ()) {
519+ return mp_const_none ;
520+ }
521+ if (!ok ) {
522+ mp_raise_OSError (MP_EIO );
523+ }
524+ return mp_const_none ;
525+ }
526+ MP_DEFINE_CONST_FUN_OBJ_1 (rp2pio_statemachine_stop_background_write_obj , rp2pio_statemachine_obj_stop_background_write );
527+
528+ //| @property
529+ //| def writing(self) -> bool:
530+ //| """Returns True if a background write is in progress"""
531+ //|
532+ STATIC mp_obj_t rp2pio_statemachine_obj_get_writing (mp_obj_t self_in ) {
533+ rp2pio_statemachine_obj_t * self = MP_OBJ_TO_PTR (self_in );
534+ return mp_obj_new_bool (common_hal_rp2pio_statemachine_get_writing (self ));
535+ }
536+ MP_DEFINE_CONST_FUN_OBJ_1 (rp2pio_statemachine_get_writing_obj , rp2pio_statemachine_obj_get_writing );
537+
538+ const mp_obj_property_t rp2pio_statemachine_writing_obj = {
539+ .base .type = & mp_type_property ,
540+ .proxy = {(mp_obj_t )& rp2pio_statemachine_get_writing_obj ,
541+ MP_ROM_NONE ,
542+ MP_ROM_NONE },
543+ };
544+
545+
546+ //| @property
547+ //| def pending(self) -> int:
548+ //| """Returns the number of pending buffers for background writing.
549+ //|
550+ //| If the number is 0, then a `StateMachine.background_write` call will not block."""
551+ //|
552+ STATIC mp_obj_t rp2pio_statemachine_obj_get_pending (mp_obj_t self_in ) {
553+ rp2pio_statemachine_obj_t * self = MP_OBJ_TO_PTR (self_in );
554+ return mp_obj_new_int (common_hal_rp2pio_statemachine_get_pending (self ));
555+ }
556+ MP_DEFINE_CONST_FUN_OBJ_1 (rp2pio_statemachine_get_pending_obj , rp2pio_statemachine_obj_get_pending );
557+
558+ const mp_obj_property_t rp2pio_statemachine_pending_obj = {
559+ .base .type = & mp_type_property ,
560+ .proxy = {(mp_obj_t )& rp2pio_statemachine_get_pending_obj ,
561+ MP_ROM_NONE ,
562+ MP_ROM_NONE },
563+ };
429564
430565//| def readinto(self, buffer: WriteableBuffer, *, start: int = 0, end: Optional[int] = None) -> None:
431566//| """Read into ``buffer``. If the number of bytes to read is 0, nothing happens. The buffer
@@ -646,6 +781,10 @@ STATIC const mp_rom_map_elem_t rp2pio_statemachine_locals_dict_table[] = {
646781 { MP_ROM_QSTR (MP_QSTR_readinto ), MP_ROM_PTR (& rp2pio_statemachine_readinto_obj ) },
647782 { MP_ROM_QSTR (MP_QSTR_write ), MP_ROM_PTR (& rp2pio_statemachine_write_obj ) },
648783 { MP_ROM_QSTR (MP_QSTR_write_readinto ), MP_ROM_PTR (& rp2pio_statemachine_write_readinto_obj ) },
784+ { MP_ROM_QSTR (MP_QSTR_background_write ), MP_ROM_PTR (& rp2pio_statemachine_background_write_obj ) },
785+ { MP_ROM_QSTR (MP_QSTR_stop_background_write ), MP_ROM_PTR (& rp2pio_statemachine_stop_background_write_obj ) },
786+ { MP_ROM_QSTR (MP_QSTR_writing ), MP_ROM_PTR (& rp2pio_statemachine_writing_obj ) },
787+ { MP_ROM_QSTR (MP_QSTR_pending ), MP_ROM_PTR (& rp2pio_statemachine_pending_obj ) },
649788
650789 { MP_ROM_QSTR (MP_QSTR_frequency ), MP_ROM_PTR (& rp2pio_statemachine_frequency_obj ) },
651790 { MP_ROM_QSTR (MP_QSTR_rxstall ), MP_ROM_PTR (& rp2pio_statemachine_rxstall_obj ) },
0 commit comments