MCUdude / MightyCore

Arduino hardware package for ATmega1284, ATmega644, ATmega324, ATmega324PB, ATmega164, ATmega32, ATmega16 and ATmega8535
Other
649 stars 182 forks source link

ATMEGA32 internal clock problems #236

Closed sensorhost closed 2 years ago

sensorhost commented 2 years ago

I have a board with an ATMEGA32A without an on-board crystal. I am having some problems with the clock speeds.

If set to 8Mhz internal, the clock rate seems correct (1 second flashes on an LED in code takes 1 second) but the UART output at 9600 is garbled. I have tried various internal Osc settings and serial print baud rates and almost all the ones I tried don't work.

Notes (or what does work kind-of)

  1. Setting 4Mhz internal Osc and UART set to 38400 Serial.begin(38400). Serial terminal set to 9600 it prints serial data ok but the LED flash rate for 1 second actually takes 4 seconds.
  2. Using a 1Mhz internal clock the 1 second flashes are correct and the serial prints at 9600 baud ok.

I can program using both ICSP and via UART with 1Mhz internal clock.

It seems there might be some clock settings that are not quite right. I have tried looking through the source code but not sure where to look or what I even need to change.

Any help is appreciated.

sensorhost commented 2 years ago

I have identified a bit more information that may help. I noticed in boards.txt option 32.menu.clock.8MHz_internal.bootloader.ckopt_bit=1 means that the baud rate is using the high rate, so I have manually set UBRRL and UBRRH to 102 which still gives slightly garbled serial data. I tweaked the value (I am using the not so accurate internal oscillator) and found that 100 gives me a stable 9600 baud using the 8Mhz internal oscillator option.

MCUdude commented 2 years ago

The issue you're having is caused by the internal oscillator. Sometimes it's not accurate enough to be used with UART communication without calibrating the internal oscillator using the OSCCAL register.

Read about the OSCCAL register in the ATmega datasheet. Basically, this register has a factory value, and maybe a bit "off". Try this sketch and upload the output to see where you're at.


void setup()
{
  const uint8_t old_osccal = OSCCAL;
  Serial.begin(9600);

  for(uint8_t i = old_osccal - 0x20; i < old_osccal + 0x20; i++)
  {
    OSCCAL = i;
    Serial.printf(F("Old OSCCAL: 0x%02x, New OSCCAL: 0x%02x, Diff: %d, Text: The quick brown fox jumps over the lazy dog\n"), old_osccal, OSCCAL, OSCCAL - old_osccal);
  }
}

void loop()
{
}
sensorhost commented 2 years ago

As always, thank you for such a quick and detailed answer. Super highly appreciated.

I did spend a number of hours working on this and studying the data sheet and eventually sorted out the OSCCAL value for 8Mhz fine. It seems the ATMEGA32 is supposed to have OSCCAL values for 1,2,4, & 8 Mhz stored inside from factory but is also states that only the 1Mhz value is automatically loaded. This basically means that programming via the UART is not really possible using the boot loader unless I am using 1Mhz internal clock. I have proven this works at 1Mhz but then my DS18B20 sensor doesn't work due to timing issues as the MCU is too slow (and not related to this core of course).

I still think may be a problem as when I compile for 4Mhz internal oscillator, delay(1000); takes 4 seconds unless this is expected behaviour. Also, setting the baud rate to 38400 (as per my original post) give a actual baud rate of 9600.

MCUdude commented 2 years ago

It seems the ATMEGA32 is supposed to have OSCCAL values for 1,2,4, & 8 Mhz stored inside from factory but it also states that only the 1Mhz value is automatically loaded.

From the datasheet:

The ATmega32 stores four different calibration values for the internal RC Oscillator. These bytes resides in the signature row High Byte of the addresses 0x0000, 0x0001, 0x0002, and 0x0003 for 1, 2, 4, and 8MHz respectively. During Reset, the 1MHz value is automatically loaded into the OSCCAL Register. If other frequencies are used, the calibration value has to be loaded manually, see “Oscillator Calibration Register – OSCCAL” on page 30 for details.

I'm not sure if the ATmega32 has four different internal oscillators or a single one that's divided down. But if there exist calibration values for 2, 4, and 8 MHz as well, these have to indeed be loaded manually. I've never done this since I always use external oscillators when using UART, in high-volume applications usually Murata CSTNE type resonators due to their small size.

I'm not sure it's possible to read the signature bytes in the program itself, but an external programmer can do this with the following Avrdude command. You'll obviously have to change the paths to Avrdude, the avrdude.conf file and probably the programmer.

/path/to/avrdude -C /path/to/avrdude.conf -v -p atmega32 -c usbasp -P USB -Ucalibration:r:-:h

I still think may be a problem as when I compile for 4Mhz internal oscillator, delay(1000); takes 4 seconds unless this is expected behaviour. Also, setting the baud rate to 38400 (as per my original post) give a actual baud rate of 9600.

Sounds like the program itself is compiled for a 16 MHz clock, but the actual clock speed is 4 MHz. Try changing the clock speed in Arduino IDE, re-compile and upload again