An experimental timer interrupt driven software based 1-Wire master interface that was created by Robert David Brinzer for a University of Glasgow Level 4 Electronic and Software Engineering Final Year project. This implementation requires mbed RTOS and does not use NOP waits. Perfect for programs that require multi-tasking. Includes the Read and Search network commands and can be easily extended to support new network and transport commands.

Files at this revision

API Documentation at this revision

Comitter:
sroy
Date:
Mon Apr 15 07:02:49 2013 +0000
Commit message:
An experimental 1-Wire Master interface driven by timer interrupts rather than NOP waits created as part of a University of Glasgow Level 4 Electronic and Software Engineering final year project. Requires the use of mbed RTOS.

Changed in this revision

Instructions/Transport.cpp Show annotated file Show diff for this revision Revisions of this file
Instructions/Transport.h Show annotated file Show diff for this revision Revisions of this file
Interface/OneWire.cpp Show annotated file Show diff for this revision Revisions of this file
Interface/OneWire.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 7c6dd6bc20e4 Instructions/Transport.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Instructions/Transport.cpp	Mon Apr 15 07:02:49 2013 +0000
@@ -0,0 +1,178 @@
+#include "Transport.h"
+
+/* This table helps with the compution of the CRC8 used in OneWire ROM
+ *
+ * The theory is that it precomputes all possible states that an eight bit shift register
+ * can go to from a certain state when given a certain byte. Computationally and array
+ * lookup should be considerably faster than simulating the shift register a bit at a time.
+ *
+ * Table was sourced from maxim document AN937 that describes the standard.
+ */
+const unsigned char crc8table[256] = {
+    0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
+    157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
+    35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
+    190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
+    70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
+    219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
+    101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
+    248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
+    140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
+    17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
+    175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
+    50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
+    202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
+    87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
+    233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
+    116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53};
+    
+// read command
+
+void OWTransport::read(OneWire_Instruction * inst, OneWire_ROM * out){
+    inst->network.code = READ_ROM;
+    inst->network.inst = &OWTransport::_inst_readsetup;
+    inst->network.args = out;
+    *out = 0; // clear rom to a valid value (0 does pass CRC8 but is impossible to get as a device)
+}
+
+void OWTransport::_inst_readsetup(OneWire * which){
+    // setup register
+    ((TransportRead *)(which->registers))->read = 0;
+    ((TransportRead *)(which->registers))->crc8 = 0;
+    
+    // setup command
+    which->readhandle = &OWTransport::_inst_readhandler;
+    which->execute.inst = &OWTransport::_inst_read;
+    
+    // execute command
+    OWTransport::_inst_read(which);
+}
+
+void OWTransport::_inst_read(OneWire * which){
+    if(((TransportRead *)(which->registers))->read < 64){
+        which->op_read();
+    }else{
+        // check if crc8 check passed (remainder 0), failure is not recoverable
+        if(((TransportRead *)(which->registers))->crc8) which->abort(CRC_ERROR);
+        else which->endInstruction();
+    }
+}
+
+void OWTransport::_inst_readhandler(OneWire * which, char bit){
+    // store bit
+    *((unsigned char *)(which->execute.args))|= bit<<(((TransportRead *)(which->registers))->read++%8);
+    
+    // every 8 bits (byte) compute CRC8 and move to next byte
+    if(!(((TransportRead *)(which->registers))->read % 8)){
+        ((TransportRead *)(which->registers))->crc8 = crc8table[((TransportRead *)(which->registers))->crc8 ^ (*((unsigned char *)(which->execute.args)))];
+        which->execute.args = (void *)(((unsigned char *)(which->execute.args))+1);
+    }
+}
+
+// search command
+
+void TransportSearchPersist::clear(){
+    rom = 0;
+    last = -1;
+    done = false;
+}
+
+void OWTransport::search(OneWire_Instruction * inst, TransportSearchPersist * search){
+    inst->network.code = SEARCH_ROM;
+    inst->network.inst = &OWTransport::_inst_searchsetup;
+    inst->network.args = search;
+}
+
+void OWTransport::_inst_searchsetup(OneWire * which){
+    if(((TransportSearchPersist *)(which->execute.args))->done){
+        // the search had completed, there is nothing more to do
+        which->abort(SUCCESS);
+        return;
+    }
+
+    // setup register
+    ((TransportSearch *)(which->registers))->read = 0;
+    ((TransportSearch *)(which->registers))->crc8 = 0;
+    ((TransportSearch *)(which->registers))->marker = -1;
+    ((TransportSearch *)(which->registers))->bit = 0;
+    
+    // setup command
+    which->readhandle = &OWTransport::_inst_searchhandler;
+    which->execute.inst = &OWTransport::_inst_search;
+    
+    // execute command
+    OWTransport::_inst_search(which);
+}
+
+void OWTransport::_inst_search(OneWire * which){
+    if(((TransportSearch *)(which->registers))->read < 64){
+        // state machine, read bit 1 -> read bit 2 and make choice -> send choice -> repeat up to 64 times
+        if(((TransportSearch *)(which->registers))->bit>>3 & 0x01){
+            // send choosen bit and advance
+            if(((unsigned char *)&(((TransportSearchPersist *)(which->execute.args))->rom))[((TransportSearch *)(which->registers))->read/8]>>(((TransportSearch *)(which->registers))->read%8) &0x01){
+                which->op_send1();
+            }else{
+                which->op_send0();
+            }
+            // compute crc8
+            if(((TransportSearch *)(which->registers))->read % 8 == 7){
+                ((TransportSearch *)(which->registers))->crc8 = crc8table[((TransportSearch *)(which->registers))->crc8 ^ ((unsigned char *)&(((TransportSearchPersist *)(which->execute.args))->rom))[((TransportSearch *)(which->registers))->read/8]];
+            }
+            
+            // prepare for next cycle (reset state machine)
+            ((TransportSearch *)(which->registers))->read+= 1;
+            ((TransportSearch *)(which->registers))->bit = 0;
+        }else{
+            // read bit 1 and 2 (read function advances state machine)
+            which->op_read();
+        }
+    }else{
+        ((TransportSearchPersist *)(which->execute.args))->last = ((TransportSearch *)(which->registers))->marker;
+        if(((TransportSearchPersist *)(which->execute.args))->last == -1) ((TransportSearchPersist *)(which->execute.args))->done = true;
+        
+        // check if crc8 check passed (remainder 0), failure is not recoverable
+        if(((TransportSearch *)(which->registers))->crc8) which->abort(CRC_ERROR);
+        else which->endInstruction();
+    }
+}
+
+void OWTransport::_inst_searchhandler(OneWire * which, char bit){
+    // store bit
+    ((TransportSearch *)(which->registers))->bit|= bit<<(((TransportSearch *)(which->registers))->bit>>2 & 0x01);
+    
+    // advance state
+    if(((TransportSearch *)(which->registers))->bit>>2 & 0x01){
+        if((((TransportSearch *)(which->registers))->bit & 0x03) == 3){
+            // all slaves were removed or broke?
+            ((TransportSearchPersist *)(which->execute.args))->done = true; // any search results that were obtained could be invalid so end search
+            which->abort(NO_PRESENCE);
+            return;
+        }else if((((TransportSearch *)(which->registers))->bit & 0x03) == 0){
+            // a conflict bit
+            if(((TransportSearch *)(which->registers))->read == ((TransportSearchPersist *)(which->execute.args))->last){
+                // already searched 0 bit path, this time send a 1
+                ((unsigned char *)&(((TransportSearchPersist *)(which->execute.args))->rom))[((TransportSearch *)(which->registers))->read/8]|= 0x01<<(((TransportSearch *)(which->registers))->read%8);
+            }else if(((TransportSearch *)(which->registers))->read > ((TransportSearchPersist *)(which->execute.args))->last){
+                // a new branch to search
+                ((unsigned char *)&(((TransportSearchPersist *)(which->execute.args))->rom))[((TransportSearch *)(which->registers))->read/8]&= ~(0x01<<(((TransportSearch *)(which->registers))->read%8));
+                ((TransportSearch *)(which->registers))->marker = ((TransportSearch *)(which->registers))->read;
+            }else if( !(((unsigned char *)&(((TransportSearchPersist *)(which->execute.args))->rom))[((TransportSearch *)(which->registers))->read/8]>>(((TransportSearch *)(which->registers))->read%8) &0x01) ){
+                // a previous branch decision
+                ((TransportSearch *)(which->registers))->marker = ((TransportSearch *)(which->registers))->read;
+            }
+        }else{
+            // no conflict so write the bit
+            if(((TransportSearch *)(which->registers))->bit & 0x01){
+                ((unsigned char *)&(((TransportSearchPersist *)(which->execute.args))->rom))[((TransportSearch *)(which->registers))->read/8]|= 0x01<<(((TransportSearch *)(which->registers))->read%8);
+            }else{
+                ((unsigned char *)&(((TransportSearchPersist *)(which->execute.args))->rom))[((TransportSearch *)(which->registers))->read/8]&= ~(0x01<<(((TransportSearch *)(which->registers))->read%8));
+            }
+        }
+        
+        // tell next call to send the choice
+        ((TransportSearch *)(which->registers))->bit|= 0x08;
+    }else{
+        // we need to read another bit
+        ((TransportSearch *)(which->registers))->bit|= 0x04;
+    }
+}
\ No newline at end of file
diff -r 000000000000 -r 7c6dd6bc20e4 Instructions/Transport.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Instructions/Transport.h	Mon Apr 15 07:02:49 2013 +0000
@@ -0,0 +1,86 @@
+#ifndef ROM_COMMANDS
+#define ROM_COMMANDS
+
+#include "OneWire.h"
+
+class ROMCommands;
+
+#define READ_ROM 0x33
+#define SKIP_ROM 0xCC
+#define MATCH_ROM 0x55
+#define SEARCH_ROM 0xF0
+
+// type used to represent a one-wire rom code
+typedef unsigned long long OneWire_ROM;
+
+// types used for the one-wire registers
+typedef struct TransportRead{
+    unsigned char read; // bits or rom read
+    unsigned char crc8; // crc8 check
+} TransportRead;
+
+/** Persistant search structure
+ *  Used to keep track of search state and results between executions of the search transport layer command
+ */
+typedef struct TransportSearchPersist{
+    /** Rom code result of previous search operation
+     *
+     *  @note value should be ignored if a one-wire execution error occured
+     */
+    OneWire_ROM rom;
+    
+    signed char last; // used internally by the micro instruction system to keep track of state
+    
+    /** Used to tell when to end a search sequence
+     *
+     *  TRUE when the search has completed
+     *
+     *  FALSE when there are still rom codes left to search
+     */
+    bool done;
+    
+    /** Clears existing search state and results in preparation for a new search
+     *
+     *  This will reset search progress to start a search sequence from the beginning
+     *
+     *  @note Search sequences should be restarted if a one-wire execution error occured as persistant state values might be invalid
+     */
+    void clear();
+} TransportSearchPersist;
+
+typedef struct TransportSearch{
+    unsigned char read; // bits or rom read
+    unsigned char crc8; // crc8 check
+    signed char marker; // last conflict marker
+    unsigned char bit; // storage place current bit result
+} TransportSearch;
+
+/** One-Wire Transport layer class
+ *  Used to set up a one-wire instruction with a transport layer
+ */
+class OWTransport{
+public:
+    /** Set a one-wire instruction to perform the read transport layer command
+     *
+     * @param inst One-wire instruction that will carry out the command
+     * @param out One-wire rom that will be used to store the read rom code
+     */
+    static void read(OneWire_Instruction * inst, OneWire_ROM * out);
+    
+    /** Set a one-wire instruction to perform the search transport layer command
+     *
+     * @param inst One-wire instruction that will carry out the command
+     * @param search Persistant search structure that will be used for search state and results
+     */
+    static void search(OneWire_Instruction * inst, TransportSearchPersist * search);
+private:
+    // private functions which carry out the one-wire logic
+    static void _inst_readsetup(OneWire * which);
+    static void _inst_read(OneWire * which);
+    static void _inst_readhandler(OneWire * which, char bit);
+    static void _inst_searchsetup(OneWire * which);
+    static void _inst_search(OneWire * which);
+    static void _inst_searchhandler(OneWire * which, char bit);
+};
+
+#endif
\ No newline at end of file
diff -r 000000000000 -r 7c6dd6bc20e4 Interface/OneWire.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Interface/OneWire.cpp	Mon Apr 15 07:02:49 2013 +0000
@@ -0,0 +1,150 @@
+#include "OneWire.h"
+
+const OneWire_MicroInstruction OneWire::_OneWire_MicroProgram[10] = {&OneWire::_io_low,&OneWire::_io_high,
+                                                                    &OneWire::_io_low,&OneWire::_io_high,
+                                                                    &OneWire::_io_low,&OneWire::_io_high,&OneWire::_io_read,
+                                                                    &OneWire::_io_low,&OneWire::_io_high,&OneWire::_io_read};
+                                                                    
+const unsigned short DEFAULT_TIMES[10] = {ONEWIRE_WRITE1LOW, ONEWIRE_TIMESLOT+ONEWIRE_RECOVER-ONEWIRE_WRITE1LOW+ONEWIRE_RECOVER,
+                                                ONEWIRE_WRITE0LOW, ONEWIRE_TIMESLOT+ONEWIRE_RECOVER-ONEWIRE_WRITE0LOW+ONEWIRE_RECOVER,
+                                                ONEWIRE_READLOW, ONEWIRE_READDURATION-ONEWIRE_READLOW-1, ONEWIRE_TIMESLOT-ONEWIRE_READDURATION-ONEWIRE_READLOW-1+ONEWIRE_RECOVER,
+                                                ONEWIRE_TIMESLOT*8, ONEWIRE_PULSEHIGH+ONEWIRE_PULSELOW/2, ONEWIRE_TIMESLOT*8-(ONEWIRE_PULSEHIGH+ONEWIRE_PULSELOW/2)+ONEWIRE_RECOVER};
+
+void OneWire::_nextmicroinst(){
+    if(_microinstn == 0){
+        _resumeinst();
+    }else{
+        _timer.attach_us(this, &OneWire::_nextmicroinst, timeing[_microinstc]);
+        (this->*_OneWire_MicroProgram[_microinstc++])();
+        _microinstn-= 1;
+    }
+}
+
+void OneWire::_resumeinst(){
+    unsigned char offset = _inststate & 0x0F;
+    if(offset < 8){
+        if((execute.code>>offset) & 0x01) op_send1();
+        else op_send0();
+        _inststate+= 1;
+    }else{
+        if(execute.inst == NULL) endInstruction();
+        else (*(execute.inst))(this);
+    }
+    
+}
+
+void OneWire::_nextinst(){
+    if(_instn > 0){
+        execute = (*_instruction).network;
+        if(execute.inst == NULL) _inststate = 0x08; // skip network and transport command but allow reset
+        else _inststate = 0x10;
+        
+        // send reset pulse
+        readhandle = &OneWire::_presencedetect;
+        op_reset();
+    }else{
+        error = SUCCESS;
+        osSignalSet(_caller, 1);
+    }
+}
+
+void OneWire::_presencedetect(OneWire * which, char bit){
+    if(bit) which->abort(NO_PRESENCE); // it is pointless to continue when there is no device attached
+}
+
+void OneWire::_ei_detect(){
+    if(detecthandle != NULL) (*detecthandle)(this);
+}
+
+// Private pin I/O methods
+
+void OneWire::_io_high(){
+    _pin = 1;
+}
+
+void OneWire::_io_low(){
+    _pin = 0;
+}
+
+void OneWire::_io_read(){
+    _pin.input();
+    (*readhandle)(this, _pin);
+    _pin.output();
+}
+
+// Public utility methods
+
+OneWire::OneWire(PinName pin) : _pin(pin), _detect(pin){
+    _pin.output();
+    _pin = 1; // turn on devices to allow them to start working
+    _pin.mode(PullUp); 
+    _detect.mode(PullUp);
+    _detect.fall(this, &OneWire::_ei_detect);
+    timeing = DEFAULT_TIMES;
+    detecthandle = NULL;
+}
+
+int OneWire::send(OneWire_Instruction * inst, unsigned char instnum){
+    _detect.fall(NULL);
+    _instruction = inst;
+    _instn = instnum;
+    _nextinst();
+    _caller = Thread::gettid();
+    Thread::signal_wait(0);
+    osSignalSet(_caller, 0);
+    _detect.fall(this, &OneWire::_ei_detect);
+    return error != SUCCESS;
+}
+
+void OneWire::endInstruction(){
+    if(_inststate>>4 && _instruction->transport.inst != NULL){
+        execute = _instruction->transport;
+        _inststate = 0x00;
+        _timer.attach_us(this, &OneWire::_resumeinst, 1); // MAKE TIMING CONFIGURABLE
+    }else{
+        _instruction+= 1;
+        _instn-= 1;
+        _timer.attach_us(this, &OneWire::_nextinst, 1); // MAKE TIMING CONFIGURABLE
+    }
+}
+
+// depricated, use at own risk
+void OneWire::repeatInstruction(){
+    execute = (*_instruction).network;
+    _inststate = 0x10;
+    // send reset pulse
+    readhandle = &OneWire::_presencedetect;
+    op_reset();
+}
+
+void OneWire::abort(OneWire_Error err){
+    _timer.detach();
+    error = err;
+    osSignalSet(_caller, 1);
+}
+
+// Public IO methods
+
+void OneWire::op_send1(){
+    _microinstn = 2;
+    _microinstc = 0;
+    _nextmicroinst();
+}
+
+void OneWire::op_send0(){
+    _microinstn = 2;
+    _microinstc = 2;
+    _nextmicroinst();
+}
+
+void OneWire::op_read(){
+    _microinstn = 3;
+    _microinstc = 4;
+    _nextmicroinst();
+}
+
+void OneWire::op_reset(){
+    _microinstn = 3;
+    _microinstc = 7;
+    _nextmicroinst();
+}
\ No newline at end of file
diff -r 000000000000 -r 7c6dd6bc20e4 Interface/OneWire.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Interface/OneWire.h	Mon Apr 15 07:02:49 2013 +0000
@@ -0,0 +1,105 @@
+#ifndef ONE_WIRE
+#define ONE_WIRE
+
+#include "mbed.h"
+#include "rtos.h"
+
+class OneWire;
+
+typedef void (* OneWire_Instruction_Func)(OneWire *);
+
+typedef struct OneWire_InstCall{
+    unsigned char code;
+    OneWire_Instruction_Func inst;
+    void * args;
+} OneWire_InstCall;
+
+typedef struct OneWire_Instruction{
+    OneWire_InstCall network;
+    OneWire_InstCall transport;
+} OneWire_Instruction;
+
+typedef void (* OneWire_ReadHandler)(OneWire * which, char bit);
+
+typedef enum OneWire_Error {SUCCESS,
+                            NO_PRESENCE,
+                             ABORTED,
+                             CRC_ERROR} OneWire_Error;
+
+#define ONEWIRE_TIMESLOT 60 // 60 to 120
+#define ONEWIRE_RECOVER 1 // 1 to whatever
+#define ONEWIRE_PULSEHIGH 30 // 15 to 30
+#define ONEWIRE_PULSELOW 120 // 60 to 240
+#define ONEWIRE_WRITE1LOW 1 // 1 to 15
+#define ONEWIRE_WRITE0LOW 59 // 1 to ONEWIRE_TIMESLOT-1
+#define ONEWIRE_READLOW 1 // 1 to 14
+#define ONEWIRE_READDURATION 15 // 15
+#define ONEWIRE_READRELEASE 15 // 0 to 44
+
+extern const unsigned short DEFAULT_TIMES[];
+
+typedef void(OneWire::*OneWire_MicroInstruction)(void);
+
+// type for detection handler
+typedef void (* OneWire_Detection_Handler)(OneWire * which);
+
+class OneWire {
+public:
+    OneWire(PinName pin);
+    int send(OneWire_Instruction *, unsigned char);
+    void endInstruction();
+    void repeatInstruction();
+    
+    // stops all communication, resuming blocked thread with error.
+    void abort(OneWire_Error err);
+    
+    // one wire wakeup function
+    
+    // public fields
+    OneWire_Error error;
+    char registers[16];
+    
+    // configuration
+    OneWire_Detection_Handler detecthandle;
+    const unsigned short * timeing;
+    OneWire_ReadHandler readhandle;
+    OneWire_InstCall execute;
+    
+    // high level IO ops
+    void op_send1();
+    void op_send0();
+    void op_read();
+    void op_reset();
+    
+private:
+    // system resources
+    DigitalInOut _pin;
+    InterruptIn _detect;
+    Timeout _timer;
+    osThreadId _caller;
+    
+    // instruction system
+    OneWire_Instruction * _instruction;
+    unsigned char _instn;
+    unsigned char _inststate;
+    static const OneWire_MicroInstruction _OneWire_MicroProgram[];
+    unsigned char _microinstc;
+    unsigned char _microinstn;
+    
+    void _nextmicroinst();
+    void _resumeinst();
+    void _nextinst();
+    
+    // reset presence detect handler
+    static void _presencedetect(OneWire * which, char bit);
+    
+    // external interrupt handler
+    void _ei_detect();
+    
+    // low level IO ops
+    void _io_high();
+    void _io_low();
+    void _io_read();
+};
+
+#endif
\ No newline at end of file