Serial communication: Teensy 3.2 received junk from Digispark clone (ATtiny85)

Status
Not open for further replies.

feklee

Active member
I want a Digispark clone (ATtiny85) to send data to a Teensy 3.2. On the Digispark, I use the SoftSerial library. On the Teensy, I use one of the hardware serial interfaces. The problem is that the Teensy outputs:

Code:
DD�D�D�D�D�D�ÔÔD�DÔÔÔÔÔD�ÔÔDD�D�D�ÔD�DÔÔ…

Expected is:
Code:
Hi!Hi!Hi!Hi!Hi!Hi!Hi!Hi!Hi!Hi!Hi!…

This looks like a timing problem to me, especially considering the randomness. But how do I resolve it?

What I already tried is playing with the communication speed. At 9600, 4800, 2400, and 1200 baud I got the above garbage. At 300 baud there was nothing received at all.

sender.ino compiled and uploaded with Digispark (16 Mhz - No USB) selected in the Arduino IDE:
Code:
#include <SoftSerial.h>
#include <TinyPinChange.h>

const uint8_t ledPin = 1;
const uint8_t rxPin = 0;
const uint8_t txPin = 2;

SoftSerial mySerial(rxPin, txPin); // RX, TX

void setup() {
  mySerial.begin(4800);
  mySerial.txMode();
  pinMode(ledPin, OUTPUT);
}

void flashLed() {
  digitalWrite(ledPin, HIGH);
  delay(100);
  digitalWrite(ledPin, LOW);
}

void loop() {
  mySerial.write("Hi!");
  flashLed();
  delay(1000);
}

received.ino, compiled and uploaded to the Teensy 3.2:

Code:
const uint8_t ledPin = 13;

void setup() {
  Serial.begin(9600);
  Serial1.begin(4800);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
}

void flashLed() {
  digitalWrite(ledPin, HIGH);
  delay(100);
  digitalWrite(ledPin, LOW);
}

void loop() {
  char c;

  if (Serial1.available()) {
    c = Serial1.read();
    Serial.print(c);
    flashLed();
  }
}

Circuit:
serial-circuit.jpg

(Next step is using half-duplex communication, to get rid of one wire.)
 
are your usb cables going to same pc? because i dont see any common grounds between both mcus..

Both were connected to the same USB hub. Anyhow, I added common ground on the breadboard as well, but the issue persists:

common-ground-serial-circuit.jpg

I forgot to mention: When the Teensy receives “Hi!” from the Digispark, then the Teensy’s LED only flashes once. When I use another Digispark as a receiver, then the LED of that flashes once per character received.
 
On both sides, you use Serialx.begin(Baudrate) without specifying more serial protocol details. On the Teensy, it defaults to 8N1. Perhaps on the other little thing, it defaults to a different number of total bits, start bits, stop bits, and so on...

BTW: SoftSerial does simple and cheap bit banging on GPIO pins. This is a no-no for serious developers because each interrupt or other unexpected delay in program execution risks to trouble the timing. Today's modern MCUs have mostly more than one hardware UART, thus, there shouldn't be any reason to use older stuff without.
 
To understand what happens in your specific case, simply take your oscilloscope or logic analyzer to show the bit pattern and timing sent by the Digispark
 
I don't have a Digispark, but I do have Arduino Uno. So I tried to set up this test using Uno.

DSC_0980_web.jpg

Here's the result I see from Teensy in the Arduino Serial Monitor.

sc.png

I ran the exact same code you posted on Teensy.

For Arduino Uno, I had to adapt your code slightly. Seems on Digispark the library is SoftSerial versus SoftwareSerial. I also had to change to pin 3 for transmit and 13 for the LED, since Uno reserves pins 0 & 1 for its serial port. Here's the exact code I ran on Uno for this test.

Code:
#include <SoftwareSerial.h>

const uint8_t ledPin = 13;
const uint8_t rxPin = 3;
const uint8_t txPin = 2;

SoftwareSerial mySerial(rxPin, txPin); // RX, TX

void setup() {
  mySerial.begin(4800);
  pinMode(ledPin, OUTPUT);
}

void flashLed() {
  digitalWrite(ledPin, HIGH);
  delay(100);
  digitalWrite(ledPin, LOW);
}

void loop() {
  mySerial.write("Hi!");
  flashLed();
  delay(1000);
}
 
I forgot to mention: When the Teensy receives “Hi!” from the Digispark, then the Teensy’s LED only flashes once.

I was able to reproduce this problem. It's caused by lack of any delay when turning the LED off. What you're seeing is 3 "blinks" which run together, visually appearing to be 1 longer blink.

You can solve this problem by changing this:

Code:
void flashLed() {
  digitalWrite(ledPin, HIGH);
  delay(100);
  digitalWrite(ledPin, LOW);
}

to this:

Code:
void flashLed() {
  digitalWrite(ledPin, HIGH);
  delay(50);
  digitalWrite(ledPin, LOW);
  delay(50);
}

I uploaded the code to Teensy with this change and I can confirm I'm seeing 3 blinks.
 
One more quick thing, this is indeed a known problem.

At 300 baud there was nothing received at all.

300 baud does not work on Teensy 3.2, unless you slow the clock to only 24 MHz in Tools > CPU Speed. When running at 96 MHz, the serial port just can't do baud rates that slow.

1200 and faster work fine.

Detailed documentation here:

https://www.pjrc.com/teensy/td_uart.html

If you *really* need 300 baud on Teensy 3.2, you can get it with AltSoftSerial.
 
Thanks for all the help! In particular thanks to @PaulStoffregen for trying to reproduce the issue using an Arduino Uno, for debugging my code, and for explaining 300 baud support!

Finally, I got the circuit to work. The board that I used as sender was broken. Replacing it solved the issue.

(This is a typical beginner issue. I was assuming that I was doing something wrong. 8N1 serial communication is pretty much voodoo to me. Only after realizing that communication between the Digispark clones also doesn’t work, I tried replacing one. See also my topic SoftSerial does not work (with clones) in the Digistump forums.)

On both sides, you use Serialx.begin(Baudrate) without specifying more serial protocol details. On the Teensy, it defaults to 8N1.

Quote from Softserial.h: <SoftSerial> library is exactly the same as the <SoftwareSerial> library but used with the <TinyPinChange> library which allows to share the Pin Change Interrupt Vector.

And the SoftwareSerial library does use 8N1.

Today's modern MCUs have mostly more than one hardware UART, thus, there shouldn't be any reason to use older stuff without.

Suggestions are welcome! Requirements:
  • dirt cheap, as I need a couple dozen boards
  • four serial channels that support half-duplex communication

This is for an experimental construction kit, where I want to have one microcontroller in each node: Github repo (not much there yet)
 
I’m back at receiving junk on the Teensy. But this time, I think it’s my code. I added another ATtiny85 as a relay:

relay-circuit.jpg

Every time the relay receives a character from the sender, it sends it right away to the Teensy:

Code:
void loop() {
  if (receiveSerial.available()) {
    char c = receiveSerial.read();
    sendSerial.write(c);
    flashLed();
    delay(100);
  }
}

This seems to be a bad idea. If I have each ATtiny85 communicate directly with the Teensy, then communication is clean.

BTW I looked for boards with four UART, but they all seem to be rather expensive. Price limit is around 10 USD. Also, the boards should be not much larger than a Teensy, better smaller.

Full code on the relay:

Code:
#include <SoftSerial.h>
#include <TinyPinChange.h>

const uint8_t ledPin = 1;
const uint8_t receivePin = 4;
const uint8_t sendPin = 0;

SoftSerial receiveSerial(receivePin, receivePin);
SoftSerial sendSerial(sendPin, sendPin);

void setup() {
  receiveSerial.begin(4800);
  receiveSerial.rxMode();
  sendSerial.begin(4800);
  sendSerial.txMode();
  receiveSerial.listen();
  pinMode(ledPin, OUTPUT);
}

void flashLed() {
  digitalWrite(ledPin, HIGH);
  delay(100);
  digitalWrite(ledPin, LOW);
}

void loop() {
  if (receiveSerial.available()) {
    char c = receiveSerial.read();
    sendSerial.write(c);
    flashLed();
    delay(100);
  }
}
 
You can get a Teensy LC for $11.29 https://store.oshpark.com/products/teensy-lc

There are probably lots of other options (personally I like Teensy...), but for example you can get a Robotis Open CM904A chip $9.95 (http://www.robotis.us/opencm9-04-a-no-connectors-onboard/) which is bigger and has 3 USARTS... Adafruit Feather M0 again larger and more expensive than Teensy LC...

With your code, I wonder how well SoftwareSerial works at 4800 baud on those boards...

Again with that code, personally I would change a few things, but again may not mater.
Code:
#include <SoftSerial.h>
#include <TinyPinChange.h>

const uint8_t ledPin = 1;
const uint8_t receivePin = 4;
const uint8_t sendPin = 0;

SoftSerial receiveSerial(receivePin, receivePin);
SoftSerial sendSerial(sendPin, sendPin);

void setup() {
  receiveSerial.begin(4800);
  receiveSerial.rxMode();
  sendSerial.begin(4800);
  sendSerial.txMode();
  receiveSerial.listen();
  pinMode(ledPin, OUTPUT);
}

void flashLed() {
  digitalWrite(ledPin, HIGH);
  delay(50);
  digitalWrite(ledPin, LOW);
  delay(50);
}

void loop() {
  if (receiveSerial.available()) {
    while (receiveSerial.available()) {
      char c = receiveSerial.read();
      sendSerial.write(c);
    }
    flashLed();
  }
  delay(100);
}

Changed the Flashled as to change the delays, as if you called it a few times in a row it would not show the low state as no delay between low and high.
And in loop, I transmit everything pending before sleeping.

Not sure if maybe your software serial is getting corrupted ...
 
3 USARTS...

Thanks for all your suggestions! In fact I’ve a Teensy LC here. Unfortunately, three UARTs is one too few.

In the meantime, I’ve read that some boards allow reconfiguring UART pinout. The ESP32 is an example: #152 Quickie: Additional ESP32 Serial Channels in Arduino IDE (Youtube)

I wonder if there is any board where UART pinout can be reconfigured while a sketch is running. Because, that would be a good solution. While I need four UARTs, the UARTs don’t need to communicate simultaneously. It is fine for them to communicate one after another, in well defined discrete time-slots.

In fact avoiding doing too much simultaneously also solves the issue that I had with the relay. Now data is relayed only after a full package has been received. Between sending packages Hi\n, the sender pauses for a second. Excerpt from relay.ino:

Code:
void loop() {
  if (receiveSerial.available()) {
    char c = receiveSerial.read();
    appendToBuffer(c);
    if (c == '\n') { // end of package received?
      flushBuffer();
      flashLed();
    }
  }
}

Find the full code in commit 21ed3151d32b26e0f52df1072b63f64c473c6224 in my GitHub repo feklee/san.

For a start, SoftSerial could be a solution. Speed likely is an issue, though. 4800 baud is slow to have fun.
 
Sounds like a reasonable solution.

I thought about suggesting something like that as well as to try to minimize other interrupts during the software serial processing.

As for re-configuring Serial ports while sketch is running, I believe you can do that with most Teensy 3.x/LC boards.

Example Serial1 defaults to pins 0 and 1 for RX/TX, but you could also use pins 3 and 4(or 5)...

Not sure how well this would work with your hardware, but I believe it is possible to do things like:
Code:
    Serial1.begin(...)
    Serial1.setTX(1);
    Serial1.setRX(0);
    // Right now Serial 1 is talking on pins 0 and 1
    ... 
    Serial1.setTX(5);
    Serial1.setRX(3);
    // Now Serial 1 is talking on pins 3 and 5
    ...
But doing these calls leave the previous pins in default unused (floating?) state... Might not be an issue, but might be... If a problem, may be solvable by using a Pull up or down resistor... Maybe more problem than it is worth...
 
I set the old pins as INPUT_DISABLE and change the RX/TX pin dynamically without calling begin(unless i need to change baud rate too) then begin could be used. the auto ESP flasher i wrote does this. If you plan to not have the old pins floating, for uart, you may assign them (at least on teensy) as INPUT_PULLUP or INPUT_PULLDOWN, both work well for uart during my testing
 
The setTX and setRX calls set the previous pins to config 0... like: CORE_PIN1_CONFIG = 0;
Which is INPUT_DISABLE...
 
Status
Not open for further replies.
Back
Top