@@ -193,52 +193,39 @@ static size_t spi_device_send_frame(ottf_console_t *console, const char *buf,
193193 // reads out the entire frame. Clear the TX-ready indicator pin before
194194 // continuing.
195195 if (console -> data .spi .tx_ready_gpio != kOttfSpiNoTxGpio ) {
196- // Where possible, for synchronization use the last read address to
197- // determine whether the host has started/finished reading the data to avoid
198- // reliance on HW chip select signals, which could be missed depending on
199- // Ibex/SPI clock speeds and are difficult to handle in emulation
200- // environments.
201- uint32_t target_read_addr = 0 ;
202- if (next_write_address == 0 ) {
203- target_read_addr = kSpiDeviceReadBufferSizeBytes - 1 ;
204- } else {
205- target_read_addr = next_write_address - 1 ;
206- }
207-
208- uint32_t initial_read_addr ;
209- if (dif_spi_device_get_last_read_address (spi_device , & initial_read_addr ) !=
210- kDifOk ) {
211- return 0 ;
212- }
213196 OT_DISCARD (dif_gpio_write (& ottf_console_gpio ,
214197 console -> data .spi .tx_ready_gpio , true));
215-
216- // Wait until a /CS low or a read address change to toggle TX ready low
217- bool cs_state ;
218- uint32_t last_read_addr ;
219- do {
220- if (dif_spi_device_get_csb_status (spi_device , & cs_state ) != kDifOk ||
221- dif_spi_device_get_last_read_address (spi_device , & last_read_addr ) !=
222- kDifOk ) {
223- return 0 ;
198+ bool cs_state = true;
199+ bool target_cs_state = false;
200+ // There will be two bulk transfers that can be synchronized by the
201+ // chip-select action. First the host will read out the 12-byte frame
202+ // header, followed by the N-byte payload. Each transfer is framed on the
203+ // wire by observing the chip-select first toggling high->low then
204+ // low->high.
205+ //
206+ // After the first toggle low, when the host begins reading out the frame
207+ // header, we can deassert the TX-ready pin as the host will continue to
208+ // complete two SPI transfers regardless.
209+ for (size_t i = 0 ; i < 4 ; ++ i ) {
210+ // Repeat four times, because there are 4 CSB-toggle events in two
211+ // standard SPI transfers.
212+
213+ // Query the state of CSB until it changes.
214+ do {
215+ if (dif_spi_device_get_csb_status (spi_device , & cs_state ) != kDifOk ) {
216+ return 0 ;
217+ }
218+ } while (cs_state != target_cs_state );
219+ target_cs_state = !target_cs_state ;
220+
221+ // After the first toggle of CSB (high->low, the start of the header
222+ // transfer), the HOST is already going to queue up and complete 2 full
223+ // transfers, so we can de-assert the TX-Ready indicator GPIO.
224+ if (i == 0 ) {
225+ OT_DISCARD (dif_gpio_write (& ottf_console_gpio ,
226+ console -> data .spi .tx_ready_gpio , false));
224227 }
225- } while (cs_state && last_read_addr == initial_read_addr );
226-
227- // After the host begins reading out the frame header, we can deassert the
228- // TX-ready pin as the host will continue to complete two SPI transfers
229- // (the header and payload) regardless.
230- OT_DISCARD (dif_gpio_write (& ottf_console_gpio ,
231- console -> data .spi .tx_ready_gpio , false));
232-
233- // Finished only when the read address matches the last written byte of
234- // data, and /CS is high (deasserted).
235- do {
236- if (dif_spi_device_get_csb_status (spi_device , & cs_state ) != kDifOk ||
237- dif_spi_device_get_last_read_address (spi_device , & last_read_addr ) !=
238- kDifOk ) {
239- return 0 ;
240- }
241- } while (!cs_state || last_read_addr != target_read_addr );
228+ }
242229
243230 // Reset the write_address before returning.
244231 next_write_address = 0 ;
0 commit comments