How to run LCD display using I2C on Zephyr? #72745
Unanswered
hanabudimlic
asked this question in
Q&A
Replies: 2 comments
-
Hi @hanabudimlic! We appreciate you submitting your first issue for our open-source project. 🌟 Even though I'm a bot, I can assure you that the whole community is genuinely grateful for your time and effort. 🤖💙 |
Beta Was this translation helpful? Give feedback.
0 replies
-
CC @erwango @ajarmouni-st @FRASTM @gautierg-st @GeorgeCGV |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Describe the bug
I am trying to use 1602 display via I2C communication protocol in Zephyr using stm32f3 discovery board. The program fails during initialization and it prints on serial monitor "Status -5" i.e. I/O error. The 'lcdInit()' function calls 'lcdSendCommand()' function that calls Zephyr's 'i2c_write()' function who ultimately returns the error code. The similar code was used to establish desired behaviour using uVision and it worked with no errors, so I believe I am missing some kind of configuration here.
I didn't change anything in the device tree, so my overlay file looks like this:
i2c1: &i2c1 {
pinctrl-0 = <&i2c1_scl_pb6 &i2c1_sda_pb7>;
pinctrl-names = "default";
status = "okay";
clock-frequency = <I2C_BITRATE_FAST>;
};
This is my main:
/*
*/
#include <stdbool.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/printk.h>
#include <string.h>
#include <zephyr/drivers/i2c.h>
#include "../inc/i2c_lcd.h"
#define I2C_INST DT_NODELABEL(i2c1)
//static const struct i2c_dt_spec i2c = I2C_DT_SPEC_GET(i2c1);
const struct device *const i2c = DEVICE_DT_GET(I2C_INST);
int main(){
if (!device_is_ready(i2c)) {
printf("i2c is not ready!\n");
} else {
printf("i2c is ready\n");
}
lcdInit(i2c);
k_sleep(K_MSEC(1000));
printf("Checkpoint\n");
k_sleep(K_MSEC(1000));
char buf[] = "hello";
lcdSendString(i2c, buf);
while (1){
printk("Hello world\n");
k_sleep(K_MSEC(1000));
}
return 0;
}
And lastly my .c file for i2c communication to lcd:
#include "i2c_lcd.h"
#include <zephyr/sys/printk.h>
// LOG_MODULE_REGISTER(i2c_lcd);
#define SLAVE_ADDRESS_LCD 0x4E
void lcdSendCommand(const struct device *const i2c_dev, char cmd){
char data_u, data_l;
uint8_t data_t[4];
data_u = (cmd & 0xf0);
data_l = ((cmd << 4) & 0xf0);
data_t[0] = data_u | 0x0C; // en=1, rs=0
data_t[1] = data_u | 0x08; // en=0, rs=0
data_t[2] = data_l | 0x0C; // en=1, rs=0
data_t[3] = data_l | 0x08; // en=0, rs=0
int ret;
ret = i2c_write(i2c_dev, data_t, 4, SLAVE_ADDRESS_LCD);
printk("Status %d\n", ret);
}
void lcdSendData(const struct device *const i2c_dev, char data){
char data_u, data_l;
uint8_t data_t[4];
data_u = (data & 0xf0);
data_l = ((data << 4) & 0xf0);
data_t[0] = data_u | 0x0D; // en=1, rs=0
data_t[1] = data_u | 0x09; // en=0, rs=0
data_t[2] = data_l | 0x0D; // en=1, rs=0
data_t[3] = data_l | 0x09; // en=0, rs=0
i2c_write(i2c_dev, data_t, 4, SLAVE_ADDRESS_LCD);
}
void lcdClear(const struct device *const i2c_dev){
lcdSendCommand(i2c_dev, 0x80);
for (int i = 0; i < 70; i++)
{
lcdSendData(i2c_dev, ' ');
}
}
void lcdPutCur(const struct device *const i2c_dev, int row, int col){
switch (row){
case 0:
col |= 0x80;
break;
case 1:
col |= 0xC0;
break;
}
}
void lcdInit (const struct device *const i2c_dev){
// 4 bit initialization
k_sleep(K_MSEC(50)); // wait for >40ms
lcdSendCommand(i2c_dev, 0x30);
k_sleep(K_MSEC(5)); // wait for >4.1ms
lcdSendCommand(i2c_dev, 0x30);
k_sleep(K_USEC(100)); // wait for >100us
lcdSendCommand(i2c_dev, 0x30);
k_sleep(K_MSEC(10));
lcdSendCommand(i2c_dev, 0x20); // 4bit mode
k_sleep(K_MSEC(10));
// display initialization
lcdSendCommand(i2c_dev, 0x28); // Function set --> DL=0 (4 bit mode), N = 1 (2 line display) F = 0 (5x8 characters)
k_sleep(K_MSEC(1));
lcdSendCommand(i2c_dev, 0x08); // Display on/off control --> D=0,C=0, B=0 ---> display off
k_sleep(K_MSEC(1));
lcdSendCommand(i2c_dev, 0x01); // clear display
k_sleep(K_MSEC(1));
k_sleep(K_MSEC(1));
lcdSendCommand(i2c_dev, 0x06); // Entry mode set --> I/D = 1 (increment cursor) & S = 0 (no shift)
k_sleep(K_MSEC(1));
lcdSendCommand(i2c_dev, 0x0C); // Display on/off control --> D = 1, C and B = 0. (Cursor and blink, last two bits)
}
void lcdSendString(const struct device *const i2c_dev, char *str){
while (*str)
lcdSendData(i2c_dev, *str++);
}
Expected behavior
I expect the program to print 'hello' on LCD display.
Impact
This issue stopped the progress with my current work.
Environment (please complete the following information):
OS: Ubuntu
Board: STM32F3 DISCOVERY
Beta Was this translation helpful? Give feedback.
All reactions