Display.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. *
  3. * Copyright (c) 2020-2023 Project CHIP Authors
  4. * Copyright (c) 2018 Nest Labs, Inc.
  5. * All rights reserved.
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. */
  19. #include <string.h>
  20. #include "driver/ledc.h"
  21. #include "esp_log.h"
  22. #include "esp_system.h"
  23. #include "freertos/FreeRTOS.h"
  24. #include "freertos/task.h"
  25. #include "freertos/timers.h"
  26. #include "Display.h"
  27. #if CONFIG_HAVE_DISPLAY
  28. // Brightness picked such that it's easy for cameras to focus on
  29. #define DEFAULT_BRIGHTNESS_PERCENT 10
  30. // 8MHz is the recommended SPI speed to init the driver with
  31. // It later gets set to the preconfigured defaults within the driver
  32. #define TFT_SPI_CLOCK_INIT_HZ 8000000
  33. // The frequency used by the ledc timer
  34. // value chosen to eliminate flicker
  35. #define LEDC_PWM_HZ 1000
  36. // with a duty resolution of LEDC_TIMER_8_BIT
  37. // the highest possible brightness value is 255
  38. #define BRIGHTNESS_MAX 255
  39. // The M5Stack's backlight is on Channel 7
  40. #define BACKLIGHT_CHANNEL LEDC_CHANNEL_7
  41. static const char * TAG = "Display";
  42. uint16_t DisplayHeight = 0;
  43. uint16_t DisplayWidth = 0;
  44. bool awake = false;
  45. #if CONFIG_DISPLAY_AUTO_OFF
  46. // FreeRTOS timer used to turn the display off after a short while
  47. TimerHandle_t displayTimer = NULL;
  48. #endif
  49. #if CONFIG_DISPLAY_AUTO_OFF
  50. static void TimerCallback(TimerHandle_t xTimer);
  51. #endif
  52. static void SetupBrightnessControl();
  53. static void SetBrightness(uint16_t brightness_percent);
  54. esp_err_t InitDisplay()
  55. {
  56. esp_err_t err;
  57. spi_lobo_device_handle_t spi;
  58. // configured based on the display driver's examples
  59. spi_lobo_bus_config_t buscfg;
  60. memset((void *) &buscfg, 0, sizeof(buscfg));
  61. buscfg.miso_io_num = PIN_NUM_MISO; // set SPI MISO pin
  62. buscfg.mosi_io_num = PIN_NUM_MOSI; // set SPI MOSI pin
  63. buscfg.sclk_io_num = PIN_NUM_CLK; // set SPI CLK pin
  64. buscfg.quadwp_io_num = -1;
  65. buscfg.quadhd_io_num = -1;
  66. spi_lobo_device_interface_config_t devcfg;
  67. memset((void *) &devcfg, 0, sizeof(devcfg));
  68. devcfg.clock_speed_hz = TFT_SPI_CLOCK_INIT_HZ;
  69. devcfg.mode = 0; // SPI mode 0
  70. devcfg.spics_io_num = -1; // we will use external CS pin
  71. devcfg.spics_ext_io_num = PIN_NUM_CS; // external CS pin
  72. devcfg.flags = LB_SPI_DEVICE_HALFDUPLEX; // ALWAYS SET to HALF DUPLEX MODE!! for display spi
  73. tft_max_rdclock = TFT_SPI_CLOCK_INIT_HZ;
  74. // Initialize all pins used by display driver.
  75. TFT_PinsInit();
  76. // Initialize SPI bus and add a device for the display.
  77. err = spi_lobo_bus_add_device(TFT_HSPI_HOST, &buscfg, &devcfg, &spi);
  78. if (err != ESP_OK)
  79. return err;
  80. // Configure the display to use the new SPI device.
  81. tft_disp_spi = spi;
  82. err = spi_lobo_device_select(spi, 1);
  83. if (err != ESP_OK)
  84. return err;
  85. err = spi_lobo_device_deselect(spi);
  86. if (err != ESP_OK)
  87. return err;
  88. // Initialize the display driver.
  89. TFT_display_init();
  90. // Detect maximum read speed and set it.
  91. tft_max_rdclock = find_rd_speed();
  92. // Set the SPI clock speed overriding the initialized 8MHz speed
  93. spi_lobo_set_speed(spi, DEFAULT_SPI_CLOCK);
  94. TFT_setGammaCurve(0);
  95. TFT_setRotation(LANDSCAPE);
  96. TFT_resetclipwin();
  97. DisplayWidth = (uint16_t)(1 + tft_dispWin.x2 - tft_dispWin.x1);
  98. DisplayHeight = (uint16_t)(1 + tft_dispWin.y2 - tft_dispWin.y1);
  99. ESP_LOGI(TAG, "Display initialized (height %u, width %u)", DisplayHeight, DisplayWidth);
  100. TFT_invertDisplay(INVERT_DISPLAY);
  101. // prepare the display for brightness control
  102. SetupBrightnessControl();
  103. #if CONFIG_DISPLAY_AUTO_OFF
  104. displayTimer = xTimerCreate("DisplayTimer", pdMS_TO_TICKS(DISPLAY_TIMEOUT_MS), false, NULL, TimerCallback);
  105. #endif
  106. // lower the brightness of the screen
  107. WakeDisplay();
  108. return err;
  109. }
  110. void SetBrightness(uint16_t brightness_percent)
  111. {
  112. uint16_t brightness = (brightness_percent * BRIGHTNESS_MAX) / 100;
  113. if (ledc_set_duty(LEDC_HIGH_SPEED_MODE, BACKLIGHT_CHANNEL, brightness) ||
  114. ledc_update_duty(LEDC_HIGH_SPEED_MODE, BACKLIGHT_CHANNEL))
  115. {
  116. ESP_LOGE(TAG, "Failed to set display brightness...");
  117. }
  118. }
  119. bool WakeDisplay()
  120. {
  121. bool woken = !awake;
  122. awake = true;
  123. SetBrightness(DEFAULT_BRIGHTNESS_PERCENT);
  124. #if CONFIG_DISPLAY_AUTO_OFF
  125. xTimerStart(displayTimer, 0);
  126. ESP_LOGI(TAG, "Display awake but will switch off automatically in %d seconds", DISPLAY_TIMEOUT_MS / 1000);
  127. #endif
  128. return woken;
  129. }
  130. void ClearDisplay()
  131. {
  132. ClearRect();
  133. }
  134. void ClearRect(uint16_t x_percent_start, uint16_t y_percent_start, uint16_t x_percent_end, uint16_t y_percent_end)
  135. {
  136. if (x_percent_end < x_percent_start)
  137. {
  138. x_percent_end = x_percent_start;
  139. }
  140. if (y_percent_end < y_percent_start)
  141. {
  142. y_percent_end = y_percent_start;
  143. }
  144. uint16_t start_x = (DisplayWidth * x_percent_start) / 100;
  145. uint16_t start_y = (DisplayHeight * y_percent_start) / 100;
  146. uint16_t end_x = (DisplayWidth * x_percent_end) / 100;
  147. uint16_t end_y = (DisplayHeight * y_percent_end) / 100;
  148. TFT_fillRect(start_x, start_y, end_x, end_y, TFT_BLACK);
  149. }
  150. void DisplayStatusMessage(char * msg, uint16_t vpos)
  151. {
  152. TFT_setFont(SMALL_FONT, NULL);
  153. uint16_t msgX = 0;
  154. uint16_t msgY = (DisplayHeight * vpos) / 100;
  155. TFT_print(msg, msgX, msgY);
  156. }
  157. void TimerCallback(TimerHandle_t xTimer)
  158. {
  159. ESP_LOGI(TAG, "Display going to sleep...");
  160. SetBrightness(0);
  161. awake = false;
  162. }
  163. void SetupBrightnessControl()
  164. {
  165. ledc_timer_config_t ledc_timer;
  166. memset(&ledc_timer, 0, sizeof(ledc_timer));
  167. ledc_timer.duty_resolution = LEDC_TIMER_8_BIT; // resolution of PWM duty
  168. ledc_timer.freq_hz = LEDC_PWM_HZ; // frequency of PWM signal
  169. ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE; // timer mode
  170. ledc_timer.timer_num = LEDC_TIMER_0; // timer index
  171. ledc_timer_config(&ledc_timer);
  172. ledc_timer_set(LEDC_HIGH_SPEED_MODE, LEDC_TIMER_0, LEDC_PWM_HZ, LEDC_TIMER_8_BIT, LEDC_REF_TICK);
  173. ledc_channel_config_t ledc_channel;
  174. memset(&ledc_channel, 0, sizeof(ledc_channel));
  175. ledc_channel.channel = BACKLIGHT_CHANNEL;
  176. ledc_channel.duty = BRIGHTNESS_MAX;
  177. ledc_channel.gpio_num = PIN_NUM_BCKL;
  178. ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE;
  179. ledc_channel.timer_sel = LEDC_TIMER_0;
  180. ledc_channel_config(&ledc_channel);
  181. }
  182. #endif // CONFIG_HAVE_DISPLAY