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_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 
114 int32_t PIOS_USART_Init(uintptr_t * usart_id, const struct pios_usart_cfg * cfg, struct pios_usart_params * params)
115 {
116  PIOS_DEBUG_Assert(usart_id);
117  PIOS_DEBUG_Assert(cfg);
118 
119  struct pios_usart_dev * usart_dev;
120 
121  usart_dev = (struct pios_usart_dev *) PIOS_USART_alloc();
122  if (!usart_dev) goto out_fail;
123 
124  /* Bind the configuration to the device instance */
125  usart_dev->cfg = cfg;
126 
127  /* Map pins to USART function */
128  if (usart_dev->cfg->remap) {
129  if (usart_dev->cfg->rx.gpio != 0)
130  GPIO_PinAFConfig(usart_dev->cfg->rx.gpio,
131  usart_dev->cfg->rx.pin_source,
132  usart_dev->cfg->remap);
133  if (usart_dev->cfg->tx.gpio != 0)
134  GPIO_PinAFConfig(usart_dev->cfg->tx.gpio,
135  usart_dev->cfg->tx.pin_source,
136  usart_dev->cfg->remap);
137  }
138 
139  /* Initialize the USART Rx and Tx pins */
140  if (usart_dev->cfg->rx.gpio != 0)
141  GPIO_Init(usart_dev->cfg->rx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->rx.init);
142  if (usart_dev->cfg->tx.gpio != 0)
143  GPIO_Init(usart_dev->cfg->tx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->tx.init);
144 
145  /* Apply inversion and swap settings */
146  if (params->rx_invert == true)
147  USART_InvPinCmd(usart_dev->cfg->regs, USART_InvPin_Rx, ENABLE);
148  else
149  USART_InvPinCmd(usart_dev->cfg->regs, USART_InvPin_Rx, DISABLE);
150 
151  if (params->tx_invert == true)
152  USART_InvPinCmd(usart_dev->cfg->regs, USART_InvPin_Tx, ENABLE);
153  else
154  USART_InvPinCmd(usart_dev->cfg->regs, USART_InvPin_Tx, DISABLE);
155 
156  if (params->rxtx_swap == true)
157  USART_SWAPPinCmd(usart_dev->cfg->regs, ENABLE);
158  else
159  USART_SWAPPinCmd(usart_dev->cfg->regs, DISABLE);
160 
161  if (params->single_wire == true)
162  USART_HalfDuplexCmd(usart_dev->cfg->regs, ENABLE);
163  else
164  USART_HalfDuplexCmd(usart_dev->cfg->regs, DISABLE);
165 
166  /* Configure the USART */
167  USART_Init(usart_dev->cfg->regs, (USART_InitTypeDef *)&params->init);
168 
169  *usart_id = (uintptr_t)usart_dev;
170 
171  /* Configure USART Interrupts */
172  switch ((uint32_t)usart_dev->cfg->regs) {
173  case (uint32_t)USART1:
174  PIOS_USART_1_id = (uintptr_t)usart_dev;
175  break;
176  }
177  NVIC_Init((NVIC_InitTypeDef *)&(usart_dev->cfg->irq.init));
178  USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
179  USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE);
180 
181  // FIXME XXX Clear / reset uart here - sends NUL char else
182 
183  /* Enable USART */
184  USART_Cmd(usart_dev->cfg->regs, ENABLE);
185 
186  return(0);
187 
188 out_fail:
189  return(-1);
190 }
191 
192 static void PIOS_USART_RxStart(uintptr_t usart_id, uint16_t rx_bytes_avail)
193 {
194  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
195 
196  bool valid = PIOS_USART_validate(usart_dev);
197  PIOS_Assert(valid);
198 
199  USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
200 }
201 static void PIOS_USART_TxStart(uintptr_t usart_id, uint16_t tx_bytes_avail)
202 {
203  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
204 
205  bool valid = PIOS_USART_validate(usart_dev);
206  PIOS_Assert(valid);
207 
208  USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE);
209 }
210 
216 static void PIOS_USART_ChangeBaud(uintptr_t usart_id, uint32_t baud)
217 {
218  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
219 
220  bool valid = PIOS_USART_validate(usart_dev);
221  PIOS_Assert(valid);
222 
223  USART_InitTypeDef USART_InitStructure;
224 
225  /* Adjust the baud rate */
226  USART_InitStructure.USART_BaudRate = baud;
227 
228  /* Get current parameters */
229  USART_InitStructure.USART_WordLength = usart_dev->cfg->regs->CR1 & (uint32_t)USART_CR1_M;
230  USART_InitStructure.USART_Parity = usart_dev->cfg->regs->CR1 & ((uint32_t)USART_CR1_PCE | (uint32_t)USART_CR1_PS);
231  USART_InitStructure.USART_StopBits = usart_dev->cfg->regs->CR2 & (uint32_t)USART_CR2_STOP;
232  USART_InitStructure.USART_HardwareFlowControl = usart_dev->cfg->regs->CR3 & ((uint32_t)USART_CR3_CTSE | (uint32_t)USART_CR3_RTSE);
233  USART_InitStructure.USART_Mode = usart_dev->cfg->regs->CR1 & ((uint32_t)USART_CR1_TE | (uint32_t)USART_CR1_RE) ;
234 
235  /* Write back the new configuration (Note this disables USART) */
236  USART_Init(usart_dev->cfg->regs, &USART_InitStructure);
237 
238  /*
239  * Re enable USART.
240  */
241  USART_Cmd(usart_dev->cfg->regs, ENABLE);
242 }
243 
244 static void PIOS_USART_RegisterRxCallback(uintptr_t usart_id, pios_com_callback rx_in_cb, uintptr_t context)
245 {
246  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
247 
248  bool valid = PIOS_USART_validate(usart_dev);
249  PIOS_Assert(valid);
250 
251  /*
252  * Order is important in these assignments since ISR uses _cb
253  * field to determine if it's ok to dereference _cb and _context
254  */
255  usart_dev->rx_in_context = context;
256  usart_dev->rx_in_cb = rx_in_cb;
257 }
258 
259 static void PIOS_USART_RegisterTxCallback(uintptr_t usart_id, pios_com_callback tx_out_cb, uintptr_t context)
260 {
261  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
262 
263  bool valid = PIOS_USART_validate(usart_dev);
264  PIOS_Assert(valid);
265 
266  /*
267  * Order is important in these assignments since ISR uses _cb
268  * field to determine if it's ok to dereference _cb and _context
269  */
270  usart_dev->tx_out_context = context;
271  usart_dev->tx_out_cb = tx_out_cb;
272 }
273 
274 static void PIOS_USART_generic_irq_handler(uintptr_t usart_id)
275 {
276  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
277 
278  bool rx_need_yield = false;
279  bool tx_need_yield = false;
280 
281  bool valid = PIOS_USART_validate(usart_dev);
282  PIOS_Assert(valid);
283 
284  /* Check if RXNE flag is set */
285  if (USART_GetITStatus(usart_dev->cfg->regs, USART_IT_RXNE)) {
286  uint8_t byte = (uint8_t)USART_ReceiveData(usart_dev->cfg->regs);
287  if (usart_dev->rx_in_cb) {
288  (void) (usart_dev->rx_in_cb)(usart_dev->rx_in_context, &byte, 1, NULL, &rx_need_yield);
289  }
290  }
291  /* Check if TXE flag is set */
292  if (USART_GetITStatus(usart_dev->cfg->regs, USART_IT_TXE)) {
293  if (usart_dev->tx_out_cb) {
294  uint8_t b;
295  uint16_t bytes_to_send;
296 
297  bytes_to_send = (usart_dev->tx_out_cb)(usart_dev->tx_out_context, &b, 1, NULL, &tx_need_yield);
298 
299  if (bytes_to_send > 0) {
300  /* Send the byte we've been given */
301  USART_SendData(usart_dev->cfg->regs, b);
302  } else {
303  /* No bytes to send, disable TXE interrupt */
304  USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
305  }
306  } else {
307  /* No bytes to send, disable TXE interrupt */
308  USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
309  }
310  }
311  /* Check for overrun condition
312  * Note i really wanted to use USART_GetITStatus but it fails on getting the
313  * ORE flag although RXNE interrupt is enabled.
314  * Probably a bug in the ST library...
315  */
316  if (USART_GetFlagStatus(usart_dev->cfg->regs, USART_FLAG_ORE)) {
317  USART_ClearITPendingBit(usart_dev->cfg->regs, USART_IT_ORE);
318  ++usart_dev->error_overruns;
319  }
320 }
321 
322 #endif
323 
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
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
uint32_t magic
int32_t PIOS_USART_Init(uintptr_t *usart_id, const struct pios_usart_cfg *cfg, struct pios_usart_params *params)
#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