SpenceKonde / ATTinyCore

Arduino core for ATtiny 1634, 828, x313, x4, x41, x5, x61, x7 and x8
Other
1.53k stars 301 forks source link

Serial Corruption on new Tiny85 chips #806

Closed ahshah closed 9 months ago

ahshah commented 9 months ago

I received some new Tiny85 chips from digikey two days ago, and for the life of me I can't get Serial working.

The current state of affairs: On Attinycore 2.0.0 commit 747d8533b Part Number: ATTINY85-20PU-ND ATTiny 85 Optiboot enabled BOD Disabled Bootloader Entry conditions: 1s Chip: ATTiny85 Clock Source+Speed: 8MHZ Internal millis()/micros(): enabled Compiler optimizations: For Size Built in Software serial: No receiving, transmit only

The Code: ` void setup() { Serial.begin(9600); }

void loop() { Serial.printf("Heartbeat\n"); delay(1000); } `

The result in serial monitor at Baud 9600: 13:34:27.636 -> He��tbea���eart��at�H�ar�be�t 13:34:30.560 -> Hea��beat��ear��ea� 13:34:32.495 -> Hear�be�t�H��r�b��t�He��tbea� 13:34:35.437 -> H�ar�be�� 13:34:36.425 -> Heartbeat 13:34:37.377 -> �eartb��t 13:34:37.543 ->

Things i've tried:

Not sure what else i can try to clear this up. The clue that seems to be interesting is that the older chips work great. I wonder if theres some magic bit incantation I managed to chant out the first time I got started on these boards that is now escaping my memory.

ahshah commented 9 months ago

Okay it works now. What did I change? Well I connected the TX line of my sparkfun FTDI breakout to a pin on the Tiny85, and now it works. Even if I disconnect this pin. I think the FTDI controller got confused? I have no idea..

ahshah commented 9 months ago

Nevermind, the issue corrected it self for a few minutes but now its back..

ahshah commented 9 months ago

Okay looks like these tinies were kalibrated krazy.
I wrote this to help me figure out how to get a sane value:

void setup() {

  Serial.begin(9600);
}
uint8_t cal = OSCCAL;
void loop() {
  delay(1000);
  for (int i = 0; i < 256; i++) {
    OSCCAL = cal + i;
    for (int j = 0; j < 10; j++) {
      Serial.printf("Heartbeat OSSCAL %u plus %d\n", cal, i);
    }
  }
  delay(1000);

  for (int i = 0; i < 256; i++) {
    OSCCAL = cal - i;
    for (int j = 0; j < 10; j++) {
      Serial.printf("Heartbeat OSSCAL %u minus %d\n", cal, i);
    }
    delay(1000);
  }

  Serial.printf("Heartbeat OSSCAL %u\n", cal);
}

Then it was a question of waiting to get a sane value in the monitor, at which point i picked the middle of the pack. Would love to hear comments before i head off and buy an oscilloscope, just to satisfy my OCD..

sleemanj commented 9 months ago

Try adjusting the oscillator (OSCCAL), say every 5 times around the loop adjust the OSCCAL by +/- 1 (expanding search from the initial value) and see if it comes good for a given value of OSCCALMessage ID: @.***>

SpenceKonde commented 9 months ago

What I do is take an AVR with a crystal timebase (usually this is a classic somethingorothger) and I set up timer1 (or timera on modern AVR) to output a 500hz square wave. That's the reference, and then I time it with..... pulseIn() ("What?! Pulse in? That blob of inscrutable compiler generated assembly? We're supposed to have faith in that?" "On my cores, yes, yes you; see the notes in the .S file, I scruted that little bastard years ago, fixed the timeout bug, and got back the flash doing that cost by eliminating duplicated code. More recently I also knocked the binary size down a few bytes"). If you time the high or low pulse, that's 1ms long, you get the answer back in us according to it's (inaccurate) timebase's idea of 1us. Then have it automatically adjust OSCCAL up or down to try to get closer to 1000us, until it's at the closest setting write to EEPROM and bang. Then load your real sketch and have it write that eeprom value to OSCCAL.

Follow any write to OSCCAL with a NOP instruction unless you know you're only nuding it up one or two. (abruptly changing the oscillator cal is bad - there are requirements that the clock not change too much between cycles to prevent malfunctions. It is suspected that that these malfunctions would be similar to the manifestations of over overclocking, which results i 1's turning into 0's, and impact the instruction immediately following the OSCCAL write. NOP is the only safe operation, with opcode 0x0000. The practical validity of this trick is demonstrated by the general reliability of micronucleus. \

SpenceKonde commented 9 months ago

This is either: A clock accuracy issue (clock needs to be within +/- 3% or so for UART, the datasheet guarantees only +/-10%. though it's usually better than that). This is properly fixed by tuning the chip, I never finished the sketch to do that, but adjusting OSCCAL until you get clock speed that gives output that is most consistent with 8 MHz (ideally testing this using any means that isn't a software implementation, and then store that in the EEPROM (with EESAVE set first, of course); somewhere in the documentation I have more details about how to make the core autoload that value into OSCCAL on startup.

Note that OSCCAL is a fudge factor for everything that impacts the speed of the internal RC, and varies between specimens and on a specific specimen, between conditions. It is strongly impacted on most classic tinyAVRs by temperature (with a more modest effect from voltage). On the final four classic tinyAVRs (841, 441, 1634, 828) it has very little temperature dependance as they started compensating it, and it is typically dead on at 3v... but it is in the system power domain and isn't voltage compensated so it eventually diverges. At about 4v, it takes a turn skyward, enough that optiboot often won't work on internal at 5v (or didn't before we took countermeasures) on the final four. 8.2-8.4 was, as I recall typical on the final four at 5v, with almost no dependence on temperature.

Don't feel like checking the datasheet, but if you look at the datasheet for your part, way down at the end in characteristics graphs, there are two key typical characteristics graphs. First, the final four (and any other final-four-like AVR I don't know of) have a distinctive F_CPU vs VDD graph that increases sharply at above 4v, but changes little below it (and F_CPU vs T will be pretty flat). But you don't have one of those. The other two types can be distinguished by the F_CPU vs OSCCAL typical graph. Two designs were used (at least, but two are widely encountered in extant hardware) prior to the final four. One of them is relatively smooth from 0 to 255; this one is superior to the "bifurcated" one which has a jump at 0x80. I think the tiny85 got the bifurcated one (like the tiny84 originally did, but they have largely replaced it with the strictly better and less expensive 84A)

But yeah - a non-UART dependent way of measuring the clock speed and seeing a drift of a few percent would be a useful test - if you have a scope just set the fuse to output the clock on a pin, put it on the scope and see just how fast the clock is directly. That will tell you that either the default speed is off significantly on your specimens, or that it's not - and in the latter case, you know that there is a bug in the core software serial implementation (which on older parts may have been hidden by systematic biasses in calibration.

A character timing issue with tSS is