OSC20M Stored Frequency Error Compensation

This oscillator can operate at multiple frequencies, selected by the value of the Frequency Select bits (FREQSEL) in the Oscillator Configuration fuse (FUSE.OSCCFG) at Reset. As previously mentioned, appropriate calibration values are loaded to adjust to center frequency (OSC20M), and temperature drift compensation (TEMPCAL20M), meeting the specifications defined in the internal oscillator characteristics. For applications requiring a wider operating range, the relative factory stored frequency error after calibrations can be used. The four errors are measured at different settings and are available in the signature row as signed byte values.

  • SIGROW.OSC16ERR3V is the frequency error from 16 MHz measured at 3V
  • SIGROW.OSC16ERR5V is the frequency error from 16 MHz measured at 5V
  • SIGROW.OSC20ERR3V is the frequency error from 20 MHz measured at 3V
  • SIGROW.OSC20ERR5V is the frequency error from 20 MHz measured at 5V

The error is stored as a compressed Q1.10 fixed point 8-bit value in order not to lose resolution, where the MSb is the sign bit and the seven LSb the lower bits of the Q1.10.

BAUD act u a l = ( BAUD i d e a l + BAUD i d e a l * S i g R o w E r r o r 1024 )

The minimum legal BAUD register value is 0x40. The target BAUD register value may therefore not be lower than 0x4A to ensure that the compensated BAUD value stays within the legal range, even for parts with negative compensation values. The example code below demonstrates how to apply this value for a more accurate USART baud rate:

  #include <assert.h> 
  /* Baud rate compensated with factory stored frequency error */
  /* Asynchronous communication without Auto-baud (Sync ) */
  /* 16MHz Clock, 3V and 600 BAUD              */

  int8_t  sigrow_val    = SIGROW.OSC16ERR3V;    // read signed error
  int32_t baud_reg_val  = 600;                  // ideal BAUD register value
  
  assert (baud_reg_val >= 0x4A);                // Verify legal min BAUD register value with max neg comp
  baud_reg_val *= (1024 + sigrow_val);          // sum resolution + error
  baud_reg_val /=  1024;                        // divide by resolution
  USART0.BAUD = (int16_t) baud_reg_val;         // set adjusted baud rate