fix WhatsNew for release
[librepilot.git] / flight / pios / stm32f10x / pios_usart.c
blobff3286cfa090a977b4d5e09255fd93602af7d9c1
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) 2010.
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
31 #include "pios.h"
33 #ifdef PIOS_INCLUDE_USART
35 #include <pios_usart_priv.h>
37 /* Provide a COM driver */
38 static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud);
39 static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context);
40 static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context);
41 static void PIOS_USART_TxStart(uint32_t usart_id, uint16_t tx_bytes_avail);
42 static void PIOS_USART_RxStart(uint32_t usart_id, uint16_t rx_bytes_avail);
44 const struct pios_com_driver pios_usart_com_driver = {
45 .set_baud = PIOS_USART_ChangeBaud,
46 .tx_start = PIOS_USART_TxStart,
47 .rx_start = PIOS_USART_RxStart,
48 .bind_tx_cb = PIOS_USART_RegisterTxCallback,
49 .bind_rx_cb = PIOS_USART_RegisterRxCallback,
52 enum pios_usart_dev_magic {
53 PIOS_USART_DEV_MAGIC = 0x11223344,
56 struct pios_usart_dev {
57 enum pios_usart_dev_magic magic;
58 const struct pios_usart_cfg *cfg;
60 pios_com_callback rx_in_cb;
61 uint32_t rx_in_context;
62 pios_com_callback tx_out_cb;
63 uint32_t tx_out_context;
65 uint32_t rx_dropped;
68 static bool PIOS_USART_validate(struct pios_usart_dev *usart_dev)
70 return usart_dev->magic == PIOS_USART_DEV_MAGIC;
73 #if defined(PIOS_INCLUDE_FREERTOS)
74 static struct pios_usart_dev *PIOS_USART_alloc(void)
76 struct pios_usart_dev *usart_dev;
78 usart_dev = (struct pios_usart_dev *)pios_malloc(sizeof(struct pios_usart_dev));
79 if (!usart_dev) {
80 return NULL;
83 memset(usart_dev, 0, sizeof(struct pios_usart_dev));
84 usart_dev->magic = PIOS_USART_DEV_MAGIC;
85 return usart_dev;
87 #else
88 static struct pios_usart_dev pios_usart_devs[PIOS_USART_MAX_DEVS];
89 static uint8_t pios_usart_num_devs;
90 static struct pios_usart_dev *PIOS_USART_alloc(void)
92 struct pios_usart_dev *usart_dev;
94 if (pios_usart_num_devs >= PIOS_USART_MAX_DEVS) {
95 return NULL;
98 usart_dev = &pios_usart_devs[pios_usart_num_devs++];
100 memset(usart_dev, 0, sizeof(struct pios_usart_dev));
101 usart_dev->magic = PIOS_USART_DEV_MAGIC;
103 return usart_dev;
105 #endif /* if defined(PIOS_INCLUDE_FREERTOS) */
107 /* Bind Interrupt Handlers
109 * Map all valid USART IRQs to the common interrupt handler
110 * and provide storage for a 32-bit device id IRQ to map
111 * each physical IRQ to a specific registered device instance.
113 static void PIOS_USART_generic_irq_handler(uint32_t usart_id);
115 static uint32_t PIOS_USART_1_id;
116 void USART1_IRQHandler(void) __attribute__((alias("PIOS_USART_1_irq_handler")));
117 static void PIOS_USART_1_irq_handler(void)
119 PIOS_USART_generic_irq_handler(PIOS_USART_1_id);
122 static uint32_t PIOS_USART_2_id;
123 void USART2_IRQHandler(void) __attribute__((alias("PIOS_USART_2_irq_handler")));
124 static void PIOS_USART_2_irq_handler(void)
126 PIOS_USART_generic_irq_handler(PIOS_USART_2_id);
129 static uint32_t PIOS_USART_3_id;
130 void USART3_IRQHandler(void) __attribute__((alias("PIOS_USART_3_irq_handler")));
131 static void PIOS_USART_3_irq_handler(void)
133 PIOS_USART_generic_irq_handler(PIOS_USART_3_id);
137 * Initialise a single USART device
139 int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg)
141 PIOS_DEBUG_Assert(usart_id);
142 PIOS_DEBUG_Assert(cfg);
144 struct pios_usart_dev *usart_dev;
146 usart_dev = (struct pios_usart_dev *)PIOS_USART_alloc();
147 if (!usart_dev) {
148 goto out_fail;
151 /* Bind the configuration to the device instance */
152 usart_dev->cfg = cfg;
154 /* Enable the USART Pins Software Remapping */
155 if (usart_dev->cfg->remap) {
156 GPIO_PinRemapConfig(usart_dev->cfg->remap, ENABLE);
159 /* Initialize the USART Rx and Tx pins */
160 GPIO_Init(usart_dev->cfg->rx.gpio, &usart_dev->cfg->rx.init);
161 GPIO_Init(usart_dev->cfg->tx.gpio, &usart_dev->cfg->tx.init);
163 /* Enable USART clock */
164 switch ((uint32_t)usart_dev->cfg->regs) {
165 case (uint32_t)USART1:
166 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
167 break;
168 case (uint32_t)USART2:
169 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
170 break;
171 case (uint32_t)USART3:
172 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
173 break;
176 /* Configure the USART */
177 USART_Init(usart_dev->cfg->regs, &usart_dev->cfg->init);
179 *usart_id = (uint32_t)usart_dev;
181 /* Configure USART Interrupts */
182 switch ((uint32_t)usart_dev->cfg->regs) {
183 case (uint32_t)USART1:
184 PIOS_USART_1_id = (uint32_t)usart_dev;
185 break;
186 case (uint32_t)USART2:
187 PIOS_USART_2_id = (uint32_t)usart_dev;
188 break;
189 case (uint32_t)USART3:
190 PIOS_USART_3_id = (uint32_t)usart_dev;
191 break;
193 NVIC_Init(&usart_dev->cfg->irq.init);
194 USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
195 USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE);
197 /* Enable USART */
198 USART_Cmd(usart_dev->cfg->regs, ENABLE);
200 return 0;
202 out_fail:
203 return -1;
206 static void PIOS_USART_RxStart(uint32_t usart_id, __attribute__((unused)) uint16_t rx_bytes_avail)
208 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
210 bool valid = PIOS_USART_validate(usart_dev);
212 PIOS_Assert(valid);
214 USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
216 static void PIOS_USART_TxStart(uint32_t usart_id, __attribute__((unused)) uint16_t tx_bytes_avail)
218 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
220 bool valid = PIOS_USART_validate(usart_dev);
222 PIOS_Assert(valid);
224 USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE);
228 * Changes the baud rate of the USART peripheral without re-initialising.
229 * \param[in] usart_id USART name (GPS, TELEM, AUX)
230 * \param[in] baud Requested baud rate
232 static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud)
234 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
236 bool valid = PIOS_USART_validate(usart_dev);
238 PIOS_Assert(valid);
240 USART_InitTypeDef USART_InitStructure;
242 /* Start with a copy of the default configuration for the peripheral */
243 USART_InitStructure = usart_dev->cfg->init;
245 /* Adjust the baud rate */
246 USART_InitStructure.USART_BaudRate = baud;
248 /* Write back the new configuration */
249 USART_Init(usart_dev->cfg->regs, &USART_InitStructure);
252 static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context)
254 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
256 bool valid = PIOS_USART_validate(usart_dev);
258 PIOS_Assert(valid);
261 * Order is important in these assignments since ISR uses _cb
262 * field to determine if it's ok to dereference _cb and _context
264 usart_dev->rx_in_context = context;
265 usart_dev->rx_in_cb = rx_in_cb;
268 static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context)
270 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
272 bool valid = PIOS_USART_validate(usart_dev);
274 PIOS_Assert(valid);
277 * Order is important in these assignments since ISR uses _cb
278 * field to determine if it's ok to dereference _cb and _context
280 usart_dev->tx_out_context = context;
281 usart_dev->tx_out_cb = tx_out_cb;
284 static void PIOS_USART_generic_irq_handler(uint32_t usart_id)
286 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
288 bool valid = PIOS_USART_validate(usart_dev);
290 PIOS_Assert(valid);
292 /* Force read of dr after sr to make sure to clear error flags */
293 volatile uint16_t sr = usart_dev->cfg->regs->SR;
294 volatile uint8_t dr = usart_dev->cfg->regs->DR;
296 /* Check if RXNE flag is set */
297 bool rx_need_yield = false;
298 if (sr & USART_SR_RXNE) {
299 uint8_t byte = dr;
300 if (usart_dev->rx_in_cb) {
301 uint16_t rc;
302 rc = (usart_dev->rx_in_cb)(usart_dev->rx_in_context, &byte, 1, NULL, &rx_need_yield);
303 if (rc < 1) {
304 /* Lost bytes on rx */
305 usart_dev->rx_dropped += 1;
310 /* Check if TXE flag is set */
311 bool tx_need_yield = false;
312 if (sr & USART_SR_TXE) {
313 if (usart_dev->tx_out_cb) {
314 uint8_t b;
315 uint16_t bytes_to_send;
317 bytes_to_send = (usart_dev->tx_out_cb)(usart_dev->tx_out_context, &b, 1, NULL, &tx_need_yield);
319 if (bytes_to_send > 0) {
320 /* Send the byte we've been given */
321 usart_dev->cfg->regs->DR = b;
322 } else {
323 /* No bytes to send, disable TXE interrupt */
324 USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
326 } else {
327 /* No bytes to send, disable TXE interrupt */
328 USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
332 #if defined(PIOS_INCLUDE_FREERTOS)
333 if (rx_need_yield || tx_need_yield) {
334 vPortYield();
336 #endif /* PIOS_INCLUDE_FREERTOS */
339 #endif /* PIOS_INCLUDE_USART */
342 * @}
343 * @}