2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
5 * @addtogroup PIOS_USART USART Functions
6 * @brief PIOS interface for USART port
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
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
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
;
68 uint8_t tx_buffer
[PIOS_UART_TX_BUFFER
];
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
);
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
));
93 memset(usart_dev
, 0, sizeof(struct pios_usart_dev
));
94 usart_dev
->magic
= PIOS_USART_DEV_MAGIC
;
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
) {
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
;
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();
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
;
180 case (uint32_t)USART2
:
181 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2
, ENABLE
);
182 PIOS_USART_2_id
= (uint32_t)usart_dev
;
184 case (uint32_t)USART3
:
185 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3
, ENABLE
);
186 PIOS_USART_3_id
= (uint32_t)usart_dev
;
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
);
200 USART_Cmd(cfg
->regs
, ENABLE
);
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
) {
279 rc
= (usart_dev
->rx_in_cb
)(usart_dev
->rx_in_context
, &byte
, 1, NULL
, &rx_need_yield
);
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
++]);
300 /* No bytes to send, disable TXE interrupt */
301 USART_ITConfig(usart_dev
->cfg
->regs
, USART_IT_TXE
, DISABLE
);
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
) {
314 #endif /* PIOS_INCLUDE_FREERTOS */
317 #endif /* PIOS_INCLUDE_USART */