Can I register additional GPIO pins and provide my own handlers?

botguy
Posts: 4
Joined: Sat Aug 04, 2018 4:01 pm

Can I register additional GPIO pins and provide my own handlers?

Postby botguy » Sat Aug 04, 2018 4:18 pm

I'd like to use the MCP23S17 to add more GPIO pins to my ESP32. I've done this successfully with multiple MCP23S17 chips and it works fine if I'm directly accessing the pins in my own code.

However, if I want to use these pins in someone else's library (for example, setting S0, S1, S2, S3 for a color sensor), it doesn't work well because they expect a native GPIO pin as an argument in their method calls.

Is it possible to register custom GPIO pins that look and feel like a normal GPIO pin and create my own handler routines for turning bits on and off? Obviously these would only support INPUT and OUTPUT but not pullup and pulldown in my case.

I've searched and haven't had much luck, so if this is common knowledge and I'm just searching for the wrong terms, please point me in the right direction. I'm using the Arduino IDE, but I'm not adverse to something else if that is what it takes to make this work.

Thanks!! -Bill

User avatar
kolban
Posts: 1683
Joined: Mon Nov 16, 2015 4:43 pm
Location: Texas, USA

Re: Can I register additional GPIO pins and provide my own handlers?

Postby kolban » Mon Aug 06, 2018 4:00 am

Howdy Bill,
I'm going to say that the answer will likely be "no". If what I'm hearing you say is that you have black box code that we believe, inside, is making API calls to perform digitalRead() and digitalWrite() then these functions are hard-coded to leverage the ESP-IDF direct GPIO access functions. These functions have no knowledge of driving additional GPIO peripherals.

So how might we solve the puzzle. Let us assume that all your GPIOs are in use. You would now create two new C functions called digitalReadMCP23S17() and digitalWriteMCP23S17(). The implementation of these functions would know how to read and write your peripheral device. You would test these functions and have confidence that they work. Next, you would find the source of your 3rd party library and (carefully) replace the calls to the original digitalRead or digitalWrite with your new function calls.
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32
Available for ESP32 consulting.

botguy
Posts: 4
Joined: Sat Aug 04, 2018 4:01 pm

Re: Can I register additional GPIO pins and provide my own handlers?

Postby botguy » Wed Aug 08, 2018 12:34 am

Thanks for the reply. It is nice and clear on how to proceed. I believe I have the source for all of the libraries I'm using so I can do the method replace you describe. Being familiar with java, I was hoping I could override a method and route requests to my implementation or the default implementation. This way when I update libraries from other sources, I don't have to customize them again.

After posting my question, I did stumble across a way to do what I described (https://arduino.stackexchange.com/questions/23439/is-there-a-way-to-replace-an-arduino-core-function-without-modifying-the-arduino), but it involves creating C:\arduino-1.8.5\hardware\arduino\avr\platform.local.txt with a special flag for the linker ("compiler.c.elf.extra_flags=-Wl,--wrap=digitalWrite"). Unfortunately, now every other sketch on my computer expects that method to be overridden as well and I can't make the change specific to one sketch.

Ultimately, I was trying to keep PWM output on native pins and interrupts (frequency counters and encoders) on naive pins then push everything else to the extended MCP23S17 pins. All of the chip select pins for my SPI hardware seem like good candidates for pushing off-chip.

I'll try your method with my software SPI library and see how it goes.

Bill

User avatar
kolban
Posts: 1683
Joined: Mon Nov 16, 2015 4:43 pm
Location: Texas, USA

Re: Can I register additional GPIO pins and provide my own handlers?

Postby kolban » Wed Aug 08, 2018 4:54 am

Howdy Bill,
Thinking about your last post, what you suggest would in fact be a perfectly allowable solution. If we look here:

https://github.com/espressif/arduino-es ... pio.c#L172

We see the implementation of digitalWrite() as being a relatively straight map to ESP32 low level GPIO. There is nothing to prevent you from taking a copy of this source file and augmenting it with your own logic to control "additional" pins.

I'm also reading later in the code the following statement:

extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite")));

we'd have to study this some more, but the last time I came across associating a function as "weak" what that meant (to me) is that the local implementation (digitalWrite) would be resolved (used) only if there wasn't another implementation of digitalWrite. If this is close to correct, then it might be that all you have to do is literally code your own digitalWrite() function in your own sketch and that will be invoked in preference to the weak definition supplied by the Arduino code base.
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32
Available for ESP32 consulting.

botguy
Posts: 4
Joined: Sat Aug 04, 2018 4:01 pm

Re: Can I register additional GPIO pins and provide my own handlers?

Postby botguy » Fri Aug 10, 2018 4:08 am

Nice find! This seems to work.
I still need to try it with external libraries, but it looks promising and all code changes can live within my project.

Thanks for the tip!
Bill


Code: Select all

extern void digitalWrite(uint8_t pin, uint8_t val)
{
    // This overwrites the built-in implementation of digitalWrite
   
    // As a proof-of-concept, override everything to pin 2 (blink pin)
    pin=2;
   
    digitalWriteOriginal(pin, val);
}

// official implementation of digitalWrite in esp32 source code as of 8/9/2018 from
// https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-gpio.c#L172
void digitalWriteOriginal(uint8_t pin, uint8_t val)
{
  if(val) {
      if(pin < 32) {
          GPIO.out_w1ts = ((uint32_t)1 << pin);
      } else if(pin < 34) {
          GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));
      }
  } else {
      if(pin < 32) {
          GPIO.out_w1tc = ((uint32_t)1 << pin);
      } else if(pin < 34) {
          GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32));
      }
  }
}

void setup() {
  // blink pin
  pinMode(2, OUTPUT);
}

void loop(void) {
  // use a random pin number
  // it will get overwritten as pin 2 (blink pin) in my custom digitalWrite method
  digitalWrite(64, HIGH);
  delay(1000);
  digitalWrite(64, LOW);
  delay(100);
}

User avatar
kolban
Posts: 1683
Joined: Mon Nov 16, 2015 4:43 pm
Location: Texas, USA

Re: Can I register additional GPIO pins and provide my own handlers?

Postby kolban » Fri Aug 10, 2018 2:49 pm

A caveat ... an area I am not familiar with ... but it dawns on me that there appears to be an "alias" to the "original" code of digitalWrite called "__digitalWrite". What that seems to say is that you could write your own digitalWrite and interecpt ... and then call "__digitalWrite()" to perform the original function if you don't handle yourself. This would then mean that you don't have to duplicate the Arduino logic in your own code.
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32
Available for ESP32 consulting.

botguy
Posts: 4
Joined: Sat Aug 04, 2018 4:01 pm

Re: Can I register additional GPIO pins and provide my own handlers?

Postby botguy » Sat Aug 11, 2018 5:07 am

You are correct. I tried this originally, but couldn't get it to work. After adding the 'extern' statements, now it works. Below is the updated code. This will still come in handy, but I should point out that I won't be able to use it for clip select (CS) with SPI like I suggested in an earlier post. Most of the code related to SPI (even Software SPI) writes directly to internal registers and doesn't use digitalWrite command.

Thanks again,
Bill

Code: Select all

extern "C" {
    void __digitalWrite(uint8_t, uint8_t);
}

void digitalWrite(uint8_t pin, uint8_t val)
{
    // This overwrites the built-in implementation of digitalWrite
   
    // As a proof-of-concept, override everything to pin 2 (blink pin)
    pin=2;
   
    // now call up to the native implementation of digitalWrite
    __digitalWrite(pin, val);
}

void setup() {
  // blink pin
  pinMode(2, OUTPUT);
}

void loop(void) {
  // use a random pin number
  // it will get overwritten as pin 2 (blink pin) in my custom digitalWrite method
  digitalWrite(64, HIGH);
  delay(1000);
  digitalWrite(64, LOW);
  delay(100);
}

Who is online

Users browsing this forum: ESP_morris and 17 guests