/* HardwareSerial.cpp - Hardware serial library for Wiring */ #include "HardwareSerial.h" #include #include "mik32_hal_irq.h" #include "wiring_LL.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_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) { 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); }