MORA99 9 Posted September 24, 2014 Author Share Posted September 24, 2014 The micros() that gompf suggested in the Energia issue (same issue I mentioned above) might help prevent totally off reading. unsigned long micros() { register uint32_t ms, cycle_cnt; do { ms = sysTickUptime; cycle_cnt = SysTickValueGet(); } while (ms != sysTickUptime); return (ms * 1000) + (80000 - cycle_cnt) / 80; } Not sure what the purpose of the do while is, to me it will always run just once, since ms is set to sysTickUptime inside it ? unless sysTickUptime counts fast in a interrupt outside of this code. I havent been able to confirm it yet, but I think there is a potential for conflict in both versions, since SysTickValue decrements with 1 per cycle, I think that the ms interrupt wont fire and complete before thats over, so for a few clocks SysTickValue will be near 16million before being reset to 80000. And if we then say 80000 - 24bit in a 32bit unsigned variable you get around 4.278.190.080 Quote Link to post Share on other sites
igor 163 Posted September 24, 2014 Share Posted September 24, 2014 unsigned long micros() { register uint32_t ms, cycle_cnt; do { ms = sysTickUptime; cycle_cnt = SysTickValueGet(); } while (ms != sysTickUptime); return (ms * 1000) + (80000 - cycle_cnt) / 80; } Not sure what the purpose of the do while is, to me it will always run just once, since ms is set to sysTickUptime inside it ? unless sysTickUptime counts fast in a interrupt outside of this code. I think the purpose of the do while is to be sure that you get a consistent set of values. Since SysTickUptime can change at any time (it is incremented by the systickHandler), there is no guarantee that two successive reads of it will have the same value. Specifically in this case we sandwich the reading of SysTickValueGet between two readings of SysTickUptime to be sure SysTickUptime didn't change after we read SysTickUptime but before we read SysTickValue. There are two cases: 1) If both readings of SysTickUptime are the same, then the value we got from SysTickValueGet should be consistent with the value of SysTickUptime (i.e. SysTickUptime has not rolled over just after we read it the first time but before we could do the value get). In which case the body of the do is executed just once. 2) The other case is the two SysTickUptime values are different. Then the ValueGet may or may not contain a valid value. (The rollover could have happened before we did the ValueGet, or after.) Since we don't know whether we have a good reading of SysTickValueGet, we throw it out and try again. In which case the body of the do is executed more than once (typically probably twice, but in theory we could be very unlucky, have a really long bunch of interrupts delay us - so we just keep trying until we get a good value). That is the way I think it will work, but I haven't tested it, and I didn't write it, and code with interrupts/critical sections/etc. generally deserves very careful scrutiny - i.e., I could be mistaken in my reading of it. Quote Link to post Share on other sites
MORA99 9 Posted September 24, 2014 Author Share Posted September 24, 2014 Okay, seems reasonable, so its to make sure both ms and sysTick was read in the same ms section, if ms overflows just as we read those two values, we retry. Quote Link to post Share on other sites
MORA99 9 Posted September 24, 2014 Author Share Posted September 24, 2014 Jep, using something along the lines of that bugreport removes the wildly off readings. unsigned long k = 0; void setup() { pinMode(3,INPUT); Serial.begin(115200); // initialize serial communication } void loop() { unsigned long c; unsigned long x = 0; for (uint16_t i=1; i!=0; i++) { c = pulseIn(3, HIGH, 1000); if (c<16||c>24) x++; if (c<10||c>30) Serial.println(c); } Serial.print("Loop ");Serial.print(k++);Serial.print(" => ");Serial.println(x); } Output,each of those loops are about 65500 tests, so <10 errors is not bad, and none of them were outside +/-10us of the signal being read Loop 0 => 9 Loop 1 => 7 Loop 2 => 8 Loop 3 => 1 Loop 4 => 8 Loop 5 => 8 Loop 6 => 9 Loop 7 => 1 Loop 8 => 9 Loop 9 => 7 Loop 10 => 9 Loop 11 => 1 Loop 12 => 9 Loop 13 => 8 Loop 14 => 9 Loop 15 => 7 Loop 16 => 2 Loop 17 => 9 Loop 18 => 8 Loop 19 => 9 Loop 20 => 1 Loop 21 => 9 Loop 22 => 8 Loop 23 => 9 Loop 24 => 1 Loop 25 => 9 Loop 26 => 7 Loop 27 => 9 Loop 28 => 1 Loop 29 => 9 Loop 30 => 8 Loop 31 => 9 Loop 32 => 1 Loop 33 => 8 Loop 34 => 7 Loop 35 => 9 Loop 36 => 1 Loop 37 => 9 Loop 38 => 8 Loop 39 => 8 Loop 40 => 1 Loop 41 => 9 Loop 42 => 8 Loop 43 => 9 Loop 44 => 9 Loop 45 => 1 Loop 46 => 9 Loop 47 => 7 Loop 48 => 8 Loop 49 => 1 Loop 50 => 9 +/-4us is a bit much, but I cant say how precise my 20$ logic tool is either Whats odd is theres a pattern to the number of off readings, first 3 loops with 7-9errors, then 1 with 1error, and repeat, but without better equipment I cant say if that error is on the cc3200 end or my tool end. Now we just energia to implement a fix in an official release. This is what I am using atm. unsigned long micros(void) { unsigned long ms, cycles; do { ms = milliseconds; cycles = SysTickValueGet(); } while(ms != milliseconds); //If miliseconds changes while we read, we retry return (ms * 1000) + (((F_CPU/1000)-cycles) / (F_CPU/1000000)); } And for delayMicroseconds I use this (have not tested the ~70min rollover yet) void delayMicroseconds(unsigned int us) { unsigned long now = micros(); unsigned long endTime = now + us; if (endTime < now) //overflow { while (micros() > endTime); //Wait for micros to overflow before normal condition below } while (micros() <= endTime); } Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.