PPM stops working after UART setup


(Daniel kirubakaran) #1

Hi,
I am using Hifive1 (version 1) board. In that i am reading PPM signal continuously from the RC receiver.

Also i am using Neo 6m GPS using software uart.

My problem is when i read receiver’s value after setting up the GPS
the receiver’s value becomes constant in other words it is not at all changing even if i move the RC controller’s Joysticks.

This is not the exact code but is the sequence of what i am doing actually.

 #include <SoftwareSerial32.h>
 SoftwareSerial32 ss(15, 16); // RX, TX

int ppm_pin = 17;

 pinMode(ppm_pin, INPUT_PULLUP);
  ppm_pinmask = digitalPinToBitMask(ppm_pin);                                      //Setup interrupt
  attachInterrupt(digitalPinToInterrupt(ppm_pin), ISR, RISING);

  set_csr(mstatus, MSTATUS_MIE);
  Serial.println(">>ReceiverStart...");


 -->**I am getting values here**
 while (receiver_input_channel_3 < 990 || receiver_input_channel_3 > 1020 || receiver_input_channel_4 < 1400) {
    receiver_input_channel_3 = convert_receiver_channel(3);                 //Convert the actual receiver signals for throttle to the standard 1000 - 2000us

    Serial.print(receiver_input[3]); Serial.print("-"); Serial.println(receiver_input_channel_3);
}
  gps_setup(); <----**This is GPS setup**

—>values became still while (1) {
Serial.print(receiver_input[1]); Serial.print("-");
Serial.print(receiver_input[2]); Serial.print("-");
Serial.print(receiver_input[3]); Serial.print("-");
Serial.print(receiver_input[4]); Serial.print("-");
Serial.print(receiver_input[5]); Serial.print("-");
Serial.println(receiver_input[6]);
//delay(100);
}

void gps_setup(void) {

  ss.begin(9600);
  delay(500);

  //Disable GPGSV messages by using the ublox protocol.
  uint8_t Disable_GPGSV[11] = {0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x03, 0x00, 0xFD, 0x15};
  ss.write(Disable_GPGSV, 11);
  delay(350);   //A small delay is added to give the GPS some time to respond @ 9600bps.
  //Set the refresh rate to 5Hz by using the ublox protocol.
  uint8_t Set_to_5Hz[14] = {0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0xC8, 0x00, 0x01, 0x00, 0x01, 0x00, 0xDE, 0x6A};
  ss.write(Set_to_5Hz, 14);
  delay(350);   //A small delay is added to give the GPS some time to respond @ 9600bps.
  //Set the baud rate to 57.6kbps by using the ublox protocol.
  uint8_t Set_to_57kbps[28] = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00,
                               0x00, 0xE1, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xE1
                              };
  ss.write(Set_to_57kbps, 28);
  delay(200);

  ss.begin(57600);
  delay(400);

}

example output:
> 1191-1026
> 1191-1026
> 1191-1026
> 1191-1026
> 1191-1026
> 1191-1026
> 1191-1026
> 1191-1026
> 1193-1029
> 1193-1029
> 1193-1029
> 1193-1029
> 1189-1023
> 1189-1023
> 1189-1023
> 1189-1023
> 1189-1023
> 1189-1023
> 1189-1023
> 1189-1023
> 1189-1023
> 1189-1023
> 1189-1023
> 1189-1023
> 1188-1021
> 1188-1021
> 1188-1021
> 1188-1021
> 1188-1021
> 1188-1021
> 1188-1021
> 1188-1021
> 1188-1021
> 1186-1018
> >Setup Done.
> (Became constant and not changing)
> 1043-1043-1043-1043-1044-1043
> 1043-1043-1043-1043-1044-1043
> 1043-1043-1043-1043-1044-1043
> 1043-1043-1043-1043-1044-1043
> 1043-1043-1043-1043-1044-1043
> 1043-1043-1043-1043-1044-1043
> 1043-1043-1043-1043-1044-1043


(Bruce Hoult) #2

I see you are using the Arduino environment, and are using an interrupt to read the ppm value.

The obvious possibility is that when you do ss.begin() the SoftwareSerial32 library may be setting up interrupts for itself to use that wipe out or at least interfer with your own interrupt.

You’d need to study the SoftwareSerial32 library to see what it does or ask its authors about that.


(Daniel kirubakaran) #3

Ok bruce. I will do it according to your suggestion.
Thanks for your reply.


(Daniel kirubakaran) #4

Issue solved!

By default neo 6m woks in 9600 Baud rate.
I tried changing its baud rate to 57600 through software.But result was not expected.
so i just connected the module through USB and changed the baud rate settings in the UBLOX’s u-center app to 57600 and saved the settings as default ( permanently ) in module’s EEPROM. So it is now set to 57600 which is same as my Serial monitor’s baud rate.

Working good !

I just removed ss.begin() and setting to 57600 baud rate code in the geps_setup().

Once again thanks to BRUCE who helped me a lot.


(Daniel kirubakaran) #5

Hi,
I am facing an another issue, i feel like both ppm interrupt and sw uart interrupt are being collapsed.Because the gps values contains some garbage values and the receiver values are paused with some values when gps values are read ,after that receiver gets its current values.So i am un able to go further.
Since Hifive1 doesn’t have built-in UART i had to use Software Uart,

What is the solution? and how to handle both interrupts?

Thanks.


(Bruce Hoult) #6

Hi Daniel,

The Arduino environment is supposed to support adding individual handlers for different interrupt sources e.g. GPIO pins, timer etc.

You’re not doing something silly such as calling delay() inside an interrupt handler?


(Daniel kirubakaran) #7

No, Bruce.
Anyways i will give the entire code for reference.https://github.com/danielkc26/dani_codes/blob/master/RC_Drone_hifive1_0.2.ino
`


(Daniel kirubakaran) #8

I was reducing the GPS baudrate from 57600 to 38400,19200,9600 (I changed the settings using U-center software in gps module as well)

At 9600 the garbage values are reduced and almost 80% of gps messages were visible.
I tried for 4800 baud but unfortunately it is not provided in SoftwareSerial32 library. Minimum Baud rate starts from 9600 only.

#include <SoftwareSerial32.h>
//#define _SWSERIAL32_DBG

#if F_CPU == 320000000L
  // 320 MHZ
  static const uint32_t CYCLES_PER_BIT_9600_320MHZ = 33333;
  static const uint32_t BITS_PER_TICK_9600_Q16_320MHZ = 2;
    // 9600 * CYCLE_RESOLUTION_320MHZ(1/320M) = 9600 * 0.000000003125 * (2^16)
    // = 0.00003 * (2^16) = 1.96608 = ~2

  // These could be omiited and used as a right shift due to them being multiples of 2
  static const uint32_t CYCLES_PER_BIT_19200_320MHZ = 16667;
  static const uint32_t BITS_PER_TICK_19200_Q16_320MHZ = 4; 

  static const uint32_t CYCLES_PER_BIT_31250_320MHZ = 10240;
  static const uint32_t BITS_PER_TICK_31250_Q17_320MHZ = 13;

  static const uint32_t CYCLES_PER_BIT_38400_320MHZ = 8333;
  static const uint32_t BITS_PER_TICK_38400_Q16_320MHZ = 8;

  static const uint32_t CYCLES_PER_BIT_57600_320MHZ = 5556;
  static const uint32_t BITS_PER_TICK_57600_Q15_320MHZ = 6;

  static const uint32_t CYCLES_PER_BIT_115200_320MHZ = 2778;
  static const uint32_t BITS_PER_TICK_115200_Q13_320MHZ = 3;

  static const uint32_t CYCLES_PER_BIT_230400_320MHZ = 1389;
  static const uint32_t BITS_PER_TICK_230400_Q16_320MHZ = 47;

(Bruce Hoult) #9

NMEA messages are traditionally designed to be short enough that 4800 bps is enough. It should be easy to modify SoftwareSerial to support 4800.


(Daniel kirubakaran) #10

Ok then, i ll try to modify.


(Daniel kirubakaran) #11

I just added the following lines.

Using the Formula

// 9600 * CYCLE_RESOLUTION_320MHZ(1/320M) = 9600 * 0.000000003125 * (2^16)
// = 0.00003 * (2^16) = 1.96608 = ~2

  1.    #if F_CPU == 320000000L
       // 320 MHZ   
       static const uint32_t CYCLES_PER_BIT_4800_320MHZ = 66666;
          static const uint32_t BITS_PER_TICK_4800_Q16_320MHZ = 1;
    

    #elif F_CPU == 256000000L
    // 256 MHZ
    static const uint32_t CYCLES_PER_BIT_4800_256MHZ = 53333;//added extra
    static const uint32_t BITS_PER_TICK_4800_Q16_256MHZ = 1;

  2.    switch (_baudRate)
       {
     	 case 4800://added extra
           #if F_CPU == 320000000L
             rxWindowWidth = CYCLES_PER_BIT_4800_320MHZ >> 1;
             txBitWidth = CYCLES_PER_BIT_4800_320MHZ;
             bitsPerTick = BITS_PER_TICK_4800_Q16_320MHZ;
             shiftScaler = 16;
           #elif F_CPU == 256000000L
             rxWindowWidth = CYCLES_PER_BIT_4800_256MHZ / 3;
             txBitWidth = CYCLES_PER_BIT_4800_256MHZ;
             bitsPerTick = BITS_PER_TICK_4800_Q16_256MHZ;
             shiftScaler = 17;
           #endif
           break;.....
    
  3.  if (((baudRate ==  4800)         ||
        (baudRate ==  9600)         ||
        (baudRate == 19200)         ||.......
    

But i am not very sure about Q16 , shiftScaler, >>1 and /3.
What are those values?
please correct me if am wrong!


(Daniel kirubakaran) #12

I tried testing a part of a code after read_gps()
With 9600 baud rate ,if i comment some lines which has arithmetic functions, i am getting the clean NMEA messages(enabled only GLL,GSA,GGA) and receiver’s channel values.

But, i get garbage values along with the NMEA messages if i run the code along with those arithmetic functions. I am suspecting those functions whether it slows down the operation so that i acts like a delay for reading the gps values. I am not sure actually.

  1. CODE with some lines commented
  void loop(){

 loop_timer = micros();
  
 if(gps_add_counter >=0)gps_add_counter--;
 
 read_gps();

  gyro_roll_input = (gyro_roll_input * 0.7) + (((float)gyro_roll / 65.5) * 0.3);   //Gyro pid input is deg/sec.
  gyro_pitch_input = (gyro_pitch_input * 0.7) + (((float)gyro_pitch / 65.5) * 0.3);//Gyro pid input is deg/sec.
  gyro_yaw_input = (gyro_yaw_input * 0.7) + (((float)gyro_yaw / 65.5) * 0.3);      //Gyro pid input is deg/sec.

/* //Gyro angle calculations
  //for 250HZ
  //0.0000611 = 1 / 250Hz / 65.5
  angle_pitch += (float)gyro_pitch * 0.0000611;                                    //Calculate the traveled pitch angle and add this to the angle_pitch variable.
  angle_roll += (float)gyro_roll * 0.0000611;                                      //Calculate the traveled roll angle and add this to the angle_roll variable.
  angle_yaw += (float)gyro_yaw * 0.0000611;                                        //Calculate the traveled yaw angle and add this to the angle_yaw variable.
  if (angle_yaw < 0) angle_yaw += 360;                                             //If the compass heading becomes smaller then 0, 360 is added to keep it in the 0 till 360 degrees range.
  else if (angle_yaw >= 360) angle_yaw -= 360;                                     //If the compass heading becomes larger then 360, 360 is subtracted to keep it in the 0 till 360 degrees range.
   
  //for 250HZ
  //0.000001066 = 0.0000611 * (3.142(PI) / 180degr) The Arduino sin function is in radians
  angle_pitch -= angle_roll * sin((float)gyro_yaw * 0.000001066);                  //If the IMU has yawed transfer the roll angle to the pitch angel.
  angle_roll += angle_pitch * sin((float)gyro_yaw * 0.000001066);                  //If the IMU has yawed transfer the pitch angle to the roll angel.


  //Accelerometer angle calculations
  acc_total_vector = sqrt((acc_x * acc_x) + (acc_y * acc_y) + (acc_z * acc_z)); //Calculate the total accelerometer vector.

  if (abs(acc_y) < acc_total_vector) {                                      //Prevent the asin function to produce a NaN
    angle_pitch_acc = asin((float)acc_y / acc_total_vector) * 57.296;       //Calculate the pitch angle.
  }
  if (abs(acc_x) < acc_total_vector) {                                      //Prevent the asin function to produce a NaN
    angle_roll_acc = asin((float)acc_x / acc_total_vector) * -57.296;       //Calculate the roll angle.
  } */
}

Output

2.CODE as it is

void loop(){

     loop_timer = micros();
      
     if(gps_add_counter >=0)gps_add_counter--;
     
     read_gps();

      gyro_roll_input = (gyro_roll_input * 0.7) + (((float)gyro_roll / 65.5) * 0.3);   //Gyro pid input is deg/sec.
      gyro_pitch_input = (gyro_pitch_input * 0.7) + (((float)gyro_pitch / 65.5) * 0.3);//Gyro pid input is deg/sec.
      gyro_yaw_input = (gyro_yaw_input * 0.7) + (((float)gyro_yaw / 65.5) * 0.3);      //Gyro pid input is deg/sec.

      //Gyro angle calculations
      //for 250HZ
      //0.0000611 = 1 / 250Hz / 65.5
      angle_pitch += (float)gyro_pitch * 0.0000611;                                    //Calculate the traveled pitch angle and add this to the angle_pitch variable.
      angle_roll += (float)gyro_roll * 0.0000611;                                      //Calculate the traveled roll angle and add this to the angle_roll variable.
      angle_yaw += (float)gyro_yaw * 0.0000611;                                        //Calculate the traveled yaw angle and add this to the angle_yaw variable.
      if (angle_yaw < 0) angle_yaw += 360;                                             //If the compass heading becomes smaller then 0, 360 is added to keep it in the 0 till 360 degrees range.
      else if (angle_yaw >= 360) angle_yaw -= 360;                                     //If the compass heading becomes larger then 360, 360 is subtracted to keep it in the 0 till 360 degrees range.

      //for 250HZ
      //0.000001066 = 0.0000611 * (3.142(PI) / 180degr) The Arduino sin function is in radians
      angle_pitch -= angle_roll * sin((float)gyro_yaw * 0.000001066);                  //If the IMU has yawed transfer the roll angle to the pitch angel.
      angle_roll += angle_pitch * sin((float)gyro_yaw * 0.000001066);                  //If the IMU has yawed transfer the pitch angle to the roll angel.


      //Accelerometer angle calculations
      acc_total_vector = sqrt((acc_x * acc_x) + (acc_y * acc_y) + (acc_z * acc_z)); //Calculate the total accelerometer vector.

      if (abs(acc_y) < acc_total_vector) {                                      //Prevent the asin function to produce a NaN
        angle_pitch_acc = asin((float)acc_y / acc_total_vector) * 57.296;       //Calculate the pitch angle.
      }
      if (abs(acc_x) < acc_total_vector) {                                      //Prevent the asin function to produce a NaN
        angle_roll_acc = asin((float)acc_x / acc_total_vector) * -57.296;       //Calculate the roll angle.
      }
      
    }

Output


(Bruce Hoult) #13

There’s an awful lot of trig going on in between calls to read_gps(). How long does it take?

I don’t see the source code for SoftwareSerial32 in your git repository. How big is the read buffer?


(Daniel kirubakaran) #14

You can find the SoftwareSerial32 source code https://github.com/westerndigitalcorporation/cinco/tree/master/hardware/freedom_e/libraries/SoftwareSerial32/src here.

In my flight controller main code you could see a delay of 4000 micro seconds in the form of while loop to make the loop’s refresh rate @ 250Hz.

I commented that delay also ,as it is also one of the reason for the GPS incoming messages to misbehave.

I think the buffer size is 64 .


(Bruce Hoult) #15

Are you sure the loop is actually finishing in less than 4 ms?

Perhaps 64 bytes is not enough for the buffer. Try increasing it to 256 or 512 or 1024. At 9600 bps you’re only receiving one character per ms so you’d think 64 bytes would be more than ample if your loop is really running at 250 Hz. But is it?


(Daniel kirubakaran) #16

Yes! I checked it before adding read_gps() function. It was less than 4ms. And I didn’t check it after that. Have to check.

Actually I tried increasing the Read buffer with 128 & 256 yesterday. I was working with 128 and showed “truncated” error when used 256. So I was in confusion I kept it back to 64 again.

I will try once again.


(Daniel kirubakaran) #17

I tried with the modified code , in which i added those lines of 4800 baud rate (stilll not sure about q16,shiftScaler…I put it in assumption)
And changed the RX buffer as macro like this #define RX_BUFFER_SIZE 8192 (tried from 128,256,512,…to 8192)

I got proper messages at this point.

But after adding the remaining part of the codes one by one it started giving garbage values.

I couldn’t predict the issue exactly ! Struggling a lot to solve the problem.:roll_eyes:

Also i will put SoftwareSerial32 cpp and h file that i am using.


(Daniel kirubakaran) #18
//---------------------------------------------------------------------------
//
// SoftwareSerial32, based on NeoSWSerial
// Copyright (C) 2015-2016, SlashDevin
// Copyright (c) 2018 Western Digital Corporation or its affiliates.
//
// SoftwareSerial32 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// SoftwareSerial32 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 General Public License for more details:
//
//     <http://www.gnu.org/licenses/>.
//
// Modified by Shadi Kamal <shadi.kamal@wdc.com>, 2018
//---------------------------------------------------------------------------
//
// Methods
// -------
//
// begin(baudRate) - initialization, optionally set baudrate, and then enable RX
// listen() - enables RX interrupts, allowing data to enter the RX buffer
// ignore() - disables RX interrupts
// setBaudRate(baudRate) - selects the baud rate (9600, 19200, 31250, 38400)
//                             - any other value is ignored
// available() - returns the number of characters in the RX buffer
// read() - returns a single character from the buffer
// write(s) - transmits a string
//
// print() is supported
//=============================================================================

#include <SoftwareSerial32.h>
//#define _SWSERIAL32_DBG

#if F_CPU == 320000000L
  // 320 MHZ
  static const uint32_t CYCLES_PER_BIT_4800_320MHZ = 66666;//added extra
  static const uint32_t BITS_PER_TICK_4800_Q16_320MHZ = 1;
  
  static const uint32_t CYCLES_PER_BIT_9600_320MHZ = 33333;
  static const uint32_t BITS_PER_TICK_9600_Q16_320MHZ = 2;
    // 9600 * CYCLE_RESOLUTION_320MHZ(1/320M) = 9600 * 0.000000003125 * (2^16)
    // = 0.00003 * (2^16) = 1.96608 = ~2

  // These could be omiited and used as a right shift due to them being multiples of 2
  static const uint32_t CYCLES_PER_BIT_19200_320MHZ = 16667;
  static const uint32_t BITS_PER_TICK_19200_Q16_320MHZ = 4; 

  static const uint32_t CYCLES_PER_BIT_31250_320MHZ = 10240;
  static const uint32_t BITS_PER_TICK_31250_Q17_320MHZ = 13;

  static const uint32_t CYCLES_PER_BIT_38400_320MHZ = 8333;
  static const uint32_t BITS_PER_TICK_38400_Q16_320MHZ = 8;

  static const uint32_t CYCLES_PER_BIT_57600_320MHZ = 5556;
  static const uint32_t BITS_PER_TICK_57600_Q15_320MHZ = 6;

  static const uint32_t CYCLES_PER_BIT_115200_320MHZ = 2778;
  static const uint32_t BITS_PER_TICK_115200_Q13_320MHZ = 3;

  static const uint32_t CYCLES_PER_BIT_230400_320MHZ = 1389;
  static const uint32_t BITS_PER_TICK_230400_Q16_320MHZ = 47;

#elif F_CPU == 256000000L
  // 256 MHZ
   static const uint32_t CYCLES_PER_BIT_4800_256MHZ = 53333;//added extra
  static const uint32_t BITS_PER_TICK_4800_Q16_256MHZ = 1;
  
  static const uint32_t CYCLES_PER_BIT_9600_256MHZ = 26667;
  static const uint32_t BITS_PER_TICK_9600_Q17_256MHZ = 5; // need to find another multiplier since it's 2.5

  static const uint32_t CYCLES_PER_BIT_19200_256MHZ = 13333;
  static const uint32_t BITS_PER_TICK_19200_Q16_256MHZ = 5;

  static const uint32_t CYCLES_PER_BIT_31250_256MHZ = 8192;
  static const uint32_t BITS_PER_TICK_31250_Q16_256MHZ = 8;

  static const uint32_t CYCLES_PER_BIT_38400_256MHZ = 6667;
  static const uint32_t BITS_PER_TICK_38400_Q16_256MHZ = 10;

  static const uint32_t CYCLES_PER_BIT_57600_256MHZ = 4444;
  static const uint32_t BITS_PER_TICK_57600_Q18_256MHZ = 59;

  static const uint32_t CYCLES_PER_BIT_115200_256MHZ = 2222;
  static const uint32_t BITS_PER_TICK_115200_Q17_256MHZ = 59;

  static const uint32_t CYCLES_PER_BIT_230400_256MHZ    = 1111;
  static const uint32_t BITS_PER_TICK_230400_Q10_256MHZ = 1;

  static const uint32_t CYCLES_PER_BIT_250000_256MHZ = 1024;
  static const uint32_t BITS_PER_TICK_250000_Q10_256MHZ = 1;

  static const uint32_t CYCLES_PER_BIT_500000_256MHZ = 512;
  static const uint32_t BITS_PER_TICK_500000_Q9_256MHZ = 1;

  static const uint32_t CYCLES_PER_BIT_1000000_256MHZ = 256;
  static const uint32_t BITS_PER_TICK_1000000_Q8_256MHZ = 1;

#else
  // 16 MHZ
  static const uint32_t CYCLES_PER_BIT_4800_16MHZ = 3333;
  static const uint32_t BITS_PER_CYCLE_4800_Q16_16MHZ = 20;

  static const uint32_t CYCLES_PER_BIT_9600_16MHZ = 1667;
  static const uint32_t BITS_PER_TICK_9600_Q13_16MHZ = 5;
  
  static const uint32_t CYCLES_PER_BIT_19200_16MHZ = 833;
  static const uint32_t BITS_PER_TICK_19200_Q12_16MHZ = 5;

  static const uint32_t CYCLES_PER_BIT_31250_16MHZ = 512;
  static const uint32_t BITS_PER_TICK_31250_Q16_16MHZ = 128;

  static const uint32_t CYCLES_PER_BIT_38400_16MHZ = 417;
  static const uint32_t BITS_PER_TICK_38400_Q11_16MHZ = 5;

  static const uint32_t CYCLES_PER_BIT_57600_16MHZ = 278;
  static const uint32_t BITS_PER_TICK_57600_Q16_16MHZ = 236;

  static const uint32_t CYCLES_PER_BIT_115200_16MHZ = 139;
  static const uint32_t BITS_PER_TICK_115200_Q13_16MHZ = 59;

#endif

static const uint8_t WAITING_FOR_START_BIT = 0xFF;
void attachPCINT( uint8_t );

// An array to hold and manage active UART instances
static SoftwareSerial32* SWUARTInstanceMap[MAX_NUM_MUART];

uint32_t SoftwareSerial32::bitTimes( uint32_t dt)
{
  return (uint32_t)((uint64_t)((dt + rxWindowWidth) * bitsPerTick) >> shiftScaler);
}

void SoftwareSerial32::begin(uint32_t baudRate)
{
  setBaudRate( baudRate );
  listen();
}

//----------------------------------------------------------------------------

void SoftwareSerial32::listen()
{
  if (listener)
    listener->ignore();

  pinMode(rxPin, INPUT);
  rxBitMask = digitalPinToBitMask( rxPin );
  rxPort    = portInputRegister( digitalPinToPort( rxPin ) );

  txBitMask = digitalPinToBitMask( txPin );
  txPort    = portOutputRegister( digitalPinToPort( txPin ) );
  if (txPort)
    *txPort  |= txBitMask;   // high = idle
  pinMode(txPin, OUTPUT);

  noInterrupts();
  attachPCINT(rxPin);

  rxState  = WAITING_FOR_START_BIT;
  rxHead   = rxTail = 0;    // no characters in buffer
  flush();

  switch (_baudRate)
  {
	 case 4800://added extra
      #if F_CPU == 320000000L
        rxWindowWidth = CYCLES_PER_BIT_4800_320MHZ >> 1;
        txBitWidth = CYCLES_PER_BIT_4800_320MHZ;
        bitsPerTick = BITS_PER_TICK_4800_Q16_320MHZ;
        shiftScaler = 16;
      #elif F_CPU == 256000000L
        rxWindowWidth = CYCLES_PER_BIT_4800_256MHZ / 3;
        txBitWidth = CYCLES_PER_BIT_4800_256MHZ;
        bitsPerTick = BITS_PER_TICK_4800_Q16_256MHZ;
        shiftScaler = 17;
      #endif
      break;
    case 9600:
      #if F_CPU == 320000000L
        rxWindowWidth = CYCLES_PER_BIT_9600_320MHZ >> 1;
        txBitWidth = CYCLES_PER_BIT_9600_320MHZ;
        bitsPerTick = BITS_PER_TICK_9600_Q16_320MHZ;
        shiftScaler = 16;
      #elif F_CPU == 256000000L
        rxWindowWidth = CYCLES_PER_BIT_9600_256MHZ / 3;
        txBitWidth = CYCLES_PER_BIT_9600_256MHZ;
        bitsPerTick = BITS_PER_TICK_9600_Q17_256MHZ;
        shiftScaler = 17;
      #else
        rxWindowWidth = CYCLES_PER_BIT_9600_16MHZ >> 1;
        txBitWidth = CYCLES_PER_BIT_9600_16MHZ;
        bitsPerTick = BITS_PER_TICK_9600_Q13_16MHZ;
        shiftScaler = 13;
      #endif
      break;
    case 19200:
      #if F_CPU == 320000000L
        rxWindowWidth = CYCLES_PER_BIT_19200_320MHZ / 3;
        txBitWidth = CYCLES_PER_BIT_19200_320MHZ;
        bitsPerTick = BITS_PER_TICK_19200_Q16_320MHZ;
        shiftScaler = 16;
      #elif F_CPU == 256000000L
        rxWindowWidth = CYCLES_PER_BIT_19200_256MHZ >> 1;
        txBitWidth = CYCLES_PER_BIT_19200_256MHZ;
        bitsPerTick = BITS_PER_TICK_19200_Q16_256MHZ;
        shiftScaler = 16;
      #else
        rxWindowWidth = CYCLES_PER_BIT_19200_16MHZ / 3;
        txBitWidth = CYCLES_PER_BIT_19200_16MHZ;
        bitsPerTick = BITS_PER_TICK_19200_Q12_16MHZ;
        shiftScaler = 12;
      #endif
      break;
    case 31250:
      #if F_CPU == 320000000L
        rxWindowWidth = CYCLES_PER_BIT_31250_320MHZ / 3;
        txBitWidth = CYCLES_PER_BIT_31250_320MHZ;
        bitsPerTick = BITS_PER_TICK_31250_Q17_320MHZ;
        shiftScaler = 17;
      #elif F_CPU == 256000000L
        rxWindowWidth = CYCLES_PER_BIT_31250_256MHZ / 3;
        txBitWidth = CYCLES_PER_BIT_31250_256MHZ;
        bitsPerTick = BITS_PER_TICK_31250_Q16_256MHZ;
        shiftScaler = 16;
      #else
        rxWindowWidth = CYCLES_PER_BIT_31250_16MHZ / 3;
        txBitWidth = CYCLES_PER_BIT_31250_16MHZ;
        bitsPerTick = BITS_PER_TICK_31250_Q16_16MHZ;
        shiftScaler = 16;
      #endif
      break;
    case 38400:
      #if F_CPU == 320000000L
        rxWindowWidth = CYCLES_PER_BIT_38400_320MHZ / 3;
        txBitWidth = CYCLES_PER_BIT_38400_320MHZ;
        bitsPerTick = BITS_PER_TICK_38400_Q16_320MHZ;
        shiftScaler = 16;
      #elif F_CPU == 256000000L
        rxWindowWidth = CYCLES_PER_BIT_38400_256MHZ / 3;
        txBitWidth = CYCLES_PER_BIT_38400_256MHZ;
        bitsPerTick = BITS_PER_TICK_38400_Q16_256MHZ; 
        shiftScaler = 16;
      #else
        rxWindowWidth = CYCLES_PER_BIT_38400_16MHZ / 3;
        txBitWidth = CYCLES_PER_BIT_38400_16MHZ;
        bitsPerTick = BITS_PER_TICK_38400_Q11_16MHZ;
        shiftScaler = 11;
      #endif
      break;
    case 57600:
      #if F_CPU == 320000000L
        rxWindowWidth = CYCLES_PER_BIT_57600_320MHZ / 3;
        txBitWidth = CYCLES_PER_BIT_57600_320MHZ;
        bitsPerTick = BITS_PER_TICK_57600_Q15_320MHZ;
        shiftScaler = 15;
      #elif F_CPU == 256000000L
        rxWindowWidth = CYCLES_PER_BIT_57600_256MHZ / 3;
        txBitWidth = CYCLES_PER_BIT_57600_256MHZ;
        bitsPerTick = BITS_PER_TICK_57600_Q18_256MHZ;
        shiftScaler = 18;
      #else
        rxWindowWidth = CYCLES_PER_BIT_57600_16MHZ / 3;
        txBitWidth = CYCLES_PER_BIT_57600_16MHZ;
        bitsPerTick = BITS_PER_TICK_57600_Q16_16MHZ;
        shiftScaler = 16;
      #endif
      break;
    case 115200:
      #if F_CPU == 320000000L
        rxWindowWidth = CYCLES_PER_BIT_115200_320MHZ / 3;
        txBitWidth = CYCLES_PER_BIT_115200_320MHZ;
        bitsPerTick = BITS_PER_TICK_115200_Q13_320MHZ;
        shiftScaler = 13;
      #elif F_CPU == 256000000L
        rxWindowWidth = CYCLES_PER_BIT_115200_256MHZ / 3;
        txBitWidth = CYCLES_PER_BIT_115200_256MHZ;
        bitsPerTick = BITS_PER_TICK_115200_Q17_256MHZ;
        shiftScaler = 17;
      #else
        rxWindowWidth = CYCLES_PER_BIT_115200_16MHZ >> 1;
        txBitWidth = CYCLES_PER_BIT_115200_16MHZ;
        bitsPerTick = BITS_PER_TICK_115200_Q13_16MHZ;
        shiftScaler = 13;
      #endif
      break;
    case 230400:
      #if F_CPU == 320000000L
        rxWindowWidth = CYCLES_PER_BIT_230400_320MHZ >> 1;
        txBitWidth = CYCLES_PER_BIT_230400_320MHZ;
        bitsPerTick = BITS_PER_TICK_230400_Q16_320MHZ;
        shiftScaler = 16;
      #elif F_CPU == 256000000L
        rxWindowWidth = CYCLES_PER_BIT_230400_256MHZ >> 1;
        txBitWidth = CYCLES_PER_BIT_230400_256MHZ;
        bitsPerTick = BITS_PER_TICK_230400_Q10_256MHZ;
        shiftScaler = 10;
      #endif
      break;
    case 250000:
      #if F_CPU == 256000000L
        rxWindowWidth = CYCLES_PER_BIT_250000_256MHZ >> 1;
        txBitWidth = CYCLES_PER_BIT_250000_256MHZ;
        bitsPerTick = BITS_PER_TICK_250000_Q10_256MHZ;
        shiftScaler = 10;
      #endif
      break;
    case 500000:
      #if F_CPU == 256000000L
        rxWindowWidth = CYCLES_PER_BIT_500000_256MHZ >> 1;
        txBitWidth    = CYCLES_PER_BIT_500000_256MHZ;
        bitsPerTick   = BITS_PER_TICK_500000_Q9_256MHZ;
        shiftScaler   = 9;
      #endif
      break;
    case 1000000:
      #if F_CPU == 256000000L
        rxWindowWidth = CYCLES_PER_BIT_1000000_256MHZ >> 1;
        txBitWidth    = CYCLES_PER_BIT_1000000_256MHZ;
        bitsPerTick   = BITS_PER_TICK_1000000_Q8_256MHZ;
        shiftScaler   = 8;
      #endif
      break;
    default:
      break;
  }

  listener = this;
  SWUARTInstanceMap[rxPin] = this;

#if defined(_SWSERIAL32_DBG)
  GPIO_REG(GPIO_OUTPUT_EN)  |= (1 << RED_LED_OFFSET);
  GPIO_REG(GPIO_INPUT_EN)   &= ~(1 << RED_LED_OFFSET);
  GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << RED_LED_OFFSET);
  GPIO_REG(GPIO_OUTPUT_EN)  |= (1 << GREEN_LED_OFFSET);
  GPIO_REG(GPIO_INPUT_EN)   &= ~(1 << GREEN_LED_OFFSET);
  GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << GREEN_LED_OFFSET);
  GPIO_REG(GPIO_OUTPUT_EN)  |= (1 << BLUE_LED_OFFSET);
  GPIO_REG(GPIO_INPUT_EN)   &= ~(1 << BLUE_LED_OFFSET);
  GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << BLUE_LED_OFFSET);

  Serial.println("SWUART Instance information:");
  Serial.print("\tlistener:\t");
  Serial.println((uint32_t)(listener), HEX);
  Serial.print("\ttxBitWidth:\t");
  Serial.println(txBitWidth);
  Serial.print("\trxWindowWidth:\t");
  Serial.println(rxWindowWidth);
  Serial.print("\tbitsPerTick:\t");
  Serial.println(bitsPerTick);
  Serial.print("\tshiftScaler:\t");
  Serial.println(shiftScaler);
  Serial.print("\trxState:\t");
  Serial.println(rxState);
  Serial.print("\tprev_t0:\t");
  Serial.println((uint32_t)(prev_t0));
  Serial.print("\trxMask:\t\t");
  Serial.println(rxMask);
  Serial.print("\trxValue:\t");
  Serial.println(rxValue);

  Serial.print("\trxBuffer:\t");
  Serial.print("[");
  for (int i = 0; i < RX_BUFFER_SIZE; i++) {
    Serial.print(rxBuffer[i], HEX);
    if (i < RX_BUFFER_SIZE - 1)
      Serial.print(", ");
  }
  Serial.println("]");

  Serial.print("\trxHead:\t\t");
  Serial.println(rxHead);
  Serial.print("\trxTail:\t\t");
  Serial.println(rxTail);
  Serial.print("\trxBitMask:\t");
  Serial.println(rxBitMask, BIN);
  Serial.print("\ttxBitMask:\t");
  Serial.println(txBitMask, BIN);
  Serial.print("\trxPort:\t\t");
  Serial.println((uint32_t)(rxPort), HEX);
  Serial.print("\ttxPort:\t\t");
  Serial.println((uint32_t)(txPort), HEX);

  Serial.println("=====SWUARTInstanceMap=====");
  for (int i = 0; i < MAX_NUM_MUART; i++) {
    Serial.print((uint32_t)(SWUARTInstanceMap[i]), HEX);
    if (i < MAX_NUM_MUART - 1)
      Serial.print(",\t");
    if (i != 0 && i % 5 == 0)
      Serial.println();
  }
  Serial.println();
  Serial.println();
#endif

  interrupts(); // For some reason this is turned off by default
  set_csr(mstatus, MSTATUS_MIE);
} // listen

//----------------------------------------------------------------------------

void SoftwareSerial32::ignore()
{
  if (listener) {
    noInterrupts();
    listener = (SoftwareSerial32 *) NULL;
    // Call the globally defined PLIC handling detachInterrupt
    ::detachInterrupt(digitalPinToInterrupt(rxPin));
    interrupts();
  }
} // ignore

//----------------------------------------------------------------------------

void SoftwareSerial32::setBaudRate(uint32_t baudRate)
{
	//added extra 4800
  if (((baudRate ==  4800)         ||
	   (baudRate ==  9600)         ||
       (baudRate == 19200)         ||
       (baudRate == 31250)         ||
       (baudRate == 38400)         ||
       (baudRate == 57600)         ||
       (baudRate == 115200)        ||
       ((F_CPU >= 256000000L)      &&
         ((baudRate == 230400)     ||
          (baudRate == 250000)     ||
          (baudRate == 500000)     ||
          (baudRate == 1000000)))) &&
      (_baudRate != baudRate)) {

    _baudRate = baudRate;

    if (this == listener)
      listen();
  }
} // setBaudRate

//----------------------------------------------------------------------------

int SoftwareSerial32::available()
{
  uint8_t avail = ((rxHead - rxTail + RX_BUFFER_SIZE) % RX_BUFFER_SIZE);

  if (avail == 0) {
    noInterrupts();
    if (checkRxTime())
      avail = 1;

    interrupts();
  }
  return avail;
} // available

//----------------------------------------------------------------------------

int SoftwareSerial32::read()
{
  if (rxHead == rxTail) return -1;
  uint8_t c = rxBuffer[rxTail];
  rxTail = (rxTail + 1) % RX_BUFFER_SIZE;

  return c;

} // read

//----------------------------------------------------------------------------

void SoftwareSerial32::attachInterrupt( isr_t fn )
{
  noInterrupts();
  _isr = fn;
  interrupts();
} // attachInterrupt

//----------------------------------------------------------------------------

void SoftwareSerial32::startChar()
{
  rxState = 0;     // got a start bit
  rxMask  = 0x01;  // bit mask, lsb first
  rxValue = 0x00;  // RX character to be, a blank slate
} // startChar

//----------------------------------------------------------------------------

void SoftwareSerial32::rxISR( uint32_t pin )
{
  #if defined(_SWSERIAL32_DBG)
    GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << RED_LED_OFFSET);
  #endif
  noInterrupts();
  uint64_t t0;
  rdmcycle(&t0);

  // Load context from pinout to state map
  SoftwareSerial32* context = SWUARTInstanceMap[pin];

  uint32_t rxPort = *portInputRegister(digitalPinToPort(pin));
  uint32_t d = rxPort & context->rxBitMask;

  if (context->rxState == WAITING_FOR_START_BIT) {

    // If it looks like a start bit then initialize,
    // otherwise ignore the rising edge and exit.

    if (d != 0) return;   // it's high so not a start bit, exit
    context->startChar();

  } else {  // data bit or stop bit (probably) received

    // Determine how many bit periods have elapsed since the last transition.

    uint32_t rxBits          = context->bitTimes(t0 - context->prev_t0);
    uint8_t  bitsLeft        = 9 - context->rxState; // ignores stop bit
    bool     nextCharStarted = (rxBits > bitsLeft);

    uint32_t  bitsThisFrame   =  nextCharStarted ? bitsLeft : rxBits;

    context->rxState += bitsThisFrame;

    // Set all those bits

    if (d == 0) {
      // back fill previous bits with 1's
      while (bitsThisFrame-- > 0) {
        context->rxValue |= context->rxMask;
        context->rxMask   = context->rxMask << 1;
      }
      context->rxMask = context->rxMask << 1;
    } else { // d==1
      // previous bits were 0's so only this bit is a 1.
      context->rxMask   = context->rxMask << (bitsThisFrame-1);
      context->rxValue |= context->rxMask;
    }

    // If 8th bit or stop bit then the character is complete.

    if (context->rxState > 7) {
      context->rxChar( context->rxValue );

      if ((d == 1) || !nextCharStarted) {
        context->rxState = WAITING_FOR_START_BIT;
        // DISABLE STOP BIT TIMER

      } else {
        // The last char ended with 1's, so this 0 is actually
        //   the start bit of the next character.

        context->startChar();
      }
    }
  }
  context->prev_t0 = t0;  // remember time stamp
  // The same bitmask is used for the GPIO fields registers and is already obtained
  // by digitalPinToBitMask called by #::listen
  GPIO_REG(GPIO_RISE_IP) |= context->rxBitMask;
  GPIO_REG(GPIO_FALL_IP) |= context->rxBitMask;
    
  interrupts();
  #if defined(_SWSERIAL32_DBG)
    GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << RED_LED_OFFSET);
  #endif
} // rxISR

//----------------------------------------------------------------------------

bool SoftwareSerial32::checkRxTime()
{
  #if defined(_SWSERIAL32_DBG)
    GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << GREEN_LED_OFFSET);
  #endif
  if (rxState != WAITING_FOR_START_BIT) {

    uint32_t d = *rxPort & rxBitMask;

    if (d) {
      // Ended on a 1, see if it has been too long
      uint64_t t0;
      rdmcycle(&t0);
      uint32_t rxBits   = bitTimes( t0-prev_t0 );
      uint8_t bitsLeft = 9 - rxState; 
      bool     completed = (rxBits > bitsLeft);

      if (completed) {

        while (bitsLeft-- > 0) {
          rxValue |= rxMask;
          rxMask   = rxMask << 1;
        }

        rxState = WAITING_FOR_START_BIT;
        rxChar( rxValue );
        if (!_isr) {
          #if defined(_SWSERIAL32_DBG)
            GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << GREEN_LED_OFFSET);
          #endif
          return true;
        }
      }
    }
  }
  #if defined(_SWSERIAL32_DBG)
    GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << GREEN_LED_OFFSET);
  #endif
  return false;
} // checkRxTime

//----------------------------------------------------------------------------

void SoftwareSerial32::rxChar( uint8_t c )
{
  if (listener) {
    if (listener->_isr)
      listener->_isr( c );
    else {
      uint8_t index = (rxHead+1) % RX_BUFFER_SIZE;
      if (index != rxTail) {
        rxBuffer[rxHead] = c;
        rxHead = index;
      }
    }
  }

} // rxChar

//----------------------------------------------------------------------------

#ifdef NEOSWSERIAL_EXTERNAL_PCINT

  // Client code must call SoftwareSerial32::rxISR(PINB) in PCINT handler

#else

  // Must define all of the vectors even though only one is used.

  // This handy PCINT code for different boards is based on PinChangeInterrupt.*
  // from the excellent Cosa project: http://github.com/mikaelpatel/Cosa

  #define PCINT_ISR(pin)                    \
  extern "C" {                              \
  static void PCINT ## pin ## _vect (void)  \
  {                                         \
    SoftwareSerial32::rxISR(pin);           \
  } }

 /* PCINT_ISR(2);
  PCINT_ISR(3);
  PCINT_ISR(4);
  PCINT_ISR(5);
  PCINT_ISR(6);
  PCINT_ISR(7);
  PCINT_ISR(8);
  PCINT_ISR(9);
  PCINT_ISR(10);
  PCINT_ISR(11);
  PCINT_ISR(12);
  PCINT_ISR(13);*/
  PCINT_ISR(15);
  PCINT_ISR(16);
  /*PCINT_ISR(17);
  PCINT_ISR(18);
  PCINT_ISR(19);*/

  // Initialize all interrupts per pin and put in the appropriate dispatcher
  // Unsupported interrupt pins: 0, 1 and 14

  static void emptyISR() {}

  typedef void (*PCINTisr_ptr_t)(void);
  PCINTisr_ptr_t PCINTdispatcher[20] = {
    emptyISR,
    emptyISR,
    emptyISR,
    emptyISR,
    emptyISR,
    emptyISR,
    emptyISR,
    emptyISR,
    emptyISR,
    emptyISR,
    emptyISR,
    emptyISR,
    emptyISR, 
    emptyISR,
    emptyISR,
    PCINT15_vect,
    PCINT16_vect,
    emptyISR,
    emptyISR,
    emptyISR,
  };

  void attachPCINT(uint8_t rxPin)
  {
    ::attachInterrupt(digitalPinToInterrupt(rxPin), PCINTdispatcher[rxPin], CHANGE);
  }

#endif

//-----------------------------------------------------------------------------
// Instead of using a TX buffer and interrupt
// service, the transmit function is a simple timer0 based delay loop.
//
// Interrupts are disabled while the character is being transmitted and
// re-enabled after each character.

size_t SoftwareSerial32::write(uint8_t txChar)
{
  #if defined(_SWSERIAL32_DBG)
    GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << BLUE_LED_OFFSET);
  #endif

  if (!txPort)
    return 0;

  uint32_t txBit  = 0;
  uint32_t b      = 0;
  noInterrupts();
  uint64_t t0, t1;
  rdmcycle(&t0);

  while (txBit++ < 9) {         // repeat for start bit + 8 data bits
    if (b)                      // if bit is set
      *txPort |= txBitMask;     // set TX line high
    else
      *txPort &= ~txBitMask;    // else set TX line low

    // Hold the line for the bit duration
    rdmcycle(&t1);
    while ((uint32_t)(t1 - t0) < txBitWidth) {
      // If a HW interrupt is pending while writing use rxISR to handle it
      // in order to be able to support the asynchronousity of a UART
      if (read_csr(mip) & MIP_MEIP) {
        clear_csr(mip, MIP_MEIP);
        GPIO_REG(GPIO_FALL_IP) |= txBitMask;
        GPIO_REG(GPIO_RISE_IP) |= txBitMask;
        rxISR(rxPin);
      } else {
        checkRxTime();
      }
      rdmcycle(&t1);
    }
    t0    += txBitWidth;    // advance start time
    b      = txChar & 0x01; // get next bit in the character to send
    txChar = txChar >> 1;   // shift character to expose the following bit
  }

  *txPort |= txBitMask;   // stop bit is high
  rdmcycle(&t1);
  interrupts();
  while ((uint32_t)(t1 - t0) < txBitWidth) {
    checkRxTime();
    rdmcycle(&t1);
  }

  #if defined(_SWSERIAL32_DBG)
    GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << BLUE_LED_OFFSET);
  #endif

  return 1;               // 1 character sent
}

(Daniel kirubakaran) #19
H file
#ifndef SoftwareSerial32_h
#define SoftwareSerial32_h

#include "Arduino.h"


//---------------------------------------------------------------------------
//
// SoftwareSerial32, based on NeoSWSerial
// Copyright (C) 2015-2016, SlashDevin
// Copyright (c) 2018 Western Digital Corporation or its affiliates.
//
// SoftwareSerial32 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// SoftwareSerial32 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 General Public License for more details:
//
//     <http://www.gnu.org/licenses/>.
//
// Modified by Shadi Kamal <shadi.kamal@wdc.com>, 2018
//---------------------------------------------------------------------------



#define RX_BUFFER_SIZE 8192  // power of 2 for optimal speeds
static const uint8_t MAX_NUM_MUART = 20;

class SoftwareSerial32 : public Stream
{
  SoftwareSerial32( const SoftwareSerial32 & ); // Not allowed
  SoftwareSerial32 & operator =( const SoftwareSerial32 & ); // Not allowed

public:
  SoftwareSerial32(uint8_t receivePin, uint8_t transmitPin)
  {
    // TODO: Block generation of more than MAX_NUM_MUART UART instances
    rxPin = receivePin;
    txPin = transmitPin;
    _isr  = (isr_t) NULL;
  }
          void   begin(uint32_t baudRate=9600);   // initialize, set baudrate, listen
          void   listen();                        // enable RX interrupts
          void   ignore();                        // disable RX interrupts
          void   setBaudRate(uint32_t baudRate);  // 9600 [default], 19200, 38400

  virtual int    available();
  virtual int    read();
  virtual size_t write(uint8_t txChar);
  using Stream::write; // make the base class overloads visible
  virtual int    peek() { return 0; };
  virtual void   flush() {};
          void   end() { ignore(); }

  typedef void (* isr_t)( uint8_t );
  void attachInterrupt( isr_t fn );
  void detachInterrupt() { attachInterrupt( (isr_t) NULL ); };

          uint32_t bitTimes( uint32_t dt );

private:
           uint8_t  rxPin, txPin;
  volatile uint32_t *rxPort;

  uint32_t _baudRate;
  isr_t    _isr;

  void rxChar( uint8_t rx ); // buffer or dispatch one received character

  bool checkRxTime();

  void startChar();

  // Member variables
  SoftwareSerial32 *listener = (SoftwareSerial32 *) NULL;
  uint32_t txBitWidth;
  uint32_t rxWindowWidth;
  uint32_t bitsPerTick;
  uint8_t shiftScaler;
  uint8_t rxState;  // 0: got start bit; >0: bits rcvd
  uint64_t prev_t0; // mcycle is a 64-bit register which indicates the time t0 in cycles
  uint8_t rxMask;   // bit mask for building received character
  uint8_t rxValue;  // character being built
  uint8_t rxBuffer[RX_BUFFER_SIZE];
  uint8_t rxHead;   // buffer pointer input
  uint8_t rxTail;   // buffer pointer output
  uint32_t rxBitMask, txBitMask;
  volatile uint32_t *txPort;  // Hifive1 has 32-bit registers

public:
  // visible only so the ISRs can call it...
  static void rxISR( uint32_t pin_num );

  //#define NEOSWSERIAL_EXTERNAL_PCINT // uncomment to use your own PCINT ISRs
};
#endif

(Bruce Hoult) #20

Hi Daniel,

I have no idea what’s going on, and not having your hardware setup have no way to debug it. You’ll need to experiment and find exactly what the point is where you start getting garbage and which line of code causes it.

Do note that 8192 is a very large buffer on a machine with only 16384 of RAM in total. 64 should be huge if you’re not somehow turning off interrupts and/or taking a very long time (64+ ms) in another interrupt handler.

Maybe your stack is overrunning the buffer? Are there any functions with large local variables? (arrays, objects with arrays in them)