My Marlin configs for Fabrikator Mini and CTC i3 Pro B
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.

u8g_dev_ssd1306_sh1106_128x64_I2C.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /**
  2. * Marlin 3D Printer Firmware
  3. * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
  4. *
  5. * Based on Sprinter and grbl.
  6. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. *
  21. */
  22. /**
  23. * Based on u8g_dev_ssd1306_128x64.c
  24. *
  25. * Universal 8bit Graphics Library
  26. *
  27. * Copyright (c) 2015, olikraus@gmail.com
  28. * All rights reserved.
  29. *
  30. * Redistribution and use in source and binary forms, with or without modification,
  31. * are permitted provided that the following conditions are met:
  32. *
  33. * * Redistributions of source code must retain the above copyright notice, this list
  34. * of conditions and the following disclaimer.
  35. *
  36. * * Redistributions in binary form must reproduce the above copyright notice, this
  37. * list of conditions and the following disclaimer in the documentation and/or other
  38. * materials provided with the distribution.
  39. *
  40. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  41. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  42. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  43. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  44. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  45. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  46. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  47. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  48. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  49. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  50. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  51. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  52. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  53. */
  54. /**
  55. * These routines are meant for two wire I2C interfaces.
  56. *
  57. * Three and four wire I2C interfaces have an A0 line. That line is
  58. * used to switch between command and data modes.
  59. *
  60. * The two wire LCDs use an instruction byte to signal if data or
  61. * command info is to follow. The command stream needs the instruction
  62. * byte between eack command byte. The data stream needs one at the
  63. * beginning.
  64. */
  65. #include "../../inc/MarlinConfigPre.h"
  66. #if HAS_MARLINUI_U8GLIB
  67. #include "HAL_LCD_com_defines.h"
  68. #define WIDTH 128
  69. #define HEIGHT 64
  70. #define PAGE_HEIGHT 8
  71. uint8_t u8g_WriteEscSeqP_2_wire(u8g_t *u8g, u8g_dev_t *dev, const uint8_t *esc_seq);
  72. // The sh1106 is compatible to the ssd1306, but is 132x64. 128x64 display area is centered within
  73. // the 132x64.
  74. static const uint8_t u8g_dev_sh1106_128x64_data_start_2_wire[] PROGMEM = {
  75. 0x010, // set upper 4 bit of the col adr to 0
  76. 0x002, // set lower 4 bit of the col adr to 2 (centered display with ssd1306)
  77. U8G_ESC_END // end of sequence
  78. };
  79. #define SH1106_PAGE_ADR(N) (0x20), (N)
  80. #define SH1106_COLUMN_RANGE(N) (0x21), (((N) >> 8) & 0xFF), ((N) & 0xFF)
  81. #define SH1106_PAGE_RANGE(N,O) (0x22), (N), (O)
  82. #define SH1106_SCROLL(N) ((N) ? 0x2F : 0x2E)
  83. #define SH1106_START_LINE(N) (0x40 | (N))
  84. #define SH1106_CONTRAST(N) (0x81), (N)
  85. #define SH1106_CHARGE_PUMP(N) (0x8D), ((N) ? 0x14 : 0x10)
  86. #define SH1106_ADC_REVERSE(N) ((N) ? 0xA1 : 0xA0)
  87. #define SH1106_ALL_PIX(N) ((N) ? 0xA5 : 0xA4)
  88. #define SH1106_INVERTED(N) ((N) ? 0xA7 : 0xA6)
  89. #define SH1106_MUX_RATIO(N) (0xA8), (N)
  90. #define SH1106_ON(N) ((N) ? 0xAF : 0xAE)
  91. #define SH1106_OUT_MODE(N) ((N) ? 0xC8 : 0xC0)
  92. #define SH1106_DISP_OFFS(N) (0xD3), (N)
  93. #define SH1106_OSC_FREQ(R,F) (0xD5), ((F) << 4 | (R))
  94. #define SH1106_CHARGE_PER(P,D) (0xD9), ((D) << 4 | (P))
  95. #define SH1106_COM_CONFIG(N) (0xDA), ((N) ? 0x12 : 0x02)
  96. #define SH1106_VCOM_DESEL(N) (0xDB), (N)
  97. #define SH1106_NOOP() (0xE3)
  98. static const uint8_t u8g_dev_sh1106_128x64_init_seq_2_wire[] PROGMEM = {
  99. U8G_ESC_ADR(0), // Initiate command mode
  100. SH1106_ON(0), // Display off, sleep mode
  101. SH1106_MUX_RATIO(0x3F), // Mux ratio
  102. SH1106_DISP_OFFS(0), // Display offset
  103. SH1106_START_LINE(0), // Start line
  104. SH1106_ADC_REVERSE(1), // Segment remap A0/A1
  105. SH1106_OUT_MODE(1), // C0: scan dir normal, C8: reverse
  106. SH1106_COM_CONFIG(1), // Com pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5)
  107. SH1106_CONTRAST(0xCF), // [2] set contrast control
  108. SH1106_PAGE_ADR(0x02), // 2012-05-27: page addressing mode
  109. SH1106_COLUMN_RANGE(0x281), // Set column range from 0 through 131
  110. SH1106_PAGE_RANGE(0, 7), // Set page range from 0 through 7
  111. SH1106_CHARGE_PER(0x1, 0xF), // [2] pre-charge period 0x22/F1
  112. SH1106_VCOM_DESEL(0x40), // Vcomh deselect level
  113. SH1106_ALL_PIX(0), // Output ram to display
  114. SH1106_INVERTED(0), // Normal display mode
  115. SH1106_OSC_FREQ(0, 8), // Clock divide ratio (0:1) and oscillator frequency (8)
  116. SH1106_CHARGE_PUMP(1), // [2] charge pump setting (P62): 0x14 enable, 0x10 disable
  117. SH1106_SCROLL(0), // 2012-05-27: Deactivate scroll
  118. SH1106_ON(1), // Display on
  119. U8G_ESC_END // End of sequence
  120. };
  121. uint8_t u8g_dev_sh1106_128x64_2x_2_wire_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) {
  122. switch (msg) {
  123. case U8G_DEV_MSG_INIT:
  124. u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS);
  125. u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_sh1106_128x64_init_seq_2_wire);
  126. break;
  127. case U8G_DEV_MSG_STOP:
  128. break;
  129. case U8G_DEV_MSG_PAGE_NEXT: {
  130. u8g_pb_t *pb = (u8g_pb_t *)(dev->dev_mem);
  131. u8g_SetAddress(u8g, dev, 0); // instruction mode
  132. u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_sh1106_128x64_data_start_2_wire);
  133. u8g_WriteByte(u8g, dev, 0x0B0 | (pb->p.page*2)); // select current page
  134. u8g_SetAddress(u8g, dev, 1); // data mode
  135. u8g_WriteSequence(u8g, dev, pb->width, (uint8_t *) pb->buf);
  136. u8g_SetChipSelect(u8g, dev, 0);
  137. u8g_SetAddress(u8g, dev, 0); // instruction mode
  138. u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_sh1106_128x64_data_start_2_wire);
  139. u8g_WriteByte(u8g, dev, 0x0B0 | (pb->p.page*2+1)); // select current page
  140. u8g_SetAddress(u8g, dev, 1); // data mode
  141. u8g_WriteSequence(u8g, dev, pb->width, (uint8_t *)(pb->buf)+pb->width);
  142. u8g_SetChipSelect(u8g, dev, 0);
  143. }
  144. break;
  145. case U8G_DEV_MSG_SLEEP_ON:
  146. return 1;
  147. case U8G_DEV_MSG_SLEEP_OFF:
  148. return 1;
  149. }
  150. return u8g_dev_pb16v1_base_fn(u8g, dev, msg, arg);
  151. }
  152. uint8_t u8g_dev_sh1106_128x64_2x_i2c_2_wire_buf[WIDTH*2] U8G_NOCOMMON ;
  153. u8g_pb_t u8g_dev_sh1106_128x64_2x_i2c_2_wire_pb = { {16, HEIGHT, 0, 0, 0}, WIDTH, u8g_dev_sh1106_128x64_2x_i2c_2_wire_buf};
  154. u8g_dev_t u8g_dev_sh1106_128x64_2x_i2c_2_wire = { u8g_dev_sh1106_128x64_2x_2_wire_fn, &u8g_dev_sh1106_128x64_2x_i2c_2_wire_pb, U8G_COM_SSD_I2C_HAL };
  155. /////////////////////////////////////////////////////////////////////////////////////////////
  156. static const uint8_t u8g_dev_ssd1306_128x64_data_start_2_wire[] PROGMEM = {
  157. 0x010, // set upper 4 bit of the col adr to 0
  158. 0x000, // set lower 4 bit of the col adr to 0
  159. U8G_ESC_END // end of sequence
  160. };
  161. static const uint8_t u8g_dev_ssd1306_128x64_init_seq_2_wire[] PROGMEM = {
  162. U8G_ESC_ADR(0), // initiate command mode
  163. 0x0AE, // display off, sleep mode
  164. 0x0A8, 0x03F, // mux ratio
  165. 0x0D3, 0x00, // display offset
  166. 0x040, // start line
  167. 0x0A1, // segment remap a0/a1
  168. 0x0C8, // c0: scan dir normal, c8: reverse
  169. 0x0DA, 0x012, // com pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5)
  170. 0x081, 0x0CF, // [2] set contrast control
  171. 0x020, 0x002, // 2012-05-27: page addressing mode
  172. 0x21, 0, 0x7F, // set column range from 0 through 127
  173. 0x22, 0, 7, // set page range from 0 through 7
  174. 0x0D9, 0x0F1, // [2] pre-charge period 0x022/f1
  175. 0x0DB, 0x040, // vcomh deselect level
  176. 0x0A4, // output ram to display
  177. 0x0A6, // none inverted normal display mode
  178. 0x0D5, 0x080, // clock divide ratio (0x00=1) and oscillator frequency (0x8)
  179. 0x08D, 0x014, // [2] charge pump setting (p62): 0x014 enable, 0x010 disable
  180. 0x02E, // 2012-05-27: Deactivate scroll
  181. 0x0AF, // display on
  182. U8G_ESC_END // end of sequence
  183. };
  184. uint8_t u8g_dev_ssd1306_128x64_2x_2_wire_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg) {
  185. switch (msg) {
  186. case U8G_DEV_MSG_INIT:
  187. u8g_InitCom(u8g, dev, U8G_SPI_CLK_CYCLE_300NS);
  188. u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_ssd1306_128x64_init_seq_2_wire);
  189. break;
  190. case U8G_DEV_MSG_STOP:
  191. break;
  192. case U8G_DEV_MSG_PAGE_NEXT: {
  193. u8g_pb_t *pb = (u8g_pb_t *)(dev->dev_mem);
  194. u8g_SetAddress(u8g, dev, 0); // instruction mode
  195. u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_ssd1306_128x64_data_start_2_wire);
  196. u8g_WriteByte(u8g, dev, 0x0B0 | (pb->p.page*2)); // select current page
  197. u8g_SetAddress(u8g, dev, 1); // data mode
  198. u8g_WriteSequence(u8g, dev, pb->width, (uint8_t *) pb->buf);
  199. u8g_SetChipSelect(u8g, dev, 0);
  200. u8g_SetAddress(u8g, dev, 0); // instruction mode
  201. u8g_WriteEscSeqP_2_wire(u8g, dev, u8g_dev_ssd1306_128x64_data_start_2_wire);
  202. u8g_WriteByte(u8g, dev, 0x0B0 | (pb->p.page*2+1)); // select current page
  203. u8g_SetAddress(u8g, dev, 1); // data mode
  204. u8g_WriteSequence(u8g, dev, pb->width, (uint8_t *)(pb->buf)+pb->width);
  205. u8g_SetChipSelect(u8g, dev, 0);
  206. }
  207. break;
  208. case U8G_DEV_MSG_SLEEP_ON:
  209. return 1;
  210. case U8G_DEV_MSG_SLEEP_OFF:
  211. return 1;
  212. }
  213. return u8g_dev_pb16v1_base_fn(u8g, dev, msg, arg);
  214. }
  215. uint8_t u8g_dev_ssd1306_128x64_2x_i2c_2_wire_buf[WIDTH*2] U8G_NOCOMMON ;
  216. u8g_pb_t u8g_dev_ssd1306_128x64_2x_i2c_2_wire_pb = { {16, HEIGHT, 0, 0, 0}, WIDTH, u8g_dev_ssd1306_128x64_2x_i2c_2_wire_buf};
  217. u8g_dev_t u8g_dev_ssd1306_128x64_2x_i2c_2_wire = { u8g_dev_ssd1306_128x64_2x_2_wire_fn, &u8g_dev_ssd1306_128x64_2x_i2c_2_wire_pb, U8G_COM_SSD_I2C_HAL };
  218. /////////////////////////////////////////////////////////////////////////////////////////////
  219. // This routine adds the instruction byte in between the command bytes. This makes the init
  220. // sequences a lot easier to read.
  221. #define I2C_CMD_MODE 0x080
  222. uint8_t u8g_WriteEscSeqP_2_wire(u8g_t *u8g, u8g_dev_t *dev, const uint8_t *esc_seq) {
  223. uint8_t is_escape = 0;
  224. for (;;) {
  225. uint8_t value = u8g_pgm_read(esc_seq);
  226. if (is_escape == 0) {
  227. if (value != 255) {
  228. if (u8g_WriteByte(u8g, dev, value) == 0 )
  229. return 0;
  230. if (u8g_WriteByte(u8g, dev, I2C_CMD_MODE) == 0 )
  231. return 0;
  232. }
  233. else {
  234. is_escape = 1;
  235. }
  236. }
  237. else {
  238. if (value == 255) {
  239. if (u8g_WriteByte(u8g, dev, value) == 0 )
  240. return 0;
  241. if (u8g_WriteByte(u8g, dev, I2C_CMD_MODE) == 0 )
  242. return 0;
  243. }
  244. else if (value == 254) {
  245. break;
  246. }
  247. else if (value >= 0x0F0) {
  248. /* not yet used, do nothing */
  249. }
  250. else if (value >= 0xE0 ) {
  251. u8g_SetAddress(u8g, dev, value & 0x0F);
  252. }
  253. else if (value >= 0xD0) {
  254. u8g_SetChipSelect(u8g, dev, value & 0x0F);
  255. }
  256. else if (value >= 0xC0) {
  257. u8g_SetResetLow(u8g, dev);
  258. value &= 0x0F;
  259. value <<= 4;
  260. value+=2;
  261. u8g_Delay(value);
  262. u8g_SetResetHigh(u8g, dev);
  263. u8g_Delay(value);
  264. }
  265. else if (value >= 0xBE) { /* not yet implemented */
  266. /* u8g_SetVCC(u8g, dev, value & 0x01); */
  267. }
  268. else if (value <= 127) {
  269. u8g_Delay(value);
  270. }
  271. is_escape = 0;
  272. }
  273. esc_seq++;
  274. }
  275. return 1;
  276. }
  277. #endif // HAS_MARLINUI_U8GLIB