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.
Revision 0:7c6dd6bc20e4, committed 2013-04-15
- 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
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