@@ -426,6 +426,141 @@ STATIC mp_obj_t rp2pio_statemachine_write(size_t n_args, const mp_obj_t *pos_arg
426
426
}
427
427
MP_DEFINE_CONST_FUN_OBJ_KW (rp2pio_statemachine_write_obj , 2 , rp2pio_statemachine_write );
428
428
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
+ };
429
564
430
565
//| def readinto(self, buffer: WriteableBuffer, *, start: int = 0, end: Optional[int] = None) -> None:
431
566
//| """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[] = {
646
781
{ MP_ROM_QSTR (MP_QSTR_readinto ), MP_ROM_PTR (& rp2pio_statemachine_readinto_obj ) },
647
782
{ MP_ROM_QSTR (MP_QSTR_write ), MP_ROM_PTR (& rp2pio_statemachine_write_obj ) },
648
783
{ 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 ) },
649
788
650
789
{ MP_ROM_QSTR (MP_QSTR_frequency ), MP_ROM_PTR (& rp2pio_statemachine_frequency_obj ) },
651
790
{ MP_ROM_QSTR (MP_QSTR_rxstall ), MP_ROM_PTR (& rp2pio_statemachine_rxstall_obj ) },
0 commit comments