piolib: please add API to access the txstall register & other FDEBUG registers
Sometimes it's necessary to wait for a txstall, not just tx fifo drain, before performing some other action. For instance, to implement transmit-only SPI with a GPIO CS pin, you need to wait for the last bit of SPI data to actually be transmitted before deasserting CS.
Hi Jeff, my head is temporarily out of PIO space, but I'll consider this and #115 when it returns.
TXSTALL appears along with other flags (RXSTALL. TXOVER and RXUNDER) in the FDEBUG register. There is currently no accessor function, so I feel free to come up with something new - ideally one that automatically selects the correct flags for the current/specified SM.
How do you feel about the following:
uint pio_sm_get_flags(PIO pio, uint sm, uint flags, bool clear);
uint pio_sm_wait_flags(PIO pio, uint sm, uint flags, bool clear, uint timeout_us);
flags is a bit mask of abstract flags. As you've probably guessed, clear allows any matching flags to be cleared. The return value is the sum of the flags which were set. pio_sm_wait_flags causes the return to block until any of the specified flags (is "events" a better name?) is true, or the timeout expires. pio_sm_get_flags is effectively pio_sm_wait_flag with a timeout of 0, and will probably be implemented as such. A return value of 0 indicates the timeout expired before any flags were set.
Here's what we do in CircuitPython on rp2 around detecting completion of a transfer:
// Clear the stall bit so we can detect when the state machine is done transmitting.
self->pio->fdebug = stall_mask;
}
// Wait for the state machine to finish transmitting the data we've queued
// up.
if (tx) {
while (!pio_sm_is_tx_fifo_empty(self->pio, self->state_machine) ||
(self->wait_for_txstall && (self->pio->fdebug & stall_mask) == 0)) {
RUN_BACKGROUND_TASKS;
if (self->user_interruptible && mp_hal_is_interrupted()) {
break;
}
}
}
the first bit would be pio_sm_get_flags(self->pio, self->state_machine, PIO_FLAG_TXSTALL, true); and the second would be pio_sm_get_flags(self->pio, self->state_machine, PIO_FLAG_TXSTALL, false). Because we need to poll for other events, we probably would't use a timeout_us variant.
We don't actually seem to use any other FDEBUG bits than TXSTALL and RXSTALL fwiw
I'd already decided to include a pio_sm_clear_flags API function, however it is implemented.