APM:Libraries
usart.c
Go to the documentation of this file.
1 /*
2 (c) 2017 night_ghost@ykoctpa.ru
3 
4 based on: LeafLabs
5 
6 
7 */
8 
9 #pragma GCC optimize ("O2")
10 
11 #include <usart.h>
12 #include <hal.h>
13 #include <systick.h>
14 /*
15  * Devices
16  */
17 
18 static ring_buffer usart1_txrb IN_CCM;
19 static ring_buffer usart1_rxrb IN_CCM;
20 static usart_state u1state IN_CCM;
21 
22 static const usart_dev usart1 = {
23  .USARTx = USART1,
24  .clk = RCC_APB2Periph_USART1,
25  .txrb = &usart1_txrb,
26  .rxrb = &usart1_rxrb,
27  .state = &u1state,
28  .irq = USART1_IRQn,
29  .rx_pin = BOARD_USART1_RX_PIN,
30  .tx_pin = BOARD_USART1_TX_PIN,
31  .gpio_af = GPIO_AF_USART1
32 };
34 const usart_dev * const _USART1 = &usart1;
35 
36 #if defined(BOARD_USART2_RX_PIN) && defined(BOARD_USART2_RX_PIN)
37 static ring_buffer usart2_txrb IN_CCM;
38 static ring_buffer usart2_rxrb IN_CCM;
39 static usart_state u2state IN_CCM;
40 
41 static const usart_dev usart2 = {
42  .USARTx = USART2,
43  .clk = RCC_APB1Periph_USART2,
44  .txrb = &usart2_txrb,
45  .rxrb = &usart2_rxrb,
46  .state = &u2state,
47  .irq = USART2_IRQn,
48  .rx_pin = BOARD_USART2_RX_PIN,
49  .tx_pin = BOARD_USART2_TX_PIN,
50  .gpio_af = GPIO_AF_USART2
51 };
53 const usart_dev * const _USART2 = &usart2;
54 #else
55 #define _USART2 NULL
56 #endif
57 
58 static ring_buffer usart3_txrb IN_CCM;
59 static ring_buffer usart3_rxrb IN_CCM;
60 static usart_state u3state IN_CCM;
61 
62 static const usart_dev usart3 = {
63  .USARTx = USART3,
64  .clk = RCC_APB1Periph_USART3,
65  .txrb = &usart3_txrb,
66  .rxrb = &usart3_rxrb,
67  .state = &u3state,
68  .irq = USART3_IRQn,
69  .rx_pin = BOARD_USART3_RX_PIN,
70  .tx_pin = BOARD_USART3_TX_PIN,
71  .gpio_af = GPIO_AF_USART3
72 };
74 const usart_dev * const _USART3 = &usart3;
75 
76 #if defined(BOARD_USART4_RX_PIN) && defined(BOARD_USART4_TX_PIN)
77 static ring_buffer uart4_txrb IN_CCM;
78 static ring_buffer uart4_rxrb IN_CCM;
79 static usart_state u4state IN_CCM;
80 
81 static const usart_dev uart4 = {
82  .USARTx = UART4,
83  .clk = RCC_APB1Periph_UART4,
84  .txrb = &uart4_txrb,
85  .rxrb = &uart4_rxrb,
86  .state = &u4state,
87  .irq = UART4_IRQn,
88  .rx_pin = BOARD_USART4_RX_PIN,
89  .tx_pin = BOARD_USART4_TX_PIN,
90  .gpio_af = GPIO_AF_UART4
91 };
93 const usart_dev * const _UART4 = &uart4;
94 #endif
95 
96 #if defined(BOARD_USART5_RX_PIN) && defined(BOARD_USART5_TX_PIN)
97 static ring_buffer uart5_txrb IN_CCM;
98 static ring_buffer uart5_rxrb IN_CCM;
99 static usart_state u5state IN_CCM;
100 
101 static const usart_dev uart5 = {
102  .USARTx = UART5,
103  .clk = RCC_APB1Periph_UART5,
104  .txrb = &uart5_txrb,
105  .rxrb = &uart5_rxrb,
106  .state = &u5state,
107  .irq = UART5_IRQn,
108  .rx_pin = BOARD_USART5_RX_PIN,
109  .tx_pin = BOARD_USART5_TX_PIN,
110  .gpio_af = GPIO_AF_UART5
111 };
112 /* UART5 device */
113 const usart_dev * const _UART5 = &uart5;
114 #endif
115 
116 #if defined(BOARD_USART6_RX_PIN) && defined(BOARD_USART6_TX_PIN)
117 static ring_buffer usart6_txrb IN_CCM;
118 static ring_buffer usart6_rxrb IN_CCM;
119 static usart_state u6state IN_CCM;
120 
121 static const usart_dev usart6 = {
122  .USARTx = USART6,
123  .clk = RCC_APB2Periph_USART6,
124  .txrb = &usart6_txrb,
125  .rxrb = &usart6_rxrb,
126  .state = &u6state,
127  .irq = USART6_IRQn,
128  .rx_pin = BOARD_USART6_RX_PIN,
129  .tx_pin = BOARD_USART6_TX_PIN,
130  .gpio_af = GPIO_AF_USART6
131 };
133 const usart_dev * const _USART6 = &usart6;
134 #endif
135 
136 const usart_dev * const UARTS[] = {
137  NULL,
138  &usart1,
139 #if defined(BOARD_USART2_RX_PIN) && defined(BOARD_USART2_RX_PIN)
140  &usart2,
141 #else
142  NULL,
143 #endif
144  &usart3,
145 #if defined(BOARD_USART4_RX_PIN) && defined(BOARD_USART4_TX_PIN)
146  &uart4,
147 #else
148  NULL,
149 #endif
150 #if defined(BOARD_USART5_RX_PIN) && defined(BOARD_USART5_TX_PIN)
151  &uart5,
152 #else
153  NULL,
154 #endif
155 #if defined(BOARD_USART6_RX_PIN) && defined(BOARD_USART6_TX_PIN)
156  &usart6,
157 #else
158  NULL,
159 #endif
160 
161 };
162 
163 void usart_foreach(void (*fn)(const usart_dev*))
164 {
165  fn(_USART1);
166 #if defined(BOARD_USART2_RX_PIN) && defined(BOARD_USART2_RX_PIN)
167  fn(_USART2);
168 #endif
169  fn(_USART3);
170 #if defined(BOARD_USART4_RX_PIN) && defined(BOARD_USART4_TX_PIN)
171  fn(_UART4);
172 #endif
173 #if defined(BOARD_USART5_RX_PIN) && defined(BOARD_USART5_TX_PIN)
174  fn(_UART5);
175 #endif
176 #if defined(BOARD_USART6_RX_PIN) && defined(BOARD_USART6_TX_PIN)
177  fn(_USART6);
178 #endif
179 }
180 
181 extern uint32_t us_ticks;
182 
187 void usart_init(const usart_dev *dev) {
188  /* Check the parameters */
189  assert_param(IS_USART_ALL_PERIPH(dev->USARTx));
190 
191  // Turn on peripheral clocks
192  if (dev->USARTx == USART1 || dev->USARTx == USART6 )
193  RCC_APB2PeriphClockCmd(dev->clk, ENABLE); // we must wait some time before access to
194  else
195  RCC_APB1PeriphClockCmd(dev->clk, ENABLE);
196 
197 }
198 
199 void usart_setup(const usart_dev *dev, uint32_t baudRate, uint16_t wordLength,
200  uint16_t stopBits, uint16_t parity, uint16_t mode, uint16_t hardwareFlowControl)
201 {
202  /* Check the parameters */
203  assert_param(IS_USART_ALL_PERIPH(dev->USARTx));
204  assert_param(IS_USART_BAUDRATE(baud));
205  assert_param(IS_USART_STOPBITS(stopbits));
206  assert_param(IS_USART_PARITY(parity));
207  assert_param(IS_USART_WORD_LENGTH(wordLength));
208  assert_param(IS_USART_MODE(mode));
209  assert_param(IS_USART_HARDWARE_FLOW_CONTROL(hardwareFlowControl));
210 
211  memset(dev->state, 0, sizeof(*dev->state));
212 
213  dev->state->txbusy = 0;
214  dev->state->callback = 0;
215 
216  /* Disable USARTx */
217  usart_disable(dev);
218 
219  rb_init(dev->txrb, USART_TX_BUF_SIZE, dev->state->tx_buf);
220  rb_init(dev->rxrb, USART_RX_BUF_SIZE, dev->state->rx_buf);
221 
222  /* Enables the USART's 8x oversampling mode. */
223  USART_OverSampling8Cmd(dev->USARTx, ENABLE);
224 
225  USART_ClockInitTypeDef USART_InitClock;
226  USART_ClockStructInit(&USART_InitClock);
227  USART_ClockInit(dev->USARTx, &USART_InitClock);
228 
229  USART_InitTypeDef USART_config;
230  USART_StructInit(&USART_config);
231  USART_config.USART_BaudRate = baudRate;
232  USART_config.USART_WordLength = wordLength;
233  USART_config.USART_StopBits = stopBits;
234  USART_config.USART_Parity = parity;
235  USART_config.USART_Mode = mode;
236  USART_config.USART_HardwareFlowControl = hardwareFlowControl;
237 
238  USART_Init(dev->USARTx, &USART_config);
239 
241  dev->USARTx->CR2 &= ~(USART_MASK2_LBDIE);
242  dev->USARTx->CR3 &= ~(USART_MASK3_CTSIE | USART_MASK3_EIE);
243 
244  if(mode & USART_Mode_Rx) { /* Enable Rx request */
245  USART_ClearFlag(dev->USARTx, USART_FLAG_RXNE);
246  dev->USARTx->CR1 |= USART_MASK_RXNEIE;
247  }
248 
249  if(mode & USART_Mode_Tx) {
250  USART_ClearFlag(dev->USARTx, USART_FLAG_TC);
251  }
252 
254 }
255 
256 
257 
258 uint32_t usart_tx(const usart_dev *dev, const uint8_t *buf, uint32_t len)
259 {
260  /* Check the parameters */
261  assert_param(IS_USART_ALL_PERIPH(USARTx));
262  assert_param(IS_USART_DATA(Data));
263 
264  uint32_t tosend = len;
265  uint32_t sent = 0;
266 
267  while (tosend) {
268  if (rb_is_full(dev->txrb))
269  break;
270  rb_insert(dev->txrb, *buf++);
271  sent++;
272  tosend--;
273  }
274  if (dev->state->txbusy == 0 && sent > 0) {
275  dev->state->txbusy = 1;
276  dev->USARTx->CR1 |= USART_MASK_TXEIE;
277  }
278 
279  return sent;
280 }
281 
282 void usart_putudec(const usart_dev *dev, uint32_t val) {
283  char digits[12];
284  int i = 0;
285 
286  do {
287  digits[i++] = val % 10 + '0';
288  val /= 10;
289  } while (val > 0);
290 
291  while (--i >= 0){
292  usart_putc(dev, digits[i]);
293  }
294 }
295 
296 /*
297  * Interrupt handlers.
298  */
299 
300 
301 static inline void usart_rx_irq(const usart_dev *dev) {
302 #ifdef ISR_PERF
303  uint32_t t=stopwatch_getticks();
304 #endif
305 
306  /* Check on Receive Data register Not Empty interrupt */
307  uint16_t sr = dev->USARTx->SR;
308  if( (sr & USART_F_RXNE) && (dev->USARTx->CR1 & USART_MASK_RXNEIE) ){
309 #ifdef USART_SAFE_INSERT
310  /* If the buffer is full and the user defines USART_SAFE_INSERT, ignore new bytes. */
311  rb_safe_insert(dev->rxrb, (uint8_t) dev->USARTx->DR);
312 #else
313  /* By default, push bytes around in the ring buffer. */
314  rb_push_insert(dev->rxrb, (uint8_t)dev->USARTx->DR);
315 #endif
316 
317  if(dev->state->callback) {
318  revo_call_handler(dev->state->callback, (uint32_t)dev);
319  }
320  }
321 
322  if( sr & USART_F_ORE ){
323  (void)dev->USARTx->DR; // cleared after reading sr, dr
324  }
325 
326 #ifdef ISR_PERF
327  t = stopwatch_getticks() - t;
328  isr_time += t;
329  if(t>max_isr_time) max_isr_time=t;
330 #endif
331 
332 }
333 
334 static inline void usart_tx_irq(const usart_dev *dev) {
335 #ifdef ISR_PERF
336  uint32_t t=stopwatch_getticks();
337 #endif
338  /* Check USART Transmit Data Register Empty Interrupt */
339  uint16_t sr = dev->USARTx->SR;
340  if( (sr & USART_F_TXE) && (dev->USARTx->CR1 & USART_MASK_TXEIE) ){
341 
342  if (dev->txrb && !rb_is_empty(dev->txrb)) {
343  dev->USARTx->DR = rb_remove(dev->txrb);
344  dev->state->txbusy = 1;
345  } else {
346  /* Disable the USART Transmit Data Register Empty Interrupt */
347  dev->USARTx->CR1 &= ~USART_MASK_TXEIE;
348  dev->state->txbusy = 0;
349  // nops needed to deactivate the irq before irq handler is left
350  asm volatile("nop");
351  asm volatile("nop");
352  }
353  }
354 #ifdef ISR_PERF
355  t = stopwatch_getticks() - t;
356  isr_time += t;
357  if(t>max_isr_time) max_isr_time=t;
358 #endif
359 
360 }
361 
363 {
364  usart_rx_irq(_USART1);
365  usart_tx_irq(_USART1);
366 }
367 
368 #if defined(BOARD_USART2_RX_PIN) && defined(BOARD_USART2_RX_PIN)
369 void USART2_IRQHandler(void)
370 {
371  usart_rx_irq(_USART2);
372  usart_tx_irq(_USART2);
373 }
374 #endif
375 
377 {
378  usart_rx_irq(_USART3);
379  usart_tx_irq(_USART3);
380 }
381 
382 #if defined( BOARD_USART4_RX_PIN) && defined( BOARD_USART4_TX_PIN)
383 void UART4_IRQHandler(void)
384 {
385  usart_rx_irq(_UART4);
386  usart_tx_irq(_UART4);
387 }
388 #endif
389 
390 #if defined( BOARD_USART5_RX_PIN) && defined( BOARD_USART5_TX_PIN)
391 void UART5_IRQHandler(void)
392 {
393  usart_rx_irq(_UART5);
394  usart_tx_irq(_UART5);
395 }
396 #endif
397 
398 #if defined( BOARD_USART6_RX_PIN) && defined( BOARD_USART6_TX_PIN)
399 void USART6_IRQHandler(void)
400 {
401  usart_rx_irq(_USART6);
402  usart_tx_irq(_USART6);
403 }
404 #endif
#define BOARD_USART5_TX_PIN
Definition: board.h:54
static uint32_t stopwatch_getticks()
Definition: stopwatch.h:33
#define USART_MASK_TCEIE
Definition: usart.h:66
void usart_putudec(const usart_dev *dev, uint32_t val)
Transmit an unsigned integer to the specified serial port in decimal format.
Definition: usart.c:282
IRQn_Type irq
Definition: usart.h:37
static void rb_insert(ring_buffer *rb, uint8_t element)
Definition: ring_buffer.h:118
#define BOARD_USART3_TX_PIN
Definition: board.h:45
#define _USART2
Definition: usart.c:55
static ring_buffer usart1_txrb IN_CCM
Definition: usart.c:18
static int rb_is_empty(ring_buffer *rb)
Returns true if and only if the ring buffer is empty.
Definition: ring_buffer.h:109
#define assert_param(expr)
void usart_setup(const usart_dev *dev, uint32_t baudRate, uint16_t wordLength, uint16_t stopBits, uint16_t parity, uint16_t mode, uint16_t hardwareFlowControl)
Configure a serial port&#39;s baud rate.
Definition: usart.c:199
#define BOARD_USART1_TX_PIN
Definition: board.h:43
uint8_t tx_buf[USART_TX_BUF_SIZE]
Definition: usart.h:27
void USART3_IRQHandler(void)
Definition: usart.c:376
static uint8_t rb_remove(ring_buffer *rb)
Remove and return the first item from a ring buffer.
Definition: ring_buffer.h:128
void UART5_IRQHandler(void)
#define USART_F_TXE
Definition: usart.h:61
void USART2_IRQHandler(void)
void UART4_IRQHandler(void)
const usart_dev *const _UART4
#define USART_RX_BUF_SIZE
Definition: usart.h:12
#define USART_F_ORE
Definition: usart.h:62
const usart_dev *const UARTS[]
Definition: usart.c:136
#define UART_INT_PRIORITY
Definition: Config.h:45
#define BOARD_USART5_RX_PIN
Definition: board.h:53
ring_buffer * rxrb
Definition: usart.h:42
static const usart_dev usart3
Definition: usart.c:62
usart_state * state
Definition: usart.h:41
static int rb_is_full(ring_buffer *rb)
Returns true if and only if the ring buffer is full.
Definition: ring_buffer.h:99
#define USART_MASK_RXNEIE
Definition: usart.h:65
static AP_HAL::OwnPtr< AP_HAL::Device > dev
Definition: ICM20789.cpp:16
static uint32_t usart_putc(const usart_dev *dev, uint8_t bt)
Transmit one character on a serial port.
Definition: usart.h:240
static void rb_init(ring_buffer *rb, uint16_t size, uint8_t *buf)
Definition: ring_buffer.h:73
#define USART_MASK_PEIE
Definition: usart.h:68
#define BOARD_USART1_RX_PIN
Definition: board.h:44
static const usart_dev usart1
Definition: usart.c:22
void USART1_IRQHandler(void)
Definition: usart.c:362
void enable_nvic_irq(uint8_t irq, uint8_t prio)
Definition: nvic.c:8
#define USART_MASK_IDLEIE
Definition: usart.h:64
#define USART_TX_BUF_SIZE
Definition: usart.h:16
uint32_t usart_tx(const usart_dev *dev, const uint8_t *buf, uint32_t len)
Nonblocking USART transmit.
Definition: usart.c:258
uint8_t rx_buf[USART_RX_BUF_SIZE]
Definition: usart.h:26
static void usart_tx_irq(const usart_dev *dev)
Definition: usart.c:334
static int rb_safe_insert(ring_buffer *rb, uint8_t element)
Attempt to insert an element into a ring buffer.
Definition: ring_buffer.h:154
#define NULL
Definition: hal_types.h:59
const usart_dev *const _USART1
Definition: usart.c:34
const usart_dev *const _USART3
Definition: usart.c:74
#define USART_MASK2_LBDIE
Definition: usart.h:70
#define USART_MASK3_CTSIE
Definition: usart.h:72
USART_TypeDef * USARTx
Definition: usart.h:35
#define BOARD_USART6_TX_PIN
Definition: board.h:47
void usart_init(const usart_dev *dev)
Initialize a serial port.
Definition: usart.c:187
static void usart_disable(const usart_dev *dev)
Turn off a serial port.
Definition: usart.h:180
uint32_t us_ticks
Definition: stopwatch.c:10
void usart_foreach(void(*fn)(const usart_dev *))
Call a function on each USART.
Definition: usart.c:163
#define USART_F_RXNE
Definition: usart.h:60
const usart_dev *const _UART5
static void usart_rx_irq(const usart_dev *dev)
Definition: usart.c:301
#define BOARD_USART6_RX_PIN
Definition: board.h:48
#define BOARD_USART4_TX_PIN
Definition: board.h:51
#define BOARD_USART4_RX_PIN
Definition: board.h:50
#define USART_MASK_TXEIE
Definition: usart.h:67
Handler callback
Definition: usart.h:22
void USART6_IRQHandler(void)
ring_buffer * txrb
Definition: usart.h:43
static int rb_push_insert(ring_buffer *rb, uint8_t element)
Append an item onto the end of a non-full ring buffer.
Definition: ring_buffer.h:173
#define USART_MASK3_EIE
Definition: usart.h:73
void revo_call_handler(Handler h, uint32_t arg)
Definition: Scheduler.cpp:1420
#define BOARD_USART3_RX_PIN
Definition: board.h:46
uint8_t txbusy
Definition: usart.h:24
uint32_t clk
Definition: usart.h:36
const usart_dev *const _USART6