Browse Source

Upload files to ''

Added support for attiny85  at 16mhz.

Attiny85 fuses settings and OSCCAL calibration are required to meet the OneWire timing specifications
master
IanF 6 years ago
parent
commit
d698f10a08
  1. 51
      LowLevel.h
  2. 71
      OneWireSlave.cpp
  3. 12
      OneWireSlave.h

51
LowLevel.h

@ -29,20 +29,38 @@
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+2)) |= (mask)) #define DIRECT_WRITE_HIGH(base, mask) ((*((base)+2)) |= (mask))
#if defined (__AVR_ATtiny85__) #if defined (__AVR_ATtiny85__)
#define CLEARINTERRUPT GIFR |= (1 << INTF0)
#include "UserTimer.h" //ATtiny-support based on TinyCore1 Arduino-core for ATtiny at http://github.com/Coding-Badly/TinyCore1.git /* Note : The attiny85 clock speed = 16mhz (fuses L 0xF1, H 0xDF. E oxFF
OSCCAL VALUE must also be calibrated to 16mhz
*/
#define CLEARINTERRUPT GIFR |= (1 << INTF0) | (1<<PCIF);
#define USERTIMER_COMPA_vect TIMER1_COMPA_vect
__attribute__((always_inline)) static inline void UserTimer_Init( void ) __attribute__((always_inline)) static inline void UserTimer_Init( void )
{ {
UserTimer_SetToPowerup(); TCCR1 = 0; //stop the timer
UserTimer_SetWaveformGenerationMode(UserTimer_(CTC_OCR)); TCNT1 = 0;
//GTCCR |= (1<<PSR1); //reset the prescaler
TIMSK = 0; // clear timer interrupts enable
} }
__attribute__((always_inline)) static inline void UserTimer_Run(short skipTicks) __attribute__((always_inline)) static inline void UserTimer_Run(int skipTicks)
{ {
UserTimer_SetCount(0);
UserTimer_SetOutputCompareMatchAndClear(skipTicks); TCNT1 = 0; //zero the timer
UserTimer_ClockSelect(UserTimer_(Prescale_Value_64)); GTCCR |= (1 << PSR1); //reset the prescaler
OCR1A = skipTicks; //set the compare value
TCCR1 |= (1 << CTC1) | (0 << CS13) | (1 << CS12) | (1 << CS11) | (0 << CS10);//32 prescaler
//TCCR1 |= (1 << CTC1) | (0 << CS13) | (1 << CS12) | (0 << CS11) | (0 << CS10);//8 prescaler
TIMSK |= (1 << OCIE1A); //interrupt on Compare Match A
} }
#define UserTimer_Stop() UserTimer_ClockSelect(UserTimer_(Stopped))
__attribute__((always_inline)) static inline void UserTimer_Stop()
{
TIMSK = 0; //&= ~(1 << OCIE1A);// clear timer interrupt enable
TCCR1 = 0;
}
#elif defined (__AVR_ATmega328P__) #elif defined (__AVR_ATmega328P__)
#define CLEARINTERRUPT EIFR |= (1 << INTF0) #define CLEARINTERRUPT EIFR |= (1 << INTF0)
@ -52,8 +70,7 @@ __attribute__((always_inline)) static inline void UserTimer_Init( void )
{ {
TCCR1A = 0; TCCR1A = 0;
TCCR1B = 0; TCCR1B = 0;
// enable timer compare interrupt TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
} }
__attribute__((always_inline)) static inline void UserTimer_Run(short skipTicks) __attribute__((always_inline)) static inline void UserTimer_Run(short skipTicks)
{ {
@ -112,6 +129,7 @@ __attribute__((always_inline)) static inline void UserTimer_Run(short skipTicks)
#error "Please define I/O register types here" #error "Please define I/O register types here"
#endif #endif
class Pin class Pin
{ {
private: private:
@ -133,13 +151,6 @@ class Pin
pinNumber_ = pin; pinNumber_ = pin;
mask_ = PIN_TO_BITMASK(pin); mask_ = PIN_TO_BITMASK(pin);
reg_ = PIN_TO_BASEREG(pin); reg_ = PIN_TO_BASEREG(pin);
int x = reg_;
Serial.print(" Pin:");
Serial.print(pin);
Serial.print(" mask:");
Serial.print(mask_);
Serial.print(" reg:");
Serial.println(x);
switch (pin) switch (pin)
{ {
@ -176,12 +187,10 @@ class Pin
inline void attachInterrupt(void (*handler)(), int mode) inline void attachInterrupt(void (*handler)(), int mode)
{ {
//Serial.print(" handler:");
//int x = handler;
//Serial.println(x);
CLEARINTERRUPT; // clear any pending interrupt (we want to call the handler only for interrupts happening after it is attached) CLEARINTERRUPT; // clear any pending interrupt (we want to call the handler only for interrupts happening after it is attached)
::attachInterrupt(interruptNumber_, handler, mode); ::attachInterrupt(interruptNumber_, handler, mode);
} }
inline void detachInterrupt() { inline void detachInterrupt() {
::detachInterrupt(interruptNumber_); ::detachInterrupt(interruptNumber_);
} }

71
OneWireSlave.cpp

@ -11,16 +11,37 @@
namespace namespace
{ {
#if defined (__AVR_ATtiny85__)
const unsigned long ResetMinDuration = 480; // min 480us / 484us measured
const unsigned long ResetMaxDuration = 640; //
const unsigned long PresenceWaitDuration = 35; // spec 15us to 60us / 40us measured
const unsigned long PresenceDuration = 150; // spec 60us to 240us / 148us measured
const unsigned long ReadBitSamplingTime = 15; // spec > 15us to 60us / 31us measured
// SendBitDuration varies the bus release time to indicate a "1"
// measured total send bit duration is 63us versus 60us in the spec
const unsigned long SendBitDuration = 20; // bus release time spec 15us / measured 19us
#elif defined (__AVR_ATmega328P__)
const unsigned long ResetMinDuration = 480; const unsigned long ResetMinDuration = 480;
const unsigned long ResetMaxDuration = 900; const unsigned long ResetMaxDuration = 900;
const unsigned long PresenceWaitDuration = 15; const unsigned long PresenceWaitDuration = 15;
const unsigned long PresenceDuration = 200; const unsigned long PresenceDuration = 200;
const unsigned long ReadBitSamplingTime = 25; const unsigned long ReadBitSamplingTime = 25;
const unsigned long SendBitDuration = 35; const unsigned long SendBitDuration = 35;
#endif
const byte ReceiveCommand = (byte) - 1; const byte ReceiveCommand = (byte) - 1;
void(*timerEvent)() = 0; void(*timerEvent)() = 0;
@ -231,16 +252,33 @@ byte OneWireSlave::crc8(const byte* data, short numBytes)
return crc; return crc;
} }
#if defined (__AVR_ATtiny85__)
void OneWireSlave::setTimerEvent_(short delayMicroSeconds, void(*handler)())
{
delayMicroSeconds -= 8; // remove overhead (tuned on attiny85, values 0 - 10 work ok)
short skipTicks = delayMicroSeconds / 2; // 16mhz clock, prescaler = 32
if (skipTicks < 1) skipTicks = 1;
timerEvent = handler;
UserTimer_Run(skipTicks);
}
#elif defined (__AVR_ATmega328P__)
void OneWireSlave::setTimerEvent_(short delayMicroSeconds, void(*handler)()) void OneWireSlave::setTimerEvent_(short delayMicroSeconds, void(*handler)())
{ {
delayMicroSeconds -= 10; // remove overhead (tuned on Arduino Uno) delayMicroSeconds -= 10; // remove overhead (tuned on Arduino Uno)
// prescaler 64
short skipTicks = (delayMicroSeconds - 3) / 4; // round the micro seconds delay to a number of ticks to skip (4us per tick, so 4us must skip 0 tick, 8us must skip 1 tick, etc.) short skipTicks = (delayMicroSeconds - 3) / 4; // round the micro seconds delay to a number of ticks to skip (4us per tick, so 4us must skip 0 tick, 8us must skip 1 tick, etc.)
if (skipTicks < 1) skipTicks = 1; if (skipTicks < 1) skipTicks = 1;
timerEvent = handler; timerEvent = handler;
UserTimer_Run(skipTicks); UserTimer_Run(skipTicks);
} }
#endif
void OneWireSlave::disableTimer_() void OneWireSlave::disableTimer_()
{ {
UserTimer_Stop(); UserTimer_Stop();
@ -386,9 +424,11 @@ void OneWireSlave::beginWaitReset_()
disableTimer_(); disableTimer_();
pin_.inputMode(); pin_.inputMode();
pin_.attachInterrupt(&OneWireSlave::waitReset_, CHANGE); pin_.attachInterrupt(&OneWireSlave::waitReset_, CHANGE);
resetStart_ = (unsigned int)-1; //resetStart_ = (unsigned int) - 1;
resetStart_ = (unsigned long) - 1;
} }
void OneWireSlave::waitReset_() void OneWireSlave::waitReset_()
{ {
onEnterInterrupt_(); onEnterInterrupt_();
@ -396,22 +436,28 @@ void OneWireSlave::waitReset_()
unsigned long now = micros(); unsigned long now = micros();
if (state) if (state)
{ {
if (resetStart_ == (unsigned int)-1) if (resetStart_ == (unsigned long) - 1)
{ {
onLeaveInterrupt_(); onLeaveInterrupt_();
return; return;
} }
static unsigned long resetDuration = now - resetStart_;
unsigned long resetDuration = now - resetStart_; //resetStart_ = (unsigned int) - 1;
resetStart_ = (unsigned int)-1; resetStart_ = (unsigned long) - 1;
if (resetDuration >= ResetMinDuration) if (resetDuration >= ResetMinDuration)
{ {
if (resetDuration > ResetMaxDuration)
{ // The following test has been removed because of a bug which causes the value of
ERROR("Reset too long"); // resetduration to exceed ResetMaxDuration intermittently. This happens
onLeaveInterrupt_(); // only on the attiny platform - possibly due to the implementation of
return; // micros() in the attiny core
}
// if (resetDuration > ResetMaxDuration)
// {
// ERROR("Reset too long");
// onLeaveInterrupt_();
// return;
// }
lastReset_ = now; lastReset_ = now;
pin_.detachInterrupt(); pin_.detachInterrupt();
@ -420,6 +466,9 @@ void OneWireSlave::waitReset_()
endWrite_(true, false); endWrite_(true, false);
if (clientReceiveCallback_ != 0) if (clientReceiveCallback_ != 0)
clientReceiveCallback_(RE_Reset, 0); clientReceiveCallback_(RE_Reset, 0);
} else
{
//ERROR("Reset too short");
} }
} }
else else

12
OneWireSlave.h

@ -21,13 +21,19 @@ public:
void end(); void end();
//! Sets (or replaces) a function to be called when something is received. The callback is executed from interrupts and should be as short as possible. Failure to return quickly can prevent the library from correctly reading the next byte. //! Sets (or replaces) a function to be called when something is received. The callback is executed from interrupts and should be as short as possible. Failure to return quickly can prevent the library from correctly reading the next byte.
void setReceiveCallback(void(*callback)(ReceiveEvent evt, byte data)) { clientReceiveCallback_ = callback; } void setReceiveCallback(void(*callback)(ReceiveEvent evt, byte data)) {
clientReceiveCallback_ = callback;
}
//! Sets (or replaces) a function to be called when a bit is received. The byte reception callback is called after that if the received bit was the last of a byte. The callback is executed from interrupts and should be as short as possible. Failure to return quickly can prevent the library from correctly reading the next bit. //! Sets (or replaces) a function to be called when a bit is received. The byte reception callback is called after that if the received bit was the last of a byte. The callback is executed from interrupts and should be as short as possible. Failure to return quickly can prevent the library from correctly reading the next bit.
void setReceiveBitCallback(void(*callback)(bool bit)) { clientReceiveBitCallback_ = callback; } void setReceiveBitCallback(void(*callback)(bool bit)) {
clientReceiveBitCallback_ = callback;
}
//! Sets (or replaces) a function to be called when the library has a message to log, if the functionality is enabled in OneWireSlave.cpp. This is for debugging purposes. //! Sets (or replaces) a function to be called when the library has a message to log, if the functionality is enabled in OneWireSlave.cpp. This is for debugging purposes.
void setLogCallback(void(*callback)(const char* message)) { logCallback_ = callback; } void setLogCallback(void(*callback)(const char* message)) {
logCallback_ = callback;
}
//! Writes the specified bytes synchronously. This function blocks until the write operation has finished. Do not call from an interrupt handler! Returns true in case of success, false if an error occurs. //! Writes the specified bytes synchronously. This function blocks until the write operation has finished. Do not call from an interrupt handler! Returns true in case of success, false if an error occurs.
bool write(const byte* bytes, short numBytes); bool write(const byte* bytes, short numBytes);

Loading…
Cancel
Save