mirror of
https://github.com/digistump/DigistumpArduino.git
synced 2025-09-17 17:32:25 -07:00
switch to setup for Arduino Boards Manager
This commit is contained in:
366
digistump-avr/cores/tiny/wiring.c
Normal file
366
digistump-avr/cores/tiny/wiring.c
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
wiring.c - Partial implementation of the Wiring API for the ATmega8.
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id: wiring.c 970 2010-05-25 20:16:15Z dmellis $
|
||||
|
||||
Modified 28-08-2009 for attiny84 R.Wiersma
|
||||
Modified 14-10-2009 for attiny45 Saposoft
|
||||
Modified 20-11-2010 - B.Cook - Rewritten to use the various Veneers.
|
||||
*/
|
||||
|
||||
#include "core_build_options.h"
|
||||
#include "core_adc.h"
|
||||
#include "core_timers.h"
|
||||
#include "wiring_private.h"
|
||||
#include "ToneTimer.h"
|
||||
#if F_CPU != 16500000L
|
||||
#include <avr/boot.h>
|
||||
#endif
|
||||
|
||||
#define millistimer_(t) TIMER_PASTE_A( timer, TIMER_TO_USE_FOR_MILLIS, t )
|
||||
#define MillisTimer_(f) TIMER_PASTE_A( Timer, TIMER_TO_USE_FOR_MILLIS, f )
|
||||
#define MILLISTIMER_(c) TIMER_PASTE_A( TIMER, TIMER_TO_USE_FOR_MILLIS, c )
|
||||
|
||||
#define MillisTimer_SetToPowerup MillisTimer_(SetToPowerup)
|
||||
#define MillisTimer_SetWaveformGenerationMode MillisTimer_(SetWaveformGenerationMode)
|
||||
#define MillisTimer_GetCount MillisTimer_(GetCount)
|
||||
#define MillisTimer_IsOverflowSet MillisTimer_(IsOverflowSet)
|
||||
#define MillisTimer_ClockSelect MillisTimer_(ClockSelect)
|
||||
#define MillisTimer_EnableOverflowInterrupt MillisTimer_(EnableOverflowInterrupt)
|
||||
#define MILLISTIMER_OVF_vect MILLISTIMER_(OVF_vect)
|
||||
|
||||
|
||||
#define MS_TIMER_TICK_EVERY_X_CYCLES 64 /* Shall be a within 1, 8, 64, 256 or 1024. (default = 64) If set to 1, HW PWM is around 64.5KHz@16.5MHz with Digispark */
|
||||
|
||||
#if F_CPU >= 3000000L
|
||||
#if !defined(MS_TIMER_TICK_EVERY_X_CYCLES)
|
||||
#define MillisTimer_Prescale_Index MillisTimer_(Prescale_Value_64)
|
||||
#define MillisTimer_Prescale_Value (64)
|
||||
#define ToneTimer_Prescale_Index ToneTimer_(Prescale_Value_64)
|
||||
#define ToneTimer_Prescale_Value (64)
|
||||
#else
|
||||
#define Prescaler_Value(Val) PRESCALER_VALUE(Val)
|
||||
#define PRESCALER_VALUE(Val) Prescale_Value_##Val
|
||||
#define MillisTimer_Prescale_Index MillisTimer_(Prescaler_Value(MS_TIMER_TICK_EVERY_X_CYCLES))
|
||||
#define MillisTimer_Prescale_Value (MS_TIMER_TICK_EVERY_X_CYCLES)
|
||||
#define ToneTimer_Prescale_Index ToneTimer_(Prescaler_Value(MS_TIMER_TICK_EVERY_X_CYCLES))
|
||||
#define ToneTimer_Prescale_Value (MS_TIMER_TICK_EVERY_X_CYCLES)
|
||||
#endif
|
||||
#else
|
||||
#define MillisTimer_Prescale_Index MillisTimer_(Prescale_Value_8)
|
||||
#define MillisTimer_Prescale_Value (8)
|
||||
#define ToneTimer_Prescale_Index ToneTimer_(Prescale_Value_8)
|
||||
#define ToneTimer_Prescale_Value (8)
|
||||
#endif
|
||||
|
||||
// the prescaler is set so that the millis timer ticks every MillisTimer_Prescale_Value (64) clock cycles, and the
|
||||
// the overflow handler is called every 256 ticks.
|
||||
#define MICROSECONDS_PER_MILLIS_OVERFLOW (clockCyclesToMicroseconds(MillisTimer_Prescale_Value * 256))
|
||||
|
||||
// the whole number of milliseconds per millis timer overflow
|
||||
#define MILLIS_INC (MICROSECONDS_PER_MILLIS_OVERFLOW / 1000)
|
||||
|
||||
// the fractional number of milliseconds per millis timer overflow. we shift right
|
||||
// by three to fit these numbers into a byte. (for the clock speeds we care
|
||||
// about - 8 and 16 MHz - this doesn't lose precision.)
|
||||
#define FRACT_INC ((MICROSECONDS_PER_MILLIS_OVERFLOW % 1000) >> 3)
|
||||
#define FRACT_MAX (1000 >> 3)
|
||||
|
||||
volatile unsigned long millis_timer_overflow_count = 0;
|
||||
volatile unsigned long millis_timer_millis = 0;
|
||||
static unsigned char millis_timer_fract = 0;
|
||||
|
||||
// bluebie changed isr to noblock so it wouldn't mess up USB libraries
|
||||
ISR(MILLISTIMER_OVF_vect, ISR_NOBLOCK)
|
||||
{
|
||||
// copy these to local variables so they can be stored in registers
|
||||
// (volatile variables must be read from memory on every access)
|
||||
unsigned long m = millis_timer_millis;
|
||||
unsigned char f = millis_timer_fract;
|
||||
|
||||
/* rmv: The code below generates considerably less code (emtpy Sketch is 326 versus 304)...
|
||||
|
||||
m += MILLIS_INC;
|
||||
f += FRACT_INC;
|
||||
if (f >= FRACT_MAX) {
|
||||
f -= FRACT_MAX;
|
||||
m += 1;
|
||||
}
|
||||
...rmv */
|
||||
|
||||
f += FRACT_INC;
|
||||
|
||||
if (f >= FRACT_MAX)
|
||||
{
|
||||
f -= FRACT_MAX;
|
||||
m = m + MILLIS_INC + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m += MILLIS_INC;
|
||||
}
|
||||
|
||||
millis_timer_fract = f;
|
||||
millis_timer_millis = m;
|
||||
millis_timer_overflow_count++;
|
||||
}
|
||||
|
||||
unsigned long millis()
|
||||
{
|
||||
unsigned long m;
|
||||
uint8_t oldSREG = SREG;
|
||||
|
||||
// disable interrupts while we read millis_timer_millis or we might get an
|
||||
// inconsistent value (e.g. in the middle of a write to millis_timer_millis)
|
||||
cli();
|
||||
m = millis_timer_millis;
|
||||
SREG = oldSREG;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
unsigned long micros()
|
||||
{
|
||||
unsigned long m;
|
||||
uint8_t oldSREG = SREG, t;
|
||||
|
||||
cli();
|
||||
m = millis_timer_overflow_count;
|
||||
t = MillisTimer_GetCount();
|
||||
|
||||
if (MillisTimer_IsOverflowSet() && (t < 255))
|
||||
m++;
|
||||
|
||||
SREG = oldSREG;
|
||||
|
||||
#if (MillisTimer_Prescale_Value >= clockCyclesPerMicrosecond())
|
||||
return ((m << 8) + t) * (MillisTimer_Prescale_Value / clockCyclesPerMicrosecond());
|
||||
#else
|
||||
return ((m << 8) + t) / (clockCyclesPerMicrosecond() / MillisTimer_Prescale_Value);
|
||||
#endif
|
||||
}
|
||||
|
||||
void delay(unsigned long ms)
|
||||
{
|
||||
uint16_t start = (uint16_t)micros();
|
||||
|
||||
while (ms > 0) {
|
||||
if (((uint16_t)micros() - start) >= 1000) {
|
||||
ms--;
|
||||
start += 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if F_CPU == 16500000L
|
||||
// optimised delay loop from Bluebie contributed to Digispark project
|
||||
// deals accurately with half-mhz clock speed, but can only delay in increments of 2us rounded down
|
||||
// this loop has been tuned empirically with an oscilloscope and works in avr-gcc 4.5.1
|
||||
void delayMicroseconds(unsigned int us){
|
||||
us &= ((unsigned int) 0) - ((unsigned int) 2); // remove least signifficant bit
|
||||
while (us > 1) {
|
||||
// 16 nops
|
||||
asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
|
||||
asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
|
||||
// 11 nops
|
||||
asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
|
||||
asm("NOP");asm("NOP");asm("NOP");
|
||||
|
||||
us -= 2;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* Improved delayMicroseconds function
|
||||
* Copyright (c) 2011, Paul Stoffregen, paul at pjrc dot com
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// modified by Bluebie in 2013 for Digispark project
|
||||
// #include <stdint.h>
|
||||
// #include <avr/io.h>
|
||||
|
||||
void delayMicroseconds(uint16_t usec) {
|
||||
asm volatile(
|
||||
#if F_CPU == 16000000L
|
||||
"sbiw %A0, 2" "\n\t" // 2
|
||||
"brcs L_%=_end" "\n\t" // 1
|
||||
"breq L_%=_end" "\n\t" // 1
|
||||
"lsl %A0" "\n\t" // 1
|
||||
"rol %B0" "\n\t" // 1
|
||||
"lsl %A0" "\n\t" // 1
|
||||
"rol %B0" "\n\t" // 1 overhead: (8)/4 = 2us
|
||||
#elif F_CPU == 8000000L
|
||||
"sbiw %A0, 3" "\n\t" // 2
|
||||
"brcs L_%=_end" "\n\t" // 1
|
||||
"breq L_%=_end" "\n\t" // 1
|
||||
"lsl %A0" "\n\t" // 1
|
||||
"rol %B0" "\n\t" // 1 overhead: (6)/2 = 3 us
|
||||
#elif F_CPU == 4000000L
|
||||
"sbiw %A0, 4" "\n\t" // 2
|
||||
"brcs L_%=_end" "\n\t" // 1
|
||||
"breq L_%=_end" "\n\t" // 1 overhead: (4) = 4 us
|
||||
#elif F_CPU == 2000000L
|
||||
"sbiw %A0, 12" "\n\t" // 2
|
||||
"brcs L_%=_end" "\n\t" // 1
|
||||
"breq L_%=_end" "\n\t" // 1
|
||||
"lsr %B0" "\n\t" // 1
|
||||
"ror %A0" "\n\t" // 1 overhead: (6)*2 = 12 us
|
||||
#elif F_CPU == 1000000L
|
||||
"sbiw %A0, 32" "\n\t" // 2
|
||||
"brcs L_%=_end" "\n\t" // 1
|
||||
"breq L_%=_end" "\n\t" // 1
|
||||
"lsr %B0" "\n\t" // 1
|
||||
"ror %A0" "\n\t" // 1
|
||||
"lsr %B0" "\n\t" // 1
|
||||
"ror %A0" "\n\t" // 1 overhead: (8)*4 = 32 us
|
||||
#endif
|
||||
"L_%=_loop:"
|
||||
"sbiw %A0, 1" "\n\t" // 2
|
||||
"brne L_%=_loop" "\n\t" // 2
|
||||
"L_%=_end:"
|
||||
: "+w" (usec)
|
||||
: "0" (usec)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void initToneTimerInternal(void)
|
||||
{
|
||||
// Stop the clock while we make changes
|
||||
ToneTimer_ClockSelect( ToneTimer_(Stopped) );
|
||||
|
||||
// Set the timer to phase-correct PWM
|
||||
#if defined( TONETIMER_SUPPORTS_PHASE_CORRECT_PWM ) && TONETIMER_SUPPORTS_PHASE_CORRECT_PWM
|
||||
ToneTimer_SetWaveformGenerationMode( ToneTimer_(Phase_Correct_PWM_FF) );
|
||||
#else
|
||||
ToneTimer_SetWaveformGenerationMode( ToneTimer_(Fast_PWM_FF) );
|
||||
#endif
|
||||
|
||||
// Timer is processor clock divided by ToneTimer_Prescale_Index (64)
|
||||
ToneTimer_ClockSelect( ToneTimer_Prescale_Index );
|
||||
}
|
||||
|
||||
void initToneTimer(void)
|
||||
{
|
||||
// Ensure the timer is in the same state as power-up
|
||||
ToneTimer_SetToPowerup();
|
||||
|
||||
#if defined( INITIALIZE_SECONDARY_TIMERS ) && INITIALIZE_SECONDARY_TIMERS
|
||||
// Prepare the timer for PWM
|
||||
initToneTimerInternal();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if F_CPU != 16500000L
|
||||
// used to detect bootloader applying calibration in init
|
||||
byte read_factory_calibration(void)
|
||||
{
|
||||
byte SIGRD = 5; // for some reason this isn't defined...
|
||||
byte value = boot_signature_byte_get(1);
|
||||
return value;
|
||||
}
|
||||
#endif
|
||||
|
||||
void init(void)
|
||||
{
|
||||
// clock calibration stuff
|
||||
// recalibrate clock if it was calibrated by bootloader (like micronucleus)
|
||||
#if F_CPU != 16500000L
|
||||
if (OSCCAL != read_factory_calibration()) {
|
||||
// adjust the calibration down from 16.5mhz to 16.0mhz
|
||||
if (OSCCAL >= 128) {
|
||||
// maybe 8 is better? oh well - only about 0.3% out anyway
|
||||
OSCCAL -= 7;
|
||||
} else {
|
||||
OSCCAL -= 5;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: detect if fuses set to PLL, regular internal oscillator or external and change behaviour in this next section...
|
||||
#if F_CPU < 16000000L
|
||||
cli();
|
||||
CLKPR = 0b10000000;
|
||||
#if F_CPU == 8000000L
|
||||
CLKPR = 1; // div 2
|
||||
#elif F_CPU == 4000000L
|
||||
CLKPR = 2 // div 4
|
||||
#elif F_CPU == 2000000L
|
||||
CLKPR = 3; // div 8
|
||||
#elif F_CPU == 1000000L
|
||||
CLKPR = 4; // div 16
|
||||
#elif F_CPU == 500000L
|
||||
CLKPR = 5; // div 32 = 500khz
|
||||
#elif F_CPU == 250000L
|
||||
CLKPR = 6; // div 64 = 250khz
|
||||
#elif F_CPU == 125000L
|
||||
CLKPR = 7; // div 128 = 125khz cpu clock
|
||||
#else
|
||||
#warning "Cannot prescale chip to specified F_CPU speed"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// this needs to be called before setup() or some functions won't work there
|
||||
sei();
|
||||
|
||||
// In case the bootloader left our millis timer in a bad way
|
||||
#if defined( HAVE_BOOTLOADER ) && HAVE_BOOTLOADER
|
||||
MillisTimer_SetToPowerup();
|
||||
#endif
|
||||
|
||||
// Use the Millis Timer for fast PWM
|
||||
MillisTimer_SetWaveformGenerationMode( MillisTimer_(Fast_PWM_FF) );
|
||||
|
||||
// Millis timer is always processor clock divided by MillisTimer_Prescale_Value (64)
|
||||
MillisTimer_ClockSelect( MillisTimer_Prescale_Index );
|
||||
|
||||
// Enable the overlow interrupt (this is the basic system tic-toc for millis)
|
||||
MillisTimer_EnableOverflowInterrupt();
|
||||
|
||||
// Initialize the timer used for Tone
|
||||
#if defined( INITIALIZE_SECONDARY_TIMERS ) && INITIALIZE_SECONDARY_TIMERS
|
||||
initToneTimerInternal();
|
||||
#endif
|
||||
|
||||
// Initialize the ADC
|
||||
#if defined( INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER ) && INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER
|
||||
ADC_PrescalerSelect( ADC_ARDUINO_PRESCALER );
|
||||
ADC_Enable();
|
||||
#endif
|
||||
}
|
||||
|
Reference in New Issue
Block a user