diff --git a/examples/OneWireHubTest/OneWireHubTest.ino b/examples/OneWireHubTest/OneWireHubTest.ino index 01de73f..aca68ac 100644 --- a/examples/OneWireHubTest/OneWireHubTest.ino +++ b/examples/OneWireHubTest/OneWireHubTest.ino @@ -29,7 +29,7 @@ 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 @@ -37,8 +37,8 @@ auto ds2413 = DS2413( 0x3A, 0x0D, 0x02, 0x04, 0x01, 0x03, 0x00 ); // Work - 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() { @@ -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"); } diff --git a/examples/debug/optimize_pinAccess/optimize_pinAccess.ino b/examples/debug/optimize_pinAccess/optimize_pinAccess.ino new file mode 100644 index 0000000..0617b8d --- /dev/null +++ b/examples/debug/optimize_pinAccess/optimize_pinAccess.ino @@ -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() +{ + +} diff --git a/src/OneWireHub.cpp b/src/OneWireHub.cpp index aaef59b..c51fdcd 100644 --- a/src/OneWireHub.cpp +++ b/src/OneWireHub.cpp @@ -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; @@ -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 @@ -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 @@ -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)) @@ -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))) @@ -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; @@ -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 @@ -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(microsecondsToClockCycles(timeout_us)/11); - while (DIRECT_READ(reg, pin_bitMask) == value) + while (DIRECT_READ(pin_baseReg, pin_bitMask) == value) { if (--retries == 0) return false; } @@ -747,14 +733,13 @@ bool OneWireHub::awaitTimeSlotAndWrite(void) #define TIMESLOT_WAIT_RETRY_COUNT static_cast(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) { @@ -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) { @@ -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();