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) 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
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.
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
));
87 memset(usart_dev
, 0, sizeof(struct pios_usart_dev
));
88 usart_dev
->magic
= PIOS_USART_DEV_MAGIC
;
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
) {
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
;
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();
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 USART_OverSampling8Cmd(usart_dev
->cfg
->regs
, ENABLE
);
201 /* Configure the USART */
202 USART_Init(usart_dev
->cfg
->regs
, (USART_InitTypeDef
*)&usart_dev
->cfg
->init
);
204 *usart_id
= (uint32_t)usart_dev
;
206 /* Configure USART Interrupts */
207 switch ((uint32_t)usart_dev
->cfg
->regs
) {
208 case (uint32_t)USART1
:
209 PIOS_USART_1_id
= (uint32_t)usart_dev
;
211 case (uint32_t)USART2
:
212 PIOS_USART_2_id
= (uint32_t)usart_dev
;
214 case (uint32_t)USART3
:
215 PIOS_USART_3_id
= (uint32_t)usart_dev
;
217 case (uint32_t)UART4
:
218 PIOS_USART_4_id
= (uint32_t)usart_dev
;
220 case (uint32_t)UART5
:
221 PIOS_USART_5_id
= (uint32_t)usart_dev
;
223 case (uint32_t)USART6
:
224 PIOS_USART_6_id
= (uint32_t)usart_dev
;
227 NVIC_Init((NVIC_InitTypeDef
*)&(usart_dev
->cfg
->irq
.init
));
228 USART_ITConfig(usart_dev
->cfg
->regs
, USART_IT_RXNE
, ENABLE
);
229 USART_ITConfig(usart_dev
->cfg
->regs
, USART_IT_TXE
, ENABLE
);
231 // FIXME XXX Clear / reset uart here - sends NUL char else
234 USART_Cmd(usart_dev
->cfg
->regs
, ENABLE
);
242 static void PIOS_USART_RxStart(uint32_t usart_id
, __attribute__((unused
)) uint16_t rx_bytes_avail
)
244 struct pios_usart_dev
*usart_dev
= (struct pios_usart_dev
*)usart_id
;
246 bool valid
= PIOS_USART_validate(usart_dev
);
250 USART_ITConfig(usart_dev
->cfg
->regs
, USART_IT_RXNE
, ENABLE
);
252 static void PIOS_USART_TxStart(uint32_t usart_id
, __attribute__((unused
)) uint16_t tx_bytes_avail
)
254 struct pios_usart_dev
*usart_dev
= (struct pios_usart_dev
*)usart_id
;
256 bool valid
= PIOS_USART_validate(usart_dev
);
260 USART_ITConfig(usart_dev
->cfg
->regs
, USART_IT_TXE
, ENABLE
);
264 * Changes the baud rate of the USART peripheral without re-initialising.
265 * \param[in] usart_id USART name (GPS, TELEM, AUX)
266 * \param[in] baud Requested baud rate
268 static void PIOS_USART_ChangeBaud(uint32_t usart_id
, uint32_t baud
)
270 struct pios_usart_dev
*usart_dev
= (struct pios_usart_dev
*)usart_id
;
272 bool valid
= PIOS_USART_validate(usart_dev
);
276 USART_InitTypeDef USART_InitStructure
;
278 /* Start with a copy of the default configuration for the peripheral */
279 USART_InitStructure
= usart_dev
->cfg
->init
;
281 /* Adjust the baud rate */
282 USART_InitStructure
.USART_BaudRate
= baud
;
284 /* Write back the new configuration */
285 USART_Init(usart_dev
->cfg
->regs
, &USART_InitStructure
);
288 static void PIOS_USART_SetCtrlLine(uint32_t usart_id
, uint32_t mask
, uint32_t state
)
290 struct pios_usart_dev
*usart_dev
= (struct pios_usart_dev
*)usart_id
;
292 bool valid
= PIOS_USART_validate(usart_dev
);
296 /* Only attempt to drive DTR if this USART has a GPIO line defined */
297 if (usart_dev
->cfg
->dtr
.gpio
&& (mask
& COM_CTRL_LINE_DTR_MASK
)) {
298 GPIO_WriteBit(usart_dev
->cfg
->dtr
.gpio
,
299 usart_dev
->cfg
->dtr
.init
.GPIO_Pin
,
300 state
& COM_CTRL_LINE_DTR_MASK
? Bit_RESET
: Bit_SET
);
304 static void PIOS_USART_RegisterRxCallback(uint32_t usart_id
, pios_com_callback rx_in_cb
, uint32_t context
)
306 struct pios_usart_dev
*usart_dev
= (struct pios_usart_dev
*)usart_id
;
308 bool valid
= PIOS_USART_validate(usart_dev
);
313 * Order is important in these assignments since ISR uses _cb
314 * field to determine if it's ok to dereference _cb and _context
316 usart_dev
->rx_in_context
= context
;
317 usart_dev
->rx_in_cb
= rx_in_cb
;
320 static void PIOS_USART_RegisterTxCallback(uint32_t usart_id
, pios_com_callback tx_out_cb
, uint32_t context
)
322 struct pios_usart_dev
*usart_dev
= (struct pios_usart_dev
*)usart_id
;
324 bool valid
= PIOS_USART_validate(usart_dev
);
329 * Order is important in these assignments since ISR uses _cb
330 * field to determine if it's ok to dereference _cb and _context
332 usart_dev
->tx_out_context
= context
;
333 usart_dev
->tx_out_cb
= tx_out_cb
;
336 static void PIOS_USART_generic_irq_handler(uint32_t usart_id
)
338 struct pios_usart_dev
*usart_dev
= (struct pios_usart_dev
*)usart_id
;
340 bool valid
= PIOS_USART_validate(usart_dev
);
344 /* Force read of dr after sr to make sure to clear error flags */
345 volatile uint16_t sr
= usart_dev
->cfg
->regs
->SR
;
346 volatile uint8_t dr
= usart_dev
->cfg
->regs
->DR
;
348 /* Check if RXNE flag is set */
349 bool rx_need_yield
= false;
350 if (sr
& USART_SR_RXNE
) {
352 if (usart_dev
->rx_in_cb
) {
353 (void)(usart_dev
->rx_in_cb
)(usart_dev
->rx_in_context
, &byte
, 1, NULL
, &rx_need_yield
);
357 /* Check if TXE flag is set */
358 bool tx_need_yield
= false;
359 if (sr
& USART_SR_TXE
) {
360 if (usart_dev
->tx_out_cb
) {
362 uint16_t bytes_to_send
;
364 bytes_to_send
= (usart_dev
->tx_out_cb
)(usart_dev
->tx_out_context
, &b
, 1, NULL
, &tx_need_yield
);
366 if (bytes_to_send
> 0) {
367 /* Send the byte we've been given */
368 usart_dev
->cfg
->regs
->DR
= b
;
370 /* No bytes to send, disable TXE interrupt */
371 USART_ITConfig(usart_dev
->cfg
->regs
, USART_IT_TXE
, DISABLE
);
374 /* No bytes to send, disable TXE interrupt */
375 USART_ITConfig(usart_dev
->cfg
->regs
, USART_IT_TXE
, DISABLE
);
379 #if defined(PIOS_INCLUDE_FREERTOS)
380 if (rx_need_yield
|| tx_need_yield
) {
383 #endif /* PIOS_INCLUDE_FREERTOS */
386 #endif /* PIOS_INCLUDE_USART */