- C that works with and XC that fails. (Code piece 1 below)
The C-code for the Arduino is “blocking” and there is no support for multi-threading. However, my first trial to port this to XC failed - XC that works with 0.65536 ms resolution. (Code piece 2 below)
But a version where the 1 ms resolution of the Arduino millis() had to be ported as 0.65536 ms ticks in XC works. The problem is how “modulo 1 ms” arithmetics is done when the timer word with is 32 bits and it increments by the XMOS processor every 10 ns. So 10 ns * 2exp16 -> 0.65536 ms. This timing is done “inline”, but since anything XC is multi-threading (multi-task) that doesn’t really harm it. The problem is I can’t order a 100 ms timeout (but I could do 152 ticks = 99.61472 ms) - XC that works with 1 ms resolution. (Code at blog note)
Here we have proper 1 ms resolution, done by “proper” handling by an XC timer, by storing a future timeout-value in proper 32 bits width. The code is “inline” as above - XC server with state-based timing serving two clients. (Code at blog note)
Here the timing is handled in a proper select case. I guess this is closest to idiomatic XC. The server serves two clients, one that fails and one that succeeds in reading a register. Impressingly the handling of the two clients is “fair”, ie. none of them jam the other
First code "C that works with and XC that fails" (1):
Code: Select all
#include <stdio.h>
#include <xs1.h>
#include <iso646.h>
#include <timer.h> // delay_milliseconds(200), XS1_TIMER_HZ etc
typedef enum {false,true} bool;
#define DEBUG_PRINT_TEST 1
#define debug_print(fmt, ...) do { if(DEBUG_PRINT_TEST) printf(fmt, __VA_ARGS__); } while (0)
signed millis () {
timer tmr;
signed current_time;
tmr :> current_time;
return (current_time / XS1_TIMER_KHZ); // Never works! XS_TIMER_KHZ is 100*1000
}
unsigned digitalRead (void) {
return (0);
}
#define RF69_TX_LIMIT_MS 100
#define TEST_TYPE signed // Too wide and does not match millis()
#define MILLIS() millis()
void test_task (void) {
TEST_TYPE millis_;
TEST_TYPE txStart;
unsigned testCnt = 0;
bool not_timed_out;
while (testCnt < 500) {
txStart = MILLIS();
do {
millis_ = MILLIS();
not_timed_out = (millis_ - txStart) < RF69_TX_LIMIT_MS;
debug_print ("testCnt(%d), millis(%d), txStart(%d), millis_-txStart(%d), timedOut(%d)\n",
testCnt, millis_, txStart, millis_ - txStart, !not_timed_out);
delay_milliseconds(20);
} while ((digitalRead() == 0) && not_timed_out);
testCnt++;
}
}
int main() {
par {
test_task();
}
return 0;
}
/* DOES NOT WORK!
testCnt(351), millis(42729), txStart(42629), millis_-txStart(100), timedOut(1)
testCnt(352), millis(42749), txStart(42749), millis_-txStart(0), timedOut(0)
testCnt(352), millis(42769), txStart(42749), millis_-txStart(20), timedOut(0)
testCnt(352), millis(42789), txStart(42749), millis_-txStart(40), timedOut(0)
testCnt(352), millis(42809), txStart(42749), millis_-txStart(60), timedOut(0)
testCnt(352), millis(42829), txStart(42749), millis_-txStart(80), timedOut(0)
testCnt(352), millis(42849), txStart(42749), millis_-txStart(100), timedOut(1) LAST TIMEOUT EVER!
testCnt(353), millis(42869), txStart(42869), millis_-txStart(0), timedOut(0)
testCnt(353), millis(42890), txStart(42869), millis_-txStart(21), timedOut(0)
testCnt(353), millis(42910), txStart(42869), millis_-txStart(41), timedOut(0)
testCnt(353), millis(42930), txStart(42869), millis_-txStart(61), timedOut(0)
testCnt(353), millis(0), txStart(42869), millis_-txStart(-42869), timedOut(0)
testCnt(353), millis(20), txStart(42869), millis_-txStart(-42849), timedOut(0)
testCnt(353), millis(40), txStart(42869), millis_-txStart(-42829), timedOut(0)
testCnt(353), millis(60), txStart(42869), millis_-txStart(-42809), timedOut(0)
testCnt(353), millis(80), txStart(42869), millis_-txStart(-42789), timedOut(0)
testCnt(353), millis(100), txStart(42869), millis_-txStart(-42769), timedOut(0)
testCnt(353), millis(120), txStart(42869), millis_-txStart(-42749), timedOut(0)
testCnt(353), millis(140), txStart(42869), millis_-txStart(-42729), timedOut(0)
*/
Code: Select all
#include <stdio.h>
#include <xs1.h>
#include <iso646.h>
#include <timer.h> // delay_milliseconds(200), XS1_TIMER_HZ etc
typedef enum {false,true} bool;
#define DEBUG_PRINT_TEST 1
#define debug_print(fmt, ...) do { if(DEBUG_PRINT_TEST) printf(fmt, __VA_ARGS__); } while (0)
// DEFINING A FMS-TICK AS A "fast ms" (fms, FMS) - AND IT IS 0.65536 ms (2exp16=65536)
// One fms-tick is 100 MHz XMOS system-tick (10 ns) into a 16 bits word every 65536 system-tick
//
typedef signed short time16_fms_t; // fms=fast ms
//
#define FAST_MILLIS_PER_10MS 15 // 10 / .65536
#define FAST_MILLIS_PER_100MS 153 // 100 / .65536
#define FAST_MILLIS_PER_1S 1526 // 1000 / .65536
//
#define MS_TO_FMS(ms) ((ms*FAST_MILLIS_PER_1S)/1000)
time16_fms_t fms() { // fms=fast ms. Returns one tick as 0.65536 ms (10ns * 65536)
timer tmr; // 32 bits
signed current_time; // 32 bits
tmr :> current_time; // 32 bits
return (time16_fms_t) (current_time >> 16); // 16 bits. Keep sign bit (or use / 65536)
}
unsigned digitalRead (void) {
return (0);
}
#define RF69_TX_LIMIT_MS 100
#define RF69_TX_LIMIT_FMS MS_TO_FMS (RF69_TX_LIMIT_MS)
void test_task (void) {
time16_fms_t now_fms;
time16_fms_t txStart_fms;
time16_fms_t diff_fms;
unsigned testCnt = 0;
bool not_timed_out;
debug_print ("100 ms is %d ticks\n",RF69_TX_LIMIT_FMS);
while (testCnt < 500) {
txStart_fms = fms();
do {
now_fms = fms();
diff_fms = now_fms - txStart_fms;
not_timed_out = diff_fms < RF69_TX_LIMIT_FMS;
debug_print ("testCnt(%d), now_fms(%d), txStart_fms(%d), diff_fms(%d), timedOut(%d)\n",
testCnt, now_fms, txStart_fms, diff_fms, !not_timed_out);
delay_milliseconds (RF69_TX_LIMIT_MS/2); // TRUE 50 ms!
} while ((digitalRead() == 0) && not_timed_out);
testCnt++;
}
}
int main() {
par {
test_task();
}
return 0;
}
/* WORKS:
100 ms is 152 ticks
testCnt(0), now_fms(581), txStart_fms(581), diff_fms(0), timedOut(0)
testCnt(0), now_fms(657), txStart_fms(581), diff_fms(76), timedOut(0)
testCnt(0), now_fms(734), txStart_fms(581), diff_fms(153), timedOut(1)
testCnt(1), now_fms(810), txStart_fms(810), diff_fms(0), timedOut(0)
...
testCnt(139), now_fms(32586), txStart_fms(32434), diff_fms(152), timedOut(1)
testCnt(140), now_fms(32663), txStart_fms(32663), diff_fms(0), timedOut(0)
testCnt(140), now_fms(32739), txStart_fms(32663), diff_fms(76), timedOut(0)
testCnt(140), now_fms(-32719), txStart_fms(32663), diff_fms(154), timedOut(1)
testCnt(141), now_fms(-32643), txStart_fms(-32643), diff_fms(0), timedOut(0)
testCnt(141), now_fms(-32567), txStart_fms(-32643), diff_fms(76), timedOut(0)
testCnt(141), now_fms(-32490), txStart_fms(-32643), diff_fms(153), timedOut(1)
*/
I guess my question is, has anyone of you made a true millis() equivalent?
I guess it would be possible by writing code for a 100*1000 modulo sized arithmetics? I guess it would need plus, minus, mult and div. Or is there some magically simpler solution that I haven't thought of? I might have dug myself into a hole!-(
[1] https://www.arduino.cc/reference/en/lan ... me/millis/
[2] http://www.teigfam.net/oyvind/home/tech ... th_timeout Disclaimer: no money, no ads, no gifts, only fun and expenses on all my blog notes!