I know there's been a dozen posts on this, I've scoured them all and could find nothing to fix the problem; but I apologize in advance if this seems redundant.
I have a 20x4 parallel lcd (from adafruit) connected to a MCP23017. Port A is controlling an 8 switch relay, and works perfect (I can control each relay independently, works completely as expected). Port B is supposed to control the lcd, but I'm having problems. I haven't used a pre-built 'backpack' or library mostly because I want to learn.
I've wired it as follows:
GPB0 -> RS
GPB1 -> R/W
GPB2 -> E
GPB4-GPB7 -> D4-D7
Backlight turns on, potentiometer works, constrast is adjusted as expected. Yet try as I might I can't seem to send a command to the lcd or display. Currently what I have is:
void WriteMCP(uint8_t addr, uint8_t reg, uint8_t value) {
Wire.beginTransmission(addr);
Wire.write(reg);
Wire.write(value);
Wire.endTransmission();
}
void LCDPulse(uint8_t cmd) {
delay(5);
WriteMCP(0x20, GPIOB, cmd);
delay(5);
WriteMCP(0x20, GPIOB, cmd | 0x04);
delay(5);
WriteMCP(0x20, GPIOB, cmd);
delay(5);
}
void LCDInit() {
WriteMCP(0x20, IODIRB, 0x00); // set ports to output
WriteMCP(0x20, GPIOB, 0x00); // zero outputs
// power on
delay(20);
WriteMCP(0x20, GPIOB, 0x30);
delay(20);
WriteMCP(0x20, GPIOB, 0x30);
delay(20);
WriteMCP(0x20, GPIOB, 0x30);
WriteMCP(0x20, GPIOB, 0x20); // 4 bit mode
// function set
LCDPulse(0x20);
LCDPulse(0x00);
delay(2000);
// display on
LCDPulse(0x00);
LCDPulse(0xF0);
delay(2000);
// display clear
LCDPulse(0x00);
LCDPulse(0x10);
delay(2000);
// write text
LCDPulse(0xF1);
LCDPulse(0xF0);
}
I've read through the HD44780U datasheet multiple times, I've looked at numerous websites with examples, I've even downloaded other lcd/i2c libraries and looked at the source code to see where I went wrong/what I'm missing but to no avail.
I've checked each connection between the mcp and lcd repeatedly with a multimeter to ensure each pin/solder connection is correct. The relay connected to Port A works fine.
The only thing I saw differently between my attempts and others was when writing the MCP, the register was never set. For example in LiquidCrystal_I2C they use:
#define printIIC(args) Wire.write(args)
// ...
void LiquidCrystal_I2C::expanderWrite(uint8_t _data){
Wire.beginTransmission(_Addr);
printIIC((int)(_data) | _backlightval);
Wire.endTransmission();
}
I'm not sure how this works at all, from what I've seen in examples for the MCP23017, and what I understand of the MCP23017's datasheet, each beginTransmission() must specify the register before writing data to it. Or maybe not? I'm not too sure at this point.
Any suggestions/ideas would be helpful.