Add serial & UART classes for Modbus use
This commit is contained in:
parent
0857a26f0b
commit
467c6e6d7d
20
Modbus/inc/SerialPort.h
Normal file
20
Modbus/inc/SerialPort.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef SERIALPORT_H_
|
||||
#define SERIALPORT_H_
|
||||
|
||||
#include "Uart.h"
|
||||
|
||||
class SerialPort {
|
||||
public:
|
||||
SerialPort();
|
||||
virtual ~SerialPort();
|
||||
int available();
|
||||
void begin(int speed = 9600);
|
||||
int read();
|
||||
int write(const char* buf, int len);
|
||||
int print(int val, int format);
|
||||
void flush();
|
||||
private:
|
||||
static LpcUart *u;
|
||||
};
|
||||
|
||||
#endif /* SERIALPORT_H_ */
|
||||
62
Modbus/inc/Uart.h
Normal file
62
Modbus/inc/Uart.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* LpcUart.h
|
||||
*
|
||||
* Created on: 4.2.2019
|
||||
* Author: keijo
|
||||
*/
|
||||
|
||||
#ifndef LPCUART_H_
|
||||
#define LPCUART_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "chip.h"
|
||||
|
||||
struct LpcPinMap {
|
||||
int port; /* set to -1 to indicate unused pin */
|
||||
int pin; /* set to -1 to indicate unused pin */
|
||||
};
|
||||
|
||||
struct LpcUartConfig {
|
||||
LPC_USART_T *pUART;
|
||||
uint32_t speed;
|
||||
uint32_t data;
|
||||
bool rs485;
|
||||
LpcPinMap tx;
|
||||
LpcPinMap rx;
|
||||
LpcPinMap rts; /* used as output enable if RS-485 mode is enabled */
|
||||
LpcPinMap cts;
|
||||
};
|
||||
|
||||
|
||||
class LpcUart {
|
||||
public:
|
||||
LpcUart(const LpcUartConfig &cfg);
|
||||
LpcUart(const LpcUart &) = delete;
|
||||
virtual ~LpcUart();
|
||||
int free(); /* get amount of free space in transmit buffer */
|
||||
int peek(); /* get number of received characters in receive buffer */
|
||||
int write(char c);
|
||||
int write(const char *s);
|
||||
int write(const char *buffer, int len);
|
||||
int read(char &c); /* get a single character. Returns number of characters read --> returns 0 if no character is available */
|
||||
int read(char *buffer, int len);
|
||||
void txbreak(bool brk); /* set break signal on */
|
||||
bool rxbreak(); /* check if break is received */
|
||||
void speed(int bps); /* change transmission speed */
|
||||
bool txempty();
|
||||
|
||||
void isr(); /* ISR handler. This will be called by the HW ISR handler. Do not call from application */
|
||||
private:
|
||||
LPC_USART_T *uart;
|
||||
IRQn_Type irqn;
|
||||
/* currently we support only fixed size ring buffers */
|
||||
static const int UART_RB_SIZE = 256;
|
||||
/* Transmit and receive ring buffers */
|
||||
RINGBUFF_T txring;
|
||||
RINGBUFF_T rxring;
|
||||
uint8_t rxbuff[UART_RB_SIZE];
|
||||
uint8_t txbuff[UART_RB_SIZE];
|
||||
static bool init; /* set when first UART is initialized. We have a global clock setting for all UARTSs */
|
||||
};
|
||||
|
||||
#endif /* LPCUART_H_ */
|
||||
50
Modbus/src/SerialPort.cpp
Normal file
50
Modbus/src/SerialPort.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
#include "SerialPort.h"
|
||||
|
||||
|
||||
|
||||
SerialPort::SerialPort() {
|
||||
if(!u) {
|
||||
LpcPinMap none = {-1, -1}; // unused pin has negative values in it
|
||||
LpcPinMap txpin = { 0, 28 }; // transmit pin that goes to rs485 driver chip
|
||||
LpcPinMap rxpin = { 0, 24 }; // receive pin that goes to rs485 driver chip
|
||||
LpcPinMap rtspin = { 1, 0 }; // handshake pin that is used to set tranmitter direction
|
||||
LpcUartConfig cfg = { LPC_USART1, 9600, UART_CFG_DATALEN_8 | UART_CFG_PARITY_NONE | UART_CFG_STOPLEN_2, true, txpin, rxpin, rtspin, none };
|
||||
u = new LpcUart(cfg);
|
||||
}
|
||||
}
|
||||
|
||||
LpcUart *SerialPort::u = nullptr;
|
||||
|
||||
SerialPort::~SerialPort() {
|
||||
/* DeInitialize UART peripheral */
|
||||
delete u;
|
||||
}
|
||||
|
||||
int SerialPort::available() {
|
||||
return u->peek();
|
||||
}
|
||||
|
||||
void SerialPort::begin(int speed) {
|
||||
u->speed(speed);
|
||||
|
||||
}
|
||||
|
||||
int SerialPort::read() {
|
||||
char byte;
|
||||
if(u->read(byte)> 0) return (byte);
|
||||
return -1;
|
||||
}
|
||||
int SerialPort::write(const char* buf, int len) {
|
||||
return u->write(buf, len);
|
||||
}
|
||||
|
||||
int SerialPort::print(int val, int format) {
|
||||
// here only to maintain compatibility with Arduino interface
|
||||
(void) val;
|
||||
(void) format;
|
||||
return (0);
|
||||
}
|
||||
|
||||
void SerialPort::flush() {
|
||||
while(!u->txempty()) __WFI();
|
||||
}
|
||||
227
Modbus/src/Uart.cpp
Normal file
227
Modbus/src/Uart.cpp
Normal file
@ -0,0 +1,227 @@
|
||||
#include <cstring>
|
||||
#include "Uart.h"
|
||||
|
||||
|
||||
static LpcUart *u0;
|
||||
static LpcUart *u1;
|
||||
static LpcUart *u2;
|
||||
|
||||
extern "C" {
|
||||
/**
|
||||
* @brief UART interrupt handler using ring buffers
|
||||
* @return Nothing
|
||||
*/
|
||||
void UART0_IRQHandler(void)
|
||||
{
|
||||
/* Want to handle any errors? Do it here. */
|
||||
|
||||
/* Use default ring buffer handler. Override this with your own
|
||||
code if you need more capability. */
|
||||
if(u0) u0->isr();
|
||||
}
|
||||
|
||||
void UART1_IRQHandler(void)
|
||||
{
|
||||
/* Want to handle any errors? Do it here. */
|
||||
|
||||
/* Use default ring buffer handler. Override this with your own
|
||||
code if you need more capability. */
|
||||
if(u1) u1->isr();
|
||||
}
|
||||
|
||||
void UART2_IRQHandler(void)
|
||||
{
|
||||
/* Want to handle any errors? Do it here. */
|
||||
|
||||
/* Use default ring buffer handler. Override this with your own
|
||||
code if you need more capability. */
|
||||
if(u2) u2->isr();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void LpcUart::isr() {
|
||||
Chip_UART_IRQRBHandler(uart, &rxring, &txring);
|
||||
}
|
||||
|
||||
bool LpcUart::init = false;
|
||||
|
||||
LpcUart::LpcUart(const LpcUartConfig &cfg) {
|
||||
CHIP_SWM_PIN_MOVABLE_T tx;
|
||||
CHIP_SWM_PIN_MOVABLE_T rx;
|
||||
CHIP_SWM_PIN_MOVABLE_T cts;
|
||||
CHIP_SWM_PIN_MOVABLE_T rts;
|
||||
bool use_rts = (cfg.rts.port >= 0);
|
||||
bool use_cts = (cfg.cts.port >= 0);
|
||||
|
||||
if(!init) {
|
||||
init = true;
|
||||
/* Before setting up the UART, the global UART clock for USARTS 1-4
|
||||
* must first be setup. This requires setting the UART divider and
|
||||
* the UART base clock rate to 16x the maximum UART rate for all
|
||||
* UARTs.
|
||||
* */
|
||||
/* Use main clock rate as base for UART baud rate divider */
|
||||
Chip_Clock_SetUARTBaseClockRate(Chip_Clock_GetMainClockRate(), false);
|
||||
}
|
||||
|
||||
uart = nullptr; // set default value before checking which UART to configure
|
||||
|
||||
if(cfg.pUART == LPC_USART0) {
|
||||
if(u0) return; // already exists
|
||||
else u0 = this;
|
||||
tx = SWM_UART0_TXD_O;
|
||||
rx = SWM_UART0_RXD_I;
|
||||
rts = SWM_UART0_RTS_O;
|
||||
cts = SWM_UART0_CTS_I;
|
||||
irqn = UART0_IRQn;
|
||||
}
|
||||
else if(cfg.pUART == LPC_USART1) {
|
||||
if(u1) return; // already exists
|
||||
else u1 = this;
|
||||
tx = SWM_UART1_TXD_O;
|
||||
rx = SWM_UART1_RXD_I;
|
||||
rts = SWM_UART1_RTS_O;
|
||||
cts = SWM_UART1_CTS_I;
|
||||
irqn = UART1_IRQn;
|
||||
}
|
||||
else if(cfg.pUART == LPC_USART2) {
|
||||
if(u2) return; // already exists
|
||||
else u2 = this;
|
||||
tx = SWM_UART2_TXD_O;
|
||||
rx = SWM_UART2_RXD_I;
|
||||
use_rts = false; // UART2 does not support handshakes
|
||||
use_cts = false;
|
||||
irqn = UART2_IRQn;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
uart = cfg.pUART; // set the actual value after validity checking
|
||||
|
||||
|
||||
if(cfg.tx.port >= 0) {
|
||||
Chip_IOCON_PinMuxSet(LPC_IOCON, cfg.tx.port, cfg.tx.pin, (IOCON_MODE_INACT | IOCON_DIGMODE_EN));
|
||||
Chip_SWM_MovablePortPinAssign(tx, cfg.tx.port, cfg.tx.pin);
|
||||
}
|
||||
|
||||
if(cfg.rx.port >= 0) {
|
||||
Chip_IOCON_PinMuxSet(LPC_IOCON, cfg.rx.port, cfg.rx.pin, (IOCON_MODE_INACT | IOCON_DIGMODE_EN));
|
||||
Chip_SWM_MovablePortPinAssign(rx, cfg.rx.port, cfg.rx.pin);
|
||||
}
|
||||
|
||||
if(use_cts) {
|
||||
Chip_IOCON_PinMuxSet(LPC_IOCON, cfg.cts.port, cfg.cts.pin, (IOCON_MODE_INACT | IOCON_DIGMODE_EN));
|
||||
Chip_SWM_MovablePortPinAssign(cts, cfg.cts.port, cfg.cts.pin);
|
||||
}
|
||||
|
||||
if(use_rts) {
|
||||
Chip_IOCON_PinMuxSet(LPC_IOCON, cfg.rts.port, cfg.rts.pin, (IOCON_MODE_INACT | IOCON_DIGMODE_EN));
|
||||
Chip_SWM_MovablePortPinAssign(rts, cfg.rts.port, cfg.rts.pin);
|
||||
}
|
||||
|
||||
|
||||
/* Setup UART */
|
||||
Chip_UART_Init(uart);
|
||||
Chip_UART_ConfigData(uart, cfg.data);
|
||||
Chip_UART_SetBaud(uart, cfg.speed);
|
||||
|
||||
if(use_rts && cfg.rs485) {
|
||||
uart->CFG |= (1 << 20); // enable rs485 mode
|
||||
//uart->CFG |= (1 << 18); // OE turnaraound time
|
||||
uart->CFG |= (1 << 21);// driver enable polarity (active high)
|
||||
}
|
||||
|
||||
Chip_UART_Enable(uart);
|
||||
Chip_UART_TXEnable(uart);
|
||||
|
||||
/* Before using the ring buffers, initialize them using the ring
|
||||
buffer init function */
|
||||
RingBuffer_Init(&rxring, rxbuff, 1, UART_RB_SIZE);
|
||||
RingBuffer_Init(&txring, txbuff, 1, UART_RB_SIZE);
|
||||
|
||||
|
||||
/* Enable receive data and line status interrupt */
|
||||
Chip_UART_IntEnable(uart, UART_INTEN_RXRDY);
|
||||
Chip_UART_IntDisable(uart, UART_INTEN_TXRDY); /* May not be needed */
|
||||
|
||||
/* Enable UART interrupt */
|
||||
NVIC_EnableIRQ(irqn);
|
||||
}
|
||||
|
||||
LpcUart::~LpcUart() {
|
||||
if(uart != nullptr) {
|
||||
NVIC_DisableIRQ(irqn);
|
||||
Chip_UART_IntDisable(uart, UART_INTEN_RXRDY);
|
||||
Chip_UART_IntDisable(uart, UART_INTEN_TXRDY);
|
||||
|
||||
if(uart == LPC_USART0) {
|
||||
u0 = nullptr;
|
||||
}
|
||||
else if(uart == LPC_USART1) {
|
||||
u1 = nullptr;
|
||||
}
|
||||
else if(uart == LPC_USART2) {
|
||||
u2 = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int LpcUart::free()
|
||||
{
|
||||
return RingBuffer_GetCount(&txring);;
|
||||
}
|
||||
|
||||
int LpcUart::peek()
|
||||
{
|
||||
return RingBuffer_GetCount(&rxring);
|
||||
}
|
||||
|
||||
int LpcUart::read(char &c)
|
||||
{
|
||||
return Chip_UART_ReadRB(uart, &rxring, &c, 1);
|
||||
}
|
||||
|
||||
int LpcUart::read(char *buffer, int len)
|
||||
{
|
||||
return Chip_UART_ReadRB(uart, &rxring, buffer, len);
|
||||
}
|
||||
|
||||
int LpcUart::write(char c)
|
||||
{
|
||||
return Chip_UART_SendRB(uart, &txring, &c, 1);
|
||||
}
|
||||
|
||||
int LpcUart::write(const char *s)
|
||||
{
|
||||
return Chip_UART_SendRB(uart, &txring, s, strlen(s));
|
||||
}
|
||||
|
||||
int LpcUart::write(const char *buffer, int len)
|
||||
{
|
||||
return Chip_UART_SendRB(uart, &txring, buffer, len);
|
||||
}
|
||||
|
||||
void LpcUart::txbreak(bool brk)
|
||||
{
|
||||
// break handling not implemented yeet
|
||||
}
|
||||
|
||||
bool LpcUart::rxbreak()
|
||||
{
|
||||
// break handling not implemented yeet
|
||||
return false;
|
||||
}
|
||||
|
||||
void LpcUart::speed(int bps)
|
||||
{
|
||||
Chip_UART_SetBaud(uart, bps);
|
||||
}
|
||||
|
||||
bool LpcUart::txempty()
|
||||
{
|
||||
return (RingBuffer_GetCount(&txring) == 0);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user