Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
1-wire.cpp
- Committer:
- andrewboyson
- Date:
- 2016-06-02
- Revision:
- 7:024ace6d943c
- Parent:
- 6:be97d38e0b01
File content as of revision 7:024ace6d943c:
#include "mbed.h"
#include "log.h"
#include "io.h"
#include "1-wire.h"
#define DEBUG false //Set to true to add debug messages to the log
//Bus zone
//========
static DigitalInOut pin(p25, PIN_INPUT, PullUp, 0);
static volatile int busvalue;
static Timer timer;
static Timer busytimer;
//Delays
#define ATTACH_US 7
#define INITIAL_US 100
#define RESET_BUS_LOW_US 480
#define READ_PRESENCE_US 70
#define RESET_RELEASE_US 410
#define WRITE_0_BUS_LOW_US 60
#define WRITE_0_RELEASE_US 10
#define WRITE_1_BUS_LOW_US 6
#define WRITE_1_RELEASE_US 64
#define READ_BIT_BUS_LOW_US 6
#define READ_BIT_US 9
#define READ_BIT_RELEASE_US 55
#define BUS_TIMEOUT_MS 5000
static void buslow (void) { pin.output(); pin = 0; }
static void busfree(void) { pin.input (); }
static void bushigh(void) { pin.output(); pin = 1; }
static void busread(void) { busvalue = pin; }
//Exchange zone
//=============
#define STATE_IDLE 0
#define RESET_LOW 1
#define RESET_RELEASE 2
#define XCHG_WRITE 3
#define PULL_UP 4
#define XCHG_READ 5
#define SEARCH_WRITE 6
#define SEARCH_BIT 7
#define SEARCH_READ_BIT_TRUE 8
#define SEARCH_READ_BIT_COMP 9
#define SEARCH_WRITE_BIT 10
static int state = STATE_IDLE;
#define JOB_NONE 0
#define JOB_XCHG 1
#define JOB_SEARCH 2
static int job = JOB_NONE;
static int lensend = 0;
static int lenrecv = 0;
static char* psend = NULL;
static char* precv = NULL;
static int pullupms = 0;
static void initiateResetLow(int jobtype)
{
buslow();
timer.stop();
timer.reset();
timer.start();
state = RESET_LOW;
job = jobtype;
}
static void readPresenceAndAwaitResetRelease()
{
busfree();
wait_us(READ_PRESENCE_US);
busread();
timer.stop();
timer.reset();
timer.start();
state = RESET_RELEASE;
}
static void writeBit(int bit)
{
buslow();
wait_us(bit ? WRITE_1_BUS_LOW_US : WRITE_0_BUS_LOW_US);
busfree();
wait_us(bit ? WRITE_1_RELEASE_US : WRITE_0_RELEASE_US);
}
static void writeBitWithPullUp(int bit)
{
buslow();
wait_us(bit ? WRITE_1_BUS_LOW_US : WRITE_0_BUS_LOW_US);
bushigh();
timer.stop();
timer.reset();
timer.start();
state = PULL_UP;
}
static void readBit()
{
buslow();
wait_us(READ_BIT_BUS_LOW_US);
busfree();
wait_us(READ_BIT_US);
busread();
wait_us(READ_BIT_RELEASE_US);
}
static char crc;
static void resetCrc()
{
crc = 0;
}
static void addBitToCrc(int bit)
{
int feedback = !(crc & 0x80) != !bit; //Logical Exclusive Or of the msb of the shift register with the input
crc <<= 1; //Move the shift register one place to the left leaving a zero in the lsb and losing the msb
if (feedback) crc ^= 0x31; //Exclusive Or the shift register with polynomial X5 + X4 + 1
}
static void resetBitPosition(int* pByteIndex, char* pBitMask)
{
*pBitMask = 1;
*pByteIndex = 0;
}
static void incrementBitPosition(int* pByteIndex, char* pBitMask)
{
*pBitMask <<= 1;
if (!*pBitMask)
{
*pBitMask = 1;
*pByteIndex += 1;
}
}
int getBitAtPosition(int byteIndex, char bitMask)
{
return psend[byteIndex] & bitMask;
}
void setBitAtPosition(int byteIndex, char bitMask, int bit)
{
if ( bit) precv[byteIndex] |= bitMask;
else precv[byteIndex] &= ~bitMask;
}
int moreBitsToRead(int byteIndex)
{
return byteIndex < lenrecv;
}
int moreBitsToWrite(int byteIndex)
{
return byteIndex < lensend;
}
int result = ONE_WIRE_RESULT_OK;
int OneWireResult()
{
return result;
}
int OneWireInit()
{
busfree();
busytimer.stop();
busytimer.reset();
state = STATE_IDLE;
job = JOB_NONE;
return 0;
}
int OneWireBusy()
{
return state;
}
void OneWireExchange(int lenBytesToSend, int lenBytesToRecv, char *pBytesToSend, char *pBytesToRecv, int msToPullUp)
{
lensend = lenBytesToSend;
lenrecv = lenBytesToRecv;
psend = pBytesToSend;
precv = pBytesToRecv;
pullupms = msToPullUp;
initiateResetLow(JOB_XCHG);
}
static int* pallfound;
static char* prom;
static void setRomBit(int position, int bit)
{
int bitindex = position & 0x07;
int byteindex = position >> 3;
int bitmask = 1 << bitindex;
if (bit) *(prom + byteindex) |= bitmask;
else *(prom + byteindex) &= ~bitmask;
}
static int getRomBit(int position)
{
int bitindex = position & 0x07;
int byteindex = position >> 3;
int bitmask = 1 << bitindex;
return *(prom + byteindex) & bitmask;
}
static int thisFurthestForkLeftPosn;
static int lastFurthestForkLeftPosn;
static char searchCommand;
static int searchBitPosn;
static int searchBitTrue;
static int searchBitComp;
static int chooseDirectionToTake()
{
if ( searchBitTrue && searchBitComp) return -1; //No devices are participating in the search
if ( searchBitTrue && !searchBitComp) return 1; //Only devices with a one at this point are participating
if (!searchBitTrue && searchBitComp) return 0; //Only devices with a zero at this point are participating
//Both bits are zero so devices with both 0s and 1s at this point are still participating
//If we have not yet reached the furthest away point we forked left (0) last time then just do whatever we did last time
if (searchBitPosn < lastFurthestForkLeftPosn) return getRomBit(searchBitPosn);
//If we are at the furthest away point that we forked left (0) last time then this time fork right (1)
if (searchBitPosn == lastFurthestForkLeftPosn) return 1;
//We are at a new fork point further than we have been before so fork left (0) and record that we did so.
thisFurthestForkLeftPosn = searchBitPosn;
return 0;
}
void OneWireSearch(char command, char* pDeviceRom, int* pAllDevicesFound) //Specify the buffer to receive the rom for the first search and NULL thereafter.
{
if (pDeviceRom)
{
pallfound = pAllDevicesFound;
*pallfound = false;
lastFurthestForkLeftPosn = -1;
prom = pDeviceRom;
for (int i = 0; i < 8; i++) *(prom + i) = 0;
}
thisFurthestForkLeftPosn = -1;
lensend = 1;
lenrecv = 0;
searchCommand = command;
psend = &searchCommand;
precv = NULL;
pullupms = 0;
initiateResetLow(JOB_SEARCH);
}
char OneWireCrc()
{
return crc;
}
int OneWireMain()
{
static int byteindex;
static char bitmask;
if (state)
{
busytimer.start();
if (busytimer.read_ms() > BUS_TIMEOUT_MS)
{
LogCrLf("1-wire bus timed out so protocol has been reset to idle.");
OneWireInit();
result = ONE_WIRE_RESULT_TIMED_OUT;
return 0;
}
}
else
{
busytimer.stop();
busytimer.reset();
}
switch(state)
{
case STATE_IDLE:
break;
case RESET_LOW:
if (timer.read_us() > RESET_BUS_LOW_US) readPresenceAndAwaitResetRelease();
break;
case RESET_RELEASE:
if (timer.read_us() > RESET_RELEASE_US)
{
busfree();
timer.stop();
timer.reset();
if (busvalue)
{
LogCrLf("No 1-wire device presence detected on the bus");
result = ONE_WIRE_RESULT_NO_DEVICE_PRESENT;
state = STATE_IDLE;
}
else
{
resetBitPosition(&byteindex, &bitmask);
switch (job)
{
case JOB_XCHG: state = XCHG_WRITE; break;
case JOB_SEARCH: state = SEARCH_WRITE; break;
default:
LogF("Unknown job in RESET_RELEASE %d\r\n", job);
return -1;
}
}
}
break;
case XCHG_WRITE:
if (moreBitsToWrite(byteindex))
{
int bit = getBitAtPosition(byteindex, bitmask);
incrementBitPosition(&byteindex, &bitmask);
if (moreBitsToWrite(byteindex)) writeBit(bit);
else writeBitWithPullUp(bit);
}
else
{
resetBitPosition(&byteindex, &bitmask);
if (moreBitsToRead(byteindex))
{
resetCrc();
readBit();
state = XCHG_READ;
}
else
{
result = ONE_WIRE_RESULT_OK;
state = STATE_IDLE;
}
}
break;
case PULL_UP:
if (timer.read_ms() > pullupms)
{
busfree();
switch (job)
{
case JOB_XCHG: state = XCHG_WRITE; break;
default:
LogF("Unknown job in PULL_UP %d\r\n", job);
return -1;
}
}
break;
case XCHG_READ:
addBitToCrc(busvalue);
setBitAtPosition(byteindex, bitmask, busvalue);
incrementBitPosition(&byteindex, &bitmask);
if (moreBitsToRead(byteindex))
{
readBit();
}
else
{
state = STATE_IDLE;
result = crc ? ONE_WIRE_RESULT_CRC_ERROR : ONE_WIRE_RESULT_OK;
}
break;
case SEARCH_WRITE:
if (moreBitsToWrite(byteindex))
{
int bit = getBitAtPosition(byteindex, bitmask);
incrementBitPosition(&byteindex, &bitmask);
writeBit(bit);
}
else
{
searchBitPosn = 0;
state = SEARCH_BIT;
}
break;
case SEARCH_BIT:
readBit();
state = SEARCH_READ_BIT_TRUE;
break;
case SEARCH_READ_BIT_TRUE:
searchBitTrue = busvalue;
readBit();
state = SEARCH_READ_BIT_COMP;
break;
case SEARCH_READ_BIT_COMP:
searchBitComp = busvalue;
state = SEARCH_WRITE_BIT;
break;
case SEARCH_WRITE_BIT:
if (DEBUG) LogF("%d%d - ", searchBitTrue, searchBitComp);
int direction;
direction = chooseDirectionToTake();
if (direction == -1)
{
LogCrLf("No devices have responded");
result = ONE_WIRE_RESULT_NO_DEVICE_PARTICIPATING;
state = STATE_IDLE;
}
else
{
if (DEBUG) LogF(" %d -> %d\r\n", direction, searchBitPosn);
setRomBit(searchBitPosn, direction);
writeBit(direction);
searchBitPosn++;
if (searchBitPosn < 64)
{
state = SEARCH_BIT;
}
else
{
if (thisFurthestForkLeftPosn == -1) *pallfound = true;
lastFurthestForkLeftPosn = thisFurthestForkLeftPosn;
result = ONE_WIRE_RESULT_OK;
state = STATE_IDLE;
}
}
break;
default:
LogF("Unknown state %d\r\n", state);
return -1;
}
return 0;
}