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 
16 /*
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25  * for more details.
26  *
27  * You should have received a copy of the GNU General Public License along
28  * with this program; if not, see <http://www.gnu.org/licenses/>
29  */
30 
31 /*
32  * @todo This is virtually identical to the F1xx driver and should be merged.
33  */
34 
35 /* Project Includes */
36 #include "pios.h"
37 
38 #if defined(PIOS_INCLUDE_USART)
39 
40 #include <pios_usart_priv.h>
41 
42 /* Provide a COM driver */
43 static void PIOS_USART_ChangeBaud(uintptr_t usart_id, uint32_t baud);
44 static void PIOS_USART_RegisterRxCallback(uintptr_t usart_id, pios_com_callback rx_in_cb, uintptr_t context);
45 static void PIOS_USART_RegisterTxCallback(uintptr_t usart_id, pios_com_callback tx_out_cb, uintptr_t context);
46 static void PIOS_USART_TxStart(uintptr_t usart_id, uint16_t tx_bytes_avail);
47 static void PIOS_USART_RxStart(uintptr_t usart_id, uint16_t rx_bytes_avail);
48 
50  .set_baud = PIOS_USART_ChangeBaud,
51  .tx_start = PIOS_USART_TxStart,
52  .rx_start = PIOS_USART_RxStart,
53  .bind_tx_cb = PIOS_USART_RegisterTxCallback,
54  .bind_rx_cb = PIOS_USART_RegisterRxCallback,
55 };
56 
57 enum pios_usart_dev_magic {
58  PIOS_USART_DEV_MAGIC = 0x4152834A,
59 };
60 
61 struct pios_usart_dev {
62  enum pios_usart_dev_magic magic;
63  const struct pios_usart_cfg * cfg;
64 
65  pios_com_callback rx_in_cb;
66  uintptr_t rx_in_context;
67  pios_com_callback tx_out_cb;
68  uintptr_t tx_out_context;
69 };
70 
71 static bool PIOS_USART_validate(struct pios_usart_dev * usart_dev)
72 {
73  return (usart_dev->magic == PIOS_USART_DEV_MAGIC);
74 }
75 
76 static struct pios_usart_dev * PIOS_USART_alloc(void)
77 {
78  struct pios_usart_dev * usart_dev;
79 
80  usart_dev = (struct pios_usart_dev *)PIOS_malloc(sizeof(*usart_dev));
81  if (!usart_dev) return(NULL);
82 
83  memset(usart_dev, 0, sizeof(*usart_dev));
84  usart_dev->magic = PIOS_USART_DEV_MAGIC;
85  return(usart_dev);
86 }
87 
88 /* Bind Interrupt Handlers
89  *
90  * Map all valid USART IRQs to the common interrupt handler
91  * and provide storage for a 32-bit device id IRQ to map
92  * each physical IRQ to a specific registered device instance.
93  */
94 static void PIOS_USART_generic_irq_handler(uintptr_t usart_id);
95 
96 static uintptr_t PIOS_USART_1_id;
97 void USART1_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_1_irq_handler")));
98 static void PIOS_USART_1_irq_handler (void)
99 {
101  PIOS_USART_generic_irq_handler (PIOS_USART_1_id);
103 }
104 
105 static uintptr_t PIOS_USART_2_id;
106 void USART2_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_2_irq_handler")));
107 static void PIOS_USART_2_irq_handler (void)
108 {
110  PIOS_USART_generic_irq_handler (PIOS_USART_2_id);
112 }
113 
114 static uintptr_t PIOS_USART_3_id;
115 void USART3_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_3_irq_handler")));
116 static void PIOS_USART_3_irq_handler (void)
117 {
119  PIOS_USART_generic_irq_handler (PIOS_USART_3_id);
121 }
122 
123 static uintptr_t PIOS_USART_4_id;
124 void USART4_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_4_irq_handler")));
125 static void PIOS_USART_4_irq_handler (void)
126 {
128  PIOS_USART_generic_irq_handler (PIOS_USART_4_id);
130 }
131 
132 static uintptr_t PIOS_USART_5_id;
133 void USART5_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_5_irq_handler")));
134 static void PIOS_USART_5_irq_handler (void)
135 {
137  PIOS_USART_generic_irq_handler (PIOS_USART_5_id);
139 }
140 
141 static uintptr_t PIOS_USART_6_id;
142 void USART6_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_6_irq_handler")));
143 static void PIOS_USART_6_irq_handler (void)
144 {
146  PIOS_USART_generic_irq_handler (PIOS_USART_6_id);
148 }
149 
153 int32_t PIOS_USART_Init(uintptr_t * usart_id, const struct pios_usart_cfg * cfg, struct pios_usart_params * params)
154 {
155  PIOS_DEBUG_Assert(usart_id);
156  PIOS_DEBUG_Assert(cfg);
157 
158  struct pios_usart_dev * usart_dev;
159 
160  usart_dev = (struct pios_usart_dev *) PIOS_USART_alloc();
161  if (!usart_dev) goto out_fail;
162 
163  /* Bind the configuration to the device instance */
164  usart_dev->cfg = cfg;
165 
166  /* Map pins to USART function */
167  /* note __builtin_ctz() due to the difference between GPIO_PinX and GPIO_PinSourceX */
168  if (usart_dev->cfg->remap) {
169  if (usart_dev->cfg->rx.gpio != 0)
170  GPIO_PinAFConfig(usart_dev->cfg->rx.gpio,
171  __builtin_ctz(usart_dev->cfg->rx.init.GPIO_Pin),
172  usart_dev->cfg->remap);
173  if (usart_dev->cfg->tx.gpio != 0)
174  GPIO_PinAFConfig(usart_dev->cfg->tx.gpio,
175  __builtin_ctz(usart_dev->cfg->tx.init.GPIO_Pin),
176  usart_dev->cfg->remap);
177  }
178 
179  /* Initialize the USART Rx and Tx pins */
180  if (usart_dev->cfg->rx.gpio != 0)
181  GPIO_Init(usart_dev->cfg->rx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->rx.init);
182  if (usart_dev->cfg->tx.gpio != 0)
183  GPIO_Init(usart_dev->cfg->tx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->tx.init);
184 
185  /* Enable single wire mode if requested */
186  if (params->single_wire == true)
187  USART_HalfDuplexCmd(usart_dev->cfg->regs, ENABLE);
188  else
189  USART_HalfDuplexCmd(usart_dev->cfg->regs, DISABLE);
190 
191  /* Configure the USART */
192  USART_Init(usart_dev->cfg->regs, (USART_InitTypeDef *)&params->init);
193 
194  *usart_id = (uintptr_t)usart_dev;
195 
196  /* Configure USART Interrupts */
197  switch ((uint32_t)usart_dev->cfg->regs) {
198  case (uint32_t)USART1:
199  PIOS_USART_1_id = (uintptr_t)usart_dev;
200  break;
201  case (uint32_t)USART2:
202  PIOS_USART_2_id = (uintptr_t)usart_dev;
203  break;
204  case (uint32_t)USART3:
205  PIOS_USART_3_id = (uintptr_t)usart_dev;
206  break;
207  case (uint32_t)UART4:
208  PIOS_USART_4_id = (uintptr_t)usart_dev;
209  break;
210  case (uint32_t)UART5:
211  PIOS_USART_5_id = (uintptr_t)usart_dev;
212  break;
213  case (uint32_t)USART6:
214  PIOS_USART_6_id = (uintptr_t)usart_dev;
215  break;
216  }
217  NVIC_Init((NVIC_InitTypeDef *)&(usart_dev->cfg->irq.init));
218  USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
219  USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE);
220 
221  // FIXME XXX Clear / reset uart here - sends NUL char else
222 
223  /* Enable USART */
224  USART_Cmd(usart_dev->cfg->regs, ENABLE);
225 
226  return(0);
227 
228 out_fail:
229  return(-1);
230 }
231 
232 static void PIOS_USART_RxStart(uintptr_t usart_id, uint16_t rx_bytes_avail)
233 {
234  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
235 
236  bool valid = PIOS_USART_validate(usart_dev);
237  PIOS_Assert(valid);
238 
239  USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
240 }
241 static void PIOS_USART_TxStart(uintptr_t usart_id, uint16_t tx_bytes_avail)
242 {
243  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
244 
245  bool valid = PIOS_USART_validate(usart_dev);
246  PIOS_Assert(valid);
247 
248  USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE);
249 }
250 
256 static void PIOS_USART_ChangeBaud(uintptr_t usart_id, uint32_t baud)
257 {
258  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
259 
260  bool valid = PIOS_USART_validate(usart_dev);
261  PIOS_Assert(valid);
262 
263  USART_InitTypeDef USART_InitStructure;
264 
265  /* Adjust the baud rate */
266  USART_InitStructure.USART_BaudRate = baud;
267 
268  /* Get current parameters */
269  USART_InitStructure.USART_WordLength = usart_dev->cfg->regs->CR1 & (uint32_t)USART_CR1_M;
270  USART_InitStructure.USART_Parity = usart_dev->cfg->regs->CR1 & ((uint32_t)USART_CR1_PCE | (uint32_t)USART_CR1_PS);
271  USART_InitStructure.USART_StopBits = usart_dev->cfg->regs->CR2 & (uint32_t)USART_CR2_STOP;
272  USART_InitStructure.USART_HardwareFlowControl = usart_dev->cfg->regs->CR3 & ((uint32_t)USART_CR3_CTSE | (uint32_t)USART_CR3_RTSE);
273  USART_InitStructure.USART_Mode = usart_dev->cfg->regs->CR1 & ((uint32_t)USART_CR1_TE | (uint32_t)USART_CR1_RE) ;
274 
275  /* Write back the new configuration */
276  USART_Init(usart_dev->cfg->regs, &USART_InitStructure);
277 }
278 
279 static void PIOS_USART_RegisterRxCallback(uintptr_t usart_id, pios_com_callback rx_in_cb, uintptr_t context)
280 {
281  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
282 
283  bool valid = PIOS_USART_validate(usart_dev);
284  PIOS_Assert(valid);
285 
286  /*
287  * Order is important in these assignments since ISR uses _cb
288  * field to determine if it's ok to dereference _cb and _context
289  */
290  usart_dev->rx_in_context = context;
291  usart_dev->rx_in_cb = rx_in_cb;
292 }
293 
294 static void PIOS_USART_RegisterTxCallback(uintptr_t usart_id, pios_com_callback tx_out_cb, uintptr_t context)
295 {
296  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
297 
298  bool valid = PIOS_USART_validate(usart_dev);
299  PIOS_Assert(valid);
300 
301  /*
302  * Order is important in these assignments since ISR uses _cb
303  * field to determine if it's ok to dereference _cb and _context
304  */
305  usart_dev->tx_out_context = context;
306  usart_dev->tx_out_cb = tx_out_cb;
307 }
308 
309 static void PIOS_USART_generic_irq_handler(uintptr_t usart_id)
310 {
311  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
312 
313  bool valid = PIOS_USART_validate(usart_dev);
314  PIOS_Assert(valid);
315 
316  /* Force read of dr after sr to make sure to clear error flags */
317  volatile uint16_t sr = usart_dev->cfg->regs->SR;
318  volatile uint8_t dr = usart_dev->cfg->regs->DR;
319 
320  /* Check if RXNE flag is set */
321  bool rx_need_yield = false;
322  if (sr & USART_SR_RXNE) {
323  uint8_t byte = dr;
324  if (usart_dev->rx_in_cb) {
325  (void) (usart_dev->rx_in_cb)(usart_dev->rx_in_context, &byte, 1, NULL, &rx_need_yield);
326  }
327  }
328 
329  /* Check if TXE flag is set */
330  bool tx_need_yield = false;
331  if (sr & USART_SR_TXE) {
332  if (usart_dev->tx_out_cb) {
333  uint8_t b;
334  uint16_t bytes_to_send;
335 
336  bytes_to_send = (usart_dev->tx_out_cb)(usart_dev->tx_out_context, &b, 1, NULL, &tx_need_yield);
337 
338  if (bytes_to_send > 0) {
339  /* Send the byte we've been given */
340  usart_dev->cfg->regs->DR = b;
341  } else {
342  /* No bytes to send, disable TXE interrupt */
343  USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
344  }
345  } else {
346  /* No bytes to send, disable TXE interrupt */
347  USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
348  }
349  }
350 }
351 
352 #endif
353 
Main PiOS header to include all the compiled in PiOS options.
void USART1_IRQHandler(void)
#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 USART6_IRQHandler
#define USART5_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 USART2_IRQHandler
#define USART3_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 USART4_IRQHandler
#define PIOS_IRQ_Prologue()
Definition: pios_irq.h:45
#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