/* 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 . * */ /** BusVoodoo RS-485 mode (code) * @file busvoodoo_rs485.c * @author King Kévin * @date 2018 * @note peripherals used: USART @ref busvoodoo_rs485_usart */ /* standard libraries */ #include // standard integer types #include // standard utilities #include // string utilities /* STM32 (including CM3) libraries */ #include // interrupt utilities #include // general purpose input output library #include // real-time control clock library #include // 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 #include "busvoodoo_uart_generic.h" // generic UART mode #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 */ /** @} */ /** enable RS-485 transceiver driver to allow transmitting */ static void busvoodoo_rs485_drive_enable(void) { gpio_set(GPIO(BUSVOODOO_RS485_DE_PORT), GPIO(BUSVOODOO_RS485_DE_PIN)); // set high to enable RS-485 transceiver driver } /** enable RS-485 transceiver driver to allow transmitting */ static void busvoodoo_rs485_drive_disable(void) { gpio_clear(GPIO(BUSVOODOO_RS485_DE_PORT), GPIO(BUSVOODOO_RS485_DE_PIN)); // set low to disable RS-485 transceiver driver } /** enable RS-485 transceiver received to allow receiving */ static void busvoodoo_rs485_receive_enable(void) { gpio_clear(GPIO(BUSVOODOO_RS485_RE_PORT), GPIO(BUSVOODOO_RS485_RE_PIN)); // set high to low enable RS-485 transceiver receiver } /** enable RS-485 transceiver received to allow receiving */ static void busvoodoo_rs485_receive_disable(void) { gpio_set(GPIO(BUSVOODOO_RS485_RE_PORT), GPIO(BUSVOODOO_RS485_RE_PIN)); // set high to disable RS-485 transceiver receiver } #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 */ /** 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, .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), }; /** setup RS-485 mode * @param[out] prefix terminal prompt prefix * @param[in] line terminal prompt line to configure mode * @return if setup is complete */ static bool busvoodoo_rs485_setup(char** prefix, const char* line) { 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