SpenceKonde / megaTinyCore

Arduino core for the tinyAVR 0/1/2-series - Ones's digit 2,4,5,7 (pincount, 8,14,20,24), tens digit 0, 1, or 2 (featureset), preceded by flash in kb. Library maintainers: porting help available!
Other
557 stars 145 forks source link

First couple of Serialprintln() from Softserial gives incorrect values attiny 1614 #279

Closed ldalep closed 3 years ago

ldalep commented 3 years ago

include

SoftwareSerial MySerial(PIN_PA4, PIN_PA5); // RX, TX

void setup() { MySerial.begin(9600); delay(100); MySerial.println("Hello World");

After the first one or two lines printed Softserial prints work fine

Is there a work around ?

SpenceKonde commented 3 years ago

First I've heard of this. As the cause is not known to me, I do not know if a workaround is possible, much less what it might be. The thing is... that code is just straight up copied from https://github.com/arduino/ArduinoCore-megaavr/tree/master/libraries/SoftwareSerial/src

If it were up to me and I had time, I'd reimplement the key functionality in inline assembly - there are so many things I'd like to do better, and know I could (beyond the many other problems I want to fix, when implemented in assembly, there's just nowhere for bugs like that to hide). Software serial implementations with both TX and RX, in general, just straight up suck even when 100% working - they're half duplex, requiring the full attention of the processor for both TX and RX.... It's the kind of thing you use only when you are absolutely desperate.. you must have a serial port, and both serial ports must do both TX and RX. This implementation is particularly odious because it uses attachInterrupt, which in turn grabs every pin interrupt available on the part!

But the problem is time, and the number of more important issues to deal with..... I think you will need to try to get a better idea of what'd going on here if you want this sorted out in a reasonable amount of time... You have verified that this isn't just the blast of repetitive reset requests sent to the target by jtag2updi when it is programming, right? (the reason they do that is that it's apparently required to be totally sure the WDT isn't on,, waiting to reset the MCU at the least convenient moment; they do that set of rapid fire resets - to deal with any MCU state, and ensure that WDT is turned off. I'm not sure if 100ms is long enough to wait at start; if you're seeing a few repetitions of the start of the expected message, this is likely what's happening.

Assuming waiting longer doesn't fix it and the wrong output is more complex, monitor it in a real serial terminal (hTerm is great if on windows - it lets you show received characters as ASCII... or hex, or even binary... AT THE SAME TIME (on consecutive lines, with the different representations lined up and highlighted in different colors) - try to see how it could have gotten from what you tried to send to what the other device saw.

ldalep commented 3 years ago

Thanks for the look at this even - can only imagine :

"You have verified that this isn't just the blast of repetitive reset requests sent to the target by jtag2updi when it is programming, right?"

Yes I have - it is coming from the port - I can live with the jtag2updi few characters as also seen on a hardware port as well (but these few characters only because of the jtag2updi). I verified this by long waits

I don't know if this helps - makes my head hurt but I have compiles and uploads with outputs using 2 Cool term ports - The first one is a clean as I got using a Serial println ();

Screen Shot 2020-12-16 at 11 00 49 AM

The next one is with the Serial println () commented out

Screen Shot 2020-12-16 at 11 01 54 AM

Finally with the Commented out Serial println() and a delay of 10msec after the first "Arduino Ready"

Screen Shot 2020-12-16 at 11 03 17 AM
Dlloydev commented 3 years ago

This isn't related to jtag2updi. The code above produces ⸮⸮⸮⸮⸮World when using nEDBG programming (curiosity Nano ATtiny3217).

I suspect the corrupt characters are partly because turning on pullups as done in SoftwareSerial.cpp won't work for tinyAVRs:

void SoftwareSerial::setTX(uint8_t tx)
{
  // First write, then set output. If we do this the other way around,
  // the pin would be output low for a short while before switching to
  // output high. Now, it is input with pullup for a short while, which
  // is fine. With inverse logic, either order is fine.
  digitalWrite(tx, _inverse_logic ? LOW : HIGH);
  pinMode(tx, OUTPUT);
  _transmitBitMask = digitalPinToBitMask(tx);
  uint8_t port = digitalPinToPort(tx);
  _transmitPortRegister = portOutputRegister(port);
}

void SoftwareSerial::setRX(uint8_t rx)
{
  pinMode(rx, INPUT);
  if (!_inverse_logic)
    digitalWrite(rx, HIGH);  // pullup for normal logic!
  _receivePin = rx;
  _receiveBitMask = digitalPinToBitMask(rx);
  uint8_t port = digitalPinToPort(rx);
  _receivePortRegister = portInputRegister(port);
}
ldalep commented 3 years ago

Seems to be something to what you say - if I put

pinMode(PIN_PB0,OUTPUT); digitalWrite(PIN_PB0,HIGH); Serial1.begin(9600);

where PIN_PB0 is the transmit pin and Serial1 is the software port this problem seems to go away - 56700 baud works to what a rathole I go down. Not sure why the author did it the way it was done......

Dlloydev commented 3 years ago

The author developed it for classic AVRs where writing the pin high first, then setting it as output would turn on the pullup. These newer AVRs have a separate register for enabling pullups, so the pin was probably floating (high-z) when initializing the software serial port. I haven't tested this, but using external pullups may also have solved the problem.

ldalep commented 3 years ago

External 10K did not solve the problem I tried that before I did the above. Why not push the pin To where it is suppose to go High or Low

Dlloydev commented 3 years ago

Why not push the pin To where it is suppose to go High or Low

I agree (TX pin) ... RX may already be pulled up or driven high depending on what devices are connected.