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 /* Project Includes */
32 #include "pios.h"
33 
34 #if defined(PIOS_INCLUDE_USART)
35 
36 #include <pios_usart_priv.h>
37 
38 /* Provide a COM driver */
39 static void PIOS_USART_ChangeBaud(uintptr_t usart_id, uint32_t baud);
40 static void PIOS_USART_RegisterRxCallback(uintptr_t usart_id, pios_com_callback rx_in_cb, uintptr_t context);
41 static void PIOS_USART_RegisterTxCallback(uintptr_t usart_id, pios_com_callback tx_out_cb, uintptr_t context);
42 static void PIOS_USART_TxStart(uintptr_t usart_id, uint16_t tx_bytes_avail);
43 static void PIOS_USART_RxStart(uintptr_t usart_id, uint16_t rx_bytes_avail);
44 
46  .set_baud = PIOS_USART_ChangeBaud,
47  .tx_start = PIOS_USART_TxStart,
48  .rx_start = PIOS_USART_RxStart,
49  .bind_tx_cb = PIOS_USART_RegisterTxCallback,
50  .bind_rx_cb = PIOS_USART_RegisterRxCallback,
51 };
52 
53 enum pios_usart_dev_magic {
54  PIOS_USART_DEV_MAGIC = 0x11223344,
55 };
56 
57 struct pios_usart_dev {
58  enum pios_usart_dev_magic magic;
59  const struct pios_usart_cfg * cfg;
60 
61  pios_com_callback rx_in_cb;
62  uintptr_t rx_in_context;
63  pios_com_callback tx_out_cb;
64  uintptr_t tx_out_context;
65 
66  uint32_t rx_dropped;
67 };
68 
69 static bool PIOS_USART_validate(struct pios_usart_dev * usart_dev)
70 {
71  return (usart_dev->magic == PIOS_USART_DEV_MAGIC);
72 }
73 
74 static struct pios_usart_dev * PIOS_USART_alloc(void)
75 {
76  struct pios_usart_dev * usart_dev;
77 
78  usart_dev = (struct pios_usart_dev *)PIOS_malloc(sizeof(*usart_dev));
79  if (!usart_dev) return(NULL);
80 
81  memset(usart_dev, 0, sizeof(*usart_dev));
82  usart_dev->magic = PIOS_USART_DEV_MAGIC;
83  return(usart_dev);
84 }
85 
86 /* Bind Interrupt Handlers
87  *
88  * Map all valid USART IRQs to the common interrupt handler
89  * and provide storage for a 32-bit device id IRQ to map
90  * each physical IRQ to a specific registered device instance.
91  */
92 static void PIOS_USART_generic_irq_handler(uintptr_t usart_id);
93 
94 static uintptr_t PIOS_USART_1_id;
95 void USART1_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_1_irq_handler")));
96 static void PIOS_USART_1_irq_handler (void)
97 {
98  PIOS_USART_generic_irq_handler (PIOS_USART_1_id);
99 }
100 
101 static uintptr_t PIOS_USART_2_id;
102 void USART2_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_2_irq_handler")));
103 static void PIOS_USART_2_irq_handler (void)
104 {
105  PIOS_USART_generic_irq_handler (PIOS_USART_2_id);
106 }
107 
108 static uintptr_t PIOS_USART_3_id;
109 void USART3_IRQHandler(void) __attribute__ ((alias ("PIOS_USART_3_irq_handler")));
110 static void PIOS_USART_3_irq_handler (void)
111 {
112  PIOS_USART_generic_irq_handler (PIOS_USART_3_id);
113 }
114 
118 int32_t PIOS_USART_Init(uintptr_t * usart_id, const struct pios_usart_cfg * cfg, struct pios_usart_params * params)
119 {
120  PIOS_DEBUG_Assert(usart_id);
121  PIOS_DEBUG_Assert(cfg);
122 
123  struct pios_usart_dev * usart_dev;
124 
125  usart_dev = (struct pios_usart_dev *) PIOS_USART_alloc();
126  if (!usart_dev) goto out_fail;
127 
128  /* Bind the configuration to the device instance */
129  usart_dev->cfg = cfg;
130 
131  /* Enable the USART Pins Software Remapping */
132  if (usart_dev->cfg->remap) {
133  GPIO_PinRemapConfig(usart_dev->cfg->remap, ENABLE);
134  }
135 
136  /* Initialize the USART Rx and Tx pins */
137  GPIO_Init(usart_dev->cfg->rx.gpio, (GPIO_InitTypeDef*)&usart_dev->cfg->rx.init);
138  GPIO_Init(usart_dev->cfg->tx.gpio, (GPIO_InitTypeDef*)&usart_dev->cfg->tx.init);
139 
140  /* Enable USART clock */
141  switch ((uint32_t)usart_dev->cfg->regs) {
142  case (uint32_t)USART1:
143  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
144  break;
145  case (uint32_t)USART2:
146  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
147  break;
148  case (uint32_t)USART3:
149  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
150  break;
151  }
152 
153  /* Configure the USART */
154  USART_Init(usart_dev->cfg->regs, (USART_InitTypeDef*)&params->init);
155 
156  *usart_id = (uintptr_t)usart_dev;
157 
158  /* Configure USART Interrupts */
159  switch ((uint32_t)usart_dev->cfg->regs) {
160  case (uint32_t)USART1:
161  PIOS_USART_1_id = (uintptr_t)usart_dev;
162  break;
163  case (uint32_t)USART2:
164  PIOS_USART_2_id = (uintptr_t)usart_dev;
165  break;
166  case (uint32_t)USART3:
167  PIOS_USART_3_id = (uintptr_t)usart_dev;
168  break;
169  }
170  NVIC_Init((NVIC_InitTypeDef*)&usart_dev->cfg->irq.init);
171  USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
172  USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE);
173 
174  /* Enable USART */
175  USART_Cmd(usart_dev->cfg->regs, ENABLE);
176 
177  return(0);
178 
179 out_fail:
180  return(-1);
181 }
182 
183 static void PIOS_USART_RxStart(uintptr_t usart_id, uint16_t rx_bytes_avail)
184 {
185  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
186 
187  bool valid = PIOS_USART_validate(usart_dev);
188  PIOS_Assert(valid);
189 
190  USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
191 }
192 static void PIOS_USART_TxStart(uintptr_t usart_id, uint16_t tx_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_TXE, ENABLE);
200 }
201 
207 static void PIOS_USART_ChangeBaud(uintptr_t usart_id, uint32_t baud)
208 {
209  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
210 
211  bool valid = PIOS_USART_validate(usart_dev);
212  PIOS_Assert(valid);
213 
214  USART_InitTypeDef USART_InitStructure;
215 
216  /* Adjust the baud rate */
217  USART_InitStructure.USART_BaudRate = baud;
218 
219  /* Get current parameters */
220  USART_InitStructure.USART_WordLength = usart_dev->cfg->regs->CR1 & (uint32_t)USART_CR1_M;
221  USART_InitStructure.USART_Parity = usart_dev->cfg->regs->CR1 & ((uint32_t)USART_CR1_PCE | (uint32_t)USART_CR1_PS);
222  USART_InitStructure.USART_StopBits = usart_dev->cfg->regs->CR2 & (uint32_t)USART_CR2_STOP;
223  USART_InitStructure.USART_HardwareFlowControl = usart_dev->cfg->regs->CR3 & ((uint32_t)USART_CR3_CTSE | (uint32_t)USART_CR3_RTSE);
224  USART_InitStructure.USART_Mode = usart_dev->cfg->regs->CR1 & ((uint32_t)USART_CR1_TE | (uint32_t)USART_CR1_RE) ;
225 
226  /* Write back the new configuration */
227  USART_Init(usart_dev->cfg->regs, &USART_InitStructure);
228 }
229 
230 static void PIOS_USART_RegisterRxCallback(uintptr_t usart_id, pios_com_callback rx_in_cb, uintptr_t context)
231 {
232  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
233 
234  bool valid = PIOS_USART_validate(usart_dev);
235  PIOS_Assert(valid);
236 
237  /*
238  * Order is important in these assignments since ISR uses _cb
239  * field to determine if it's ok to dereference _cb and _context
240  */
241  usart_dev->rx_in_context = context;
242  usart_dev->rx_in_cb = rx_in_cb;
243 }
244 
245 static void PIOS_USART_RegisterTxCallback(uintptr_t usart_id, pios_com_callback tx_out_cb, uintptr_t context)
246 {
247  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
248 
249  bool valid = PIOS_USART_validate(usart_dev);
250  PIOS_Assert(valid);
251 
252  /*
253  * Order is important in these assignments since ISR uses _cb
254  * field to determine if it's ok to dereference _cb and _context
255  */
256  usart_dev->tx_out_context = context;
257  usart_dev->tx_out_cb = tx_out_cb;
258 }
259 
260 static void PIOS_USART_generic_irq_handler(uintptr_t usart_id)
261 {
263  struct pios_usart_dev * usart_dev = (struct pios_usart_dev *)usart_id;
264 
265  bool valid = PIOS_USART_validate(usart_dev);
266  PIOS_Assert(valid);
267 
268  /* Force read of dr after sr to make sure to clear error flags */
269  volatile uint16_t sr = usart_dev->cfg->regs->SR;
270  volatile uint8_t dr = usart_dev->cfg->regs->DR;
271 
272  /* Check if RXNE flag is set */
273  bool rx_need_yield = false;
274  if (sr & USART_SR_RXNE) {
275  uint8_t byte = dr;
276  if (usart_dev->rx_in_cb) {
277  uint16_t rc;
278  rc = (usart_dev->rx_in_cb)(usart_dev->rx_in_context, &byte, 1, NULL, &rx_need_yield);
279  if (rc < 1) {
280  /* Lost bytes on rx */
281  usart_dev->rx_dropped += 1;
282  }
283  }
284  }
285 
286  /* Check if TXE flag is set */
287  bool tx_need_yield = false;
288  if (sr & USART_SR_TXE) {
289  if (usart_dev->tx_out_cb) {
290  uint8_t b;
291  uint16_t bytes_to_send;
292 
293  bytes_to_send = (usart_dev->tx_out_cb)(usart_dev->tx_out_context, &b, 1, NULL, &tx_need_yield);
294 
295  if (bytes_to_send > 0) {
296  /* Send the byte we've been given */
297  usart_dev->cfg->regs->DR = b;
298  } else {
299  /* No bytes to send, disable TXE interrupt */
300  USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
301  }
302  } else {
303  /* No bytes to send, disable TXE interrupt */
304  USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
305  }
306  }
308 }
309 
310 #endif
311 
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
#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 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