I2CLCDBoard.ino 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. /*
  2. I2CLCDBoard.ino
  3. https://github.com/olikraus/u8g2/issues/2191
  4. Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
  5. Copyright (c) 2023, olikraus@gmail.com
  6. All rights reserved.
  7. Redistribution and use in source and binary forms, with or without modification,
  8. are permitted provided that the following conditions are met:
  9. * Redistributions of source code must retain the above copyright notice, this list
  10. of conditions and the following disclaimer.
  11. * Redistributions in binary form must reproduce the above copyright notice, this
  12. list of conditions and the following disclaimer in the documentation and/or other
  13. materials provided with the distribution.
  14. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  15. CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  16. INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  17. MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  19. CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  20. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  21. NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  23. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  24. STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  25. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  26. ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. #include <Arduino.h>
  29. #include <U8g2lib.h>
  30. #include <Wire.h>
  31. /*
  32. Example for the I2C LCD GFX Board https://github.com/olikraus/u8g2/issues/2191
  33. Required updates for T6963 and LC7981 :
  34. 1. Update write strobe and chip select signals in "u8x8_byte_i2c_lcd_gfx_board_t6963_8080()"
  35. 2. Update the setup procedure in "setup()"
  36. Control Signal List for I2C Port Expander @0x3e:
  37. Bit 0: C/D
  38. Bit 1: R/W
  39. Bit 2: E
  40. Bit 3: E2
  41. Bit 4: /CS
  42. Bit 5: /RD
  43. Bit 6: /Reset
  44. Bit 7: LED
  45. */
  46. #define I2C_LCD_CD 1
  47. #define I2C_LCD_RW 2
  48. #define I2C_LCD_E 4
  49. #define I2C_LCD_E2 8
  50. #define I2C_LCD_CS 16
  51. #define I2C_LCD_RD 32
  52. #define I2C_LCD_RESET 64
  53. #define I2C_LCD_LED 128
  54. /* default value for the LED control gpio line */
  55. #define I2C_LCD_LED_DEFAULT I2C_LCD_LED
  56. //#define I2C_LCD_LED_DEFAULT 0
  57. #define I2C_LCD_CTRL_ADR 0x3e
  58. #define I2C_LCD_DATA_ADR 0x3f
  59. /*
  60. Set a bit in the internal register and in the i2c control gpio
  61. The call "u8x8_set_ctrl_bit(u8x8, 0, 1);" will just refresh the gpio lines
  62. Typically the second argument will be one of the I2C_LCD_xxx macros
  63. Reusing the "i2c_started" member variable, which is not used by the i2c lcd board software (i2c_started is only used by sw emulated i2c)
  64. */
  65. void u8x8_set_ctrl_bit(u8x8_t *u8x8, uint8_t bit, uint8_t is_set) U8X8_NOINLINE;
  66. void u8x8_set_ctrl_bit(u8x8_t *u8x8, uint8_t bit, uint8_t is_set)
  67. {
  68. if ( is_set )
  69. u8x8->i2c_started |= (uint8_t)bit; // reused i2c_started to store the gpio state
  70. else
  71. u8x8->i2c_started &= ~(uint8_t)bit; // reused i2c_started to store the gpio state
  72. Wire.beginTransmission(I2C_LCD_CTRL_ADR);
  73. Wire.write(u8x8->i2c_started); // Sends value byte
  74. Wire.endTransmission(); // Stop transmitting
  75. }
  76. /*
  77. The new gpio&delay procedure extents the existing arduino procedure and adds proper reset handling
  78. */
  79. uint8_t u8x8_gpio_and_delay_i2c_lcd_gfx_board(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, U8X8_UNUSED void *arg_ptr)
  80. {
  81. uint8_t i;
  82. switch(msg)
  83. {
  84. case U8X8_MSG_GPIO_RESET:
  85. u8x8_set_ctrl_bit(u8x8, I2C_LCD_RESET, arg_int);
  86. return 1;
  87. case U8X8_MSG_GPIO_AND_DELAY_INIT:
  88. u8x8->i2c_started = I2C_LCD_CS|I2C_LCD_RD|I2C_LCD_RESET|I2C_LCD_LED_DEFAULT; // assign default value for ctrl byte, reuse "i2c_started" member variable to store the gpio state
  89. u8x8_set_ctrl_bit(u8x8, 0, 1); // just transmit the control byte (which is stored in "i2c_started" member variable)
  90. return 1;
  91. }
  92. return u8x8_gpio_and_delay_arduino(u8x8, msg, arg_int, arg_ptr);
  93. }
  94. /*
  95. This is an example byte level procedure for a T6963 board.
  96. This procedure will assume, that the T6963 is configured in 8080 mode.
  97. Probably the same procedure can be also used for LC7981 displays.
  98. In general chip select and write strobe signals may differ and need to be checked.
  99. */
  100. uint8_t u8x8_byte_i2c_lcd_gfx_board_t6963_8080(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
  101. {
  102. /* usually only the following two varibables need to be modified */
  103. uint8_t write_strobe = I2C_LCD_RW; /* T6963 in 8080mode */
  104. uint8_t chip_select = I2C_LCD_CS;
  105. uint8_t *data;
  106. switch(msg)
  107. {
  108. case U8X8_MSG_BYTE_SEND:
  109. data = (uint8_t *)arg_ptr;
  110. while( arg_int > 0 )
  111. {
  112. Wire.beginTransmission(I2C_LCD_DATA_ADR);
  113. Wire.write(*data);
  114. Wire.endTransmission();
  115. data++;
  116. arg_int--;
  117. // Assumption: u8x8_set_ctrl_bit() will be slow enough, so that no extra delay is required
  118. //u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->data_setup_time_ns);
  119. u8x8_set_ctrl_bit(u8x8, write_strobe, 0); // in 8080 mode, the RW signal is the /WR signal
  120. //u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->write_pulse_width_ns);
  121. u8x8_set_ctrl_bit(u8x8, write_strobe, 1); // in 8080 mode, the RW signal is the /WR signal
  122. }
  123. break;
  124. case U8X8_MSG_BYTE_INIT:
  125. Wire.begin();
  126. Wire.setClock(400000); // Assumption: PCF8574A supports fast I2C mode
  127. /* disable chipselect */
  128. u8x8_set_ctrl_bit(u8x8, chip_select, u8x8->display_info->chip_disable_level); // disable display controller
  129. /* ensure that the enable signal is high */
  130. u8x8_set_ctrl_bit(u8x8, write_strobe, 1); // in 8080 mode, the RW signal is the /WR signal
  131. break;
  132. case U8X8_MSG_BYTE_SET_DC:
  133. u8x8_set_ctrl_bit(u8x8, I2C_LCD_CD, arg_int); // command/data data/command
  134. break;
  135. case U8X8_MSG_BYTE_START_TRANSFER:
  136. u8x8_set_ctrl_bit(u8x8, chip_select, u8x8->display_info->chip_enable_level); // command/data data/command
  137. u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->post_chip_enable_wait_ns, NULL);
  138. break;
  139. case U8X8_MSG_BYTE_END_TRANSFER:
  140. u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->pre_chip_disable_wait_ns, NULL);
  141. u8x8_set_ctrl_bit(u8x8, chip_select, u8x8->display_info->chip_disable_level); // command/data data/command
  142. break;
  143. default:
  144. return 0;
  145. }
  146. return 1;
  147. }
  148. /*
  149. This is an example byte level procedure for a LC7981 board.
  150. This procedure will assume, that the LC7981 is configured in 6800 mode.
  151. Probably the same procedure can be also used for T6963 displays.
  152. In general chip select and write strobe signals may differ and need to be checked.
  153. */
  154. uint8_t u8x8_byte_i2c_lcd_gfx_board_lc7981_6800(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
  155. {
  156. /* usually only the following two varibables need to be modified */
  157. uint8_t rw_line = I2C_LCD_RW;
  158. uint8_t write_strobe = I2C_LCD_E; // 6800 mode
  159. uint8_t chip_select = I2C_LCD_CS;
  160. uint8_t *data;
  161. switch(msg)
  162. {
  163. case U8X8_MSG_BYTE_SEND:
  164. u8x8_set_ctrl_bit(u8x8, rw_line, 0);
  165. data = (uint8_t *)arg_ptr;
  166. while( arg_int > 0 )
  167. {
  168. Wire.beginTransmission(I2C_LCD_DATA_ADR);
  169. Wire.write(*data);
  170. Wire.endTransmission();
  171. data++;
  172. arg_int--;
  173. // Assumption: u8x8_set_ctrl_bit() will be slow enough, so that no extra delay is required
  174. //u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->data_setup_time_ns);
  175. u8x8_set_ctrl_bit(u8x8, write_strobe, 1);
  176. //u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->write_pulse_width_ns);
  177. u8x8_set_ctrl_bit(u8x8, write_strobe, 0); // in 6800 mode, data is taken over with the falling edge of the E data line
  178. }
  179. break;
  180. case U8X8_MSG_BYTE_INIT:
  181. Wire.begin();
  182. Wire.setClock(400000); // Assumption: PCF8574A supports fast I2C mode
  183. /* disable chipselect */
  184. u8x8_set_ctrl_bit(u8x8, chip_select, u8x8->display_info->chip_disable_level); // disable display controller
  185. /* low signal level for the R/W line */
  186. u8x8_set_ctrl_bit(u8x8, rw_line, 0); // in 6800 mode, the R/W signal must be low for writing
  187. /* ensure that the enable signal is low */
  188. u8x8_set_ctrl_bit(u8x8, write_strobe, 0); // in 8080 mode, the RW signal is the /WR signal
  189. break;
  190. case U8X8_MSG_BYTE_SET_DC:
  191. u8x8_set_ctrl_bit(u8x8, I2C_LCD_CD, arg_int); // command/data data/command
  192. break;
  193. case U8X8_MSG_BYTE_START_TRANSFER:
  194. u8x8_set_ctrl_bit(u8x8, chip_select, u8x8->display_info->chip_enable_level); // command/data data/command
  195. u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->post_chip_enable_wait_ns, NULL);
  196. break;
  197. case U8X8_MSG_BYTE_END_TRANSFER:
  198. u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->pre_chip_disable_wait_ns, NULL);
  199. u8x8_set_ctrl_bit(u8x8, chip_select, u8x8->display_info->chip_disable_level); // command/data data/command
  200. break;
  201. default:
  202. return 0;
  203. }
  204. return 1;
  205. }
  206. /*
  207. This is an example byte level procedure for SED1520 / SBN1661 displays.
  208. The display needs to be configured in 6800 mode.
  209. In general chip select and write strobe signals may differ and need to be checked.
  210. */
  211. uint8_t u8x8_byte_i2c_lcd_gfx_board_sed1520_6800(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
  212. {
  213. uint8_t chip_select = I2C_LCD_CS;
  214. uint8_t *data;
  215. static uint8_t enable_pin = I2C_LCD_E; // the enable pin may differ. The current enable pin number is stored here
  216. switch(msg)
  217. {
  218. case U8X8_MSG_BYTE_SEND:
  219. data = (uint8_t *)arg_ptr;
  220. while( arg_int > 0 )
  221. {
  222. Wire.beginTransmission(I2C_LCD_DATA_ADR);
  223. Wire.write(*data);
  224. Wire.endTransmission();
  225. data++;
  226. arg_int--;
  227. // Assumption: u8x8_set_ctrl_bit() will be slow enough, so that no extra delay is required
  228. //u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->data_setup_time_ns);
  229. u8x8_set_ctrl_bit(u8x8, enable_pin, 0);
  230. //u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, 200);
  231. //u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->write_pulse_width_ns);
  232. u8x8_set_ctrl_bit(u8x8, enable_pin, 1);
  233. }
  234. break;
  235. case U8X8_MSG_BYTE_INIT:
  236. Wire.begin();
  237. Wire.setClock(400000); // Assumption: PCF8574A supports fast I2C mode
  238. /* 6800 mode: Permanently assign R/W to GND */
  239. u8x8_set_ctrl_bit(u8x8, I2C_LCD_RW, 0); // in 6800 mode, the R/W can 0 all the time (write mode only)
  240. /* chipselect */
  241. u8x8_set_ctrl_bit(u8x8, I2C_LCD_CS, 0); // there is no CS for the SED1520... but still, we apply a default value here
  242. /* ensure that the enable signal is high */
  243. u8x8_set_ctrl_bit(u8x8, I2C_LCD_E, 0); // clear E1
  244. u8x8_set_ctrl_bit(u8x8, I2C_LCD_E2, 0); // clear E2
  245. enable_pin = I2C_LCD_E; // assign E1 as initial enable signal
  246. break;
  247. case U8X8_MSG_BYTE_SET_DC:
  248. u8x8_set_ctrl_bit(u8x8, I2C_LCD_CD, arg_int); // command/data data/command
  249. break;
  250. case U8X8_MSG_BYTE_START_TRANSFER:
  251. /* arg_int is set by u8x8_d_sbn1661_122x32() function (which is also used by sed1520) */
  252. enable_pin = I2C_LCD_E;
  253. if ( arg_int != 0 ) // the CAD procedure will tell, which enable signal to use
  254. enable_pin = I2C_LCD_E2;
  255. break;
  256. case U8X8_MSG_BYTE_END_TRANSFER:
  257. break;
  258. default:
  259. return 0;
  260. }
  261. return 1;
  262. }
  263. /*
  264. This is an example byte level procedure for a ST7920 display board.
  265. This procedure will put the ST7920 in parallel mode.
  266. The ST7920 must be connected to J3 of the I2C GFX Board.
  267. See also: https://github.com/olikraus/u8g2/issues/2191
  268. */
  269. uint8_t u8x8_byte_i2c_lcd_gfx_board_st7920(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
  270. {
  271. /* usually only the following two varibables need to be modified */
  272. uint8_t read_write = I2C_LCD_RW; /* Must be permanently 0 for the ST7920 to use the write mode */
  273. uint8_t enable_strobe = I2C_LCD_E; /* Used to latch in data for the ST7920 */
  274. uint8_t psb_select = I2C_LCD_CS; /* CS is connected to PSB at J3, so CS must be permanently 1 for parallel mode */
  275. uint8_t *data;
  276. switch(msg)
  277. {
  278. case U8X8_MSG_BYTE_SEND:
  279. data = (uint8_t *)arg_ptr;
  280. while( arg_int > 0 )
  281. {
  282. Wire.beginTransmission(I2C_LCD_DATA_ADR);
  283. Wire.write(*data);
  284. Wire.endTransmission();
  285. data++;
  286. arg_int--;
  287. // Assumption: u8x8_set_ctrl_bit() will be slow enough, so that no extra delay is required
  288. //u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->data_setup_time_ns);
  289. u8x8_set_ctrl_bit(u8x8, enable_strobe, 1); // in 8080 mode, the RW signal is the /WR signal
  290. //u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->write_pulse_width_ns);
  291. u8x8_set_ctrl_bit(u8x8, enable_strobe, 0); // in 8080 mode, the RW signal is the /WR signal
  292. }
  293. break;
  294. case U8X8_MSG_BYTE_INIT:
  295. Wire.begin();
  296. Wire.setClock(400000); // Assumption: PCF8574A supports fast I2C mode
  297. /* ensure that the enable signal is low (ST7920 datasheet) */
  298. u8x8_set_ctrl_bit(u8x8, enable_strobe, 0); // ST7920: Generate low-high-low pulse for data transfer, so start with 0
  299. u8x8_set_ctrl_bit(u8x8, read_write, 0); // ST7920: must be permanently low for write mode
  300. u8x8_set_ctrl_bit(u8x8, psb_select, 1); // ST7920: This is actually connected to PSB on J1, so make this permanently 1 for parallel mode
  301. u8x8_set_ctrl_bit(u8x8, I2C_LCD_CD, 0); // ST7920: Command Mode
  302. break;
  303. case U8X8_MSG_BYTE_SET_DC:
  304. u8x8_set_ctrl_bit(u8x8, I2C_LCD_CD, arg_int); // command/data data/command
  305. break;
  306. case U8X8_MSG_BYTE_START_TRANSFER:
  307. //u8x8_set_ctrl_bit(u8x8, chip_select, u8x8->display_info->chip_enable_level); // command/data data/command
  308. //u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->post_chip_enable_wait_ns, NULL);
  309. break;
  310. case U8X8_MSG_BYTE_END_TRANSFER:
  311. //u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->pre_chip_disable_wait_ns, NULL);
  312. //u8x8_set_ctrl_bit(u8x8, chip_select, u8x8->display_info->chip_disable_level); // command/data data/command
  313. break;
  314. default:
  315. return 0;
  316. }
  317. return 1;
  318. }
  319. /*
  320. This is an example byte level procedure for a KS0108 display board.
  321. The KS0108 192x64 display must be connected to J9 of the I2C GFX Board (2024 PCB).
  322. See also: https://github.com/olikraus/u8g2/issues/2191
  323. */
  324. uint8_t u8x8_byte_i2c_lcd_gfx_board_ks0108(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
  325. {
  326. /* usually only the following two varibables need to be modified */
  327. uint8_t read_write = I2C_LCD_RW; /* Must be permanently 0 for the KS0108 */
  328. uint8_t enable_strobe = I2C_LCD_E; /* Used to latch in data for the KS0108 */
  329. uint8_t cs1 = I2C_LCD_CS; /* CS1 */
  330. uint8_t cs2 = I2C_LCD_E2; /* CS2 see mapping, in https://github.com/olikraus/u8g2/issues/2191 */
  331. uint8_t cs3 = I2C_LCD_RD; /* CS3 see mapping, in https://github.com/olikraus/u8g2/issues/2191 */
  332. uint8_t *data;
  333. switch(msg)
  334. {
  335. case U8X8_MSG_BYTE_SEND:
  336. data = (uint8_t *)arg_ptr;
  337. while( arg_int > 0 )
  338. {
  339. Wire.beginTransmission(I2C_LCD_DATA_ADR);
  340. Wire.write(*data);
  341. Wire.endTransmission();
  342. data++;
  343. arg_int--;
  344. // Assumption: u8x8_set_ctrl_bit() will be slow enough, so that no extra delay is required
  345. //u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->data_setup_time_ns);
  346. u8x8_set_ctrl_bit(u8x8, enable_strobe, 1);
  347. //u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->write_pulse_width_ns);
  348. u8x8_set_ctrl_bit(u8x8, enable_strobe, 0);
  349. }
  350. break;
  351. case U8X8_MSG_BYTE_INIT:
  352. Wire.begin();
  353. Wire.setClock(400000); // Assumption: PCF8574A supports fast I2C mode
  354. /* ensure that the enable signal is low (ST7920 datasheet) */
  355. u8x8_set_ctrl_bit(u8x8, enable_strobe, 0); // Generate low-high-low pulse for data transfer, so start with 0
  356. u8x8_set_ctrl_bit(u8x8, read_write, 0); // must be permanently low for write mode
  357. u8x8_set_ctrl_bit(u8x8, cs1, 1);
  358. u8x8_set_ctrl_bit(u8x8, cs2, 1);
  359. u8x8_set_ctrl_bit(u8x8, cs3, 1);
  360. u8x8_set_ctrl_bit(u8x8, I2C_LCD_CD, 0);
  361. break;
  362. case U8X8_MSG_BYTE_SET_DC:
  363. u8x8_set_ctrl_bit(u8x8, I2C_LCD_CD, arg_int); // command/data
  364. break;
  365. case U8X8_MSG_BYTE_START_TRANSFER:
  366. /* expects 3 bits in arg_int for the chip select lines */
  367. if ( arg_int&1 ) u8x8->i2c_started|=cs1; else u8x8->i2c_started&=~cs1;
  368. if ( arg_int&2 ) u8x8->i2c_started|=cs2; else u8x8->i2c_started&=~cs2;
  369. if ( arg_int&4 ) u8x8->i2c_started|=cs3; else u8x8->i2c_started&=~cs3;
  370. u8x8_set_ctrl_bit(u8x8, 0, 1); // just transmit the control byte (which is stored in "i2c_started" member variable)
  371. //u8x8_set_ctrl_bit(u8x8, chip_select, u8x8->display_info->chip_enable_level); // command/data data/command
  372. //u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->post_chip_enable_wait_ns, NULL);
  373. break;
  374. case U8X8_MSG_BYTE_END_TRANSFER:
  375. /* expects 3 bits in arg_int for the chip select lines */
  376. if ( arg_int&1 ) u8x8->i2c_started|=cs1; else u8x8->i2c_started&=~cs1;
  377. if ( arg_int&2 ) u8x8->i2c_started|=cs2; else u8x8->i2c_started&=~cs2;
  378. if ( arg_int&4 ) u8x8->i2c_started|=cs3; else u8x8->i2c_started&=~cs3;
  379. u8x8_set_ctrl_bit(u8x8, 0, 1); // just transmit the control byte (which is stored in "i2c_started" member variable)
  380. //u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->pre_chip_disable_wait_ns, NULL);
  381. //u8x8_set_ctrl_bit(u8x8, chip_select, u8x8->display_info->chip_disable_level); // command/data data/command
  382. break;
  383. default:
  384. return 0;
  385. }
  386. return 1;
  387. }
  388. U8G2 u8g2; // create a plain U8g2 object
  389. void setup(void)
  390. {
  391. /*
  392. Do a manual update of the plain U8g2 object with the C API for the display.
  393. Use a special byte function, which includes the support for the I2C LCD GFX board.
  394. The C init functions are listed here: https://github.com/olikraus/u8g2/wiki/u8g2setupc
  395. Just replace the function name accordingly.
  396. Note:
  397. For T6963 / ST7920 displays, use the "u8x8_byte_i2c_lcd_gfx_board_t6963_8080" callback function.
  398. For LC7981 displays, use the "u8x8_byte_i2c_lcd_gfx_board_lc7981_6800" callback function.
  399. For SBN1661 / SED1520 use the "u8x8_byte_i2c_lcd_gfx_board_sed1520_6800" callback function.
  400. */
  401. //u8g2_Setup_t6963_240x128_2(u8g2.getU8g2(), U8G2_R0, u8x8_byte_i2c_lcd_gfx_board_t6963_8080, u8x8_gpio_and_delay_i2c_lcd_gfx_board); // J4
  402. //u8g2_Setup_t6963_128x128_2(u8g2.getU8g2(), U8G2_R0, u8x8_byte_i2c_lcd_gfx_board_t6963_8080, u8x8_gpio_and_delay_i2c_lcd_gfx_board); // J2
  403. //u8g2_Setup_sed1520_122x32_2(u8g2.getU8g2(), U8G2_R0, u8x8_byte_i2c_lcd_gfx_board_sed1520_6800, u8x8_gpio_and_delay_i2c_lcd_gfx_board); // J5
  404. //u8g2_Setup_st7920_128x64_2(u8g2.getU8g2(), U8G2_R0, u8x8_byte_i2c_lcd_gfx_board_st7920, u8x8_gpio_and_delay_i2c_lcd_gfx_board); // J3
  405. //u8g2_Setup_lc7981_240x128_2(u8g2.getU8g2(), U8G2_R0, u8x8_byte_i2c_lcd_gfx_board_lc7981_6800, u8x8_gpio_and_delay_i2c_lcd_gfx_board); // J3
  406. u8g2_Setup_ks0108_erm19264_2(u8g2.getU8g2(), U8G2_R0, u8x8_byte_i2c_lcd_gfx_board_ks0108, u8x8_gpio_and_delay_i2c_lcd_gfx_board); // J9 (requires 2024 PCB)
  407. /*
  408. After providing the callback function, start the communication with the display by using u8g2.begin()
  409. */
  410. u8g2.begin();
  411. }
  412. void drawLogo(void)
  413. {
  414. uint8_t mdy = 0;
  415. if ( u8g2.getDisplayHeight() < 59 )
  416. mdy = 5;
  417. u8g2.setFontMode(1); // Transparent
  418. u8g2.setDrawColor(1);
  419. #ifdef MINI_LOGO
  420. u8g2.setFontDirection(0);
  421. u8g2.setFont(u8g2_font_inb16_mf);
  422. u8g2.drawStr(0, 22, "U");
  423. u8g2.setFontDirection(1);
  424. u8g2.setFont(u8g2_font_inb19_mn);
  425. u8g2.drawStr(14,8,"8");
  426. u8g2.setFontDirection(0);
  427. u8g2.setFont(u8g2_font_inb16_mf);
  428. u8g2.drawStr(36,22,"g");
  429. u8g2.drawStr(48,22,"\xb2");
  430. u8g2.drawHLine(2, 25, 34);
  431. u8g2.drawHLine(3, 26, 34);
  432. u8g2.drawVLine(32, 22, 12);
  433. u8g2.drawVLine(33, 23, 12);
  434. #else
  435. u8g2.setFontDirection(0);
  436. u8g2.setFont(u8g2_font_inb24_mf);
  437. u8g2.drawStr(0, 30-mdy, "U");
  438. u8g2.setFontDirection(1);
  439. u8g2.setFont(u8g2_font_inb30_mn);
  440. u8g2.drawStr(21,8-mdy,"8");
  441. u8g2.setFontDirection(0);
  442. u8g2.setFont(u8g2_font_inb24_mf);
  443. u8g2.drawStr(51,30-mdy,"g");
  444. u8g2.drawStr(67,30-mdy,"\xb2");
  445. u8g2.drawHLine(2, 35-mdy, 47);
  446. u8g2.drawHLine(3, 36-mdy, 47);
  447. u8g2.drawVLine(45, 32-mdy, 12);
  448. u8g2.drawVLine(46, 33-mdy, 12);
  449. #endif
  450. }
  451. void drawURL(void)
  452. {
  453. #ifndef MINI_LOGO
  454. u8g2.setFont(u8g2_font_4x6_tr);
  455. if ( u8g2.getDisplayHeight() < 59 )
  456. {
  457. u8g2.drawStr(89,20-5,"github.com");
  458. u8g2.drawStr(73,29-5,"/olikraus/u8g2");
  459. }
  460. else
  461. {
  462. u8g2.drawStr(1,54,"github.com/olikraus/u8g2");
  463. }
  464. #endif
  465. }
  466. uint8_t x = 0;
  467. long t = 0;
  468. long tt = 0;
  469. void loop(void)
  470. {
  471. t = millis();
  472. u8g2.firstPage();
  473. do
  474. {
  475. u8g2.drawFrame(0,0,u8g2.getDisplayWidth(),u8g2.getDisplayHeight() );
  476. drawLogo();
  477. drawURL();
  478. //u8g2.setFont(u8g2_font_ncenB18_tr);
  479. //u8g2.drawStr(x*2,19,"Hello World!");
  480. u8g2.setFont(u8g2_font_4x6_tr);
  481. u8g2.setCursor(x*2, 62);
  482. u8g2.print(tt, DEC);
  483. } while ( u8g2.nextPage() );
  484. x++;
  485. x &= 15;
  486. tt = millis() - t;
  487. }