Closed supersjimmie closed 8 years ago
E.g. would something like this be possible? Micropython esp8266: Allow GPIO16 to be used as a pin in the uPy pin HAL. https://github.com/micropython/micropython/commit/67a6d31955cb7ff8985f9f96675a70870eea4089
Pin 16 doesn't have an interrupt associated with it, so any function which uses interrupts will not work with this pin. I2C doesn't use interrupts, and some DHT libraries also don't use interrupts. I would say that using pin 16 for I2C is a pretty safe choice.
Thanks @igrr but afaik I have read that I2C does not work on gpio16 at this moment?
I have tried DHT, in the DHT library is a line pinMode(_pin, INPUT_PULLUP);
, which is not compatlble with gpio16. But even when I change it to only INPUT or INPUT_PULLDOWN_16 and use a stronger pull up resistor there are no readings. (perhaps that pulldown part is the main limitation for most usage?
With onewire on gpio16 (and not the pullup flag used) it should work but again no readings. (maybe that same hardware limitation?)
I want to add that it is certainly possible to share pins between busses. I have SPI and I2C share one pin. I use SPI_CLK as I2C_SDA. this was the combination that worked best for me. there are some discussions on the intertubes about sharing even more pins, but I couldn't get that to work.
@everslick what pins are you using exactly for SPI and for I2C? And did you need to modify the libraries or just the begin(scl,sda) for I2C?
My SPI attached device will be a very time-sensitive (cc1101 radio rx/tx) module so I think that any interference will cause trouble. So I would really like to know what gpio16 can be used for to keep all clearly separated.
// RTC pins
// SPI pins
i switch gpio configuration before and after i2c transmissions:
static void start_transmission(void) { pinMode(GPIO_SDA, INPUT_PULLUP); }
static void end_transmission(void) { pinMode(GPIO_SDA, OUTPUT); }
so i had to modify (read: copy and modify the i2c lib) like this:
#define SDA_LOW() (GPES = (1 << GPIO_SDA))
#define SDA_HIGH() (GPEC = (1 << GPIO_SDA))
#define SDA_READ() ((GPI & (1 << GPIO_SDA)) != 0)
#define SCL_LOW() (GPES = (1 << GPIO_SCL))
#define SCL_HIGH() (GPEC = (1 << GPIO_SCL))
#define SCL_READ() ((GPI & (1 << GPIO_SCL)) != 0)
#ifndef FCPU80
#define FCPU80 80000000L
#endif
#if F_CPU == FCPU80
#define I2C_CLOCK_STRETCH_MULTIPLIER 3
#else
#define I2C_CLOCK_STRETCH_MULTIPLIER 6
#endif
static uint32_t stretch_limit = 230 * I2C_CLOCK_STRETCH_MULTIPLIER;
static uint8_t delay_count = 19;
static void start_transmission(void) {
pinMode(GPIO_SDA, INPUT_PULLUP);
}
static void end_transmission(void) {
pinMode(GPIO_SDA, OUTPUT);
}
static void i2c_delay(uint8_t v) {
volatile uint32_t reg;
for (int i=0; i<v; i++) reg = GPI;
}
static bool write_start(void) {
SCL_HIGH();
SDA_HIGH();
if (SDA_READ() == 0) return (false);
i2c_delay(delay_count);
SDA_LOW();
i2c_delay(delay_count);
return (true);
}
static bool write_stop(void){
uint32_t i = 0;
SCL_LOW();
SDA_LOW();
i2c_delay(delay_count);
SCL_HIGH();
while (SCL_READ() == 0 && (i++) < stretch_limit); // clock stretching
i2c_delay(delay_count);
SDA_HIGH();
i2c_delay(delay_count);
return (true);
}
static bool write_bit(bool bit) {
uint32_t i = 0;
SCL_LOW();
if (bit) SDA_HIGH(); else SDA_LOW();
i2c_delay(delay_count+1);
SCL_HIGH();
while (SCL_READ() == 0 && (i++) < stretch_limit); // clock stretching
i2c_delay(delay_count);
return (true);
}
static bool read_bit(void) {
uint32_t i = 0;
SCL_LOW();
SDA_HIGH();
i2c_delay(delay_count+2);
SCL_HIGH();
while (SCL_READ() == 0 && (i++) < stretch_limit); // Clock stretching
bool bit = SDA_READ();
i2c_delay(delay_count);
return (bit);
}
static bool write_byte(uint8_t byte) {
uint8_t bit;
for (bit = 0; bit < 8; bit++) {
write_bit(byte & 0x80);
byte <<= 1;
}
return (!read_bit()); // NACK/ACK
}
static uint8_t read_byte(bool nack) {
uint8_t byte = 0;
uint8_t bit;
for (bit=0; bit<8; bit++) byte = (byte << 1) | read_bit();
write_bit(nack);
return (byte);
}
bool i2c_init(void) {
return (true);
}
uint8_t i2c_write(uint8_t addr, uint8_t *buf, uint32_t len, bool stop) {
uint32_t i;
start_transmission();
if (!write_start()) {
end_transmission();
return (4); // line busy
}
if (!write_byte(((addr << 1) | 0) & 0xFF)) {
if (stop) write_stop();
end_transmission();
return (2); // received NACK on transmit of addr
}
for (i=0; i<len; i++) {
if (!write_byte(buf[i])) {
if (stop) write_stop();
end_transmission();
return (3); // received NACK on transmit of data
}
}
if (stop) write_stop();
i = 0;
while (SDA_READ() == 0 && (i++) < 10){
SCL_LOW();
i2c_delay(delay_count);
SCL_HIGH();
i2c_delay(delay_count);
}
end_transmission();
return (0);
}
int8_t i2c_read(uint8_t addr, uint8_t *buf, uint32_t len, bool stop) {
uint32_t i;
start_transmission();
if (!write_start()) {
end_transmission();
return (4); // line busy
}
if (!write_byte(((addr << 1) | 1) & 0xFF)) {
if (stop) write_stop();
end_transmission();
return (2); // received NACK on transmit of addr
}
for (i=0; i<(len-1); i++) buf[i] = read_byte(false);
buf[len-1] = read_byte(true); // last bit is NACK
if (stop) write_stop();
i = 0;
while (SDA_READ() == 0 && (i++) < 10) {
SCL_LOW();
i2c_delay(delay_count);
SCL_HIGH();
i2c_delay(delay_count);
}
end_transmission();
return (0);
}
uint8_t i2c_status(void) {
int clock_count = 20;
start_transmission();
// SCL held low by another device, no procedure available to recover
if (SCL_READ() == 0) {
end_transmission();
return (I2C_SCL_HELD_LOW);
}
// if SDA low, read the bits slaves have to sent to a max
while ((SDA_READ() == 0) && (clock_count > 0)) {
read_bit();
// I2C bus error. SCL held low beyond slave clock stretch time
if (SCL_READ() == 0) {
end_transmission();
return (I2C_SCL_HELD_LOW_AFTER_READ);
}
}
// I2C bus error. SDA line held low by slave/another_master after n bits.
if (SDA_READ() == 0) {
end_transmission();
return (I2C_SDA_HELD_LOW);
}
// line busy. SDA again held low by another device. 2nd master?
if (!write_start()) {
end_transmission();
return (I2C_SDA_HELD_LOW_AFTER_INIT);
}
end_transmission();
return (I2C_OK);
}
Thanks @everslick but "switch gpio configuration before and after i2c transmissions" may cause more trouble for me because I need both constantly. SPI is constantly receiving and random sending, while I would like to connect at least 2 new sensors plus an lcd display to I2C.
So still love to hear what I can do with GPIO16.
Do you need to log to the original serial port? If you can add a telnet service to your application and send your log/debug info to port 23 you could free up the HW RX/TX pins for something else. Or switch to an i2c temperature/humidity sensor instead of the DHT and free up GPIO3.
@jeffryr If I want to use the hw tx/rx, I have to disconnect anything from that pins before I can upload a newer code. And since I am nearly constantly renewing now, that's not so handy. (and yes I am logging a lot and I dont want another computer always on for logging over telnet)
@jeffryr https://github.com/jeffryr If I want to use the hw tx/rx, I have to disconnect anything from that pins before I can upload a newer code. And since I am nearly constantly renewing now, that's not so handy.
not necessarily, depends on what you use the pins for additionally to serial. also updating with OTA is much more convenient anyway. i do it 99% of the time, only if i manage to brick the device by uploading a defective firmware (read OTA stops working), i reconnect USB.
(and yes I am logging a lot and I dont want another computer always on for logging over telnet)
but you already have it running, otherwise were is the serial port connected to? besides that, i recommend to log using UDP not telnet (which is TCP). to me supersjimmie's suggestions are sensible.
not necessarily, depends on what you use the pins for additionally to serial. also updating with OTA is much more convenient anyway.
Good idea @everslick , will do some testing if perhaps 1-wire or DHT can be physically connected to the same pin as Serial RX (GPIO 3?) while still being able to upload new sketches. While the code runs, I don't need RX (only TX for logging) so the only possible problem is electrical interference when uploading a new sketch. Updating over OTA caused a lot of trouble the last time I tried (because my code is also doing a lot of networking, I guess). Will try that again too.
I moved ds18b20's (1-wire) to 'reserved' gpio10 and dht seems to work when sharing Hardware Serial RX. This just cleared enough for me.
I have tried DHT, in the DHT library is a line
pinMode(_pin, INPUT_PULLUP);
, which is not compatlble with gpio16. But even when I change it to only INPUT or INPUT_PULLDOWN_16 and use a stronger pull up resistor there are no readings. (perhaps that pulldown part is the main limitation for most usage?
Just for the record, I'm having the same issue: tried the DHT library (Adafruit version 1.4.0) with ESP8266 (ESP-12F on a DOITING board) using Arduino (v1.8.13 esp8266 v.1.0.4) and GPIO16 (labeled as D0 on the board) is a no-go; all other pins that are supposed to work (GPIO5/D1, GPIO4/D2, GPIO14/D5, GPIO12/D6, GPIO13/D7do in fact work, but GPIO16/D0 won't work in any way.
So, is it safe to assume D0 is a dead pin for DHT usage?
dht seems to work when sharing Hardware Serial RX.
PS: DHT also worked for me on GPIO15/D8 aka "Hardware Serial RX", but it must be disconnected to be able to flash (ie, upload a program) to the ESP8266.
Basic Infos
While there are physically enough pins their limitations cause my problem.
Hardware
Hardware: NodeMCU v2 Core Version: 2.2.0 / 2.3.0
Description
I am running out of free pins because I want to use SPI, I2C, onewire, DHT and softwareserial on one NodeMCU:
Problem description My free GPIO's are 6, 7, 8, 9 and 16. Even in DIO mode, GPIO 6-9 are not usable, the module crashes when I try to use them. (hardware mod is not an option for me) Since softwareserial on GPIO0 (D3 pin) causes boot problems, I need to move it to another pin, or I need to free another pin so I can then move softwareserial to that pin. So I guess I need to put something on GPIO16 (D0 pin).
Settings in IDE
Module: NodeMCU 1.0 (ESP-12E Module) Flash Mode: dio Upload Using: SERIAL
My question is, does anyone know how to put either of those in GPIO16: dht, softwareserial, i2c, spi?