2018-05-01 13:44:28 +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/>.
*
*/
/** BusVoodoo RS-485 mode (code)
* @ file busvoodoo_rs485 . c
* @ author King Kévin < kingkevin @ cuvoodoo . info >
* @ date 2018
* @ note peripherals used : USART @ ref busvoodoo_rs485_usart
*/
/* standard libraries */
# include <stdint.h> // standard integer types
# include <stdlib.h> // standard utilities
# include <string.h> // string utilities
/* STM32 (including CM3) libraries */
2018-07-13 18:32:15 +02:00
# include <libopencm3/cm3/nvic.h> // interrupt utilities
2018-05-01 13:44:28 +02:00
# include <libopencm3/stm32/gpio.h> // general purpose input output library
# include <libopencm3/stm32/rcc.h> // real-time control clock library
# include <libopencm3/stm32/usart.h> // USART utilities
/* own libraries */
# include "global.h" // board definitions
# include "print.h" // printing utilities
# include "menu.h" // menu definitions
# include "busvoodoo_global.h" // BusVoodoo definitions
# include "busvoodoo_oled.h" // OLED utilities
2018-06-17 12:11:34 +02:00
# include "busvoodoo_uart_generic.h" // generic UART mode
2018-05-01 13:44:28 +02:00
# include "busvoodoo_rs485.h" // own definitions
/** @defgroup busvoodoo_rs485_usart USART peripheral used for RS-485/422 communication, using a RS-485/422 transceiver
* @ {
*/
# define BUSVOODOO_RS485_USART 2 /**< USART peripheral */
/** @} */
2018-06-17 12:11:34 +02:00
/** enable RS-485 transceiver driver to allow transmitting */
static void busvoodoo_rs485_drive_enable ( void )
2018-05-01 13:44:28 +02:00
{
2018-06-17 12:11:34 +02:00
gpio_set ( GPIO ( BUSVOODOO_RS485_DE_PORT ) , GPIO ( BUSVOODOO_RS485_DE_PIN ) ) ; // set high to enable RS-485 transceiver driver
2018-05-01 13:44:28 +02:00
}
2018-06-17 12:11:34 +02:00
/** enable RS-485 transceiver driver to allow transmitting */
static void busvoodoo_rs485_drive_disable ( void )
2018-05-01 13:44:28 +02:00
{
gpio_clear ( GPIO ( BUSVOODOO_RS485_DE_PORT ) , GPIO ( BUSVOODOO_RS485_DE_PIN ) ) ; // set low to disable RS-485 transceiver driver
}
2018-06-17 12:11:34 +02:00
/** enable RS-485 transceiver received to allow receiving */
static void busvoodoo_rs485_receive_enable ( void )
2018-05-01 13:44:28 +02:00
{
gpio_clear ( GPIO ( BUSVOODOO_RS485_RE_PORT ) , GPIO ( BUSVOODOO_RS485_RE_PIN ) ) ; // set high to low enable RS-485 transceiver receiver
}
2018-06-17 12:11:34 +02:00
/** enable RS-485 transceiver received to allow receiving */
static void busvoodoo_rs485_receive_disable ( void )
2018-05-01 13:44:28 +02:00
{
2018-06-17 12:11:34 +02:00
gpio_set ( GPIO ( BUSVOODOO_RS485_RE_PORT ) , GPIO ( BUSVOODOO_RS485_RE_PIN ) ) ; // set high to disable RS-485 transceiver receiver
2018-05-01 13:44:28 +02:00
}
2018-07-13 18:32:15 +02:00
# define BUSVOODOO_RS485_RX_TIMER 2 /**< timer ID to capture RX edges */
# define BUSVOODOO_RS485_RX_CHANNEL 4 /**< channel ID used as input capture to capture RX edges */
2018-06-17 12:11:34 +02:00
/** RS-485 specific methods that will be called by the generic methods */
static const struct busvoodoo_uart_generic_specific_t busvoodoo_uart_generic_rs485 = {
. usart = USART ( BUSVOODOO_RS485_USART ) ,
. usart_rcc = RCC_USART ( BUSVOODOO_RS485_USART ) ,
. usart_rst = RST_USART ( BUSVOODOO_RS485_USART ) ,
. multidrive = false ,
. tx_port = USART_TX_PORT ( BUSVOODOO_RS485_USART ) ,
. tx_pin = USART_TX_PIN ( BUSVOODOO_RS485_USART ) ,
. tx_rcc = RCC_USART_PORT ( BUSVOODOO_RS485_USART ) ,
. tx_pre = & busvoodoo_rs485_drive_enable ,
. tx_post = & busvoodoo_rs485_drive_disable ,
. rx_port = USART_RX_PORT ( BUSVOODOO_RS485_USART ) ,
. rx_pin = USART_RX_PIN ( BUSVOODOO_RS485_USART ) ,
. rx_rcc = RCC_USART_PORT ( BUSVOODOO_RS485_USART ) ,
. rx_pre = & busvoodoo_rs485_receive_enable ,
. rx_post = & busvoodoo_rs485_receive_disable ,
. hwflowctl = false ,
. rts_port = 0 ,
. rts_pin = 0 ,
. rts_rcc = 0 ,
. cts_port = 0 ,
. cts_pin = 0 ,
. cts_rcc = 0 ,
2018-07-13 18:32:15 +02:00
. timer = TIM ( BUSVOODOO_RS485_RX_TIMER ) ,
. timer_rcc = RCC_TIM ( BUSVOODOO_RS485_RX_TIMER ) ,
. timer_port = TIM_CH_PORT ( BUSVOODOO_RS485_RX_TIMER , BUSVOODOO_RS485_RX_CHANNEL ) ,
. timer_port_rcc = RCC_TIM_CH ( BUSVOODOO_RS485_RX_TIMER , BUSVOODOO_RS485_RX_CHANNEL ) ,
. timer_pin = TIM_CH_PIN ( BUSVOODOO_RS485_RX_TIMER , BUSVOODOO_RS485_RX_CHANNEL ) ,
. timer_ic = TIM_IC ( BUSVOODOO_RS485_RX_CHANNEL ) ,
. timer_ic_in_ti = TIM_IC_IN_TI ( BUSVOODOO_RS485_RX_CHANNEL ) ,
. timer_sr_ccif = TIM_SR_CCIF ( BUSVOODOO_RS485_RX_CHANNEL ) ,
. timer_sr_ccof = TIM_SR_CCOF ( BUSVOODOO_RS485_RX_CHANNEL ) ,
. timer_ccr = & TIM_CCR ( BUSVOODOO_RS485_RX_TIMER , BUSVOODOO_RS485_RX_CHANNEL ) ,
. timer_dier_ccie = TIM_DIER_CCIE ( BUSVOODOO_RS485_RX_CHANNEL ) ,
. timer_nvic_irq = NVIC_TIM_IRQ ( BUSVOODOO_RS485_RX_TIMER ) ,
2018-06-17 12:11:34 +02:00
} ;
2018-05-01 13:44:28 +02:00
2018-06-17 12:11:34 +02:00
/** setup RS-485 mode
* @ param [ out ] prefix terminal prompt prefix
* @ param [ in ] line terminal prompt line to configure mode
* @ return if setup is complete
2018-05-01 13:44:28 +02:00
*/
2018-06-17 12:11:34 +02:00
static bool busvoodoo_rs485_setup ( char * * prefix , const char * line )
2018-05-01 13:44:28 +02:00
{
2018-06-17 12:11:34 +02:00
bool complete = false ; // is the setup complete
if ( NULL = = line ) { // first call
busvoodoo_uart_generic_configure ( & busvoodoo_uart_generic_rs485 ) ; // provide the RS-485 specific information
}
complete = busvoodoo_uart_generic_setup ( prefix , line ) ; // configure underlying generic UART
if ( complete ) { // generic configuration finished
gpio_clear ( GPIO ( BUSVOODOO_RS485_DE_PORT ) , GPIO ( BUSVOODOO_RS485_DE_PIN ) ) ; // set low to disable RS-485 transceiver drive
gpio_set_mode ( GPIO ( BUSVOODOO_RS485_DE_PORT ) , GPIO_MODE_OUTPUT_10_MHZ , GPIO_CNF_OUTPUT_PUSHPULL , GPIO ( BUSVOODOO_RS485_DE_PIN ) ) ; // setup RS-485 Drive Enable GPIO as output (pulled low to disable by default)
gpio_set ( GPIO ( BUSVOODOO_RS485_RE_PORT ) , GPIO ( BUSVOODOO_RS485_RE_PIN ) ) ; // set RS-485 transceiver Receive Enable pin high to disable received
gpio_set_mode ( GPIO ( BUSVOODOO_RS485_RE_PORT ) , GPIO_MODE_OUTPUT_10_MHZ , GPIO_CNF_OUTPUT_OPENDRAIN , GPIO ( BUSVOODOO_RS485_RE_PIN ) ) ; // setup RS-485 Receive Enable GPIO as output (pulled high to disable by default)
busvoodoo_led_blue_off ( ) ; // disable blue LED because there is no activity
* prefix = " RS-485/422 " ; // display mode
busvoodoo_oled_text_left ( * prefix ) ; // set mode title on OLED display
const char * pinout_io [ 10 ] = { " GND " , " 5V " , " 3V3 " , " LV " , NULL , NULL , NULL , NULL , NULL , NULL } ; // RS-485 mode I/O pinout
for ( uint8_t i = 0 ; i < LENGTH ( pinout_io ) & & i < LENGTH ( busvoodoo_global_pinout_io ) ; i + + ) {
busvoodoo_global_pinout_io [ i ] = pinout_io [ i ] ; // set pin names
2018-05-01 13:44:28 +02:00
}
2018-06-17 12:11:34 +02:00
# if BUSVOODOO_HARDWARE_VERSION==0
const char * pinout_rscan [ 5 ] = { " HV " , NULL , NULL , " B " , " A " } ; // RS-485 mode RS/CAN pinout for hardware version 0
# else
const char * pinout_rscan [ 5 ] = { " HV " , NULL , " A " , " B " , NULL } ; // RS-485 mode RS/CAN pinout
# endif
for ( uint8_t i = 0 ; i < LENGTH ( pinout_rscan ) & & i < LENGTH ( busvoodoo_global_pinout_rscan ) ; i + + ) {
busvoodoo_global_pinout_rscan [ i ] = pinout_rscan [ i ] ; // set pin names
2018-05-01 13:44:28 +02:00
}
2018-06-17 12:11:34 +02:00
const char * pinout [ 10 ] = { pinout_rscan [ 0 ] , pinout_io [ 0 ] , pinout_rscan [ 1 ] , pinout_io [ 2 ] , pinout_rscan [ 2 ] , pinout_io [ 4 ] , pinout_rscan [ 3 ] , pinout_io [ 6 ] , pinout_rscan [ 4 ] , pinout_io [ 8 ] } ; // pinout to display
busvoodoo_oled_text_pinout ( ( const char * * ) pinout , false ) ; // set pinout on display
busvoodoo_oled_update ( ) ; // update display to show text and pinout
2018-05-01 13:44:28 +02:00
}
2018-06-17 12:11:34 +02:00
return complete ;
2018-05-01 13:44:28 +02:00
}
2018-06-17 12:11:34 +02:00
/** exit RS-485 mode
2018-05-01 13:44:28 +02:00
*/
2018-06-17 12:11:34 +02:00
static void busvoodoo_rs485_exit ( void )
2018-05-01 13:44:28 +02:00
{
2018-06-17 12:11:34 +02:00
busvoodoo_uart_generic_exit ( ) ; // exiting the underlying generic UART does everything we need
2018-05-01 13:44:28 +02:00
gpio_set ( GPIO ( BUSVOODOO_RS485_RE_PORT ) , GPIO ( BUSVOODOO_RS485_RE_PIN ) ) ; // set high to disable RS-485 transceiver receiver
2018-06-17 12:11:34 +02:00
gpio_clear ( GPIO ( BUSVOODOO_RS485_DE_PORT ) , GPIO ( BUSVOODOO_RS485_DE_PIN ) ) ; // set low to disable RS-485 transceiver driver
2018-05-01 13:44:28 +02:00
}
const struct busvoodoo_mode_t busvoodoo_rs485_mode = {
. name = " rs485 " ,
. description = " Recommended Standard 485/422 " ,
. full_only = true ,
. setup = & busvoodoo_rs485_setup ,
2018-06-17 12:11:34 +02:00
. commands = busvoodoo_uart_generic_commands ,
. commands_nb = busvoodoo_uart_generic_commands_nb ,
2018-05-01 13:44:28 +02:00
. exit = & busvoodoo_rs485_exit ,
} ;