diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 6e7e359..af2269d 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -8,13 +8,13 @@ ], "defines": [ "MCU=\"atmega1284p\"", - "BAUD=19200", - "F_CPU=8000000", + "F_CPU=16000000", "_DEBUG=1", "_BUILD_TYPE=\"Debug\"", "_FEATURE_ON=1", "_FEATURE_OFF=0", "_FEATURE_ENABLE_DEBUG_PORT=_FEATURE_ON", + "_FEATURE_OPT_DEBUG_PORT_BAUD=USART_BAUD_38400", "_CONFIG_DFLT_WPM=200", "_CONFIG_DFLT_WPM_ELEMENT_SCALE=1.0f", "_CONFIG_DFLT_BUZZER_ENABLED=true", diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b5858c..0a915f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,8 +37,6 @@ set(DEVICE_MCU atmega1284p CACHE STRING "The MCU model to compile for.") set(DEVICE_F_CPU 16000000 CACHE STRING "The device's CPU frequency, in Hz.") -set(DEVICE_BAUD 19200 - CACHE STRING "The default USART baud rate, in bits per second.") # -- Project Setup -- @@ -75,7 +73,6 @@ add_compile_definitions( # Device information MCU="${DEVICE_MCU}" F_CPU=${DEVICE_F_CPU} - BAUD=${DEVICE_BAUD} # Build type _BUILD_TYPE="${CMAKE_BUILD_TYPE}" $<$:_DEBUG=1> diff --git a/configuration.cmake b/configuration.cmake index d779ae8..828cd56 100644 --- a/configuration.cmake +++ b/configuration.cmake @@ -18,6 +18,17 @@ add_compile_definitions( _FEATURE_ENABLE_DEBUG_PORT=${FEATURE_ENABLE_DEBUG_PORT} ) +# -- Feature Options -- + +# Define values +set(FEATURE_OPT_DEBUG_PORT_BAUD USART_BAUD_38400 + CACHE STRING "Baud rate for debug port. (usart_baud_t)") + +# Set compile definitions +add_compile_definitions( + _FEATURE_OPT_DEBUG_PORT_BAUD=${FEATURE_OPT_DEBUG_PORT_BAUD} +) + # -- Configuration Defaults -- # Define values diff --git a/src/main/application/debug_port.c b/src/main/application/debug_port.c index 6fdfbf2..0a3e558 100644 --- a/src/main/application/debug_port.c +++ b/src/main/application/debug_port.c @@ -266,6 +266,7 @@ void debug_port_init( void ) usart_init( DEBUG_PORT_USART, true, true, + _FEATURE_OPT_DEBUG_PORT_BAUD, USART_DATA_BITS_8, USART_STOP_BITS_1, USART_PARITY_DISABLED ); diff --git a/src/main/drivers/gpio.c b/src/main/drivers/gpio.c index da11608..f6b26af 100644 --- a/src/main/drivers/gpio.c +++ b/src/main/drivers/gpio.c @@ -24,19 +24,19 @@ // Helper macro for the register table below #define gpio_reg( _port, _pin, _pcmsk_reg ) \ - { register_addr( DDR ## _port ), \ - register_addr( PIN ## _port ), \ - register_addr( PORT ## _port ), \ - register_addr( PCMSK ## _pcmsk_reg ), \ + { register8_addr( DDR ## _port ), \ + register8_addr( PIN ## _port ), \ + register8_addr( PORT ## _port ), \ + register8_addr( PCMSK ## _pcmsk_reg ), \ _pin } // This array must be in the same order as the gpio_pin_t enumeration static struct { - register_t ddr_reg; /**< DDR register. */ - register_t in_reg; /**< PIN register. */ - register_t out_reg; /**< PORT register. */ - register_t pcmsk_reg; /**< PCMSK register. */ + register8_t ddr_reg; /**< DDR register. */ + register8_t in_reg; /**< PIN register. */ + register8_t out_reg; /**< PORT register. */ + register8_t pcmsk_reg; /**< PCMSK register. */ uint8_t index; /**< Pin index in port. */ } const s_reg_tbl[] = diff --git a/src/main/drivers/usart.c b/src/main/drivers/usart.c index 70196a6..602535d 100644 --- a/src/main/drivers/usart.c +++ b/src/main/drivers/usart.c @@ -18,7 +18,6 @@ #include #include #include -#include #include "core/sys.h" #include "drivers/usart.h" @@ -29,21 +28,23 @@ /* --------------------------------------------------- CONSTANTS ---------------------------------------------------- */ #define usart_reg( _idx ) \ - { register_addr( UDR ## _idx ), \ - register_addr( UCSR ## _idx ## A ), \ - register_addr( UCSR ## _idx ## B ), \ - register_addr( UCSR ## _idx ## C ), \ - register_addr( UBRR ## _idx ## H ), \ - register_addr( UBRR ## _idx ## L ) } + { register8_addr( UDR ## _idx ), \ + register8_addr( UCSR ## _idx ## A ), \ + register8_addr( UCSR ## _idx ## B ), \ + register8_addr( UCSR ## _idx ## C ), \ + register16_addr( UBRR ## _idx ), \ + register8_addr( UBRR ## _idx ## H ), \ + register8_addr( UBRR ## _idx ## L ) } static struct { - register_t udr; /**< The UDRn register for this USART. */ - register_t ucsra; /**< The UCSRnA register for this USART. */ - register_t ucsrb; /**< The UCSRnB register for this USART. */ - register_t ucsrc; /**< The UCSRnC register for this USART. */ - register_t ubrrh; /**< The UBRRnH register for this USART. */ - register_t ubrrl; /**< The UBRRnL register for this USART. */ + register8_t udr; /**< The UDRn register for this USART. */ + register8_t ucsra; /**< The UCSRnA register for this USART. */ + register8_t ucsrb; /**< The UCSRnB register for this USART. */ + register8_t ucsrc; /**< The UCSRnC register for this USART. */ + register16_t ubrr; /**< The UBRRn register for this USART. */ + register8_t ubrrh; /**< The UBRRnH register for this USART. */ + register8_t ubrrl; /**< The UBRRnL register for this USART. */ } const s_reg_tbl[] = { @@ -69,14 +70,17 @@ _Static_assert( array_count( s_reg_tbl ) == USART_COUNT, "Invalid register table /** * @def TX_DELAY_US * @brief The time to wait before trying again if the TX buffer is full, in microseconds. + * @note This macro uses `19200` as a conservative estimated baud rate. */ -#define TX_DELAY_US ( ( ( USEC_PER_MSEC * MSEC_PER_SEC ) / ( unsigned int )BAUD ) * 2 ) +#define TX_DELAY_US ( ( ( USEC_PER_MSEC * MSEC_PER_SEC ) / ( unsigned int )19200 ) * BITS_PER_BYTE ) /* ----------------------------------------------------- MACROS ----------------------------------------------------- */ // Validation macros #define validate_usart( _usart ) \ assert_always( ( _usart ) < USART_COUNT ) +#define validate_baud( _baud ) \ + assert_always( ( _baud ) < USART_BAUD_COUNT ) #define validate_data_bits( _data_bits ) \ assert_always( ( _data_bits ) < USART_DATA_BITS_COUNT ) #define validate_parity( _parity ) \ @@ -95,6 +99,8 @@ _Static_assert( array_count( s_reg_tbl ) == USART_COUNT, "Invalid register table ( * ( s_reg_tbl[ ( _usart ) ].ucsrb ) ) #define UCSRC( _usart ) \ ( * ( s_reg_tbl[ ( _usart ) ].ucsrc ) ) +#define UBRR( _usart ) \ + ( * ( s_reg_tbl[ ( _usart ) ].ubrr ) ) #define UBRRH( _usart ) \ ( * ( s_reg_tbl[ ( _usart ) ].ubrrh ) ) #define UBRRL( _usart ) \ @@ -149,12 +155,6 @@ static volatile size_t s_tx_tail[ USART_COUNT ]; /* ---------------------------------------------- PROCEDURE PROTOTYPES ---------------------------------------------- */ -/** - * @fn autoconfigure_baud( usart_t ) - * @brief Automatically configures the baud rate for the specified USART based on the `BAUD` macro. - */ -static void autoconfigure_baud( usart_t usart ); - /** * @fn isr_rx_complete( usart_t ) * @brief Runs the USART RX complete interrupt service routine for the specified USART. @@ -185,6 +185,12 @@ static size_t rx_buf_avail( usart_t usart ); */ static size_t rx_buf_count( usart_t usart ); +/** + * @fn set_baud( usart_t, usart_baud_t ) + * @brief Sets the baud rate for the specified USART. + */ +static void set_baud( usart_t usart, usart_baud_t baud ); + /** * @fn set_data_bits( usart_t, usart_data_bits_t ) * @brief Sets the data bits setting for the specified USART. @@ -314,11 +320,13 @@ usart_error_t usart_get_errors( usart_t usart ) void usart_init( usart_t usart, bool rx_enabled, bool tx_enabled, + usart_baud_t baud, usart_data_bits_t data_bits, usart_stop_bits_t stop_bits, usart_parity_t parity ) { validate_usart( usart ); + validate_baud( baud ); validate_data_bits( data_bits ); validate_stop_bits( stop_bits ); validate_parity( parity ); @@ -332,7 +340,7 @@ void usart_init( usart_t usart, TX_TAIL( usart ) = 0; // Configure USART - autoconfigure_baud( usart ); + set_baud( usart, baud ); set_data_bits( usart, data_bits ); set_stop_bits( usart, stop_bits ); set_parity( usart, parity ); @@ -347,20 +355,6 @@ void usart_init( usart_t usart, } /* usart_init() */ -size_t usart_max_rx_size( void ) -{ - return( RX_BUF_SIZE ); - -} /* usart_max_rx_size() */ - - -size_t usart_max_tx_size( void ) -{ - return( TX_BUF_SIZE ); - -} /* usart_max_tx_size() */ - - size_t usart_rx( usart_t usart, byte_t * data, size_t max_size ) { validate_usart( usart ); @@ -449,19 +443,6 @@ size_t usart_tx_str( usart_t usart, char const * str, usart_wait_mode_t wait_mod } /* usart_tx_str() */ -static void autoconfigure_baud( usart_t usart ) -{ - UBRRH( usart ) = UBRRH_VALUE; - UBRRL( usart ) = UBRRL_VALUE; - #if( USE_2X ) - set_bit( UCSRA( usart ), U2X0 ); - #else - clear_bit( UCSRA( usart ), U2X0 ); - #endif - -} /* autoconfigure_baud() */ - - static void isr_rx_complete( usart_t usart, event_t event ) { // If the buffer is full, drop the oldest received byte @@ -523,6 +504,70 @@ static size_t rx_buf_count( usart_t usart ) } /* rx_buf_count() */ +static void set_baud( usart_t usart, usart_baud_t baud ) +{ + _Static_assert( F_CPU == 16000000UL, "Baud settings depend on F_CPU of 16 MHz!" ); + + // Always enable 2X setting + set_bit( UCSRA( usart ), U2X0 ); + + // Set UBRR register based on selected baud rate + // These are taken from table 19-12 in the ATmega1283P data sheet: + // https://ww1.microchip.com/downloads/en/DeviceDoc/ATmega164A_PA-324A_PA-644A_PA-1284_P_Data-Sheet-40002070B.pdf + switch( baud ) + { + case USART_BAUD_2400: + UBRR( usart ) = 832; + break; + + case USART_BAUD_4800: + UBRR( usart ) = 416; + break; + + case USART_BAUD_9600: + UBRR( usart ) = 207; + break; + + case USART_BAUD_14400: + UBRR( usart ) = 138; + break; + + case USART_BAUD_19200: + UBRR( usart ) = 103; + break; + + case USART_BAUD_28800_NOT_RECOMMENDED: + UBRR( usart ) = 68; + break; + + case USART_BAUD_38400: + UBRR( usart ) = 51; + break; + + case USART_BAUD_57600_NOT_RECOMMENDED: + UBRR( usart ) = 34; + break; + + case USART_BAUD_76800: + UBRR( usart ) = 25; + break; + + case USART_BAUD_115200_NOT_RECOMMENDED: + UBRR( usart ) = 16; + break; + + case USART_BAUD_230400_NOT_RECOMMENDED: + UBRR( usart ) = 8; + break; + + case USART_BAUD_250000: + UBRR( usart ) = 7; + break; + } + +} /* set_baud() */ + + static void set_data_bits( usart_t usart, usart_data_bits_t data_bits ) { // Note that UCSZn2 is in UCSRnB, not UCSRnC diff --git a/src/main/drivers/usart.h b/src/main/drivers/usart.h index 72ff1d0..2bd6cdd 100644 --- a/src/main/drivers/usart.h +++ b/src/main/drivers/usart.h @@ -34,6 +34,31 @@ enum USART_COUNT, /**< Number of valid USARTs. */ }; +/** + * @typedef usart_baud_t + * @brief Enumeration of the supported USART baud settings. + * @note The approximate error percentage for each setting is indicated in the comment. Baud settings with an error + * of more than 0.5% are not recommended. + */ +typedef uint8_t usart_baud_t; +enum +{ + USART_BAUD_2400, /**< 2400 baud (0.0% error). */ + USART_BAUD_4800, /**< 4800 baud (-0.1% error). */ + USART_BAUD_9600, /**< 9600 baud (0.2% error). */ + USART_BAUD_14400, /**< 14400 baud (-0.1% error). */ + USART_BAUD_19200, /**< 19200 baud (0.2% error). */ + USART_BAUD_28800_NOT_RECOMMENDED, /**< 28800 baud (0.6% error - N/R). */ + USART_BAUD_38400, /**< 38400 baud (0.2% error). */ + USART_BAUD_57600_NOT_RECOMMENDED, /**< 57600 baud (-0.8% error - N/R). */ + USART_BAUD_76800, /**< 76800 baud (0.2% error). */ + USART_BAUD_115200_NOT_RECOMMENDED, /**< 115200 baud (2.1% error - N/R). */ + USART_BAUD_230400_NOT_RECOMMENDED, /**< 230400 baud (-3.5% error - N/R). */ + USART_BAUD_250000, /**< 250000 baud (0.0% error). */ + + USART_BAUD_COUNT, /**< Number of valid USART baud settings. */ +}; + /** * @typedef usart_data_bits_t * @brief Enumeration of the supported data bits settings for the USARTs. @@ -126,29 +151,18 @@ void usart_deinit( usart_t usart ); usart_error_t usart_get_errors( usart_t usart ); /** - * @fn usart_init( usart_t, bool, bool, usart_data_bits_t, usart_stop_bits_t, usart_parity_t ) + * @fn usart_init( usart_t, bool, bool, usart_baud_t, usart_data_bits_t, usart_stop_bits_t, usart_parity_t ) * @brief Initializes the specified USART with the specified configuration. * @note Must be called prior to attempting any use of the USART. */ void usart_init( usart_t usart, bool rx_enabled, bool tx_enabled, + usart_baud_t baud, usart_data_bits_t data_bits, usart_stop_bits_t stop_bits, usart_parity_t parity ); -/** - * @fn usart_max_rx_size( void ) - * @brief Returns the maximum supported RX buffer size for all USARTs. - */ -size_t usart_max_rx_size( void ); - -/** - * @fn usart_max_tx_size( void ) - * @brief Returns the maximum supported TX buffer size for all USARTs. - */ -size_t usart_max_tx_size( void ); - /** * @fn usart_rx( usart_t, byte_t *, size_t ) * @brief Receives up to `max_size` bytes from the RX buffer for the specified USART. diff --git a/src/main/utility/types.h b/src/main/utility/types.h index 6a106a4..f3d8689 100644 --- a/src/main/utility/types.h +++ b/src/main/utility/types.h @@ -24,10 +24,16 @@ typedef uint8_t byte_t; /** - * @typedef register_t - * @brief Typedef for a pointer to a memory-mapped register. + * @typedef register8_t + * @brief Typedef for a pointer to an 8-bit memory-mapped register. */ -typedef volatile byte_t * register_t; +typedef volatile byte_t * register8_t; + +/** + * @typedef register16_t + * @brief Typedef for a pointer to a 16-bit memory-mapped register. + */ +typedef volatile uint16_t * register16_t; /** * @typedef tick_t @@ -38,10 +44,17 @@ typedef uint32_t tick_t; /* ----------------------------------------------------- MACROS ----------------------------------------------------- */ /** - * @def register_addr( _reg ) - * @brief Returns the address of the specified register as a `register_t`. + * @def register8_addr( _reg ) + * @brief Returns the address of the specified 8-bit register as a `register8_t`. + */ +#define register8_addr( _reg ) \ + ( ( register8_t )( & ( _reg ) ) ) + +/** + * @def register16_addr( _reg ) + * @brief Returns the address of the specified 16-bit register as a `register16_t`. */ -#define register_addr( _reg ) \ - ( ( register_t )( & ( _reg ) ) ) +#define register16_addr( _reg ) \ + ( ( register16_t )( & ( _reg ) ) ) #endif /* !defined( UTILITY_TYPES_H ) */