mirror of https://github.com/ARMmbed/mbed-os.git
NRF52: serial_api: Use polling for putc
There are scenarios where putc is called within a critical section, e.g to log ASSERTs in early initialization code. The interrupts being disabled here prevents the handlers for the UARTE from executing. This breaks the tx_in_progress flag based approach. The tx_in_progress never gets reset. Poll on the TXDRDY instead. It can be recreated with a simple program as shown here: *************** Current Behavior **************** ++ MbedOS Error Info ++ Error Status: 0x80FF0100 Code: 256 Module: 255 Error Message: F ************** With Fix ************************* ++ MbedOS Error Info ++ Error Status: 0x80FF0100 Code: 256 Module: 255 Error Message: Fatal Run-time error Location: 0x2C0A9 Error Value: 0x0 Current Thread: Id: 0x20005520 Entry: 0x30EBF StackSize: 0x1000 StackMem: 0x20004520 SP: 0x20005490 For more info, visit: https://armmbed.github.io/mbedos-error/?error=0x80FF0100 -- MbedOS Error Info -- nrf failure at .\main.cpp:22 ***************************************************pull/8479/head
parent
455b44bd0f
commit
099d0500ef
|
@ -1439,6 +1439,7 @@ int serial_getc(serial_t *obj)
|
|||
*/
|
||||
void serial_putc(serial_t *obj, int character)
|
||||
{
|
||||
bool done = false;
|
||||
MBED_ASSERT(obj);
|
||||
|
||||
#if DEVICE_SERIAL_ASYNCH
|
||||
|
@ -1449,35 +1450,20 @@ void serial_putc(serial_t *obj, int character)
|
|||
|
||||
int instance = uart_object->instance;
|
||||
|
||||
/**
|
||||
* tx_in_progress acts like a mutex to ensure only one transmission can be active at a time.
|
||||
* The flag is modified using the atomic compare-and-set function.
|
||||
*/
|
||||
bool mutex = false;
|
||||
|
||||
do {
|
||||
uint8_t expected = 0;
|
||||
uint8_t desired = 1;
|
||||
|
||||
mutex = core_util_atomic_cas_u8((uint8_t *) &nordic_nrf5_uart_state[instance].tx_in_progress, &expected, desired);
|
||||
} while (mutex == false);
|
||||
|
||||
/* Take ownership and configure UART if necessary. */
|
||||
nordic_nrf5_serial_configure(obj);
|
||||
|
||||
/* 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 ENDTX event and enable interrupts. */
|
||||
nrf_uarte_event_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_ENDTX);
|
||||
nrf_uarte_int_enable(nordic_nrf5_uart_register[instance], NRF_UARTE_INT_ENDTX_MASK);
|
||||
nrf_uarte_task_trigger(nordic_nrf5_uart_register[instance], NRF_UARTE_TASK_STARTTX);
|
||||
|
||||
/* Trigger DMA transfer. */
|
||||
nrf_uarte_task_trigger(nordic_nrf5_uart_register[instance],
|
||||
NRF_UARTE_TASK_STARTTX);
|
||||
do {
|
||||
done = nrf_uarte_event_extra_check(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_TXDRDY);
|
||||
} while(done == false);
|
||||
|
||||
nrf_uarte_event_extra_clear(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_TXDRDY);
|
||||
}
|
||||
|
||||
/** Check if the serial peripheral is readable
|
||||
|
|
|
@ -228,6 +228,25 @@ __STATIC_INLINE void nrf_uarte_event_clear(NRF_UARTE_Type * p_reg, nrf_uarte_eve
|
|||
*/
|
||||
__STATIC_INLINE bool nrf_uarte_event_check(NRF_UARTE_Type * p_reg, nrf_uarte_event_t event);
|
||||
|
||||
/**
|
||||
* @brief Function for checking the state of a specific extra UARTE event.
|
||||
*
|
||||
* @param[in] p_reg Pointer to the peripheral registers structure.
|
||||
* @param[in] event Event to check.
|
||||
*
|
||||
* @retval True if event is set, False otherwise.
|
||||
*/
|
||||
__STATIC_INLINE bool nrf_uarte_event_extra_check(NRF_UARTE_Type * p_reg, uint32_t event);
|
||||
|
||||
/**
|
||||
* @brief Function for clearing a specific extra UARTE event.
|
||||
*
|
||||
* @param[in] p_reg Pointer to the peripheral registers structure.
|
||||
* @param[in] event Extra event to clear.
|
||||
*/
|
||||
|
||||
__STATIC_INLINE void nrf_uarte_event_extra_clear(NRF_UARTE_Type * p_reg, uint32_t event);
|
||||
|
||||
/**
|
||||
* @brief Function for returning the address of a specific UARTE event register.
|
||||
*
|
||||
|
@ -456,11 +475,25 @@ __STATIC_INLINE void nrf_uarte_event_clear(NRF_UARTE_Type * p_reg, nrf_uarte_eve
|
|||
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_uarte_event_extra_clear(NRF_UARTE_Type * p_reg, uint32_t event)
|
||||
{
|
||||
*((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0x0UL;
|
||||
#if __CORTEX_M == 0x04
|
||||
volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event));
|
||||
(void)dummy;
|
||||
#endif
|
||||
|
||||
}
|
||||
__STATIC_INLINE bool nrf_uarte_event_check(NRF_UARTE_Type * p_reg, nrf_uarte_event_t event)
|
||||
{
|
||||
return (bool)*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
|
||||
}
|
||||
|
||||
__STATIC_INLINE bool nrf_uarte_event_extra_check(NRF_UARTE_Type * p_reg, uint32_t event)
|
||||
{
|
||||
return (bool)*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
|
||||
}
|
||||
|
||||
__STATIC_INLINE uint32_t nrf_uarte_event_address_get(NRF_UARTE_Type * p_reg,
|
||||
nrf_uarte_event_t event)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue