test_soft_i2c.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /*
  2. * Copyright (c) 2022-2024, Xiaohua Semiconductor Co., Ltd.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2024-12-30 CDT first version
  9. */
  10. /*
  11. * 程序清单:这是 Soft I2C 设备使用例程。
  12. * 例程导出了 sw_i2c_sample 到控制终端。
  13. * 命令调用格式:sw_i2c_sample cmd_id [options]
  14. * 命令解释:命令第二个参数是要使用的Soft I2C设备的命令,为空则打印命令使用说明
  15. * 程序功能:查找Soft I2C设备,读写I2C设备寄存器。
  16. * 注意:测试要用逻辑分析仪或示波器抓取信号
  17. */
  18. #include <rtthread.h>
  19. #include <rtdevice.h>
  20. #include <board.h>
  21. #include "rtconfig.h"
  22. #include "rtdef.h"
  23. #if defined(RT_USING_I2C)
  24. #if defined(BSP_USING_I2C1_SW)
  25. /* using i2c1 control oled12864 */
  26. #define SW_I2C_NAME "i2c1_sw"
  27. #define SSD1306_ADDR (0x78U >> 1)
  28. #define SSD1306_MD_CMD (0x00U)
  29. #define SSD1306_MD_DATA (0x40U)
  30. /* symbol parameters: width pixles, lenght pixels */
  31. #define SYM_W_PIX (8U)
  32. #define SYM_H_PIX (8U)
  33. /* ssd ohysical parameters */
  34. #define SSD_PAGE_SIZE (8U)
  35. #define SSD_COL_SIZE (128U)
  36. /* each page 8 pix */
  37. #define PAGE_PIX_SIZE (8U)
  38. /* each byte set horizontal 1 pix */
  39. #define SYM_W_BYTE (SYM_W_PIX / 1)
  40. /* each byte set vertical 8 pix */
  41. #define SYM_H_BYTE (SYM_H_PIX / 8)
  42. /* each character occupis */
  43. #define SYM_BYTE_SIZE (SYM_W_BYTE * SYM_H_BYTE)
  44. /* soft i2c command defines */
  45. enum SW_I2C_CMD
  46. {
  47. SW_I2C_INIT = 0x01,
  48. SSD1306_CMD_INIT,
  49. SSD1306_CMD_DISPLAY,
  50. SSD1306_CMD_DEINIT,
  51. };
  52. /* local variables */
  53. struct rt_i2c_msg msg;
  54. rt_uint8_t ssd_init_array[30];
  55. rt_uint8_t logo_array[5][SYM_BYTE_SIZE];
  56. /* local functions */
  57. static void ssd1306_init(struct rt_i2c_bus_device *i2c_dev);
  58. static void ssd1306_roll_display(struct rt_i2c_bus_device *i2c_dev);
  59. static void ssd1306_deinit(struct rt_i2c_bus_device *i2c_dev);
  60. /* write_reg ssd1306 basic opertion */
  61. static void ssd1306_write_single_reg(struct rt_i2c_bus_device *i2c_dev,
  62. rt_bool_t is_write_cmd, rt_uint8_t data)
  63. {
  64. rt_uint8_t buff[2];
  65. struct rt_i2c_msg msgs;
  66. msgs.addr = SSD1306_ADDR;
  67. msgs.flags = RT_I2C_WR;
  68. if (RT_TRUE == is_write_cmd)
  69. {
  70. buff[0] = SSD1306_MD_CMD;
  71. }
  72. else
  73. {
  74. buff[0] = SSD1306_MD_DATA;
  75. }
  76. buff[1] = data;
  77. msgs.buf = buff;
  78. msgs.len = 2;
  79. if (1 != rt_i2c_transfer(i2c_dev, &msgs, 1))
  80. {
  81. rt_kprintf("failed to send cmd\n");
  82. }
  83. }
  84. /* write_reg ssd1306 basic opertion */
  85. static void ssd1306_write_mult_reg(struct rt_i2c_bus_device *i2c_dev,
  86. rt_bool_t is_write_cmd, rt_uint8_t len, rt_uint8_t *data
  87. /*rt_uint8_t data*/)
  88. {
  89. rt_uint8_t *buff = NULL;
  90. struct rt_i2c_msg msgs;
  91. msgs.addr = SSD1306_ADDR;
  92. msgs.flags = RT_I2C_WR;
  93. buff = (rt_uint8_t *)rt_malloc((len + 1) * sizeof(rt_uint8_t));
  94. if (RT_TRUE == is_write_cmd)
  95. {
  96. buff[0] = SSD1306_MD_CMD;
  97. }
  98. else
  99. {
  100. buff[0] = SSD1306_MD_DATA;
  101. }
  102. rt_memcpy(buff + 1, data, len);
  103. msgs.buf = buff;
  104. msgs.len = len + 1;
  105. if (1 != rt_i2c_transfer(i2c_dev, &msgs, 1))
  106. {
  107. rt_kprintf("failed to send cmd\n");
  108. }
  109. rt_free(buff);
  110. buff = NULL;
  111. }
  112. static int sw_i2c_sample(int argc, char *argv[])
  113. {
  114. static struct rt_i2c_bus_device *rt_i2c_dev;
  115. /* print soft i2c usage */
  116. if (argc <= 1)
  117. {
  118. rt_kprintf("soft i2c usage as following:\n");
  119. rt_kprintf("sw_i2c_sample %d: soft i2c init\n", SW_I2C_INIT);
  120. rt_kprintf("sw_i2c_sample %d: oled ssd1306 init\n", SSD1306_CMD_INIT);
  121. rt_kprintf("sw_i2c_sample %d: write ssd1306 \n", SSD1306_CMD_DISPLAY);
  122. rt_kprintf("sw_i2c_sample %d: turn off ssd1306\n", SSD1306_CMD_DEINIT);
  123. return -RT_ERROR;
  124. }
  125. switch (*argv[1] - '0')
  126. {
  127. case SW_I2C_INIT:
  128. rt_i2c_dev = (struct rt_i2c_bus_device *)rt_device_find(SW_I2C_NAME);
  129. if (NULL == rt_i2c_dev)
  130. {
  131. rt_kprintf("failed to find i2c device %s\n", SW_I2C_NAME);
  132. return -RT_ERROR;
  133. }
  134. break;
  135. /* communicate with eeprom to soft i2c read function */
  136. case SSD1306_CMD_INIT:
  137. ssd1306_init(rt_i2c_dev);
  138. break;
  139. /* communicate with ssd1306 to soft i2c read function */
  140. case SSD1306_CMD_DISPLAY:
  141. ssd1306_roll_display(rt_i2c_dev);
  142. break;
  143. case SSD1306_CMD_DEINIT:
  144. ssd1306_deinit(rt_i2c_dev);
  145. break;
  146. default:
  147. rt_kprintf("unkwon command\n");
  148. break;
  149. }
  150. return RT_EOK;
  151. }
  152. /* ssd1306 de-init and turn off */
  153. static void ssd1306_deinit(struct rt_i2c_bus_device *i2c_dev)
  154. {
  155. rt_uint8_t ssd_deinit_array[] =
  156. {
  157. 0X8D, /* set charge pump */
  158. 0X10, /* turn off charge pump */
  159. 0XAE, /* OLED sleep */
  160. };
  161. ssd1306_write_mult_reg(i2c_dev, RT_TRUE,
  162. sizeof(ssd_deinit_array) / sizeof(ssd_deinit_array[0]),
  163. ssd_deinit_array);
  164. }
  165. /* ssd oled initialize */
  166. static void ssd1306_init(struct rt_i2c_bus_device *i2c_dev)
  167. {
  168. ssd1306_write_mult_reg(i2c_dev, RT_TRUE,
  169. sizeof(ssd_init_array) / sizeof(ssd_init_array[0]),
  170. ssd_init_array);
  171. }
  172. /*
  173. Function: write a heigh * width = 16 *16 --->pixel: 16 * 8character
  174. Input: void
  175. Output: void
  176. Data: 20210828
  177. */
  178. void mOledWriteCharHnWm(struct rt_i2c_bus_device *i2c_dev,
  179. uint8_t page, uint8_t col, uint8_t *ArrChar)
  180. {
  181. if (ArrChar == NULL)
  182. return;
  183. rt_kprintf("x=%3d, y=%d\n", col, page);
  184. for (uint8_t page_idx = 0; page_idx < SYM_H_BYTE; page_idx++)
  185. {
  186. /* set start page: page0-page1 */
  187. ssd1306_write_single_reg(i2c_dev, RT_TRUE, 0xb0 + page + page_idx);
  188. /* lower 4-bit address of column start */
  189. ssd1306_write_single_reg(i2c_dev, RT_TRUE, 0x00 + ((col & 0x0F) >> 0));
  190. /* higher 4-bit address of column start */
  191. ssd1306_write_single_reg(i2c_dev, RT_TRUE, 0x10 + ((col & 0xF0) >> 4));
  192. /* send a character(total BYTE_CHAR byte) from array */
  193. ssd1306_write_mult_reg(i2c_dev, RT_FALSE, SYM_W_BYTE,
  194. ArrChar + SYM_W_BYTE * page_idx);
  195. }
  196. }
  197. /* fill oled with character "XHSC" */
  198. static void ssd1306_roll_display(struct rt_i2c_bus_device *i2c_dev)
  199. {
  200. rt_uint8_t base_col, base_page;
  201. rt_uint8_t offset_page, offset_col;
  202. rt_uint16_t idx;
  203. /* using a write times related variable control position */
  204. static rt_uint16_t u16WriteTimes = 0;
  205. if (u16WriteTimes >= (SSD_COL_SIZE / SYM_W_PIX) * (SSD_PAGE_SIZE / (SYM_H_PIX / PAGE_PIX_SIZE)))
  206. {
  207. u16WriteTimes = 0;
  208. }
  209. /* each page write, eg. base_page = 7 / (128 / 8) = 0 */
  210. base_page = u16WriteTimes / (SSD_COL_SIZE / SYM_W_PIX);
  211. /* eg. base_col = (7 % (128 / 8)) * 8 = 56 */
  212. base_col = (u16WriteTimes % (SSD_COL_SIZE / SYM_W_PIX)) * SYM_W_PIX;
  213. offset_page = 0;
  214. offset_col = 0;
  215. /* each write cycle finish the data writing in array */
  216. for (idx = 0; idx < sizeof(logo_array) / sizeof(logo_array[0]); idx++)
  217. {
  218. offset_col = idx * SYM_W_PIX;
  219. if (base_col + offset_col >= SSD_COL_SIZE)
  220. {
  221. /*
  222. base_col + offset_col = [128, 256), page_offset = 1,
  223. base_col + offset_col = [256, 384), page_offset = 2,
  224. ...
  225. */
  226. offset_page = (base_col + offset_col) / SSD_COL_SIZE;
  227. }
  228. mOledWriteCharHnWm(i2c_dev, ((base_page + offset_page) * SYM_H_BYTE) % SSD_PAGE_SIZE, (base_col + offset_col) % SSD_COL_SIZE, *(logo_array + idx));
  229. }
  230. u16WriteTimes++;
  231. }
  232. rt_uint8_t ssd_init_array[] =
  233. {
  234. 0xAE, /* display off */
  235. 0x20, /* Set Memory Addressing Mode */
  236. 0x10, /* Set addressing orient */
  237. 0xB0, /* Set Page Start Address for Page Addressing Mode,0-7 */
  238. 0xC8, /* Set COM Output Scan Direction */
  239. 0x00, /* set low column address */
  240. 0x10, /* set high column address */
  241. 0x40, /* set start line address */
  242. 0x81, /* set contrast control register */
  243. 0xFF, /* breightness 0x00~0xff */
  244. 0xA1, /* set segment re-map 0 to 127 */
  245. 0xA6, /* set normal display */
  246. 0xA8, /* set multiplex ratio(1 to 64) */
  247. 0x3F, /* */
  248. 0xC8, /* */
  249. 0xA4, /* 0xa4,Output follows RAM content;0xa5,Output ignores RAM content */
  250. 0xD3, /* set display offset */
  251. 0x00, /* not offset */
  252. 0xD5, /* set display clock divide ratio/oscillator frequency */
  253. 0xF0, /* set divide ratio */
  254. 0xD9, /* set pre-charge period */
  255. 0x22, /* */
  256. 0xDA, /* set com pins hardware configuration */
  257. 0x12, /* */
  258. 0xDB, /* set vcomh */
  259. 0x20, /* 0x20,0.77xVcc */
  260. 0x8D, /* set DC-DC enable */
  261. 0x14, /* */
  262. 0xAF, /* --turn on oled panel */
  263. };
  264. rt_uint8_t logo_array[][SYM_BYTE_SIZE] =
  265. {
  266. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  267. 0x44, 0x44, 0x6C, 0x74, 0x54, 0x6C, 0x44, 0x44, /*"X"*/
  268. 0x44, 0x7C, 0x54, 0x10, 0x10, 0x54, 0x7C, 0x44, /*"H"*/
  269. 0x00, 0x68, 0x54, 0x54, 0x54, 0x54, 0x24, 0x00, /*"S"*/
  270. 0x38, 0x6C, 0x44, 0x44, 0x44, 0x44, 0x24, 0x00, /*"C"*/
  271. };
  272. MSH_CMD_EXPORT(sw_i2c_sample, soft i2c sample);
  273. #endif /* BSP_USING_I2C1_SW */
  274. #endif/* RT_USING_I2C */
  275. /*
  276. EOF
  277. */