Browse Source

- fixed bug in Pin::attachInterrupt (this is an arduino bug : interrupts that have been triggered before the handler is attached will cause it to be called immediately ; but only interrupts happening after should call the handler)

- changed OneWireSlave interface to make it completely static (there is an instance, but it's only a wrapper to the static stuff, so that the syntax looks nice)
- the search rom algorithm works fine most of the time, but sometimes it fails, probably because of interrupts being blocked at the wrong time (small delay to respond to the master to send a zero)
timer1
Youen Toupin 9 years ago
parent
commit
2294595995
  1. 12
      LowLevel.h
  2. 5
      OneWireIO.ino
  3. 88
      OneWireSlave.cpp
  4. 103
      OneWireSlave.h

12
LowLevel.h

@ -76,6 +76,12 @@ private:
byte interruptNumber_; byte interruptNumber_;
public: public:
Pin()
: mask_(0)
, reg_(0)
, interruptNumber_((byte)-1)
{ }
Pin(uint8_t pin) Pin(uint8_t pin)
{ {
mask_ = PIN_TO_BITMASK(pin); mask_ = PIN_TO_BITMASK(pin);
@ -97,7 +103,11 @@ public:
inline void writeHigh() { DIRECT_WRITE_HIGH(reg_, mask_); } inline void writeHigh() { DIRECT_WRITE_HIGH(reg_, mask_); }
inline void write(bool value) { if (value) writeHigh(); else writeLow(); } inline void write(bool value) { if (value) writeHigh(); else writeLow(); }
inline void attachInterrupt(void (*handler)(), int mode) { ::attachInterrupt(interruptNumber_, handler, mode); } inline void attachInterrupt(void (*handler)(), int mode)
{
EIFR |= (1 << INTF0); // clear any pending interrupt (we want to call the handler only for interrupts happending after it is attached)
::attachInterrupt(interruptNumber_, handler, mode);
}
inline void detachInterrupt() { ::detachInterrupt(interruptNumber_); } inline void detachInterrupt() { ::detachInterrupt(interruptNumber_); }
}; };

5
OneWireIO.ino

@ -11,14 +11,13 @@ SerialChannel debug("debug");
Pin led(LEDPin); Pin led(LEDPin);
byte owROM[7] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }; byte owROM[7] = { 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 };
OneWireSlave oneWire(owROM, OWPin);
void setup() void setup()
{ {
led.outputMode(); led.outputMode();
led.writeLow(); led.writeLow();
oneWire.enable(); OneWire.begin(owROM, OWPin);
Serial.begin(9600); Serial.begin(9600);
} }
@ -40,7 +39,7 @@ void loop()
SerialChannel::flush(); SerialChannel::flush();
byte b; byte b;
if (oneWire.read(b)) if (OneWire.read(b))
{ {
char msg[32]; char msg[32];
sprintf(msg, "Received byte : %d", (int)b); sprintf(msg, "Received byte : %d", (int)b);

88
OneWireSlave.cpp

@ -25,7 +25,25 @@ namespace
void(*timerEvent)() = 0; void(*timerEvent)() = 0;
} }
OneWireSlave* OneWireSlave::inst_ = 0; OneWireSlave OneWire;
byte OneWireSlave::rom_[8];
Pin OneWireSlave::pin_;
byte OneWireSlave::tccr1bEnable_;
unsigned long OneWireSlave::resetStart_;
unsigned long OneWireSlave::lastReset_;
void(*OneWireSlave::receiveBitCallback_)(bool bit, bool error);
void(*OneWireSlave::bitSentCallback_)(bool error);
byte OneWireSlave::receivingByte_;
byte OneWireSlave::receivingBitPos_;
byte OneWireSlave::receiveTarget_;
byte OneWireSlave::searchRomBytePos_;
byte OneWireSlave::searchRomBitPos_;
bool OneWireSlave::searchRomInverse_;
ISR(TIMER1_COMPA_vect) // timer1 interrupt ISR(TIMER1_COMPA_vect) // timer1 interrupt
{ {
@ -35,38 +53,37 @@ ISR(TIMER1_COMPA_vect) // timer1 interrupt
event(); event();
} }
OneWireSlave::OneWireSlave(byte* rom, byte pinNumber) void OneWireSlave::begin(byte* rom, byte pinNumber)
: pin_(pinNumber)
, resetStart_((unsigned long)-1)
, lastReset_(0)
, ignoreNextEdge_(false)
{ {
inst_ = this; // we can have only one instance in the current implementation pin_ = Pin(pinNumber);
resetStart_ = (unsigned long)-1;
lastReset_ = 0;
memcpy(rom_, rom, 7); memcpy(rom_, rom, 7);
rom_[7] = crc8_(rom_, 7); rom_[7] = crc8_(rom_, 7);
}
void OneWireSlave::enable()
{
#ifdef DEBUG_LOG #ifdef DEBUG_LOG
debug.append("Enabling 1-wire library"); debug.append("Enabling 1-wire library");
dbgOutput.outputMode(); dbgOutput.outputMode();
dbgOutput.writeHigh(); dbgOutput.writeHigh();
#endif #endif
cli(); // disable interrupts cli(); // disable interrupts
pin_.inputMode(); pin_.inputMode();
pin_.writeLow(); // make sure the internal pull-up resistor is disabled
// prepare hardware timer // prepare hardware timer
TCCR1A = 0; TCCR1A = 0;
TCCR1B = 0; TCCR1B = 0;
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
tccr1bEnable_ = (1 << WGM12) | (1 << CS11) | (1 << CS10); // turn on CTC mode with 64 prescaler tccr1bEnable_ = (1 << WGM12) | (1 << CS11) | (1 << CS10); // turn on CTC mode with 64 prescaler
// start 1-wire activity
beginWaitReset_(); beginWaitReset_();
sei(); // enable interrupts sei(); // enable interrupts
} }
void OneWireSlave::disable() void OneWireSlave::end()
{ {
#ifdef DEBUG_LOG #ifdef DEBUG_LOG
debug.append("Disabling 1-wire library"); debug.append("Disabling 1-wire library");
@ -165,7 +182,7 @@ void OneWireSlave::releaseBus_()
void OneWireSlave::beginWaitReset_() void OneWireSlave::beginWaitReset_()
{ {
disableTimer_(); disableTimer_();
pin_.attachInterrupt(&OneWireSlave::waitResetHandler_, CHANGE); pin_.attachInterrupt(&OneWireSlave::waitReset_, CHANGE);
resetStart_ = (unsigned int)-1; resetStart_ = (unsigned int)-1;
} }
@ -195,7 +212,7 @@ void OneWireSlave::waitReset_()
lastReset_ = now; lastReset_ = now;
pin_.detachInterrupt(); pin_.detachInterrupt();
setTimerEvent_(PresenceWaitDuration - (micros() - now), &OneWireSlave::beginPresenceHandler_); setTimerEvent_(PresenceWaitDuration - (micros() - now), &OneWireSlave::beginPresence_);
} }
} }
else else
@ -209,7 +226,7 @@ void OneWireSlave::beginPresence_()
{ {
unsigned long now = micros(); unsigned long now = micros();
pullLow_(); pullLow_();
setTimerEvent_(PresenceDuration, &OneWireSlave::endPresenceHandler_); setTimerEvent_(PresenceDuration, &OneWireSlave::endPresence_);
#ifdef DEBUG_LOG #ifdef DEBUG_LOG
debug.SC_APPEND_STR_TIME("reset", lastReset_); debug.SC_APPEND_STR_TIME("reset", lastReset_);
debug.SC_APPEND_STR_TIME("beginPresence", now); debug.SC_APPEND_STR_TIME("beginPresence", now);
@ -224,7 +241,6 @@ void OneWireSlave::endPresence_()
debug.SC_APPEND_STR_TIME("endPresence", now); debug.SC_APPEND_STR_TIME("endPresence", now);
#endif #endif
ignoreNextEdge_ = true;
beginWaitCommand_(); beginWaitCommand_();
} }
@ -238,26 +254,21 @@ void OneWireSlave::beginReceive_()
{ {
receivingByte_ = 0; receivingByte_ = 0;
receivingBitPos_ = 0; receivingBitPos_ = 0;
beginReceiveBit_(&OneWireSlave::onBitReceivedHandler_); beginReceiveBit_(&OneWireSlave::onBitReceived_);
} }
void OneWireSlave::beginReceiveBit_(void(*completeCallback)(bool bit, bool error)) void OneWireSlave::beginReceiveBit_(void(*completeCallback)(bool bit, bool error))
{ {
receiveBitCallback_ = completeCallback; receiveBitCallback_ = completeCallback;
pin_.attachInterrupt(&OneWireSlave::receiveHandler_, FALLING); pin_.attachInterrupt(&OneWireSlave::receive_, FALLING);
} }
void OneWireSlave::receive_() void OneWireSlave::receive_()
{ {
onEnterInterrupt_(); onEnterInterrupt_();
if (!ignoreNextEdge_) pin_.detachInterrupt();
{ setTimerEvent_(ReadBitSamplingTime, &OneWireSlave::readBit_);
pin_.detachInterrupt();
setTimerEvent_(ReadBitSamplingTime, &OneWireSlave::readBitHandler_);
}
ignoreNextEdge_ = false;
onLeaveInterrupt_(); onLeaveInterrupt_();
} }
@ -267,11 +278,11 @@ void OneWireSlave::beginSendBit_(bool bit, void(*completeCallback)(bool error))
bitSentCallback_ = completeCallback; bitSentCallback_ = completeCallback;
if (bit) if (bit)
{ {
pin_.attachInterrupt(&OneWireSlave::sendBitOneHandler_, FALLING); pin_.attachInterrupt(&OneWireSlave::sendBitOne_, FALLING);
} }
else else
{ {
pin_.attachInterrupt(&OneWireSlave::sendBitZeroHandler_, FALLING); pin_.attachInterrupt(&OneWireSlave::sendBitZero_, FALLING);
} }
} }
@ -279,28 +290,19 @@ void OneWireSlave::sendBitOne_()
{ {
onEnterInterrupt_(); onEnterInterrupt_();
bool ignoreEdge = ignoreNextEdge_; bitSentCallback_(false);
ignoreNextEdge_ = false;
if (!ignoreEdge)
bitSentCallback_(false);
onLeaveInterrupt_(); onLeaveInterrupt_();
} }
void OneWireSlave::sendBitZero_() void OneWireSlave::sendBitZero_()
{ {
onEnterInterrupt_(); pullLow_(); // this must be executed first because the timing is very tight with some master devices
if (ignoreNextEdge_) onEnterInterrupt_();
{
ignoreNextEdge_ = false;
return;
}
pullLow_();
pin_.detachInterrupt(); pin_.detachInterrupt();
setTimerEvent_(SendBitDuration, &OneWireSlave::endSendBitZeroHandler_); setTimerEvent_(SendBitDuration, &OneWireSlave::endSendBitZero_);
onLeaveInterrupt_(); onLeaveInterrupt_();
} }
@ -366,7 +368,7 @@ void OneWireSlave::onBitReceived_(bool bit, bool error)
} }
} }
beginReceiveBit_(&OneWireSlave::onBitReceivedHandler_); beginReceiveBit_(&OneWireSlave::onBitReceived_);
} }
void OneWireSlave::beginSearchRom_() void OneWireSlave::beginSearchRom_()
@ -384,7 +386,7 @@ void OneWireSlave::beginSearchRomSendBit_()
bool currentBit = bitRead(currentByte, searchRomBitPos_); bool currentBit = bitRead(currentByte, searchRomBitPos_);
bool bitToSend = searchRomInverse_ ? !currentBit : currentBit; bool bitToSend = searchRomInverse_ ? !currentBit : currentBit;
beginSendBit_(bitToSend, &OneWireSlave::continueSearchRomHandler_); beginSendBit_(bitToSend, &OneWireSlave::continueSearchRom_);
} }
void OneWireSlave::continueSearchRom_(bool error) void OneWireSlave::continueSearchRom_(bool error)
@ -403,7 +405,7 @@ void OneWireSlave::continueSearchRom_(bool error)
} }
else else
{ {
beginReceiveBit_(&OneWireSlave::searchRomOnBitReceivedHandler_); beginReceiveBit_(&OneWireSlave::searchRomOnBitReceived_);
} }
} }

103
OneWireSlave.h

@ -7,14 +7,11 @@
class OneWireSlave class OneWireSlave
{ {
public: public:
///! Constructs a 1-wire slave that will be identified by the specified ROM (7 bytes, starting from the family code, CRC will be computed internally). Call enable to actually start listening for the 1-wire master. ///! Starts listening for the 1-wire master, on the specified pin, as a virtual slave device identified by the specified ROM (7 bytes, starting from the family code, CRC will be computed internally). Reset, Presence, SearchRom and MatchRom are handled automatically. The library will use the external interrupt on the specified pin (note that this is usually not possible with all pins, depending on the board), as well as one hardware timer. Blocking interrupts (either by disabling them explicitely with sei/cli, or by spending time in another interrupt) can lead to malfunction of the library, due to tight timing for some 1-wire operations.
OneWireSlave(byte* rom, byte pinNumber); void begin(byte* rom, byte pinNumber);
///! Starts listening for the 1-wire master. Reset, Presence and SearchRom are handled automatically. The library will use interrupts on the pin specified in the constructor, as well as one hardware timer. Blocking interrupts (either by disabling them explicitely with sei/cli, or by spending time in another interrupt) can lead to malfunction of the library, due to tight timing for some 1-wire operations.
void enable();
///! Stops all 1-wire activities, which frees hardware resources for other purposes. ///! Stops all 1-wire activities, which frees hardware resources for other purposes.
void disable(); void end();
///! Pops one byte from the receive buffer, or returns false if no byte has been received. ///! Pops one byte from the receive buffer, or returns false if no byte has been received.
bool read(byte& b); bool read(byte& b);
@ -26,74 +23,62 @@ public:
void write(byte* bytes, short numBytes, void(*complete)(bool error)); void write(byte* bytes, short numBytes, void(*complete)(bool error));
private: private:
byte crc8_(byte* data, short numBytes); static byte crc8_(byte* data, short numBytes);
void setTimerEvent_(short delayMicroSeconds, void(*handler)()); static void setTimerEvent_(short delayMicroSeconds, void(*handler)());
void disableTimer_(); static void disableTimer_();
void onEnterInterrupt_(); static void onEnterInterrupt_();
void onLeaveInterrupt_(); static void onLeaveInterrupt_();
void error_(const char* message); static void error_(const char* message);
void pullLow_(); static void pullLow_();
void releaseBus_(); static void releaseBus_();
void beginWaitReset_(); static void beginReceiveBit_(void(*completeCallback)(bool bit, bool error));
void beginWaitCommand_(); static void beginSendBit_(bool bit, void(*completeCallback)(bool error));
void beginReceive_();
void beginReceiveBit_(void(*completeCallback)(bool bit, bool error)); static void beginWaitReset_();
void beginSendBit_(bool bit, void(*completeCallback)(bool error)); static void beginWaitCommand_();
static void beginReceive_();
static void onBitReceived_(bool bit, bool error);
void beginSearchRom_(); static void beginSearchRom_();
void beginSearchRomSendBit_(); static void beginSearchRomSendBit_();
inline static void continueSearchRomHandler_(bool error) { inst_->continueSearchRom_(error); } static void continueSearchRom_(bool error);
void continueSearchRom_(bool error); static void searchRomOnBitReceived_(bool bit, bool error);
inline static void searchRomOnBitReceivedHandler_(bool bit, bool error) { inst_->searchRomOnBitReceived_(bit, error); }
void searchRomOnBitReceived_(bool bit, bool error);
// interrupt handlers // interrupt handlers
inline static void waitResetHandler_() { inst_->waitReset_(); } static void waitReset_();
void waitReset_(); static void beginPresence_();
inline static void beginPresenceHandler_() { inst_->beginPresence_(); } static void endPresence_();
void beginPresence_(); static void receive_();
inline static void endPresenceHandler_() { inst_->endPresence_(); } static void readBit_();
void endPresence_(); static void sendBitOne_();
inline static void receiveHandler_() { inst_->receive_(); } static void sendBitZero_();
void receive_(); static void endSendBitZero_();
inline static void readBitHandler_() { inst_->readBit_(); }
void readBit_();
inline static void onBitReceivedHandler_(bool bit, bool error) { inst_->onBitReceived_(bit, error); }
void onBitReceived_(bool bit, bool error);
inline static void sendBitOneHandler_() { inst_->sendBitOne_(); }
void sendBitOne_();
inline static void sendBitZeroHandler_() { inst_->sendBitZero_(); }
void sendBitZero_();
inline static void endSendBitZeroHandler_() { inst_->endSendBitZero_(); }
void endSendBitZero_();
private: private:
static OneWireSlave* inst_; static byte rom_[8];
byte rom_[8]; static Pin pin_;
Pin pin_; static byte tccr1bEnable_;
byte tccr1bEnable_;
unsigned long resetStart_;
unsigned long lastReset_;
void(*receiveBitCallback_)(bool bit, bool error); static unsigned long resetStart_;
void(*bitSentCallback_)(bool error); static unsigned long lastReset_;
byte receivingByte_; static void(*receiveBitCallback_)(bool bit, bool error);
byte receivingBitPos_; static void(*bitSentCallback_)(bool error);
byte receiveTarget_;
bool ignoreNextEdge_; static byte receivingByte_;
static byte receivingBitPos_;
static byte receiveTarget_;
byte searchRomBytePos_; static byte searchRomBytePos_;
byte searchRomBitPos_; static byte searchRomBitPos_;
bool searchRomInverse_; static bool searchRomInverse_;
}; };
extern OneWireSlave OneWire;
#endif #endif

Loading…
Cancel
Save