Revert "REVONANO - Workaround for the SBUS issue (use oversample 8 instead of 16...
[librepilot.git] / flight / pios / stm32f4xx / pios_usart.c
blobbcc26cacf7545aad0dcd2c3ee59771a0cb455a56
1 /**
2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
4 * @{
5 * @addtogroup PIOS_USART USART Functions
6 * @brief PIOS interface for USART port
7 * @{
9 * @file pios_usart.c
10 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
11 * @brief USART commands. Inits USARTs, controls USARTs & Interupt handlers. (STM32 dependent)
12 * @see The GNU Public License (GPL) Version 3
14 *****************************************************************************/
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 3 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 * for more details.
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
28 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 * @todo This is virtually identical to the F1xx driver and should be merged.
35 #include "pios.h"
37 #ifdef PIOS_INCLUDE_USART
39 #include <pios_usart_priv.h>
41 /* Provide a COM driver */
42 static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud);
43 static void PIOS_USART_SetCtrlLine(uint32_t usart_id, uint32_t mask, uint32_t state);
44 static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context);
45 static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context);
46 static void PIOS_USART_TxStart(uint32_t usart_id, uint16_t tx_bytes_avail);
47 static void PIOS_USART_RxStart(uint32_t usart_id, uint16_t rx_bytes_avail);
49 const struct pios_com_driver pios_usart_com_driver = {
50 .set_baud = PIOS_USART_ChangeBaud,
51 .set_ctrl_line = PIOS_USART_SetCtrlLine,
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,
58 enum pios_usart_dev_magic {
59 PIOS_USART_DEV_MAGIC = 0x4152834A,
62 struct pios_usart_dev {
63 enum pios_usart_dev_magic magic;
64 const struct pios_usart_cfg *cfg;
66 pios_com_callback rx_in_cb;
67 uint32_t rx_in_context;
68 pios_com_callback tx_out_cb;
69 uint32_t tx_out_context;
72 static bool PIOS_USART_validate(struct pios_usart_dev *usart_dev)
74 return usart_dev->magic == PIOS_USART_DEV_MAGIC;
77 #if defined(PIOS_INCLUDE_FREERTOS)
78 static struct pios_usart_dev *PIOS_USART_alloc(void)
80 struct pios_usart_dev *usart_dev;
82 usart_dev = (struct pios_usart_dev *)pios_malloc(sizeof(struct pios_usart_dev));
83 if (!usart_dev) {
84 return NULL;
87 memset(usart_dev, 0, sizeof(struct pios_usart_dev));
88 usart_dev->magic = PIOS_USART_DEV_MAGIC;
89 return usart_dev;
91 #else
92 static struct pios_usart_dev pios_usart_devs[PIOS_USART_MAX_DEVS];
93 static uint8_t pios_usart_num_devs;
94 static struct pios_usart_dev *PIOS_USART_alloc(void)
96 struct pios_usart_dev *usart_dev;
98 if (pios_usart_num_devs >= PIOS_USART_MAX_DEVS) {
99 return NULL;
102 usart_dev = &pios_usart_devs[pios_usart_num_devs++];
104 memset(usart_dev, 0, sizeof(struct pios_usart_dev));
105 usart_dev->magic = PIOS_USART_DEV_MAGIC;
107 return usart_dev;
109 #endif /* if defined(PIOS_INCLUDE_FREERTOS) */
111 /* Bind Interrupt Handlers
113 * Map all valid USART IRQs to the common interrupt handler
114 * and provide storage for a 32-bit device id IRQ to map
115 * each physical IRQ to a specific registered device instance.
117 static void PIOS_USART_generic_irq_handler(uint32_t usart_id);
119 static uint32_t PIOS_USART_1_id;
120 void USART1_IRQHandler(void) __attribute__((alias("PIOS_USART_1_irq_handler")));
121 static void PIOS_USART_1_irq_handler(void)
123 PIOS_USART_generic_irq_handler(PIOS_USART_1_id);
126 static uint32_t PIOS_USART_2_id;
127 void USART2_IRQHandler(void) __attribute__((alias("PIOS_USART_2_irq_handler")));
128 static void PIOS_USART_2_irq_handler(void)
130 PIOS_USART_generic_irq_handler(PIOS_USART_2_id);
133 static uint32_t PIOS_USART_3_id;
134 void USART3_IRQHandler(void) __attribute__((alias("PIOS_USART_3_irq_handler")));
135 static void PIOS_USART_3_irq_handler(void)
137 PIOS_USART_generic_irq_handler(PIOS_USART_3_id);
140 static uint32_t PIOS_USART_4_id;
141 void USART4_IRQHandler(void) __attribute__((alias("PIOS_USART_4_irq_handler")));
142 static void PIOS_USART_4_irq_handler(void)
144 PIOS_USART_generic_irq_handler(PIOS_USART_4_id);
147 static uint32_t PIOS_USART_5_id;
148 void USART5_IRQHandler(void) __attribute__((alias("PIOS_USART_5_irq_handler")));
149 static void PIOS_USART_5_irq_handler(void)
151 PIOS_USART_generic_irq_handler(PIOS_USART_5_id);
154 static uint32_t PIOS_USART_6_id;
155 void USART6_IRQHandler(void) __attribute__((alias("PIOS_USART_6_irq_handler")));
156 static void PIOS_USART_6_irq_handler(void)
158 PIOS_USART_generic_irq_handler(PIOS_USART_6_id);
162 * Initialise a single USART device
164 int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg)
166 PIOS_DEBUG_Assert(usart_id);
167 PIOS_DEBUG_Assert(cfg);
169 struct pios_usart_dev *usart_dev;
171 usart_dev = (struct pios_usart_dev *)PIOS_USART_alloc();
172 if (!usart_dev) {
173 goto out_fail;
176 /* Bind the configuration to the device instance */
177 usart_dev->cfg = cfg;
179 /* Map pins to USART function */
180 /* note __builtin_ctz() due to the difference between GPIO_PinX and GPIO_PinSourceX */
181 if (usart_dev->cfg->remap) {
182 GPIO_PinAFConfig(usart_dev->cfg->rx.gpio,
183 __builtin_ctz(usart_dev->cfg->rx.init.GPIO_Pin),
184 usart_dev->cfg->remap);
185 GPIO_PinAFConfig(usart_dev->cfg->tx.gpio,
186 __builtin_ctz(usart_dev->cfg->tx.init.GPIO_Pin),
187 usart_dev->cfg->remap);
190 /* Initialize the USART Rx and Tx pins */
191 GPIO_Init(usart_dev->cfg->rx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->rx.init);
192 GPIO_Init(usart_dev->cfg->tx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->tx.init);
194 /* If a DTR line is specified, initialize it */
195 if (usart_dev->cfg->dtr.gpio) {
196 GPIO_Init(usart_dev->cfg->dtr.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->dtr.init);
197 PIOS_USART_SetCtrlLine((uint32_t)usart_dev, COM_CTRL_LINE_DTR_MASK, 0);
200 /* Configure the USART */
201 USART_Init(usart_dev->cfg->regs, (USART_InitTypeDef *)&usart_dev->cfg->init);
203 *usart_id = (uint32_t)usart_dev;
205 /* Configure USART Interrupts */
206 switch ((uint32_t)usart_dev->cfg->regs) {
207 case (uint32_t)USART1:
208 PIOS_USART_1_id = (uint32_t)usart_dev;
209 break;
210 case (uint32_t)USART2:
211 PIOS_USART_2_id = (uint32_t)usart_dev;
212 break;
213 case (uint32_t)USART3:
214 PIOS_USART_3_id = (uint32_t)usart_dev;
215 break;
216 case (uint32_t)UART4:
217 PIOS_USART_4_id = (uint32_t)usart_dev;
218 break;
219 case (uint32_t)UART5:
220 PIOS_USART_5_id = (uint32_t)usart_dev;
221 break;
222 case (uint32_t)USART6:
223 PIOS_USART_6_id = (uint32_t)usart_dev;
224 break;
226 NVIC_Init((NVIC_InitTypeDef *)&(usart_dev->cfg->irq.init));
227 USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
228 USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE);
230 // FIXME XXX Clear / reset uart here - sends NUL char else
232 /* Enable USART */
233 USART_Cmd(usart_dev->cfg->regs, ENABLE);
235 return 0;
237 out_fail:
238 return -1;
241 static void PIOS_USART_RxStart(uint32_t usart_id, __attribute__((unused)) uint16_t rx_bytes_avail)
243 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
245 bool valid = PIOS_USART_validate(usart_dev);
247 PIOS_Assert(valid);
249 USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
251 static void PIOS_USART_TxStart(uint32_t usart_id, __attribute__((unused)) uint16_t tx_bytes_avail)
253 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
255 bool valid = PIOS_USART_validate(usart_dev);
257 PIOS_Assert(valid);
259 USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE);
263 * Changes the baud rate of the USART peripheral without re-initialising.
264 * \param[in] usart_id USART name (GPS, TELEM, AUX)
265 * \param[in] baud Requested baud rate
267 static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud)
269 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
271 bool valid = PIOS_USART_validate(usart_dev);
273 PIOS_Assert(valid);
275 USART_InitTypeDef USART_InitStructure;
277 /* Start with a copy of the default configuration for the peripheral */
278 USART_InitStructure = usart_dev->cfg->init;
280 /* Adjust the baud rate */
281 USART_InitStructure.USART_BaudRate = baud;
283 /* Write back the new configuration */
284 USART_Init(usart_dev->cfg->regs, &USART_InitStructure);
287 static void PIOS_USART_SetCtrlLine(uint32_t usart_id, uint32_t mask, uint32_t state)
289 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
291 bool valid = PIOS_USART_validate(usart_dev);
293 PIOS_Assert(valid);
295 /* Only attempt to drive DTR if this USART has a GPIO line defined */
296 if (usart_dev->cfg->dtr.gpio && (mask & COM_CTRL_LINE_DTR_MASK)) {
297 GPIO_WriteBit(usart_dev->cfg->dtr.gpio,
298 usart_dev->cfg->dtr.init.GPIO_Pin,
299 state & COM_CTRL_LINE_DTR_MASK ? Bit_RESET : Bit_SET);
303 static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context)
305 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
307 bool valid = PIOS_USART_validate(usart_dev);
309 PIOS_Assert(valid);
312 * Order is important in these assignments since ISR uses _cb
313 * field to determine if it's ok to dereference _cb and _context
315 usart_dev->rx_in_context = context;
316 usart_dev->rx_in_cb = rx_in_cb;
319 static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context)
321 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
323 bool valid = PIOS_USART_validate(usart_dev);
325 PIOS_Assert(valid);
328 * Order is important in these assignments since ISR uses _cb
329 * field to determine if it's ok to dereference _cb and _context
331 usart_dev->tx_out_context = context;
332 usart_dev->tx_out_cb = tx_out_cb;
335 static void PIOS_USART_generic_irq_handler(uint32_t usart_id)
337 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
339 bool valid = PIOS_USART_validate(usart_dev);
341 PIOS_Assert(valid);
343 /* Force read of dr after sr to make sure to clear error flags */
344 volatile uint16_t sr = usart_dev->cfg->regs->SR;
345 volatile uint8_t dr = usart_dev->cfg->regs->DR;
347 /* Check if RXNE flag is set */
348 bool rx_need_yield = false;
349 if (sr & USART_SR_RXNE) {
350 uint8_t byte = dr;
351 if (usart_dev->rx_in_cb) {
352 (void)(usart_dev->rx_in_cb)(usart_dev->rx_in_context, &byte, 1, NULL, &rx_need_yield);
356 /* Check if TXE flag is set */
357 bool tx_need_yield = false;
358 if (sr & USART_SR_TXE) {
359 if (usart_dev->tx_out_cb) {
360 uint8_t b;
361 uint16_t bytes_to_send;
363 bytes_to_send = (usart_dev->tx_out_cb)(usart_dev->tx_out_context, &b, 1, NULL, &tx_need_yield);
365 if (bytes_to_send > 0) {
366 /* Send the byte we've been given */
367 usart_dev->cfg->regs->DR = b;
368 } else {
369 /* No bytes to send, disable TXE interrupt */
370 USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
372 } else {
373 /* No bytes to send, disable TXE interrupt */
374 USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
378 #if defined(PIOS_INCLUDE_FREERTOS)
379 if (rx_need_yield || tx_need_yield) {
380 vPortYield();
382 #endif /* PIOS_INCLUDE_FREERTOS */
385 #endif /* PIOS_INCLUDE_USART */
388 * @}
389 * @}