aboutsummaryrefslogtreecommitdiff
path: root/cores/arduino
diff options
context:
space:
mode:
Diffstat (limited to 'cores/arduino')
-rw-r--r--cores/arduino/HardwareSerial.cpp1
-rw-r--r--cores/arduino/WInterrupts.c12
-rw-r--r--cores/arduino/wiring.c151
3 files changed, 124 insertions, 40 deletions
diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp
index 41935e3..4022698 100644
--- a/cores/arduino/HardwareSerial.cpp
+++ b/cores/arduino/HardwareSerial.cpp
@@ -220,6 +220,7 @@ size_t HardwareSerial::write(uint8_t c)
if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(*_ucsra, UDRE0)) {
*_udr = c;
sbi(*_ucsra, TXC0);
+ _written = true;
return 1;
}
tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE;
diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c
index d3fbf10..71dd45c 100644
--- a/cores/arduino/WInterrupts.c
+++ b/cores/arduino/WInterrupts.c
@@ -223,6 +223,18 @@ void detachInterrupt(uint8_t interruptNum) {
#warning detachInterrupt may need some more work for this cpu (case 1)
#endif
break;
+
+ case 2:
+ #if defined(EIMSK) && defined(INT2)
+ EIMSK &= ~(1 << INT2);
+ #elif defined(GICR) && defined(INT2)
+ GICR &= ~(1 << INT2); // atmega32
+ #elif defined(GIMSK) && defined(INT2)
+ GIMSK &= ~(1 << INT2);
+ #elif defined(INT2)
+ #warning detachInterrupt may need some more work for this cpu (case 2)
+ #endif
+ break;
#endif
}
diff --git a/cores/arduino/wiring.c b/cores/arduino/wiring.c
index 5cbe241..6cb22c0 100644
--- a/cores/arduino/wiring.c
+++ b/cores/arduino/wiring.c
@@ -92,7 +92,6 @@ unsigned long micros() {
#error TIMER 0 not defined
#endif
-
#ifdef TIFR0
if ((TIFR0 & _BV(TOV0)) && (t < 255))
m++;
@@ -119,65 +118,118 @@ void delay(unsigned long ms)
}
}
-/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */
+/* Delay for the given number of microseconds. Assumes a 1, 8, 12, 16, 20 or 24 MHz clock. */
void delayMicroseconds(unsigned int us)
{
+ // call = 4 cycles + 2 to 4 cycles to init us(2 for constant delay, 4 for variable)
+
// calling avrlib's delay_us() function with low values (e.g. 1 or
// 2 microseconds) gives delays longer than desired.
//delay_us(us);
-#if F_CPU >= 20000000L
+#if F_CPU >= 24000000L
+ // for the 24 MHz clock for the aventurous ones, trying to overclock
+
+ // zero delay fix
+ if (!us) return; // = 3 cycles, (4 when true)
+
+ // the following loop takes a 1/6 of a microsecond (4 cycles)
+ // per iteration, so execute it six times for each microsecond of
+ // delay requested.
+ us *= 6; // x6 us, = 7 cycles
+
+ // account for the time taken in the preceeding commands.
+ // we just burned 22 (24) cycles above, remove 5, (5*4=20)
+ // us is at least 6 so we can substract 5
+ us -= 5; //=2 cycles
+
+#elif F_CPU >= 20000000L
// for the 20 MHz clock on rare Arduino boards
- // for a one-microsecond delay, simply wait 2 cycle and return. The overhead
- // of the function call yields a delay of exactly a one microsecond.
+ // for a one-microsecond delay, simply return. the overhead
+ // of the function call takes 18 (20) cycles, which is 1us
__asm__ __volatile__ (
"nop" "\n\t"
- "nop"); //just waiting 2 cycle
- if (--us == 0)
- return;
+ "nop" "\n\t"
+ "nop" "\n\t"
+ "nop"); //just waiting 4 cycles
+ if (us <= 1) return; // = 3 cycles, (4 when true)
// the following loop takes a 1/5 of a microsecond (4 cycles)
// per iteration, so execute it five times for each microsecond of
// delay requested.
- us = (us<<2) + us; // x5 us
+ us = (us << 2) + us; // x5 us, = 7 cycles
// account for the time taken in the preceeding commands.
- us -= 2;
+ // we just burned 26 (28) cycles above, remove 7, (7*4=28)
+ // us is at least 10 so we can substract 7
+ us -= 7; // 2 cycles
#elif F_CPU >= 16000000L
// for the 16 MHz clock on most Arduino boards
// for a one-microsecond delay, simply return. the overhead
- // of the function call yields a delay of approximately 1 1/8 us.
- if (--us == 0)
- return;
+ // of the function call takes 14 (16) cycles, which is 1us
+ if (us <= 1) return; // = 3 cycles, (4 when true)
- // the following loop takes a quarter of a microsecond (4 cycles)
+ // the following loop takes 1/4 of a microsecond (4 cycles)
// per iteration, so execute it four times for each microsecond of
// delay requested.
- us <<= 2;
+ us <<= 2; // x4 us, = 4 cycles
// account for the time taken in the preceeding commands.
- us -= 2;
-#else
- // for the 8 MHz internal clock on the ATmega168
+ // we just burned 19 (21) cycles above, remove 5, (5*4=20)
+ // us is at least 8 so we can substract 5
+ us -= 5; // = 2 cycles,
+
+#elif F_CPU >= 12000000L
+ // for the 12 MHz clock if somebody is working with USB
+
+ // for a 1 microsecond delay, simply return. the overhead
+ // of the function call takes 14 (16) cycles, which is 1.5us
+ if (us <= 1) return; // = 3 cycles, (4 when true)
- // for a one- or two-microsecond delay, simply return. the overhead of
- // the function calls takes more than two microseconds. can't just
- // subtract two, since us is unsigned; we'd overflow.
- if (--us == 0)
- return;
- if (--us == 0)
- return;
+ // the following loop takes 1/3 of a microsecond (4 cycles)
+ // per iteration, so execute it three times for each microsecond of
+ // delay requested.
+ us = (us << 1) + us; // x3 us, = 5 cycles
+
+ // account for the time taken in the preceeding commands.
+ // we just burned 20 (22) cycles above, remove 5, (5*4=20)
+ // us is at least 6 so we can substract 5
+ us -= 5; //2 cycles
+
+#elif F_CPU >= 8000000L
+ // for the 8 MHz internal clock
- // the following loop takes half of a microsecond (4 cycles)
+ // for a 1 and 2 microsecond delay, simply return. the overhead
+ // of the function call takes 14 (16) cycles, which is 2us
+ if (us <= 2) return; // = 3 cycles, (4 when true)
+
+ // the following loop takes 1/2 of a microsecond (4 cycles)
// per iteration, so execute it twice for each microsecond of
// delay requested.
- us <<= 1;
-
- // partially compensate for the time taken by the preceeding commands.
- // we can't subtract any more than this or we'd overflow w/ small delays.
- us--;
+ us <<= 1; //x2 us, = 2 cycles
+
+ // account for the time taken in the preceeding commands.
+ // we just burned 17 (19) cycles above, remove 4, (4*4=16)
+ // us is at least 6 so we can substract 4
+ us -= 4; // = 2 cycles
+
+#else
+ // for the 1 MHz internal clock (default settings for common Atmega microcontrollers)
+
+ // the overhead of the function calls is 14 (16) cycles
+ if (us <= 16) return; //= 3 cycles, (4 when true)
+ if (us <= 25) return; //= 3 cycles, (4 when true), (must be at least 25 if we want to substract 22)
+
+ // compensate for the time taken by the preceeding and next commands (about 22 cycles)
+ us -= 22; // = 2 cycles
+ // the following loop takes 4 microseconds (4 cycles)
+ // per iteration, so execute it us/4 times
+ // us is at least 4, divided by 4 gives us 1 (no zero delay bug)
+ us >>= 2; // us div 4, = 4 cycles
+
+
#endif
// busy wait
@@ -185,6 +237,7 @@ void delayMicroseconds(unsigned int us)
"1: sbiw %0,1" "\n\t" // 2 cycles
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
);
+ // return = 4 cycles
}
void init()
@@ -199,7 +252,7 @@ void init()
#if defined(TCCR0A) && defined(WGM01)
sbi(TCCR0A, WGM01);
sbi(TCCR0A, WGM00);
-#endif
+#endif
// set timer 0 prescale factor to 64
#if defined(__AVR_ATmega128__)
@@ -302,14 +355,32 @@ void init()
#endif
#if defined(ADCSRA)
- // set a2d prescale factor to 128
- // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
- // XXX: this will not work properly for other clock speeds, and
- // this code should use F_CPU to determine the prescale factor.
- sbi(ADCSRA, ADPS2);
- sbi(ADCSRA, ADPS1);
- sbi(ADCSRA, ADPS0);
-
+ // set a2d prescaler so we are inside the desired 50-200 KHz range.
+ #if F_CPU >= 16000000 // 16 MHz / 128 = 125 KHz
+ sbi(ADCSRA, ADPS2);
+ sbi(ADCSRA, ADPS1);
+ sbi(ADCSRA, ADPS0);
+ #elif F_CPU >= 8000000 // 8 MHz / 64 = 125 KHz
+ sbi(ADCSRA, ADPS2);
+ sbi(ADCSRA, ADPS1);
+ cbi(ADCSRA, ADPS0);
+ #elif F_CPU >= 4000000 // 4 MHz / 32 = 125 KHz
+ sbi(ADCSRA, ADPS2);
+ cbi(ADCSRA, ADPS1);
+ sbi(ADCSRA, ADPS0);
+ #elif F_CPU >= 2000000 // 2 MHz / 16 = 125 KHz
+ sbi(ADCSRA, ADPS2);
+ cbi(ADCSRA, ADPS1);
+ cbi(ADCSRA, ADPS0);
+ #elif F_CPU >= 1000000 // 1 MHz / 8 = 125 KHz
+ cbi(ADCSRA, ADPS2);
+ sbi(ADCSRA, ADPS1);
+ sbi(ADCSRA, ADPS0);
+ #else // 128 kHz / 2 = 64 KHz -> This is the closest you can get, the prescaler is 2
+ cbi(ADCSRA, ADPS2);
+ cbi(ADCSRA, ADPS1);
+ sbi(ADCSRA, ADPS0);
+ #endif
// enable a2d conversions
sbi(ADCSRA, ADEN);
#endif