correct logic hazard in latch and load nybble; was transitioning control lines at the same time as enable, causing spurious behaviour on less-tolerant displays

improve timing parameters in init sequences for better display compatibility

correct (row,col) -> address calculation; affects 4-line displays

update comments in header and readme
This commit is contained in:
ziggurat29
2016-05-29 11:09:00 -05:00
parent 4cc722aa1a
commit 4643fcdfd8
3 changed files with 43 additions and 21 deletions
+23 -11
View File
@@ -63,9 +63,9 @@
/* timing characteristics of the LCD interface */ /* timing characteristics of the LCD interface */
#define DELAY_US_NYBBLE0 200 #define DELAY_US_NYBBLE0 20
#define DELAY_US_NYBBLE1 100 #define DELAY_US_NYBBLE1 10
#define DELAY_US_WRITE 35 #define DELAY_US_WRITE 40
#define DELAY_US_HOMECLEAR 1500 #define DELAY_US_HOMECLEAR 1500
/* HD44780 commands */ /* HD44780 commands */
@@ -259,7 +259,7 @@ static inline uint8_t rc2addr(FAR struct pcf8574_lcd_dev_s *priv,
* of first line, and fourth line is a continuation of second. * of first line, and fourth line is a continuation of second.
*/ */
return (row - 2) * 0x40 + (col - priv->cfg.cols); return (row - 2) * 0x40 + (col + priv->cfg.cols);
} }
} }
@@ -383,9 +383,14 @@ static void latch_nybble(FAR struct pcf8574_lcd_dev_s *priv, uint8_t nybble,
en_bit = 1 << priv->cfg.en; en_bit = 1 << priv->cfg.en;
rs_bit = rs ? (1 << priv->cfg.rs) : 0; rs_bit = rs ? (1 << priv->cfg.rs) : 0;
/* Put the nybble, preserving backlight, reset R/~W and set EN and maybe RS */ /* Put the nybble, preserving backlight, reset R/~W and maybe RS */
lcddata = prepare_nybble(priv, nybble) | priv->bl_bit | en_bit | rs_bit; lcddata = prepare_nybble(priv, nybble) | priv->bl_bit | rs_bit;
pca8574_write(priv, lcddata);
/* Now set EN */
lcddata |= en_bit;
pca8574_write(priv, lcddata); pca8574_write(priv, lcddata);
up_udelay(DELAY_US_NYBBLE0); /* setup */ up_udelay(DELAY_US_NYBBLE0); /* setup */
@@ -419,9 +424,14 @@ static uint8_t load_nybble(FAR struct pcf8574_lcd_dev_s *priv, bool rs)
rs_bit = rs ? (1 << priv->cfg.rs) : 0; rs_bit = rs ? (1 << priv->cfg.rs) : 0;
rw_bit = 1 << priv->cfg.rw; rw_bit = 1 << priv->cfg.rw;
/* Put highs on the data lines, preserve, set R/~W and set EN and maybe RS */ /* Put highs on the data lines, preserve, set R/~W and maybe RS */
lcddata = prepare_nybble(priv, 0x0f) | priv->bl_bit | en_bit | rw_bit | rs_bit; lcddata = prepare_nybble(priv, 0x0f) | priv->bl_bit | rw_bit | rs_bit;
pca8574_write(priv, lcddata);
/* Now set EN */
lcddata |= en_bit;
pca8574_write(priv, lcddata); pca8574_write(priv, lcddata);
up_udelay(DELAY_US_NYBBLE0); /* setup */ up_udelay(DELAY_US_NYBBLE0); /* setup */
@@ -538,7 +548,7 @@ static void lcd_init(FAR struct pcf8574_lcd_dev_s *priv)
{ {
/* Wait for more than 15 ms after Vcc for the LCD to stabilize */ /* Wait for more than 15 ms after Vcc for the LCD to stabilize */
usleep(20000); usleep(50000);
/* Perform the init sequence. This sequence of commands is constructed so /* Perform the init sequence. This sequence of commands is constructed so
* that it will get the device into nybble mode irrespective of what state * that it will get the device into nybble mode irrespective of what state
@@ -548,7 +558,7 @@ static void lcd_init(FAR struct pcf8574_lcd_dev_s *priv)
* the remainder of operations. * the remainder of operations.
*/ */
/* Send Command 0x30, set 8-bit mode, and wait > 4.1 ms*/ /* Send Command 0x30, set 8-bit mode, and wait > 4.1 ms */
latch_nybble(priv, 0x30>>4, false); latch_nybble(priv, 0x30>>4, false);
usleep(5000); usleep(5000);
@@ -556,15 +566,17 @@ static void lcd_init(FAR struct pcf8574_lcd_dev_s *priv)
/* Send Command 0x30, set 8-bit mode, and wait > 100 us */ /* Send Command 0x30, set 8-bit mode, and wait > 100 us */
latch_nybble(priv, 0x30>>4, false); latch_nybble(priv, 0x30>>4, false);
usleep(200); usleep(5000);
/* Send Command 0x30, set 8-bit mode */ /* Send Command 0x30, set 8-bit mode */
latch_nybble(priv, 0x30>>4, false); latch_nybble(priv, 0x30>>4, false);
usleep(200);
/* now Function set: Set interface to be 4 bits long (only 1 cycle write for the first time). */ /* now Function set: Set interface to be 4 bits long (only 1 cycle write for the first time). */
latch_nybble(priv, 0x20>>4, false); latch_nybble(priv, 0x20>>4, false);
usleep(5000);
/* Function set: DL=0;Interface is 4 bits, N=1 (2 Lines), F=0 (5x8 dots font) */ /* Function set: DL=0;Interface is 4 bits, N=1 (2 Lines), F=0 (5x8 dots font) */
+14 -7
View File
@@ -225,7 +225,7 @@ Example of programming a character image:
Now character '\x04' will display as an 'up arrow'. Now character '\x04' will display as an 'up arrow'.
Note, you might consider avoiding the use of code point 0x00 unless Note, you might consider avoiding the use of code point 0x00 unless
absolutely needed, because the embedded nul character can cause you absolutely need it, because the embedded nul character can cause
problems. The driver, and write() apis are binary, and unaffected, problems. The driver, and write() apis are binary, and unaffected,
but things like printf() and puts() assume C-style strings, and are but things like printf() and puts() assume C-style strings, and are
affected. affected.
@@ -237,9 +237,16 @@ Troubleshooting
bus timeouts that suggest a non-responsive slave. bus timeouts that suggest a non-responsive slave.
* Check your board wiring and configuration specification. Buzz * Check your board wiring and configuration specification. Buzz
out the lines if you have to. out the lines if you have to.
* Con't forget to check the 'contrast' potentiometer. The voltage * Remember to set the (ros,cols) geometry in pcf8574_lcd_backpack_config_s
at the central wiper should be approximately 0.29 V. The useful before registration of the driver, since this cannot be determined
range of voltages at this pin is very narrow, and outside that programmatically.
range there will be nothing visible on the display, so most of the * If the driver registration step seems to 'hang' it could be the I2C
turn range of the pot is non-useful. Much of human life has been driver performing retries due to no response from the LCD backpack. Check
wasted in the rediscovery of this farcically idiotic 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 non-useful. It's less 'contrast' and
more 'LCD segment drive bias'.
+6 -3
View File
@@ -58,12 +58,15 @@
* Pretty much anything on the market except 4x40, which really consists of two * Pretty much anything on the market except 4x40, which really consists of two
* separate 2x40 controllers, and the I2C backpack doesn't support those due * separate 2x40 controllers, and the I2C backpack doesn't support those due
* to the second 'E' line being needed. * to the second 'E' line being needed.
* Additionally, you still need to set the (row,col) geometry explicitly, since
* there is not a means of determining this dynamically.
* Consider these 'informative'. * Consider these 'informative'.
* XXX Note, actual testing has been done on LCD_I2C_BACKPACK_CFG_MJKDZ only, * XXX Note, actual testing has been done on LCD_I2C_BACKPACK_CFG_MJKDZ
* the others come from online research. * and LCD_I2C_BACKPACK_CFG_SAINSMART only, the others come from online
* research.
*/ */
/* board marked 'mjkdz' */ /* board marked 'mjkdz' and Arduino-IIC-LCD GY-LCD-V1 */
#define LCD_I2C_BACKPACK_CFG_MJKDZ {0x20,4,5,6,0,1,2,3,7,false,0,0} #define LCD_I2C_BACKPACK_CFG_MJKDZ {0x20,4,5,6,0,1,2,3,7,false,0,0}