MCP23S17 on ESP8266

Hi guy

Im looking for an explanation in something that has me stumped.

I currently have a MCP23S17 hooked up to the the ESP8266. I use the following library to access the the expander chip: GitHub - n0mjs710/MCP23S17: Arduino Driver for Microchip MCP23S17

So, I hooked up a button with a couple LED's and all works well, except that when the button is high (pushed), I get a reading of 3855 and when its set to low, I get a reading 2831.

3855 - 2831 = 1024 , which works out 2^10.

What I don't understand ... where does the 3855, 2831 values come from? Just doesn't make sense to me!

#include <SPI.h>
#include "Mcp23s17.h"

#define MCP23S17_SLAVE_SELECT_PIN  15 
MCP23S17 Mcp23s17 = MCP23S17( MCP23S17_SLAVE_SELECT_PIN );

void setup()
{
  
  Serial.begin(115200);
  Mcp23s17.pinMode(OUTPUT);
  Mcp23s17.port(0x0F0F);

    Mcp23s17.pinMode(8,OUTPUT);
    Mcp23s17.pinMode(9,OUTPUT);
    Mcp23s17.pinMode(10,INPUT);
    
    Mcp23s17.digitalWrite(8, HIGH);
    delay(100);
    Mcp23s17.digitalWrite(9, HIGH);
}

void loop()
{

   int vin = Mcp23s17.digitalRead(10);
   Serial.print("Voltage - ");
   Serial.println(vin);
   delay(200);
}

What makes you think that a digital reading pin 10 of the expander some how is measuring a voltage?

You set the port to = 0x0F0F = 3855 then if you toggle bit 10 by setting it to an input to get 2831? I'm guessing that the library is returning the integer value of the entire word when you do your digital read instead of returning a boolean because you specified the variable as an integer.

Grumpy_Mike:
What makes you think that a digital reading pin 10 of the expander some how is measuring a voltage?

I was expecting a 0 or 1 or even 0 or 1024. At the end of day, aren't you measuring voltage essentially?

I think I found the problem.

In the library, the digitalRead doesn't have a return statement.

int MCP23S17::digitalRead(uint8_t pin)
{
(int)(read_addr(GPIO) & 1<<pin);
}

I added it in, now I get the desired result. When the button is not pushed I get 0. When it is activated, I get 1024

When the button is not pushed I get 0. When it is activated, I get 1024

So it looks like that is returning the whole 16 bits, with bit 10 being set. If you add more buttons you will get other numbers. To get just the bit you are after you have to mask it. That is the problem with librarys, they are seldom documented sufficiently.

jakespotgieter:
At the end of day, aren't you measuring voltage essentially?

No you are not, you are detecting if the voltage input is above or below a specific threshold, that is not the same as measuring he voltage.

Grumpy_Mike:
So it looks like that is returning the whole 16 bits, with bit 10 being set. If you add more buttons you will get other numbers. To get just the bit you are after you have to mask it. That is the problem with librarys, they are seldom documented sufficiently.
No you are not, you are detecting if the voltage input is above or below a specific threshold, that is not the same as measuring he voltage.

Thanks for that explanation Mike. That does make sense what you saying. I will definitely test that to confirm.

I am new to this, and that is one of the problems that I'm finding with a lot of libraries out there. They only take you so far until you run into a problem.

Yes I think there is too much dependence on libraries with Arduinos. They are great for simplifying things but they hide too much and stop you learning so that when you need to do something not covered in a library then you hit a brick wall.
It would be better if you did this

int MCP23S17::digitalRead(uint8_t pin)
{
  if((read_addr(GPIO) & (1<<pin) ) == 0){
  return 0;
}
else {
return 1;
   }
}
int MCP23S17::digitalRead(uint8_t pin)
{
  return bitRead(read_addr(GPIO), pin);
}

Problem with all these solutions, including the above, is that if you want to read each button in turn, it will communicate over the i2c bus for each button, when only one communication was needed. Better to read all 16 pins into a variable, then use bitRead() or bit masking on the variable to read each button.

Grumpy_Mike:
No you are not, you are detecting if the voltage input is above or below a specific threshold, that is not the same as measuring he voltage.

Apologies for my ignorance, but I'm still lost with the above.

In the ADC, because we working with a 10 bit chip in arduino world, we get the following

2^10 = 1024
1024 / 5v = .0049 volts or 4.9 mV

so each unit of the 1024 ADC value is 4.9mv

But obviously in the world of digital, we only have 1's and 0's. So does that not mean that the threshold is directly related to the voltage that is applied i.e.

1024 / 2 = 512 (512 X 0.0049v = 2.5088v) which means, any value below 512 (>=2.5088v) = 0 or above 512(<=2.5088v) is 1

Do you know of a article that I could read up that could explain this to me. Don't want to waste your time with trivial stuff :slight_smile:

I have also deviated from this thread some what!

PaulRB:

int MCP23S17::digitalRead(uint8_t pin)

{
  return bitRead(read_addr(GPIO), pin);
}




Problem with all these solutions, including the above, is that if you want to read each button in turn, it will communicate over the i2c bus for each button, when only one communication was needed. Better to read all 16 pins into a variable, then use bitRead() or bit masking on the variable to read each button.

I like that idea. Sounds a lot more efficient than cycling through each one at a time.

jakespotgieter:
In the ADC, because we working with a 10 bit chip in arduino world, we get the following

2^10 = 1024
1024 / 5v = .0049 volts or 4.9 mV

so each unit of the 1024 ADC value is 4.9mv

But obviously in the world of digital, we only have 1's and 0's. So does that not mean that the threshold is directly related to the voltage that is applied i.e.

1024 / 2 = 512 (512 X 0.0049v = 2.5088v) which means, any value below 512 (>=2.5088v) = 0 or above 512(<=2.5088v) is 1

That is all irrelevant. The MCP32S17 is not an ADC. It has 16 digital inputs. On any one of those inputs, any voltage below about 1/3 of the supply voltage will be read as LOW or 0. Any voltage above 2/3 of the supply voltage will be read as HIGH or 1. Any voltage between 1/3 and 2/3 won't be read reliably.

The number you are reading back from the chip is not the result of an ADC conversion of an analog voltage, it is simply the result of 16 digital inputs packed into a word. If you are seeing random variations, it is because some of those digital inputs are floating and not giving a reliable reading.

But obviously in the world of digital, we only have 1's and 0's. So does that not mean that the threshold is directly related to the voltage that is applied i.e.

No. For a digital pin anything below 0.7V is a zero and everything above 3V is a one for a 5V system. These voltages change somewhat with the technology like cmos TTL and so on. Note there is a region of voltages that are not defined and so are not guarantee to return any specific level, but will always read as a zero or a one.

I am not sure what you don't understand about this. I am not sure where you think an A/D applies to this chip.

24 / 2 = 512 (512 X 0.0049v = 2.5088v) which means, any value below 512 (>=2.5088v) = 0 or above 512(<=2.5088v) is 1

Sorry but this is just nonsense.

PaulRB:
That is all irrelevant. The MCP32S17 is not an ADC. It has 16 digital inputs. On any one of those inputs, any voltage below about 1/3 of the supply voltage will be read as LOW or 0. Any voltage above 2/3 of the supply voltage will be read as HIGH or 1. Any voltage between 1/3 and 2/3 won't be read reliably.

The number you are reading back from the chip is not the result of an ADC conversion of an analog voltage, it is simply the result of 16 digital inputs packed into a word. If you are seeing random variations, it is because some of those digital inputs are floating and not giving a reliable reading.

I know the MCP32S17 is not an ADC, but I thought it might work with a similar concept. Clearly, I was mistaken.

I think that is where I was getting confused was with the random variations.

Grumpy_Mike:
No. For a digital pin anything below 0.7V is a zero and everything above 3V is a one for a 5V system. These voltages change somewhat with the technology like cmos TTL and so on. Note there is a region of voltages that are not defined and so are not guarantee to return any specific level, but will always read as a zero or a one.

I am not sure what you don't understand about this. I am not sure where you think an A/D applies to this chip.
Sorry but this is just nonsense.

What i was trying to get at... I thought the "theory" worked on a similar concept to a ADC. I was trying to determine when it would be a 0 or 1.

But your first paragraph explains it nicely.

Thanks for the help, Grumpy Mike! :smiley: