Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wokwi support #35

Open
urish opened this issue Oct 13, 2022 · 21 comments
Open

Wokwi support #35

urish opened this issue Oct 13, 2022 · 21 comments

Comments

@urish
Copy link

urish commented Oct 13, 2022

Hello, Developer of Wokwi here.

I learned that you had a negative past experience related to Wokwi. Sorry about this. I'd like to to straighten things out.

How do you feel about working together to have the hd44780 library fully supported on Wokwi?

As far as I understand, we would need to implement hd44780+pcf8574 reading on our end, so that hd44780_I2Cexp::ioread returns a valid value. Unless I got something wrong?

In any case, if you do not feel like spending any time on this and prefer just to close the issue, then I totally understand and respect your decision.

@bperrybap
Copy link
Contributor

I would like to have all the hd44780 i/o classes working in woki.
So I would like to work with you guys to get it working.
It appears that the issue is reads from the PCF8574 are not being handled properly.
The PCF8574 has weak pullups that are always enabled on the port pins.
They generate the high signals when the pins are being used for output
They are still enabled on input/reads but it doesn't take much to pull them down on reads.
There are some real world interactions that happen to the signal levels read on the PCF8574 port pins when the PCF8574 is hooked up the LCD pins and the backlight transistor.

There are half a dozen or so different i2c backpacks that use different wiring between the PCF8574 and the LCD, and then there are 3 different backlight circuits.
The auto detection code in the hd44780 library probes the backpack through the PCF8574 port pins to determine the pin mappings and backlight circuit being used.
From what I can tell the current emulation of the LCD backpack is hard coded to one design - which is fine, but reads from the PCF89574 need to respond the same way as the real h/w would for that h/w combination.

I don't know how the emulations work and how they interact with each other when connected,
but I would be willing to work with you guys to make it work at least good enough to allow the hd44780_I2Cexp i/o class work. (the class for the i2c LCD backpack)

I'm guessing you will need some information from me about this as there is no place where these interactions are actually documented. i.e. you are not going to find this in the hd44780 datasheet and there is no real place to look to see the effect of using a transistor base pin as in input to a PCF8574 port pin with its weak pullup.
And how those effects change depending on the LCD pin and whether the transistor is NPN or PNP.

What do you need from me to get started?

@bperrybap
Copy link
Contributor

bperrybap commented Oct 13, 2022

It is more than ioread()
ioread() is used to read DDRAM from the LCD. That is called after all the configuration and initialization is completed.
The i/o class can still function even if ioread() does not work (some backpacks do not support reading LCD)
i.e. for some backpacks ioread() is never used and is not supported.

But PCF8574 reads still needs to work since the library does probing during initialization to figure out the h/w design for the proper low level initialization/configuration.

Direct probing of the backpack h/w is done through the i/o expander chip (which can be PCF8574 or MCP23008) in ioinit() by calling IdentifyIOexp() to determine the type of io expander chip (PCF8574 vs MCP2008) and then and autocfg8574() to determine the pin mappings and backlight control active level for the PCF8574 based backpacks.

@bperrybap
Copy link
Contributor

There are comments in code for the IdentifyIOexp() and autocfg8574() where I tried to explain what the code is looking for.
You will see that what is read depends on the last thing written to the port and what each pin is hooked up to.

@urish
Copy link
Author

urish commented Oct 13, 2022

Thank you. This was really helpful!

Luckily, the code is well commented, so I was able to quickly figure out what the simulator needs to do - it boils down to returning 0x00 any time after 0x00 is written (that matches the PCF8574 detection in IdentifyIOExp()), and then returning 0xf7 for any other write, so autocfg8574() figures out we're using the rs = 0; rw = 1; en = 2; d4 = 4; d5 = 5; d6 = 6; d7 = 7; bl = 3; wiring variant. I didn't know these I2C backpack were such a mess...

Anyway, now it seems to work on Wokwi, at least with a simple testing program:

https://wokwi.com/projects/345429854144954963

@bperrybap
Copy link
Contributor

That is very cool. It gets basic functionality working for writing to the display.
However, it won't get reads from the LCD working as support for LCD data reads is more complex.
i.e. supporting the read() API function which maps to ioread() in the i/o class.

To support that, not only will the LCD emulation need to support LCD reads, but the PCF8574 pin values reported will need to be based on how the LCD drives the data pins when a read is done.
i.e. when R/W high, and E high.

From my testing I was not able to get reads from the LCD in 4 bit parallel mode working. (interfacing directly to the LCD with pins)
So there are some issues with LCD emulation for reads as well.
I would say that a first step would be to get 4 bit reads working with direct pin control,
then, try to get LCD reads working through the PCF8574.

For testing LCD reads in 4 bit mode you can use the hd44780_pinIO class.
There is a demo sketch called ReadWrite (in each i/o class) that writes to the top row of the LCD then attempts to read it and write it back to the 2nd row.

The big daddy is the hd44780_I2Cexp i/o class I2CexpDiag sketch.
That does lots of tests and requires writes & reads through the PCF8574 to be fully working.
It tests for external pullups on the i2c signals, and after the library probes the device, it will perform DDRAM tests
which requires the ability to read data from the LCD through the PCF8574.

@bperrybap
Copy link
Contributor

bperrybap commented Oct 13, 2022

I hope my previous comment didn't come off poorly.
I think this first step is really good, and is good enough to deploy, for now, as it will get it working for most people right away since most users only write to the LCD in their sketches.
Getting full reads to work is a more difficult task.

@urish
Copy link
Author

urish commented Oct 14, 2022

Thanks for clarifying that! What are the common use cases for reading back from the LCD?

@bperrybap
Copy link
Contributor

bperrybap commented Oct 14, 2022

Most sketch code doesn't do reads from the LCD.
There have been a few requests on the Arduino forum to read from the LCD over the years but not that many.
It tends to be for some very specific use case and it tends to be uncommon / quite rare.
The hd44780 library is the only library I've seen that provides API functions to supports reading from the LCD.
It allows user code to read data or status from the LCD using read() and status()

The most common use case for reading from the LCD is to read the BUSY status.
A few libraries do this, but most do not use BUSY.
On the AVR platform provided by arduino.cc using BUSY will be slower than not using BUSY for normal character writes given the poor and slow implementation of digitalRead(), digitalWrite(), and pinMode()
Teensy on the other hand has MUCH faster implementations on its AVR platform, (arduino.cc refused to use Paul's faster code in their bundled AVR platform even though he offered it to them)

Any library that uses BUSY status will need to have the ability to read the LCD.
i.e. any library that uses BUSY will not work with wokwi, including those that use direct pin control until LCD status reads are supported.
Also when reading status vs data from the LCD, you get the DDRAM pointer which is the cursor position.
That can be useful for certain applications although I'm not aware of any other library other than hd44780 that uses reading cursor position or provides an API to read LCD status.

The hd44780 library itself doesn't use BUSY.
But the hd44780 library does read from the LCD when custom characters are created to get the current cursor position.
See the hd44780 library createChar() function. It calls status() which calls ioread() to read the LCD status register.
The reason is that the only way to get the LCD out of CGRAM mode back into DDRAM mode (so it can display characters on the display) is to either clear the display, home the display or set the cursor position.
Every other hd4480 LCD library I've seen, including LiquidCrystal leave the display in CGRAM mode after setting a custom character. IMO, this is an undocumented bug than can create a non obvious issue.
This means that until the user sketch code does a clear, home or set cursor position, any calls to write(), or print() which calls write() will corrupt CGRAM and not write to the LCD display since the LCD is still in CGRAM mode.
Since the only way to get the LCD back into DDRAM mode affects the DDRAM pointer (cursor position), the hd44780 library, in its creatChar() function will read the DDRAM pointer before writing to CGRAM mode, then set the DDRAM pointer to what it was prior to writing to CGRAM. This puts the LCD back into the same state it was prior to calling createChar()
This allows the user to set a custom character and not affect the cursor position - no other library supports this.

The hd44780 library does check to see if LCD reads are supported, if not, it will put the LCD back into DDRAM mode by setting the cursor position to 0,0 which puts the LCD back into DDRAM mode but does alter the cursor position.

While I'm not a fan of these types of things,
a temporary hack could be to have the hd44780 library use a define/macro that is set by wokwi when the library is being built & used in wokwi that the hd44780 library could use to disable read support from the LCD.
(note: disabling read support from the LCD does not remove the need to read from the PCF8574 chip)
Disabling LCD read support will allow createChar() to still work, (not as well as it does when reads are support) and allow read() and status() to return the proper error values to indicate a lack of LCD read support.
All the hd44780 examples already modify their behavior or fail gracefully if they wanted to read from the LCD and reads from the LCD is not supported / available.

Does wokwi set a define/macro during the build to indicate that the code is being built in/for the wokwi environment?
I'm assuming not, given this issue:
wokwi/wokwi-features#234
Seems like there are some use cases that can benefit from having a wokwi build macro that can allow code to compile time adjust to the simulator environment.

Long term, it would nice get LCD reads fully working.

If going down this path of using wokwi defines to adjust the code for the wokwi environment
It would be nice to have a second macro to indicate that wokwi reads from hd44780 LCDs is not supported.
That way whenever LCD read support is implemented in wokwi it will "just work" in the hd44780 library without having to do a library update.

@bperrybap
Copy link
Contributor

Any news/update on this?

@urish
Copy link
Author

urish commented Nov 23, 2022

Sorry for not responding earlier. This is still on my list, but I haven't got to it yet (the list is pretty long...).

If I understand correctly, the current situation is that createChar won't work perfectly with Wokwi - it'll alter the char, but then the cursor position will be reset to 0, 0?

In any case, I'm not very fond of adding a macro that indicates the the code if being built for Wokwi. This will eventually encourage working around simulator bugs instead of fixing them.

If you think it's important to fix this, I can make an effort to prioritize adding support for reads in Wokwi. Otherwise, I think we can close this issue and wait to see if any users come up with this request. I'd love to hear your thoughts.

@bperrybap
Copy link
Contributor

There is a slight misunderstanding of createChar()
It is worse than "won't work perfectly", it will incorrectly set the cursor position to a garbage location since reading the ddram address returns garbage. This position is likely to be a position outside of the viewing area of the display when the display is not 20x4

The hd44780 library code is designed to work around the lack of read support/capability but it can't work around reads returning garbage.
LCD reads that return garbage will cause some of the included examples to fail since they depend on the ability to read from the LCD.

Inability to read from the LCD is an issue that is bigger than just when using a PCF8574.
i.e. any code that attempts to read from the LCD will have issues.
The biggest issue will be for Arduino libraries or any other code that uses BUSY status.
Those libraries are doing direct pin control (no PCF8574) and will read the status register to monitor the BUSY bit.
This type of code will not function under wokwi until reads work. There is no work around for that type of code.

Whether or not this read issue affects hd44780 library users sketch code that use custom characters will depend on if their code sets the cursor position after programming custom characters.
With all other LCD libraries users must do something that sets the cursor position since all the other LCD libraries are broken and have a bug that leaves the LCD in CGRAM mode. Users must do something in their sketch code to set the cursor position to get the LCD back into DDRAM mode.

Given the hd44780 library is the only LCD library that restores the LCD to DDRAM mode, it is likely that the issue won't be very wide spread. And it won't be an issue for users that take "working" code from other libraries like LiquidCrystal_I2C or LiquidCrystal and switch to the hd44780_I2Cecxp i/o class.
But it may be an issue for those that started with hd44780_I2Cexp i/o class who are either intentionally or unknowingly depending on this capability. And it will be an issue for any users that wrote code to explicitly read data from the LCD.

So on the positive side, the vast majority of users never use the read capability of the hd44780 library - particularly since no other LCD library supports reading from the LCD so unless they explicitly attempt to read from the LCD they will never see this issue - assuming you added the code to support the hd44780_I2Cexp auto configuration.

It will definitely be an issue for the diagnostic tool I2CexpDiag that comes bundled with the hd44780_I2Cexp i/o class examples.
It does all kinds of special things to test out the h/w including a full RAM test of the internal DDRAM on the LCD.
As is, with reads not returning proper data, it will report h/w failures.
If reads are not supported/disabled, then I2CexpDiag will skip over anything/tests that need read capability.
The ReadWrite example will also fail with errors. It demonstrates how to use the read capability of the library.
If reads are not supported it will print a message on the LCD saying reads are not support for this h/w.

This is why I mentioned the possibility of having a macro/define as the library could disable read support to allow things to fall back to working without read support or failing gracefully vs reporting h/w errors.
But if that is done, it should be done in a way, perhaps with with a macro or multiple macros which can be used to determine if/when LCD read support under wokwi has been implemented.
This will allow the hd44780 library to magically support LCD reads under wokwi once wokwi supports it.

But maybe it is ok to leave the issue there (assuming auto configuration works), and see how many users stumble on it and complain to let that be the driver of setting its priority?

Here is summary of what createChar() does, with an updated copy of the code with some new added comments for clarity.

creatChar() reads the status register which returns the BUSY bit and the current ddram address.
If the status() call fails (which means reading from the LCD is not supported) it sets the ddramaddr value to zero which is character position (0,0)
If the status() call succeeds (which it will under wokwi), then the code strips off the BUSY bit to get the ddram address.
If the read from the LCD is garbage, then the ddramaddr value will now be garbage.

After the character is data is written to CGRAM, the code will restore the cursor position(ddram address) back to where it was prior to programming. Setting the cursor position necessary for two reasons.

  1. this is the most important: it puts the LCD back into DDRAM mode so characters can be written to the display.
  2. it restores the ddram address (cursor position) since there is only a single address pointer that is shared between DDRAM mode and CGRAM mode and setting the custom character alters the DDRAM address (cursor position).
// Allows filling in the first 8 CGRAM locations
// with custom characters
// note that it is not possible to support more than 8 locations
// since SETCGRAMADDR instruction is bit 6 and there no room
// for any more address bits.
// (location is bits 3-5 and data row is bits 0-2 of the instruction)
int hd44780::createChar(uint8_t location, uint8_t charmap[])
{
int rval;
int ddramaddr;

	location &= 0x7; // we only have 8 locations 0-7

	ddramaddr = status(); // fetch status which includes ddram address

	if(ddramaddr < 0) // status() failed, so set ddramaddr value to 0
		ddramaddr = 0;
	else
		ddramaddr &= 0x7f; // strip off BUSY bit to get ddramaddr value

	rval = command(HD44780_SETCGRAMADDR | (location << 3));
	if(rval)
		return(rval);
	for (int i=0; i<8; i++)
	{
		if(_write(charmap[i]) != 1) // use raw write to avoid line processing
			return(RV_EIO);
	}

	// put LCD back into DDRAM mode so write() works
	// this setCursor() will set the ddram address (cursor position)
	// back to where it was if status() is supported or to 0,0 if not.
	// note: the 0 being passed to setCursor() is not the address,
	// it is a 'trick' to allow a raw ddram address to be sent to the LCD.
	return(setCursor(ddramaddr , 0));
}

@bperrybap
Copy link
Contributor

I guess that was a long way of saying that if you put in the changes to support the hd44780_I2Cexp auto configuration, most users will be happy and won't notice that reads from the LCD are not working properly and return garbage.
But any code that depends on reads from the LCD working including the I2CexpDiag tool or the ReadWrite examples will obviously fail to work as intended.

@urish
Copy link
Author

urish commented Nov 28, 2022

I really appreciate the fact that you take the time to write such detailed explanations, thank you.

We now have read support for the hd44870, and it should also work though the PCF8574. I've tested readWrite and it seems to work both with I/O pins and through the I2C extender:

I'd love to hear your feedback, and thanks again for collaborating on this!

@bperrybap
Copy link
Contributor

Very cool. I'm guessing that was a lot of work.
Even the hd44780_I2Cexp I2CexpDiag sketch now works.
That sketch really exercises the h/w.
I'm in awe that Wokwi can do what it does - and I'm not easily impressed.

I did notice one issue with the simulator that is related to backlight control that need to be fixed.
If you notice the backlight is off when using hd44780_I2Cexp examples.
If running the I2CexpDiag sketch, you will notice that the backlight does work but its state is backwards.
i.e. when the sketch attempts to turn on the backlight on it goes off and when it attempts to turn it on off it goes on.
This is because the hd44780 library incorrectly determined the backlight control active level during its probing.
(there is small a issue in the h/w emulation)

There are 6 different backpack designs.
The hd44780_I2Cexp supports all of them and probes to determine which one.
The LiquidCrystal_I2C (as well as most others) only supports 1 of them.

The simulator will need to decide how it wants to deal with all these different backpack designs.
It can support only one (as it does now) or it could support multiple of them or have a way to configure which one.
Supporting only one is probably good enough but it needs a small tweak to behave like the real h/w so that the hd44780 library can properly determine which backpack design is in use.

The hd44780_I2Cexp i/o probes through the PCF8574 to determine which one is in use.
There is one pin on the PCF8574 that connects to a backlight circuit.
Most backlight circuits use a transistor. But some use an NPN and some use a PNP (one uses an FET)
The PCF8574 backlight control pin is connected to the base and depending on which transistor is used the backlight control circuit uses either active high or active low signal to turn on the backlight. The hd44780 library must figure out which level to use to turn on the backlight.
Here is link to schematic for the most common backpack design:
https://www.sunrom.com/p/i2c-lcd-backpack-pcf8574

This appears to be what woki is emulating.
It often sold under these names: YWROBOT, DFROBOT, SAINSMART, FUNDUINO, SUNROM

You can see that PCF8574 P3 connects to the base of a NPN transistor.
There is a pullup on the transistor base pin. The pullup will cause the backlight to be on at powerup so no host interaction is required to turn on the backlight and a high on P3 will turn on the backlight and a low on P3 will turn off the backlight.

Whereas with the PNP designs that require a low on the base to turn on the backlight, it will power up off and will not turn on until the host sets backlight control pin to low.

This is where it gets tricky and is non obvious.
On the NPN designs (the one Wokwi appears to be emulating), even through there is a pullup on the transistor base that is also connected to the P3 pin of the PCF8574, the PCF8574 pin will read as low on real h/w.
This is because the current draw through the base is enough to pull the signal down to be read as low.
So the PCF8574 backlight control pin will be biased in the opposite direction of the backlight control active level.
i.e. for an NPN transistor which uses active high, the pin reads low, for a PNP transistor which uses active low, the pin will read high.

The hd44780 library probed to incorrectly determine that a RobotArduino LCM1602 backpack with active low backlight control was being used due to reading the incorrect level on pcf8574 P3.

All this is a long way of saying, the woki simulator for the lcd backpack needs to read low on the pcf8574 P3 pin so that the hd44780 library can properly determine the backlight control active level.

@urish
Copy link
Author

urish commented Nov 28, 2022

Fascinating, I was wondering about the situation with the backlight. You seem to know the ins and outs of these LCD1602 modules!

Thanks for the detailed explanation of the backlight detection mechanism. Yes, for now, we'll keep it seems with just the most common design. I've updated Wokwi to read low for P3, so now hd44780 correctly detects the backlight.

@bperrybap
Copy link
Contributor

Yay! that is great news.

Yeah, I spent quite a bit of time probing these LCDs and backpacks trying to come up with a way to create a method to auto configure the device since so many people were having issues getting their LCDs working.
Now with auto address location and auto configuration, the casual/less technical user can get a plug-n-play experience when using this type of LCD device.

These days, nearly all the backpacks people are purchasing seem to be the design you are emulating.
But several years back that wasn't the case.
Ironically, I think it was the lack of configurabilty or difficulty of configuration of s/w that drove most vendors to the single design we are mostly seeing today.

BTW, I also spent LOTs of time with KS0108 type displays. Now THAT is a big can of worms.

@urish
Copy link
Author

urish commented Nov 28, 2022

KS0108? Are these the graphic LCDs?

p.s. I want to link to one or two of the hd44780 examples from the Wokwi docs for the LCD1602. Any suggested examples?

@bperrybap
Copy link
Contributor

KS0108 - yes it is a graphic LCD.
Problem is there is no standard pinout for the devices and the enables, strobes, & chipselects can work differently.
Even things like power and ground are not on the same pins.
So if the incorrect datasheet is used, the glcd can be instantly burned up.

Not sure how/where you want to go with the LCD1602 reference page and examples.
i.e. the LCD1602 reference page its getting enough parts that it might benefit from some partitioning or sub pages for the different libraries.

For hd44780, there are HelloWorld examples for each i/o class, that could be directly linked to in the hd44780 github repository,
i.e.
https://github.com/duinoWitchery/hd44780/blob/master/examples/ioClass/hd44780_I2Cexp/HelloWorld/HelloWorld.ino
https://github.com/duinoWitchery/hd44780/blob/master/examples/ioClass/hd44780_pinIO/HelloWorld/HelloWorld.ino

However, they are not as brief as they could be particularly for pinIO as the pinIO class is setup for an LCD shield to work on the ESP boards so there are some conditionals in it.
Also, I'm in the process of making some directory structure changes to the library which means the examples will be moved in the repository tree. So depending on revision of the repository you look at, those directories (or the new locations) may or may not exist.
So I would discourage linking into the hd44780 github repository for examples.
I would suggest providing very brief minimal examples just like what was done for LiquidCrystal and LiquidCrystal_I2C

One thing that might be helpful is to provide a link to a library page in the actual example code for more information when possible.
i.e. a link to the LiquidCrystal page for that library like
https://docs.arduino.cc/learn/electronics/lcd-displays
and links to the corresponding wiki page for the hd44780 i/o classes.

When these links are in the example they are clickable so the user can click on the link to get additional information about the library and its API.
LiquidCrystal_I2C doesn't really have much other than the github repository which doesn't have any more information and is no longer maintained so not sure having a link to the repository would be that helpful for that library.

Here are some very brief examples like what was done for LiquidCrystal and LiquidCrystal_I2C.
i.e. something like:

For hd44780_I2Cexp:

// LCD1602 to LCD i2c backpack example
// LCD controlled using i2c backpack
// see hd44780_I2Cexp wiki for more information:
// https://github.com/duinoWitchery/hd44780/wiki/ioClass:-hd44780_I2Cexp

#include <Wire.h>
#include <hd44780.h>                       // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header

hd44780_I2Cexp lcd; // declare lcd object: auto locate & auto config expander chip

#define LCD_COLUMNS 16
#define LCD_LINES   2

void setup()
{
  lcd.begin(LCD_COLUMNS, LCD_LINES);
  // you can now interact with the LCD, e.g.:
  lcd.print("Hello World!");
}

void loop()
{
  // ...
}

For hd44780_pinIO
(note: I used pins to work with the most common lcd keypad shield)

// LCD1602 to Arduino Uno connection example
// LCD controlled directly by Arduino pins
// see hd44780_pinIO wiki for more information:
// https://github.com/duinoWitchery/hd44780/wiki/ioClass:-hd44780_pinIO

#include <hd44780.h>
#include <hd44780ioClass/hd44780_pinIO.h> // Arduino pin i/o class header

const int rs=8, en=9, db4=4, db5=5, db6=6, db7=7; // pins for LCDkeypad shield
hd44780_pinIO lcd(rs, en, db4, db5, db6, db7);

#define LCD_COLUMNS 16
#define LCD_LINES   2

void setup()
{ 
  lcd.begin(LCD_COLUMNS, LCD_LINES);
  // you can now interact with the LCD, e.g.:
  lcd.print("Hello World!");
}

void loop() 
{
  // ...
}

For LiquidCrystal something like this:
The link below has great information but is not provided by arduino.cc
https://arduinogetstarted.com/reference/library/arduino-lcd-library
maybe you could contact them about collaboration & use this link in the wokwi example?
It is very complete and extensive.|
It does do some self promotion and have some adds, but the information seems better than the Arduino.cc documentation pages

// LCD1602 to Arduino Uno connection example
// LCD controlled directly by Arduino pins
// see these links for more information:
// https://docs.arduino.cc/learn/electronics/lcd-displays
// https://www.arduino.cc/reference/en/libraries/liquidcrystal/

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 10, 9, 8, 7);

void setup() {
  lcd.begin(16, 2);
  // you can now interact with the LCD, e.g.:
  lcd.print("Hello World!");
}

void loop() {
  // ...
}

@urish
Copy link
Author

urish commented Nov 29, 2022

Awesome, thank you so much!

@matititam, can you please add these examples to the Wokwi docs and get in touch with
arduinogetstarted.com as bperrybap suggests?

@matititam
Copy link

Definitely yes. I will start on this ASAP

@drf5n
Copy link

drf5n commented Mar 23, 2023

For easy dissemination and adoption, it might be nice to have links to the examples as implemented in Wokwi. Three places they could be useful are:

  • On a list accessible from the README.md so folks who are RTFM can try out the library and code with an very low barrier.
  • Within the code comments of the code, so copied code leads the reader to a working reference location
  • Within the code comments of the code on Wokwi, so cut&pasted code has a chance of leading the reader/debugger back to the source.

Perhaps something like adding a section for SEE ALSO to the comments in https://github.com/duinoWitchery/hd44780/blob/master/examples/ioClass/hd44780_I2Cexp/HelloWorld/HelloWorld.ino to point back here, and to a Wokwi reference implementation you own.

I was thinking something like this:

https://wokwi.com/projects/360021172047397889

// vi:ts=4
// ----------------------------------------------------------------------------
// HelloWorld - simple demonstration of lcd
// Created by Bill Perry 2016-07-02
// [email protected]
//
// This example code is unlicensed and is released into the public domain
// ----------------------------------------------------------------------------
//
// This sketch is for LCDs with PCF8574 or MCP23008 chip based backpacks
// WARNING:
//	Use caution when using 3v only processors like arm and ESP8266 processors
//	when interfacing with 5v modules as not doing proper level shifting or
//	incorrectly hooking things up can damage the processor.
// 
// Sketch prints "Hello, World!" on the lcd
//
// If initialization of the LCD fails and the arduino supports a built in LED,
// the sketch will simply blink the built in LED.
//
// NOTE:
//	If the sketch fails to produce the expected results, or blinks the LED,
//	run the included I2CexpDiag sketch to test the i2c signals and the LCD.
//
// SEE ALSO:
//    https://github.com/duinoWitchery/hd44780
//    https://github.com/duinoWitchery/hd44780/blob/master/examples/ioClass/hd44780_I2Cexp/HelloWorld/HelloWorld.ino
//    Wokwi simulation https://wokwi.com/projects/345429854144954963
//      (sim adapted from https://wokwi.com/projects/345429854144954963
//    https://github.com/duinoWitchery/hd44780/issues/35
//    
// ----------------------------------------------------------------------------
// LiquidCrystal compability:
// Since hd44780 is LiquidCrystal API compatible, most existing LiquidCrystal
// sketches should work with hd44780 hd44780_I2Cexp i/o class once the
// includes are changed to use hd44780 and the lcd object constructor is
// changed to use the hd44780_I2Cexp i/o class.

#include <Wire.h>
#include <hd44780.h>                       // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header

hd44780_I2Cexp lcd; // declare lcd object: auto locate & auto config expander chip

// If you wish to use an i/o expander at a specific address, you can specify the
// i2c address and let the library auto configure it. If you don't specify
// the address, or use an address of zero, the library will search for the
// i2c address of the device.
// hd44780_I2Cexp lcd(i2c_address); // specify a specific i2c address
//
// It is also possible to create multiple/seperate lcd objects
// and the library can still automatically locate them.
// Example:
// hd4480_I2Cexp lcd1;
// hd4480_I2Cexp lcd2;
// The individual lcds would be referenced as lcd1 and lcd2
// i.e. lcd1.home() or lcd2.clear()
//
// It is also possible to specify the i2c address
// when declaring the lcd object.
// Example:
// hd44780_I2Cexp lcd1(0x20);
// hd44780_I2Cexp lcd2(0x27);
// This ensures that each each lcd object is assigned to a specific
// lcd device rather than letting the library automatically asign it.

// LCD geometry
const int LCD_COLS = 16;
const int LCD_ROWS = 2;

void setup()
{
int status;

	// initialize LCD with number of columns and rows: 
	// hd44780 returns a status from begin() that can be used
	// to determine if initalization failed.
	// the actual status codes are defined in <hd44780.h>
	// See the values RV_XXXX
	//
	// looking at the return status from begin() is optional
	// it is being done here to provide feedback should there be an issue
	//
	// note:
	//	begin() will automatically turn on the backlight
	//
	status = lcd.begin(LCD_COLS, LCD_ROWS);
	if(status) // non zero status means it was unsuccesful
	{
		// hd44780 has a fatalError() routine that blinks an led if possible
		// begin() failed so blink error code using the onboard LED if possible
		hd44780::fatalError(status); // does not return
	}

	// initalization was successful, the backlight should be on now

	// Print a message to the LCD
	lcd.print("Hello, World!");
}

void loop() {}

Given that https://wokwi.com/projects/360021172047397889
wokwi sketch, you could erase all its code, drop in another hd44780 sketch, and Wokwi is already wired-up and has the Library added to the build environment.

...for example, following the links and advice from that Wokwi sim to the repository and to https://github.com/duinoWitchery/hd44780/blob/master/examples/ioClass/hd44780_I2Cexp/I2CexpDiag/I2CexpDiag.ino with its own Copy button and to get you this output from just a couple mouse clicks:

********************************************************************
Serial Initialized
--------------------------------------------------------------------
I2CexpDiag - i2c LCD i/o expander backpack diagnostic tool
--------------------------------------------------------------------
hd44780 lib version: 1.3.2
--------------------------------------------------------------------
Reported Arduino Revision: 1.6.7
CPU ARCH: AVR - F_CPU: 16000000
--------------------------------------------------------------------
SDA digital pin: 18 A4
SCL digital pin: 19 A5
--------------------------------------------------------------------
Checking for required external I2C pull-up on SDA - YES
Checking for required external I2C pull-up on SCL - YES
Checking for I2C pins shorted together - Not Shorted
--------------------------------------------------------------------
Scanning i2c bus for devices..
 i2c device found at address 0x27
Total I2C devices found: 1
--------------------------------------------------------------------
Scanning i2c bus for all lcd displays (4 max)
 LCD at address: 0x27 | config: P01245673H | R/W control: Yes
Total LCD devices found: 1
--------------------------------------------------------------------
LCD Display Memory Test
Display: 0
 Walking 1s data test:	PASSED
 Address line test:	PASSED
--------------------------------------------------------------------
Each working display should have its backlight on
and be displaying its #, address, and config information
If all pixels are on, or no pixels are showing, but backlight is on, try adjusting contrast pot
If backlight is off, wait for next test
--------------------------------------------------------------------
Blinking backlight test: to verify BL level autodetection
If backlight is mostly off but
you briefly see "BL Off" on display with backlight on,
then the library autodetected incorrect BL level
and the library cannot autoconfigure the device
--------------------------------------------------------------------
Displaying 'uptime' on all displays
--------------------------------------------------------------------

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants