Skip to content

Commit

Permalink
clean up pin-access
Browse files Browse the repository at this point in the history
tested with atmega328
  • Loading branch information
orgua committed Sep 26, 2016
1 parent be14bab commit 5a83935
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 39 deletions.
13 changes: 7 additions & 6 deletions examples/OneWireHubTest/OneWireHubTest.ino
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,16 @@ auto ds18B20 = DS18B20(0x28, 0x0D, 0x01, 0x08, 0x0B, 0x02, 0x00); // Work
auto ds18S20 = DS18B20(0x10, 0x0D, 0x01, 0x08, 0x0F, 0x02, 0x00);
auto ds2401a = DS2401( 0x01, 0x00, 0x0D, 0x24, 0x01, 0x00, 0x0A ); // Work - Serial Number
auto ds2401b = DS2401( 0x01, 0x00, 0x0D, 0x24, 0x01, 0x00, 0x0B ); // Work - Serial Number
// auto ds2405 = DS2405( 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ); // - Single address switch
auto ds2405 = DS2405( 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ); // - Single address switch
// auto ds2408 = DS2408( 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ); // - 8-Channel Addressable Switch
auto ds2413 = DS2413( 0x3A, 0x0D, 0x02, 0x04, 0x01, 0x03, 0x00 ); // Work - Dual channel addressable switch
// auto ds2423 = DS2423( 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ); // - 4kb 1-Wire RAM with Counter
// auto ds2433 = DS2433( 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ); // - 4Kb 1-Wire EEPROM
auto ds2438 = DS2438( 0x26, 0x0D, 0x02, 0x04, 0x03, 0x08, 0x00 ); // - Smart Battery Monitor
auto ds2450 = DS2450( 0x20, 0x0D, 0x0A, 0x02, 0x04, 0x05, 0x00 ); // - 4 channel A/D
auto ds2890A = DS2890( 0x2C, 0x0D, 0x02, 0x08, 0x09, 0x00, 0x0A ); // Work - Single channel digital potentiometer
auto ds2890B = DS2890( 0x2C, 0x0D, 0x02, 0x08, 0x09, 0x00, 0x0B );
auto ds2890C = DS2890( 0x2C, 0x0D, 0x02, 0x08, 0x09, 0x00, 0x0C );
//auto ds2890B = DS2890( 0x2C, 0x0D, 0x02, 0x08, 0x09, 0x00, 0x0B );
//auto ds2890C = DS2890( 0x2C, 0x0D, 0x02, 0x08, 0x09, 0x00, 0x0C );

bool blinking()
{
Expand Down Expand Up @@ -71,13 +71,14 @@ void setup()
hub.attach(ds18B20);
hub.attach(ds18S20);
hub.attach(ds2401a);
hub.attach(ds2401b);
hub.attach(ds2405);
//hub.attach(ds2401b);
hub.attach(ds2413);
hub.attach(ds2438);
//hub.attach(ds2450);
hub.attach(ds2890A);
hub.attach(ds2890B);
hub.attach(ds2890C);
//hub.attach(ds2890B);
//hub.attach(ds2890C);

Serial.println("config done");
}
Expand Down
140 changes: 140 additions & 0 deletions examples/debug/optimize_pinAccess/optimize_pinAccess.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* Test-Code for portable hardware access
*
* atmega328@16MHz makes around 571 kHz with pin-toggling
*/

#include "OneWireHub.h"

/////////////////////////////////////////////////////////////////////////
/////// From OnewireHub <0.9.7 //////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

uint8_t pin_bitMaskL;
volatile uint8_t *baseRegL;

void pinConfigLegacy(const uint8_t pin)
{
// setup direct pin-access
pin_bitMaskL = digitalPinToBitMask(pin);
baseRegL = portInputRegister(digitalPinToPort(pin));
}

void pinTestLegacy(void)
{
volatile uint8_t *reg asm("r30") = baseRegL; // note: asm only for AVR, really needed? investigate

DIRECT_WRITE_LOW(reg, pin_bitMaskL);
DIRECT_MODE_OUTPUT(reg, pin_bitMaskL); // set it low, so it always reads zero

while(1)
{
DIRECT_WRITE_HIGH(reg, pin_bitMaskL);
DIRECT_WRITE_LOW(reg, pin_bitMaskL);
};
};


/////////////////////////////////////////////////////////////////////////
/////// From OnewireLib 2.3.2 //////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

/*
#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin)))
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
#define IO_REG_TYPE uint8_t
#define IO_REG_ASM asm("r30")
*/

IO_REG_TYPE bitmask;
volatile IO_REG_TYPE *baseReg;

void pinConfigOneWireLib(const uint8_t pin)
{
pinMode(pin, OUTPUT); // why output? not ok for 1Wire
bitmask = PIN_TO_BITMASK(pin);
baseReg = PIN_TO_BASEREG(pin);
}


void pinTestOneWireLib(void)
{
IO_REG_TYPE mask = bitmask; // note: why? it is already done, why not const
volatile IO_REG_TYPE *reg IO_REG_ASM = baseReg; // TODO: really needed as a copy? why volatile

// call
noInterrupts(); // note: why needed? it does not need to be atomic, only with pin-changing interrupts
DIRECT_WRITE_LOW(reg, mask);
DIRECT_MODE_OUTPUT(reg, mask); // drive output low
interrupts();

while(1)
{
DIRECT_WRITE_HIGH(reg, mask);
DIRECT_WRITE_LOW(reg, mask);
};
};

////////////////////////////////////////////////////////////////////////////////

using io_reg_t = uint8_t; // define special datatype for register-access

io_reg_t pin_bitMask;
volatile io_reg_t *pin_baseReg; // needs to be volatile, because its only written but never read, so it gets optimized out

void pinConfigClean(const uint8_t pin)
{
pinMode(pin, INPUT); // as a OW-slave we should mostly listen
// setup direct pin-access
pin_bitMask = PIN_TO_BITMASK(pin);
pin_baseReg = PIN_TO_BASEREG(pin);
};

void pinTestClean(void)
{
DIRECT_WRITE_LOW(pin_baseReg, pin_bitMask);
DIRECT_MODE_OUTPUT(pin_baseReg, pin_bitMask); // put it low, so it always reads zero

while(1)
{
DIRECT_WRITE_HIGH(pin_baseReg, pin_bitMask);
DIRECT_WRITE_LOW(pin_baseReg, pin_bitMask);
};
};


void setup()
{
const uint8_t pin_test = 8;

// measurement with oszi --> each of this work with an atmega328p, 16MHz Clock bring 571 kHz pinFreq for case 1-3, double for case 4
switch(3)
{
case 0:
case 1:
pinConfigLegacy(pin_test);
pinTestLegacy();
break;

case 2:
pinConfigOneWireLib(pin_test);
pinTestOneWireLib();
break;

case 3:
pinConfigClean(pin_test);
pinTestClean();
break;

case 4: // brings 1310 kHz
pinConfigClean(pin_test);
noInterrupts();
pinTestClean();
break;
};
};

void loop()
{

}
51 changes: 18 additions & 33 deletions src/OneWireHub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ OneWireHub::OneWireHub(uint8_t pin)
{
_error = Error::NO_ERROR;

pin_bitMask = PIN_TO_BITMASK(pin);
pin_bitMask = PIN_TO_BITMASK(pin);
pin_baseReg = PIN_TO_BASEREG(pin);

extend_timeslot_detection = 0;
Expand All @@ -19,8 +19,7 @@ OneWireHub::OneWireHub(uint8_t pin)
slave_list[i] = nullptr;

// prepare pin
volatile uint8_t *reg asm("r30") = pin_baseReg;
DIRECT_MODE_INPUT(reg, pin_bitMask);
DIRECT_MODE_INPUT(pin_baseReg, pin_bitMask);

// debug:
#if USE_GPIO_DEBUG
Expand Down Expand Up @@ -251,11 +250,7 @@ bool OneWireHub::poll(void)

bool OneWireHub::checkReset(uint16_t timeout_us) // there is a specific high-time needed before a reset may occur --> >120us
{
volatile uint8_t *reg asm("r30") = pin_baseReg;

noInterrupts();
DIRECT_MODE_INPUT(reg, pin_bitMask);
interrupts();
DIRECT_MODE_INPUT(pin_baseReg, pin_bitMask);

wait(ONEWIRE_TIME_BUS_CHANGE_MAX); // let the input settle

Expand All @@ -270,7 +265,7 @@ bool OneWireHub::checkReset(uint16_t timeout_us) // there is a specific high-tim
}
}

if (!DIRECT_READ(reg, pin_bitMask)) return false; // just leave if pin is Low, don't bother to wait
if (!DIRECT_READ(pin_baseReg, pin_bitMask)) return false; // just leave if pin is Low, don't bother to wait

// wait for the bus to become low (master-controlled), since we are polling we don't know for how long it was zero
if (!waitWhilePinIs(1, timeout_us))
Expand Down Expand Up @@ -303,22 +298,16 @@ bool OneWireHub::checkReset(uint16_t timeout_us) // there is a specific high-tim

bool OneWireHub::showPresence(void)
{
volatile uint8_t *reg asm("r30") = pin_baseReg;

// Master will delay it's "Presence" check (bus-read) after the reset
waitWhilePinIs( 1, ONEWIRE_TIME_PRESENCE_SAMPLE_MIN); // no pinCheck demanded, but this additional check can cut waitTime

// pull the bus low and hold it some time
noInterrupts();
DIRECT_WRITE_LOW(reg, pin_bitMask);
DIRECT_MODE_OUTPUT(reg, pin_bitMask); // drive output low
interrupts();
DIRECT_WRITE_LOW(pin_baseReg, pin_bitMask);
DIRECT_MODE_OUTPUT(pin_baseReg, pin_bitMask); // drive output low

wait(ONEWIRE_TIME_PRESENCE_LOW_STD);

noInterrupts();
DIRECT_MODE_INPUT(reg, pin_bitMask); // allow it to float
interrupts();
DIRECT_MODE_INPUT(pin_baseReg, pin_bitMask); // allow it to float

// When the master or other slaves release the bus within a given time everything is fine
if (!waitWhilePinIs( 0, (ONEWIRE_TIME_PRESENCE_LOW_MAX - ONEWIRE_TIME_PRESENCE_LOW_STD)))
Expand Down Expand Up @@ -573,8 +562,7 @@ bool OneWireHub::sendBit(const bool value)
{
// if we wait for release we could detect faulty writing slots --> pedantic Mode not needed for now
wait(ONEWIRE_TIME_WRITE_ZERO_LOW_STD);
volatile uint8_t *reg asm("r30") = pin_baseReg;
DIRECT_MODE_INPUT(reg, pin_bitMask);
DIRECT_MODE_INPUT(pin_baseReg, pin_bitMask);
}

return true;
Expand Down Expand Up @@ -658,10 +646,9 @@ bool OneWireHub::recvBit(void)
}

waitWhilePinIs( 0, ONEWIRE_TIME_READ_STD); // no pinCheck demanded, but this additional check can cut waitTime
volatile uint8_t *reg asm("r30") = pin_baseReg;
DIRECT_MODE_INPUT(reg, pin_bitMask);
DIRECT_MODE_INPUT(pin_baseReg, pin_bitMask);

return DIRECT_READ(reg, pin_bitMask);
return DIRECT_READ(pin_baseReg, pin_bitMask);
}

#define USE_DELAY 1
Expand All @@ -683,18 +670,17 @@ void OneWireHub::wait(const uint16_t timeout_us)
// returns true if pins stays in the wanted state all the time
bool OneWireHub::waitWhilePinIs(const bool value, const uint16_t timeout_us)
{
volatile uint8_t *reg asm("r30") = pin_baseReg;
if (DIRECT_READ(reg, pin_bitMask) != value) return true; // shortcut
if (DIRECT_READ(pin_baseReg, pin_bitMask) != value) return true; // shortcut

#if USE_MICROS
uint32_t time_trigger = micros() + timeout_us;
while (DIRECT_READ(reg, pin_bitMask) == value)
while (DIRECT_READ(pin_baseReg, pin_bitMask) == value)
{
if (micros() >= time_trigger) return false;
}
#else
uint16_t retries = static_cast<uint16_t>(microsecondsToClockCycles(timeout_us)/11);
while (DIRECT_READ(reg, pin_bitMask) == value)
while (DIRECT_READ(pin_baseReg, pin_bitMask) == value)
{
if (--retries == 0) return false;
}
Expand Down Expand Up @@ -747,14 +733,13 @@ bool OneWireHub::awaitTimeSlotAndWrite(void)
#define TIMESLOT_WAIT_RETRY_COUNT static_cast<uint16_t>(microsecondsToClockCycles(135)/8) /// :11 is a specif value for 8bit-atmega, still to determine
bool OneWireHub::awaitTimeSlotAndWrite(const bool writeZero)
{
volatile uint8_t *reg asm("r30") = pin_baseReg;
noInterrupts();
DIRECT_WRITE_LOW(reg, pin_bitMask);
DIRECT_MODE_INPUT(reg, pin_bitMask);
DIRECT_WRITE_LOW(pin_baseReg, pin_bitMask);
DIRECT_MODE_INPUT(pin_baseReg, pin_bitMask);

//While bus is low, retry until HIGH
uint16_t retries = TIMESLOT_WAIT_RETRY_COUNT;
while (!DIRECT_READ(reg, pin_bitMask))
while (!DIRECT_READ(pin_baseReg, pin_bitMask))
{
if (--retries == 0)
{
Expand Down Expand Up @@ -786,7 +771,7 @@ bool OneWireHub::awaitTimeSlotAndWrite(const bool writeZero)
};

//Wait for bus to fall form 1 to 0
while (DIRECT_READ(reg, pin_bitMask))
while (DIRECT_READ(pin_baseReg, pin_bitMask))
{
if (--retries == 0)
{
Expand All @@ -801,7 +786,7 @@ bool OneWireHub::awaitTimeSlotAndWrite(const bool writeZero)
if (writeZero)
{
// Low is allready set
DIRECT_MODE_OUTPUT(reg, pin_bitMask);
DIRECT_MODE_OUTPUT(pin_baseReg, pin_bitMask);
};

interrupts();
Expand Down

0 comments on commit 5a83935

Please sign in to comment.