S&B Volcano vaporizer remote control with Pi Pico W
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * lcd.c
  3. *
  4. * Copyright (c) 2023 Thomas Buck (thomas@xythobuz.de)
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * See <http://www.gnu.org/licenses/>.
  17. */
  18. #include <math.h>
  19. #include "pico/stdlib.h"
  20. #include "hardware/spi.h"
  21. #include "hardware/pwm.h"
  22. #include "driver_st7789.h"
  23. #include "config.h"
  24. #include "log.h"
  25. #include "lcd.h"
  26. #define LCD_PIN_DC 8
  27. #define LCD_PIN_CS 9
  28. #define LCD_PIN_CLK 10
  29. #define LCD_PIN_DIN 11
  30. #define LCD_PIN_RST 12
  31. #define LCD_PIN_BL 13
  32. #define ST7789_PICO_COLUMN LCD_HEIGHT
  33. #define ST7789_PICO_ROW LCD_WIDTH
  34. #define ST7789_PICO_ACCESS (ST7789_ORDER_PAGE_TOP_TO_BOTTOM | \
  35. ST7789_ORDER_COLUMN_LEFT_TO_RIGHT | \
  36. ST7789_ORDER_PAGE_COLUMN_NORMAL | \
  37. ST7789_ORDER_LINE_TOP_TO_BOTTOM | \
  38. ST7789_ORDER_COLOR_RGB | \
  39. ST7789_ORDER_REFRESH_LEFT_TO_RIGHT)
  40. #define ST7789_PICO_RGB_INTERFACE_COLOR_FORMAT 0
  41. #define ST7789_PICO_CONTROL_INTERFACE_COLOR_FORMAT ST7789_CONTROL_INTERFACE_COLOR_FORMAT_16_BIT
  42. #define ST7789_PICO_PORCH_NORMAL_BACK 0x0C
  43. #define ST7789_PICO_PORCH_NORMAL_FRONT 0x0C
  44. #define ST7789_PICO_PORCH_ENABLE ST7789_BOOL_FALSE
  45. #define ST7789_PICO_PORCH_IDEL_BACK 0x03
  46. #define ST7789_PICO_PORCH_IDEL_FRONT 0x03
  47. #define ST7789_PICO_PORCH_PART_BACK 0x03
  48. #define ST7789_PICO_PORCH_PART_FRONT 0x03
  49. #define ST7789_PICO_VGHS ST7789_VGHS_13P26_V
  50. #define ST7789_PICO_VGLS_NEGATIVE ST7789_VGLS_NEGATIVE_10P43
  51. #define ST7789_PICO_VCOMS 0.725f
  52. #define ST7789_PICO_XMY ST7789_BOOL_FALSE
  53. #define ST7789_PICO_XBGR ST7789_BOOL_TRUE
  54. #define ST7789_PICO_XINV ST7789_BOOL_FALSE
  55. #define ST7789_PICO_XMX ST7789_BOOL_TRUE
  56. #define ST7789_PICO_XMH ST7789_BOOL_TRUE
  57. #define ST7789_PICO_XMV ST7789_BOOL_FALSE
  58. #define ST7789_PICO_XGS ST7789_BOOL_FALSE
  59. #define ST7789_PICO_VDV_VRH_FROM ST7789_VDV_VRH_FROM_CMD
  60. #define ST7789_PICO_VRHS 4.45f
  61. #define ST7789_PICO_VDV 0.0f
  62. #define ST7789_PICO_INVERSION_SELECTION ST7789_INVERSION_SELECTION_DOT
  63. #define ST7789_PICO_FRAME_RATE ST7789_FRAME_RATE_60_HZ
  64. #define ST7789_PICO_AVDD ST7789_AVDD_6P8_V
  65. #define ST7789_PICO_AVCL_NEGTIVE ST7789_AVCL_NEGTIVE_4P8_V
  66. #define ST7789_PICO_VDS ST7789_VDS_2P3_V
  67. #define ST7789_PICO_POSITIVE_VOLTAGE_GAMMA {0xD0, 0x04, 0x0D, 0x11, 0x13, 0x2B, 0x3F, \
  68. 0x54, 0x4C, 0x18, 0x0D, 0x0B, 0x1F, 0x23}
  69. #define ST7789_PICO_NEGATIVA_VOLTAGE_GAMMA {0xD0, 0x04, 0x0C, 0x11, 0x13, 0x2C, 0x3F, \
  70. 0x44, 0x51, 0x2F, 0x1F, 0x1F, 0x20, 0x23}
  71. static st7789_handle_t gs_handle;
  72. static uint16_t bl_value = 0;
  73. static uint8_t st7789_interface_spi_init(void) {
  74. // Use SPI1 at 100MHz
  75. spi_init(spi1, 100 * 1000 * 1000);
  76. gpio_set_function(LCD_PIN_CLK, GPIO_FUNC_SPI);
  77. gpio_set_function(LCD_PIN_DIN, GPIO_FUNC_SPI);
  78. // Chip select is active-low, so we'll initialise it to a driven-high state
  79. gpio_init(LCD_PIN_CS);
  80. gpio_set_dir(LCD_PIN_CS, GPIO_OUT);
  81. gpio_put(LCD_PIN_CS, 1);
  82. spi_set_format(spi1,
  83. 8, // Number of bits per transfer
  84. 0, // Polarity (CPOL)
  85. 0, // Phase (CPHA)
  86. SPI_MSB_FIRST);
  87. return 0;
  88. }
  89. static uint8_t st7789_interface_spi_deinit(void) {
  90. spi_deinit(spi1);
  91. gpio_deinit(LCD_PIN_CS);
  92. return 0;
  93. }
  94. static uint8_t st7789_interface_spi_write_cmd(uint8_t *buf, uint16_t len) {
  95. gpio_put(LCD_PIN_CS, 0);
  96. spi_write_blocking(spi1, buf, len);
  97. gpio_put(LCD_PIN_CS, 1);
  98. return 0;
  99. }
  100. static void st7789_interface_delay_ms(uint32_t ms) {
  101. sleep_ms(ms);
  102. }
  103. static void st7789_interface_debug_print(const char *const fmt, ...) {
  104. va_list args;
  105. va_start(args, fmt);
  106. debug_log_va(true, fmt, args);
  107. va_end(args);
  108. }
  109. static uint8_t st7789_interface_cmd_data_gpio_init(void) {
  110. gpio_init(LCD_PIN_DC);
  111. gpio_set_dir(LCD_PIN_DC, GPIO_OUT);
  112. return 0;
  113. }
  114. static uint8_t st7789_interface_cmd_data_gpio_deinit(void) {
  115. gpio_deinit(LCD_PIN_DC);
  116. return 0;
  117. }
  118. static uint8_t st7789_interface_cmd_data_gpio_write(uint8_t value) {
  119. gpio_put(LCD_PIN_DC, value);
  120. return 0;
  121. }
  122. static uint8_t st7789_interface_reset_gpio_init(void) {
  123. gpio_init(LCD_PIN_RST);
  124. gpio_set_dir(LCD_PIN_RST, GPIO_OUT);
  125. return 0;
  126. }
  127. static uint8_t st7789_interface_reset_gpio_deinit(void) {
  128. gpio_deinit(LCD_PIN_RST);
  129. return 0;
  130. }
  131. static uint8_t st7789_interface_reset_gpio_write(uint8_t value) {
  132. gpio_put(LCD_PIN_RST, value);
  133. return 0;
  134. }
  135. void lcd_init(void) {
  136. uint8_t reg;
  137. DRIVER_ST7789_LINK_INIT(&gs_handle, st7789_handle_t);
  138. DRIVER_ST7789_LINK_SPI_INIT(&gs_handle, st7789_interface_spi_init);
  139. DRIVER_ST7789_LINK_SPI_DEINIT(&gs_handle, st7789_interface_spi_deinit);
  140. DRIVER_ST7789_LINK_SPI_WRITE_COMMAND(&gs_handle, st7789_interface_spi_write_cmd);
  141. DRIVER_ST7789_LINK_COMMAND_DATA_GPIO_INIT(&gs_handle, st7789_interface_cmd_data_gpio_init);
  142. DRIVER_ST7789_LINK_COMMAND_DATA_GPIO_DEINIT(&gs_handle, st7789_interface_cmd_data_gpio_deinit);
  143. DRIVER_ST7789_LINK_COMMAND_DATA_GPIO_WRITE(&gs_handle, st7789_interface_cmd_data_gpio_write);
  144. DRIVER_ST7789_LINK_RESET_GPIO_INIT(&gs_handle, st7789_interface_reset_gpio_init);
  145. DRIVER_ST7789_LINK_RESET_GPIO_DEINIT(&gs_handle, st7789_interface_reset_gpio_deinit);
  146. DRIVER_ST7789_LINK_RESET_GPIO_WRITE(&gs_handle, st7789_interface_reset_gpio_write);
  147. DRIVER_ST7789_LINK_DELAY_MS(&gs_handle, st7789_interface_delay_ms);
  148. DRIVER_ST7789_LINK_DEBUG_PRINT(&gs_handle, st7789_interface_debug_print);
  149. st7789_init(&gs_handle);
  150. st7789_set_column(&gs_handle, ST7789_PICO_COLUMN);
  151. st7789_set_row(&gs_handle, ST7789_PICO_ROW);
  152. st7789_set_memory_data_access_control(&gs_handle, ST7789_PICO_ACCESS);
  153. st7789_set_interface_pixel_format(&gs_handle,
  154. ST7789_PICO_RGB_INTERFACE_COLOR_FORMAT,
  155. ST7789_PICO_CONTROL_INTERFACE_COLOR_FORMAT);
  156. st7789_set_porch(&gs_handle,
  157. ST7789_PICO_PORCH_NORMAL_BACK,
  158. ST7789_PICO_PORCH_NORMAL_FRONT,
  159. ST7789_PICO_PORCH_ENABLE,
  160. ST7789_PICO_PORCH_IDEL_BACK,
  161. ST7789_PICO_PORCH_IDEL_FRONT,
  162. ST7789_PICO_PORCH_PART_BACK,
  163. ST7789_PICO_PORCH_PART_FRONT);
  164. st7789_set_gate_control(&gs_handle, ST7789_PICO_VGHS, ST7789_PICO_VGLS_NEGATIVE);
  165. st7789_vcom_convert_to_register(&gs_handle, ST7789_PICO_VCOMS, &reg);
  166. st7789_set_vcoms(&gs_handle, reg);
  167. st7789_set_lcm_control(&gs_handle,
  168. ST7789_PICO_XMY,
  169. ST7789_PICO_XBGR,
  170. ST7789_PICO_XINV,
  171. ST7789_PICO_XMX,
  172. ST7789_PICO_XMH,
  173. ST7789_PICO_XMV,
  174. ST7789_PICO_XGS);
  175. st7789_set_vdv_vrh_from(&gs_handle, ST7789_PICO_VDV_VRH_FROM);
  176. st7789_vrhs_convert_to_register(&gs_handle, ST7789_PICO_VRHS, &reg);
  177. st7789_set_vrhs(&gs_handle, reg);
  178. st7789_vdv_convert_to_register(&gs_handle, ST7789_PICO_VDV, &reg);
  179. st7789_set_vdv(&gs_handle, reg);
  180. st7789_set_frame_rate(&gs_handle, ST7789_PICO_INVERSION_SELECTION, ST7789_PICO_FRAME_RATE);
  181. st7789_set_power_control_1(&gs_handle,
  182. ST7789_PICO_AVDD,
  183. ST7789_PICO_AVCL_NEGTIVE,
  184. ST7789_PICO_VDS);
  185. uint8_t param_positive[14] = ST7789_PICO_POSITIVE_VOLTAGE_GAMMA;
  186. st7789_set_positive_voltage_gamma_control(&gs_handle, param_positive);
  187. uint8_t param_negative[14] = ST7789_PICO_NEGATIVA_VOLTAGE_GAMMA;
  188. st7789_set_negative_voltage_gamma_control(&gs_handle, param_negative);
  189. st7789_display_inversion_on(&gs_handle);
  190. st7789_sleep_out(&gs_handle);
  191. st7789_display_on(&gs_handle);
  192. st7789_clear(&gs_handle);
  193. // backlight
  194. uint bl_slice = pwm_gpio_to_slice_num(LCD_PIN_BL);
  195. uint bl_channel = pwm_gpio_to_channel(LCD_PIN_BL);
  196. gpio_set_function(LCD_PIN_BL, GPIO_FUNC_PWM);
  197. pwm_set_wrap(bl_slice, 0xFFFF);
  198. pwm_set_clkdiv(bl_slice, 1.0f);
  199. pwm_set_chan_level(bl_slice, bl_channel, bl_value);
  200. pwm_set_enabled(bl_slice, true);
  201. }
  202. uint16_t lcd_get_backlight(void) {
  203. return bl_value;
  204. }
  205. void lcd_set_backlight(uint16_t value) {
  206. uint bl_slice = pwm_gpio_to_slice_num(LCD_PIN_BL);
  207. uint bl_channel = pwm_gpio_to_channel(LCD_PIN_BL);
  208. bl_value = value;
  209. pwm_set_chan_level(bl_slice, bl_channel, bl_value);
  210. }
  211. void lcd_clear(void) {
  212. st7789_clear(&gs_handle);
  213. }
  214. void lcd_write_point(uint16_t x, uint16_t y, uint32_t color) {
  215. st7789_draw_point(&gs_handle, ST7789_PICO_COLUMN - y - 1, x, color);
  216. }
  217. void lcd_write_rect(uint16_t left, uint16_t top, uint16_t right, uint16_t bottom, uint32_t color) {
  218. if (right >= ST7789_PICO_ROW) {
  219. right = ST7789_PICO_ROW - 1;
  220. }
  221. if (bottom >= ST7789_PICO_COLUMN) {
  222. bottom = ST7789_PICO_COLUMN - 1;
  223. }
  224. if (top >= bottom) {
  225. return;
  226. }
  227. if (left >= right) {
  228. return;
  229. }
  230. // handle, left, top, right, bottom, color);
  231. st7789_fill_rect(&gs_handle, 240 - bottom - 1, left, 240 - top - 1, right, color);
  232. }
  233. uint32_t from_hsv(float h, float s, float v) {
  234. float i = floorf(h * 6.0f);
  235. float f = h * 6.0f - i;
  236. v *= 255.0f;
  237. float p = v * (1.0f - s);
  238. float q = v * (1.0f - f * s);
  239. float t = v * (1.0f - (1.0f - f) * s);
  240. switch (((uint32_t)i) % 6) {
  241. case 0:
  242. return RGB_565((uint32_t)v, (uint32_t)t, (uint32_t)p);
  243. case 1:
  244. return RGB_565((uint32_t)q, (uint32_t)v, (uint32_t)p);
  245. case 2:
  246. return RGB_565((uint32_t)p, (uint32_t)v, (uint32_t)t);
  247. case 3:
  248. return RGB_565((uint32_t)p, (uint32_t)q, (uint32_t)v);
  249. case 4:
  250. return RGB_565((uint32_t)t, (uint32_t)p, (uint32_t)v);
  251. case 5:
  252. return RGB_565((uint32_t)v, (uint32_t)p, (uint32_t)q);
  253. default:
  254. return RGB_565(0, 0, 0);
  255. }
  256. }