@@ -271,17 +271,152 @@ void init()
271
271
{
272
272
// this needs to be called before setup() or some functions won't
273
273
// work there
274
+
275
+ /*************************** GET VCC & FUSE SETTING ***************************/
276
+
277
+
278
+ /* Measure VDD using ADC */
279
+ uint8_t supply_voltage ;
280
+
281
+ /* Initialize AC reference (what we are measuring) - 1.5V known */
282
+ VREF .CTRLA |= VREF_AC0REFSEL_1V5_gc ;
283
+
284
+ /* Enable AC reference */
285
+ VREF .CTRLB |= VREF_AC0REFEN_bm ;
286
+
287
+ /* DAC to max -- output reference voltage */
288
+ AC0 .DACREF = 0xFF ;
289
+
290
+ /* Enable DAC REF by selecting it as input and enabling AC */
291
+ AC0 .MUXCTRLA |= AC_MUXNEG_DACREF_gc ;
292
+ AC0 .CTRLA |= ADC_ENABLE_bm ;
293
+
294
+ /* Initialize ADC reference (VDD) */
295
+ ADC0 .CTRLC = ADC_REFSEL_VDDREF_gc ;
296
+
297
+ /* Initialize MUX (DAC/AC reference from VREF) */
298
+ ADC0 .MUXPOS = ADC_MUXPOS_DACREF_gc ;
299
+
300
+ /* Enable ADC */
301
+ ADC0 .CTRLA |= ADC_ENABLE_bm ;
302
+
303
+ /* Start a conversion */
304
+ ADC0 .COMMAND |= ADC_STCONV_bm ;
305
+
306
+ /* Wait until result is ready */
307
+ while (!(ADC0 .INTFLAGS & ADC_RESRDY_bm ));
308
+
309
+ /* Result ready */
310
+ /* supply_voltage = (VIN * 1024)/result where VIN = 1.5V from VREF */
311
+ uint16_t adc_result = ADC0 .RES ;
312
+
313
+ uint16_t voltage = (15 * 1024 ) / adc_result ; /* using 1.5 << 1 to avoid using float */
314
+
315
+ /* Only for the purposes of staying within safe operating range -- approximate */
316
+ if (voltage >= 48 ){ /* 4.8V+ -> 5V */
317
+ supply_voltage = VCC_5V0 ;
318
+ } else if (voltage >= 30 ){ /* 3V-4V7 -> 3V3 */
319
+ supply_voltage = VCC_3V3 ;
320
+ } else { /* < 3V -> 1V8 */
321
+ supply_voltage = VCC_1V8 ;
322
+ }
323
+
324
+ /* Fuse setting for 16/20MHz oscillator */
325
+ uint8_t fuse_setting = FUSE .OSCCFG & FUSE_FREQSEL_gm ;
326
+
327
+ /* Deinitialize ADC, AC & VREF */
328
+ ADC0 .CTRLA = 0x00 ;
329
+ ADC0 .MUXPOS = 0x00 ;
330
+ ADC0 .CTRLC = 0x00 ;
331
+
332
+ AC0 .CTRLA = 0x00 ;
333
+ AC0 .MUXCTRLA = 0x00 ;
334
+ AC0 .DACREF = 0xFF ;
335
+
336
+ VREF .CTRLB = 0x00 ;
337
+ VREF .CTRLA = 0x00 ;
274
338
275
339
/******************************** CLOCK STUFF *********************************/
276
340
277
- /* Disable system clock prescaler - F_CPU should now be ~16MHz */
278
- _PROTECTED_WRITE (CLKCTRL_MCLKCTRLB , 0x00 );
279
-
280
- /* Calculate actual F_CPU with error values from signature row */
281
- int8_t sigrow_val = SIGROW .OSC16ERR5V ;
282
- int64_t cpu_freq = F_CPU ;
283
- cpu_freq *= (1024 + sigrow_val );
284
- cpu_freq /= 1024 ;
341
+ int64_t cpu_freq ;
342
+
343
+ #if (PERFORM_SIGROW_CORRECTION_F_CPU == 1 )
344
+ int8_t sigrow_val = 0 ;
345
+ #endif
346
+
347
+ /* Initialize clock divider to stay within safe operating area */
348
+
349
+ if (supply_voltage >= VCC_5V0 ){
350
+
351
+ /* Disable system clock prescaler - F_CPU should now be ~16/20MHz */
352
+ _PROTECTED_WRITE (CLKCTRL_MCLKCTRLB , 0x00 );
353
+
354
+ /* Assign cpu_freq value and sigrow_val depending on fuse setting */
355
+ if (fuse_setting == FREQSEL_20MHZ_gc ){
356
+ cpu_freq = 20000000 ;
357
+
358
+ #if (PERFORM_SIGROW_CORRECTION_F_CPU == 1 )
359
+ sigrow_val = SIGROW .OSC20ERR5V ;
360
+ #endif
361
+
362
+ } else { /* fuse_setting == FREQSEL_16MHZ_gc */
363
+ cpu_freq = 16000000 ;
364
+
365
+ #if (PERFORM_SIGROW_CORRECTION_F_CPU == 1 )
366
+ sigrow_val = SIGROW .OSC16ERR5V ;
367
+ #endif
368
+
369
+ }
370
+
371
+ } else if (supply_voltage == VCC_3V3 ) {
372
+
373
+ /* Enable system clock prescaler to DIV2 - F_CPU should now be ~8/10MHz */
374
+ _PROTECTED_WRITE (CLKCTRL_MCLKCTRLB , (CLKCTRL_PEN_bm | CLKCTRL_PDIV_2X_gc ));
375
+
376
+ /* Assign cpu_freq value and sigrow_val depending on fuse setting */
377
+ if (fuse_setting == FREQSEL_20MHZ_gc ){
378
+ cpu_freq = 10000000 ;
379
+
380
+ #if (PERFORM_SIGROW_CORRECTION_F_CPU == 1 )
381
+ sigrow_val = SIGROW .OSC20ERR3V ;
382
+ #endif
383
+
384
+ } else { /* fuse_setting == FREQSEL_16MHZ_gc */
385
+ cpu_freq = 8000000 ;
386
+
387
+ #if (PERFORM_SIGROW_CORRECTION_F_CPU == 1 )
388
+ sigrow_val = SIGROW .OSC16ERR3V ;
389
+ #endif
390
+ }
391
+
392
+ } else {
393
+ /* Shouldn't get here but just in case... */
394
+
395
+ /* Enable system clock prescaler to DIV4 - F_CPU should now be ~4/5MHz */
396
+ _PROTECTED_WRITE (CLKCTRL_MCLKCTRLB , (CLKCTRL_PEN_bm | CLKCTRL_PDIV_4X_gc ));
397
+
398
+
399
+ if (fuse_setting == FREQSEL_20MHZ_gc ){
400
+ cpu_freq = 5000000 ;
401
+ #if (PERFORM_SIGROW_CORRECTION_F_CPU == 1 )
402
+ sigrow_val = SIGROW .OSC20ERR3V ;
403
+ #endif
404
+
405
+ } else { /* fuse_setting == FREQSEL_16MHZ_gc */
406
+ cpu_freq = 4000000 ;
407
+ #if (PERFORM_SIGROW_CORRECTION_F_CPU == 1 )
408
+ sigrow_val = SIGROW .OSC16ERR3V ;
409
+ #endif
410
+ }
411
+ }
412
+
413
+ #if (PERFORM_SIGROW_CORRECTION_F_CPU == 1 )
414
+ /* Calculate actual F_CPU with error values from signature row */
415
+ cpu_freq *= (1024 + sigrow_val );
416
+ cpu_freq /= 1024 ;
417
+ #endif /* (CORRECT_F_CPU == 1) */
418
+
419
+ /* Apply calculated value to F_CPU_CORRECTED */
285
420
F_CPU_CORRECTED = (uint32_t )cpu_freq ;
286
421
287
422
/***************************** TIMERS FOR PWM *********************************/
0 commit comments