Skip to content

Commit 4bb9bb9

Browse files
schodetlaurensvalk
authored andcommitted
pbio/drv/display_nxt: Use asynchronous wait for SPI mode change and writing.
Replace busy loops with busy asynchronous loops, to avoid blocking all the threads. Refs: pybricks/support#2425
1 parent 7663acd commit 4bb9bb9

File tree

1 file changed

+35
-25
lines changed

1 file changed

+35
-25
lines changed

lib/pbio/drv/display/display_nxt.c

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -115,43 +115,52 @@ static bool pbdrv_display_user_frame_update_requested;
115115
static uint8_t pbdrv_display_send_buffer[PBDRV_CONFIG_DISPLAY_NUM_COLS];
116116

117117
/*
118-
* Set the data transmission mode.
118+
* Switch to command transmission mode and send a command byte to the LCD controller.
119119
*/
120-
static void spi_set_tx_mode(spi_mode_t mode) {
121-
if (spi_mode == mode) {
122-
// Mode hasn't changed, no-op.
123-
return;
124-
} else {
120+
static pbio_error_t spi_write_command_byte(pbio_os_state_t *state, uint8_t command) {
121+
PBIO_OS_ASYNC_BEGIN(state);
122+
123+
if (spi_mode != SPI_MODE_COMMAND) {
125124
// If there is a mode switch, we need to let the SPI controller
126125
// drain all data first, to avoid spurious writes of the wrong
127126
// type.
128127
while (!(*AT91C_SPI_SR & AT91C_SPI_TXEMPTY)) {
129-
;
128+
pbio_os_request_poll();
129+
PBIO_OS_AWAIT_ONCE(state);
130130
}
131+
spi_mode = SPI_MODE_COMMAND;
132+
*AT91C_PIOA_CODR = AT91C_PA12_MISO;
131133
}
132134

133-
spi_mode = mode;
134-
135-
if (mode == SPI_MODE_COMMAND) {
136-
*AT91C_PIOA_CODR = AT91C_PA12_MISO;
137-
} else {
138-
*AT91C_PIOA_SODR = AT91C_PA12_MISO;
135+
// Wait for the transmit register to empty.
136+
while (!(*AT91C_SPI_SR & AT91C_SPI_TDRE)) {
137+
pbio_os_request_poll();
138+
PBIO_OS_AWAIT_ONCE(state);
139139
}
140+
141+
// Send the command byte.
142+
*AT91C_SPI_TDR = command;
143+
144+
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
140145
}
141146

142147
/*
143-
* Send a command byte to the LCD controller.
148+
* Switch to data transmission mode.
144149
*/
145-
static void spi_write_command_byte(uint8_t command) {
146-
spi_set_tx_mode(SPI_MODE_COMMAND);
150+
static pbio_error_t spi_set_data_mode(pbio_os_state_t *state) {
151+
PBIO_OS_ASYNC_BEGIN(state);
147152

148-
// Wait for the transmit register to empty.
149-
while (!(*AT91C_SPI_SR & AT91C_SPI_TDRE)) {
150-
;
153+
// Let the SPI controller drain all data first, to avoid spurious
154+
// writes of the wrong type.
155+
while (!(*AT91C_SPI_SR & AT91C_SPI_TXEMPTY)) {
156+
pbio_os_request_poll();
157+
PBIO_OS_AWAIT_ONCE(state);
151158
}
152159

153-
// Send the command byte and wait for a reply.
154-
*AT91C_SPI_TDR = command;
160+
spi_mode = SPI_MODE_DATA;
161+
*AT91C_PIOA_SODR = AT91C_PA12_MISO;
162+
163+
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
155164
}
156165

157166
/*
@@ -235,6 +244,7 @@ static pbio_os_process_t pbdrv_display_nxt_process;
235244
*/
236245
static pbio_error_t pbdrv_display_nxt_process_thread(pbio_os_state_t *state, void *context) {
237246
static pbio_os_timer_t timer;
247+
static pbio_os_state_t sub;
238248
static size_t i;
239249
static int page;
240250

@@ -294,20 +304,20 @@ static pbio_error_t pbdrv_display_nxt_process_thread(pbio_os_state_t *state, voi
294304
// Issue a reset command, and wait. Normally here we'd check the
295305
// UC1601 status register, but as noted at the start of the file, we
296306
// can't read from the LCD controller due to the board setup.
297-
spi_write_command_byte(RESET());
307+
PBIO_OS_AWAIT(state, &sub, spi_write_command_byte(&sub, RESET()));
298308
PBIO_OS_AWAIT_MS(state, &timer, 20);
299309

300310
// Send every command of the init sequence.
301311
for (i = 0; i < sizeof(lcd_init_sequence); i++) {
302-
spi_write_command_byte(lcd_init_sequence[i]);
312+
PBIO_OS_AWAIT(state, &sub, spi_write_command_byte(&sub, lcd_init_sequence[i]));
303313
}
304314

305315
// Clear display to start with.
306316
memset(&pbdrv_display_user_frame, 0, sizeof(pbdrv_display_user_frame));
307317
pbdrv_display_user_frame_update_requested = true;
308318

309319
// Make sure that we are in data TX mode.
310-
spi_set_tx_mode(SPI_MODE_DATA);
320+
PBIO_OS_AWAIT(state, &sub, spi_set_data_mode(&sub));
311321

312322
// Done initializing.
313323
pbio_busy_count_down();
@@ -348,7 +358,7 @@ static pbio_error_t pbdrv_display_nxt_process_thread(pbio_os_state_t *state, voi
348358
// capacitors gracefully.
349359
*AT91C_SPI_IDR = ~0;
350360
*AT91C_SPI_PTCR = AT91C_PDC_TXTDIS;
351-
spi_write_command_byte(RESET());
361+
PBIO_OS_AWAIT(state, &sub, spi_write_command_byte(&sub, RESET()));
352362
PBIO_OS_AWAIT_MS(state, &timer, 20);
353363

354364
pbio_busy_count_down();

0 commit comments

Comments
 (0)