I have a necessity for more than 3 receiving uarts. Using the hardware timers I am able to increase the number of uarts. The sketch uses the falling edge of a start bit to produce an interrupt on the declared receiving pin. The ISR to this interrupt disables the interrupt on the pin and sets a one-shoot timer that fires 1/2 bit time after. On the the service to the one-shoot timer, the timer is set as a repeat-timer firing with period equal to the bit time. Then it reads the state of the pin on the first 8 firings and on the 9th the received byte is placed in a buffer and the pin is placed again in its initial waiting state.
My experience of C and C++ is very limited and I am not able to write a library or a class for the code I include here. I would like to have a library so that a sketch would look like this
Code: Select all
HardwareSerial SerialOut(2);
SoftwareSerial SerialIn(0)
void setup() {
Serial.begin(115200);
SerialOut.begin(9600);
SerialIn_begin(12, 256, 9600);
}
void loop() {
delay (500);
SerialOut.println("Send this out on pin 17 to be read in on pin 12!");
byte b;
int n = SerialIn_available();
for (int i=0; i < n; i++){
b = SerialIn.read();
Serial.print(char(b));
}
}
Code: Select all
// Sketch to test up to extra 4 receiving UARTs using the 4
// ESP32 hardware timers. Tested with timer0 and timer1 only
// Works without errors up to 38400 baud and tested on
// NodeMCU-32S with pins pins 25 and 34 connected
// together and pins 17 and 12 also connected together
HardwareSerial Serial1(1);
HardwareSerial Serial2(2);
void setup() {
Serial.begin(115200);
// send on pin 25 to be received on pin 34
Serial1.begin(9600, SERIAL_8N1, 26, 25);
Serial0_begin(34, 256, 9600);
// send on pin 17 to be received on pin 12
Serial2.begin(9600);
Serial1_begin(12, 256, 9600);
}
void loop() {
delay (500);
Serial1.println("This is transmitted on pin 25 and is received on pin 34");
Serial2.println("This is transmitted on pin 17 and is received on pin 12");
delay(500);
byte b0;
int nnn0 = Serial0_available();
for (int i0=0; i0 < nnn0; i0++){
b0 = Serial0_read();
Serial.print(char(b0));
}
byte b1;
int nnn1 = Serial1_available();
for (int i1=0; i1 < nnn1; i1++){
b1 = Serial1_read();
Serial.print(char(b1));
}
}
// I am not able to put the following in a class or library!
// *********************************************************
// please help!
// for timer 0
uint32_t bit_ticks0; // duration of bit in ticks, where each tick is 0.1 us
uint32_t init_ticks0; // ticks from falling edge to the middle of start bit
int rxbuffSize0;
int rxPin0;
byte bitCounter0;
uint8_t rx0;
unsigned int inPos0;
unsigned int outPos0;
uint8_t *rxBuffer0;
hw_timer_t * timer0 = NULL;
void IRAM_ATTR rxISR0();
void IRAM_ATTR OnceTimerISR0();
void IRAM_ATTR RepeatTimerISR0();
// for timer 1
uint32_t bit_ticks1; // duration of bit in ticks, where each tick is 0.1 us
uint32_t init_ticks1; // ticks from falling edge to the middle of start bit
int rxbuffSize1;
int rxPin1;
byte bitCounter1;
uint8_t rx1;
unsigned int inPos1;
unsigned int outPos1;
uint8_t *rxBuffer1;
hw_timer_t * timer1 = NULL;
void IRAM_ATTR rxISR1();
void IRAM_ATTR OnceTimerISR1();
void IRAM_ATTR RepeatTimerISR1();
//portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
void Serial0_begin(int Pin, int bSize, long baud) {
rxPin0 = Pin;
pinMode(rxPin0, INPUT_PULLUP);
rxBuffer0 = (uint8_t*)malloc(bSize);
rxbuffSize0 = bSize;
inPos0 = outPos0 = 0;
bit_ticks0 = 10000000 / baud; // units = 0.1 micro seconds
init_ticks0 = (bit_ticks0 / 2);
timer0 = timerBegin(0, 8, true);
attachInterrupt(rxPin0, rxISR0, FALLING);
}
void Serial1_begin(int Pin, int bSize, long baud) {
rxPin1 = Pin;
pinMode(rxPin1, INPUT_PULLUP);
rxBuffer1 = (uint8_t*)malloc(bSize);
rxbuffSize1 = bSize;
inPos1 = outPos1 = 0;
bit_ticks1 = 10000000 / baud; // units = 0.1 micro seconds
init_ticks1 = (bit_ticks1 / 2);
timer1 = timerBegin(1, 8, true);
attachInterrupt(rxPin1, rxISR1, FALLING);
}
void IRAM_ATTR rxISR0() {
// portENTER_CRITICAL_ISR(&timerMux);
detachInterrupt(rxPin0);
timerAttachInterrupt(timer0, &OnceTimerISR0, true);
timerAlarmWrite(timer0, init_ticks0, true);
timerAlarmEnable(timer0);
rx0 = 0;
// portEXIT_CRITICAL_ISR(&timerMux);
}
void IRAM_ATTR rxISR1() {
// portENTER_CRITICAL_ISR(&timerMux);
detachInterrupt(rxPin1);
timerAttachInterrupt(timer1, &OnceTimerISR1, true);
timerAlarmWrite(timer1, init_ticks1, true);
timerAlarmEnable(timer1);
rx1 = 0;
// portEXIT_CRITICAL_ISR(&timerMux);
}
void IRAM_ATTR OnceTimerISR0() {
// portENTER_CRITICAL_ISR(&timerMux);
timerAttachInterrupt(timer0, &RepeatTimerISR0, true);
timerAlarmWrite(timer0, bit_ticks0, true);
timerAlarmEnable(timer0);
bitCounter0 = 1;
// portEXIT_CRITICAL_ISR(&timerMux);
}
void IRAM_ATTR OnceTimerISR1() {
// portENTER_CRITICAL_ISR(&timerMux);
timerAttachInterrupt(timer1, &RepeatTimerISR1, true);
timerAlarmWrite(timer1, bit_ticks1, true);
timerAlarmEnable(timer1);
bitCounter1 = 1;
// portEXIT_CRITICAL_ISR(&timerMux);
}
void IRAM_ATTR RepeatTimerISR0() {
// portENTER_CRITICAL_ISR(&timerMux);
if (bitCounter0 == 9) {
timerAlarmDisable(timer0);
if (digitalRead(rxPin0)) {
int next = (inPos0+1) % rxbuffSize0;
if (next != outPos0) {
rxBuffer0[inPos0] = rx0;
inPos0 = next;
}
}
attachInterrupt(rxPin0, rxISR0, FALLING);
}
rx0 >>= 1;
if (digitalRead(rxPin0)) { rx0 |= 0x80; }
bitCounter0 = bitCounter0 + 1;
// portEXIT_CRITICAL_ISR(&timerMux);
}
void IRAM_ATTR RepeatTimerISR1() {
// portENTER_CRITICAL_ISR(&timerMux);
if (bitCounter1 == 9) {
timerAlarmDisable(timer1);
if (digitalRead(rxPin1)) {
int next = (inPos1+1) % rxbuffSize1;
if (next != outPos1) {
rxBuffer1[inPos1] = rx1;
inPos1 = next;
}
}
attachInterrupt(rxPin1, rxISR1, FALLING);
}
rx1 >>= 1;
if (digitalRead(rxPin1)) { rx1 |= 0x80; }
bitCounter1 = bitCounter1 + 1;
// portEXIT_CRITICAL_ISR(&timerMux);
}
int Serial0_available() {
int avail = inPos0 - outPos0;
if (avail < 0) avail += rxbuffSize0;
return avail;
}
int Serial1_available() {
int avail = inPos1 - outPos1;
if (avail < 0) avail += rxbuffSize1;
return avail;
}
uint8_t Serial0_read() {
if ( inPos0 == outPos0) return -1;
uint8_t ch = rxBuffer0[outPos0];
outPos0 = (outPos0 + 1) % rxbuffSize0;
return ch;
}
uint8_t Serial1_read() {
if ( inPos1 == outPos1) return -1;
uint8_t ch = rxBuffer1[outPos1];
outPos1 = (outPos1 + 1) % rxbuffSize1;
return ch;
}
void Serial0_end() {
detachInterrupt(rxPin0);
timerEnd(timer0);
timer0 = NULL;
}
void Serial1_end() {
detachInterrupt(rxPin1);
timerEnd(timer1);
timer1 = NULL;
}