New HardwareTimer for STM32 5.7.0 (#15655)
parent
4762dfe797
commit
ac71cdc265
@ -0,0 +1,391 @@
|
|||||||
|
/*
|
||||||
|
* SoftwareSerial.cpp (formerly NewSoftSerial.cpp)
|
||||||
|
*
|
||||||
|
* Multi-instance software serial library for Arduino/Wiring
|
||||||
|
* -- Interrupt-driven receive and other improvements by ladyada
|
||||||
|
* (http://ladyada.net)
|
||||||
|
* -- Tuning, circular buffer, derivation from class Print/Stream,
|
||||||
|
* multi-instance support, porting to 8MHz processors,
|
||||||
|
* various optimizations, PROGMEM delay tables, inverse logic and
|
||||||
|
* direct port writing by Mikal Hart (http://www.arduiniana.org)
|
||||||
|
* -- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com)
|
||||||
|
* -- 20MHz processor support by Garrett Mace (http://www.macetech.com)
|
||||||
|
* -- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/)
|
||||||
|
* -- STM32 support by Armin van der Togt
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* The latest version of this library can always be found at
|
||||||
|
* http://arduiniana.org.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Includes
|
||||||
|
//
|
||||||
|
#include "SoftwareSerial.h"
|
||||||
|
#include <timer.h>
|
||||||
|
|
||||||
|
#define OVERSAMPLE 3 // in RX, Timer will generate interruption OVERSAMPLE time during a bit. Thus OVERSAMPLE ticks in a bit. (interrupt not synchonized with edge).
|
||||||
|
|
||||||
|
// defined in bit-periods
|
||||||
|
#define HALFDUPLEX_SWITCH_DELAY 5
|
||||||
|
// It's best to define TIMER_SERIAL in variant.h. If not defined, we choose one here
|
||||||
|
// The order is based on (lack of) features and compare channels, we choose the simplest available
|
||||||
|
// because we only need an update interrupt
|
||||||
|
#if !defined(TIMER_SERIAL)
|
||||||
|
#if defined (TIM18_BASE)
|
||||||
|
#define TIMER_SERIAL TIM18
|
||||||
|
#elif defined (TIM7_BASE)
|
||||||
|
#define TIMER_SERIAL TIM7
|
||||||
|
#elif defined (TIM6_BASE)
|
||||||
|
#define TIMER_SERIAL TIM6
|
||||||
|
#elif defined (TIM22_BASE)
|
||||||
|
#define TIMER_SERIAL TIM22
|
||||||
|
#elif defined (TIM21_BASE)
|
||||||
|
#define TIMER_SERIAL TIM21
|
||||||
|
#elif defined (TIM17_BASE)
|
||||||
|
#define TIMER_SERIAL TIM17
|
||||||
|
#elif defined (TIM16_BASE)
|
||||||
|
#define TIMER_SERIAL TIM16
|
||||||
|
#elif defined (TIM15_BASE)
|
||||||
|
#define TIMER_SERIAL TIM15
|
||||||
|
#elif defined (TIM14_BASE)
|
||||||
|
#define TIMER_SERIAL TIM14
|
||||||
|
#elif defined (TIM13_BASE)
|
||||||
|
#define TIMER_SERIAL TIM13
|
||||||
|
#elif defined (TIM11_BASE)
|
||||||
|
#define TIMER_SERIAL TIM11
|
||||||
|
#elif defined (TIM10_BASE)
|
||||||
|
#define TIMER_SERIAL TIM10
|
||||||
|
#elif defined (TIM12_BASE)
|
||||||
|
#define TIMER_SERIAL TIM12
|
||||||
|
#elif defined (TIM19_BASE)
|
||||||
|
#define TIMER_SERIAL TIM19
|
||||||
|
#elif defined (TIM9_BASE)
|
||||||
|
#define TIMER_SERIAL TIM9
|
||||||
|
#elif defined (TIM5_BASE)
|
||||||
|
#define TIMER_SERIAL TIM5
|
||||||
|
#elif defined (TIM4_BASE)
|
||||||
|
#define TIMER_SERIAL TIM4
|
||||||
|
#elif defined (TIM3_BASE)
|
||||||
|
#define TIMER_SERIAL TIM3
|
||||||
|
#elif defined (TIM2_BASE)
|
||||||
|
#define TIMER_SERIAL TIM2
|
||||||
|
#elif defined (TIM20_BASE)
|
||||||
|
#define TIMER_SERIAL TIM20
|
||||||
|
#elif defined (TIM8_BASE)
|
||||||
|
#define TIMER_SERIAL TIM8
|
||||||
|
#elif defined (TIM1_BASE)
|
||||||
|
#define TIMER_SERIAL TIM1
|
||||||
|
#else
|
||||||
|
#error No suitable timer found for SoftwareSerial, define TIMER_SERIAL in variant.h
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
//
|
||||||
|
// Statics
|
||||||
|
//
|
||||||
|
HardwareTimer SoftwareSerial::timer(TIMER_SERIAL);
|
||||||
|
const IRQn_Type SoftwareSerial::timer_interrupt_number = static_cast<IRQn_Type>(getTimerUpIrq(TIMER_SERIAL));
|
||||||
|
uint32_t SoftwareSerial::timer_interrupt_priority = NVIC_EncodePriority(NVIC_GetPriorityGrouping(), TIM_IRQ_PRIO, TIM_IRQ_SUBPRIO);
|
||||||
|
SoftwareSerial *SoftwareSerial::active_listener = nullptr;
|
||||||
|
SoftwareSerial *volatile SoftwareSerial::active_out = nullptr;
|
||||||
|
SoftwareSerial *volatile SoftwareSerial::active_in = nullptr;
|
||||||
|
int32_t SoftwareSerial::tx_tick_cnt = 0; // OVERSAMPLE ticks needed for a bit
|
||||||
|
int32_t volatile SoftwareSerial::rx_tick_cnt = 0; // OVERSAMPLE ticks needed for a bit
|
||||||
|
uint32_t SoftwareSerial::tx_buffer = 0;
|
||||||
|
int32_t SoftwareSerial::tx_bit_cnt = 0;
|
||||||
|
uint32_t SoftwareSerial::rx_buffer = 0;
|
||||||
|
int32_t SoftwareSerial::rx_bit_cnt = -1; // rx_bit_cnt = -1 : waiting for start bit
|
||||||
|
uint32_t SoftwareSerial::cur_speed = 0;
|
||||||
|
|
||||||
|
void SoftwareSerial::setInterruptPriority(uint32_t preemptPriority, uint32_t subPriority) {
|
||||||
|
timer_interrupt_priority = NVIC_EncodePriority(NVIC_GetPriorityGrouping(), preemptPriority, subPriority);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Private methods
|
||||||
|
//
|
||||||
|
|
||||||
|
void SoftwareSerial::setSpeed(uint32_t speed) {
|
||||||
|
if (speed != cur_speed) {
|
||||||
|
timer.pause();
|
||||||
|
if (speed != 0) {
|
||||||
|
// Disable the timer
|
||||||
|
uint32_t clock_rate, cmp_value;
|
||||||
|
// Get timer clock
|
||||||
|
clock_rate = timer.getTimerClkFreq();
|
||||||
|
int pre = 1;
|
||||||
|
// Calculate prescale an compare value
|
||||||
|
do {
|
||||||
|
cmp_value = clock_rate / (speed * OVERSAMPLE);
|
||||||
|
if (cmp_value >= UINT16_MAX) {
|
||||||
|
clock_rate /= 2;
|
||||||
|
pre *= 2;
|
||||||
|
}
|
||||||
|
} while (cmp_value >= UINT16_MAX);
|
||||||
|
timer.setPrescaleFactor(pre);
|
||||||
|
timer.setOverflow(cmp_value);
|
||||||
|
timer.setCount(0);
|
||||||
|
timer.attachInterrupt(&handleInterrupt);
|
||||||
|
timer.resume();
|
||||||
|
NVIC_SetPriority(timer_interrupt_number, timer_interrupt_priority);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
timer.detachInterrupt();
|
||||||
|
cur_speed = speed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function sets the current object as the "listening"
|
||||||
|
// one and returns true if it replaces another
|
||||||
|
bool SoftwareSerial::listen() {
|
||||||
|
if (active_listener != this) {
|
||||||
|
// wait for any transmit to complete as we may change speed
|
||||||
|
while (active_out);
|
||||||
|
active_listener->stopListening();
|
||||||
|
rx_tick_cnt = 1; // 1 : next interrupt will decrease rx_tick_cnt to 0 which means RX pin level will be considered.
|
||||||
|
rx_bit_cnt = -1; // rx_bit_cnt = -1 : waiting for start bit
|
||||||
|
setSpeed(_speed);
|
||||||
|
active_listener = this;
|
||||||
|
if (!_half_duplex) active_in = this;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop listening. Returns true if we were actually listening.
|
||||||
|
bool SoftwareSerial::stopListening() {
|
||||||
|
if (active_listener == this) {
|
||||||
|
// wait for any output to complete
|
||||||
|
while (active_out);
|
||||||
|
if (_half_duplex) setRXTX(false);
|
||||||
|
active_listener = nullptr;
|
||||||
|
active_in = nullptr;
|
||||||
|
// turn off ints
|
||||||
|
setSpeed(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SoftwareSerial::setTX() {
|
||||||
|
if (_inverse_logic)
|
||||||
|
LL_GPIO_ResetOutputPin(_transmitPinPort, _transmitPinNumber);
|
||||||
|
else
|
||||||
|
LL_GPIO_SetOutputPin(_transmitPinPort, _transmitPinNumber);
|
||||||
|
pinMode(_transmitPin, OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SoftwareSerial::setRX() {
|
||||||
|
pinMode(_receivePin, _inverse_logic ? INPUT_PULLDOWN : INPUT_PULLUP); // pullup for normal logic!
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SoftwareSerial::setRXTX(bool input) {
|
||||||
|
if (_half_duplex) {
|
||||||
|
if (input) {
|
||||||
|
if (active_in != this) {
|
||||||
|
setRX();
|
||||||
|
rx_bit_cnt = -1; // rx_bit_cnt = -1 : waiting for start bit
|
||||||
|
rx_tick_cnt = 2; // 2 : next interrupt will be discarded. 2 interrupts required to consider RX pin level
|
||||||
|
active_in = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (active_in == this) {
|
||||||
|
setTX();
|
||||||
|
active_in = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SoftwareSerial::send() {
|
||||||
|
if (--tx_tick_cnt <= 0) { // if tx_tick_cnt > 0 interrupt is discarded. Only when tx_tick_cnt reaches 0 is TX pin set.
|
||||||
|
if (tx_bit_cnt++ < 10) { // tx_bit_cnt < 10 transmission is not finished (10 = 1 start +8 bits + 1 stop)
|
||||||
|
// Send data (including start and stop bits)
|
||||||
|
if (tx_buffer & 1)
|
||||||
|
LL_GPIO_SetOutputPin(_transmitPinPort, _transmitPinNumber);
|
||||||
|
else
|
||||||
|
LL_GPIO_ResetOutputPin(_transmitPinPort, _transmitPinNumber);
|
||||||
|
tx_buffer >>= 1;
|
||||||
|
tx_tick_cnt = OVERSAMPLE; // Wait OVERSAMPLE ticks to send next bit
|
||||||
|
}
|
||||||
|
else { // Transmission finished
|
||||||
|
tx_tick_cnt = 1;
|
||||||
|
if (_output_pending) {
|
||||||
|
active_out = nullptr;
|
||||||
|
|
||||||
|
// In half-duplex mode wait HALFDUPLEX_SWITCH_DELAY bit-periods after the byte has
|
||||||
|
// been transmitted before allowing the switch to RX mode
|
||||||
|
}
|
||||||
|
else if (tx_bit_cnt > 10 + OVERSAMPLE * HALFDUPLEX_SWITCH_DELAY) {
|
||||||
|
if (_half_duplex && active_listener == this) setRXTX(true);
|
||||||
|
active_out = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// The receive routine called by the interrupt handler
|
||||||
|
//
|
||||||
|
inline void SoftwareSerial::recv() {
|
||||||
|
if (--rx_tick_cnt <= 0) { // if rx_tick_cnt > 0 interrupt is discarded. Only when rx_tick_cnt reaches 0 is RX pin considered
|
||||||
|
bool inbit = LL_GPIO_IsInputPinSet(_receivePinPort, _receivePinNumber) ^ _inverse_logic;
|
||||||
|
if (rx_bit_cnt == -1) { // rx_bit_cnt = -1 : waiting for start bit
|
||||||
|
if (!inbit) {
|
||||||
|
// got start bit
|
||||||
|
rx_bit_cnt = 0; // rx_bit_cnt == 0 : start bit received
|
||||||
|
rx_tick_cnt = OVERSAMPLE + 1; // Wait 1 bit (OVERSAMPLE ticks) + 1 tick in order to sample RX pin in the middle of the edge (and not too close to the edge)
|
||||||
|
rx_buffer = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
rx_tick_cnt = 1; // Waiting for start bit, but wrong level. Wait for next Interrupt to check RX pin level
|
||||||
|
}
|
||||||
|
else if (rx_bit_cnt >= 8) { // rx_bit_cnt >= 8 : waiting for stop bit
|
||||||
|
if (inbit) {
|
||||||
|
// Stop-bit read complete. Add to buffer.
|
||||||
|
uint8_t next = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF;
|
||||||
|
if (next != _receive_buffer_head) {
|
||||||
|
// save new data in buffer: tail points to byte destination
|
||||||
|
_receive_buffer[_receive_buffer_tail] = rx_buffer; // save new byte
|
||||||
|
_receive_buffer_tail = next;
|
||||||
|
}
|
||||||
|
else // rx_bit_cnt = x with x = [0..7] correspond to new bit x received
|
||||||
|
_buffer_overflow = true;
|
||||||
|
}
|
||||||
|
// Full trame received. Restart waiting for start bit at next interrupt
|
||||||
|
rx_tick_cnt = 1;
|
||||||
|
rx_bit_cnt = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// data bits
|
||||||
|
rx_buffer >>= 1;
|
||||||
|
if (inbit) rx_buffer |= 0x80;
|
||||||
|
rx_bit_cnt++; // Prepare for next bit
|
||||||
|
rx_tick_cnt = OVERSAMPLE; // Wait OVERSAMPLE ticks before sampling next bit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Interrupt handling
|
||||||
|
//
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
inline void SoftwareSerial::handleInterrupt(HardwareTimer*) {
|
||||||
|
if (active_in) active_in->recv();
|
||||||
|
if (active_out) active_out->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Constructor
|
||||||
|
//
|
||||||
|
SoftwareSerial::SoftwareSerial(uint16_t receivePin, uint16_t transmitPin, bool inverse_logic /* = false */) :
|
||||||
|
_receivePin(receivePin),
|
||||||
|
_transmitPin(transmitPin),
|
||||||
|
_receivePinPort(digitalPinToPort(receivePin)),
|
||||||
|
_receivePinNumber(STM_LL_GPIO_PIN(digitalPinToPinName(receivePin))),
|
||||||
|
_transmitPinPort(digitalPinToPort(transmitPin)),
|
||||||
|
_transmitPinNumber(STM_LL_GPIO_PIN(digitalPinToPinName(transmitPin))),
|
||||||
|
_speed(0),
|
||||||
|
_buffer_overflow(false),
|
||||||
|
_inverse_logic(inverse_logic),
|
||||||
|
_half_duplex(receivePin == transmitPin),
|
||||||
|
_output_pending(0),
|
||||||
|
_receive_buffer_tail(0),
|
||||||
|
_receive_buffer_head(0)
|
||||||
|
{
|
||||||
|
if ((receivePin < NUM_DIGITAL_PINS) || (transmitPin < NUM_DIGITAL_PINS)) {
|
||||||
|
/* Enable GPIO clock for tx and rx pin*/
|
||||||
|
set_GPIO_Port_Clock(STM_PORT(digitalPinToPinName(transmitPin)));
|
||||||
|
set_GPIO_Port_Clock(STM_PORT(digitalPinToPinName(receivePin)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_Error_Handler("ERROR: invalid pin number\n", -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Destructor
|
||||||
|
//
|
||||||
|
SoftwareSerial::~SoftwareSerial() { end(); }
|
||||||
|
|
||||||
|
//
|
||||||
|
// Public methods
|
||||||
|
//
|
||||||
|
|
||||||
|
void SoftwareSerial::begin(long speed) {
|
||||||
|
#ifdef FORCE_BAUD_RATE
|
||||||
|
speed = FORCE_BAUD_RATE;
|
||||||
|
#endif
|
||||||
|
_speed = speed;
|
||||||
|
if (!_half_duplex) {
|
||||||
|
setTX();
|
||||||
|
setRX();
|
||||||
|
listen();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
setTX();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoftwareSerial::end() {
|
||||||
|
stopListening();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read data from buffer
|
||||||
|
int SoftwareSerial::read() {
|
||||||
|
// Empty buffer?
|
||||||
|
if (_receive_buffer_head == _receive_buffer_tail) return -1;
|
||||||
|
|
||||||
|
// Read from "head"
|
||||||
|
uint8_t d = _receive_buffer[_receive_buffer_head]; // grab next byte
|
||||||
|
_receive_buffer_head = (_receive_buffer_head + 1) % _SS_MAX_RX_BUFF;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SoftwareSerial::available() {
|
||||||
|
return (_receive_buffer_tail + _SS_MAX_RX_BUFF - _receive_buffer_head) % _SS_MAX_RX_BUFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SoftwareSerial::write(uint8_t b) {
|
||||||
|
// wait for previous transmit to complete
|
||||||
|
_output_pending = 1;
|
||||||
|
while (active_out) { /* nada */ }
|
||||||
|
// add start and stop bits.
|
||||||
|
tx_buffer = b << 1 | 0x200;
|
||||||
|
if (_inverse_logic) tx_buffer = ~tx_buffer;
|
||||||
|
tx_bit_cnt = 0;
|
||||||
|
tx_tick_cnt = OVERSAMPLE;
|
||||||
|
setSpeed(_speed);
|
||||||
|
if (_half_duplex) setRXTX(false);
|
||||||
|
_output_pending = 0;
|
||||||
|
// make us active
|
||||||
|
active_out = this;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoftwareSerial::flush() {
|
||||||
|
noInterrupts();
|
||||||
|
_receive_buffer_head = _receive_buffer_tail = 0;
|
||||||
|
interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SoftwareSerial::peek() {
|
||||||
|
// Empty buffer?
|
||||||
|
if (_receive_buffer_head == _receive_buffer_tail) return -1;
|
||||||
|
|
||||||
|
// Read from "head"
|
||||||
|
return _receive_buffer[_receive_buffer_head];
|
||||||
|
}
|
@ -0,0 +1,119 @@
|
|||||||
|
/**
|
||||||
|
* SoftwareSerial.h (formerly NewSoftSerial.h)
|
||||||
|
*
|
||||||
|
* Multi-instance software serial library for Arduino/Wiring
|
||||||
|
* -- Interrupt-driven receive and other improvements by ladyada
|
||||||
|
* (http://ladyada.net)
|
||||||
|
* -- Tuning, circular buffer, derivation from class Print/Stream,
|
||||||
|
* multi-instance support, porting to 8MHz processors,
|
||||||
|
* various optimizations, PROGMEM delay tables, inverse logic and
|
||||||
|
* direct port writing by Mikal Hart (http://www.arduiniana.org)
|
||||||
|
* -- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com)
|
||||||
|
* -- 20MHz processor support by Garrett Mace (http://www.macetech.com)
|
||||||
|
* -- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/)
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* The latest version of this library can always be found at
|
||||||
|
* http://arduiniana.org.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SOFTWARESERIAL_H
|
||||||
|
#define SOFTWARESERIAL_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Definitions
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#define _SS_MAX_RX_BUFF 64 // RX buffer size
|
||||||
|
|
||||||
|
class SoftwareSerial : public Stream {
|
||||||
|
private:
|
||||||
|
// per object data
|
||||||
|
uint16_t _receivePin;
|
||||||
|
uint16_t _transmitPin;
|
||||||
|
GPIO_TypeDef *_receivePinPort;
|
||||||
|
uint32_t _receivePinNumber;
|
||||||
|
GPIO_TypeDef *_transmitPinPort;
|
||||||
|
uint32_t _transmitPinNumber;
|
||||||
|
uint32_t _speed;
|
||||||
|
|
||||||
|
uint16_t _buffer_overflow: 1;
|
||||||
|
uint16_t _inverse_logic: 1;
|
||||||
|
uint16_t _half_duplex: 1;
|
||||||
|
uint16_t _output_pending: 1;
|
||||||
|
|
||||||
|
unsigned char _receive_buffer[_SS_MAX_RX_BUFF];
|
||||||
|
volatile uint8_t _receive_buffer_tail;
|
||||||
|
volatile uint8_t _receive_buffer_head;
|
||||||
|
|
||||||
|
uint32_t delta_start = 0;
|
||||||
|
|
||||||
|
// static data
|
||||||
|
static bool initialised;
|
||||||
|
static HardwareTimer timer;
|
||||||
|
static const IRQn_Type timer_interrupt_number;
|
||||||
|
static uint32_t timer_interrupt_priority;
|
||||||
|
static SoftwareSerial *active_listener;
|
||||||
|
static SoftwareSerial *volatile active_out;
|
||||||
|
static SoftwareSerial *volatile active_in;
|
||||||
|
static int32_t tx_tick_cnt;
|
||||||
|
static volatile int32_t rx_tick_cnt;
|
||||||
|
static uint32_t tx_buffer;
|
||||||
|
static int32_t tx_bit_cnt;
|
||||||
|
static uint32_t rx_buffer;
|
||||||
|
static int32_t rx_bit_cnt;
|
||||||
|
static uint32_t cur_speed;
|
||||||
|
|
||||||
|
// private methods
|
||||||
|
void send();
|
||||||
|
void recv();
|
||||||
|
void setTX();
|
||||||
|
void setRX();
|
||||||
|
void setSpeed(uint32_t speed);
|
||||||
|
void setRXTX(bool input);
|
||||||
|
static void handleInterrupt(HardwareTimer *timer);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// public methods
|
||||||
|
|
||||||
|
SoftwareSerial(uint16_t receivePin, uint16_t transmitPin, bool inverse_logic = false);
|
||||||
|
virtual ~SoftwareSerial();
|
||||||
|
void begin(long speed);
|
||||||
|
bool listen();
|
||||||
|
void end();
|
||||||
|
bool isListening() { return active_listener == this; }
|
||||||
|
bool stopListening();
|
||||||
|
bool overflow() {
|
||||||
|
bool ret = _buffer_overflow;
|
||||||
|
if (ret) _buffer_overflow = false;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
int peek();
|
||||||
|
|
||||||
|
virtual size_t write(uint8_t byte);
|
||||||
|
virtual int read();
|
||||||
|
virtual int available();
|
||||||
|
virtual void flush();
|
||||||
|
operator bool() { return true; }
|
||||||
|
|
||||||
|
static void setInterruptPriority(uint32_t preemptPriority, uint32_t subPriority);
|
||||||
|
|
||||||
|
using Print::write;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SOFTWARESERIAL_H
|
@ -1,29 +0,0 @@
|
|||||||
import os,shutil
|
|
||||||
from SCons.Script import DefaultEnvironment
|
|
||||||
from platformio import util
|
|
||||||
|
|
||||||
env = DefaultEnvironment()
|
|
||||||
platform = env.PioPlatform()
|
|
||||||
board = env.BoardConfig()
|
|
||||||
|
|
||||||
FRAMEWORK_DIR = platform.get_package_dir("framework-arduinoststm32")
|
|
||||||
CMSIS_DIR = os.path.join(FRAMEWORK_DIR, "CMSIS", "CMSIS")
|
|
||||||
assert os.path.isdir(FRAMEWORK_DIR)
|
|
||||||
assert os.path.isdir(CMSIS_DIR)
|
|
||||||
assert os.path.isdir("buildroot/share/PlatformIO/variants")
|
|
||||||
|
|
||||||
mcu_type = board.get("build.mcu")[:-2]
|
|
||||||
variant = board.get("build.variant")
|
|
||||||
series = mcu_type[:7].upper() + "xx"
|
|
||||||
variant_dir = os.path.join(FRAMEWORK_DIR, "variants", variant)
|
|
||||||
|
|
||||||
source_dir = os.path.join("buildroot/share/PlatformIO/variants", variant)
|
|
||||||
assert os.path.isdir(source_dir)
|
|
||||||
|
|
||||||
if not os.path.isdir(variant_dir):
|
|
||||||
os.mkdir(variant_dir)
|
|
||||||
|
|
||||||
for file_name in os.listdir(source_dir):
|
|
||||||
full_file_name = os.path.join(source_dir, file_name)
|
|
||||||
if os.path.isfile(full_file_name):
|
|
||||||
shutil.copy(full_file_name, variant_dir)
|
|
@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define HAL_MODULE_ENABLED
|
||||||
|
#define HAL_ADC_MODULE_ENABLED
|
||||||
|
#define HAL_CRC_MODULE_ENABLED
|
||||||
|
#define HAL_DMA_MODULE_ENABLED
|
||||||
|
#define HAL_GPIO_MODULE_ENABLED
|
||||||
|
#define HAL_I2C_MODULE_ENABLED
|
||||||
|
#define HAL_PWR_MODULE_ENABLED
|
||||||
|
#define HAL_RCC_MODULE_ENABLED
|
||||||
|
//#define HAL_RTC_MODULE_ENABLED Real Time Clock...do we use it?
|
||||||
|
#define HAL_SPI_MODULE_ENABLED
|
||||||
|
#define HAL_TIM_MODULE_ENABLED
|
||||||
|
#define HAL_USART_MODULE_ENABLED
|
||||||
|
#define HAL_CORTEX_MODULE_ENABLED
|
||||||
|
//#define HAL_UART_MODULE_ENABLED // by default
|
||||||
|
//#define HAL_PCD_MODULE_ENABLED // Since STM32 v3.10700.191028 this is automatically added if any type of USB is enabled (as in Arduino IDE)
|
||||||
|
|
||||||
|
#undef HAL_SD_MODULE_ENABLED
|
||||||
|
#undef HAL_DAC_MODULE_ENABLED
|
||||||
|
#undef HAL_FLASH_MODULE_ENABLED
|
||||||
|
#undef HAL_CAN_MODULE_ENABLED
|
||||||
|
#undef HAL_CAN_LEGACY_MODULE_ENABLED
|
||||||
|
#undef HAL_CEC_MODULE_ENABLED
|
||||||
|
#undef HAL_CRYP_MODULE_ENABLED
|
||||||
|
#undef HAL_DCMI_MODULE_ENABLED
|
||||||
|
#undef HAL_DMA2D_MODULE_ENABLED
|
||||||
|
#undef HAL_ETH_MODULE_ENABLED
|
||||||
|
#undef HAL_NAND_MODULE_ENABLED
|
||||||
|
#undef HAL_NOR_MODULE_ENABLED
|
||||||
|
#undef HAL_PCCARD_MODULE_ENABLED
|
||||||
|
#undef HAL_SRAM_MODULE_ENABLED
|
||||||
|
#undef HAL_SDRAM_MODULE_ENABLED
|
||||||
|
#undef HAL_HASH_MODULE_ENABLED
|
||||||
|
#undef HAL_EXTI_MODULE_ENABLED
|
||||||
|
#undef HAL_SMBUS_MODULE_ENABLED
|
||||||
|
#undef HAL_I2S_MODULE_ENABLED
|
||||||
|
#undef HAL_IWDG_MODULE_ENABLED
|
||||||
|
#undef HAL_LTDC_MODULE_ENABLED
|
||||||
|
#undef HAL_DSI_MODULE_ENABLED
|
||||||
|
#undef HAL_QSPI_MODULE_ENABLED
|
||||||
|
#undef HAL_RNG_MODULE_ENABLED
|
||||||
|
#undef HAL_SAI_MODULE_ENABLED
|
||||||
|
#undef HAL_IRDA_MODULE_ENABLED
|
||||||
|
#undef HAL_SMARTCARD_MODULE_ENABLED
|
||||||
|
#undef HAL_WWDG_MODULE_ENABLED
|
||||||
|
#undef HAL_HCD_MODULE_ENABLED
|
||||||
|
#undef HAL_FMPI2C_MODULE_ENABLED
|
||||||
|
#undef HAL_SPDIFRX_MODULE_ENABLED
|
||||||
|
#undef HAL_DFSDM_MODULE_ENABLED
|
||||||
|
#undef HAL_LPTIM_MODULE_ENABLED
|
||||||
|
#undef HAL_MMC_MODULE_ENABLED
|
Loading…
Reference in New Issue