Skip to content

Commit 04d34da

Browse files
Canocmaglie
Cano
authored andcommitted
zero delay fix, ADC prescaler fix
1 parent d3ba34d commit 04d34da

File tree

1 file changed

+75
-61
lines changed

1 file changed

+75
-61
lines changed

cores/arduino/wiring.c

+75-61
Original file line numberDiff line numberDiff line change
@@ -123,118 +123,114 @@ void delay(unsigned long ms)
123123
void delayMicroseconds(unsigned int us)
124124
{
125125
// call = 4 cycles + 2 to 4 cycles to init us(2 for constant delay, 4 for variable)
126+
126127
// calling avrlib's delay_us() function with low values (e.g. 1 or
127128
// 2 microseconds) gives delays longer than desired.
128129
//delay_us(us);
129130
#if F_CPU >= 24000000L
130131
// for the 24 MHz clock for the aventurous ones, trying to overclock
131132

132-
// for a one-microsecond delay, simply wait 6 cycles and return. The overhead
133-
// of the function call yields a delay of exactly one microsecond.
134-
__asm__ __volatile__ (
135-
"nop" "\n\t"
136-
"nop" "\n\t"
137-
"nop" "\n\t"
138-
"nop" "\n\t"
139-
"nop" "\n\t"
140-
"nop"); //just waiting 6 cycles
141-
if (--us == 0)
142-
return;
133+
// zero delay fix
134+
if (!us) return; // = 3 cycles, (4 when true)
143135

144136
// the following loop takes a 1/6 of a microsecond (4 cycles)
145137
// per iteration, so execute it six times for each microsecond of
146138
// delay requested.
147-
us *= 6; // x6 us
139+
us *= 6; // x6 us, = 7 cycles
148140

149141
// account for the time taken in the preceeding commands.
150-
us -= 2;
142+
// we just burned 22 (24) cycles above, remove 5, (5*4=20)
143+
// us is at least 6 so we can substract 5
144+
us -= 5; //=2 cycles
151145

152146
#elif F_CPU >= 20000000L
153147
// for the 20 MHz clock on rare Arduino boards
154148

155-
// for a one-microsecond delay, simply wait 2 cycles and return. The overhead
156-
// of the function call yields a delay of exactly one microsecond.
149+
// for a one-microsecond delay, simply return. the overhead
150+
// of the function call takes 18 (20) cycles, which is 1us
157151
__asm__ __volatile__ (
158152
"nop" "\n\t"
159-
"nop"); //just waiting 2 cycle
160-
if (--us == 0)
161-
return;
153+
"nop" "\n\t"
154+
"nop" "\n\t"
155+
"nop"); //just waiting 4 cycles
156+
if (us <= 1) return; // = 3 cycles, (4 when true)
162157

163158
// the following loop takes a 1/5 of a microsecond (4 cycles)
164159
// per iteration, so execute it five times for each microsecond of
165160
// delay requested.
166-
us = (us<<2) + us; // x5 us
161+
us = (us << 2) + us; // x5 us, = 7 cycles
167162

168163
// account for the time taken in the preceeding commands.
169-
us -= 2;
164+
// we just burned 26 (28) cycles above, remove 7, (7*4=28)
165+
// us is at least 10 so we can substract 7
166+
us -= 7; // 2 cycles
170167

171168
#elif F_CPU >= 16000000L
172169
// for the 16 MHz clock on most Arduino boards
173170

174171
// for a one-microsecond delay, simply return. the overhead
175-
// of the function call yields a delay of approximately 1 1/8 us.
176-
if (--us == 0)
177-
return;
172+
// of the function call takes 14 (16) cycles, which is 1us
173+
if (us <= 1) return; // = 3 cycles, (4 when true)
178174

179175
// the following loop takes 1/4 of a microsecond (4 cycles)
180176
// per iteration, so execute it four times for each microsecond of
181177
// delay requested.
182-
us <<= 2; // x4 us
178+
us <<= 2; // x4 us, = 4 cycles
183179

184180
// account for the time taken in the preceeding commands.
185-
us -= 2;
181+
// we just burned 19 (21) cycles above, remove 5, (5*4=20)
182+
// us is at least 8 so we can substract 5
183+
us -= 5; // = 2 cycles,
186184

187185
#elif F_CPU >= 12000000L
188186
// for the 12 MHz clock if somebody is working with USB
189187

190-
// for a one-microsecond delay, simply return. the overhead
191-
// of the function call yields a delay of approximately 1.5 us.
192-
if (--us == 0)
193-
return;
188+
// for a 1 microsecond delay, simply return. the overhead
189+
// of the function call takes 14 (16) cycles, which is 1.5us
190+
if (us <= 1) return; // = 3 cycles, (4 when true)
194191

195192
// the following loop takes 1/3 of a microsecond (4 cycles)
196193
// per iteration, so execute it three times for each microsecond of
197194
// delay requested.
198-
us = (us << 1) + us; // x3 us
195+
us = (us << 1) + us; // x3 us, = 5 cycles
199196

200197
// account for the time taken in the preceeding commands.
201-
us -= 2;
198+
// we just burned 20 (22) cycles above, remove 5, (5*4=20)
199+
// us is at least 6 so we can substract 5
200+
us -= 5; //2 cycles
201+
202202
#elif F_CPU >= 8000000L
203203
// for the 8 MHz internal clock
204204

205-
// for a one- or two-microsecond delay, simply return. the overhead of
206-
// the function calls takes more than two microseconds. can't just
207-
// subtract two, since us is unsigned; we'd overflow.
208-
if (--us == 0)
209-
return;
210-
if (--us == 0)
211-
return;
205+
// for a 1 and 2 microsecond delay, simply return. the overhead
206+
// of the function call takes 14 (16) cycles, which is 2us
207+
if (us <= 2) return; // = 3 cycles, (4 when true)
212208

213209
// the following loop takes 1/2 of a microsecond (4 cycles)
214210
// per iteration, so execute it twice for each microsecond of
215211
// delay requested.
216-
us <<= 1; //x2 us
217-
218-
// partially compensate for the time taken by the preceeding commands.
219-
// we can't subtract any more than this or we'd overflow w/ small delays.
220-
us--;
212+
us <<= 1; //x2 us, = 2 cycles
213+
214+
// account for the time taken in the preceeding commands.
215+
// we just burned 17 (19) cycles above, remove 4, (4*4=16)
216+
// us is at least 6 so we can substract 4
217+
us -= 4; // = 2 cycles
221218

222219
#else
223220
// for the 1 MHz internal clock (default settings for common Atmega microcontrollers)
224221

225-
// the overhead of the function calls takes about 16 microseconds.
226-
if (us <= 16) //4 cycles spent here
227-
return;
228-
if (us <= 22) { //4 cycles spent here
229-
return;
230-
}
231-
232-
// compensate for the time taken by the preceeding and next commands.
233-
us -= 22;
222+
// the overhead of the function calls is 14 (16) cycles
223+
if (us <= 16) return; //= 3 cycles, (4 when true)
224+
if (us <= 25) return; //= 3 cycles, (4 when true), (must be at least 25 if we want to substract 22)
234225

226+
// compensate for the time taken by the preceeding and next commands (about 22 cycles)
227+
us -= 22; // = 2 cycles
235228
// the following loop takes 4 microseconds (4 cycles)
236229
// per iteration, so execute it us/4 times
237-
us >>= 2; // us div 4
230+
// us is at least 4, divided by 4 gives us 1 (no zero delay bug)
231+
us >>= 2; // us div 4, = 4 cycles
232+
233+
238234
#endif
239235

240236
// busy wait
@@ -360,14 +356,32 @@ void init()
360356
#endif
361357

362358
#if defined(ADCSRA)
363-
// set a2d prescale factor to 128
364-
// 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
365-
// XXX: this will not work properly for other clock speeds, and
366-
// this code should use F_CPU to determine the prescale factor.
367-
sbi(ADCSRA, ADPS2);
368-
sbi(ADCSRA, ADPS1);
369-
sbi(ADCSRA, ADPS0);
370-
359+
// set a2d prescaler so we are inside the desired 50-200 KHz range.
360+
#if F_CPU >= 16000000 // 16 MHz / 128 = 125 KHz
361+
sbi(ADCSRA, ADPS2);
362+
sbi(ADCSRA, ADPS1);
363+
sbi(ADCSRA, ADPS0);
364+
#elif F_CPU >= 8000000 // 8 MHz / 64 = 125 KHz
365+
sbi(ADCSRA, ADPS2);
366+
sbi(ADCSRA, ADPS1);
367+
cbi(ADCSRA, ADPS0);
368+
#elif F_CPU >= 4000000 // 4 MHz / 32 = 125 KHz
369+
sbi(ADCSRA, ADPS2);
370+
cbi(ADCSRA, ADPS1);
371+
sbi(ADCSRA, ADPS0);
372+
#elif F_CPU >= 2000000 // 2 MHz / 16 = 125 KHz
373+
sbi(ADCSRA, ADPS2);
374+
cbi(ADCSRA, ADPS1);
375+
cbi(ADCSRA, ADPS0);
376+
#elif F_CPU >= 1000000 // 1 MHz / 8 = 125 KHz
377+
cbi(ADCSRA, ADPS2);
378+
sbi(ADCSRA, ADPS1);
379+
sbi(ADCSRA, ADPS0);
380+
#else // 128 kHz / 2 = 64 KHz -> This is the closest you can get, the prescaler is 2
381+
cbi(ADCSRA, ADPS2);
382+
cbi(ADCSRA, ADPS1);
383+
sbi(ADCSRA, ADPS0);
384+
#endif
371385
// enable a2d conversions
372386
sbi(ADCSRA, ADEN);
373387
#endif

0 commit comments

Comments
 (0)