/**************************************************************************** * * Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED. * * This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics Ltd and MAY NOT * be copied by any method or incorporated into another program without * the express written consent of Aerospace C.Power. This Information or any portion * thereof remains the property of Aerospace C.Power. The Information contained herein * is believed to be accurate and Aerospace C.Power assumes no responsibility or * liability for its use in any way and conveys no license or title under * any patent or copyright and makes no representation or warranty that this * Information is free from patent or copyright infringement. * * ****************************************************************************/ #include "os_utils.h" #include "os_types.h" #include "os_mem.h" #include "iot_i2c_api.h" #include "iot_gpio_api.h" #include "iot_errno.h" #include "iot_lcd.h" #include "iot_io_api.h" /* Whether enable dump display data. */ #define IOT_LCD_DUMP_DEBUG 1 /* Whether key interruption is allowed. */ #define HT16K23_KEY_INT_ENABLE 0 /* The iic config of ht16k23. */ #define HT16K23_IIC_SLAVE_ADDR 0x73 /* I2C slave device addr. */ #define HT16K23_IIC_DISPLAY_RAM_START_ADDR 0 /* iot lcd display ram start addr. */ #define HT16K23_IIC_KEY_ADDR 0x20 /* iot lcd key addr. */ #define HT16K23_IIC_INIT_COMPLETED 1 #define HT16K23_IIC_INIT_UNCOMPLETED 0 #define HT16K23_IIC_DEF_PORT 0 /* Port#0. */ #define HT16K23_IIC_DEF_SPEED 50 /* 50K. */ #define HT16K23_IIC_DEF_NACK_NUM 1 /* N-ACK number. */ #define HT16K23_IIC_DEF_GPIO_SCL 28 /* GPIO28. */ #define HT16K23_IIC_DEF_GPIO_SDA 36 /* GPIO36. */ #define HT16K23_IIC_DEF_GPIO_INT 22 /* GPIO22. */ #define HT16K23_IIC_INT_ADDR 0x30 /* iot lcd int addr. */ #if HT16K23_KEY_INT_ENABLE /* set LCD to 16 * 8 display mode, int output, int pin level high is valied. */ #define HT16K23_SET_MODE_CMD 0xA7 #else /* set LCD to 16 * 8 display mode, no INT */ #define HT16K23_SET_MODE_CMD 0xA1 #endif /* into normal mode and open the display. */ #define HT16K23_SET_SYS_CMD_WORK 0x83 /* into standby mode. */ #define HT16K23_SET_SYS_CMD_STANDBY 0x80 /* set key scan period to 3 clock period. */ #define HT16K23_SET_CMD_KEY_SCAN 0xf9 /* seg reg operation. */ typedef struct { uint8_t seg_addr; /* start addr of the display ram. */ display_bitmap seg_data; /* the data that need to display. */ }lcd_seg_item; typedef struct _iot_lcd_iic_cfg_t { uint32_t inited; /* IIC initialization completed? 0, not yet * 1, done. */ uint32_t port; /* IIC port number. */ uint32_t baud; /* IIC baudrate, unit is Kb. */ uint32_t nack_wait_num; /* wait nack number. */ uint16_t gpio_scl; /* SCL gpio pin. */ uint16_t gpio_sda; /* SDA gpio pin. */ } iot_lcd_iic_cfg_t; static iot_lcd_iic_cfg_t ht16k23_iic_cfg = { HT16K23_IIC_INIT_UNCOMPLETED, /* IIC initialization uncompleted. */ HT16K23_IIC_DEF_PORT, /* IIC device port number. */ HT16K23_IIC_DEF_SPEED, /* Baudrate, unit is Kb. */ HT16K23_IIC_DEF_NACK_NUM, /* Wait nack number. */ HT16K23_IIC_DEF_GPIO_SCL, /* SCL gpio pin. */ HT16K23_IIC_DEF_GPIO_SDA /* SDA gpio pin. */ }; iot_lcd_key_handle_cb key_handle_cb; uint8_t iot_lcd_status = HT16K23_STAT_STANDBY; /* display ram. */ lcd_seg_item iot_lcd_seg_item_g; #ifdef IOT_LCD_DUMP_DEBUG /* @brief iot_lcd_dump_display_data() - dump the display data. */ static void iot_lcd_dump_display_data_inner(uint8_t *display_buf, uint32_t line) { uint8_t *p = display_buf; uint32_t i = 0, len = HT16K23_MAX_DISPLAY_RAM_LEN; iot_printf("lcd display data DUMP(%03d):", len); for(; i < len; i++) { iot_printf("%02X ", p[i]); } iot_printf("\n[dump end.@%04d]\n", line); return; } #else static void iot_lcd_dump_display_data_inner(uint8_t *display_buf, uint32_t line) { (void)display_buf; (void)line; } #endif #define iot_lcd_dump_display_data(buf) \ iot_lcd_dump_display_data_inner(buf, __LINE__) /* @brief iot_lcd_iic_init() - init iic return: ERR_OK:success. * ERR_FAIL:failed. */ static uint8_t iot_lcd_iic_init() { iot_i2c_module_cfg_t iic_cfg; iic_cfg.port = ht16k23_iic_cfg.port; iic_cfg.baud = ht16k23_iic_cfg.baud; iic_cfg.nack_wait_num = ht16k23_iic_cfg.nack_wait_num; iic_cfg.gpio.scl = ht16k23_iic_cfg.gpio_scl; iic_cfg.gpio.sda = ht16k23_iic_cfg.gpio_sda; /* iot_gpio_open_as_output can cancel the function bound on the GPIO. * This is not necessary if those GPIOs are not multiplex. */ if ((ERR_OK != iot_gpio_open_as_output(iic_cfg.gpio.scl)) || (ERR_OK != iot_gpio_open_as_output(iic_cfg.gpio.sda))) { iot_printf("[%s][err] open gpio failed.\n", __FUNCTION__); return ERR_FAIL; } if (ERR_OK != iot_i2c_module_init(&iic_cfg)) { iot_printf("[%s][err] init i2c failed.\n", __FUNCTION__); return ERR_FAIL; } iot_printf("[%s] init i2c of the LCD ht16k23 successfully!\n", __FUNCTION__); ht16k23_iic_cfg.inited = HT16K23_IIC_INIT_COMPLETED; return ERR_OK; } /* @brief lcd_open() - open lcd, init into normal mode, LCD is 16*8 return: ERR_OK:success. * ERR_FAIL:failed. */ static uint8_t iot_lcd_open(void) { uint8_t ret = 0; /* set LCD to 16 * 8 display mode, no INT. */ uint8_t mode_cmd = HT16K23_SET_MODE_CMD; /* into work mode and open the display. */ uint8_t sys_cmd = HT16K23_SET_SYS_CMD_WORK; /* set key scan period to 3 clock period. */ uint8_t key_scan_mode = HT16K23_SET_CMD_KEY_SCAN; if(HT16K23_IIC_INIT_COMPLETED != ht16k23_iic_cfg.inited) { iot_printf("[%s][err] iot lcd iic not init!\n", __FUNCTION__); return ERR_FAIL; } ret |= iot_i2c_write(IOT_I2C_PORT_0, HT16K23_IIC_SLAVE_ADDR, (char*)&mode_cmd, sizeof(mode_cmd)); ret |= iot_i2c_write(IOT_I2C_PORT_0, HT16K23_IIC_SLAVE_ADDR, (char*)&key_scan_mode, sizeof(key_scan_mode)); ret |= iot_i2c_write(IOT_I2C_PORT_0, HT16K23_IIC_SLAVE_ADDR, (char*)&sys_cmd, sizeof(sys_cmd)); if(ret != ERR_OK) { iot_printf("[%s][err] open lcd failed.\n", __FUNCTION__); return ERR_FAIL; } iot_printf("[%s] open the LCD ht16k23 successfully!\n", __FUNCTION__); iot_lcd_status = HT16K23_STAT_NORMAL; return ERR_OK; } /* @brief lcd_stand_by_set() - set system mode to stand by return: ERR_OK:success. * ERR_FAIL:failed. */ uint8_t iot_lcd_set_standby() { uint8_t sys_cmd = HT16K23_SET_SYS_CMD_STANDBY; uint8_t ret = 0; /* read key data before set mode standby. */ iot_poll_read_key_data(); /* will set standby fail, so delay 50ms.*/ os_delay(50); ret = iot_i2c_write(IOT_I2C_PORT_0, HT16K23_IIC_SLAVE_ADDR, (char*)&sys_cmd, sizeof(sys_cmd)); if(ret != ERR_OK) { iot_printf("[%s][err] set standby failed.\n", __FUNCTION__); return ERR_FAIL; } iot_printf("[%s] set the LCD ht16k23 into standby mode successfully!\n", __FUNCTION__); iot_lcd_status = HT16K23_STAT_STANDBY; return ERR_OK; } /* @brief iot_lcd_set_weakup() - set system mode to wakeup return: ERR_OK:success. * ERR_FAIL:failed. */ uint8_t iot_lcd_set_weakup() { uint8_t sys_cmd = HT16K23_SET_SYS_CMD_WORK; uint8_t ret = 0; ret = iot_i2c_write(IOT_I2C_PORT_0, HT16K23_IIC_SLAVE_ADDR, (char*)&sys_cmd, sizeof(sys_cmd)); if(ret != ERR_OK) { iot_printf("[%s][err] set wakeup failed.\n", __FUNCTION__); return ERR_FAIL; } iot_printf("[%s] set the LCD ht16k23 into weakup mode successfully!\n", __FUNCTION__); iot_lcd_status = HT16K23_STAT_NORMAL; return ERR_OK; } /* @brief iot_lcd_get_status() - get lcd work status, normal or standby. return: reference HT16K23_STAT_XXX. */ uint8_t iot_lcd_get_status() { return iot_lcd_status; } /* @brief lcd_clear_screen() - clear lcd screen return: ERR_OK:success. * ERR_FAIL:failed. */ uint8_t iot_lcd_clear_screen() { uint8_t ret = 0; iot_lcd_seg_item_g.seg_addr = HT16K23_IIC_DISPLAY_RAM_START_ADDR; os_mem_set(iot_lcd_seg_item_g.seg_data.display_data, 0, HT16K23_MAX_DISPLAY_RAM_LEN); ret = iot_i2c_write(IOT_I2C_PORT_0, HT16K23_IIC_SLAVE_ADDR, (char*)&iot_lcd_seg_item_g, sizeof(iot_lcd_seg_item_g)); if(ret != ERR_OK) { iot_printf("[%s][err] clear lcd failed.\n", __FUNCTION__); return ERR_FAIL; } iot_printf("[%s] clear screen of the LCD ht16k23 successfully!\n", __FUNCTION__); return ERR_OK; } /** * @brief iic_read_bytes() - read datas from reg addr 30H, 20H, 21H, 22H * * @param addr adress of slave address * @param reg addr of read * @param data the pointer to read data buffer * @param len the number of read data * * @return 0: read successful * @return other: read failed * */ static uint8_t iot_lcd_iic_read_bytes(uint8_t reg_addr, uint8_t *data, uint8_t len) { uint8_t ret = 0; uint8_t addr = reg_addr; if((NULL == data) || (len == 0)) { iot_printf("[%s][err] invalid params func.\n", __FUNCTION__); return ERR_FAIL; } if(HT16K23_IIC_INIT_COMPLETED != ht16k23_iic_cfg.inited) { iot_printf("[%s][err] not init the i2c\n", __FUNCTION__); return ERR_FAIL; } ret = iot_i2c_write(IOT_I2C_PORT_0, HT16K23_IIC_SLAVE_ADDR, (char*)&addr, 1); ret |= iot_i2c_read(IOT_I2C_PORT_0, HT16K23_IIC_SLAVE_ADDR, (char*)data, len); if(ret != ERR_OK) { iot_printf("[%s][err] i2c wirte|read failed.\n", __FUNCTION__); return ERR_FAIL; } return ERR_OK; } /* @brief iot_lcd_get_display_status() - query display status. @param: display_buf the buffer that save display ram data. @param: buf_len the length of buf. return: ERR_OK:success. * ERR_FAIL:failed. */ uint8_t iot_lcd_get_display_data(display_bitmap *display_buf) { if(NULL == display_buf) { iot_printf("[%s][err]invaled params!\n", __FUNCTION__); return ERR_FAIL; } if(HT16K23_STAT_STANDBY == iot_lcd_status) { iot_printf("[%s][err] LCD standby, not support operate the lcd ram!\n", __FUNCTION__); return ERR_FAIL; } iot_lcd_seg_item_g.seg_addr = HT16K23_IIC_DISPLAY_RAM_START_ADDR; os_mem_set(iot_lcd_seg_item_g.seg_data.display_data, 0, HT16K23_MAX_DISPLAY_RAM_LEN); if(ERR_OK != iot_lcd_iic_read_bytes(iot_lcd_seg_item_g.seg_addr, iot_lcd_seg_item_g.seg_data.display_data, HT16K23_MAX_DISPLAY_RAM_LEN)) { iot_printf("[%s][err] read i2c failed.\n", __FUNCTION__); return ERR_FAIL; } iot_lcd_dump_display_data(iot_lcd_seg_item_g.seg_data.display_data); os_mem_cpy(display_buf->display_data, iot_lcd_seg_item_g.seg_data.display_data, HT16K23_MAX_DISPLAY_RAM_LEN); return ERR_OK; } /* @brief iot_lcd_set_display_data() - set display data. @param: display_data data that set to the display memory. @param: data_len the length of the display data. return: ERR_OK:success. * ERR_FAIL:failed. */ uint8_t iot_lcd_set_display_data(display_bitmap *display_data) { if(NULL == display_data) { iot_printf("[%s][err] invaled params!\n", __FUNCTION__); return ERR_FAIL; } if(HT16K23_STAT_STANDBY == iot_lcd_status) { iot_printf("[%s][err] LCD standby, not support operate the lcd ram!\n", __FUNCTION__); return ERR_FAIL; } iot_lcd_seg_item_g.seg_addr = HT16K23_IIC_DISPLAY_RAM_START_ADDR; os_mem_set(iot_lcd_seg_item_g.seg_data.display_data, 0, HT16K23_MAX_DISPLAY_RAM_LEN); os_mem_cpy(iot_lcd_seg_item_g.seg_data.display_data, display_data->display_data, HT16K23_MAX_DISPLAY_RAM_LEN); iot_lcd_dump_display_data(iot_lcd_seg_item_g.seg_data.display_data); if(ERR_OK !=iot_i2c_write(IOT_I2C_PORT_0, HT16K23_IIC_SLAVE_ADDR, (char*)&iot_lcd_seg_item_g, HT16K23_MAX_DISPLAY_RAM_LEN + 1)) { iot_printf("[%s][err] write i2c failed.\n", __FUNCTION__); return ERR_FAIL; } return ERR_OK; } #if HT16K23_KEY_INT_ENABLE /* @brief iot_lcd_key_handle_register() - register lcd key handle callback func. @param: keycb the lcd key handle callback func. return: ERR_OK:success. * ERR_FAIL:failed. */ uint8_t iot_lcd_key_handle_register(iot_lcd_key_handle_cb keycb) { if(NULL != keycb) { key_handle_cb = keycb; return ERR_OK; } return ERR_FAIL; } /* @brief get_int_status() - get interrupt status return: int_satus. * ERR_FAIL:failed. */ static uint8_t iot_lcd_get_int_status() { uint8_t int_reg_addr = HT16K23_IIC_INT_ADDR; uint8_t int_satus = 0; if(ERR_OK != iot_lcd_iic_read_bytes(int_reg_addr, &int_satus, 1)) { iot_printf("[%s][err] read i2c failed.\n", __FUNCTION__); return ERR_FAIL; } return int_satus; } /* isr */ static void key_handler_isr(int arg) { uint8_t key_data = 0; int int_status = 0; (void)arg; int_status = iot_lcd_get_int_status(); key_data = iot_poll_read_key_data(); iot_printf("[%s] int_status:%d, key_data:%d\n", int_status, key_data); if(NULL != key_handle_cb) { key_handle_cb(key_data); } /* Prevent interrupted scanning too fast. */ os_delay(100); iot_gpio_interrupt_enable(HT16K23_IIC_DEF_GPIO_INT, 1); return; } /* @brief iot_lcd_int_init() - init interrupt return: ERR_OK:success. * ERR_FAIL:failed. */ uint8_t iot_lcd_int_init() { uint8_t ret = 0; iot_gpio_set_pull_mode(HT16K23_IIC_DEF_GPIO_INT, GPIO_PULL_DOWN); ret |= iot_gpio_open_as_interrupt(HT16K23_IIC_DEF_GPIO_INT); ret |= iot_gpio_interrupt_config(HT16K23_IIC_DEF_GPIO_INT, GPIO_INT_LEVEL_HIGH, (iot_gpio_isr_func)key_handler_isr, 0, GPIO_INT_FUNC_ENABLE_AUTOSTOP); ret |= iot_gpio_interrupt_enable(HT16K23_IIC_DEF_GPIO_INT, 1); if(ret != ERR_OK) { iot_printf("[%s][err] int init failed!\n", __FUNCTION__); iot_gpio_close(HT16K23_IIC_DEF_GPIO_INT); return ERR_FAIL; } iot_printf("[%s] init the LCD ht16k23 successfully!\n", __FUNCTION__); return ERR_OK; } #else uint8_t iot_lcd_key_handle_register(iot_lcd_key_handle_cb keycb) { (void)keycb; return ERR_OK; } uint8_t iot_lcd_int_init() { return ERR_OK; } #endif /* @brief iot_poll_read_key_data() - poll read ram key data If enable interrupt,when interrupt triggered will call it. otherwise upper-app polling call is required * @return which key was pressed. * ERR_FAIL: something error. */ uint8_t iot_poll_read_key_data() { /* key reg start addr. */ uint8_t addr = HT16K23_IIC_KEY_ADDR; /* Three registers need to be read to empty them. */ uint8_t key_data[3]; os_mem_set(key_data, 0, sizeof(key_data)); if(ERR_OK != iot_lcd_iic_read_bytes(addr, key_data, sizeof(key_data))) { iot_printf("[%s][err] read i2c failed.\n", __FUNCTION__); return ERR_FAIL; } /* only data[0] is valied. */ return key_data[0]; } /* @brief lcd_init() - lcd init, int init, open lcd, clear screen. @param: iot_lcd_type lcd type.. return: ERR_OK:success. * ERR_FAIL:failed. */ uint8_t iot_lcd_init() { uint8_t ret = ERR_OK; ret |= iot_lcd_iic_init(); ret |= iot_lcd_open(); ret |= iot_lcd_clear_screen(); if(ret != ERR_OK) { iot_printf("[%s][err] iot lcd init failed.\n", __FUNCTION__); return ERR_FAIL; } return ERR_OK; }