SmingHub / Sming

Sming - powerful open source framework simplifying the creation of embedded C++ applications.
https://sming.readthedocs.io
GNU Lesser General Public License v3.0
1.48k stars 347 forks source link

OneWire library x-pin impact #50

Closed ToSa27 closed 9 years ago

ToSa27 commented 9 years ago

The OneWire library impacts pins other than the one pin selected. Easy to reproduce on an ESP-12:

The LED at GPIO4 turns on when the OneWire library searches for devices and then turns off again.

ToSa27 commented 9 years ago

Removing the fast pin access via register/mask and instead using the slow pinMode/digitalRead/digitalWrite functions seems to be a work-around (definitely not a good solution though). The easiest way to test that is to comment the block of defines in OneWire.h:

/*
#elif defined(__ESP8266_EX__)
#define PIN_TO_BASEREG(pin)             (portOutputRegister(digitalPinToPort(pin)))
#define PIN_TO_BITMASK(pin)             (digitalPinToBitMask(pin))
#define IO_REG_TYPE uint8_t
#define IO_REG_ASM
#define DIRECT_READ(base, mask)         (((*((base)+GPIO_IN_ADDRESS)) & (mask)) ? 1 : 0)
#define DIRECT_MODE_INPUT(base, mask)   ((*((base)+GPIO_ENABLE_ADDRESS)) &= ~(mask))
#define DIRECT_MODE_OUTPUT(base, mask)  ((*((base)+GPIO_ENABLE_ADDRESS)) |= (mask))
#define DIRECT_WRITE_LOW(base, mask)    ((*(base)) &= ~(mask))
#define DIRECT_WRITE_HIGH(base, mask)   ((*(base)) |= (mask))
*/
#else
#define PIN_TO_BASEREG(pin)             NULL
#define PIN_TO_BITMASK(pin)             (pin)
#define IO_REG_TYPE                     uint16_t
#define IO_REG_ASM
#define DIRECT_READ(base, mask)         ((digitalRead(mask) > 0) ? 1 : 0)
#define DIRECT_MODE_INPUT(base, mask)   (pinMode(mask, INPUT))
#define DIRECT_MODE_OUTPUT(base, mask)  (pinMode(mask, OUTPUT))
#define DIRECT_WRITE_LOW(base, mask)    (digitalWrite(mask, LOW))
#define DIRECT_WRITE_HIGH(base, mask)   (digitalWrite(mask, HIGH))
#endif
anakod commented 9 years ago

Hello. Thank you. Can you reproduce this with direct pin switching code (portOutputRegister, digitalPinToBitMask) without using additional libraries?

ToSa27 commented 9 years ago

I'll give that a try and report back.

Separate question: did you define ARDUINO somewhere? It appears that all code blocks like this:

#if ARDUINO >= 100
   ... do something ...
#else
   ... do something else ...
#endif

actually end up proceeding the second block because ARDUINO is not defined at all. Is that by purpose - you might end up using code that is just kept for compatibility with very old arduino core versions?

ToSa27 commented 9 years ago

It is reproducible with the code below not using any library. The defines are copied from OneWire.h though and I would guess these defines are part of the problem...

[code]

include

include <SmingCore/SmingCore.h>

define PIN_TO_BASEREG(pin) (portOutputRegister(digitalPinToPort(pin)))

define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))

define IO_REG_TYPE uint8_t

define IO_REG_ASM

define DIRECTREAD(base, mask) (((((base)+GPIO_IN_ADDRESS)) & (mask)) ? 1 : 0)

define DIRECT_MODEINPUT(base, mask) ((((base)+GPIO_ENABLE_ADDRESS)) &= ~(mask))

define DIRECT_MODEOUTPUT(base, mask) ((((base)+GPIO_ENABLE_ADDRESS)) |= (mask))

define DIRECT_WRITELOW(base, mask) (((base)) &= ~(mask))

define DIRECT_WRITE_HIGH(base, mask) ((*(base)) |= (mask))

define WORK_PIN 12 // GPIO0

IO_REG_TYPE bitmask; volatile IO_REG_TYPE *baseReg;

void init() { Serial.begin(SERIAL_BAUD_RATE); Serial.systemDebugOutput(true);

bitmask = PIN_TO_BITMASK(WORK_PIN);
baseReg = PIN_TO_BASEREG(WORK_PIN);

Serial.println("DIRECT_MODE_OUTPUT");
DIRECT_MODE_OUTPUT(baseReg, bitmask);
Serial.println("DIRECT_MODE_OUTPUT done");
delay(5000);

Serial.println("DIRECT_WRITE_HIGH");
DIRECT_WRITE_HIGH(baseReg, bitmask);                // <== here GPIO4 goes high (even if pin is 12)
Serial.println("DIRECT_WRITE_HIGH done");
delay(5000);

} [/code]

ToSa27 commented 9 years ago

It is for sure the logic in SmingCore\pins_arduino.h that causes the issues and need to be adjusted. For example:

#define digitalPinToPort(P) ( P < 0 ? NOT_A_PIN : ( (int)P < 8 ? PA : ( (int)P < 16 ? PB : ( (int)P == 16 ? PC : NOT_A_PIN ) ) ) )
#define digitalPinToBitMask(P) ( (int)P < 8 ? _BV((int)P) : ( P < 16 ? _BV( (int)P-8 ) : 1) )

#define STD_GPIO_OUT (PERIPHS_GPIO_BASEADDR + GPIO_OUT_ADDRESS)
#define STD_GPIO_IN (PERIPHS_GPIO_BASEADDR + GPIO_IN_ADDRESS)
#define STD_GPIO_ENABLE (PERIPHS_GPIO_BASEADDR + GPIO_ENABLE_ADDRESS)

#define portOutputRegister(P) ( ((volatile uint8_t*)(P != PC ? STD_GPIO_OUT : RTC_GPIO_OUT)) + ( ( ((int)P) == PB ) ? 1 : 0) )
#define portInputRegister(P)  ( ((volatile uint8_t*)(P != PC ? STD_GPIO_IN : RTC_GPIO_IN_DATA)) + ( ( ((int)P) == PB ) ? 1 : 0) )
#define portModeRegister(P)   ( ((volatile uint8_t*)(P != PC ? STD_GPIO_ENABLE : RTC_GPIO_ENABLE)) + ( ( ((int)P) == PB ) ? 1 : 0) ) // Stored bits: 0=In, 1=Out

the ESP8266 gpio registers are 16 bit wide - GPIO0...GPIO15 all covered within one register (see ESP8266 wiki).

I guess it's all working fine for pin 0..7 but starts causing issues for 8.. Just a few libraries actually use these functions which is probably why it wasn't reported earlier.

hreintke commented 9 years ago

This issue has been inactive for a long period and is being closed. If the issue is still valid please open a new with complete description