LNSC-2420-Firmware/src/rs485.c

139 lines
2.5 KiB
C

#include <libopencm3/stm32/usart.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/cm3/nvic.h>
#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();
}
}
void rs485_deepsleep_prepare(void)
{
// force the transceiver to RX mode
gpio_clear(RS485_PORT, RS485_DE_PIN);
}
void rs485_deepsleep_resume(void)
{
// if a transmission is still in progress, switch to TX mode again
if(usartActive) {
gpio_set(RS485_PORT, RS485_DE_PIN);
}
}