diff --git a/src/main.c b/src/main.c index a663072..d635928 100644 --- a/src/main.c +++ b/src/main.c @@ -15,6 +15,7 @@ #include #include "led_chplex.h" +#include "rs485.h" #include "charge_pump.h" #include "power_switch.h" @@ -45,6 +46,9 @@ static void init_clock(void) // Port B is needed for the LEDs rcc_periph_clock_enable(RCC_GPIOB); + + // USART1 is used for RS485 + rcc_periph_clock_enable(RCC_USART1); } @@ -108,6 +112,7 @@ int main(void) init_clock(); init_gpio(); + rs485_init(); charge_pump_init(); power_switch_init(); @@ -116,6 +121,8 @@ int main(void) init_systick(1000); + rs485_enqueue("LNSC-2420 v" VERSION " initialized.\n"); + // triggered every 1 ms while (1) { diff --git a/src/pinout.h b/src/pinout.h index 5ab3f12..492001d 100644 --- a/src/pinout.h +++ b/src/pinout.h @@ -35,4 +35,12 @@ #define ANALOG_INPUT_I_SOLAR 3 #define ANALOG_INPUT_I_LOAD 4 +/* RS485 */ + +#define RS485_PORT GPIOB + +#define RS485_DE_PIN GPIO5 // High = Driver enabled +#define RS485_TX_PIN GPIO6 +#define RS485_RX_PIN GPIO7 + #endif // PINOUT_H diff --git a/src/rs485.c b/src/rs485.c new file mode 100644 index 0000000..1d34dfb --- /dev/null +++ b/src/rs485.c @@ -0,0 +1,122 @@ +#include +#include +#include + +#include "pinout.h" + +#include "rs485.h" + +#define RS485_BUFFER_SIZE 128 +static volatile char debugBuffer[RS485_BUFFER_SIZE]; + +static volatile uint16_t readPos, writePos; +static volatile uint8_t bufferFull, bufferEmpty, usartActive; + +void rs485_init(void) +{ + // initialize the ring buffer + readPos = 0; + writePos = 0; + bufferFull = 0; + bufferEmpty = 1; + usartActive = 0; + + /* Initialize GPIOs */ + + // RS485 drive enable signal + gpio_clear(RS485_PORT, RS485_DE_PIN); + gpio_mode_setup(RS485_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, RS485_DE_PIN); + + // RX and TX pins + gpio_mode_setup(RS485_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, RS485_TX_PIN | RS485_RX_PIN); + gpio_set_af(RS485_PORT, GPIO_AF0, RS485_TX_PIN | RS485_RX_PIN); + + // enable interrupt + nvic_enable_irq(NVIC_USART1_IRQ); + + /* Setup USART1 parameters. */ + usart_set_baudrate(USART1, 115200); + usart_set_databits(USART1, 8); + usart_set_stopbits(USART1, USART_CR2_STOPBITS_1); + usart_set_mode(USART1, USART_MODE_TX); + usart_set_parity(USART1, USART_PARITY_NONE); + usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE); + + /* Enable the USART. */ + usart_enable(USART1); + + /* Enable the USART1 TX Interrupt */ + usart_enable_tx_interrupt(USART1); + usart_enable_tx_complete_interrupt(USART1); +} + + +static void rs485_transfer(void) +{ + if(bufferEmpty) { + usart_disable_tx_interrupt(USART1); + usartActive = 0; + return; + } + + usart_send(USART1, debugBuffer[readPos]); + + readPos++; + if(readPos == RS485_BUFFER_SIZE) { + readPos = 0; + } + + if(readPos == writePos) { + bufferEmpty = 1; + } + + bufferFull = 0; + usart_enable_tx_interrupt(USART1); +} + + +void usart1_isr(void) +{ + if(USART1_ISR & USART_ISR_TXE) { + rs485_transfer(); + } + + if(USART1_ISR & USART_ISR_TC) { + USART1_ICR |= USART_ICR_TCCF; + + if(!usartActive) { + gpio_clear(RS485_PORT, RS485_DE_PIN); + } + } +} + + +void rs485_enqueue(const char *str) +{ + while(*str) { + if(bufferFull) { + break; + } + + debugBuffer[writePos] = *str; + + writePos++; + if(writePos == RS485_BUFFER_SIZE) { + writePos = 0; + } + + if(writePos == readPos) { + bufferFull = 1; + } + + bufferEmpty = 0; + + str++; + } + + if(!usartActive) { + usartActive = 1; + gpio_set(RS485_PORT, RS485_DE_PIN); + rs485_transfer(); + } +} diff --git a/src/rs485.h b/src/rs485.h new file mode 100644 index 0000000..9325daf --- /dev/null +++ b/src/rs485.h @@ -0,0 +1,9 @@ +#ifndef RS485_H +#define RS485_H + +void rs485_init(void); +void rs485_periodic(void); + +void rs485_enqueue(const char *str); + +#endif // RS485_H