|
| 1 | +/** |
| 2 | + * @file pcd8544.c |
| 3 | + * |
| 4 | + * Roughly based on: |
| 5 | + * https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library |
| 6 | + * https://github.com/olikraus/u8g2 |
| 7 | + */ |
| 8 | + |
| 9 | +#include "disp_spi.h" |
| 10 | +#include "driver/gpio.h" |
| 11 | + |
| 12 | +#include <esp_log.h> |
| 13 | +#include "freertos/FreeRTOS.h" |
| 14 | +#include "freertos/task.h" |
| 15 | + |
| 16 | +#include "pcd8544.h" |
| 17 | + |
| 18 | +#define TAG "lv_pcd8544" |
| 19 | + |
| 20 | +/********************** |
| 21 | + * MACROS |
| 22 | + **********************/ |
| 23 | + |
| 24 | +#define BIT_SET(a,b) ((a) |= (1U<<(b))) |
| 25 | +#define BIT_CLEAR(a,b) ((a) &= ~(1U<<(b))) |
| 26 | + |
| 27 | +/********************** |
| 28 | + * STATIC FUNCTIONS |
| 29 | + **********************/ |
| 30 | + |
| 31 | +static void pcd8544_send_cmd(uint8_t cmd) |
| 32 | +{ |
| 33 | + disp_wait_for_pending_transactions(); |
| 34 | + gpio_set_level(PCD8544_DC, 0); /*Command mode*/ |
| 35 | + disp_spi_send_data(&cmd, 1); |
| 36 | +} |
| 37 | + |
| 38 | +static void pcd8544_send_data(void * data, uint16_t length) |
| 39 | +{ |
| 40 | + disp_wait_for_pending_transactions(); |
| 41 | + gpio_set_level(PCD8544_DC, 1); /*Data mode*/ |
| 42 | + disp_spi_send_data(data, length); |
| 43 | +} |
| 44 | + |
| 45 | +static void pcd8544_send_colors(void * data, uint16_t length) |
| 46 | +{ |
| 47 | + gpio_set_level(PCD8544_DC, 1); /*Data mode*/ |
| 48 | + disp_spi_send_colors(data, length); |
| 49 | +} |
| 50 | + |
| 51 | +/********************** |
| 52 | + * GLOBAL FUNCTIONS |
| 53 | + **********************/ |
| 54 | + |
| 55 | +void pcd8544_init(void){ |
| 56 | + |
| 57 | + // TODO: orientation |
| 58 | + |
| 59 | + // Initialize non-SPI GPIOs |
| 60 | + gpio_pad_select_gpio(PCD8544_DC); |
| 61 | + gpio_set_direction(PCD8544_DC, GPIO_MODE_OUTPUT); |
| 62 | + gpio_pad_select_gpio(PCD8544_RST); |
| 63 | + gpio_set_direction(PCD8544_RST, GPIO_MODE_OUTPUT); |
| 64 | + |
| 65 | + // Reset the display |
| 66 | + gpio_set_level(PCD8544_RST, 0); |
| 67 | + vTaskDelay(100 / portTICK_RATE_MS); |
| 68 | + gpio_set_level(PCD8544_RST, 1); |
| 69 | + vTaskDelay(100 / portTICK_RATE_MS); |
| 70 | + |
| 71 | + pcd8544_send_cmd(0x21); /* activate chip (PD=0), horizontal increment (V=0), enter extended command set (H=1) */ |
| 72 | + pcd8544_send_cmd(0x06); /* temp. control: b10 = 2 */ |
| 73 | + pcd8544_send_cmd(0x13); /* bias system 1:48 */ |
| 74 | + pcd8544_send_cmd(0xc0); /* medium Vop = Contrast 0x40 = 64 */ |
| 75 | + |
| 76 | + pcd8544_send_cmd(0x20); /* activate chip (PD=0), horizontal increment (V=0), enter extended command set (H=0) */ |
| 77 | + pcd8544_send_cmd(0x0c); /* display mode normal */ |
| 78 | +} |
| 79 | + |
| 80 | +void pcd8544_set_contrast (uint8_t contrast){ |
| 81 | + if (contrast > 0x7f){ |
| 82 | + contrast = 0x7f; |
| 83 | + } |
| 84 | + pcd8544_send_cmd(0x21); /* activate chip (PD=0), horizontal increment (V=0), enter extended command set (H=1) */ |
| 85 | + pcd8544_send_cmd(0x80 | contrast); /* medium Vop = Contrast */ |
| 86 | +} |
| 87 | + |
| 88 | +void pcd8544_rounder(lv_disp_drv_t * disp_drv, lv_area_t *area){ |
| 89 | + uint8_t hor_max = disp_drv->hor_res; |
| 90 | + uint8_t ver_max = disp_drv->ver_res; |
| 91 | + |
| 92 | + area->x1 = 0; |
| 93 | + area->y1 = 0; |
| 94 | + area->x2 = hor_max - 1; |
| 95 | + area->y2 = ver_max - 1; |
| 96 | +} |
| 97 | + |
| 98 | +void pcd8544_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, |
| 99 | + lv_color_t color, lv_opa_t opa){ |
| 100 | + |
| 101 | + uint8_t set = (color.full == 0) && (LV_OPA_TRANSP != opa); |
| 102 | + |
| 103 | + uint16_t byte_index = x + (( y>>3 ) * buf_w); |
| 104 | + uint8_t bit_index = y & 0x7; |
| 105 | + |
| 106 | + if (set) { |
| 107 | + BIT_SET(buf[byte_index], bit_index); |
| 108 | + } else { |
| 109 | + BIT_CLEAR(buf[byte_index], bit_index); |
| 110 | + } |
| 111 | +} |
| 112 | + |
| 113 | +void pcd8544_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_map){ |
| 114 | + |
| 115 | + pcd8544_send_cmd(0x20); /* activate chip (PD=0), horizontal increment (V=0), enter extended command set (H=0) */ |
| 116 | + |
| 117 | + uint8_t * buf = (uint8_t *) color_map; |
| 118 | + |
| 119 | + if ((area->x1 == 0) && (area->y1 == 0) && (area->x2 == (disp_drv->hor_res - 1)) && (area->y2 == (disp_drv->ver_res - 1))){ |
| 120 | + |
| 121 | + // optimize flush of complete frame buffer in a single SPI transaction |
| 122 | + |
| 123 | + pcd8544_send_cmd(0x40); /* set Y address */ |
| 124 | + pcd8544_send_cmd(0x80); /* set X address */ |
| 125 | + pcd8544_send_colors(buf, disp_drv->hor_res * disp_drv->ver_res / 8); |
| 126 | + |
| 127 | + } else { |
| 128 | + |
| 129 | + // send horizontal tiles |
| 130 | + |
| 131 | + uint16_t bank_start = area->y1 / 8; |
| 132 | + uint16_t bank_end = area->y2 / 8; |
| 133 | + |
| 134 | + uint16_t bank; |
| 135 | + uint16_t cols_to_update = area->x2 - area->x1 + 1; |
| 136 | + for (bank = bank_start ; bank <= bank_end ; bank++ ){ |
| 137 | + pcd8544_send_cmd(0x40 | bank ); /* set Y address */ |
| 138 | + pcd8544_send_cmd(0x80 | area->x1 ); /* set X address */ |
| 139 | + uint16_t offset = bank * disp_drv->hor_res + area->x1; |
| 140 | + pcd8544_send_data(&buf[offset], cols_to_update); |
| 141 | + } |
| 142 | + |
| 143 | + lv_disp_flush_ready(disp_drv); |
| 144 | + |
| 145 | + } |
| 146 | +} |
0 commit comments