@@ -426,63 +426,79 @@ 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 start_continuous_write(self, buffer: Optional[ReadableBuffer], *, start: int = 0, end: Optional[int] = None) -> None:
430
- //| """Write the data contained in ``buffer`` to the state machine repeatedly until stopped. If the buffer is empty or None, an existing continuous_write is canceled.
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.
431
437
//|
432
438
//| Writes to the FIFO will match the input buffer's element size. For example, bytearray elements
433
439
//| will perform 8 bit writes to the PIO FIFO. The RP2040's memory bus will duplicate the value into
434
440
//| the other byte positions. So, pulling more data in the PIO assembly will read the duplicated values.
435
441
//|
436
442
//| To perform 16 or 32 bits writes into the FIFO use an `array.array` with a type code of the desired
437
- //| size, or use `memoryview.cast` to change the interpretation of an existing buffer.
438
- //|
439
- //| To atomically change from one buffer to another, simply call
440
- //| `StateMachine.start_continuous_write` again with a different buffer with the same element size.
441
- //| The call will only return once DMA has started putting the previous
442
- //| buffer's data into the PIO FIFO.
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.
443
446
//|
444
- //| If the buffer is modified while it is being written out, the updated
447
+ //| If a buffer is modified while it is being written out, the updated
445
448
//| values will be used. However, because of interactions between CPU
446
449
//| writes, DMA and the PIO FIFO are complex, it is difficult to predict
447
450
//| the result of modifying multiple values. Instead, alternate between
448
451
//| a pair of buffers.
449
452
//|
450
- //| :param ~circuitpython_typing.ReadableBuffer buffer: Write out the data in this buffer
451
- //| :param int start: Start of the slice of ``buffer`` to write out: ``buffer[start:end]``
452
- //| :param int end: End of the slice; this index is not included. Defaults to ``len(buffer)``"""
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
+ //| """
453
460
//| ...
454
461
//|
455
- STATIC mp_obj_t rp2pio_statemachine_start_continuous_write (size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
456
- enum { ARG_buffer , ARG_start , ARG_end };
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 };
457
482
static const mp_arg_t allowed_args [] = {
458
- { MP_QSTR_buffer , MP_ARG_REQUIRED | MP_ARG_OBJ , {.u_obj = MP_OBJ_NULL } },
459
- { MP_QSTR_start , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 0 } },
460
- { MP_QSTR_end , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = INT_MAX } },
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 } },
461
485
};
462
486
rp2pio_statemachine_obj_t * self = MP_OBJ_TO_PTR (pos_args [0 ]);
463
487
check_for_deinit (self );
464
488
mp_arg_val_t args [MP_ARRAY_SIZE (allowed_args )];
465
489
mp_arg_parse_all (n_args - 1 , pos_args + 1 , kw_args , MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
466
490
467
- mp_buffer_info_t bufinfo = {};
468
- if (args [ARG_buffer ].u_obj != mp_const_none ) {
469
- mp_get_buffer_raise (args [ARG_buffer ].u_obj , & bufinfo , MP_BUFFER_READ );
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 ;
470
498
}
471
- int32_t start = args [ARG_start ].u_int ;
472
- size_t length = bufinfo .len ;
473
- normalize_buffer_bounds (& start , args [ARG_end ].u_int , & length );
474
- bool ok = true;
475
- if (length == 0 ) {
476
- ok = common_hal_rp2pio_statemachine_end_continuous_write (self );
477
- } else {
478
- uint8_t * original_pointer = bufinfo .buf ;
479
- int stride_in_bytes = mp_binary_get_size ('@' , bufinfo .typecode , NULL );
480
- if (stride_in_bytes > 4 ) {
481
- mp_raise_ValueError (translate ("Buffer elements must be 4 bytes long or less" ));
482
- }
483
499
484
- ok = common_hal_rp2pio_statemachine_start_continuous_write (self , args [ ARG_buffer ]. u_obj , (( uint8_t * ) bufinfo . buf ) + start , length , stride_in_bytes );
485
- }
500
+ bool ok = common_hal_rp2pio_statemachine_background_write (self , & once_info , & loop_info , stride_in_bytes );
501
+
486
502
if (mp_hal_is_interrupted ()) {
487
503
return mp_const_none ;
488
504
}
@@ -491,14 +507,14 @@ STATIC mp_obj_t rp2pio_statemachine_start_continuous_write(size_t n_args, const
491
507
}
492
508
return mp_const_none ;
493
509
}
494
- MP_DEFINE_CONST_FUN_OBJ_KW (rp2pio_statemachine_start_continuous_write_obj , 2 , rp2pio_statemachine_start_continuous_write );
510
+ MP_DEFINE_CONST_FUN_OBJ_KW (rp2pio_statemachine_background_write_obj , 1 , rp2pio_statemachine_background_write );
495
511
496
- //| def end_continuous_write (self) -> None:
497
- //| """Stop a continuous write, if one is in progress."""
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 ."""
498
514
//|
499
- STATIC mp_obj_t rp2pio_statemachine_obj_end_continuous_write (mp_obj_t self_in ) {
515
+ STATIC mp_obj_t rp2pio_statemachine_obj_stop_background_write (mp_obj_t self_in ) {
500
516
rp2pio_statemachine_obj_t * self = MP_OBJ_TO_PTR (self_in );
501
- bool ok = common_hal_rp2pio_statemachine_end_continuous_write (self );
517
+ bool ok = common_hal_rp2pio_statemachine_stop_background_write (self );
502
518
if (mp_hal_is_interrupted ()) {
503
519
return mp_const_none ;
504
520
}
@@ -507,8 +523,45 @@ STATIC mp_obj_t rp2pio_statemachine_obj_end_continuous_write(mp_obj_t self_in) {
507
523
}
508
524
return mp_const_none ;
509
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
+ };
510
564
511
- MP_DEFINE_CONST_FUN_OBJ_1 (rp2pio_statemachine_end_continuous_write_obj , rp2pio_statemachine_obj_end_continuous_write );
512
565
//| def readinto(self, buffer: WriteableBuffer, *, start: int = 0, end: Optional[int] = None) -> None:
513
566
//| """Read into ``buffer``. If the number of bytes to read is 0, nothing happens. The buffer
514
567
//| includes any data added to the fifo even if it was added before this was called.
@@ -728,8 +781,10 @@ STATIC const mp_rom_map_elem_t rp2pio_statemachine_locals_dict_table[] = {
728
781
{ MP_ROM_QSTR (MP_QSTR_readinto ), MP_ROM_PTR (& rp2pio_statemachine_readinto_obj ) },
729
782
{ MP_ROM_QSTR (MP_QSTR_write ), MP_ROM_PTR (& rp2pio_statemachine_write_obj ) },
730
783
{ MP_ROM_QSTR (MP_QSTR_write_readinto ), MP_ROM_PTR (& rp2pio_statemachine_write_readinto_obj ) },
731
- { MP_ROM_QSTR (MP_QSTR_start_continuous_write ), MP_ROM_PTR (& rp2pio_statemachine_start_continuous_write_obj ) },
732
- { MP_ROM_QSTR (MP_QSTR_end_continuous_write ), MP_ROM_PTR (& rp2pio_statemachine_end_continuous_write_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 ) },
733
788
734
789
{ MP_ROM_QSTR (MP_QSTR_frequency ), MP_ROM_PTR (& rp2pio_statemachine_frequency_obj ) },
735
790
{ MP_ROM_QSTR (MP_QSTR_rxstall ), MP_ROM_PTR (& rp2pio_statemachine_rxstall_obj ) },
0 commit comments