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.

274 lines
13 KiB

  1. # ST7565 LCD Driver
  2. ## Supported Hardware
  3. LCD modules using ST7565 driver IC, communicating over SPI.
  4. |Module |IC |Size |Notes |
  5. |------------------------------|-------|------|----------------------------------------------------------|
  6. |Newhaven Display NHD-C12832A1Z|ST7565R|128x32|Used by Ergodox Infinity; primary consumer of this feature|
  7. |Zolentech ZLE12864B |ST7565P|128x64|Requires contrast adjustment |
  8. ## Usage
  9. To enable the feature, there are three steps. First, when compiling your keyboard, you'll need to add the following to your `rules.mk`:
  10. ```make
  11. ST7565_ENABLE = yes
  12. ```
  13. Then in your `keymap.c` file, implement the ST7565 task call. This example assumes your keymap has three layers named `_QWERTY`, `_FN` and `_ADJ`:
  14. ```c
  15. #ifdef ST7565_ENABLE
  16. void st7565_task_user(void) {
  17. // Host Keyboard Layer Status
  18. st7565_write_P(PSTR("Layer: "), false);
  19. switch (get_highest_layer(layer_state)) {
  20. case _QWERTY:
  21. st7565_write_P(PSTR("Default\n"), false);
  22. break;
  23. case _FN:
  24. st7565_write_P(PSTR("FN\n"), false);
  25. break;
  26. case _ADJ:
  27. st7565_write_P(PSTR("ADJ\n"), false);
  28. break;
  29. default:
  30. // Or use the write_ln shortcut over adding '\n' to the end of your string
  31. st7565_write_ln_P(PSTR("Undefined"), false);
  32. }
  33. // Host Keyboard LED Status
  34. led_t led_state = host_keyboard_led_state();
  35. st7565_write_P(led_state.num_lock ? PSTR("NUM ") : PSTR(" "), false);
  36. st7565_write_P(led_state.caps_lock ? PSTR("CAP ") : PSTR(" "), false);
  37. st7565_write_P(led_state.scroll_lock ? PSTR("SCR ") : PSTR(" "), false);
  38. }
  39. #endif
  40. ```
  41. ## Logo Example
  42. In the default font, certain ranges of characters are reserved for a QMK logo. To render this logo to the screen, use the following code example:
  43. ```c
  44. static void render_logo(void) {
  45. static const char PROGMEM qmk_logo[] = {
  46. 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94,
  47. 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4,
  48. 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0x00
  49. };
  50. st7565_write_P(qmk_logo, false);
  51. }
  52. ```
  53. ## Buffer Read Example
  54. For some purposes, you may need to read the current state of the display buffer. The `st7565_read_raw` function can be used to safely read bytes from the buffer.
  55. In this example, calling `fade_display` in the `st7565_task_user` function will slowly fade away whatever is on the screen by turning random pixels off over time.
  56. ```c
  57. //Setup some mask which can be or'd with bytes to turn off pixels
  58. const uint8_t single_bit_masks[8] = {127, 191, 223, 239, 247, 251, 253, 254};
  59. static void fade_display(void) {
  60. //Define the reader structure
  61. display_buffer_reader_t reader;
  62. uint8_t buff_char;
  63. if (random() % 30 == 0) {
  64. srand(timer_read());
  65. // Fetch a pointer for the buffer byte at index 0. The return structure
  66. // will have the pointer and the number of bytes remaining from this
  67. // index position if we want to perform a sequential read by
  68. // incrementing the buffer pointer
  69. reader = st7565_read_raw(0);
  70. //Loop over the remaining buffer and erase pixels as we go
  71. for (uint16_t i = 0; i < reader.remaining_element_count; i++) {
  72. //Get the actual byte in the buffer by dereferencing the pointer
  73. buff_char = *reader.current_element;
  74. if (buff_char != 0) {
  75. st7565_write_raw_byte(buff_char & single_bit_masks[rand() % 8], i);
  76. }
  77. //increment the pointer to fetch a new byte during the next loop
  78. reader.current_element++;
  79. }
  80. }
  81. }
  82. ```
  83. ## Other Examples
  84. In split keyboards, it is very common to have two displays that each render different content and are oriented or flipped differently. You can do this by switching which content to render by using the return value from `is_keyboard_master()` or `is_keyboard_left()` found in `split_util.h`, e.g:
  85. ```c
  86. #ifdef ST7565_ENABLE
  87. display_rotation_t st7565_init_user(display_rotation_t rotation) {
  88. if (!is_keyboard_master()) {
  89. return DISPLAY_ROTATION_180; // flips the display 180 degrees if offhand
  90. }
  91. return rotation;
  92. }
  93. void st7565_task_user(void) {
  94. if (is_keyboard_master()) {
  95. render_status(); // Renders the current keyboard state (layer, lock, caps, scroll, etc)
  96. } else {
  97. render_logo(); // Renders a static logo
  98. }
  99. }
  100. #endif
  101. ```
  102. ## Basic Configuration
  103. |Define |Default |Description |
  104. |------------------------|--------------|-----------------------------------------------------------------------------------------------------|
  105. |`ST7565_A0_PIN` |*Not defined* |(Required) The GPIO connected to the display's A0 (data/command) pin |
  106. |`ST7565_RST_PIN` |*Not defined* |(Required) The GPIO connected to the display's reset pin |
  107. |`ST7565_SS_PIN` |*Not defined* |(Required) The GPIO connected to the display's slave select pin |
  108. |`ST7565_SPI_CLK_DIVISOR`|`4` |The SPI clock divisor to use |
  109. |`ST7565_FONT_H` |`"glcdfont.c"`|The font code file to use for custom fonts |
  110. |`ST7565_FONT_START` |`0` |The starting character index for custom fonts |
  111. |`ST7565_FONT_END` |`223` |The ending character index for custom fonts |
  112. |`ST7565_FONT_WIDTH` |`6` |The font width |
  113. |`ST7565_FONT_HEIGHT` |`8` |The font height (untested) |
  114. |`ST7565_TIMEOUT` |`60000` |Turns off the screen after 60000ms of keyboard inactivity. Helps reduce burn-in. Set to 0 to disable.|
  115. |`ST7565_COLUMN_OFFSET` |`0` |Shift output to the right this many pixels. |
  116. |`ST7565_CONTRAST` |`32` |The default contrast level of the display, from 0 to 255. |
  117. |`ST7565_UPDATE_INTERVAL`|`0` |Set the time interval for updating the display in ms. This will improve the matrix scan rate. |
  118. ## Custom sized displays
  119. The default display size for this feature is 128x32 and all necessary defines are precalculated with that in mind.
  120. |Define |Default |Description |
  121. |-----------------------|----------|-----------------------------------------------------------------------------------------------------------|
  122. |`ST7565_DISPLAY_WIDTH` |`128` |The width of the display. |
  123. |`ST7565_DISPLAY_HEIGHT`|`32` |The height of the display. |
  124. |`ST7565_MATRIX_SIZE` |`512` |The local buffer size to allocate.<br>`(ST7565_DISPLAY_HEIGHT / 8 * ST7565_DISPLAY_WIDTH)`. |
  125. |`ST7565_BLOCK_TYPE` |`uint16_t`|The unsigned integer type to use for dirty rendering. |
  126. |`ST7565_BLOCK_COUNT` |`16` |The number of blocks the display is divided into for dirty rendering.<br>`(sizeof(ST7565_BLOCK_TYPE) * 8)`.|
  127. |`ST7565_BLOCK_SIZE` |`32` |The size of each block for dirty rendering<br>`(ST7565_MATRIX_SIZE / ST7565_BLOCK_COUNT)`. |
  128. ## API
  129. ```c
  130. // Rotation enum values are flags
  131. typedef enum {
  132. DISPLAY_ROTATION_0,
  133. DISPLAY_ROTATION_180
  134. } display_rotation_t;
  135. // Initialize the display, rotating the rendered output based on the define passed in.
  136. // Returns true if the was initialized successfully
  137. bool st7565_init(display_rotation_t rotation);
  138. // Called at the start of st7565_init, weak function overridable by the user
  139. // rotation - the value passed into st7565_init
  140. // Return new display_rotation_t if you want to override default rotation
  141. display_rotation_t st7565_init_user(display_rotation_t rotation);
  142. // Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering
  143. void st7565_clear(void);
  144. // Renders the dirty chunks of the buffer to display
  145. void st7565_render(void);
  146. // Moves cursor to character position indicated by column and line, wraps if out of bounds
  147. // Max column denoted by 'st7565_max_chars()' and max lines by 'st7565_max_lines()' functions
  148. void st7565_set_cursor(uint8_t col, uint8_t line);
  149. // Advances the cursor to the next page, writing ' ' if true
  150. // Wraps to the begining when out of bounds
  151. void st7565_advance_page(bool clearPageRemainder);
  152. // Moves the cursor forward 1 character length
  153. // Advance page if there is not enough room for the next character
  154. // Wraps to the begining when out of bounds
  155. void st7565_advance_char(void);
  156. // Writes a single character to the buffer at current cursor position
  157. // Advances the cursor while writing, inverts the pixels if true
  158. // Main handler that writes character data to the display buffer
  159. void st7565_write_char(const char data, bool invert);
  160. // Writes a string to the buffer at current cursor position
  161. // Advances the cursor while writing, inverts the pixels if true
  162. void st7565_write(const char *data, bool invert);
  163. // Writes a string to the buffer at current cursor position
  164. // Advances the cursor while writing, inverts the pixels if true
  165. // Advances the cursor to the next page, wiring ' ' to the remainder of the current page
  166. void st7565_write_ln(const char *data, bool invert);
  167. // Pans the buffer to the right (or left by passing true) by moving contents of the buffer
  168. // Useful for moving the screen in preparation for new drawing
  169. void st7565_pan(bool left);
  170. // Returns a pointer to the requested start index in the buffer plus remaining
  171. // buffer length as struct
  172. display_buffer_reader_t st7565_read_raw(uint16_t start_index);
  173. // Writes a string to the buffer at current cursor position
  174. void st7565_write_raw(const char *data, uint16_t size);
  175. // Writes a single byte into the buffer at the specified index
  176. void st7565_write_raw_byte(const char data, uint16_t index);
  177. // Sets a specific pixel on or off
  178. // Coordinates start at top-left and go right and down for positive x and y
  179. void st7565_write_pixel(uint8_t x, uint8_t y, bool on);
  180. // Writes a PROGMEM string to the buffer at current cursor position
  181. // Advances the cursor while writing, inverts the pixels if true
  182. // Remapped to call 'void st7565_write(const char *data, bool invert);' on ARM
  183. void st7565_write_P(const char *data, bool invert);
  184. // Writes a PROGMEM string to the buffer at current cursor position
  185. // Advances the cursor while writing, inverts the pixels if true
  186. // Advances the cursor to the next page, wiring ' ' to the remainder of the current page
  187. // Remapped to call 'void st7565_write_ln(const char *data, bool invert);' on ARM
  188. void st7565_write_ln_P(const char *data, bool invert);
  189. // Writes a PROGMEM string to the buffer at current cursor position
  190. void st7565_write_raw_P(const char *data, uint16_t size);
  191. // Can be used to manually turn on the screen if it is off
  192. // Returns true if the screen was on or turns on
  193. bool st7565_on(void);
  194. // Called when st7565_on() turns on the screen, weak function overridable by the user
  195. // Not called if the screen is already on
  196. void st7565_on_user(void);
  197. // Can be used to manually turn off the screen if it is on
  198. // Returns true if the screen was off or turns off
  199. bool st7565_off(void);
  200. // Called when st7565_off() turns off the screen, weak function overridable by the user
  201. // Not called if the screen is already off
  202. void st7565_off_user(void);
  203. // Returns true if the screen is currently on, false if it is
  204. // not
  205. bool st7565_is_on(void);
  206. // Basically it's st7565_render, but with timeout management and st7565_task_user calling!
  207. void st7565_task(void);
  208. // Called at the start of st7565_task, weak function overridable by the user
  209. void st7565_task_user(void);
  210. // Inverts the display
  211. // Returns true if the screen was or is inverted
  212. bool st7565_invert(bool invert);
  213. // Returns the maximum number of characters that will fit on a line
  214. uint8_t st7565_max_chars(void);
  215. // Returns the maximum number of lines that will fit on the display
  216. uint8_t st7565_max_lines(void);
  217. ```