Загрузка данных
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#define MSG_SIZE 17
#define QUEUE_MAX_MSGS 10
//#define LCD_THREAD_STACK 1024
#define LCD_THREAD_STACK 2048
#define LCD_THREAD_PRIO 14
static uint8_t cur_col = 0;
/* Get PCF8574 from dts */
static const struct device *pcf_dev = DEVICE_DT_GET(DT_NODELABEL(pcf8574));
#define LCD_RS (1 << 0) // Port 0
#define LCD_RW (1 << 1) // Port 1
#define LCD_E (1 << 2) // Port 2
#define LCD_BL (1 << 3) // Port 3 (Backlight)
#define LCD_DATA_MASK 0xF0 // Port 4-7 (D4-D7)
/* Global var for lcd backlight */
static uint8_t backlight_state = LCD_BL;
//LCD Message
struct lcd_msg_t {
char text[MSG_SIZE];
uint8_t row;
uint8_t col;
uint8_t mode;
};
K_MSGQ_DEFINE(lcd_msgq, sizeof(struct lcd_msg_t), QUEUE_MAX_MSGS, 4);
/* Send 4 bit data*/
void lcd_send_nibble(uint8_t nibble, uint8_t rs_flag)
{
// Set byte: 4 bits - data, 4 bits- backlight and control
uint8_t port_val = (nibble << 4) | rs_flag | backlight_state;
// RW always 0 (write mode)
port_val &= ~LCD_RW;
// 1. Set data and RS, E -> 0
//gpio_port_set_masked_raw(pcf_dev, 0xFF, port_val);
gpio_port_set_bits_raw(pcf_dev, port_val);
gpio_port_clear_bits_raw(pcf_dev, ~port_val & 0xFF);
k_busy_wait(1);
// 2. Enable (E = 1) for set data on display
//gpio_port_set_masked_raw(pcf_dev, 0xFF, port_val | LCD_E);
gpio_port_set_bits_raw(pcf_dev, LCD_E);
k_busy_wait(1);
// 3. Reset Enable (E = 0)
//gpio_port_set_masked_raw(pcf_dev, 0xFF, port_val);
gpio_port_clear_bits_raw(pcf_dev, LCD_E);
k_busy_wait(50);
}
/* Send 8 bit function */
void lcd_send_byte(uint8_t value, uint8_t rs_flag)
{
lcd_send_nibble(value >> 4, rs_flag);
lcd_send_nibble(value & 0x0F, rs_flag);
}
void lcd_command(uint8_t cmd) { lcd_send_byte(cmd, 0); }
void lcd_data(uint8_t data) { lcd_send_byte(data, LCD_RS); }
/* Init display 1602A in 4-bit mode */
int lcd_init(void)
{
int i,ret;
if(!device_is_ready(pcf_dev)) {
printf("Error: No i2c PCF device\n");
return -ENODEV;
}
for(i=0; i < 8; i++)
{
ret = gpio_pin_configure(pcf_dev, i, GPIO_OUTPUT_INACTIVE);
if(ret < 0)
{
printf("Error gpio_pin_configure %d err=%d\n",i,ret);
//return ret;
}
}
k_msleep(50);
// Set controller HD44780 to 4-bit mode
lcd_send_nibble(0x03, 0);
k_msleep(5);
lcd_send_nibble(0x03, 0);
k_busy_wait(150);
lcd_send_nibble(0x03, 0);
k_busy_wait(150);
lcd_send_nibble(0x02, 0);
k_msleep(2);
// Set display parameters
lcd_command(0x28); // 4-bit mode, 2 lines, font 5x8
lcd_command(0x0C); // Display ON, Cursor OFF, Blinking OFF
lcd_command(0x06); // Autoincrement cursor
lcd_command(0x01); // Clean display
k_msleep(2);
return 1;
}
/* Set cursor position */
void lcd_set_cursor(uint8_t col, uint8_t row)
{
uint8_t row_offsets[] = {0x00, 0x40};
lcd_command(0x80 | (col + row_offsets[row]));
cur_col = col;
}
/* Print line */
void lcd_print(const char *str)
{
uint8_t count = cur_col;
while (*str && count < 16) {
lcd_data(*str++);
count++;
}
}
//mode = 0 - clear 16 symbols, add data
//mode = 1 - only clear 16 symbols
//mode = 2 - append mode data without clear
void lcd_render_thread(void *p1, void *p2, void *p3)
{
struct lcd_msg_t msg;
uint8_t i = 0;
while (1) {
// Wait message queue
if (k_msgq_get(&lcd_msgq, &msg, K_FOREVER) == 0)
{
if(msg.mode != 2) //not append mode
{
lcd_set_cursor(msg.col, msg.row);
for(i=0; i < 16 - msg.col; i++)
lcd_data(' ');
}
if(msg.mode != 1)
{
lcd_set_cursor(msg.col, msg.row);
lcd_print(msg.text);
}
k_msleep(50);
}
}
}
K_THREAD_DEFINE(lcd_thread_id, LCD_THREAD_STACK, lcd_render_thread, NULL, NULL, NULL, LCD_THREAD_PRIO, 0, 0);
int safe_lcd_print(uint8_t col, uint8_t row, const char *text, uint8_t mode)
{
struct lcd_msg_t msg;
msg.col = col;
msg.row = row;
msg.mode = mode;
memset(msg.text, 0, MSG_SIZE);
strncpy(msg.text, text, MSG_SIZE - 1);
msg.text[MSG_SIZE - 1] = '\0';
// Set to queue, if queue is full - don't wait (K_NO_WAIT)
return k_msgq_put(&lcd_msgq, &msg, K_NO_WAIT);
}
Иногда происходит:
[00:00:39.854,000] <err> os: ***** MPU FAULT *****
[00:00:39.854,000] <err> os: Instruction Access Violation
[00:00:39.854,000] <err> os: r0/a1: 0xff860000 r1/a2: 0xff6c0000 r2/a3: 0xff960001
[00:00:39.854,000] <err> os: r3/a4: 0xff8b0000 r12/ip: 0xff7e0000 r14/lr: 0xff6d0001
[00:00:39.854,000] <err> os: xpsr: 0xff0c0000
[00:00:39.854,000] <err> os: s[ 0]: 0xff7f0000 s[ 1]: 0xff9a0000 s[ 2]: 0xffb60000 s[ 3]: 0xffcd0001
[00:00:39.854,000] <err> os: s[ 4]: 0xffae0002 s[ 5]: 0xffc30000 s[ 6]: 0xffca0000 s[ 7]: 0xffeb0000
[00:00:39.854,000] <err> os: s[ 8]: 0xffe70001 s[ 9]: 0xffed0002 s[10]: 0xffd90001 s[11]: 0xfff10000
[00:00:39.854,000] <err> os: s[12]: 0x00050000 s[13]: 0xffe4ffff s[14]: 0x00000001 s[15]: 0x00000000
[00:00:39.854,000] <err> os: fpscr: 0x80023ae0
[00:00:39.854,000] <err> os: Faulting instruction address (r15/pc): 0xff8ffffe
[00:00:39.854,000] <err> os: >>> ZEPHYR FATAL ERROR 20: Unknown error on CPU 0
[00:00:39.854,000] <err> os: Current thread: 0x80008600 (lcd_thread_id)
[00:00:39.862,000] <err> os: Halting system
Иногда всё хорошо