• No More I2C Expander!

    Dolen10/20/2022 at 09:19 1 comment

    For expediency's sake I had originally chosen to drive my LCD using an I2C "backpack" board, specifically one with the PCF8574 GPIO expander. Along with the help of the New-LiquidCrystal library, I was able to get it running fairly easily (after determining the pin assignments on the backpack board).

    However, this never felt like an optimal solution. The ESP8266 lacks hardware I2C, and the knowledge that it was bit-banged was keeping me awake at night. Besides, I wasn't using any other IOs from the ESP, so I might as well control the LCD directly. On the software front, it would just be a matter of changing an include file. And although the LCD runs at 5V, the HD44780 controller accepts logic VIH of >2.2V, which means it should work fine with the ESP 3.3V IOs.

    And yet, having made all the requisite changes and plugged the display directly into the breadboard, I was greeted with garbled text:

    This led me down a frustrating rabbit hole of messing with pin assignments, trying to modify the library, and even attempting to run the LCD at 3.3V, all to no avail. Although the screen worked just fine when using the I2C backpack, it had issues when connected directly, despite using the same library. I could write a whole separate post about this ordeal, but at the end of it I was certain that this was a timing issue.

    The HD44780 datasheet gives max execution times for various commands (such as clearing the screen or writing a character). But these values assume a typical controller frequency of 270kHz, and it was evident that my particular screen was running much slower than that. In a "proper" application you're expected to read the LCD's busy flag and wait for the commands to complete. The LCD library code instead delays by fixed amounts (or in some cases, not at all), and just assumes that the controller has had enough time to complete its operation. This is an acceptable method, but you need to be 110% certain that the allotted delays are compatible with the display modules in question.  

    Ultimately I gave up on the 3rd party library and wrote my own driver code (which has been merged). To optimize for speed I took advantage of the fact that the four SPI pins are muxed to consecutive bits of the GPIO port, so I could write 4-bit values in parallel instead of the repeated calls to digitalWrite() which had been employed by the New-LiquidCrystal library. Although this means that the pin assignments are fixed, I wasn't using those pins anyway. A full screen clear-and-refresh takes just under 10 milliseconds, compared to 75ms via I2C at 100kHz.

    After some trial-and-error and checking timings on an oscilloscope, I was finally able to get the proper text display that I had been looking for:

    I also cleaned up the wiring a bit, if you couldn't tell.

  • Demo Video

    Dolen10/13/2022 at 22:52 0 comments

    This video demonstrates several features of the code, including track title/artist display, and support for seeking forwards and skipping tracks.