0
\$\begingroup\$

As part of an alarm clock project, I am trying to interface a 16x2 I2C LCD with an STM32F103RB microcontroller. The LCD uses an I2C backpack and only utilizes D7-D4 meaning 4-bit mode must be used. However, I am having trouble getting the device initialized in 4-bit mode. When I attempt to print a single character to the LCD, it prints two characters. For example when sending 'c', a 'o' and '?' get printed. Also, when sending a command to clear the display no characters are cleared which lead me to believe this is the issue. I have tested similar code on a Raspberry Pi, and the commands and characters are written properly to the LCD controller. The LCD model is the LCD1602. The c code I am using to drive the display is shown below:

/*
 * lcd1602.c
 *
 *  Created on: Jul 24, 2020
 *      Author: someone
 */
#include "lcd6502.h"

static uint8_t addresses[32] = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
        0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
        0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F
};

void writeNibble(I2C_HandleTypeDef *hi2c, uint8_t reg, uint8_t nibble) {
    uint8_t setup = 0x00;
    uint8_t data = 0x00;
    uint8_t closing = 0x00;

    if(reg == 1) {
        setup = 0b00001101;
        HAL_I2C_Master_Transmit(hi2c, LCD6502_ADDR, &setup, strlen(setup), 100);
        HAL_Delay(10);
        data = (nibble << 4) | 0b00001101;
        HAL_I2C_Master_Transmit(hi2c, LCD6502_ADDR, &data, strlen(data), 100);
        HAL_Delay(10);
        closing = (nibble << 4) | 0b00001001;
        HAL_I2C_Master_Transmit(hi2c, LCD6502_ADDR, &closing, strlen(closing), 100);
    } else if (reg == 0) {
        setup = 0b00001100;
        HAL_I2C_Master_Transmit(hi2c, LCD6502_ADDR, &setup, strlen(setup), 100);
        HAL_Delay(1);
        data = (nibble << 4) | 0b00001100;
        HAL_I2C_Master_Transmit(hi2c, LCD6502_ADDR, &data, strlen(data), 100);
        HAL_Delay(1);
        closing = (nibble << 4) | 0b00001000;
        HAL_I2C_Master_Transmit(hi2c, LCD6502_ADDR, &closing, strlen(closing), 100);
    }
}

void writeByte(I2C_HandleTypeDef *hi2c, uint8_t reg, uint8_t byte) {
    uint8_t highNibble = 0x0F & (byte >> 4);
    uint8_t lowNibble = 0x0F & byte;
    writeNibble(hi2c, reg, highNibble);
    HAL_Delay(5);
    writeNibble(hi2c, reg, lowNibble);
}

void initLCD(I2C_HandleTypeDef *hi2c) {
    writeNibble(hi2c, CR, 0b00000010);
    writeByte(hi2c, CR, 0b00101000);
    writeByte(hi2c, CR, 0b00001111);
    writeByte(hi2c, CR, 0b00000001);
}

uint8_t readNibble(I2C_HandleTypeDef *hi2c, uint8_t reg) {
    uint8_t setup = 0x00;
    uint8_t data = 0x00;
    uint8_t closing = 0x00;
    uint8_t byte = 0x00;

    if(reg == 1) {
        setup = 0b00001111;
        HAL_I2C_Master_Transmit(hi2c, LCD6502_ADDR, &setup, strlen(setup), 100);
        HAL_Delay(1);
        HAL_I2C_Master_Receive(hi2c, LCD6502_ADDR, &data, strlen(data), 100);
        HAL_Delay(1);
        closing = 0b00001011;
        HAL_I2C_Master_Transmit(hi2c, LCD6502_ADDR, closing, strlen(closing), 100);
    } else if (reg == 0) {
        setup = 0b00001110;
        HAL_I2C_Master_Transmit(hi2c, LCD6502_ADDR, &setup, strlen(setup), 100);
        HAL_Delay(1);
        HAL_I2C_Master_Receive(hi2c, LCD6502_ADDR, data, strlen(data), 100);
        HAL_Delay(1);
        closing = 0b00001010;
        HAL_I2C_Master_Transmit(hi2c, LCD6502_ADDR, closing, strlen(closing), 100);
    }
    return data;
}

uint8_t readByte(I2C_HandleTypeDef *hi2c, uint8_t reg) {
    uint8_t highNibble = 0x00;
    uint8_t lowNibble = 0x00;
    uint8_t byte = 0x00;
    highNibble = readNibble(hi2c, reg);
    HAL_Delay(1);
    lowNibble = readNibble(hi2c, reg);
    byte = (highNibble << 4) | lowNibble;
    return byte;
}

void lcd_putc(I2C_HandleTypeDef *hi2c, uint8_t c) {
    writeByte(hi2c, DR, c);
}

void lcd_puts(I2C_HandleTypeDef *hi2c, uint8_t *s) {
//  uint8_t address = 0x00;
    while(*s != '\0') {
//      if(readByte(hi2c, 0) & 0b01111111 == 0x0F) { // ignore the busy flag
//          // Set the DDRAM address
//          writeByte(hi2c, 0, )
//      }
        lcd_putc(hi2c, *s);
        s++;
    }
}

\$\endgroup\$
9
  • \$\begingroup\$ LCD's normally have data mode and command mode. If you are sending a command to clear but it's not working leads me to believe that you haven't entered commands mode. The fact that data is being displayed, means the LCD is in data mode. Try changing the mode. It might be possible that your clear command is being displayed as '?'. I would check these things. \$\endgroup\$
    – varun
    Jul 27, 2020 at 18:25
  • 2
    \$\begingroup\$ Don't use strlen to things that are not strings. \$\endgroup\$
    – Justme
    Jul 27, 2020 at 18:56
  • \$\begingroup\$ That one. Maybe you meant to use sizeof(setup) etc. \$\endgroup\$ Jul 27, 2020 at 20:55
  • \$\begingroup\$ @Justme Thanks, this fixed the problem. I believe I was creating a segmentation fault on the MCU with the strlen calls. \$\endgroup\$ Jul 27, 2020 at 22:13
  • 1
    \$\begingroup\$ You didn't say it was faulting the MCU. That would have been imoortant info. I am rather surprised it was the only issue as the init sequence is not what LCD controller datasheets suggest. It was just the most obvious thing why it did not work. \$\endgroup\$
    – Justme
    Jul 28, 2020 at 4:58

1 Answer 1

0
\$\begingroup\$

Problem is using strlen on bytes, if you want to send one byte just use 1 as the length.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.