Skip to content

Commit

Permalink
V1.1.2
Browse files Browse the repository at this point in the history
  • Loading branch information
felias-fogg committed Jun 30, 2023
1 parent bc59dc2 commit 2de9f42
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 24 deletions.
8 changes: 6 additions & 2 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,15 @@ V1.0.1 (27.06.2023)
- moved utility folder to extras in order to be compliant with the
Arduino library rules

V1.1.0
V1.1.0 (30.06.2023)
- added ATtiny13 (with a really stripped down output and no error
checking)

V1.1.1
V1.1.1 (30.06.2023)
- had to add ATtiny13 conditionals in the init function in order to avoid getting an error from the
Vcc library
- and it had to be added to avrCalibrate.h as well (sigh)

V1.1.2 (30.06.2023)
- added some error detection for ATiny13 calibration
- added a trouble shooting section to the readme
2 changes: 1 addition & 1 deletion extras/calibServer/calibServer.ino
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// open drain pin using Timer1. Additionally, it passes the 1200 baud output of a target board
// to Serial.

#define VERSION "1.1.1"
#define VERSION "1.1.2"

#define FREQPIN MISO
#define TTYPIN SCK
Expand Down
34 changes: 21 additions & 13 deletions extras/calibTarget/calibTarget.ino
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// a fully calibrated clock will give us 100000 counts.


#define VERSION "1.1.1"
#define VERSION "1.1.2"

//#define TRUEMILLIVOLT 3309 // the true voltage measured in mV
#define TRUEMILLIVOLT 5003 // the true voltage measured in mV
Expand Down Expand Up @@ -49,6 +49,11 @@
#define SUCCTHRES 3 // number of consecutive measurements to accept a level change
#define MIN_CHANGE 100

#if defined(__AVR_ATtiny13__) || defined(__AVR_ATtiny13A__)
#define MAXOSCCAL 0x7F
#else
#define MAXOSCCAL 0x7FF
#endif

#if !defined(__AVR_ATtiny2313__) && !defined(__AVR_ATtiny2313A__) && !defined(__AVR_ATtiny4313__) \
&& !defined(__AVR_ATtiny13__) && !defined(__AVR_ATtiny13A__) // these do not support Vcc measuring
Expand Down Expand Up @@ -156,7 +161,7 @@ char valstr[16];
#else
char valstr[7];
#endif
long ticks[5];
long ticks[5] = {0,0,0,0,0};
long count;

void setup(void)
Expand Down Expand Up @@ -212,17 +217,18 @@ void calOSCCAL(void)
txstr(itoa(OSCCAL,valstr,16));
#endif

for (byte i=0; i<5; i++) ticks[i] = 0;
ticks[0] = measure();
if (!ticksOK(ticks)) return;
#if FLASHEND >= 0x400
if (!ticksOK()) return;
#endif
if (ticks[0] > TRUETICKS) dir = -1;
do {
reportMeasurement();
OSCCAL = OSCCAL + dir;
shiftTicks();
ticks[0] = measure();
if (!ticksOK(ticks)) return;
} while ((ticks[0] < TRUETICKS && dir == 1 && OSCCAL != 0xFF) || (ticks[0] >= TRUETICKS && dir == -1 && OSCCAL != 0));
if (!ticksOK()) return;
} while ((ticks[0] < TRUETICKS && dir == 1 && OSCCAL != MAXOSCCAL) || (ticks[0] >= TRUETICKS && dir == -1 && OSCCAL != 0));
reportMeasurement();
shiftTicks();
OSCCAL = OSCCAL + dir;
Expand Down Expand Up @@ -302,26 +308,28 @@ bool waitTransTo(boolean level)
}


boolean ticksOK(long t[5])
boolean ticksOK(void)
{
#if FLASHEND >= 0x400
if (t[0] < 0) {
if (ticks[0] < 0) {
#if FLASHEND >= 0x0800
txstr(F("\n\rOSCCAL calib. timeout\n\r"));
#else
#elif FLASHEND >= 0x400
txstr("\n\rtimeout\n\r");
#else
txchar('-');
#endif
return false;
}
if ((abs(t[0]-t[1]) < MIN_CHANGE) && (abs(t[1]-t[2]) < MIN_CHANGE) && (abs(t[0]-t[2]) < MIN_CHANGE)) {
if ((abs(ticks[0]-ticks[1]) < MIN_CHANGE) && (abs(ticks[1]-ticks[2]) < MIN_CHANGE) && (abs(ticks[0]-ticks[2]) < MIN_CHANGE)) {
#if FLASHEND >= 0x0800
txstr(F("\n\rOSCCAL calib. impossible\n\r"));
#else
#elif FLASHEND >= 0x400
txstr("\n\rNo change!\n\r");
#else
txchar('*');
#endif
return false;
}
#endif
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "avrCalibrate",
"version": "1.1.1",
"version": "1.1.2",
"keywords": "calibration, internal reference voltage, MCU clock, OSCCAL",
"description": "Supports calibration of OSCCAL value and internal reference voltage and supports setting them at startup",
"repository":
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=avrCalibrate
version=1.1.1
version=1.1.2
author=Bernhard Nebel <nebel@hinterm-ziel.de>
maintainer=Bernhard Nebel <nebel@hinterm-ziel.de>
sentence=This library determines OSCCAL calibration values for MCU clock frequency and internal reference voltage and loads them at setup.
Expand Down
Binary file added pics/calibServer-attiny13.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added pics/calibServer-attiny25.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 36 additions & 6 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This library contains just one function to set user calibration values in a (cla

### Purpose

If you use a crystal, a ceramic resonator, or an external oscillator, the MCU clock frequency is most probably very accurate, usually better than 0.1%. This means it can be used for timing purposes and to support asynchronous communication. However, if you are relying on the internal RC oscillator, the guaranteed accuracy is often much worse. For some MCUs, only ±10% is guaranteed. This is not tolerable for asynchronous serial communication. The accuracy can be improved significantly by setting the OSCCAL register. Similarly, the internal reference voltage is nominally 1.1 volt. But it is only guaranteed in the range of ±10%. Again, here one can improve accuracy by determining the exemplar specific value. And with that you can very precisely measure the supply voltage, which is very helpful when running on batteries.
If you use a crystal, a ceramic resonator, or an external oscillator, the MCU clock frequency is most probably very accurate, usually better than 0.1%. This means, the MCU can be used for timing purposes and it can communicate asynchronously. However, if you are relying on the internal RC oscillator, the guaranteed accuracy is often much worse. For some MCUs, only ±10% is guaranteed. This is not tolerable for asynchronous serial communication. The accuracy can be improved significantly by setting the OSCCAL register. Similarly, the internal reference voltage is nominally 1.1 volt. But it is only guaranteed in the range of ±10%. Again, here one can improve accuracy by determining the exemplar specific value. And with that you can very precisely measure the supply voltage, which is very helpful when running on batteries.

The `avrCalibrate` library contains just one function, called `init`, that does nothing more than loading predetermined values to the `OSCCAL` register (to adjust the MCU clock frequency) and to an internal variable (for remembering the true internal reference voltage) at startup. With that, using the Vcc library later on, you can get precise measurements of the supply voltage.

Expand All @@ -16,15 +16,23 @@ If you want to use only one of the values, then you still could use this functio

### Calibration process

The predetermined calibration values can either be stored in EEPROM or can be provided as constant values. The tricky part is, of course, to determine these calibration values. For that purpose, two Arduino sketches are provided in the `extras` folder. The `calibTarget` sketch needs to be loaded to the target board using a programmer. Before you do that, you need to adjust the compile-time constant `TRUEMILLIVOLT` to the true supply voltage of the target board (which should be measured using an accurate Multimeter). When you upload the sketch, make sure that you have selected 1 or 8 MHz clock frequency (1.2 or 9.6 MHz for the ATtiny13) generated internally. Otherwise the calibration will not work. Further disable the millis/micros interrupt when you target MCU has 2K Byte or less flash memory.
The predetermined calibration values can either be stored in EEPROM or can be provided as constant values. The tricky part is, of course, to determine these calibration values. For that purpose, two Arduino sketches are provided in the `extras` folder. The `calibTarget` sketch needs to be loaded to the target board using a programmer (perhaps using an Arduoino UNO as a programmer). Before you do that, you need to adjust the compile-time constant `TRUEMILLIVOLT` to the true supply voltage of the target board (which should be measured using an accurate multimeter). When you upload the sketch, make sure that you have selected 1 or 8 MHz clock frequency (1.2 or 9.6 MHz for the ATtiny13) generated internally. Otherwise the calibration will not work. Further disable the millis/micros interrupt when your target MCU has only 2K Byte flash memory.

Next you need to upload the `calibServer` sketch to an Arduino UNO or similar board that uses a ceramic resonator or crystal. It generates a reasonably accurate 10 Hz signal that is used to calibrate the `OSCCAL` value on the target board.

You then need to connect the two boards using an ICSP cable (see below). Now open the monitor window and set the baud rate to 115200. After pressing the `RESET` button on the server board, which will also reset the target board, the calibration can be started by pressing a key. This could look like as in the following picture.
You then need to connect the two boards using an ICSP cable (see below). Now open the monitor window and set the baud rate to 115200. After pressing the `RESET` button on the server board, which will also reset the target board as well, the calibration can be started by pressing any key (and sending the key press, if you use the Arduino monitor). This could look like as in the following picture.

![](pics/calibServer.png)

It starts with the OSCCAL calibration by systematically changing the OSCCAL value and stopping once the best value (close to 100000) has been determined. Afterwards, the correct internal reference voltage is determined. Note that both values are supply voltage and temperature dependent and should be performed in an environment similar to where the target board will be deployed. Furthermore, one should either give the MCU some time (1 minute) to reach its operating temperature or perform 5 or so calibration runs until the results stabilize (in particular the voltage calibration).
It starts with the OSCCAL calibration by systematically changing the OSCCAL value starting with the factory calibration and stopping once the best value (close to 100000) has been determined. Afterwards, the correct internal reference voltage is determined. Note that both values are supply voltage and temperature dependent and should be performed in an environment similar to where the target board will be deployed. Furthermore, one should either give the MCU some time (1 minute) to reach its operating temperature or perform 5 or so calibration runs until the results stabilize (in particular the voltage calibration).

The calibration process on the ATtiny2X MCUs is much less verbose, since the calibration sketch needs to fit into 2K. However, the same amount of information is provided. The output of a calibration process for an ATiny25 may look like as follows.

![](pics/calibServer-attiny25.png)

Finally, the output of the calibration sketch running on an ATtiny13 is truly minimal. First, it calibrates only the OSCCAL value. Second it displays only the start and the final value of the OSCCAL register.

![](pics/calibServer-attiny13.png)

The calibration values will be stored in EEPROM in the last 4 bytes. The first 2 bytes provide the internal reference voltage value (-1 means value is invalid). If the next byte is zero, then the stored OSCCAL calibration value stored in the last byte is valid.

Expand All @@ -39,7 +47,7 @@ Instead of using the EEPROM values, you can write down the values that are shown

The simplest way to connect the server board to the target board is to use an ICSP cable. However, this works only if you plan to run the target board with the same supply voltage as the one used for the server board because the calibration is supply voltage dependent. Furthermore, if you source a target board with 5V and the board is not 5V tolerant, you may actually destroy the electronics on it.

In order to deal with this problem, you may want to consider to buy a server board with switchable supply voltage such as [Seeduino 4.3](https://www.seeedstudio.com/Seeeduino-V4-2-p-2517.html) or [Keyestudio 328 PLUS Board](https://wiki.keyestudio.com/KS0486_Keyestudio_PLUS_Development_Board_(Black_And_Eco-friendly)) in order to overcome this hurdle.
In order to deal with this problem, you may want to consider to buy am UNO compatible server board with switchable supply voltage such as [Seeduino 4.3](https://www.seeedstudio.com/Seeeduino-V4-2-p-2517.html) or [Keyestudio 328 PLUS Board](https://wiki.keyestudio.com/KS0486_Keyestudio_PLUS_Development_Board_(Black_And_Eco-friendly)) in order to overcome this hurdle.

Alternatively, you can individually connect the MOSI, MISO, SCK, RESET, and GND pins on the ICSP connectors, and provide the target board with its own individual supply voltage. As long as it is 3.3 V or more, the target board will be able to talk to the server board. Further the 10 Hz signal is generated as an open collector signal, where the pull-up voltage comes from the target board. If you plan to run the target board with a lower supply voltage than 3.3 V, you will need level shifters.

Expand Down Expand Up @@ -79,4 +87,26 @@ As targets, the following MCUs are supported. On MCUs with only 2K bytes or less
* ATmega1280, ATmega2560
* ATmega32U4, ATmega16U4 (only internal reference voltage calibration)

The ATtiny43U board that I own does not deliver meaningful data when one tries to measure Vcc. For this reason, it is not supported. ATtinyX23 do not have an ADC. The ATtiny13 has an ADC, but you cannot connect the internal reference voltage to the ADC. So, in these two cases, one cannot measure Vcc. Finally, for the USB-MCUs ATmegaXU4, I am not aware of any Arduino core that supports using the RC-oscillator. So, only internal reference voltage calibration is supported.
The ATtiny43U board that I own does not deliver meaningful data when one tries to measure Vcc. For this reason, it is not supported. The ATtinyX23s do not have an ADC. The ATtiny13 has an ADC, but you cannot connect the internal reference voltage to the ADC. So, in these two cases, one cannot measure Vcc. Finally, for the USB-MCUs ATmegaXU4, I am not aware of any Arduino core that supports using the RC-oscillator. So, only internal reference voltage calibration is supported.c

### Trouble shooting

##### Problem: After the line "Feedback from target board", nothing is printed.

This could be caused by wrong wiring or by a discrepancy in the supposed clock frequency and the actual clock frequency of the target board. So, please check the wiring and maybe reflash the calibTarget sketch on the target board after using the `Burn bootloader` command in the `Tools` menu. This will not upload a boot loader, but it will set the right fuses.

##### Problem: After the line "Feedback from target board", a lot of garbled characters are printed.

This can happen if the clock frequency if off by more than 5%. After a while, when the clock frequency is changed to its nominal value, one should see legible text. If this does not happen, then the clock frequency is probably way off (perhaps there is a discrepancy of the supposed and the actual clock frequency: see above).

##### Problem: The OSCCAL calibration process is terminated with the message "OSCCAL calib. timeout" or "timeout" (or with a "-" on an ATtiny13)

This happens when the target board does not receive the 10 Hz signal from the server board. This is most probably a wiring error (check the MISO connection).

##### Problem: The OSCCAL calibration process is terminated with the message "OSCCAL calib. impossible" or "No change" (or with a "*" on an ATtiny13)

This happens when changing the OSCCAL register does not lead to a change of the clock frequency. It most probably means that the clock is generated by a crystal or resonator.

##### Problem: The final intref value is off by more than 10%., i.e., less than 1000 or more than 1200

This should not happen, except for MCUs with a nominal internal reference voltage different from 1100 mV (e.g., ATtiny26, ATmega8, ATmega16, ATmega32, and ATmega8535). It may happen, if you do not connect AVcc and Vcc (e.g., on a ATtinyX61 and ATtinyX7). The most likely reason is, however, a wrong value for the compile time constant `TRUEMILLIVOLT` in the `calibTarget` sketch.

0 comments on commit 2de9f42

Please sign in to comment.