Skip to content

Commit a492319

Browse files
committed
test new delay-function
1 parent 5a83935 commit a492319

File tree

2 files changed

+177
-1
lines changed

2 files changed

+177
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
/*
2+
* Test-Code for a suitable timing function
3+
*
4+
* - Var1: use micros()
5+
* - Var2: count ticks
6+
*
7+
* Results (Atmega328@16MHz)
8+
* - 16bit-ticks-loop takes 11 ticks to repeat, 32bit takes 14 ticks
9+
* - results on pin are the same, early leaving the loop takes 690 ns
10+
* -
11+
*
12+
*/
13+
14+
#include "OneWireHub.h"
15+
16+
class WaitWhilePinIs
17+
{
18+
private:
19+
// setup direct pin-access
20+
uint8_t pin_bitMask;
21+
volatile uint8_t *pin_baseReg;
22+
//volatile uint8_t *reg asm("r30") = baseReg;
23+
24+
uint32_t factor_nslp;
25+
26+
public:
27+
WaitWhilePinIs(uint8_t digital_pin) // initialize and calibrate
28+
{
29+
// initialize
30+
pin_bitMask = digitalPinToBitMask(digital_pin);
31+
pin_baseReg = portInputRegister(digitalPinToPort(digital_pin));
32+
33+
// prepare measurement
34+
DIRECT_MODE_OUTPUT(pin_baseReg, pin_bitMask);
35+
DIRECT_WRITE_HIGH(pin_baseReg, pin_bitMask);
36+
uint8_t pin_value = 1;
37+
static_assert(microsecondsToClockCycles(1) < 40000L, "CPU is too fast"); // protect from overrun with static_assert, maybe convert to dynanic type
38+
const uint32_t retries = 100000L * microsecondsToClockCycles(1); // 100ms (if loop takes 1 cylce) for every frequency, uint32-overrun at 40 GHz
39+
// 100000L takes 1100ms on atmega328p@16Mhz
40+
41+
// measure
42+
const uint32_t time_start = micros();
43+
loops(retries,pin_value);
44+
const uint32_t time_stop = micros();
45+
46+
// analyze
47+
const uint32_t time_ns = (time_stop - time_start) * 1000;
48+
factor_nslp = time_ns / retries; // nanoseconds per loop
49+
DIRECT_WRITE_LOW(pin_baseReg, pin_bitMask); // disable internal pullup
50+
DIRECT_MODE_INPUT(pin_baseReg, pin_bitMask);
51+
};
52+
53+
void loops(volatile uint32_t retries, const bool pin_value = false)
54+
{
55+
while (DIRECT_READ(pin_baseReg, pin_bitMask) == pin_value) if (--retries == 0) break; // standard loop for measuring, 13 cycles per loop32 for an atmega328p
56+
};
57+
58+
uint32_t calculateRetries(const uint32_t time_ns)
59+
{
60+
return (time_ns / factor_nslp); // precalc waitvalues, the OP can take up da 550 cylces
61+
};
62+
63+
void nanoseconds(const uint32_t time_ns, const bool pin_value = false)
64+
{
65+
if (time_ns < factor_nslp) return;
66+
uint32_t retries = calculateRetries(time_ns); // not cheap .... precalc if possible
67+
loops(retries, pin_value);
68+
};
69+
};
70+
71+
class Delay
72+
{
73+
private:
74+
uint32_t factor_nslp;
75+
76+
public:
77+
Delay(void) // initialize and calibrate
78+
{
79+
// prepare measurement
80+
static_assert(microsecondsToClockCycles(1) < 40000L, "CPU is too fast"); // protect from overrun with static_assert, maybe convert to dynanic type
81+
const uint32_t retries = 100000L * microsecondsToClockCycles(1); // 100ms (if loop takes 1 cylce) for every frequency, uint32-overrun at 40 GHz
82+
// 100000L takes 600ms on atmega328p@16Mhz
83+
84+
// measure
85+
const uint32_t time_start = micros();
86+
loops(retries);
87+
const uint32_t time_stop = micros();
88+
89+
// analyze
90+
const uint32_t time_ns = (time_stop - time_start) * 1000;
91+
factor_nslp = time_ns / retries; // nanoseconds per loop
92+
};
93+
94+
void loops(volatile uint32_t retries)
95+
{
96+
while (--retries); // standard loop for measuring
97+
};
98+
99+
uint32_t calculateRetries(const uint32_t time_ns)
100+
{
101+
return (time_ns / factor_nslp); // precalc waitvalues, the OP can take up da 550 cylces
102+
};
103+
104+
void nanoseconds(const uint32_t time_ns)
105+
{
106+
if (time_ns < factor_nslp) return;
107+
const uint32_t retries = calculateRetries(time_ns); // not cheap .... precalc if possible
108+
loops(retries);
109+
};
110+
};
111+
112+
113+
114+
void setup()
115+
{
116+
const uint8_t pin_debug = 2;
117+
const uint8_t pin_delay = 8;
118+
const bool pin_value = false;
119+
120+
const uint32_t wait_ns[] = { 1000, 10000, 100000, 1000000}; // 1us, 10us, 100us, 1ms
121+
const uint8_t sizeof_wait = sizeof(wait_ns) >> 2;
122+
123+
pinMode(pin_debug,OUTPUT);
124+
// TODO: measure with logic analyzer and test if values are ok, pin_delay has to be false, otherwise dalay will exit early
125+
126+
{ // just delay
127+
digitalWrite(pin_debug,HIGH);
128+
auto delay32 = Delay();
129+
digitalWrite(pin_debug,LOW);
130+
delay(5);
131+
132+
for (uint8_t i = 0; i < sizeof_wait; ++i)
133+
{
134+
const uint32_t retries = delay32.calculateRetries(wait_ns[i]);
135+
136+
digitalWrite(pin_debug, HIGH);
137+
delay32.loops(retries);
138+
digitalWrite(pin_debug, LOW);
139+
140+
delay(5);
141+
};
142+
}; // got: <5us, 13.4us, 103.6us, 1005us
143+
144+
delay(10);
145+
146+
{ // do a pincheck
147+
digitalWrite(pin_debug,HIGH);
148+
auto delay32 = WaitWhilePinIs(pin_delay);
149+
digitalWrite(pin_debug,LOW);
150+
delay(5);
151+
152+
for (uint8_t i = 0; i < sizeof_wait; ++i)
153+
{
154+
const uint32_t retries = delay32.calculateRetries(wait_ns[i]);
155+
156+
digitalWrite(pin_debug, HIGH);
157+
delay32.loops(retries, pin_value);
158+
digitalWrite(pin_debug, LOW);
159+
160+
delay(5);
161+
};
162+
}; // got: 5us, 13.4us, 103.2us, 1005us
163+
};
164+
165+
void loop()
166+
{
167+
168+
}
169+
170+
171+
172+
173+
174+
175+
176+

examples/debug/optimize_pinAccess/optimize_pinAccess.ino

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ void setup()
108108
const uint8_t pin_test = 8;
109109

110110
// measurement with oszi --> each of this work with an atmega328p, 16MHz Clock bring 571 kHz pinFreq for case 1-3, double for case 4
111-
switch(3)
111+
switch(4)
112112
{
113113
case 0:
114114
case 1:

0 commit comments

Comments
 (0)