dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_usart.c
Go to the documentation of this file.
1 
17 /*
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 3 of the License, or
21  * (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful, but
24  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26  * for more details.
27  *
28  * You should have received a copy of the GNU General Public License along
29  * with this program; if not, see <http://www.gnu.org/licenses/>
30  */
31 
32 /*
33  * @todo This is virtually identical to the F1xx driver and should be merged.
34  */
35 
36 /* Project Includes */
37 #include "pios.h"
38 
39 #if defined(PIOS_INCLUDE_USART)
40 
41 #include <pios_usart_priv.h>
42 
43 /* Provide a COM driver */
44 static void PIOS_USART_ChangeBaud(uintptr_t usart_id, uint32_t baud);
45 static void PIOS_USART_RegisterRxCallback(uintptr_t usart_id, pios_com_callback rx_in_cb, uintptr_t context);
46 static void PIOS_USART_RegisterTxCallback(uintptr_t usart_id, pios_com_callback tx_out_cb, uintptr_t context);
47 static void PIOS_USART_TxStart(uintptr_t usart_id, uint16_t tx_bytes_avail);
48 static void PIOS_USART_RxStart(uintptr_t usart_id, uint16_t rx_bytes_avail);
49 
51  .set_baud = PIOS_USART_ChangeBaud,
52  .tx_start = PIOS_USART_TxStart,
53  .rx_start = PIOS_USART_RxStart,
54  .bind_tx_cb = PIOS_USART_RegisterTxCallback,
55  .bind_rx_cb = PIOS_USART_RegisterRxCallback,
56 };
57 
58 enum pios_usart_dev_magic {
59  PIOS_USART_DEV_MAGIC = 0x4152834A,
60 };
61 
62 struct pios_usart_dev {
63  enum pios_usart_dev_magic magic;
64  const struct pios_usart_cfg * cfg;
65 
66  pios_com_callback rx_in_cb;
67  uintptr_t rx_in_context;
68  pios_com_callback tx_out_cb;
69  uintptr_t tx_out_context;
70 
71  uint32_t error_overruns;
72 };
73 
74 static bool PIOS_USART_validate(struct pios_usart_dev * usart_dev)
75 {
76  return (usart_dev->magic == PIOS_USART_DEV_MAGIC);
77 }
78 
79 static struct pios_usart_dev * PIOS_USART_alloc(void)
80 {
81  struct pios_usart_dev * usart_dev;
82 
83  usart_dev = (struct pios_usart_dev *)PIOS_malloc(sizeof(*usart_dev));
84  if (!usart_dev) return(NULL);
85 
86  memset(usart_dev, 0, sizeof(*usart_dev));
87  usart_dev->magic = PIOS_USART_DEV_MAGIC;
88 
89  usart_dev->error_overruns = 0;
90 
91  return(usart_dev);
92 }
93 
94 /* Bind Interrupt Handlers
95  *
96  * Map all valid USART IRQs to the common interrupt handler
97  * and provide storage for a 32-bit device id IRQ to map
98  * each physical IRQ to a specific registered device instance.
99  */
100 static void PIOS_USART_generic_irq_handler(uintptr_t usart_id);
101 
102 static uintptr_t PIOS_USART_1_id;
103 void USART1_EXTI25_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_1_irq_handler")));
104 static void PIOS_USART_1_irq_handler (void)
105 {
107  PIOS_USART_generic_irq_handler (PIOS_USART_1_id);
109 }
110 
111 static uintptr_t PIOS_USART_2_id;
112 void USART2_EXTI26_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_2_irq_handler")));
113 static void PIOS_USART_2_irq_handler (void)
114 {
116  PIOS_USART_generic_irq_handler (PIOS_USART_2_id);
118 }
119 
120 static uintptr_t PIOS_USART_3_id;
121 void USART3_EXTI28_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_3_irq_handler")));
122 static void PIOS_USART_3_irq_handler (void)
123 {
125  PIOS_USART_generic_irq_handler (PIOS_USART_3_id);
127 }
128 
129 static uintptr_t PIOS_UART_4_id;
130 void UART4_EXTI34_IRQHandler(void) __attribute__ ((alias ("PIOS_UART_4_irq_handler")));
131 static void PIOS_UART_4_irq_handler (void)
132 {
134  PIOS_USART_generic_irq_handler (PIOS_UART_4_id);
136 }
137 
138 static uintptr_t PIOS_UART_5_id;
139 void UART5_EXTI35_IRQHandler(void) __attribute__ ((alias ("PIOS_UART_5_irq_handler")));
140 static void PIOS_UART_5_irq_handler (void)
141 {
143  PIOS_USART_generic_irq_handler (PIOS_UART_5_id);
145 }
146 
150 int32_t PIOS_USART_Init(uintptr_t * usart_id, const struct pios_usart_cfg * cfg, struct pios_usart_params * params)
151 {
152  PIOS_DEBUG_Assert(usart_id);
153  PIOS_DEBUG_Assert(cfg);
154 
155  struct pios_usart_dev * usart_dev;
156 
157  usart_dev = (struct pios_usart_dev *) PIOS_USART_alloc();
158  if (!usart_dev) goto out_fail;
159 
160  /* Bind the configuration to the device instance */
161  usart_dev->cfg = cfg;
162 
163  /* Map pins to USART function */
164  if (usart_dev->cfg->remap) {
165  if (usart_dev->cfg->rx.gpio != 0)
166  GPIO_PinAFConfig(usart_dev->cfg->rx.gpio,
167  usart_dev->cfg->rx.pin_source,
168  usart_dev->cfg->remap);
169  if (usart_dev->cfg->tx.gpio != 0)
170  GPIO_PinAFConfig(usart_dev->cfg->tx.gpio,
171  usart_dev->cfg->tx.pin_source,
172  usart_dev->cfg->remap);
173  }
174 
175  /* Initialize the USART Rx and Tx pins */
176  if (usart_dev->cfg->rx.gpio != 0)
177  GPIO_Init(usart_dev->cfg->rx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->rx.init);
178  if (usart_dev->cfg->tx.gpio != 0)
179  GPIO_Init(usart_dev->cfg->tx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->tx.init);
180 
181  /* Apply inversion and swap settings */
182  if (params->rx_invert == true)
183  USART_InvPinCmd(usart_dev->cfg->regs, USART_InvPin_Rx, ENABLE);
184  else
185  USART_InvPinCmd(usart_dev->cfg->regs, USART_InvPin_Rx, DISABLE);
186 
187  if (params->tx_invert == true)
188  USART_InvPinCmd(usart_dev->cfg->regs, USART_InvPin_Tx, ENABLE);
189  else
190  USART_InvPinCmd(usart_dev->cfg->regs, USART_InvPin_Tx, DISABLE);
191 
192  if (params->rxtx_swap == true)
193  USART_SWAPPinCmd(usart_dev->cfg->regs, ENABLE);
194  else
195  USART_SWAPPinCmd(usart_dev->cfg->regs, DISABLE);
196 
197  if (params->single_wire == true)
198  USART_HalfDuplexCmd(usart_dev->cfg->regs, ENABLE);
199  else
200  USART_HalfDuplexCmd(usart_dev->cfg->regs, DISABLE);
201 
202  /* Configure the USART */
203  USART_Init(usart_dev->cfg->regs, (USART_InitTypeDef *)&params->init);
204 
205  *usart_id = (uintptr_t)usart_dev;
206 
207  /* Configure USART Interrupts */
208  switch ((uint32_t)usart_dev->cfg->regs) {
209  case (uint32_t)USART1:
210  PIOS_USART_1_id = (uintptr_t)usart_dev;
211  break;
212  case (uint32_t)USART2:
213  PIOS_USART_2_id = (uintptr_t)usart_dev;
214  break;
215  case (uint32_t)USART3:
216  PIOS_USART_3_id = (uintptr_t)usart_dev;
217  break;
218  case (uint32_t)UART4:
219  PIOS_UART_4_id = (uintptr_t)usart_dev;
220  break;
221  case (uint32_t)UART5:
222  PIOS_UART_5_id = (uintptr_t)usart_dev;
223  break;
224  }
225  NVIC_Init((NVIC_InitTypeDef *)&(usart_dev->cfg->irq.init));
226  USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
227  USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE);
228 
229  // FIXME XXX Clear / reset uart here - sends NUL char else
230 
231  /* Enable USART */
232  USART_Cmd(usart_dev->cfg->regs, ENABLE);
233 
234  return(0);
235 
236 out_fail:
237  return(-1);
238 }
239 
240 static void PIOS_USART_RxStart(uintptr_t usart_id, uint16_t rx_bytes_avail)
241 {
242  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
243 
244  bool valid = PIOS_USART_validate(usart_dev);
245  PIOS_Assert(valid);
246 
247  USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
248 }
249 static void PIOS_USART_TxStart(uintptr_t usart_id, uint16_t tx_bytes_avail)
250 {
251  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
252 
253  bool valid = PIOS_USART_validate(usart_dev);
254  PIOS_Assert(valid);
255 
256  USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE);
257 }
258 
264 static void PIOS_USART_ChangeBaud(uintptr_t usart_id, uint32_t baud)
265 {
266  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
267 
268  bool valid = PIOS_USART_validate(usart_dev);
269  PIOS_Assert(valid);
270 
271  USART_InitTypeDef USART_InitStructure;
272 
273  /* Adjust the baud rate */
274  USART_InitStructure.USART_BaudRate = baud;
275 
276  /* Get current parameters */
277  USART_InitStructure.USART_WordLength = usart_dev->cfg->regs->CR1 & (uint32_t)USART_CR1_M;
278  USART_InitStructure.USART_Parity = usart_dev->cfg->regs->CR1 & ((uint32_t)USART_CR1_PCE | (uint32_t)USART_CR1_PS);
279  USART_InitStructure.USART_StopBits = usart_dev->cfg->regs->CR2 & (uint32_t)USART_CR2_STOP;
280  USART_InitStructure.USART_HardwareFlowControl = usart_dev->cfg->regs->CR3 & ((uint32_t)USART_CR3_CTSE | (uint32_t)USART_CR3_RTSE);
281  USART_InitStructure.USART_Mode = usart_dev->cfg->regs->CR1 & ((uint32_t)USART_CR1_TE | (uint32_t)USART_CR1_RE) ;
282 
283  /* Write back the new configuration (Note this disables USART) */
284  USART_Init(usart_dev->cfg->regs, &USART_InitStructure);
285 
286  /*
287  * Re enable USART.
288  */
289  USART_Cmd(usart_dev->cfg->regs, ENABLE);
290 }
291 
292 static void PIOS_USART_RegisterRxCallback(uintptr_t usart_id, pios_com_callback rx_in_cb, uintptr_t context)
293 {
294  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
295 
296  bool valid = PIOS_USART_validate(usart_dev);
297  PIOS_Assert(valid);
298 
299  /*
300  * Order is important in these assignments since ISR uses _cb
301  * field to determine if it's ok to dereference _cb and _context
302  */
303  usart_dev->rx_in_context = context;
304  usart_dev->rx_in_cb = rx_in_cb;
305 }
306 
307 static void PIOS_USART_RegisterTxCallback(uintptr_t usart_id, pios_com_callback tx_out_cb, uintptr_t context)
308 {
309  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
310 
311  bool valid = PIOS_USART_validate(usart_dev);
312  PIOS_Assert(valid);
313 
314  /*
315  * Order is important in these assignments since ISR uses _cb
316  * field to determine if it's ok to dereference _cb and _context
317  */
318  usart_dev->tx_out_context = context;
319  usart_dev->tx_out_cb = tx_out_cb;
320 }
321 
322 static void PIOS_USART_generic_irq_handler(uintptr_t usart_id)
323 {
324  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
325 
326  bool rx_need_yield = false;
327  bool tx_need_yield = false;
328 
329  bool valid = PIOS_USART_validate(usart_dev);
330  PIOS_Assert(valid);
331 
332  /* Check if RXNE flag is set */
333  if (USART_GetITStatus(usart_dev->cfg->regs, USART_IT_RXNE)) {
334  uint8_t byte = (uint8_t)USART_ReceiveData(usart_dev->cfg->regs);
335  if (usart_dev->rx_in_cb) {
336  (void) (usart_dev->rx_in_cb)(usart_dev->rx_in_context, &byte, 1, NULL, &rx_need_yield);
337  }
338  }
339  /* Check if TXE flag is set */
340  if (USART_GetITStatus(usart_dev->cfg->regs, USART_IT_TXE)) {
341  if (usart_dev->tx_out_cb) {
342  uint8_t b;
343  uint16_t bytes_to_send;
344 
345  bytes_to_send = (usart_dev->tx_out_cb)(usart_dev->tx_out_context, &b, 1, NULL, &tx_need_yield);
346 
347  if (bytes_to_send > 0) {
348  /* Send the byte we've been given */
349  USART_SendData(usart_dev->cfg->regs, b);
350  } else {
351  /* No bytes to send, disable TXE interrupt */
352  USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
353  }
354  } else {
355  /* No bytes to send, disable TXE interrupt */
356  USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
357  }
358  }
359  /* Check for overrun condition
360  * Note i really wanted to use USART_GetITStatus but it fails on getting the
361  * ORE flag although RXNE interrupt is enabled.
362  * Probably a bug in the ST library...
363  */
364  if (USART_GetFlagStatus(usart_dev->cfg->regs, USART_FLAG_ORE)) {
365  USART_ClearITPendingBit(usart_dev->cfg->regs, USART_IT_ORE);
366  ++usart_dev->error_overruns;
367  }
368 }
369 
370 #endif
371 
Main PiOS header to include all the compiled in PiOS options.
#define PIOS_DEBUG_Assert(test)
Definition: pios_debug.h:51
#define PIOS_IRQ_Epilogue()
Definition: pios_irq.h:46
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
#define USART2_EXTI26_IRQHandler
USART_InitTypeDef init
USART private definitions.
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
const struct pios_com_driver pios_usart_com_driver
#define UART5_EXTI35_IRQHandler
#define USART1_EXTI25_IRQHandler
uint32_t magic
int32_t PIOS_USART_Init(uintptr_t *usart_id, const struct pios_usart_cfg *cfg, struct pios_usart_params *params)
#define USART3_EXTI28_IRQHandler
#define PIOS_IRQ_Prologue()
Definition: pios_irq.h:45
#define UART4_EXTI34_IRQHandler
#define PIOS_Assert(test)
Definition: pios_debug.h:52
uint16_t(* pios_com_callback)(uintptr_t context, uint8_t *buf, uint16_t buf_len, uint16_t *headroom, bool *task_woken)
Definition: pios_com.h:41
void(* set_baud)(uintptr_t id, uint32_t baud)
Definition: pios_com.h:44