Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 121 additions & 19 deletions targets/TARGET_NORDIC/TARGET_NRF5x/serial_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ typedef struct {
uint8_t buffer[NUMBER_OF_BANKS][DMA_BUFFER_SIZE];
uint32_t rxdrdy_counter;
uint32_t endrx_counter;
uint32_t usage_counter;
uint8_t tx_data;
volatile uint8_t tx_in_progress;
volatile uint8_t rx_in_progress;
Expand Down Expand Up @@ -562,9 +563,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;
Expand Down Expand Up @@ -611,6 +609,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;
Expand Down Expand Up @@ -673,21 +677,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
}
}

Expand Down Expand Up @@ -895,10 +906,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;
Expand Down Expand Up @@ -1000,7 +1007,6 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
/* Enable interrupts for UARTE0. */
NVIC_SetVector(UARTE0_UART0_IRQn, (uint32_t) nordic_nrf5_uart0_handler);
nordic_nrf5_uart_irq_enable(0);
nrf_uarte_enable(nordic_nrf5_uart_register[0]);

#if UART1_ENABLED
/* Initialize FIFO buffer for UARTE1. */
Expand All @@ -1013,7 +1019,6 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
/* Enable interrupts for UARTE1. */
NVIC_SetVector(UARTE1_IRQn, (uint32_t) nordic_nrf5_uart1_handler);
nordic_nrf5_uart_irq_enable(1);
nrf_uarte_enable(nordic_nrf5_uart_register[1]);
#endif
}

Expand All @@ -1022,6 +1027,15 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)

uart_object->instance = instance;

/* Increment usage counter for this instance. */
nordic_nrf5_uart_state[instance].usage_counter++;

/* Enable instance on first usage. */
if (nordic_nrf5_uart_state[instance].usage_counter == 1) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does each peripheral instance have a usage counter? Shouldn't the usage counter be a part of the bank of peripherals?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You enable/disable each instance separately.


nrf_uarte_enable(nordic_nrf5_uart_register[instance]);
}

/* Store pins in serial object. */
if (tx == NC) {

Expand Down Expand Up @@ -1060,6 +1074,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.
Expand All @@ -1075,7 +1094,27 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
*/
void serial_free(serial_t *obj)
{
MBED_ASSERT(obj);

#if DEVICE_SERIAL_ASYNCH
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The need for this feels very strange.

Is this to say that obj can take multiple serial_t types?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

struct serial_s *uart_object = &obj->serial;
#else
struct serial_s *uart_object = obj;
#endif

int instance = uart_object->instance;

if (nordic_nrf5_uart_state[instance].usage_counter > 1) {

/* Decrement usage counter for this instance. */
nordic_nrf5_uart_state[instance].usage_counter--;

/* Disable instance when not in use. */
if (nordic_nrf5_uart_state[instance].usage_counter == 0) {

nrf_uarte_disable(nordic_nrf5_uart_register[instance]);
}
}
}

/** Configure the baud rate
Expand Down Expand Up @@ -1335,6 +1374,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
Expand Down Expand Up @@ -1412,15 +1466,41 @@ void serial_putc(serial_t *obj, int character)
/* Take ownership and configure UART if necessary. */
nordic_nrf5_serial_configure(obj);

/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for comments

* 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
Expand Down Expand Up @@ -1574,6 +1654,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,
Expand Down Expand Up @@ -1708,16 +1802,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. */
Expand Down