Skip to content

Commit 1c0717c

Browse files
authored
Merge pull request #12 from espreng/bugfix-fcpu-corrected
Changed approach to F_CPU to be user-defined
2 parents 3fa390c + f2a8550 commit 1c0717c

File tree

1 file changed

+42
-133
lines changed

1 file changed

+42
-133
lines changed

cores/arduino/wiring.c

Lines changed: 42 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -276,146 +276,55 @@ void init()
276276
// this needs to be called before setup() or some functions won't
277277
// work there
278278

279-
/*************************** GET VCC & FUSE SETTING ***************************/
280-
281-
282-
/* Measure VDD using ADC */
283-
uint8_t supply_voltage;
284-
285-
/* Initialize AC reference (what we are measuring) - 1.5V known */
286-
VREF.CTRLA |= VREF_AC0REFSEL_1V5_gc;
287-
288-
/* Enable AC reference */
289-
VREF.CTRLB |= VREF_AC0REFEN_bm;
290-
291-
/* DAC to max -- output reference voltage */
292-
AC0.DACREF = 0xFF;
293-
294-
/* Enable DAC REF by selecting it as input and enabling AC */
295-
AC0.MUXCTRLA |= AC_MUXNEG_DACREF_gc;
296-
AC0.CTRLA |= ADC_ENABLE_bm;
297-
298-
/* Initialize ADC reference (VDD) */
299-
ADC0.CTRLC = ADC_REFSEL_VDDREF_gc;
300-
301-
/* Initialize MUX (DAC/AC reference from VREF) */
302-
ADC0.MUXPOS = ADC_MUXPOS_DACREF_gc;
303-
304-
/* Enable ADC */
305-
ADC0.CTRLA |= ADC_ENABLE_bm;
306-
307-
/* Start a conversion */
308-
ADC0.COMMAND |= ADC_STCONV_bm;
309-
310-
/* Wait until result is ready */
311-
while(!(ADC0.INTFLAGS & ADC_RESRDY_bm));
312-
313-
/* Result ready */
314-
/* supply_voltage = (VIN * 1024)/result where VIN = 1.5V from VREF */
315-
uint16_t adc_result = ADC0.RES;
316-
317-
uint16_t voltage = (15 * 1024) / adc_result; /* using 1.5 << 1 to avoid using float */
318-
319-
/* Only for the purposes of staying within safe operating range -- approximate */
320-
if(voltage >= 48){ /* 4.8V+ -> 5V */
321-
supply_voltage = VCC_5V0;
322-
} else if (voltage >= 30){ /* 3V-4V7 -> 3V3 */
323-
supply_voltage = VCC_3V3;
324-
} else { /* < 3V -> 1V8 */
325-
supply_voltage = VCC_1V8;
326-
}
327-
328-
/* Fuse setting for 16/20MHz oscillator */
329-
uint8_t fuse_setting = FUSE.OSCCFG & FUSE_FREQSEL_gm;
330-
331-
/* Deinitialize ADC, AC & VREF */
332-
ADC0.CTRLA = 0x00;
333-
ADC0.MUXPOS = 0x00;
334-
ADC0.CTRLC = 0x00;
335-
336-
AC0.CTRLA = 0x00;
337-
AC0.MUXCTRLA = 0x00;
338-
AC0.DACREF = 0xFF;
339-
340-
VREF.CTRLB = 0x00;
341-
VREF.CTRLA = 0x00;
342-
343279
/******************************** CLOCK STUFF *********************************/
344280

281+
/* We assume 5V operating frequency and FUSE.OSCCFG -> 16MHz */
282+
345283
int64_t cpu_freq;
346284

347-
#if (PERFORM_SIGROW_CORRECTION_F_CPU == 1)
348-
int8_t sigrow_val = 0;
349-
#endif
350-
351-
/* Initialize clock divider to stay within safe operating area */
352-
353-
if(supply_voltage >= VCC_5V0){
354-
355-
/* Disable system clock prescaler - F_CPU should now be ~16/20MHz */
356-
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, 0x00);
357-
358-
/* Assign cpu_freq value and sigrow_val depending on fuse setting */
359-
if(fuse_setting == FREQSEL_20MHZ_gc){
360-
cpu_freq = 20000000;
361-
362-
#if (PERFORM_SIGROW_CORRECTION_F_CPU == 1)
363-
sigrow_val = SIGROW.OSC20ERR5V;
364-
#endif
365-
366-
} else { /* fuse_setting == FREQSEL_16MHZ_gc */
367-
cpu_freq = 16000000;
368-
369-
#if (PERFORM_SIGROW_CORRECTION_F_CPU == 1)
370-
sigrow_val = SIGROW.OSC16ERR5V;
371-
#endif
372-
373-
}
374-
375-
} else if (supply_voltage == VCC_3V3) {
376-
377-
/* Enable system clock prescaler to DIV2 - F_CPU should now be ~8/10MHz */
378-
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, (CLKCTRL_PEN_bm | CLKCTRL_PDIV_2X_gc));
379-
380-
/* Assign cpu_freq value and sigrow_val depending on fuse setting */
381-
if(fuse_setting == FREQSEL_20MHZ_gc){
382-
cpu_freq = 10000000;
383-
384-
#if (PERFORM_SIGROW_CORRECTION_F_CPU == 1)
385-
sigrow_val = SIGROW.OSC20ERR3V;
386-
#endif
387-
388-
} else { /* fuse_setting == FREQSEL_16MHZ_gc */
389-
cpu_freq = 8000000;
390-
391-
#if (PERFORM_SIGROW_CORRECTION_F_CPU == 1)
392-
sigrow_val = SIGROW.OSC16ERR3V;
393-
#endif
394-
}
395-
396-
} else {
397-
/* Shouldn't get here but just in case... */
398-
399-
/* Enable system clock prescaler to DIV4 - F_CPU should now be ~4/5MHz */
400-
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, (CLKCTRL_PEN_bm | CLKCTRL_PDIV_4X_gc));
401-
402-
403-
if(fuse_setting == FREQSEL_20MHZ_gc){
404-
cpu_freq = 5000000;
405-
#if (PERFORM_SIGROW_CORRECTION_F_CPU == 1)
406-
sigrow_val = SIGROW.OSC20ERR3V;
407-
#endif
408-
409-
} else { /* fuse_setting == FREQSEL_16MHZ_gc */
410-
cpu_freq = 4000000;
411-
#if (PERFORM_SIGROW_CORRECTION_F_CPU == 1)
412-
sigrow_val = SIGROW.OSC16ERR3V;
413-
#endif
414-
}
415-
}
285+
#if (F_CPU == 16000000)
286+
cpu_freq = 16000000;
287+
288+
/* No division on clock */
289+
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, 0x00);
290+
291+
#elif (F_CPU == 8000000)
292+
cpu_freq = 8000000;
293+
294+
/* Clock DIV2 */
295+
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, (CLKCTRL_PEN_bm | CLKCTRL_PDIV_2X_gc));
296+
297+
#elif (F_CPU == 4000000)
298+
cpu_freq = 4000000;
299+
300+
/* Clock DIV4 */
301+
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, (CLKCTRL_PEN_bm | CLKCTRL_PDIV_4X_gc))
302+
303+
#elif (F_CPU == 2000000)
304+
cpu_freq = 2000000;
305+
306+
/* Clock DIV8 */
307+
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, (CLKCTRL_PEN_bm | CLKCTRL_PDIV_8X_gc))
308+
#else
309+
310+
#ifndef F_CPU
311+
# warning "F_CPU not defined"
312+
#define F_CPU 16000000
313+
#endif
314+
315+
# warning "F_CPU defined as an invalid value - may cause undefined behavior"
316+
317+
/* Default value is 16MHz */
318+
cpu_freq = 16000000;
319+
320+
/* No division on clock */
321+
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, 0x00);
322+
#endif
323+
416324

417325
#if (PERFORM_SIGROW_CORRECTION_F_CPU == 1)
418326
/* Calculate actual F_CPU with error values from signature row */
327+
uint8_t sigrow_val = SIGROW.OSC16ERR5V;
419328
cpu_freq *= (1024 + sigrow_val);
420329
cpu_freq /= 1024;
421330
#endif /* (CORRECT_F_CPU == 1) */

0 commit comments

Comments
 (0)