From dfcde5bb47c569eff3f017dc2504b25cc0d67fa6 Mon Sep 17 00:00:00 2001 From: Martin Guy Date: Mon, 25 Apr 2011 16:32:00 +0200 Subject: [PATCH] Starting to fix AVR32 UARt code: - Check for error return values and return errors when they happen - Return error value when invalid parameters are passed - uart.setup(): return the actual baud rate set. --- src/platform/avr32/platform.c | 33 +++++++++++++++------ src/platform/avr32/usart.c | 54 +++++++++++++++++++++++++++++++++++ src/platform/avr32/usart.h | 10 +++++++ 3 files changed, 88 insertions(+), 9 deletions(-) diff --git a/src/platform/avr32/platform.c b/src/platform/avr32/platform.c index 7b71f06a..a0c8f2fa 100644 --- a/src/platform/avr32/platform.c +++ b/src/platform/avr32/platform.c @@ -348,27 +348,42 @@ u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity, int st opts.baudrate = baud; // Set stopbits - if( stopbits == PLATFORM_UART_STOPBITS_1 ) + switch (stopbits) { + case PLATFORM_UART_STOPBITS_1: opts.stopbits = USART_1_STOPBIT; - else if( stopbits == PLATFORM_UART_STOPBITS_1_5 ) + break; + case PLATFORM_UART_STOPBITS_1_5: opts.stopbits = USART_1_5_STOPBITS; - else + break; + case PLATFORM_UART_STOPBITS_2: opts.stopbits = USART_2_STOPBITS; + break; + default: + return 0; + } // Set parity - if( parity == PLATFORM_UART_PARITY_EVEN ) + switch (parity) { + case PLATFORM_UART_PARITY_EVEN: opts.paritytype = USART_EVEN_PARITY; - else if( parity == PLATFORM_UART_PARITY_ODD ) + break; + case PLATFORM_UART_PARITY_ODD: opts.paritytype = USART_ODD_PARITY; - else + break; + case PLATFORM_UART_PARITY_NONE: opts.paritytype = USART_NO_PARITY; + break; + default: + return 0; + } // Set actual interface gpio_enable_module(uart_pins + id * 2, 2 ); - usart_init_rs232( pusart, &opts, REQ_PBA_FREQ ); + if ( usart_init_rs232( pusart, &opts, REQ_PBA_FREQ ) != USART_SUCCESS ) + return 0; - // [TODO] Return actual baud here - return baud; + // Return actual baud here + return usart_get_async_baudrate(pusart, REQ_PBA_FREQ); } void platform_s_uart_send( unsigned id, u8 data ) diff --git a/src/platform/avr32/usart.c b/src/platform/avr32/usart.c index 0948cd49..4641ff26 100644 --- a/src/platform/avr32/usart.c +++ b/src/platform/avr32/usart.c @@ -111,6 +111,60 @@ static int usart_set_async_baudrate(volatile avr32_usart_t *usart, unsigned int } +/*! \brief Return the actual baud rate set into the USART + * + * Baud rate calculation: + * \f$ Baudrate = \frac{SelectedClock}{Over \times (CD + \frac{FP}{8})} \f$, \e Over being 16 or 8. + * + * \param usart Base address of the USART instance. + * \param pba_hz USART module input clock frequency (PBA clock, Hz). + * + * \retval baudrate The closest integer to the actual baud rate + * \retval 0 UART clock is off or there was some error on our part + */ +unsigned int usart_get_async_baudrate(volatile avr32_usart_t *usart, unsigned long pba_hz) +{ + unsigned int clock; // Master clock frequency + unsigned int over; // divisor of 8 or 16 + unsigned int cd; // clock divider (0-65535) + unsigned int fp; // fractional part of clock divider (0-7) + unsigned int divisor; // What the master clock is divided by to get + // the final baud rate + + // Find + switch ((usart->mr & AVR32_USART_MR_USCLKS_MASK) >> AVR32_USART_MR_USCLKS_OFFSET) + { + case AVR32_USART_MR_USCLKS_MCK: + clock = pba_hz; + break; + + case AVR32_USART_MR_USCLKS_MCK_DIV: + // I can't figure out where the divider is defined. The datasheet + // section 26.7.1 says it is "product dependent, but generally set to 8". + // Fortunately, the code above always selects MCK. + case AVR32_USART_MR_USCLKS_SCK: + // If we have an external clock, we don't know its frequency here. + default: + return 0; + } + + over = usart->mr & AVR32_USART_MR_OVER_MASK; + cd = (usart->brgr & AVR32_USART_BRGR_CD_MASK) >> AVR32_USART_BRGR_CD_OFFSET; + fp = (usart->brgr & AVR32_USART_BRGR_FP_MASK) >> AVR32_USART_BRGR_FP_OFFSET; + + // if CD==0, no baud rate is generated. + // if CD==1, the clock divider and fractional part are bypassed. + if (cd == 0) return 0; + if (cd == 1) fp = 0; + + // Rewriting "divisor = 8 * (2 - over) * (cd + fp/8)" for integer math: + divisor = (2 - over) * (8 * cd + fp); + + // Round to the integer that is closest to the actual result + return (clock + divisor/2) / divisor; +} + + /*! \brief Calculates a clock divider (\e CD) for the USART synchronous master * modes to generate a baud rate as close as possible to the baud rate * set point. diff --git a/src/platform/avr32/usart.h b/src/platform/avr32/usart.h index c066cdcc..d095713a 100644 --- a/src/platform/avr32/usart.h +++ b/src/platform/avr32/usart.h @@ -230,6 +230,16 @@ extern void usart_reset(volatile avr32_usart_t *usart); */ extern int usart_init_rs232(volatile avr32_usart_t *usart, const usart_options_t *opt, long pba_hz); +/*! \brief Returns the actual baud rate set into the USART in async mode + * + * \param usart Base address of the USART instance. + * \param pba_hz USART module input clock frequency (PBA clock, Hz). + * + * \retval baudrate The nearest integer to the actual baud rate + * \retval 0 No baudrate is being generated or some error + */ +extern unsigned int usart_get_async_baudrate(volatile avr32_usart_t *usart, unsigned long pba_hz); + /*! \brief Sets up the USART to use the standard RS232 protocol in TX-only mode. * * Compared to \ref usart_init_rs232, this function allows very high baud rates