228 lines
5.8 KiB
C++
228 lines
5.8 KiB
C++
/*
|
||
HardwareSerial.cpp - Hardware serial library for Wiring
|
||
*/
|
||
|
||
#include "HardwareSerial.h"
|
||
#include <uart_lib.h>
|
||
#include "mik32_hal_irq.h"
|
||
#include "wiring_LL.h"
|
||
|
||
// HardwareSerial class objects for use in Arduino IDE
|
||
HardwareSerial Serial0(0);
|
||
#if SERIAL_PORT_QTY > 1
|
||
HardwareSerial Serial1(1);
|
||
#endif
|
||
// default interface
|
||
HardwareSerial& Serial = DEFAULT_SERIAL;
|
||
|
||
|
||
void serialEvent() __attribute__((weak));
|
||
bool Serial0_available() __attribute__((weak));
|
||
|
||
void serialEventRun(void)
|
||
{
|
||
if (Serial0_available && serialEvent && Serial0_available())
|
||
serialEvent();
|
||
}
|
||
|
||
|
||
// Public Methods
|
||
void HardwareSerial::begin(unsigned long baud, uint8_t config)
|
||
{
|
||
// find the frequency divider (F_CPU is in the preprocessor defines)
|
||
uint32_t brr = (uint32_t)(F_CPU/baud);
|
||
if (brr < 16) // the driver says that the divisor must be at least 16
|
||
brr = 16;
|
||
|
||
// parse config
|
||
uint32_t reg1config = UART_CONTROL1_RE_M | UART_CONTROL1_TE_M | UART_CONTROL1_RXNEIE_M;
|
||
uint32_t reg2config = 0;
|
||
uint32_t reg3config = 0;
|
||
|
||
// first look at parity, because the parity bit is included in the data length
|
||
bool useParity = true;
|
||
if ((config >> 4) == 0) // no - everything is zero, don't set anything in reg1config
|
||
useParity = false;
|
||
else if ((config >> 4) == 2) // even
|
||
reg1config |= UART_CONTROL1_PCE_M;
|
||
else if ((config >> 4) == 3) // odd
|
||
reg1config |= (UART_CONTROL1_PCE_M | UART_CONTROL1_PS_M);
|
||
|
||
// data length
|
||
if (((config & 0x07) == 4) && (useParity == false)) // 7 bit + no parity
|
||
// 7 bits without parity - configure 7 bits
|
||
reg1config |= UART_CONTROL1_M_7BIT_M;
|
||
else if (((config & 0x07) == 6) && (useParity == true)) // 8 bit + parity
|
||
// 8 bits with parity - configure 9 bits
|
||
reg1config |= UART_CONTROL1_M_9BIT_M;
|
||
// if 7 bits with parity or 8 bits without parity - do not change anything,
|
||
// leaving the data length selected as 8 bits
|
||
|
||
// stop bit // stop bit = 1 - everything is zero, don't set anything
|
||
if ((config >> 3) & (0x01 == 1)) // stop bit = 2
|
||
reg2config |= UART_CONTROL2_STOP_1_M;
|
||
|
||
// turn on the receiver and transmitter, apply the parsed config
|
||
if (uartNum == 0)
|
||
{
|
||
UART_Init(UART_0, brr, reg1config, reg2config, reg3config);
|
||
// Enable level-based interrupts for the EPIC_UART_0 line, we have only receive interrupt enabled
|
||
HAL_EPIC_MaskLevelSet(HAL_EPIC_UART_0_MASK);
|
||
isInited = true;
|
||
}
|
||
else if (uartNum == 1)
|
||
{
|
||
UART_Init(UART_1, brr, reg1config, reg2config, reg3config);
|
||
// Enable level-based interrupts for the EPIC_UART_1 line, we have only receive interrupt enabled
|
||
HAL_EPIC_MaskLevelSet(HAL_EPIC_UART_1_MASK);
|
||
isInited = true;
|
||
}
|
||
}
|
||
|
||
void HardwareSerial::end()
|
||
{
|
||
if (isInited)
|
||
{
|
||
// deinit uart and disable uart interrupt
|
||
if (uartNum == 0)
|
||
{
|
||
// wait for the data to be sent if necessary
|
||
UART_WaitDataTranferCompleteFlag(UART_0);
|
||
UART_Deinit(UART_0);
|
||
HAL_EPIC_MaskLevelClear(HAL_EPIC_UART_0_MASK);
|
||
isInited = false;
|
||
}
|
||
else if (uartNum == 1)
|
||
{
|
||
// wait for the data to be sent if necessary
|
||
UART_WaitDataTranferCompleteFlag(UART_1);
|
||
UART_Deinit(UART_1);
|
||
HAL_EPIC_MaskLevelClear(HAL_EPIC_UART_1_MASK);
|
||
isInited = false;
|
||
}
|
||
|
||
// reset buffer indices
|
||
_rx_buffer_head = _rx_buffer_tail = 0;
|
||
}
|
||
}
|
||
|
||
int HardwareSerial::available(void)
|
||
{
|
||
// free space in buffer
|
||
return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE;
|
||
}
|
||
|
||
int HardwareSerial::availableForWrite(void)
|
||
{
|
||
// don't use buffer
|
||
return -1;
|
||
}
|
||
|
||
void HardwareSerial::rx_complete_irq(void)
|
||
{
|
||
// which UART to use
|
||
UART_TypeDef* uart = UART_0;
|
||
if (uartNum == 1)
|
||
uart = UART_1;
|
||
|
||
// find next index in buffer with upper limit
|
||
uint8_t i = (uint8_t)(_rx_buffer_head + 1)%SERIAL_RX_BUFFER_SIZE;
|
||
unsigned char c;
|
||
// while there is something to receive, put the data into the buffer
|
||
// and edit the buffer index
|
||
while(!UART_IS_RX_FIFO_EMPTY(uart))
|
||
{
|
||
c = UART_READ_BYTE(uart);
|
||
if (i != _rx_buffer_tail)
|
||
{
|
||
// write if there is space in the buffer
|
||
_rx_buffer[_rx_buffer_head] = c;
|
||
_rx_buffer_head = i;
|
||
}
|
||
}
|
||
}
|
||
|
||
// wrapper for use in С-files
|
||
extern "C" void __attribute__((optimize("O3"))) serial_interrupt_handler(uint8_t uartNumInt)
|
||
{
|
||
if (uartNumInt == 0)
|
||
{
|
||
Serial0.rx_complete_irq();
|
||
}
|
||
else if ((uartNumInt == 1) && (SERIAL_PORT_QTY > 1))
|
||
{
|
||
Serial1.rx_complete_irq();
|
||
}
|
||
}
|
||
|
||
int HardwareSerial::peek(void)
|
||
{
|
||
if (_rx_buffer_head == _rx_buffer_tail) // nothing to read
|
||
return -1;
|
||
else
|
||
return _rx_buffer[_rx_buffer_tail]; // return first element
|
||
}
|
||
|
||
int HardwareSerial::read(void)
|
||
{
|
||
// if there is nothing to read, return -1
|
||
if (_rx_buffer_head == _rx_buffer_tail)
|
||
return -1;
|
||
else
|
||
{
|
||
// return first element and edit the buffer index
|
||
unsigned char c = _rx_buffer[_rx_buffer_tail];
|
||
_rx_buffer_tail = (uint8_t)(_rx_buffer_tail + 1)%SERIAL_RX_BUFFER_SIZE;
|
||
return (int)c;
|
||
}
|
||
}
|
||
|
||
// write byte
|
||
size_t HardwareSerial::write(uint8_t c)
|
||
{
|
||
if (isInited)
|
||
{
|
||
if (uartNum == 0)
|
||
{
|
||
UART_WriteByte(UART_0, c);
|
||
UART_WaitTransmission(UART_0);
|
||
}
|
||
else if (uartNum == 1)
|
||
{
|
||
UART_WriteByte(UART_1, c);
|
||
UART_WaitTransmission(UART_1);
|
||
}
|
||
return 1;
|
||
}
|
||
else
|
||
return 0;
|
||
}
|
||
|
||
// write bytes buffer
|
||
size_t HardwareSerial::write(const uint8_t *buffer, size_t size)
|
||
{
|
||
if (isInited)
|
||
{
|
||
size_t n = 0;
|
||
while (size--)
|
||
{
|
||
if (HardwareSerial::write(*buffer++))
|
||
n++;
|
||
else
|
||
break;
|
||
}
|
||
return n;
|
||
}
|
||
else
|
||
return 0;
|
||
}
|
||
|
||
void HardwareSerial::flush()
|
||
{
|
||
// wait for the data transfer complete
|
||
if (uartNum == 0)
|
||
UART_WaitDataTranferCompleteFlag(UART_0);
|
||
else if (uartNum == 1)
|
||
UART_WaitDataTranferCompleteFlag(UART_1);
|
||
}
|