elbear_arduino_bsp/cores/arduino/HardwareSerial.cpp
2024-09-05 08:49:43 +03:00

225 lines
5.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
HardwareSerial.cpp - Hardware serial library for Wiring
*/
#include "HardwareSerial.h"
#include <uart_lib.h>
#include "mik32_hal_irq.h"
// HardwareSerial class objects for use in Arduino IDE
HardwareSerial Serial(0);
#if SERIAL_PORT_QTY > 1
HardwareSerial Serial1(1);
#endif
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_IsRxFifoEmpty(uart))
{
c = UART_ReadByte(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 serial_handler_wrapper(uint8_t uartNumInt)
{
if (uartNumInt == 0)
{
Serial.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);
}