Skip to content

Commit fa76b63

Browse files
Marcus Chang0xc0170
authored andcommitted
Serial re-implementation for the NRF52 series
Serial implementation uses UARTE instead of UART peripheral: * EasyDMA is used for reading and writing data. * Triple buffering for receiving data. See README for full description.
1 parent 42f4982 commit fa76b63

File tree

19 files changed

+1854
-492
lines changed

19 files changed

+1854
-492
lines changed

targets/TARGET_NORDIC/TARGET_NRF5x/PeripheralPinsDefault.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,26 @@
2121
* Can be overwritten by user.
2222
*/
2323
MBED_WEAK const PinMapI2C PinMap_I2C[1] = {
24-
{NC, NC, NC}
24+
{ NC, NC, NC }
2525
};
2626

2727
/* Default mapping between SPI pins and SPI instance.
2828
* Can be overwritten by user.
2929
*/
3030
MBED_WEAK const PinMapSPI PinMap_SPI[1] = {
31-
{NC, NC, NC, NC}
31+
{ NC, NC, NC, NC }
3232
};
3333

3434
/* Default mapping between PWM pins and PWM instance.
3535
* Can be overwritten by user.
3636
*/
3737
MBED_WEAK const PinMapPWM PinMap_PWM[1] = {
38-
{NC, NC}
38+
{ NC, NC }
39+
};
40+
41+
/* Default mapping between UART pins and UART instance.
42+
* Can be overwritten by user.
43+
*/
44+
MBED_WEAK const PinMapUART PinMap_UART[1] = {
45+
{ NC, NC, NC }
3946
};

targets/TARGET_NORDIC/TARGET_NRF5x/README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,65 @@ The tables must be placed in a C compilation file.
4040
1. When called from the same thread, it is safe to assign I2C and SPI objects to the same instance.
4141
1. If an instance is being used exclusively for either I2C or SPI, the objects can safely be called from multiple threads.
4242
1. If an instance is being used for both I2C and SPI, the user must provide thread safety between the objects.
43+
44+
45+
### Serial
46+
47+
The serial implementation uses the UARTE module which works exclusively through EasyDMA and RAM buffers. For optimal performance, each configured instance (NRF52832 has 1, NRF52840 has 2) has three buffers statically assigned:
48+
49+
1. Rx DMA buffer, which EasyDMA is currently writing to.
50+
1. Rx DMA buffer, pre-loaded in EasyDMA for automatic switchover.
51+
1. Rx FIFO buffer, for serving data to the application.
52+
53+
When the first DMA buffer is full or flushed the interrupt handler will automatically copy the DMA buffer to the FIFO buffer. This happens in interrupt context to avoid data loss and with UARTE interrupts set at the highest priority. The FIFO buffer is backed by the Nordic atomic fifo, which can be read and written to safely without disabling interrupts.
54+
55+
#### Customization
56+
57+
All buffers can be resized to fit the application:
58+
59+
```
60+
"name": "nordic",
61+
"config": {
62+
"uart-dma-size": {
63+
"help": "UART DMA buffer. 2 buffers per instance. DMA buffer is filled by UARTE",
64+
"value": 8
65+
},
66+
"uart-0-fifo-size": {
67+
"help": "UART0 FIFO buffer. FIFO buffer is filled from DMA buffer.",
68+
"value": 32
69+
},
70+
"uart-1-fifo-size": {
71+
"help": "UART1 FIFO buffer. FIFO buffer is filled from DMA buffer.",
72+
"value": 32
73+
}
74+
}
75+
```
76+
77+
All DMA buffers are the same size and must be at least 5 bytes due to hardware restrictions. DMA buffers should be sized to handle the worst expected interrupt latency. FIFO buffers can be configured per instance and the size should reflect the largest expected burst data. For example, a serial debug port might receive a line of data at a time, so an 80 byte FIFO buffer would be adequate. A serial port connected to a wifi radio should have a FIFO buffer in the kilo byte range.
78+
79+
For the NRF52840, UARTE instances are assigned based on pins and calling order. Serial objects with the same pin configurations will go to the same instance. A custom configuration table can be provided by overriding the weakly defined default empty table. In the example below, serial objects using pins `p1` and `p2` for `Tx` and `Rx` will always be assigned to `Instance 1` and serial objects using pins `p3` and `p4` for `Tx` and `Rx` will be assigned to `Instance 0` regardless of calling order. The custom configuration table must always be terminated with a row of `NC`.
80+
81+
```
82+
const PinMapI2C PinMap_UART[] = {
83+
{p1, p2, 1},
84+
{p3, p4, 0},
85+
{NC, NC, NC}
86+
};
87+
```
88+
89+
The table must be placed in a C compilation file.
90+
91+
92+
#### RTC2
93+
94+
Because each DMA buffer must be at least 5 bytes deep, each buffer is automatically flushed after a certain idle period to ensure low latency and correctness. This idle timeout is implemented using 2 of the 4 channels on RTC instance 2. This leaves RTC0 for the SoftDevice and RTC1 for Mbed tickers.
95+
96+
The RTC2 ISR is set at the lowest interrupt priority to ensure that UARTE interrupts take precedence. The last 2 of the 4 RTC channels are used for decoupling UARTE ISR context from Mbed IRQ events. This ensures that any user code will only delay other user callbacks and idle flushing and puts an upper bound on the interrupt handling time for the UARTE ISR.
97+
98+
#### Limitations
99+
100+
* The UARTE hardware only supports 8-bit, None/Even parity, and 1 stop bit.
101+
* The asynchronous read and write implementation currently only support 255 byte transfers.
102+
* The EasyDMA hardware can only read from RAM, which means all Tx buffers must reside in RAM. If a Tx buffer residing in flash is passed to the asynchronous write function, the function will try to copy the Tx buffer to a temporary internal buffer and transmit the data from there.
103+
* It is not possible to do an asynchronous write from flash and receive non-asynchronously at the same time since the non-asynchronous receive buffer is being used as the temporary transmission buffer.
104+

targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/TARGET_MCU_NRF52832/PeripheralNames.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,6 @@
4545
extern "C" {
4646
#endif
4747

48-
#define STDIO_UART_TX TX_PIN_NUMBER
49-
#define STDIO_UART_RX RX_PIN_NUMBER
50-
#define STDIO_UART UART_0
51-
5248
typedef enum {
5349
UART_0 = (int)NRF_UART0_BASE
5450
} UARTName;

targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/TARGET_MCU_NRF52832/TARGET_DELTA_DFBM_NQ620/PinNames.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ typedef enum {
139139
// mBed interface Pins
140140
USBTX = TX_PIN_NUMBER,
141141
USBRX = RX_PIN_NUMBER,
142+
STDIO_UART_TX = TX_PIN_NUMBER,
143+
STDIO_UART_RX = RX_PIN_NUMBER,
142144

143145
SPI_PSELMOSI0 = p23,
144146
SPI_PSELMISO0 = p24,

targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/TARGET_MCU_NRF52832/TARGET_MTB_UBLOX_NINA_B1/PinNames.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ typedef enum {
119119
TX_PIN_NUMBER = p6,
120120
CTS_PIN_NUMBER = p7,
121121
RTS_PIN_NUMBER = p31,
122+
STDIO_UART_TX = TX_PIN_NUMBER,
123+
STDIO_UART_RX = RX_PIN_NUMBER,
122124

123125
I2C_SDA = p2,
124126
I2C_SCL = p3,

targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/TARGET_MCU_NRF52832/TARGET_NRF52_DK/PinNames.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ typedef enum {
140140
// mBed interface Pins
141141
USBTX = TX_PIN_NUMBER,
142142
USBRX = RX_PIN_NUMBER,
143+
STDIO_UART_TX = TX_PIN_NUMBER,
144+
STDIO_UART_RX = RX_PIN_NUMBER,
143145

144146
SPI_PSELMOSI0 = p23,
145147
SPI_PSELMISO0 = p24,

targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/TARGET_MCU_NRF52832/TARGET_RBLAB_BLENANO2/PinNames.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ typedef enum {
130130
TX_PIN_NUMBER = p29,
131131
CTS_PIN_NUMBER = p28,
132132
RTS_PIN_NUMBER = p2,
133+
STDIO_UART_TX = TX_PIN_NUMBER,
134+
STDIO_UART_RX = RX_PIN_NUMBER,
133135

134136
// mBed interface Pins
135137
USBTX = TX_PIN_NUMBER,

targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/TARGET_MCU_NRF52832/TARGET_UBLOX_EVA_NINA/PinNames.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ typedef enum {
8484
TX_PIN_NUMBER = p6,
8585
CTS_PIN_NUMBER = p7,
8686
RTS_PIN_NUMBER = p31,
87+
STDIO_UART_TX = TX_PIN_NUMBER,
88+
STDIO_UART_RX = RX_PIN_NUMBER,
89+
8790
I2C_SDA0 = p2,
8891
I2C_SCL0 = p3,
8992

targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/TARGET_MCU_NRF52832/TARGET_UBLOX_EVK_NINA_B1/PinNames.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ typedef enum {
107107
TX_PIN_NUMBER = p6,
108108
CTS_PIN_NUMBER = p7,
109109
RTS_PIN_NUMBER = p31,
110+
STDIO_UART_TX = TX_PIN_NUMBER,
111+
STDIO_UART_RX = RX_PIN_NUMBER,
110112
I2C_SDA0 = p2,
111113
I2C_SCL0 = p3,
112114
// mBed interface pins

targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/TARGET_MCU_NRF52832/TARGET_VBLUNO52/PinNames.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ typedef enum {
141141
TX_PIN_NUMBER = p6,
142142
CTS_PIN_NUMBER = p7, //not on Header
143143
RTS_PIN_NUMBER = p5, //not on Header
144+
STDIO_UART_TX = TX_PIN_NUMBER,
145+
STDIO_UART_RX = RX_PIN_NUMBER,
144146

145147
// mBed interface Pins
146148
USBTX = TX_PIN_NUMBER,

targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/TARGET_MCU_NRF52832/config/sdk_config.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3004,7 +3004,7 @@
30043004
// <e> UART_ENABLED - nrf_drv_uart - UART/UARTE peripheral driver
30053005
//==========================================================
30063006
#ifndef UART_ENABLED
3007-
#define UART_ENABLED 0
3007+
#define UART_ENABLED 1
30083008
#endif
30093009
// <o> UART_DEFAULT_CONFIG_HWFC - Hardware Flow Control
30103010

@@ -3044,7 +3044,7 @@
30443044
// <268435456=> 1000000 baud
30453045

30463046
#ifndef UART_DEFAULT_CONFIG_BAUDRATE
3047-
#define UART_DEFAULT_CONFIG_BAUDRATE 30801920
3047+
#define UART_DEFAULT_CONFIG_BAUDRATE 2576384
30483048
#endif
30493049

30503050
// <o> UART_DEFAULT_CONFIG_IRQ_PRIORITY - Interrupt priority

targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/TARGET_MCU_NRF52840/PeripheralNames.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,6 @@
4545
extern "C" {
4646
#endif
4747

48-
#define STDIO_UART_TX TX_PIN_NUMBER
49-
#define STDIO_UART_RX RX_PIN_NUMBER
50-
#define STDIO_UART UART_0
51-
5248
typedef enum
5349
{
5450
UART_0 = (int)NRF_UART0_BASE

targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/TARGET_MCU_NRF52840/TARGET_NRF52840_DK/PinNames.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ typedef enum {
178178
// mBed interface Pins
179179
USBTX = TX_PIN_NUMBER,
180180
USBRX = RX_PIN_NUMBER,
181+
STDIO_UART_TX = TX_PIN_NUMBER,
182+
STDIO_UART_RX = RX_PIN_NUMBER,
181183

182184
SPI_PSELMOSI0 = P1_13,
183185
SPI_PSELMISO0 = P1_14,

targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/TARGET_MCU_NRF52840/config/sdk_config.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3004,7 +3004,7 @@
30043004
// <e> UART_ENABLED - nrf_drv_uart - UART/UARTE peripheral driver
30053005
//==========================================================
30063006
#ifndef UART_ENABLED
3007-
#define UART_ENABLED 0
3007+
#define UART_ENABLED 1
30083008
#endif
30093009
// <o> UART_DEFAULT_CONFIG_HWFC - Hardware Flow Control
30103010

@@ -3044,7 +3044,7 @@
30443044
// <268435456=> 1000000 baud
30453045

30463046
#ifndef UART_DEFAULT_CONFIG_BAUDRATE
3047-
#define UART_DEFAULT_CONFIG_BAUDRATE 30801920
3047+
#define UART_DEFAULT_CONFIG_BAUDRATE 2576384
30483048
#endif
30493049

30503050
// <o> UART_DEFAULT_CONFIG_IRQ_PRIORITY - Interrupt priority
@@ -3095,7 +3095,7 @@
30953095
// <e> UART1_ENABLED - Enable UART1 instance
30963096
//==========================================================
30973097
#ifndef UART1_ENABLED
3098-
#define UART1_ENABLED 0
3098+
#define UART1_ENABLED 1
30993099
#endif
31003100
// <q> UART1_CONFIG_USE_EASY_DMA - Default setting for using EasyDMA
31013101

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "nordic",
3+
"config": {
4+
"uart-hwfc": {
5+
"help": "Enable hardware flow control for STDIO.",
6+
"value": 1
7+
},
8+
"lf-clock-src": {
9+
"help": "Select Low Frequency clock source.",
10+
"value": "NRF_LF_SRC_XTAL"
11+
},
12+
"uart-timeout-us": {
13+
"help": "Idle time in micro seconds between characters before buffer is flushed.",
14+
"value": 2000
15+
},
16+
"uart-0-fifo-size": {
17+
"help": "UART0 FIFO buffer. FIFO buffer is filled from DMA buffer.",
18+
"value": 32
19+
},
20+
"uart-1-fifo-size": {
21+
"help": "UART1 FIFO buffer. FIFO buffer is filled from DMA buffer.",
22+
"value": 32
23+
},
24+
"uart-dma-size": {
25+
"help": "UART DMA buffer. 2 buffers per instance. DMA buffer is filled by UARTE",
26+
"value": 8
27+
}
28+
}
29+
}

targets/TARGET_NORDIC/TARGET_NRF5x/objects.h

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,32 @@
5252
extern "C" {
5353
#endif
5454

55+
#include "nrf_uart.h"
56+
5557
struct serial_s {
56-
uint32_t placeholder; // struct is unused by nRF5x API implementation
57-
}; // but it must be not empty (required by strict compiler - IAR)
58+
int instance;
59+
uint32_t tx;
60+
uint32_t rx;
61+
uint32_t cts;
62+
uint32_t rts;
63+
nrf_uart_hwfc_t hwfc;
64+
nrf_uart_parity_t parity;
65+
nrf_uart_baudrate_t baudrate;
66+
uint32_t context;
67+
uint32_t handler;
68+
uint32_t mask;
69+
uint32_t event;
70+
bool update;
71+
#if DEVICE_SERIAL_ASYNCH
72+
bool rx_asynch;
73+
uint32_t tx_handler;
74+
uint32_t tx_mask;
75+
uint32_t tx_event;
76+
uint32_t rx_handler;
77+
uint32_t rx_mask;
78+
uint32_t rx_event;
79+
#endif
80+
};
5881

5982
struct spi_s {
6083
int instance;

0 commit comments

Comments
 (0)