mirror of https://github.com/ARMmbed/mbed-os.git
Fix serial_putc bug in NRF52 family
serial_putc didn't work when called with interrupts disabled.pull/6547/head
parent
3663494bd9
commit
cafa8ae752
|
@ -562,9 +562,6 @@ static void nordic_nrf5_uart_event_handler_rxdrdy(int instance)
|
|||
*/
|
||||
static void nordic_nrf5_uart_event_handler_endtx(int instance)
|
||||
{
|
||||
/* Set Tx done. */
|
||||
nordic_nrf5_uart_state[instance].tx_in_progress = 0;
|
||||
|
||||
/* Check if callback handler and Tx event mask is set. */
|
||||
uart_irq_handler callback = (uart_irq_handler) nordic_nrf5_uart_state[instance].owner->handler;
|
||||
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)
|
|||
*/
|
||||
static void nordic_nrf5_uart_event_handler_endtx_asynch(int instance)
|
||||
{
|
||||
/* Disable ENDTX interrupt. */
|
||||
nordic_nrf5_uart_register[instance]->INTEN &= ~NRF_UARTE_INT_ENDTX_MASK;
|
||||
|
||||
/* Clear ENDTX event. */
|
||||
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX);
|
||||
|
||||
/* Set Tx done and reset Tx mode to be not asynchronous. */
|
||||
nordic_nrf5_uart_state[instance].tx_in_progress = 0;
|
||||
nordic_nrf5_uart_state[instance].tx_asynch = false;
|
||||
|
@ -673,21 +676,28 @@ static void nordic_nrf5_uart_event_handler(int instance)
|
|||
nordic_nrf5_uart_event_handler_rxdrdy(instance);
|
||||
}
|
||||
|
||||
/* Tx single character has been sent. */
|
||||
if (nrf_uarte_event_check(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_TXDRDY)) {
|
||||
|
||||
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_TXDRDY);
|
||||
|
||||
/* In non-async transfers this will generate and interrupt if callback and mask is set. */
|
||||
if (!nordic_nrf5_uart_state[instance].tx_asynch) {
|
||||
|
||||
nordic_nrf5_uart_event_handler_endtx(instance);
|
||||
}
|
||||
}
|
||||
|
||||
/* Tx DMA buffer has been sent. */
|
||||
if (nrf_uarte_event_check(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX))
|
||||
{
|
||||
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX);
|
||||
|
||||
#if DEVICE_SERIAL_ASYNCH
|
||||
/* Call appropriate event handler based on current mode. */
|
||||
/* Call async event handler in async mode. */
|
||||
if (nordic_nrf5_uart_state[instance].tx_asynch) {
|
||||
|
||||
nordic_nrf5_uart_event_handler_endtx_asynch(instance);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
nordic_nrf5_uart_event_handler_endtx(instance);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -895,10 +905,6 @@ static void nordic_nrf5_serial_configure(serial_t *obj)
|
|||
/* Configure common setting. */
|
||||
nordic_nrf5_uart_configure_object(obj);
|
||||
|
||||
/* Clear Tx event and enable Tx interrupts. */
|
||||
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX);
|
||||
nordic_nrf5_uart_register[instance]->INTEN |= NRF_UARTE_INT_ENDTX_MASK;
|
||||
|
||||
/* Set new owner. */
|
||||
nordic_nrf5_uart_state[instance].owner = uart_object;
|
||||
uart_object->update = false;
|
||||
|
@ -1060,6 +1066,11 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
|
|||
uart_object->hwfc = NRF_UART_HWFC_DISABLED;
|
||||
}
|
||||
|
||||
/* The STDIO object is stored in this file. Set the flag once initialized. */
|
||||
if (obj == &stdio_uart) {
|
||||
stdio_uart_inited = 1;
|
||||
}
|
||||
|
||||
/* Initializing the serial object does not make it the owner of an instance.
|
||||
* Only when the serial object is being used will the object take ownership
|
||||
* over the instance.
|
||||
|
@ -1335,6 +1346,21 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
|
|||
|
||||
uart_object->mask &= ~type;
|
||||
}
|
||||
|
||||
/* Enable TXDRDY event. */
|
||||
if ((type == NORDIC_TX_IRQ) && enable) {
|
||||
|
||||
/* Clear Tx ready event and enable Tx ready interrupts. */
|
||||
nrf_uarte_event_clear(nordic_nrf5_uart_register[uart_object->instance], NRF_UARTE_EVENT_TXDRDY);
|
||||
nordic_nrf5_uart_register[uart_object->instance]->INTEN |= NRF_UARTE_INT_TXDRDY_MASK;
|
||||
|
||||
/* Disable TXDRDY event. */
|
||||
} else if ((type == NORDIC_TX_IRQ) && !enable) {
|
||||
|
||||
/* Disable Tx ready interrupts and clear Tx ready event. */
|
||||
nordic_nrf5_uart_register[uart_object->instance]->INTEN &= ~NRF_UARTE_INT_TXDRDY_MASK;
|
||||
nrf_uarte_event_clear(nordic_nrf5_uart_register[uart_object->instance], NRF_UARTE_EVENT_TXDRDY);
|
||||
}
|
||||
}
|
||||
|
||||
/** Get character. This is a blocking call, waiting for a character
|
||||
|
@ -1412,15 +1438,41 @@ void serial_putc(serial_t *obj, int character)
|
|||
/* Take ownership and configure UART if necessary. */
|
||||
nordic_nrf5_serial_configure(obj);
|
||||
|
||||
/**
|
||||
* The UARTE module can generate two different Tx events: TXDRDY when each character has
|
||||
* been transmitted and ENDTX when the entire buffer has been sent.
|
||||
*
|
||||
* For the blocking serial_putc, TXDRDY interrupts are enabled and only used for the
|
||||
* single character TX IRQ callback handler. The ENDTX event does not generate an interrupt
|
||||
* but is caught using a busy-wait loop. Once ENDTX has been generated we disable TXDRDY
|
||||
* interrupts again.
|
||||
*/
|
||||
|
||||
/* Arm Tx DMA buffer. */
|
||||
nordic_nrf5_uart_state[instance].tx_data = character;
|
||||
nrf_uarte_tx_buffer_set(nordic_nrf5_uart_register[instance],
|
||||
&nordic_nrf5_uart_state[instance].tx_data,
|
||||
1);
|
||||
|
||||
/* Clear TXDRDY event and enable TXDRDY interrupts. */
|
||||
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_TXDRDY);
|
||||
nordic_nrf5_uart_register[instance]->INTEN |= NRF_UARTE_INT_TXDRDY_MASK;
|
||||
|
||||
/* Clear ENDTX event. */
|
||||
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX);
|
||||
|
||||
/* Trigger DMA transfer. */
|
||||
nrf_uarte_task_trigger(nordic_nrf5_uart_register[instance],
|
||||
NRF_UARTE_TASK_STARTTX);
|
||||
|
||||
/* Busy-wait until the ENDTX event occurs. */
|
||||
while (!nrf_uarte_event_check(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX));
|
||||
|
||||
/* Disable TXDRDY event again. */
|
||||
nordic_nrf5_uart_register[instance]->INTEN &= ~NRF_UARTE_INT_TXDRDY_MASK;
|
||||
|
||||
/* Release mutex. As the owner this call is safe. */
|
||||
nordic_nrf5_uart_state[instance].tx_in_progress = 0;
|
||||
}
|
||||
|
||||
/** 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
|
|||
nordic_nrf5_uart_state[instance].tx_asynch = true;
|
||||
nordic_nrf5_serial_configure(obj);
|
||||
|
||||
/**
|
||||
* The UARTE module can generate two different Tx events: TXDRDY when each
|
||||
* character has been transmitted and ENDTX when the entire buffer has been sent.
|
||||
*
|
||||
* For the async serial_tx_async, TXDRDY interrupts are disabled completely. ENDTX
|
||||
* interrupts are enabled and used to signal the completion of the async transfer.
|
||||
*
|
||||
* The ENDTX interrupt is diabled immediately after it is fired in the ISR.
|
||||
*/
|
||||
|
||||
/* Clear Tx event and enable Tx interrupts. */
|
||||
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX);
|
||||
nordic_nrf5_uart_register[instance]->INTEN |= NRF_UARTE_INT_ENDTX_MASK;
|
||||
|
||||
/* Set Tx DMA buffer. */
|
||||
nrf_uarte_tx_buffer_set(nordic_nrf5_uart_register[obj->serial.instance],
|
||||
buffer,
|
||||
|
@ -1708,16 +1774,24 @@ void serial_tx_abort_asynch(serial_t *obj)
|
|||
/* Transmission might be in progress. Disable interrupts to prevent ISR from firing. */
|
||||
core_util_critical_section_enter();
|
||||
|
||||
int instance = obj->serial.instance;
|
||||
|
||||
/* Disable ENDTX interrupts. */
|
||||
nordic_nrf5_uart_register[instance]->INTEN &= ~NRF_UARTE_INT_ENDTX_MASK;
|
||||
|
||||
/* Clear ENDTX event. */
|
||||
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX);
|
||||
|
||||
/* Reset Tx flags. */
|
||||
nordic_nrf5_uart_state[obj->serial.instance].tx_in_progress = 0;
|
||||
nordic_nrf5_uart_state[obj->serial.instance].tx_asynch = false;
|
||||
nordic_nrf5_uart_state[instance].tx_in_progress = 0;
|
||||
nordic_nrf5_uart_state[instance].tx_asynch = false;
|
||||
|
||||
/* Force reconfiguration. */
|
||||
obj->serial.update = true;
|
||||
nordic_nrf5_serial_configure(obj);
|
||||
|
||||
/* Trigger STOP task. */
|
||||
nrf_uarte_task_trigger(nordic_nrf5_uart_register[obj->serial.instance],
|
||||
nrf_uarte_task_trigger(nordic_nrf5_uart_register[instance],
|
||||
NRF_UARTE_TASK_STOPTX);
|
||||
|
||||
/* Enable interrupts again. */
|
||||
|
|
Loading…
Reference in New Issue