Skip to content

Commit 44acaf5

Browse files
authored
Merge pull request #7369 from marcuschangarm/fix-nrf52-serial
Fix race condition in serial_api.c for NRF52 series
2 parents 2da597e + 2d71866 commit 44acaf5

File tree

2 files changed

+26
-86
lines changed

2 files changed

+26
-86
lines changed

targets/TARGET_NORDIC/TARGET_NRF5x/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,15 @@ All buffers can be resized to fit the application:
108108
```
109109
"name": "nordic",
110110
"config": {
111-
"uart-dma-size": {
111+
"uart_dma_size": {
112112
"help": "UART DMA buffer. 2 buffers per instance. DMA buffer is filled by UARTE",
113113
"value": 8
114114
},
115-
"uart-0-fifo-size": {
115+
"uart_0_fifo_size": {
116116
"help": "UART0 FIFO buffer. FIFO buffer is filled from DMA buffer.",
117117
"value": 32
118118
},
119-
"uart-1-fifo-size": {
119+
"uart_1_fifo_size": {
120120
"help": "UART1 FIFO buffer. FIFO buffer is filled from DMA buffer.",
121121
"value": 32
122122
}

targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/serial_api.c

Lines changed: 23 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,6 @@
110110
#define DMA_BUFFER_SIZE MBED_CONF_NORDIC_UART_DMA_SIZE
111111
#define NUMBER_OF_BANKS 2
112112

113-
/**
114-
* Default timer delay for callbacks.
115-
*/
116-
#define CALLBACK_DELAY_US 100
117-
118113
/**
119114
* Use RTC2 for idle timeouts.
120115
* Each channel is dedicated to one particular task.
@@ -130,10 +125,10 @@
130125
/**
131126
* SWI IRQ numbers
132127
*/
133-
#define UARTE0_SWI_TX_0_IRQ SWI2_EGU2_IRQn
134-
#define UARTE0_SWI_RX_0_IRQ SWI3_EGU3_IRQn
135-
#define UARTE1_SWI_TX_0_IRQ SWI4_EGU4_IRQn
136-
#define UARTE1_SWI_RX_0_IRQ SWI5_EGU5_IRQn
128+
#define UARTE0_SWI_TX_IRQ SWI2_EGU2_IRQn
129+
#define UARTE0_SWI_RX_IRQ SWI3_EGU3_IRQn
130+
#define UARTE1_SWI_TX_IRQ SWI4_EGU4_IRQn
131+
#define UARTE1_SWI_RX_IRQ SWI5_EGU5_IRQn
137132

138133
/***
139134
* _______ _ __
@@ -433,8 +428,8 @@ static void nordic_nrf5_uart_swi_rx_1(void)
433428
*/
434429
static void nordic_nrf5_uart_event_handler_endtx(int instance)
435430
{
436-
/* Disable TXDRDY event again. */
437-
nordic_nrf5_uart_register[instance]->INTEN &= ~NRF_UARTE_INT_TXDRDY_MASK;
431+
/* Disable ENDTX event again. */
432+
nordic_nrf5_uart_register[instance]->INTEN &= ~NRF_UARTE_INT_ENDTX_MASK;
438433

439434
/* Release mutex. As the owner this call is safe. */
440435
nordic_nrf5_uart_state[instance].tx_in_progress = 0;
@@ -519,12 +514,12 @@ static void nordic_swi_tx_trigger(int instance)
519514
{
520515
if (instance == 0) {
521516

522-
NVIC_SetPendingIRQ(UARTE0_SWI_TX_0_IRQ);
517+
NVIC_SetPendingIRQ(UARTE0_SWI_TX_IRQ);
523518
}
524519
#if UART1_ENABLED
525520
else if (instance == 1) {
526521

527-
NVIC_SetPendingIRQ(UARTE1_SWI_TX_0_IRQ);
522+
NVIC_SetPendingIRQ(UARTE1_SWI_TX_IRQ);
528523
}
529524
#endif
530525
}
@@ -538,11 +533,11 @@ static void nordic_swi_rx_trigger(int instance)
538533
{
539534
if (instance == 0) {
540535

541-
NVIC_SetPendingIRQ(UARTE0_SWI_RX_0_IRQ);
536+
NVIC_SetPendingIRQ(UARTE0_SWI_RX_IRQ);
542537
}
543538
else if (instance == 1) {
544539

545-
NVIC_SetPendingIRQ(UARTE1_SWI_RX_0_IRQ);
540+
NVIC_SetPendingIRQ(UARTE1_SWI_RX_IRQ);
546541
}
547542
}
548543

@@ -716,33 +711,14 @@ static void nordic_nrf5_uart_event_handler(int instance)
716711
nordic_nrf5_uart_event_handler_rxdrdy(instance);
717712
}
718713

719-
/* Tx single character has been sent. */
720-
if (nrf_uarte_event_check(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_TXDRDY)) {
721-
722-
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_TXDRDY);
723-
724-
/* In non-async transfers this will generate an interrupt if callback and mask is set. */
725-
if (!nordic_nrf5_uart_state[instance].tx_asynch) {
726-
727-
/* Use SWI to de-prioritize callback. */
728-
nordic_swi_tx_trigger(instance);
729-
}
730-
}
731-
732-
#if DEVICE_SERIAL_ASYNCH
733714
/* Tx DMA buffer has been sent. */
734715
if (nrf_uarte_event_check(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX))
735716
{
736717
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX);
737718

738-
/* Call async event handler in async mode. */
739-
if (nordic_nrf5_uart_state[instance].tx_asynch) {
740-
741-
/* Use SWI to de-prioritize callback. */
742-
nordic_swi_tx_trigger(instance);
743-
}
719+
/* Use SWI to de-prioritize callback. */
720+
nordic_swi_tx_trigger(instance);
744721
}
745-
#endif
746722
}
747723

748724
/**
@@ -1029,24 +1005,24 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
10291005
NRF_RTC_INT_COMPARE1_MASK);
10301006

10311007
/* Enable RTC2 IRQ. Priority is set to lowest so that the UARTE ISR can interrupt it. */
1032-
nrf_drv_common_irq_enable(RTC2_IRQn, APP_IRQ_PRIORITY_LOWEST);
1008+
nrf_drv_common_irq_enable(RTC2_IRQn, APP_IRQ_PRIORITY_HIGHEST);
10331009

10341010
/* Start RTC2. According to the datasheet the added power consumption is neglible so
10351011
* the RTC2 will run forever.
10361012
*/
10371013
nrf_rtc_task_trigger(NRF_RTC2, NRF_RTC_TASK_START);
10381014

10391015
/* Enable interrupts for SWI. */
1040-
NVIC_SetVector(UARTE0_SWI_TX_0_IRQ, (uint32_t) nordic_nrf5_uart_swi_tx_0);
1041-
NVIC_SetVector(UARTE0_SWI_RX_0_IRQ, (uint32_t) nordic_nrf5_uart_swi_rx_0);
1042-
nrf_drv_common_irq_enable(UARTE0_SWI_TX_0_IRQ, APP_IRQ_PRIORITY_LOWEST);
1043-
nrf_drv_common_irq_enable(UARTE0_SWI_RX_0_IRQ, APP_IRQ_PRIORITY_LOWEST);
1016+
NVIC_SetVector(UARTE0_SWI_TX_IRQ, (uint32_t) nordic_nrf5_uart_swi_tx_0);
1017+
NVIC_SetVector(UARTE0_SWI_RX_IRQ, (uint32_t) nordic_nrf5_uart_swi_rx_0);
1018+
nrf_drv_common_irq_enable(UARTE0_SWI_TX_IRQ, APP_IRQ_PRIORITY_LOWEST);
1019+
nrf_drv_common_irq_enable(UARTE0_SWI_RX_IRQ, APP_IRQ_PRIORITY_LOWEST);
10441020

10451021
#if UART1_ENABLED
1046-
NVIC_SetVector(UARTE1_SWI_TX_0_IRQ, (uint32_t) nordic_nrf5_uart_swi_tx_1);
1047-
NVIC_SetVector(UARTE1_SWI_RX_0_IRQ, (uint32_t) nordic_nrf5_uart_swi_rx_1);
1048-
nrf_drv_common_irq_enable(UARTE1_SWI_TX_0_IRQ, APP_IRQ_PRIORITY_LOWEST);
1049-
nrf_drv_common_irq_enable(UARTE1_SWI_RX_0_IRQ, APP_IRQ_PRIORITY_LOWEST);
1022+
NVIC_SetVector(UARTE1_SWI_TX_IRQ, (uint32_t) nordic_nrf5_uart_swi_tx_1);
1023+
NVIC_SetVector(UARTE1_SWI_RX_IRQ, (uint32_t) nordic_nrf5_uart_swi_rx_1);
1024+
nrf_drv_common_irq_enable(UARTE1_SWI_TX_IRQ, APP_IRQ_PRIORITY_LOWEST);
1025+
nrf_drv_common_irq_enable(UARTE1_SWI_RX_IRQ, APP_IRQ_PRIORITY_LOWEST);
10501026
#endif
10511027

10521028
/* Initialize FIFO buffer for UARTE0. */
@@ -1411,21 +1387,6 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
14111387

14121388
uart_object->mask &= ~type;
14131389
}
1414-
1415-
/* Enable TXDRDY event. */
1416-
if ((type == NORDIC_TX_IRQ) && enable) {
1417-
1418-
/* Clear Tx ready event and enable Tx ready interrupts. */
1419-
nrf_uarte_event_clear(nordic_nrf5_uart_register[uart_object->instance], NRF_UARTE_EVENT_TXDRDY);
1420-
nordic_nrf5_uart_register[uart_object->instance]->INTEN |= NRF_UARTE_INT_TXDRDY_MASK;
1421-
1422-
/* Disable TXDRDY event. */
1423-
} else if ((type == NORDIC_TX_IRQ) && !enable) {
1424-
1425-
/* Disable Tx ready interrupts and clear Tx ready event. */
1426-
nordic_nrf5_uart_register[uart_object->instance]->INTEN &= ~NRF_UARTE_INT_TXDRDY_MASK;
1427-
nrf_uarte_event_clear(nordic_nrf5_uart_register[uart_object->instance], NRF_UARTE_EVENT_TXDRDY);
1428-
}
14291390
}
14301391

14311392
/** Get character. This is a blocking call, waiting for a character
@@ -1503,26 +1464,15 @@ void serial_putc(serial_t *obj, int character)
15031464
/* Take ownership and configure UART if necessary. */
15041465
nordic_nrf5_serial_configure(obj);
15051466

1506-
/**
1507-
* The UARTE module can generate two different Tx events: TXDRDY when each character has
1508-
* been transmitted and ENDTX when the entire buffer has been sent.
1509-
*
1510-
* For the blocking serial_putc, TXDRDY interrupts are enabled and only used for the
1511-
* single character TX IRQ callback handler.
1512-
*/
1513-
15141467
/* Arm Tx DMA buffer. */
15151468
nordic_nrf5_uart_state[instance].tx_data = character;
15161469
nrf_uarte_tx_buffer_set(nordic_nrf5_uart_register[instance],
15171470
&nordic_nrf5_uart_state[instance].tx_data,
15181471
1);
15191472

1520-
/* Clear TXDRDY event and enable TXDRDY interrupts. */
1521-
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_TXDRDY);
1522-
nordic_nrf5_uart_register[instance]->INTEN |= NRF_UARTE_INT_TXDRDY_MASK;
1523-
1524-
/* Clear ENDTX event. */
1473+
/* Clear ENDTX event and enable interrupts. */
15251474
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX);
1475+
nordic_nrf5_uart_register[instance]->INTEN |= NRF_UARTE_INT_ENDTX_MASK;
15261476

15271477
/* Trigger DMA transfer. */
15281478
nrf_uarte_task_trigger(nordic_nrf5_uart_register[instance],
@@ -1680,16 +1630,6 @@ int serial_tx_asynch(serial_t *obj, const void *tx, size_t tx_length, uint8_t tx
16801630
nordic_nrf5_uart_state[instance].tx_asynch = true;
16811631
nordic_nrf5_serial_configure(obj);
16821632

1683-
/**
1684-
* The UARTE module can generate two different Tx events: TXDRDY when each
1685-
* character has been transmitted and ENDTX when the entire buffer has been sent.
1686-
*
1687-
* For the async serial_tx_async, TXDRDY interrupts are disabled completely. ENDTX
1688-
* interrupts are enabled and used to signal the completion of the async transfer.
1689-
*
1690-
* The ENDTX interrupt is diabled immediately after it is fired in the ISR.
1691-
*/
1692-
16931633
/* Clear Tx event and enable Tx interrupts. */
16941634
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX);
16951635
nordic_nrf5_uart_register[instance]->INTEN |= NRF_UARTE_INT_ENDTX_MASK;

0 commit comments

Comments
 (0)