CANBUS and Clocks and OrderingHi A very short intro at lecture room and then “Selfstudy/workshop”. You can call me by email. I will be available 15 min after intro lecture This page is organised as
Monday will be used for
NBNBNB: You can find many FlexCAN implementations out in “the cloud” The one above has been tested by Henrik and me and seems to work … Exercises for CANBUS partInspect code in
a) In the write call (starting from line 223) question; what is the difference in the outgoing part with timeout == 0 and timeout != 0 (and positive). b) in the read call (starting from line 170) question: how many rx buffers do we have ? c) write a test program for buffers you can run the code on one teensy if you connect you might be inspired by FlexCANtest/cantest2 and more
What impact will it have to set timeout to 0 or 1 in the can pkg you use to receive data in when calling FlexCAN read (in line 170) Exercise timestampingFlexCANtest/cantest3 is prepared for tx and rx an int in data byte 3-6 (see also FlexCANtest/cantest3a for inspiration)
ExtraHow does object ID works in FlexCAN ? Try to
some CANBUS stuffSee CANBUS code for FlexCANCANbus Exercise
file canmastertime.ino // -------------------------------------------------------------------- // DUAL Can program for teen sy 3.6CANtest for Teensy 3.6 dual CAN bus // beerlicense Jens Dalsgaard Nielsen Oct 2017 // inspired by Pawelsky's dualcantest // // -------------------------------------------------------------------- #include <FlexCAN.h> #ifndef __MK66FX1M0__ #error "Teensy 3.6 with dual CAN bus is required to run this example" #endif FlexCAN CANbus0(50000, 0, 1, 1); // 1 Mbit CAN0, 1,1 routes CAN0 to pins 29 & 30 FlexCAN CANbus1(50000, 1, 0, 0); // 1 Mbit CAN1 0,0 has no function - is always on pins 33 & 34 static CAN_message_t msgMasterBuf, msgSlaveBuf; // buffers for master and slave //#define MASTER // If MASTER is not defined (just above ) we define SLAVE #ifndef MASTER #define SLAVE #endif /*---------------------------------------------------------------- typedef struct CAN_message_t { uint32_t id; // can identifier uint8_t ext; // identifier is extended uint8_t len; // length of data uint16_t timeout; // milliseconds, zero will disable waiting uint8_t buf[8]; } CAN_message_t; ----------------------------------------------------------------*/ void wrInt(uint8_t buf[], unsigned long i , int pos) { unsigned long ii; ii = i; memcpy(&buf[pos], &(ii), sizeof(unsigned long)); // copy int to array on position "pos" } unsigned long rdInt(uint8_t buf[], int pos) { unsigned long i; memcpy(&i, &(buf[pos]), sizeof(unsigned long)); // copy int to array on position "pos" return i; } void dataDump(uint8_t data[]) // just print 8 bytes data { int i; Serial.print("CAN data: "); for (i = 0; i < 8 ; i++) { Serial.print(data[i]); } Serial.println(""); } void CANPackageDump(CAN_message_t pk) // prints CAN package { // We just dump a CAN bus package on Serial // Serial.print("CAN package dump. objektID: "); Serial.print(pk.id); // objektID in package if (pk.ext == 1) { Serial.print(" ext objektID (29 bit) "); } else { Serial.print(" short objektID(11bit) "); } Serial.print(" "); dataDump(pk.buf); // dump 8 byte data } void initMsg(CAN_message_t *pMessage, int objektID) { pMessage->id = objektID; pMessage->ext = 0; // 11 bit objektID pMessage->len = 8; // all 8 byte data shall be transmitted for (int i = 0; i < 8; i++) { pMessage->buf[i] = i; // write 0,1,2,...,7 in 8 byte in buf } } // ------------------------------------------------------------- // ------------------------------------------------------------- // -------------TRANSMIT AND RECEIVE FOR MASTER/SLAVE----------- // ------------------------------------------------------------- // ------------------------------------------------------------- // ------------------------------------------------------------- // ------------------------------------------------------------- // ------------USAGE OF the 8 byte data in buf ----------- // ------------------------------------------------------------- // ------------------------------------------------------------- /* Layout and use of the 8 data bytes in the CAN bus packet buf[0] : id of sender - legal interval 0-255 buf[1]: command (like 'R', 'W', 'C', 'T' etc buf[2]: no of port for buf[4]..buf[7]: 4 bytes used for transport of time (unsigned long) R: read W: write C: config (port) T: global time */ /* master sends a time packet every 3 second the time is pick up from millis plus an offset on 100.000.000 The offset is a dirty trick to be sure that two nodes can find each other It only require they are powered up with a max time distance of 100.000.000 milliseconds millis overflow at 2.000.000.000 So after 20 days the algoritms break as it is now */ const int masterID = 100; const int slaveID = 101; const int broadCastID = 50; const int masterClockID = 05; // high pririty for clock use const int timeBetweenTimePackets = 5000; // milli sec int lastMasterTxTime = 0; int masterTXCount = 0; const unsigned long timeOff = 10000000; unsigned long millisOffset = timeOff; // our own millis timer syncronized function unsigned long myMillis() { return millis() + millisOffset; } int noClockAdjustUp = 0, noClockAdjustDown = 0; void setMyClock(unsigned long timeFromClockMaster) { unsigned long timeNow; unsigned long adjustT; timeNow = myMillis(); if ( timeNow < timeFromClockMaster) { // locally we are behind masterclock adjustT = (timeFromClockMaster - timeNow); millisOffset += adjustT; noClockAdjustUp++; Serial.print(" offset(behind) adjust time no "); Serial.print(noClockAdjustUp); Serial.print(" adj amount "); Serial.print(adjustT); Serial.print(" new offset "); Serial.println(millisOffset); } else if (timeFromClockMaster < timeNow ) { // or we are ahead. adjustT = (timeNow - timeFromClockMaster); millisOffset -= adjustT; Serial.print(" offset(ahead) adjust -time no "); Serial.print(noClockAdjustDown); Serial.print(" adj amount "); Serial.print(adjustT); Serial.print(" new offset "); Serial.println(millisOffset); noClockAdjustDown++; // HMMMM what do you think about we can get same time again .. (back to the future syndrome) } else { Serial.println(" no clock adjust"); } } void txMaster() { unsigned long test; // if we are MASTER include the collowing code, othwerwises the txMAster function will just be empty #ifdef MASTER if ( timeBetweenTimePackets < (myMillis() - lastMasterTxTime ) ) { // has one second passed since last Tx ? lastMasterTxTime = myMillis(); // for next second // we add 1000000 bq we assume that from start there is less than 100000000 msec (100000 seconds) be startupTime of two nodes wrInt(msgMasterBuf.buf, (lastMasterTxTime), 4); // copy lastMasterTxTime to can //package buf array positions 4,5,6,7 (in the end) test = rdInt(msgMasterBuf.buf, 4); msgMasterBuf.id = masterClockID; // give it high prority (== low number) msgMasterBuf.ext = 0; msgMasterBuf.buf[0] = 'T'; // time package so everybody can recognize it CANbus0.write(msgMasterBuf); Serial.print("TX-MS int from master tx buf "); Serial.print(test); Serial.print(" org "); Serial.println(lastMasterTxTime); masterTXCount++; // now we have send one more Serial.print("TX master clock: "); Serial.println(myMillis()); } #endif } // receive part for master void rxMaster() { unsigned long timeFromClock; if ( CANbus0.available() ) { // any messages arrived ? Serial.println("RX-MS"); CANbus0.read(msgMasterBuf); // is it for me ? if (msgMasterBuf.id == masterID) { Serial.println(" master received a for-me package"); switch (msgMasterBuf.buf[1]) { case 'R': break; case 'W': break; case 'C': break; default :; } } else if (msgMasterBuf.id == masterClockID) { // Is it a time sync package from clock master ? // if we are not master we should be able to do clock stuff // but for now we wil llet it be handled by the slave // so time adjustment code is commented out here #ifndef MASTER // YES - double check it. There shall be a 'T' in buf[0]; if (msgMasterBuf.buf[0] == 'T') { // time sync package timeFromClock = rdInt(msgMasterBuf.buf, 4); // lets get int which is in buf[4] .. buf[7] (int is size 4 bytes) // no time adjustjment for now // setMyClock(timeFromClock); // and set/test my local clock Serial.print(" RX time pkg with time: "); Serial.println(timeFromClock); } #endif } else { Serial.print(" received a not-for-me packet with ID: "); Serial.println(msgMasterBuf.id); } } } // receive and reply for slave int slaveTXCount = 0; void rxSlave() { unsigned long timeFromClock;== if ( CANbus1.available() ) { // any messages arrived ? CANbus1.read(msgSlaveBuf); Serial.println("RX-SL"); // is it for us ? if (msgSlaveBuf.id == slaveID) { Serial.println("RX+ slave received a for-me package"); switch (msgSlaveBuf.buf[1]) { case 'R': msgSlaveBuf.id = masterID; msgSlaveBuf.ext = 0; // 11 bit objektID // here you can put info in package to master CANbus1.write(msgSlaveBuf); slaveTXCount++; Serial.print(" TX slave: "); Serial.println(slaveTXCount); break; case 'W': break; case 'C': break; default :; } } // HERE WE DO CLOCK SYNC STUFF else if (msgSlaveBuf.id == masterClockID) { #ifndef MASTER if (msgSlaveBuf.buf[0] == 'T') { // time sync package just an extra check timeFromClock = rdInt(msgSlaveBuf.buf, 4); // lets get unsigned long (32 bit) which is in buf[4] .. buf[7] Serial.print(" RX time pkg with time: "); Serial.println(timeFromClock); Serial.print(" local time is just now(ahead ?) "); Serial.println( myMillis()); // I know it takes time to print - but it will make problem more visible - time setMyClock(timeFromClock); // and set/test my local clock // But this should be done with the slave on another node. // we cant send time msg from myself to me. // In this case transport delay will naturally every sync time give an adjustment } #endif } } } void initAndStartCan0AndCan1() { pinMode(28, OUTPUT); // add on driver board for CAN0 enable pin (active LOW) pinMode(35, OUTPUT); // add on driver board for CAN1 enable pin (active LOW) digitalWrite(28, LOW); // activate CAN bus transceiver/driver for can0 digitalWrite(35, LOW); // activate 230 canbus transceiver for can1 CANbus0.begin(); // intitalise and start CAN0 interface (to be used for master) CANbus1.begin(); // ... - slave interface } // ------------------------------------------------------------- // ------------------------------------------------------------- // ----------------------HERE WE START-------------------------- // ------------------------------------------------------------- // ------------------------------------------------------------- void setup(void) { pinMode(13, OUTPUT); // our famous LED on pin 13 Serial.begin(115200); delay(1000); // let USb serial get time to be activated Serial.println( sizeof(int)); Serial.print(" Ul "); Serial.println(sizeof(unsigned long)); Serial.println("Teensy 3.6 dual CAN bus timer test "); initMsg(&msgMasterBuf, 100); // 100 is objektID which will be written in CAN package initMsg(&msgSlaveBuf, 200); // 200 is ... initAndStartCan0AndCan1(); Serial.println("gogo"); } // ------------------------------------------------------------- void loop(void) { // service as fast as possible - so NO delay in the functions !!! please :-) txMaster(); rxMaster(); rxSlave(); } Another smart program
name of code dualclock01 // -------------------------------------------------------------------- // DUAL Can program for teen sy 3.6CANtest for Teensy 3.6 dual CAN bus // beerlicense Jens Dalsgaard Nielsen Oct 2017 // inspired by Pawelsky's dualcantest // // -------------------------------------------------------------------- #include <FlexCAN.h> #ifndef __MK66FX1M0__ #error "Teensy 3.6 with dual CAN bus is required to run this example" #endif /*---------------------------------------------------------------- BASIC struct to send and to receive CAN bus messages typedef struct CAN_message_t { uint32_t id; // can identifier uint8_t ext; // identifier is extended uint8_t len; // length of data uint16_t timeout; // milliseconds, zero will disable waiting uint8_t buf[8]; } CAN_message_t; ----------------------------------------------------------------*/ CAN_message_t msgMasterBuf, msgSlaveBuf; // buffers for master and slave FlexCAN CANbus0(50000, 0, 1, 1); // 1 Mbit CAN0, 1,1 routes CAN0 to pins 29 & 30 FlexCAN CANbus1(50000, 1, 0, 0); // 1 Mbit CAN1 0,0 has no function - is always on pins 33 & 34 // --------- CONFIG PART ------------------- #define MASTERCLOCK #define BUGPR(x) Serial.print(x) // who is who and who am I ? const int myMasterID = 100; const int mySlaveID = 101; const int broadCastID = 50; const int masterClockID = 05; // high pririty for clock use // -----------------oOo----------------- void wrInt(uint8_t buf[], unsigned long i , int pos) // -- write int/long(32bit=4 byte) to an array { unsigned long ii; ii = i; memcpy(&buf[pos], &(ii), sizeof(unsigned long)); // copy int to array on position "pos" } unsigned long rdInt(uint8_t buf[], int pos) // -- read int/long(32bit=4 byte) to an array { unsigned long i; memcpy(&i, &(buf[pos]), sizeof(unsigned long)); // copy int to array on position "pos" return i; } void dataDump(CAN_message_t canPackage) // just print 8 bytes data (used for CANbus data buf { int i; for (i = 0; i < 8 ; i++) { BUGPR(canPackage.buf[i]); BUGPR(" "); } } void CANPackageDump(CAN_message_t pk) // prints CAN package { // We just dump a CAN bus package on Serial // if (pk.ext == 1) { BUGPR(" (29 bit) "); } else { BUGPR(" (11bit) "); } BUGPR("id length buf[8] "); BUGPR(pk.id); // objektID in package BUGPR(" "); BUGPR(pk.len); BUGPR(" : "); dataDump(pk); // dump 8 byte data BUGPR("\n"); } // ------------------------------------------------------------- // ------------------------------------------------------------- // -------------TRANSMIT AND RECEIVE FOR MASTER/SLAVE----------- // ------------------------------------------------------------- // ------------------------------------------------------------- // ------------------------------------------------------------- // ------------------------------------------------------------- // ------------USAGE OF the 8 byte data in buf ----------- // ------------------------------------------------------------- // ------------------------------------------------------------- /* Layout and use of the 8 data bytes in the CAN bus packet buf[0] : id of sender - legal interval 0-255 buf[1]: command (like 'R', 'W', 'C', 'T' etc buf[2]: no of port for buf[4]..buf[7]: 4 bytes used for transport of time (unsigned long) R: read W: write C: config (port) T: global time master sends a time packet every 3 second the time is pick up from millis plus an offset on 100.000.000 The offset is a dirty trick to be sure that two nodes can find each other It only require they are powered up with a max time distance of 100.000.000 milliseconds millis overflow at 2.000.000.000 So after 20 days the algoritms break as it is now */ const int timeBetweenTimePackets = 5000; // milli sec int lastMasterTxTime = 0; // time for last time sync/watch adjustement packet sedn from TxMasterr int masterTXCount = 0; // and how many has been send int noClockAdjustUp = 0, noClockAdjustDown = 0; // how many tiems has slave adjusted watch being behind or ahead const unsigned long timeOff = 10000000; // Our startTime is 0 + ... unsigned long millisOffset = 0; // time adjust part for slave // our own millis timer syncronized function for everybody except TxMaster where it sneds tiem sync packages //------------------------------------------------------oOo--------------------------------------- unsigned long myMillis() { return millis() + millisOffset; // millisOffset will change when watch is syncronized } //------------------------------------------------------oOo--------------------------------------- unsigned long masterClockMillis() { return millis() + timeOff; // timeOff is constant } //------------------------------------------------------oOo--------------------------------------- void setMyClock(unsigned long timeFromClockMaster) { unsigned long timeNow; unsigned long adjustT; timeNow = myMillis(); if ( timeNow < timeFromClockMaster) { // locally we are behind masterclock adjustT = (timeFromClockMaster - timeNow); millisOffset += adjustT; noClockAdjustUp++; BUGPR(" offset(behind) adjust time no "); BUGPR(noClockAdjustUp); BUGPR(" adj amount "); BUGPR(adjustT); BUGPR(" new offset "); BUGPR(millisOffset); BUGPR("\n"); } else if (timeFromClockMaster < timeNow ) { // or we are ahead. adjustT = (timeNow - timeFromClockMaster); millisOffset -= adjustT; noClockAdjustDown++; BUGPR(" offset(ahead) adjust -time no "); BUGPR(noClockAdjustDown); BUGPR(" adj amount "); BUGPR(adjustT); BUGPR(" new offset "); BUGPR(millisOffset); BUGPR("\n"); // HMMMM what do you think about we can get same time again .. (back to the future syndrome) } else { BUGPR(" no clock adjust this time\n"); } } //------------------------------------------------------oOo--------------------------------------- void tstAndSendTxClockSyncPackage() { #ifdef MASTERCLOCK unsigned long timeNow; timeNow = masterClockMillis(); if ( timeBetweenTimePackets < (timeNow - lastMasterTxTime ) ) { // has one second passed since last Tx ? lastMasterTxTime = timeNow; // for next second wrInt(msgMasterBuf.buf, timeNow, 4); // copy lastMasterTxTime to can //package buf array positions 4,5,6,7 (in the end) msgMasterBuf.id = masterClockID; // give it high prority (== low number) msgMasterBuf.ext = 0; // 11 bit address msgMasterBuf.buf[0] = 'T'; // time package so everybody can recognize it msgMasterBuf.len = 8; CANbus1.write(msgMasterBuf); BUGPR("TX-MS int from master tx buf no"); BUGPR(masterTXCount); BUGPR(" time now is: "); BUGPR(timeNow); BUGPR("\n"); masterTXCount++; // now we have send one more } #endif } //------------------------------------------------------oOo--------------------------------------- void txMaster() { // if we are MASTER include the collowing code, othwerwises the txMAster function will just be empty #ifdef MASTERCLOCK tstAndSendTxClockSyncPackage(); #endif } //------------------------------------------------------oOo--------------------------------------- void rxMasterPersonalPackage(CAN_message_t CANpk) { BUGPR(" master received a for-me package\n"); switch (CANpk.buf[1]) { case 'R': break; case 'W': break; case 'C': break; // -------------------------------------------------------------------- // DUAL Can program for teen sy 3.6CANtest for Teensy 3.6 dual CAN bus // beerlicense Jens Dalsgaard Nielsen Oct 2017 // inspired by Pawelsky's dualcantest // // -------------------------------------------------------------------- #include <FlexCAN.h> #ifndef __MK66FX1M0__ #error "Teensy 3.6 with dual CAN bus is required to run this example" #endif /*---------------------------------------------------------------- BASIC struct to send and to receive CAN bus messages typedef struct CAN_message_t { uint32_t id; // can identifier uint8_t ext; // identifier is extended uint8_t len; // length of data uint16_t timeout; // milliseconds, zero will disable waiting uint8_t buf[8]; } CAN_message_t; ----------------------------------------------------------------*/ CAN_message_t msgMasterBuf, msgSlaveBuf; // buffers for master and slave FlexCAN CANbus0(50000, 0, 1, 1); // 1 Mbit CAN0, 1,1 routes CAN0 to pins 29 & 30 FlexCAN CANbus1(50000, 1, 0, 0); // 1 Mbit CAN1 0,0 has no function - is always on pins 33 & 34 // --------- CONFIG PART ------------------- #define MASTERCLOCK #define BUGPR(x) Serial.print(x) // who is who and who am I ? const int myMasterID = 100; const int mySlaveID = 101; const int broadCastID = 50; const int masterClockID = 05; // high pririty for clock use // -----------------oOo----------------- void wrInt(uint8_t buf[], unsigned long i , int pos) // -- write int/long(32bit=4 byte) to an array { unsigned long ii; ii = i; memcpy(&buf[pos], &(ii), sizeof(unsigned long)); // copy int to array on position "pos" } unsigned long rdInt(uint8_t buf[], int pos) // -- read int/long(32bit=4 byte) to an array { unsigned long i; memcpy(&i, &(buf[pos]), sizeof(unsigned long)); // copy int to array on position "pos" return i; } void dataDump(CAN_message_t canPackage) // just print 8 bytes data (used for CANbus data buf { int i; for (i = 0; i < 8 ; i++) { BUGPR(canPackage.buf[i]); BUGPR(" "); } } void CANPackageDump(CAN_message_t pk) // prints CAN package { // We just dump a CAN bus package on Serial // if (pk.ext == 1) { BUGPR(" (29 bit) "); } else { BUGPR(" (11bit) "); } BUGPR("id length buf[8] "); BUGPR(pk.id); // objektID in package BUGPR(" "); BUGPR(pk.len); BUGPR(" : "); dataDump(pk); // dump 8 byte data BUGPR("\n"); } // ------------------------------------------------------------- // ------------------------------------------------------------- // -------------TRANSMIT AND RECEIVE FOR MASTER/SLAVE----------- // ------------------------------------------------------------- // ------------------------------------------------------------- // ------------------------------------------------------------- // ------------------------------------------------------------- // ------------USAGE OF the 8 byte data in buf ----------- // ------------------------------------------------------------- // ------------------------------------------------------------- /* Layout and use of the 8 data bytes in the CAN bus packet buf[0] : id of sender - legal interval 0-255 buf[1]: command (like 'R', 'W', 'C', 'T' etc buf[2]: no of port for buf[4]..buf[7]: 4 bytes used for transport of time (unsigned long) R: read W: write C: config (port) T: global time master sends a time packet every 3 second the time is pick up from millis plus an offset on 100.000.000 The offset is a dirty trick to be sure that two nodes can find each other It only require they are powered up with a max time distance of 100.000.000 milliseconds millis overflow at 2.000.000.000 So after 20 days the algoritms break as it is now */ const int timeBetweenTimePackets = 5000; // milli sec int lastMasterTxTime = 0; // time for last time sync/watch adjustement packet sedn from TxMasterr int masterTXCount = 0; // and how many has been send int noClockAdjustUp = 0, noClockAdjustDown = 0; // how many tiems has slave adjusted watch being behind or ahead const unsigned long timeOff = 10000000; // Our startTime is 0 + ... unsigned long millisOffset = 0; // time adjust part for slave // our own millis timer syncronized function for everybody except TxMaster where it sneds tiem sync packages //------------------------------------------------------oOo--------------------------------------- unsigned long myMillis() { return millis() + millisOffset; // millisOffset will change when watch is syncronized } //------------------------------------------------------oOo--------------------------------------- unsigned long masterClockMillis() { return millis() + timeOff; // timeOff is constant } //------------------------------------------------------oOo--------------------------------------- void setMyClock(unsigned long timeFromClockMaster) { unsigned long timeNow; unsigned long adjustT; timeNow = myMillis(); if ( timeNow < timeFromClockMaster) { // locally we are behind masterclock adjustT = (timeFromClockMaster - timeNow); millisOffset += adjustT; noClockAdjustUp++; BUGPR(" offset(behind) adjust time no "); BUGPR(noClockAdjustUp); BUGPR(" adj amount "); BUGPR(adjustT); BUGPR(" new offset "); BUGPR(millisOffset); BUGPR("\n"); } else if (timeFromClockMaster < timeNow ) { // or we are ahead. adjustT = (timeNow - timeFromClockMaster); millisOffset -= adjustT; noClockAdjustDown++; BUGPR(" offset(ahead) adjust -time no "); BUGPR(noClockAdjustDown); BUGPR(" adj amount "); BUGPR(adjustT); BUGPR(" new offset "); BUGPR(millisOffset); BUGPR("\n"); // HMMMM what do you think about we can get same time again .. (back to the future syndrome) } else { BUGPR(" no clock adjust this time\n"); } } //------------------------------------------------------oOo--------------------------------------- void tstAndSendTxClockSyncPackage() { #ifdef MASTERCLOCK unsigned long timeNow; timeNow = masterClockMillis(); if ( timeBetweenTimePackets < (timeNow - lastMasterTxTime ) ) { // has one second passed since last Tx ? lastMasterTxTime = timeNow; // for next second wrInt(msgMasterBuf.buf, timeNow, 4); // copy lastMasterTxTime to can //package buf array positions 4,5,6,7 (in the end) msgMasterBuf.id = masterClockID; // give it high prority (== low number) msgMasterBuf.ext = 0; // 11 bit address msgMasterBuf.buf[0] = 'T'; // time package so everybody can recognize it msgMasterBuf.len = 8; CANbus1.write(msgMasterBuf); BUGPR("TX-MS int from master tx buf no"); BUGPR(masterTXCount); BUGPR(" time now is: "); BUGPR(timeNow); BUGPR("\n"); masterTXCount++; // now we have send one more } #endif } //------------------------------------------------------oOo--------------------------------------- void txMaster() { // if we are MASTER include the collowing code, othwerwises the txMAster function will just be empty #ifdef MASTERCLOCK tstAndSendTxClockSyncPackage(); #endif } //------------------------------------------------------oOo--------------------------------------- void rxMasterPersonalPackage(CAN_message_t CANpk) { BUGPR(" master received a for-me package\n"); switch (CANpk.buf[1]) { case 'R': break; case 'W': break; case 'C': break; default :; } } //------------------------------------------------------oOo--------------------------------------- void doClockSync(CAN_message_t CANpk) { unsigned long timeFromClock; timeFromClock = rdInt(CANpk.buf, 4); // lets get int which is in buf[4] .. buf[7] (int is size 4 bytes) // no time adjustjment for now setMyClock(timeFromClock); // and set/test my local clock BUGPR(" RX time pkg with time: "); BUGPR(timeFromClock); BUGPR("\n"); } // receive part for master //------------------------------------------------------oOo--------------------------------------- void rxMaster() { unsigned long timeFromClock; if ( CANbus1.available() ) { // any messages arrived ? CANbus1.read(msgMasterBuf); BUGPR("RX-MS\n"); if (msgMasterBuf.id == myMasterID) { // is it for me personally ? rxMasterPersonalPackage(msgMasterBuf); } else if (msgMasterBuf.id == masterClockID) { // Is it a time sync package from clock master ? // if we are not master we should be able to do clock stuff // but for now we wil llet it be handled by the slave // so time adjustment code is commented out here // YES - double check it. There shall be a 'T' in buf[0]; if (msgMasterBuf.buf[0] == 'T') { // time sync package doClockSync(msgMasterBuf); } } else { return; BUGPR(" received a not-for-me packet with ID: "); BUGPR(msgMasterBuf.id); BUGPR("\n"); } } } void rxSlavePersonalPackage(CAN_message_t CANpk) { BUGPR(" master received a for-me package"); switch (CANpk.buf[1]) { case 'R': CANpk.id = myMasterID; CANpk.ext = 0; // 11 bit objektID // here you can put info in package to master CANbus1.write(CANpk); BUGPR(" TX slave to ... "); BUGPR(CANpk.id); break; case 'W': break; case 'C': break; default :; } BUGPR("\n"); } // receive and reply for slave //------------------------------------------------------oOo--------------------------------------- void rxSlave() { unsigned long timeFromClock; if ( CANbus0.available() ) { // any messages arrived ? CANbus0.read(msgSlaveBuf); BUGPR("RX SL pak received "); CANPackageDump(msgSlaveBuf); if (msgSlaveBuf.id == mySlaveID) { // is it for us ? BUGPR("RX+ slave received a for-me package\n"); rxSlavePersonalPackage(msgSlaveBuf); } // HERE WE DO CLOCK SYNC STUFF else if (msgSlaveBuf.id == masterClockID) { if (msgSlaveBuf.buf[0] == 'T') { // time sync package just an extra check doClockSync(msgSlaveBuf); } } } } //------------------------------------------------------oOo--------------------------------------- void initAndStartCan0AndCan1() { pinMode(28, OUTPUT); // add on driver board for CAN0 enable pin (active LOW) pinMode(35, OUTPUT); // add on driver board for CAN1 enable pin (active LOW) digitalWrite(28, LOW); // activate CAN bus transceiver/driver for can0 digitalWrite(35, LOW); // activate 230 canbus transceiver for can1 CANbus0.begin(); // intitalise and start CAN0 interface (to be used for master) CANbus1.begin(); // ... - slave interface } // ------------------------------------------------------------- // ------------------------------------------------------------- // ----------------------HERE WE START-------------------------- // ------------------------------------------------------------- // ------------------------------------------------------------- //------------------------------------------------------oOo--------------------------------------- void setup(void) { pinMode(13, OUTPUT); // our famous LED on pin 13 Serial.begin(115200); delay(1000); // let USb serial get time to be activated BUGPR("Teensy 3.6 dual CAN bus timer clock set test \n"); initAndStartCan0AndCan1(); BUGPR("gogo\n"); } //------------------------------------------------------oOo--------------------------------------- void loop(void) { // service as fast as possible - so NO delay in the functions !!! please :-) txMaster(); rxMaster(); rxSlave(); } default :; } } //------------------------------------------------------oOo--------------------------------------- void doClockSync(CAN_message_t CANpk) { unsigned long timeFromClock; timeFromClock = rdInt(CANpk.buf, 4); // lets get int which is in buf[4] .. buf[7] (int is size 4 bytes) // no time adjustjment for now setMyClock(timeFromClock); // and set/test my local clock BUGPR(" RX time pkg with time: "); BUGPR(timeFromClock); BUGPR("\n"); } // receive part for master //------------------------------------------------------oOo--------------------------------------- void rxMaster() { unsigned long timeFromClock; if ( CANbus1.available() ) { // any messages arrived ? CANbus1.read(msgMasterBuf); BUGPR("RX-MS\n"); if (msgMasterBuf.id == myMasterID) { // is it for me personally ? rxMasterPersonalPackage(msgMasterBuf); } else if (msgMasterBuf.id == masterClockID) { // Is it a time sync package from clock master ? // if we are not master we should be able to do clock stuff // but for now we wil llet it be handled by the slave // so time adjustment code is commented out here // YES - double check it. There shall be a 'T' in buf[0]; if (msgMasterBuf.buf[0] == 'T') { // time sync package doClockSync(msgMasterBuf); } } else { return; BUGPR(" received a not-for-me packet with ID: "); BUGPR(msgMasterBuf.id); BUGPR("\n"); } } } void rxSlavePersonalPackage(CAN_message_t CANpk) { BUGPR(" master received a for-me package"); switch (CANpk.buf[1]) { case 'R': CANpk.id = myMasterID; CANpk.ext = 0; // 11 bit objektID // here you can put info in package to master CANbus1.write(CANpk); BUGPR(" TX slave to ... "); BUGPR(CANpk.id); break; case 'W': break; case 'C': break; default :; } BUGPR("\n"); } // receive and reply for slave //------------------------------------------------------oOo--------------------------------------- void rxSlave() { unsigned long timeFromClock; if ( CANbus0.available() ) { // any messages arrived ? CANbus0.read(msgSlaveBuf); BUGPR("RX SL pak received "); CANPackageDump(msgSlaveBuf); if (msgSlaveBuf.id == mySlaveID) { // is it for us ? BUGPR("RX+ slave received a for-me package\n"); rxSlavePersonalPackage(msgSlaveBuf); } // HERE WE DO CLOCK SYNC STUFF else if (msgSlaveBuf.id == masterClockID) { if (msgSlaveBuf.buf[0] == 'T') { // time sync package just an extra check doClockSync(msgSlaveBuf); } } } } //------------------------------------------------------oOo--------------------------------------- void initAndStartCan0AndCan1() { pinMode(28, OUTPUT); // add on driver board for CAN0 enable pin (active LOW) pinMode(35, OUTPUT); // add on driver board for CAN1 enable pin (active LOW) digitalWrite(28, LOW); // activate CAN bus transceiver/driver for can0 digitalWrite(35, LOW); // activate 230 canbus transceiver for can1 CANbus0.begin(); // intitalise and start CAN0 interface (to be used for master) CANbus1.begin(); // ... - slave interface } // ------------------------------------------------------------- // ------------------------------------------------------------- // ----------------------HERE WE START-------------------------- // ------------------------------------------------------------- // ------------------------------------------------------------- //------------------------------------------------------oOo--------------------------------------- void setup(void) { pinMode(13, OUTPUT); // our famous LED on pin 13 Serial.begin(115200); delay(1000); // let USb serial get time to be activated BUGPR("Teensy 3.6 dual CAN bus timer clock set test \n"); initAndStartCan0AndCan1(); BUGPR("gogo\n"); } //------------------------------------------------------oOo--------------------------------------- void loop(void) { // service as fast as possible - so NO delay in the functions !!! please :-) txMaster(); rxMaster(); rxSlave(); } SELF STUDY PARTClocksTodays selfstudy is about clocks and ordering. Basic problem is ordering of events on different machines.
Today we can argue for that in many systems we can base and evaluate event ordering on time from satellites. In some cases this may not be possible. So … See a blog story which covers most of the stuff in a nice way. Primary Litterature
Exercises
Secondary litterature - is you have time
Some extra litteratureThis as just things I have found during the years. Dont read it for today m but might be nice to have :-) All litterature just above as a zip file Jens |