REVONANO Milestones update
[librepilot.git] / flight / pios / stm32f0x / pios_usart.c
blob4239f31d5b73be51c05c5c8e5dbdd3940e7bcbec
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 #define PIOS_UART_TX_BUFFER 10
38 /* Provide a COM driver */
39 static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud);
40 static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context);
41 static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context);
42 static void PIOS_USART_TxStart(uint32_t usart_id, uint16_t tx_bytes_avail);
43 static void PIOS_USART_RxStart(uint32_t usart_id, uint16_t rx_bytes_avail);
45 const struct pios_com_driver pios_usart_com_driver = {
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,
53 enum pios_usart_dev_magic {
54 PIOS_USART_DEV_MAGIC = 0x11223344,
57 struct pios_usart_dev {
58 enum pios_usart_dev_magic magic;
59 const struct pios_usart_cfg *cfg;
61 pios_com_callback rx_in_cb;
62 uint32_t rx_in_context;
63 pios_com_callback tx_out_cb;
64 uint32_t tx_out_context;
66 uint32_t rx_dropped;
68 uint8_t tx_buffer[PIOS_UART_TX_BUFFER];
69 uint8_t tx_len;
70 uint8_t tx_pos;
73 static struct pios_usart_dev *PIOS_USART_validate(uint32_t usart_id)
75 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
77 bool valid = (usart_dev->magic == PIOS_USART_DEV_MAGIC);
79 PIOS_Assert(valid);
80 return usart_dev;
83 #if defined(PIOS_INCLUDE_FREERTOS)
84 static struct pios_usart_dev *PIOS_USART_alloc(void)
86 struct pios_usart_dev *usart_dev;
88 usart_dev = (struct pios_usart_dev *)pvPortMalloc(sizeof(struct pios_usart_dev));
89 if (!usart_dev) {
90 return NULL;
93 memset(usart_dev, 0, sizeof(struct pios_usart_dev));
94 usart_dev->magic = PIOS_USART_DEV_MAGIC;
95 return usart_dev;
97 #else
98 static struct pios_usart_dev pios_usart_devs[PIOS_USART_MAX_DEVS];
99 static uint8_t pios_usart_num_devs;
100 static struct pios_usart_dev *PIOS_USART_alloc(void)
102 struct pios_usart_dev *usart_dev;
104 if (pios_usart_num_devs >= PIOS_USART_MAX_DEVS) {
105 return NULL;
108 usart_dev = &pios_usart_devs[pios_usart_num_devs++];
110 memset(usart_dev, 0, sizeof(struct pios_usart_dev));
111 usart_dev->magic = PIOS_USART_DEV_MAGIC;
113 return usart_dev;
115 #endif /* if defined(PIOS_INCLUDE_FREERTOS) */
117 /* Bind Interrupt Handlers
119 * Map all valid USART IRQs to the common interrupt handler
120 * and provide storage for a 32-bit device id IRQ to map
121 * each physical IRQ to a specific registered device instance.
123 static void PIOS_USART_generic_irq_handler(uint32_t usart_id);
125 static uint32_t PIOS_USART_1_id;
126 void USART1_IRQHandler(void) __attribute__((alias("PIOS_USART_1_irq_handler")));
127 static void PIOS_USART_1_irq_handler(void)
129 PIOS_USART_generic_irq_handler(PIOS_USART_1_id);
132 static uint32_t PIOS_USART_2_id;
133 void USART2_IRQHandler(void) __attribute__((alias("PIOS_USART_2_irq_handler")));
134 static void PIOS_USART_2_irq_handler(void)
136 PIOS_USART_generic_irq_handler(PIOS_USART_2_id);
139 static uint32_t PIOS_USART_3_id;
140 void USART3_IRQHandler(void) __attribute__((alias("PIOS_USART_3_irq_handler")));
141 static void PIOS_USART_3_irq_handler(void)
143 PIOS_USART_generic_irq_handler(PIOS_USART_3_id);
147 * Initialise a single USART device
149 int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg)
151 PIOS_DEBUG_Assert(usart_id);
152 PIOS_DEBUG_Assert(cfg);
154 struct pios_usart_dev *usart_dev;
156 usart_dev = (struct pios_usart_dev *)PIOS_USART_alloc();
157 if (!usart_dev) {
158 return -1;
161 /* Bind the configuration to the device instance */
162 usart_dev->cfg = cfg;
164 /* Enable the USART Pins Software Remapping */
165 if (usart_dev->cfg->remap) {
166 GPIO_PinAFConfig(cfg->rx.gpio, __builtin_ctz(cfg->rx.init.GPIO_Pin), cfg->remap);
167 GPIO_PinAFConfig(cfg->tx.gpio, __builtin_ctz(cfg->tx.init.GPIO_Pin), cfg->remap);
170 /* Initialize the USART Rx and Tx pins */
171 GPIO_Init(cfg->rx.gpio, (GPIO_InitTypeDef *)&cfg->rx.init);
172 GPIO_Init(cfg->tx.gpio, (GPIO_InitTypeDef *)&cfg->tx.init);
174 /* Enable USART clock */
175 switch ((uint32_t)cfg->regs) {
176 case (uint32_t)USART1:
177 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
178 PIOS_USART_1_id = (uint32_t)usart_dev;
179 break;
180 case (uint32_t)USART2:
181 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
182 PIOS_USART_2_id = (uint32_t)usart_dev;
183 break;
184 case (uint32_t)USART3:
185 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
186 PIOS_USART_3_id = (uint32_t)usart_dev;
187 break;
190 /* Configure the USART */
191 USART_Init(cfg->regs, (USART_InitTypeDef *)&cfg->init);
192 *usart_id = (uint32_t)usart_dev;
194 NVIC_Init((NVIC_InitTypeDef *)&cfg->irq.init);
195 USART_ITConfig(cfg->regs, USART_IT_RXNE, ENABLE);
196 USART_ITConfig(cfg->regs, USART_IT_TXE, ENABLE);
197 USART_ITConfig(cfg->regs, USART_IT_ORE, DISABLE);
198 USART_ITConfig(cfg->regs, USART_IT_TC, DISABLE);
199 /* Enable USART */
200 USART_Cmd(cfg->regs, ENABLE);
202 return 0;
205 static void PIOS_USART_RxStart(uint32_t usart_id, __attribute__((unused)) uint16_t rx_bytes_avail)
207 const struct pios_usart_dev *usart_dev = PIOS_USART_validate(usart_id);
209 USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
211 static void PIOS_USART_TxStart(uint32_t usart_id, __attribute__((unused)) uint16_t tx_bytes_avail)
213 const struct pios_usart_dev *usart_dev = PIOS_USART_validate(usart_id);
215 USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE);
219 * Changes the baud rate of the USART peripheral without re-initialising.
220 * \param[in] usart_id USART name (GPS, TELEM, AUX)
221 * \param[in] baud Requested baud rate
223 static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud)
225 const struct pios_usart_dev *usart_dev = PIOS_USART_validate(usart_id);
227 USART_InitTypeDef USART_InitStructure;
229 /* Start with a copy of the default configuration for the peripheral */
230 USART_InitStructure = usart_dev->cfg->init;
232 /* Adjust the baud rate */
233 USART_InitStructure.USART_BaudRate = baud;
235 /* Write back the new configuration */
236 USART_Init(usart_dev->cfg->regs, &USART_InitStructure);
238 USART_Cmd(usart_dev->cfg->regs, ENABLE);
241 static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context)
243 struct pios_usart_dev *usart_dev = PIOS_USART_validate(usart_id);
246 * Order is important in these assignments since ISR uses _cb
247 * field to determine if it's ok to dereference _cb and _context
249 usart_dev->rx_in_context = context;
250 usart_dev->rx_in_cb = rx_in_cb;
253 static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context)
255 struct pios_usart_dev *usart_dev = PIOS_USART_validate(usart_id);
258 * Order is important in these assignments since ISR uses _cb
259 * field to determine if it's ok to dereference _cb and _context
261 usart_dev->tx_out_context = context;
262 usart_dev->tx_out_cb = tx_out_cb;
265 static void PIOS_USART_generic_irq_handler(uint32_t usart_id)
267 struct pios_usart_dev *usart_dev = PIOS_USART_validate(usart_id);
269 /* Force read of dr after sr to make sure to clear error flags */
272 /* Check if RXNE flag is set */
273 bool rx_need_yield = false;
275 if (USART_GetITStatus(usart_dev->cfg->regs, USART_IT_RXNE) != RESET) {
276 uint8_t byte = USART_ReceiveData(usart_dev->cfg->regs) & 0x00FF;
277 if (usart_dev->rx_in_cb) {
278 uint16_t rc;
279 rc = (usart_dev->rx_in_cb)(usart_dev->rx_in_context, &byte, 1, NULL, &rx_need_yield);
280 if (rc < 1) {
281 /* Lost bytes on rx */
282 usart_dev->rx_dropped += 1;
287 /* Check if TXE flag is set */
288 bool tx_need_yield = false;
289 if (USART_GetITStatus(usart_dev->cfg->regs, USART_IT_TXE) != RESET) {
290 if (usart_dev->tx_out_cb) {
291 if (!usart_dev->tx_len) {
292 usart_dev->tx_len = (usart_dev->tx_out_cb)(usart_dev->tx_out_context, usart_dev->tx_buffer, PIOS_UART_TX_BUFFER, NULL, &tx_need_yield);
293 usart_dev->tx_pos = 0;
295 if (usart_dev->tx_len > 0) {
296 /* Send the byte we've been given */
297 USART_SendData(usart_dev->cfg->regs, usart_dev->tx_buffer[usart_dev->tx_pos++]);
298 usart_dev->tx_len--;
299 } else {
300 /* No bytes to send, disable TXE interrupt */
301 USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
303 } else {
304 /* No bytes to send, disable TXE interrupt */
305 USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
308 USART_ClearITPendingBit(usart_dev->cfg->regs, USART_IT_ORE);
309 USART_ClearITPendingBit(usart_dev->cfg->regs, USART_IT_TC);
310 #if defined(PIOS_INCLUDE_FREERTOS)
311 if (rx_need_yield || tx_need_yield) {
312 vPortYield();
314 #endif /* PIOS_INCLUDE_FREERTOS */
317 #endif /* PIOS_INCLUDE_USART */
320 * @}
321 * @}