2016-08-16 11:56:10 +02:00
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*
*/
/** library to control multiple software USARTs (code)
* @ file usart_soft . c
* @ author King Kévin < kingkevin @ cuvoodoo . info >
* @ date 2016
* @ note peripherals used : GPIO @ ref usart_soft_gpio , timer @ ref usart_soft_timer
*/
/* standard libraries */
# include <stdint.h> // standard integer types
# include <stdlib.h> // general utilities
/* STM32 (including CM3) libraries */
# include <libopencm3/stm32/rcc.h> // real-time control clock library
# include <libopencm3/stm32/gpio.h> // general purpose input output library
# include <libopencm3/stm32/timer.h> // timer library
# include <libopencm3/cm3/nvic.h> // interrupt handler
# include "usart_soft.h" // software USART library API
# include "global.h" // common methods
/** @defgroup usart_soft_gpio GPIO used for the software USART ports
* @ {
*/
2016-08-18 10:45:36 +02:00
static const uint32_t usart_soft_rx_ports [ USART_SOFT_RX_PORTS ] = { 0 } ; /**< GPIO ports for receive signals */
static const uint32_t usart_soft_rx_pins [ USART_SOFT_RX_PORTS ] = { 0 } ; /**< GPIO pins for receive signals */
static const uint32_t usart_soft_tx_ports [ USART_SOFT_TX_PORTS ] = { 0 } ; /**< GPIO ports for transmit signals */
static const uint32_t usart_soft_tx_pins [ USART_SOFT_TX_PORTS ] = { 0 } ; /**< GPIO pins for transmit signals */
2016-08-16 11:56:10 +02:00
/** @} */
/** @defgroup usart_soft_config USART configurations
2016-08-18 10:45:36 +02:00
* @ note this implementation is designed for 8 bits , no parity , any stop configuration since this is the most common case
2016-08-16 11:56:10 +02:00
* @ {
*/
2016-08-18 10:45:36 +02:00
static const uint32_t usart_soft_rx_baudrates [ USART_SOFT_RX_PORTS ] = { 9600 } ; /**< receive signal baudrates (2400-115200) */
static const uint32_t usart_soft_tx_baudrates [ USART_SOFT_TX_PORTS ] = { 0 } ; /**< transmit signal baudrates (2400-115200) */
2016-08-16 11:56:10 +02:00
/** @} */
/** @defgroup usart_soft_timer timer used to same USART signals
* @ {
*/
2016-08-18 10:45:36 +02:00
# define USART_SOFT_RX_TIMER 3 /**< timer peripheral for receive signals */
# define USART_SOFT_TX_TIMER 4 /**< timer peripheral for transmit signals */
2016-08-16 11:56:10 +02:00
/** @} */
2016-08-18 10:45:36 +02:00
bool usart_soft_setup ( void )
2016-08-16 11:56:10 +02:00
{
2016-08-18 10:45:36 +02:00
// verify configuration
if ( ( USART_SOFT_RX_PORTS < 0 ) | | ( USART_SOFT_RX_PORTS > 4 ) ) {
return false ;
}
if ( ( USART_SOFT_TX_PORTS < 0 ) | | ( USART_SOFT_TX_PORTS > 4 ) ) {
return false ;
}
for ( uint8_t i = 0 ; i < USART_SOFT_RX_PORTS ; i + + ) {
if ( ( usart_soft_rx_baudrates [ i ] < 2400 ) | | ( usart_soft_rx_baudrates [ i ] > 115200 ) ) {
return false ;
}
}
for ( uint8_t i = 0 ; i < USART_SOFT_TX_PORTS ; i + + ) {
if ( ( usart_soft_tx_baudrates [ i ] < 2400 ) | | ( usart_soft_tx_baudrates [ i ] > 115200 ) ) {
return false ;
}
}
2016-08-16 11:56:10 +02:00
// setup GPIOs
2016-08-18 10:45:36 +02:00
for ( uint8_t i = 0 ; i < USART_SOFT_RX_PORTS ; i + + ) {
rcc_periph_clock_enable ( RCC_GPIO [ usart_soft_rx_ports [ i ] ] ) ; // enable clock for GPIO peripheral
2016-08-18 11:25:11 +02:00
gpio_set_mode ( GPIO_PORT [ usart_soft_rx_ports [ i ] ] , GPIO_MODE_INPUT , GPIO_CNF_INPUT_PULL_UPDOWN , GPIO_PIN ( usart_soft_rx_pins [ i ] ) ) ; // setup GPIO pin USART receive
gpio_set ( GPIO_PORT [ usart_soft_rx_ports [ i ] ] , GPIO_PIN ( usart_soft_rx_pins [ i ] ) ) ; // pull up to avoid noise when not connected
2016-08-18 10:45:36 +02:00
}
for ( uint8_t i = 0 ; i < USART_SOFT_TX_PORTS ; i + + ) {
rcc_periph_clock_enable ( RCC_GPIO [ usart_soft_tx_ports [ i ] ] ) ; // enable clock for GPIO peripheral
2016-08-18 11:25:11 +02:00
gpio_set_mode ( GPIO_PORT [ usart_soft_tx_ports [ i ] ] , GPIO_MODE_OUTPUT_2_MHZ , GPIO_CNF_OUTPUT_PUSHPULL , GPIO_PIN ( usart_soft_tx_pins [ i ] ) ) ; // setup GPIO pin USART transmit
2016-08-16 11:56:10 +02:00
}
2016-08-18 10:45:36 +02:00
// setup timer
if ( USART_SOFT_RX_PORTS > 0 ) {
rcc_periph_clock_enable ( RCC_TIM [ USART_SOFT_RX_TIMER ] ) ; // enable clock for timer peripheral
timer_reset ( TIM [ USART_SOFT_RX_TIMER ] ) ; // reset timer state
timer_set_mode ( TIM [ USART_SOFT_RX_TIMER ] , TIM_CR1_CKD_CK_INT , TIM_CR1_CMS_EDGE , TIM_CR1_DIR_UP ) ; // set timer mode, use undivided timer clock, edge alignment (simple count), and count up
timer_set_prescaler ( TIM [ USART_SOFT_RX_TIMER ] , 0 ) ; // prescaler to be able to sample 2400-115200 bps (72MHz/2^16=1099<2400bps)
nvic_enable_irq ( NVIC_TIM_IRQ [ USART_SOFT_RX_TIMER ] ) ; // allow interrupt for timer
}
if ( USART_SOFT_TX_PORTS > 0 ) {
rcc_periph_clock_enable ( RCC_TIM [ USART_SOFT_TX_TIMER ] ) ; // enable clock for timer peripheral
timer_reset ( TIM [ USART_SOFT_TX_TIMER ] ) ; // reset timer state
timer_set_mode ( TIM [ USART_SOFT_TX_TIMER ] , TIM_CR1_CKD_CK_INT , TIM_CR1_CMS_EDGE , TIM_CR1_DIR_UP ) ; // set timer mode, use undivided timer clock, edge alignment (simple count), and count up
timer_set_prescaler ( TIM [ USART_SOFT_TX_TIMER ] , 0 ) ; // prescaler to be able to sample 2400-115200 bps (72MHz/2^16=1099<2400bps)
nvic_enable_irq ( NVIC_TIM_IRQ [ USART_SOFT_TX_TIMER ] ) ; // allow interrupt for timer
}
return true ; // setup completed
}
void TIM_ISR ( USART_SOFT_RX_TIMER ) ( void )
{
2016-08-16 11:56:10 +02:00
}