Загрузка данных


#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>

#define MSG_SIZE 16
#define QUEUE_MAX_MSGS 10
//#define LCD_THREAD_STACK 1024
//#define LCD_THREAD_STACK 2048
#define LCD_THREAD_STACK 4096
//#define LCD_THREAD_STACK 5120

#define LCD_THREAD_PRIORITY 13

/* 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)

#define LCD_GPIO_PORT_RAW

/* 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;
    uint8_t text_size;
};
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; 

    //k_sched_lock();
    // 1. Set data and RS, E -> 0
#ifdef LCD_GPIO_PORT_RAW
    gpio_port_set_masked_raw(pcf_dev, 0xFF, port_val);
#else
    gpio_port_set_bits_raw(pcf_dev, port_val);
    gpio_port_clear_bits_raw(pcf_dev, ~port_val & 0xFF);
#endif
    k_busy_wait(1);

    // 2. Enable (E = 1) for set data on display
#ifdef LCD_GPIO_PORT_RAW
    gpio_port_set_masked_raw(pcf_dev, 0xFF, port_val | LCD_E);
#else
    gpio_port_set_bits_raw(pcf_dev, LCD_E);
#endif
    k_busy_wait(1);

    // 3. Reset Enable (E = 0)
#ifdef LCD_GPIO_PORT_RAW
    gpio_port_set_masked_raw(pcf_dev, 0xFF, port_val);
#else
    gpio_port_clear_bits_raw(pcf_dev, LCD_E);
#endif
    //k_sched_unlock();
    k_busy_wait(5);
}

/* Send 8 bit function */
void lcd_send_byte(uint8_t value, uint8_t rs_flag)
{
    printf("[%c]\n",value);
#ifndef MY_CODE
    return;
#endif
    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[2] = {0x00, 0x40};
    lcd_command(0x80 | (col + row_offsets[row]));
}

/* Print line */
void lcd_print(const char *str, uint8_t len)
{
    while (len && *str) {
        lcd_data(*str++);
        len--;
    }
}

void lcd_print_stack_size(int num, struct k_thread *current_thread)
{
    size_t unused, size;

    k_thread_stack_space_get(current_thread, &unused);
    size = current_thread->stack_info.size;
    printf("%d) LCD Stack: Used %zu / Total %zu bytes (Unused: %zu)\n", num, size - unused, size, unused);
}

//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;
    struct k_thread *current_thread;
    uint8_t i = 0;

    while (1) {
        // Wait message queue
        if (k_msgq_get(&lcd_msgq, &msg, K_FOREVER) == 0)
        {
            current_thread = k_current_get();
            printf("0) col=%d row=%d text=[%.15s] mode=%d\n",msg.col,msg.row,msg.text,msg.mode);
            lcd_print_stack_size(0, current_thread);
            if(msg.mode != 2) //not append mode
            {
                lcd_set_cursor(msg.col, msg.row);
                for(i=0; i < 16 - msg.col; i++)
                    lcd_data(' ');
            }
            lcd_print_stack_size(1, current_thread);
            printf("1) col=%d row=%d text=[%.15s] mode=%d\n",msg.col,msg.row,msg.text,msg.mode);
            if(msg.mode != 1)
            {
                lcd_set_cursor(msg.col, msg.row);
                lcd_print_stack_size(2, current_thread);
                printf("2) col=%d row=%d text=[%.15s] mode=%d text_size=%d\n",msg.col,msg.row,msg.text,msg.mode, msg.text_size);
                lcd_print(msg.text, msg.text_size);
            }
            lcd_print_stack_size(3, current_thread);
            printf("3) col=%d row=%d text=[%.15s] mode=%d\n",msg.col,msg.row,msg.text,msg.mode);
            //k_msleep(50);
            k_msleep(1);
        }
    }
}

K_THREAD_DEFINE(lcd_thread_id, LCD_THREAD_STACK, lcd_render_thread, NULL, NULL, NULL, LCD_THREAD_PRIORITY, 0, 0);

int safe_lcd_print(uint8_t col, uint8_t row, const char *text, uint8_t mode)
{
    struct lcd_msg_t msg;
    size_t len = MSG_SIZE;

#ifndef MY_CODE
    return 0;
#endif
    len = strlen(text);
    if(text == NULL || len <= 0)
        return 0;
    if(col >= 16)
        col = 15;
    if(row > 1)
        row = 1;
    msg.col = col;
    msg.row = row;
    msg.mode = mode;
    if(len >= MSG_SIZE)
        len = MSG_SIZE - 1;
    msg.text_size = len;
    strncpy(msg.text, text, len);
    msg.text[len] = '\0';
    // Set to queue, if queue is full - don't wait (K_NO_WAIT)
    return k_msgq_put(&lcd_msgq, &msg, K_NO_WAIT);
}

kernel thread stacks
0x80009bb8 clock                            (real size 15360):  unused 14128    usage 1232 / 15360 ( 8 %)       prior=12        stack=0x80046000
0x80009918 pa_thread_hnd_out                (real size 4096):   unused 3512     usage  584 / 4096 (14 %)        prior=11        stack=0x80044f00
0x800097c8 i2s_thread_out                   (real size 4096):   unused 3752     usage  344 / 4096 ( 8 %)        prior=11        stack=0x80043e00
0x80009528 pa_thread_hnd_in                 (real size 4096):   unused 2400     usage 1696 / 4096 (41 %)        prior=11        stack=0x80041c00
0x80009678 i2s_thread_in                    (real size 4096):   unused 3784     usage  312 / 4096 ( 7 %)        prior=11        stack=0x80040b00
0x800093d8 pjsua_0                          (real size 20480):  unused 6856     usage 13624 / 20480 (66 %)      prior=12        stack=0x8003ba00
0x80009288 ev_thread                        (real size 1024):   unused  744     usage  280 / 1024 (27 %)        prior=12        stack=0x8003b500
0x80009138 media                            (real size 4096):   unused 2328     usage 1768 / 4096 (43 %)        prior=12        stack=0x8003a400
0x80008fe8 main_thread                      (real size 30720):  unused 14272    usage 16448 / 30720 (53 %)      prior=10        stack=0x8002b180
0x80009e20 usbd_msc                         (real size 1024):   unused  736     usage  288 / 1024 (28 %)        prior=-1        stack=0x80027080
0x80008580 lcd_thread_id                    (real size 4096):   unused    0     usage 4096 / 4096 (100 %)       prior=13        stack=0x80023280
0x80009f38 input                            (real size 1024):   unused  776     usage  248 / 1024 (24 %)        prior=14        stack=0x80027500
0x8000a358 rx_q[0]                          (real size 2048):   unused 1632     usage  416 / 2048 (20 %)        prior=-1        stack=0x80027d80
0x8000a200 net_mgmt                         (real size  896):   unused  656     usage  240 /  896 (26 %)        prior=-1        stack=0x80027980
0x8000a508 tcp_work                         (real size 1024):   unused  784     usage  240 / 1024 (23 %)        prior=-14       stack=0x80028600
0x80009d08 usbd                             (real size 1024):   unused  768     usage  256 / 1024 (25 %)        prior=-8        stack=0x80026c00
0x80008c10 shell_uart                       (real size 2048):   unused  916     usage 1132 / 2048 (55 %)        prior=14        stack=0x80026380
0x80007f18 kbd-matrix                       (real size 1024):   unused  712     usage  312 / 1024 (30 %)        prior=0         stack=0x80008100
0x8000abe0 sysworkq                         (real size 1664):   unused 1200     usage  464 / 1664 (27 %)        prior=-1        stack=0x8002a880
0x8000a650 udc_work_q                       (real size  512):   unused  272     usage  240 /  512 (46 %)        prior=-1        stack=0x80028a80
0x8000a788 ENET_RX                          (real size 2048):   unused 1544     usage  504 / 2048 (24 %)        prior=-14       stack=0x80028d00
0x800086b8 logging                          (real size 8192):   unused 7832     usage  360 / 8192 ( 4 %)        prior=14        stack=0x80024300
0x8000a970 idle                             (real size  384):   unused  312     usage   72 /  384 (18 %)        prior=15        stack=0x80029e00
0x80029500 IRQ 00                           (real size 2048):   unused 1712     usage  336 / 2048 (16 %)

Переполнение стэка lcd происходит после нескольких звонков(проект pjsip).