Skip to content

Commit

Permalink
[stm32] Fixes for USART interrupt handler.
Browse files Browse the repository at this point in the history
The interrupt handler occasionally hangs in case of noise on the line.
Fixes were two:
1) Disable IDLE line interrupt, disable LIN break interrupt in the port settings.
   (neither of them should be used for asynchronous single buffer communication).
2) In interrupt handler routine, explicitly check for the error flags, only if
   no errors occur check the received byte. Otherwise clear the USART_DR and
   log the error.

Added USART_ERRORS messages to monitor problems on USART lines.

Closes paparazzi#418
  • Loading branch information
podhrmic authored and flixr committed Apr 16, 2013
1 parent 24d7fd6 commit 64b1fe8
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 19 deletions.
7 changes: 6 additions & 1 deletion conf/messages.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1755,7 +1755,12 @@
<field name="electrical_current" type="int32" unit="mA"/>
</message>

<!--208 is free -->
<message name="UART_ERRORS" id="208">
<field name="overrun_cnt" type="uint16"/>
<field name="noise_err_cnt" type="uint16"/>
<field name="framing_err_cnt" type="uint16"/>
<field name="bus_number" type="uint8"/>
</message>

<message name="IMU_GYRO_LP" id="209">
<field name="gp" type="float" unit="rad/s"/>
Expand Down
1 change: 1 addition & 0 deletions conf/telemetry/default_rotorcraft.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<message name="GPS_INT" period=".25"/>
<message name="INS" period=".25"/>
<message name="I2C_ERRORS" period="6."/>
<message name="UART_ERRORS" period="3.1"/>
</mode>

<mode name="ppm">
Expand Down
53 changes: 39 additions & 14 deletions sw/airborne/arch/stm32/mcu_periph/uart_arch.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ void uart_periph_set_baudrate(struct uart_periph* p, uint32_t baud, bool_t hw_fl
usart_set_flow_control((u32)p->reg_addr, USART_FLOWCONTROL_NONE);
}

/* Disable Idle Line interrupt */
USART_CR1((u32)p->reg_addr) &= ~USART_CR1_IDLEIE;

/* Disable LIN break detection interrupt */
USART_CR2((u32)p->reg_addr) &= ~USART_CR2_LBDIE;

/* Enable USART1 Receive interrupts */
USART_CR1((u32)p->reg_addr) |= USART_CR1_RXNEIE;

Expand Down Expand Up @@ -85,7 +91,7 @@ void uart_transmit(struct uart_periph* p, uint8_t data ) {
static inline void usart_isr(struct uart_periph* p) {

if (((USART_CR1((u32)p->reg_addr) & USART_CR1_TXEIE) != 0) &&
((USART_SR((u32)p->reg_addr) & USART_SR_TXE) != 0)) {
((USART_SR((u32)p->reg_addr) & USART_SR_TXE) != 0)) {
// check if more data to send
if (p->tx_insert_idx != p->tx_extract_idx) {
usart_send((u32)p->reg_addr,p->tx_buf[p->tx_extract_idx]);
Expand All @@ -99,14 +105,34 @@ static inline void usart_isr(struct uart_periph* p) {
}

if (((USART_CR1((u32)p->reg_addr) & USART_CR1_RXNEIE) != 0) &&
((USART_SR((u32)p->reg_addr) & USART_SR_RXNE) != 0)) {
((USART_SR((u32)p->reg_addr) & USART_SR_RXNE) != 0) &&
((USART_SR((u32)p->reg_addr) & USART_SR_ORE) == 0) &&
((USART_SR((u32)p->reg_addr) & USART_SR_NE) == 0) &&
((USART_SR((u32)p->reg_addr) & USART_SR_FE) == 0)) {
uint16_t temp = (p->rx_insert_idx + 1) % UART_RX_BUFFER_SIZE;;
p->rx_buf[p->rx_insert_idx] = usart_recv((u32)p->reg_addr);
// check for more room in queue
if (temp != p->rx_extract_idx)
p->rx_insert_idx = temp; // update insert index
}

else {
/* ORE, NE or FE error - read USART_DR reg and log the error */
if (((USART_CR1((u32)p->reg_addr) & USART_CR1_RXNEIE) != 0) &&
((USART_SR((u32)p->reg_addr) & USART_SR_ORE) != 0)) {
usart_recv((u32)p->reg_addr);
p->ore++;
}
if (((USART_CR1((u32)p->reg_addr) & USART_CR1_RXNEIE) != 0) &&
((USART_SR((u32)p->reg_addr) & USART_SR_NE) != 0)) {
usart_recv((u32)p->reg_addr);
p->ne_err++;
}
if (((USART_CR1((u32)p->reg_addr) & USART_CR1_RXNEIE) != 0) &&
((USART_SR((u32)p->reg_addr) & USART_SR_FE) != 0)) {
usart_recv((u32)p->reg_addr);
p->fe_err++;
}
}
}

static inline void usart_enable_irq(u8 IRQn) {
Expand Down Expand Up @@ -134,16 +160,16 @@ void uart1_init( void ) {

/* Init GPIOS */
gpio_set_mode(GPIO_BANK_USART1_TX, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX);
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX);
gpio_set_mode(GPIO_BANK_USART1_RX, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_FLOAT, GPIO_USART1_RX);
GPIO_CNF_INPUT_FLOAT, GPIO_USART1_RX);

#if UART1_HW_FLOW_CONTROL
#warning "USING UART1 FLOW CONTROL. Make sure to pull down CTS if you are not connecting any flow-control-capable hardware."
gpio_set_mode(GPIO_BANK_USART1_RTS, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_RTS);
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_RTS);
gpio_set_mode(GPIO_BANK_USART1_CTS, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_FLOAT, GPIO_USART1_CTS);
GPIO_CNF_INPUT_FLOAT, GPIO_USART1_CTS);

/* Configure USART1, enable hardware flow control*/
uart_periph_set_baudrate(&uart1, UART1_BAUD, TRUE);
Expand Down Expand Up @@ -173,9 +199,9 @@ void uart2_init( void ) {

/* Init GPIOS */
gpio_set_mode(GPIO_BANK_USART2_TX, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART2_TX);
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART2_TX);
gpio_set_mode(GPIO_BANK_USART2_RX, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_FLOAT, GPIO_USART2_RX);
GPIO_CNF_INPUT_FLOAT, GPIO_USART2_RX);

/* Configure USART */
uart_periph_set_baudrate(&uart2, UART2_BAUD, FALSE);
Expand Down Expand Up @@ -203,9 +229,9 @@ void uart3_init( void ) {
/* Init GPIOS */
AFIO_MAPR |= AFIO_MAPR_USART3_REMAP_PARTIAL_REMAP;
gpio_set_mode(GPIO_BANK_USART3_PR_TX, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART3_PR_TX);
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART3_PR_TX);
gpio_set_mode(GPIO_BANK_USART3_PR_RX, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_FLOAT, GPIO_USART3_PR_RX);
GPIO_CNF_INPUT_FLOAT, GPIO_USART3_PR_RX);

/* Configure USART */
uart_periph_set_baudrate(&uart3, UART3_BAUD, FALSE);
Expand All @@ -232,9 +258,9 @@ void uart5_init( void ) {

/* Init GPIOS */
gpio_set_mode(GPIO_BANK_UART5_TX, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_UART5_TX);
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_UART5_TX);
gpio_set_mode(GPIO_BANK_UART5_RX, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_FLOAT, GPIO_UART5_RX);
GPIO_CNF_INPUT_FLOAT, GPIO_UART5_RX);

/* Configure USART */
uart_periph_set_baudrate(&uart5, UART5_BAUD, FALSE);
Expand All @@ -243,4 +269,3 @@ void uart5_init( void ) {
void uart5_isr(void) { usart_isr(&uart5); }

#endif /* USE_UART5 */

78 changes: 78 additions & 0 deletions sw/airborne/firmwares/rotorcraft/telemetry.h
Original file line number Diff line number Diff line change
Expand Up @@ -904,4 +904,82 @@
#include "generated/settings.h"
#define PERIODIC_SEND_DL_VALUE(_trans, _dev) PeriodicSendDlValue(_trans, _dev)

/*
* Sending of UART errors.
*/
#ifdef USE_UART1
#define PERIODIC_SEND_UART1_ERRORS(_trans, _dev) { \
const uint8_t _bus1 = 1; \
DOWNLINK_SEND_UART_ERRORS(_trans, _dev, \
&uart1.ore, \
&uart1.ne_err, \
&uart1.fe_err, \
&_bus1); \
}
#else
#define PERIODIC_SEND_UART1_ERRORS(_trans, _dev) {}
#endif

#ifdef USE_UART2
#define PERIODIC_SEND_UART2_ERRORS(_trans, _dev) { \
const uint8_t _bus2 = 2; \
DOWNLINK_SEND_UART_ERRORS(_trans, _dev, \
&uart2.ore, \
&uart2.ne_err, \
&uart2.fe_err, \
&_bus2); \
}
#else
#define PERIODIC_SEND_UART2_ERRORS(_trans, _dev) {}
#endif

#ifdef USE_UART3
#define PERIODIC_SEND_UART3_ERRORS(_trans, _dev) { \
const uint8_t _bus3 = 3; \
DOWNLINK_SEND_UART_ERRORS(_trans, _dev, \
&uart3.ore, \
&uart3.ne_err, \
&uart3.fe_err, \
&_bus3); \
}
#else
#define PERIODIC_SEND_UART3_ERRORS(_trans, _dev) {}
#endif

#ifdef USE_UART5
#define PERIODIC_SEND_UART5_ERRORS(_trans, _dev) { \
const uint8_t _bus5 = 5; \
DOWNLINK_SEND_UART_ERRORS(_trans, _dev, \
&uart5.ore, \
&uart5.ne_err, \
&uart5.fe_err, \
&_bus5); \
}
#else
#define PERIODIC_SEND_UART5_ERRORS(_trans, _dev) {}
#endif


#ifndef SITL
#define PERIODIC_SEND_UART_ERRORS(_trans, _dev) { \
static uint8_t uart_nb_cnt = 0; \
switch (uart_nb_cnt) { \
case 0: \
PERIODIC_SEND_UART1_ERRORS(_trans, _dev); break; \
case 1: \
PERIODIC_SEND_UART2_ERRORS(_trans, _dev); break; \
case 2: \
PERIODIC_SEND_UART3_ERRORS(_trans, _dev); break; \
case 3: \
PERIODIC_SEND_UART5_ERRORS(_trans, _dev); break; \
default: break; \
} \
uart_nb_cnt++; \
if (uart_nb_cnt == 4) \
uart_nb_cnt = 0; \
}
#else
#define PERIODIC_SEND_UART_ERRORS(_trans, _dev) {}
#endif

#endif /* TELEMETRY_H */
3 changes: 3 additions & 0 deletions sw/airborne/mcu_periph/uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ void uart_periph_init(struct uart_periph* p) {
p->tx_insert_idx = 0;
p->tx_extract_idx = 0;
p->tx_running = FALSE;
p->ore = 0;
p->ne_err = 0;
p->fe_err = 0;
}

bool_t uart_check_free_space(struct uart_periph* p, uint8_t len) {
Expand Down
13 changes: 9 additions & 4 deletions sw/airborne/mcu_periph/uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,26 +48,31 @@
#define B57600 57600
#define B115200 115200
#define B230400 230400
#define B921600 921600

/**
* UART peripheral
*/
struct uart_periph {
/* Receive buffer */
/** Receive buffer */
uint8_t rx_buf[UART_RX_BUFFER_SIZE];
uint16_t rx_insert_idx;
uint16_t rx_extract_idx;
/* Transmit buffer */
/** Transmit buffer */
uint8_t tx_buf[UART_TX_BUFFER_SIZE];
uint16_t tx_insert_idx;
uint16_t tx_extract_idx;
uint8_t tx_running;
/* UART Register */
/** UART Register */
void* reg_addr;
/* UART Dev (linux) */
/** UART Dev (linux) */
char dev[UART_DEV_NAME_SIZE];
volatile uint16_t ore; ///< overrun error counter
volatile uint16_t ne_err; ///< noise error counter
volatile uint16_t fe_err; ///< framing error counter
};


extern void uart_periph_init(struct uart_periph* p);
extern void uart_periph_set_baudrate(struct uart_periph* p, uint32_t baud, bool_t hw_flow_control);
extern void uart_transmit(struct uart_periph* p, uint8_t data);
Expand Down

0 comments on commit 64b1fe8

Please sign in to comment.