Hi there,
I’m busy porting the terrible Arduino LCD library over to NRF52. https://github.com/johnrickman/LiquidCrystal_I2C
It’s terrible as it uses CPU delays which cripple performance elsewhere. The version I’m doing uses peripherals only. Unfortunately I’m having a spot of bother getting anything but corruption onto the screen. The hardware and I2C side are fine but what I’m sending isn’t. Most likely I’ve borked either the timings during init or the commands. One area is the library above is actually writing 6 bytes as part of the ‘4 bit mode’ whereas other libraries are writing 4 bytes.
Not shown here is the code which ensures there’s 50us between commands/data in 4-bit mode but this is only uses right at the end and it’s broken before then.
Are there any HD44780 experts here that can spot a problem?
// commands
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// flags for display entry mode
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// flags for display on/off control
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// flags for display/cursor shift
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// flags for function set
#define LCD_FUNCTIONSET 0x20
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// flags for backlight control
#define LCD_BACKLIGHT 0x08
#define LCD_CMD_EN 0b100 // Enable bit
#define LCD_CMD_RW 0b10 // Read/Write bit
#define LCD_CMD_RS 0b1 // Register select bit
static void lcdTransactionStart (void) {
dmaBuffer.locked = 1;
dmaBuffer.writeBuffer = getNextBuffer(dmaBuffer.writeBuffer);
}
static void lcdTransactionEnd (void) {
dmaBuffer.locked = 0;
if (!dmaBuffer.writing) {
__startTransfer();
}
}
static void lcdTransactionWrite (uint8_t* data, uint8_t size) {
memcpy(&dmaBuffer.writeBuffer->data, data, size);
dmaBuffer.writeBuffer->size += size;
}
static void send (uint8_t data, uint8_t mode) {
uint8_t packet[4];
uint8_t focus = data & 0xF0;
packet[0] = focus | mode | LCD_CMD_EN;
packet[1] = focus | mode;
focus = (data << 4) & 0xF0;
packet[2] = focus | mode | LCD_CMD_EN;
packet[3] = focus | mode;
lcdTransactionWrite(&packet[0], 4);
}
static void lcdTransactionAppendCommand (uint8_t data) {
send(data, 0);
}
static void lcdTransactionAppendChar (uint8_t data) {
send(data, LCD_CMD_RS);
}
void lcdTransactionAppendString (char *str) {
while (*str) {
lcdTransactionAppendChar(*str++);
}
}
// use on init or one off commands
static void lcdCmd4 (uint8_t cmd) {
lcdTransactionStart();
lcdTransactionAppendCommand(cmd);
lcdTransactionEnd();
while (dmaBuffer.writing) {}
nrf_delay_ms(1);
}
void lcdInit (void) {
dmaBuffer.transferBuffer = &dmaBuffer.buffers[0];
dmaBuffer.writeBuffer = &dmaBuffer.buffers[BUFFER_ARRAY-1];
// 8 bit mode
nrf_delay_ms(100); // wait for >40ms
lcdCmd4(LCD_FUNCTIONSET|LCD_8BITMODE);
nrf_delay_ms(4); // wait for >4.1ms
lcdCmd4(LCD_FUNCTIONSET|LCD_8BITMODE);
nrf_delay_ms(4); // wait for >4.1ms
lcdCmd4(LCD_FUNCTIONSET|LCD_8BITMODE);
nrf_delay_ms(1);
// 4 bit mode
lcdCmd4(LCD_FUNCTIONSET|LCD_4BITMODE);
// display initialisation
lcdCmd4(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_2LINE);
lcdCmd4(LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
lcdCmd4(LCD_CLEARDISPLAY);
nrf_delay_ms(2000);
lcdCmd4(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
lcdCmd4(LCD_RETURNHOME);
nrf_delay_ms(2000);
}