Go Down

Topic: About generalizing digitalRead, digitalWrite and pinMode to extender IO (Read 668 times) previous topic - next topic

liudr

I am trying to run LCD and some inputs over I2C port extenders. I was a bit disappointed to find out that was not as easy as 1-2-3. So I was looking for solutions, so that I can run liquidcrystal library without any modification, unlike what fm did or adafruit. Here is what I came up with, which should make the Arduino software a lot more powerful:

The functions digitalRead, digitalWrite and pinMode are defined in wiring_digital.c and they never check if the pin number goes beyond maximum.
If I insert an if statement in all these functions to call another function in case the pin number is greater than a certain value, say 127, so the correct routine can be called to these extended pins without the liquidcrystal library or other libraries written to call these functions even know what goes on. This will easily extend liquidcrystal, keypad, all my pin_interfaces library classes. If we extend enough, we also cover PWM pins as analogWrite, analogRead with much higher accuracy with external chips. We can also couple DAC to analogWrite, all without any programs knowing that they are running on pins external to the ATMEGA chip. This is a great extension to what arduino is.

What do you think? Should Arduino team make some changes so these alternative pin access functions can be defined in the main arduino code?

Code: [Select]
wiring_digital.c
...
void alt_digitalWrite(uint8_t pin, uint8_t val);
void digitalWrite(uint8_t pin, uint8_t val)
{
  if (pin>127) alt_digitalWrite(pin,val);
  else {//do original digitalWrite}
}


Code: [Select]
main .ino
void setup()
{
}

void loop()
{
}

void alt_digitalWrite(uint8_t pin, uint8_t val)
{
//digital write on external pins
}

robtillaart

interesting idea:

The alt_digitalWrite() must exist otherwise it will not compile.
A better implementation might mimic the way attachInterrupt() works.
- The framework has a function pointer which is default NULL.
- The user can do  attachDigitalWrite(altDigitalWrite);  and   detachDigitalWrite();

Code: (example) [Select]

void digitalWrite(uint8_t pin, uint8_t val)
{
 
  if (pin > 127 && alt_digitalWrite != NULL )
  {
    alt_digitalWrite(pin,val);
    return;
  }
  //do original digitalWrite
}
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

liudr


robtillaart

An interesting variation could be

Code: [Select]

void digitalWrite(uint8_t pin, uint8_t val)
{
  if (alt_digitalWrite != NULL )
  {
    if (alt_digitalWrite(pin,val) ) return;
  }

  //do original digitalWrite
}


Besides doing the extended IO  alt_digitalWrite()  intercepts  the "normal" IO and do something.
e.g. when you set pin 13  it can automatically set pin 95, or send something to an LCD , or send something over I2C.

the bool return value [true/false] decides if the original code is to be called after alt_digitalWrite().

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

liudr

That's really smart! I would define the digitalWrite or read as returning integer and only 0 and 1 are mapped to high and low and then maybe -1 maps to "please run original digitalWrite or read".

Arduino team should know about this!

robtillaart

boolean was invented for true and false ...

the signature should be   bool alt_digitalWrite(uint8_t pin, uint8_t val);

an example of a serial dumper
Code: [Select]
bool alt_digitalWrite(uint8_t pin, uint8_t val)
{
  Serial.println(pin, DEC);

  if (pin > 20) return false;
  return true;
}
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

liudr

Yes but that will help digitalRead's alternative function since it is expected to return true or false. I am going to implement this in Arduino IDE 1.0.5  R2 with some extender chips, just to see how far I can go with various libraries, code, and hardware.

kowalski

@liudr

Have you seen this work?

https://github.com/neu-rah/Arduino-VirtualPins/blob/master/hardware/arduino/cores/arduino/virtual_pins.h

It sounds a lot like what you are describing.

More info here; https://groups.google.com/a/arduino.cc/forum/#!topic/developers/g3IqPZ2wB5k and https://github.com/neu-rah/Arduino-VirtualPins

The Cosa solution to your original issue (LCD adapters) is to use abstract interfaces. The LCD port access is done by an adapter object; an implementation of the class LCD::IO, https://github.com/mikaelpatel/Cosa/blob/master/cores/cosa/Cosa/LCD.hh#L184.

The best example of how this works is the CosaLCDbench sketch, https://github.com/mikaelpatel/Cosa/blob/master/examples/LCD/CosaLCDbench/CosaLCDbench.ino#L47. The LCD handling is three layers; 1) implementation of the LCD interface, 2) implementation of the LCD port adapter, 3) binding of the LCD driver to IOStream.

Please note that CosaLCDbench handles three types of LCDs and over 10 types of adapters ranging from 4-bit parallel to 3 wire Shift Register over SPI.

Cheers!

liudr

kowalski,

Thanks. The virtual pin seems interesting, almost what we are discussing. It only uses shift registers. I'm trying to use GPIO extender chips so they will have input and output and some pullup resistors. This makes them more like regular pins. Plus, I am trying to stay away from PROGMEM. That seems awkward. A digital read has to read from multiple PROGMEM arrays to determine what port and pin to read. It was probably the only way for ATMEGA8 to do it with such limited memory. I'll just do an attachInterrupt method like Rob suggested and report back how well it works. I am a bit apprehended by the use of github. It provides  no help to a non-programmer professional. Impossible to understand what he did or what I should grab from it.

liudr

I just implemented some of the features we discussed. It seems pretty sweet. I can even use this generalization to do simulations! Here is a sample code:

Code: [Select]
int led = 20;

// the setup routine runs once when you press reset:
void setup()
{               
  Serial.begin(9600);
  // initialize the digital pin as an output.
  //pinMode(led, OUTPUT);
  altDigitalWrite=&digitalWriteHaHa;
  altDigitalRead=&myDigitalRead;
}

// the loop routine runs over and over again forever:
void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  Serial.println(digitalRead(20));
  delay(1000);               // wait for a second
}

void digitalWriteHaHa(uint8_t pin, uint8_t val)
{
  Serial.println("haha");
}

int myDigitalRead(uint8_t pin)
{
  return HIGH;
}


Output:
Code: [Select]
haha
haha
1
haha
haha
1
haha
haha
1


With the attachInterrupt way, the alternative digital read write and mode can use all functions and libraries available to the main sketch, a huge convenience.

Files that need to be changed are Arduino.h to include the declarations of these alternative function pointers, wiring_digital.c with alternative functions before the original functions, and additional lines in the main sketch. I just need to test its speed on an I2C extender. Hopefully we can get 20KHz on digital pins when we run 400KHz I2C bus speed. That is enough to do an accurate photo gate setup for physics labs.

I do have some questions on how the IDE compiles files, which I will spin off a new topic. Thanks guys.

Go Up