Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
3 changes: 0 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 --

Expand Down Expand Up @@ -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}"
$<$<CONFIG:Debug>:_DEBUG=1>
Expand Down
11 changes: 11 additions & 0 deletions configuration.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/main/application/debug_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down
16 changes: 8 additions & 8 deletions src/main/drivers/gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[] =
Expand Down
141 changes: 93 additions & 48 deletions src/main/drivers/usart.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
#include <util/setbaud.h>

#include "core/sys.h"
#include "drivers/usart.h"
Expand All @@ -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[] =
{
Expand All @@ -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 ) \
Expand All @@ -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 ) \
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 );
Expand All @@ -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 );
Expand All @@ -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 );
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
40 changes: 27 additions & 13 deletions src/main/drivers/usart.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
Loading