Skip to content

Commit cafa8ae

Browse files
author
Marcus Chang
committed
Fix serial_putc bug in NRF52 family
serial_putc didn't work when called with interrupts disabled.
1 parent 3663494 commit cafa8ae

File tree

1 file changed

+91
-17
lines changed

1 file changed

+91
-17
lines changed

targets/TARGET_NORDIC/TARGET_NRF5x/serial_api.c

Lines changed: 91 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -562,9 +562,6 @@ static void nordic_nrf5_uart_event_handler_rxdrdy(int instance)
562562
*/
563563
static void nordic_nrf5_uart_event_handler_endtx(int instance)
564564
{
565-
/* Set Tx done. */
566-
nordic_nrf5_uart_state[instance].tx_in_progress = 0;
567-
568565
/* Check if callback handler and Tx event mask is set. */
569566
uart_irq_handler callback = (uart_irq_handler) nordic_nrf5_uart_state[instance].owner->handler;
570567
uint32_t mask = nordic_nrf5_uart_state[instance].owner->mask;
@@ -611,6 +608,12 @@ static void nordic_nrf5_uart_event_handler_endrx_asynch(int instance)
611608
*/
612609
static void nordic_nrf5_uart_event_handler_endtx_asynch(int instance)
613610
{
611+
/* Disable ENDTX interrupt. */
612+
nordic_nrf5_uart_register[instance]->INTEN &= ~NRF_UARTE_INT_ENDTX_MASK;
613+
614+
/* Clear ENDTX event. */
615+
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX);
616+
614617
/* Set Tx done and reset Tx mode to be not asynchronous. */
615618
nordic_nrf5_uart_state[instance].tx_in_progress = 0;
616619
nordic_nrf5_uart_state[instance].tx_asynch = false;
@@ -673,21 +676,28 @@ static void nordic_nrf5_uart_event_handler(int instance)
673676
nordic_nrf5_uart_event_handler_rxdrdy(instance);
674677
}
675678

679+
/* Tx single character has been sent. */
680+
if (nrf_uarte_event_check(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_TXDRDY)) {
681+
682+
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_TXDRDY);
683+
684+
/* In non-async transfers this will generate and interrupt if callback and mask is set. */
685+
if (!nordic_nrf5_uart_state[instance].tx_asynch) {
686+
687+
nordic_nrf5_uart_event_handler_endtx(instance);
688+
}
689+
}
690+
676691
/* Tx DMA buffer has been sent. */
677692
if (nrf_uarte_event_check(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX))
678693
{
679-
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX);
680-
681694
#if DEVICE_SERIAL_ASYNCH
682-
/* Call appropriate event handler based on current mode. */
695+
/* Call async event handler in async mode. */
683696
if (nordic_nrf5_uart_state[instance].tx_asynch) {
684697

685698
nordic_nrf5_uart_event_handler_endtx_asynch(instance);
686-
} else
687-
#endif
688-
{
689-
nordic_nrf5_uart_event_handler_endtx(instance);
690699
}
700+
#endif
691701
}
692702
}
693703

@@ -895,10 +905,6 @@ static void nordic_nrf5_serial_configure(serial_t *obj)
895905
/* Configure common setting. */
896906
nordic_nrf5_uart_configure_object(obj);
897907

898-
/* Clear Tx event and enable Tx interrupts. */
899-
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX);
900-
nordic_nrf5_uart_register[instance]->INTEN |= NRF_UARTE_INT_ENDTX_MASK;
901-
902908
/* Set new owner. */
903909
nordic_nrf5_uart_state[instance].owner = uart_object;
904910
uart_object->update = false;
@@ -1060,6 +1066,11 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
10601066
uart_object->hwfc = NRF_UART_HWFC_DISABLED;
10611067
}
10621068

1069+
/* The STDIO object is stored in this file. Set the flag once initialized. */
1070+
if (obj == &stdio_uart) {
1071+
stdio_uart_inited = 1;
1072+
}
1073+
10631074
/* Initializing the serial object does not make it the owner of an instance.
10641075
* Only when the serial object is being used will the object take ownership
10651076
* over the instance.
@@ -1335,6 +1346,21 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
13351346

13361347
uart_object->mask &= ~type;
13371348
}
1349+
1350+
/* Enable TXDRDY event. */
1351+
if ((type == NORDIC_TX_IRQ) && enable) {
1352+
1353+
/* Clear Tx ready event and enable Tx ready interrupts. */
1354+
nrf_uarte_event_clear(nordic_nrf5_uart_register[uart_object->instance], NRF_UARTE_EVENT_TXDRDY);
1355+
nordic_nrf5_uart_register[uart_object->instance]->INTEN |= NRF_UARTE_INT_TXDRDY_MASK;
1356+
1357+
/* Disable TXDRDY event. */
1358+
} else if ((type == NORDIC_TX_IRQ) && !enable) {
1359+
1360+
/* Disable Tx ready interrupts and clear Tx ready event. */
1361+
nordic_nrf5_uart_register[uart_object->instance]->INTEN &= ~NRF_UARTE_INT_TXDRDY_MASK;
1362+
nrf_uarte_event_clear(nordic_nrf5_uart_register[uart_object->instance], NRF_UARTE_EVENT_TXDRDY);
1363+
}
13381364
}
13391365

13401366
/** Get character. This is a blocking call, waiting for a character
@@ -1412,15 +1438,41 @@ void serial_putc(serial_t *obj, int character)
14121438
/* Take ownership and configure UART if necessary. */
14131439
nordic_nrf5_serial_configure(obj);
14141440

1441+
/**
1442+
* The UARTE module can generate two different Tx events: TXDRDY when each character has
1443+
* been transmitted and ENDTX when the entire buffer has been sent.
1444+
*
1445+
* For the blocking serial_putc, TXDRDY interrupts are enabled and only used for the
1446+
* single character TX IRQ callback handler. The ENDTX event does not generate an interrupt
1447+
* but is caught using a busy-wait loop. Once ENDTX has been generated we disable TXDRDY
1448+
* interrupts again.
1449+
*/
1450+
14151451
/* Arm Tx DMA buffer. */
14161452
nordic_nrf5_uart_state[instance].tx_data = character;
14171453
nrf_uarte_tx_buffer_set(nordic_nrf5_uart_register[instance],
14181454
&nordic_nrf5_uart_state[instance].tx_data,
14191455
1);
14201456

1457+
/* Clear TXDRDY event and enable TXDRDY interrupts. */
1458+
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_TXDRDY);
1459+
nordic_nrf5_uart_register[instance]->INTEN |= NRF_UARTE_INT_TXDRDY_MASK;
1460+
1461+
/* Clear ENDTX event. */
1462+
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX);
1463+
14211464
/* Trigger DMA transfer. */
14221465
nrf_uarte_task_trigger(nordic_nrf5_uart_register[instance],
14231466
NRF_UARTE_TASK_STARTTX);
1467+
1468+
/* Busy-wait until the ENDTX event occurs. */
1469+
while (!nrf_uarte_event_check(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX));
1470+
1471+
/* Disable TXDRDY event again. */
1472+
nordic_nrf5_uart_register[instance]->INTEN &= ~NRF_UARTE_INT_TXDRDY_MASK;
1473+
1474+
/* Release mutex. As the owner this call is safe. */
1475+
nordic_nrf5_uart_state[instance].tx_in_progress = 0;
14241476
}
14251477

14261478
/** Check if the serial peripheral is readable
@@ -1574,6 +1626,20 @@ int serial_tx_asynch(serial_t *obj, const void *tx, size_t tx_length, uint8_t tx
15741626
nordic_nrf5_uart_state[instance].tx_asynch = true;
15751627
nordic_nrf5_serial_configure(obj);
15761628

1629+
/**
1630+
* The UARTE module can generate two different Tx events: TXDRDY when each
1631+
* character has been transmitted and ENDTX when the entire buffer has been sent.
1632+
*
1633+
* For the async serial_tx_async, TXDRDY interrupts are disabled completely. ENDTX
1634+
* interrupts are enabled and used to signal the completion of the async transfer.
1635+
*
1636+
* The ENDTX interrupt is diabled immediately after it is fired in the ISR.
1637+
*/
1638+
1639+
/* Clear Tx event and enable Tx interrupts. */
1640+
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX);
1641+
nordic_nrf5_uart_register[instance]->INTEN |= NRF_UARTE_INT_ENDTX_MASK;
1642+
15771643
/* Set Tx DMA buffer. */
15781644
nrf_uarte_tx_buffer_set(nordic_nrf5_uart_register[obj->serial.instance],
15791645
buffer,
@@ -1708,16 +1774,24 @@ void serial_tx_abort_asynch(serial_t *obj)
17081774
/* Transmission might be in progress. Disable interrupts to prevent ISR from firing. */
17091775
core_util_critical_section_enter();
17101776

1777+
int instance = obj->serial.instance;
1778+
1779+
/* Disable ENDTX interrupts. */
1780+
nordic_nrf5_uart_register[instance]->INTEN &= ~NRF_UARTE_INT_ENDTX_MASK;
1781+
1782+
/* Clear ENDTX event. */
1783+
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX);
1784+
17111785
/* Reset Tx flags. */
1712-
nordic_nrf5_uart_state[obj->serial.instance].tx_in_progress = 0;
1713-
nordic_nrf5_uart_state[obj->serial.instance].tx_asynch = false;
1786+
nordic_nrf5_uart_state[instance].tx_in_progress = 0;
1787+
nordic_nrf5_uart_state[instance].tx_asynch = false;
17141788

17151789
/* Force reconfiguration. */
17161790
obj->serial.update = true;
17171791
nordic_nrf5_serial_configure(obj);
17181792

17191793
/* Trigger STOP task. */
1720-
nrf_uarte_task_trigger(nordic_nrf5_uart_register[obj->serial.instance],
1794+
nrf_uarte_task_trigger(nordic_nrf5_uart_register[instance],
17211795
NRF_UARTE_TASK_STOPTX);
17221796

17231797
/* Enable interrupts again. */

0 commit comments

Comments
 (0)