| pcf8574 lcd backpack - readme.txt |
| 20160524a, ziggurat29 |
| |
| Abstract |
| ======== |
| |
| This describes the use of the pcf8574_lcd_backpack.h, .c driver module for NuttX. |
| |
| Contents |
| ======== |
| |
| o Summary for Those Who Don't Like to Read |
| o Introduction |
| o Usage |
| - Specifying the I2C Address |
| - Specifying the LCD Display Format |
| - Specifying Unknown/New Backpacks |
| o Special Features |
| - Codec |
| - Ioctl |
| o Troubleshooting |
| |
| Summary for Those Who Don't Like to Read |
| ======================================== |
| |
| To use, in your board_app_initialize(), |
| |
| 1) instantiate an I2C bus: |
| |
| FAR struct i2c_master_s* i2c = stm32l4_i2cbus_initialize(1); |
| |
| 2) set the configuration for the particular make of board, and LCD format: |
| |
| struct pcf8574_lcd_backpack_config_s cfg = LCD_I2C_BACKPACK_CFG_MJKDZ; |
| cfg.rows = 2; |
| cfg.cols = 16; |
| |
| 3) instantiate the device on the I2C bus previously created: |
| |
| ret = pcf8574_lcd_backpack_register("/dev/slcd0", i2c, &cfg); |
| |
| Introduction |
| ============ |
| |
| The character LCD modules based on the HD44780 (and compatible ST7706U, KS0066U, |
| SED1278, etc.) drivers have been around for many decades and are quite popular. |
| One challenge is that they require a large number of GPIO (11 in 8-bit mode, 7 |
| in 4-bit mode, and an additional line if you control the backlight). |
| |
| To address this, several folks have created daughter boards for the LCD module |
| which present a two-wire I2C interface. Generally, folks call these interface |
| boards an 'lcd backpack'. A large class of them (and in particular, the very |
| inexpensive ones found on ebay, q.v. google "ebay i2c lcd backpack"; they're |
| usually about $USD 1), use the same design: a PCF8574 I2C IO expander. |
| Variations occur in mapping GPIO line to LCD pins, but otherwise the |
| expectation is that you control the LCD at a low-level tweaking the lines |
| ("byte-banging"?) |
| |
| My original motivation for producing this was to simply serve as a test device |
| for some I2C driver work I was doing, but it occurred to me that it may be |
| useful to others, given the popularity of the 'lcd backpack', so I cleaned up |
| the code and made it general to support all the variations on the market, and |
| also to adopt the NuttX notion of a 'segment lcd codec', which is used to |
| transport escape sequences (for doing things like clearing the display, turning |
| on/off the cursor, etc), and also the standard ioctls. |
| |
| I believe it should support all "lcd backpack"s on the market (because you can |
| specify the particular wiring), and all HD44780-based LCD modules in 1-line, |
| 2-line, and 4-line configurations (except 4x40 -- this is not supported by |
| the hardware). |
| |
| This module should be cpu-architecture-neutral, and work with any standard I2C |
| bus object. At the time of this writing it has been tested only with the |
| STM32L4 chip and with the 'MJKDZ' backpack board with a 16x2 lcd module. |
| |
| Usage |
| ===== |
| |
| The driver is contained in the files pcf8574_lcd_backpack.h and |
| pcf8574_lcd_backpack.c; you can include these in your build in whatever manner |
| you choose (e.g. copy them into your board's src directory, and reference them |
| in the Makefile). |
| |
| As with other I2C devices, you first instantiate the I2C bus, and then |
| instantiate the driver on that bus. When instantiating the driver, you also |
| provide a configuration 'descriptor' that specified board wiring and LCD |
| format parameters. You can explicitly specify any wiring configuration, and |
| some known popular boards are already #defined for your convenience. |
| |
| E.g.: |
| |
| #include <nuttx/i2c/i2c_master.h> |
| #include "pcf8574_lcd_backpack.h" |
| |
| #define MJKDZ_I2C_PORTNO 1 |
| #define MJKDZ_DEVICE_NAME "/dev/lcd0" |
| |
| FAR struct i2c_master_s* g_i2cMJKDZ = NULL; |
| |
| .... |
| |
| g_i2cMJKDZ = stm32l4_i2cbus_initialize(MJKDZ_I2C_PORTNO); |
| |
| .... |
| |
| struct pcf8574_lcd_backpack_config_s cfg = LCD_I2C_BACKPACK_CFG_MJKDZ; |
| cfg.rows = 2; |
| cfg.cols = 16; |
| |
| ret = pcf8574_lcd_backpack_register(MJKDZ_DEVICE_NAME, g_i2cMJKDZ, &cfg); |
| |
| If all the above executes successfully, you should wind up with a character |
| device node "/dev/lcd0". Applications can open that node and write() to it, |
| and the shell can emit data to it (e.g. 'echo Hi, there! > /dev/lcd0'). |
| |
| That is the basic configuration. Some additional configuration points are |
| worth noting. |
| |
| Specifying the I2C Address |
| -------------------------- |
| |
| The 'struct pcf8574_lcd_backpack_config_s' shown above is initialized using |
| the convenience macro LCD_I2C_BACKPACK_CFG_MJKDZ. Those convenience macros |
| use the default I2C address for the board, however many of the boards allow |
| altering the address (by jumpers, or removing pullups). You need to specify |
| the correct address for your board's physical configuration. You can do that |
| via |
| |
| cfg.addr = 0x23; |
| |
| Specifying the LCD Display Format |
| --------------------------------- |
| |
| The LCD modules cannot 'self-describe' their physical format, so it must be |
| explicitly provided to the driver. The correct format is important for |
| computing screen coordinate addresses and for scrolling and line wrap. |
| |
| In the example above, the screen format is specifying by setting the |
| fields in the configuration descriptor: |
| |
| cfg.rows = 2; |
| cfg.cols = 16; |
| |
| The lcd backpack can accommodate all known 1-line and 2-line displays, and |
| 4-line displays up to 4 x 32. Explicitly, the 4 x 40 /cannot/ be supported |
| because it has an important hardware difference (it is actually two 4x20 |
| controllers, and the LCD backpack does not have the wiring for the |
| second controller's 'E' line). This is a hardware limitation of the |
| lcd backpack, rather than the driver. |
| |
| Specifying Unknown/New Backpacks |
| -------------------------------- |
| |
| The descriptor initializer macros in the form LCD_I2C_BACKPACK_CFG_xxx |
| located near the top of pcf8574_lcd_backpack.h are provided for convenience. |
| However, their use is not required, and it can be useful to initialize the |
| descriptor with explicit values, say, for custom or unknown boards. |
| |
| The format of this descriptor is conscientiously chosen to be semantically |
| similar to an equivalent initialization mechanism popular in the Arduino |
| community used in their LCD support libraries. It specifies: |
| |
| * I2C address |
| * pin mapping for data lines |
| * pin mapping for control lines |
| * pin mapping for backlight control line |
| * polarity sense of backlight control line |
| |
| and we add to that |
| |
| * (row, column) size of display |
| |
| (the Arduino libraries specify display size at a different point in code) |
| You should be able to readily port a functional Arduino project by cutting- |
| and-pasting the sequence of numbers that are the pin defs for the lcd |
| backpack you are using. |
| |
| Special Features |
| ================ |
| |
| Codec |
| ----- |
| |
| The driver supports the NuttX 'segment lcd codec', which facilitates the |
| encoding of control functions into the write() stream. These can be used |
| to clear the display, move the cursor, etc. For details, q.v. |
| |
| nuttx/lcd/slcd_codec.h |
| |
| Ioctl |
| ----- |
| |
| The driver supports the NuttX ioctl definitions for segment lcd. Q.v. |
| |
| nuttx/lcd/slcd_ioctl.h |
| |
| Additionally, the ioctl SLCDIOC_CREATECHAR is provided to allow the |
| creation of custom characters. |
| |
| The HD44780 devices generally support the creation of 8 custom |
| characters, which map to code points 0-7. The characters are 5x8 |
| pixels (with the expectation that the last row is left blank, to |
| accommodate the underscore cursor, though this is not strictly a |
| requirement). |
| |
| The SLCDIOC_CREATECHAR ioctl takes a parameter, which is a struct |
| consisting of the character index being programmed (0-7) and the |
| 8-byte bitmap of the character image. The bitmap is constructed |
| with each byte representing a row, from top row to bottom row. |
| Each row is imaged left to right, MSB to LSB, right-justified (i.e., |
| bit 4 is leftmost, bit 0 is rightmost, and bits 7-5 are unused). |
| |
| You may reference these characters simply by including them in |
| the data you write() to the device, e.g. |
| |
| write(fd, "\x01,\x02Hi, there!\n", 13); |
| |
| Example of programming a character image: |
| |
| static const struct slcd_createchar_s custom_char = |
| { 4, { 0x04, 0x0e, 0x15, 0x04, 0x04, 0x04, 0x04, 0x00 } }; /* up arrow */ |
| |
| ret = ioctl(fd, SLCDIOC_CREATECHAR, (unsigned long)custom_char); |
| |
| Now character '\x04' will display as an 'up arrow'. |
| |
| Note, you might consider avoiding the use of code point 0x00 unless |
| you absolutely need it, because the embedded nul character can cause |
| problems. The driver, and write() apis are binary, and unaffected, |
| but things like printf() and puts() assume C-style strings, and are |
| affected. |
| |
| Troubleshooting |
| =============== |
| |
| * Check your I2C address. turn on debugging output so you can see |
| bus timeouts that suggest a non-responsive slave. |
| * Check your board wiring and configuration specification. Buzz |
| out the lines if you have to. |
| * Remember to set the (ros,cols) geometry in pcf8574_lcd_backpack_config_s |
| before registration of the driver, since this cannot be determined |
| programmatically. |
| * If the driver registration step seems to 'hang' it could be the I2C |
| driver performing retries due to no response from the LCD backpack. Check |
| the address. Turning on debug output for I2C can help make this visible. |
| * Don't forget to check the 'contrast' potentiometer. The voltage at the |
| central wiper should be approximately 0.3 V - 2.4 V, but the actual value |
| is is dependent on the physics of the attached LCD module. The useful |
| range of voltages at this pin for any given LCD is quite narrow, and |
| outside that range there will be nothing visible on the display, so most |
| of the turn range of the pot is useless. It's less 'contrast' and |
| more 'LCD segment drive bias'. |