diff --git a/.vscode/settings.json b/.vscode/settings.json
index a1e24f1..9285178 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -52,6 +52,10 @@
"diskio_blkdev.h": "c",
"three_conduction_main.h": "c",
"one_conduction_main.h": "c",
- "one_conduction_board.h": "c"
+ "one_conduction_board.h": "c",
+ "driver_ssd1306.h": "c",
+ "driver_ssd1306_font.h": "c",
+ "driver_ssd1306_basic.h": "c",
+ "driver_ssd1306_interface.h": "c"
}
}
\ No newline at end of file
diff --git a/README.md b/README.md
index 8bca8f0..efc73b0 100644
--- a/README.md
+++ b/README.md
@@ -65,4 +65,11 @@ PIN4 PIN30/PIN31 PIN28/PIN29 PIN11/PIN20
+```
+
+```
+屏幕驱动:
+https://github.com/libdriver/ssd1306
+1306驱动和1312是一样的,只不过1312默认是镜像的
+
```
\ No newline at end of file
diff --git a/app/app.uvoptx b/app/app.uvoptx
index 72e05c0..62ad6a9 100644
--- a/app/app.uvoptx
+++ b/app/app.uvoptx
@@ -488,6 +488,42 @@
0
0
+
+ 1
+ 7
+ 1
+ 0
+ 0
+ 0
+ .\src\basic\ssd1306\driver_ssd1306.c
+ driver_ssd1306.c
+ 0
+ 0
+
+
+ 1
+ 8
+ 1
+ 0
+ 0
+ 0
+ .\src\basic\ssd1306\driver_ssd1306_basic.c
+ driver_ssd1306_basic.c
+ 0
+ 0
+
+
+ 1
+ 9
+ 1
+ 0
+ 0
+ 0
+ .\src\basic\ssd1306\driver_ssd1306_interface.c
+ driver_ssd1306_interface.c
+ 0
+ 0
+
@@ -498,7 +534,7 @@
0
2
- 7
+ 10
1
0
0
@@ -518,7 +554,7 @@
0
3
- 8
+ 11
1
0
0
@@ -530,7 +566,7 @@
3
- 9
+ 12
1
0
0
@@ -550,7 +586,7 @@
0
4
- 10
+ 13
1
0
0
@@ -570,7 +606,7 @@
0
5
- 11
+ 14
1
0
0
@@ -582,7 +618,7 @@
5
- 12
+ 15
1
0
0
@@ -594,7 +630,7 @@
5
- 13
+ 16
1
0
0
@@ -606,7 +642,7 @@
5
- 14
+ 17
1
0
0
@@ -618,7 +654,7 @@
5
- 15
+ 18
1
0
0
@@ -630,7 +666,7 @@
5
- 16
+ 19
1
0
0
@@ -642,7 +678,7 @@
5
- 17
+ 20
1
0
0
@@ -654,7 +690,7 @@
5
- 18
+ 21
1
0
0
@@ -674,7 +710,7 @@
0
6
- 19
+ 22
1
0
0
@@ -694,7 +730,7 @@
0
7
- 20
+ 23
1
0
0
@@ -706,7 +742,7 @@
7
- 21
+ 24
1
0
0
@@ -718,7 +754,7 @@
7
- 22
+ 25
1
0
0
@@ -730,7 +766,7 @@
7
- 23
+ 26
1
0
0
@@ -742,7 +778,7 @@
7
- 24
+ 27
1
0
0
@@ -754,7 +790,7 @@
7
- 25
+ 28
1
0
0
@@ -766,7 +802,7 @@
7
- 26
+ 29
1
0
0
@@ -778,7 +814,7 @@
7
- 27
+ 30
1
0
0
@@ -790,7 +826,7 @@
7
- 28
+ 31
1
0
0
@@ -802,7 +838,7 @@
7
- 29
+ 32
1
0
0
@@ -814,7 +850,7 @@
7
- 30
+ 33
1
0
0
@@ -826,7 +862,7 @@
7
- 31
+ 34
1
0
0
@@ -838,7 +874,7 @@
7
- 32
+ 35
1
0
0
@@ -850,7 +886,7 @@
7
- 33
+ 36
1
0
0
@@ -862,7 +898,7 @@
7
- 34
+ 37
1
0
0
@@ -874,7 +910,7 @@
7
- 35
+ 38
1
0
0
@@ -886,7 +922,7 @@
7
- 36
+ 39
1
0
0
@@ -898,7 +934,7 @@
7
- 37
+ 40
1
0
0
@@ -918,7 +954,7 @@
0
8
- 38
+ 41
1
0
0
@@ -930,7 +966,7 @@
8
- 39
+ 42
1
0
0
@@ -942,7 +978,7 @@
8
- 40
+ 43
1
0
0
@@ -954,7 +990,7 @@
8
- 41
+ 44
1
0
0
@@ -966,7 +1002,7 @@
8
- 42
+ 45
1
0
0
@@ -978,7 +1014,7 @@
8
- 43
+ 46
1
0
0
@@ -990,7 +1026,7 @@
8
- 44
+ 47
1
0
0
@@ -1002,7 +1038,7 @@
8
- 45
+ 48
1
0
0
@@ -1014,7 +1050,7 @@
8
- 46
+ 49
1
0
0
@@ -1026,7 +1062,7 @@
8
- 47
+ 50
1
0
0
@@ -1038,7 +1074,7 @@
8
- 48
+ 51
1
0
0
@@ -1050,7 +1086,7 @@
8
- 49
+ 52
1
0
0
@@ -1062,7 +1098,7 @@
8
- 50
+ 53
1
0
0
@@ -1074,7 +1110,7 @@
8
- 51
+ 54
1
0
0
@@ -1086,7 +1122,7 @@
8
- 52
+ 55
1
0
0
@@ -1098,7 +1134,7 @@
8
- 53
+ 56
1
0
0
@@ -1110,7 +1146,7 @@
8
- 54
+ 57
1
0
0
@@ -1122,7 +1158,7 @@
8
- 55
+ 58
1
0
0
@@ -1134,7 +1170,7 @@
8
- 56
+ 59
1
0
0
@@ -1146,7 +1182,7 @@
8
- 57
+ 60
1
0
0
@@ -1158,7 +1194,7 @@
8
- 58
+ 61
1
0
0
@@ -1170,7 +1206,7 @@
8
- 59
+ 62
1
0
0
@@ -1182,7 +1218,7 @@
8
- 60
+ 63
1
0
0
@@ -1194,7 +1230,7 @@
8
- 61
+ 64
1
0
0
@@ -1206,7 +1242,7 @@
8
- 62
+ 65
1
0
0
@@ -1218,7 +1254,7 @@
8
- 63
+ 66
1
0
0
@@ -1230,7 +1266,7 @@
8
- 64
+ 67
1
0
0
@@ -1250,7 +1286,7 @@
0
9
- 65
+ 68
1
0
0
@@ -1262,7 +1298,7 @@
9
- 66
+ 69
1
0
0
@@ -1274,7 +1310,7 @@
9
- 67
+ 70
1
0
0
@@ -1286,7 +1322,7 @@
9
- 68
+ 71
1
0
0
@@ -1298,7 +1334,7 @@
9
- 69
+ 72
1
0
0
@@ -1310,7 +1346,7 @@
9
- 70
+ 73
1
0
0
@@ -1330,7 +1366,7 @@
0
10
- 71
+ 74
1
0
0
@@ -1342,7 +1378,7 @@
10
- 72
+ 75
1
0
0
@@ -1354,7 +1390,7 @@
10
- 73
+ 76
1
0
0
@@ -1374,7 +1410,7 @@
0
11
- 74
+ 77
1
0
0
@@ -1386,7 +1422,7 @@
11
- 75
+ 78
1
0
0
@@ -1398,7 +1434,7 @@
11
- 76
+ 79
1
0
0
@@ -1418,7 +1454,7 @@
0
12
- 77
+ 80
1
0
0
@@ -1438,7 +1474,7 @@
0
13
- 78
+ 81
1
0
0
@@ -1450,7 +1486,7 @@
13
- 79
+ 82
1
0
0
diff --git a/app/app.uvprojx b/app/app.uvprojx
index 98703d6..001de2e 100644
--- a/app/app.uvprojx
+++ b/app/app.uvprojx
@@ -413,6 +413,21 @@
1
.\src\one_conduction\one_conduction_main.c
+
+ driver_ssd1306.c
+ 1
+ .\src\basic\ssd1306\driver_ssd1306.c
+
+
+ driver_ssd1306_basic.c
+ 1
+ .\src\basic\ssd1306\driver_ssd1306_basic.c
+
+
+ driver_ssd1306_interface.c
+ 1
+ .\src\basic\ssd1306\driver_ssd1306_interface.c
+
@@ -4162,6 +4177,21 @@
1
.\src\one_conduction\one_conduction_main.c
+
+ driver_ssd1306.c
+ 1
+ .\src\basic\ssd1306\driver_ssd1306.c
+
+
+ driver_ssd1306_basic.c
+ 1
+ .\src\basic\ssd1306\driver_ssd1306_basic.c
+
+
+ driver_ssd1306_interface.c
+ 1
+ .\src\basic\ssd1306\driver_ssd1306_interface.c
+
diff --git a/app/src/basic/m24m02/m24m02.c b/app/src/basic/m24m02/m24m02.c
new file mode 100644
index 0000000..e69de29
diff --git a/app/src/basic/m24m02/m24m02.h b/app/src/basic/m24m02/m24m02.h
new file mode 100644
index 0000000..e69de29
diff --git a/app/src/basic/ssd1306/driver_ssd1306.c b/app/src/basic/ssd1306/driver_ssd1306.c
new file mode 100644
index 0000000..ba864fc
--- /dev/null
+++ b/app/src/basic/ssd1306/driver_ssd1306.c
@@ -0,0 +1,2356 @@
+/**
+ * Copyright (c) 2015 - present LibDriver All rights reserved
+ *
+ * The MIT License (MIT)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * @file driver_ssd1306.c
+ * @brief driver ssd1306 source file
+ * @version 2.0.0
+ * @author Shifeng Li
+ * @date 2021-03-30
+ *
+ * history
+ *
+ * Date | Version | Author | Description
+ * |
---|
2021/03/30 | 2.0 | Shifeng Li | format the code
+ * |
2020/12/10 | 1.0 | Shifeng Li | first upload
+ * |
+ */
+
+#include "driver_ssd1306.h"
+#include "driver_ssd1306_font.h"
+
+/**
+ * @brief chip information definition
+ */
+#define CHIP_NAME "Solomon Systech SSD1306" /**< chip name */
+#define MANUFACTURER_NAME "Solomon Systech" /**< manufacturer name */
+#define SUPPLY_VOLTAGE_MIN 1.65f /**< chip min supply voltage */
+#define SUPPLY_VOLTAGE_MAX 3.3f /**< chip max supply voltage */
+#define MAX_CURRENT 0.78f /**< chip max current */
+#define TEMPERATURE_MIN -40.0f /**< chip min operating temperature */
+#define TEMPERATURE_MAX 85.0f /**< chip max operating temperature */
+#define DRIVER_VERSION 2000 /**< driver version */
+
+/**
+ * @brief chip command data definition
+ */
+#define SSD1306_CMD 0 /**< command */
+#define SSD1306_DATA 1 /**< data */
+
+/**
+ * @brief chip command definition
+ */
+#define SSD1306_CMD_LOWER_COLUMN_START_ADDRESS 0x00 /**< command lower column start address */
+#define SSD1306_CMD_HIGHER_COLUMN_START_ADDRESS 0x10 /**< command higher column start address */
+#define SSD1306_CMD_MEMORY_ADDRESSING_MODE 0x20 /**< command memory addressing mode */
+#define SSD1306_CMD_SET_COLUMN_ADDRESS 0x21 /**< command set column address */
+#define SSD1306_CMD_SET_PAGE_ADDRESS 0x22 /**< command set page address */
+#define SSD1306_CMD_SET_FADE_OUT_AND_BLINKING 0x23 /**< command set fade out and blinking */
+#define SSD1306_CMD_RIGHT_HORIZONTAL_SCROLL 0x26 /**< command right horizontal scroll */
+#define SSD1306_CMD_LEFT_HORIZONTAL_SCROLL 0x27 /**< command left horizontal scroll */
+#define SSD1306_CMD_VERTICAL_RIGHT_HORIZONTAL_SCROLL 0x29 /**< command vertical right horizontal scroll */
+#define SSD1306_CMD_VERTICAL_LEFT_HORIZONTAL_SCROLL 0x2A /**< command vertical left horizontal scroll */
+#define SSD1306_CMD_DEACTIVATE_SCROLL 0x2E /**< command deactivate scroll */
+#define SSD1306_CMD_ACTIVATE_SCROLL 0x2F /**< command activate scroll */
+#define SSD1306_CMD_DISPLAY_START_LINE 0x40 /**< command display start line */
+#define SSD1306_CMD_CONTRAST_CONTROL 0x81 /**< command contrast control */
+#define SSD1306_CMD_CHARGE_PUMP_SETTING 0x8D /**< command charge pump setting */
+#define SSD1306_CMD_COLUMN_0_MAPPED_TO_SEG0 0xA0 /**< command column 0 mapped to seg 0 */
+#define SSD1306_CMD_COLUMN_127_MAPPED_TO_SEG0 0xA1 /**< command column 127 mapped to seg 0 */
+#define SSD1306_CMD_VERTICAL_SCROLL_AREA 0xA3 /**< command vertical scroll area */
+#define SSD1306_CMD_ENTIRE_DISPLAY_OFF 0xA4 /**< command entire display off */
+#define SSD1306_CMD_ENTIRE_DISPLAY_ON 0xA5 /**< command entire display on */
+#define SSD1306_CMD_NORMAL_DISPLAY 0xA6 /**< command normal display */
+#define SSD1306_CMD_INVERSE_DISPLAY 0xA7 /**< command inverse display */
+#define SSD1306_CMD_MULTIPLEX_RATIO 0xA8 /**< command multiplex ratio */
+#define SSD1306_CMD_DISPLAY_OFF 0xAE /**< command display off */
+#define SSD1306_CMD_DISPLAY_ON 0xAF /**< command display on */
+#define SSD1306_CMD_PAGE_ADDR 0xB0 /**< command page address */
+#define SSD1306_CMD_SCAN_DIRECTION_COM0_START 0xC0 /**< command scan direction com 0 start */
+#define SSD1306_CMD_SCAN_DIRECTION_COMN_1_START 0xC8 /**< command scan direction com n-1 start */
+#define SSD1306_CMD_DISPLAY_OFFSET 0xD3 /**< command display offset */
+#define SSD1306_CMD_DISPLAY_CLOCK_DIVIDE 0xD5 /**< command display clock divide */
+#define SSD1306_CMD_SET_ZOOM_IN 0xD6 /**< command set zoom in */
+#define SSD1306_CMD_PRE_CHARGE_PERIOD 0xD9 /**< command pre charge period */
+#define SSD1306_CMD_COM_PINS_CONF 0xDA /**< command com pins conf */
+#define SSD1306_CMD_COMH_DESLECT_LEVEL 0xDB /**< command comh deslect level */
+#define SSD1306_CMD_NOP 0xE3 /**< command nop */
+
+/**
+ * @brief write one byte
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] data is the write data
+ * @param[in] cmd is the command or data type
+ * @return status code
+ * - 0 success
+ * - 1 write failed
+ * @note none
+ */
+static uint8_t a_ssd1306_write_byte(ssd1306_handle_t *handle, uint8_t data, uint8_t cmd)
+{
+ uint8_t res;
+
+ if (handle->iic_spi == SSD1306_INTERFACE_IIC) /* if iic */
+ {
+ if (cmd != 0) /* if data */
+ {
+ if (handle->iic_write(handle->iic_addr, 0x40, &data, 1) != 0) /* write data */
+ {
+ return 1; /* return error */
+ }
+ else
+ {
+ return 0; /* success return 0 */
+ }
+ }
+ else
+ {
+ if (handle->iic_write(handle->iic_addr, 0x00, &data, 1) != 0) /* write command */
+ {
+ return 1; /* return error */
+ }
+ else
+ {
+ return 0; /* success return 0 */
+ }
+ }
+ }
+ else if (handle->iic_spi == SSD1306_INTERFACE_SPI) /* if spi */
+ {
+ res = handle->spi_cmd_data_gpio_write(cmd); /* write data command */
+ if (res != 0) /* check error */
+ {
+ return 1; /* return error */
+ }
+
+ if (handle->spi_write_cmd(&data, 1) != 0) /* write command */
+ {
+ return 1; /* return error */
+ }
+ else
+ {
+ return 0; /* success return 0 */
+ }
+ }
+ else
+ {
+ return 1; /* return error */
+ }
+}
+
+/**
+ * @brief write multiple bytes
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] *data points to a data buffer
+ * @param[in] len is the data length
+ * @param[in] cmd is the command or data type
+ * @return status code
+ * - 0 success
+ * - 1 write failed
+ * @note none
+ */
+static uint8_t a_ssd1306_multiple_write_byte(ssd1306_handle_t *handle, uint8_t *data, uint8_t len, uint8_t cmd)
+{
+ uint8_t res;
+
+ if (handle->iic_spi == SSD1306_INTERFACE_IIC) /* if iic */
+ {
+ if (cmd != 0) /* if data */
+ {
+ if (handle->iic_write(handle->iic_addr, 0x40, data, len) != 0) /* write data */
+ {
+ return 1; /* return error */
+ }
+ else
+ {
+ return 0; /* success return 0 */
+ }
+ }
+ else
+ {
+ if (handle->iic_write(handle->iic_addr, 0x00, data, len) != 0) /* write command */
+ {
+ return 1; /* return error */
+ }
+ else
+ {
+ return 0; /* success return 0 */
+ }
+ }
+ }
+ else if (handle->iic_spi == SSD1306_INTERFACE_SPI) /* if spi */
+ {
+ res = handle->spi_cmd_data_gpio_write(cmd); /* write data command */
+ if (res != 0) /* check error */
+ {
+ return 1; /* return error */
+ }
+
+ if (handle->spi_write_cmd(data, len) != 0) /* write command */
+ {
+ return 1; /* return error */
+ }
+ else
+ {
+ return 0; /* success return 0 */
+ }
+ }
+ else
+ {
+ return 1; /* return error */
+ }
+}
+
+/**
+ * @brief draw a point in gram
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[in] data is the write data
+ * @return status code
+ * - 0 success
+ * - 1 gram draw point failed
+ * @note none
+ */
+static uint8_t a_ssd1306_gram_draw_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t data)
+{
+ uint8_t pos;
+ uint8_t bx;
+ uint8_t temp = 0;
+
+ pos = y / 8; /* get y page */
+ bx = y % 8; /* get y point */
+ temp = 1 << bx; /* set data */
+ if (data != 0) /* if 1 */
+ {
+ handle->gram[x][pos] |= temp; /* set 1 */
+ }
+ else
+ {
+ handle->gram[x][pos] &= ~temp; /* set 0 */
+ }
+
+ return 0; /* success return 0 */
+}
+
+/**
+ * @brief draw a char in gram
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[in] chr is the write char
+ * @param[in] size is the char size
+ * @param[in] mode is the display mode
+ * @return status code
+ * - 0 success
+ * - 1 gram show char failed
+ * @note none
+ */
+static uint8_t a_ssd1306_gram_show_char(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t chr, uint8_t size, uint8_t mode)
+{
+ uint8_t temp, t, t1;
+ uint8_t y0 = y;
+ uint8_t csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2); /* get size */
+
+ chr = chr - ' '; /* get index */
+ for (t = 0; t < csize; t++) /* write size */
+ {
+ if (size == 12) /* if size 12 */
+ {
+ temp = gsc_ssd1306_ascii_1206[chr][t]; /* get ascii 1206 */
+ }
+ else if (size == 16) /* if size 16 */
+ {
+ temp = gsc_ssd1306_ascii_1608[chr][t]; /* get ascii 1608 */
+ }
+ else if(size == 24) /* if size 24 */
+ {
+ temp = gsc_ssd1306_ascii_2412[chr][t]; /* get ascii 2412 */
+ }
+ else
+ {
+ return 1; /* return error */
+ }
+ for (t1 = 0; t1 < 8; t1++) /* write one line */
+ {
+ if ((temp & 0x80) != 0) /* if 1 */
+ {
+ if (a_ssd1306_gram_draw_point(handle, x, y, mode) != 0) /* draw point */
+ {
+ return 1; /* return error */
+ }
+ }
+ else
+ {
+ if (a_ssd1306_gram_draw_point(handle, x, y, !mode) != 0) /* draw point */
+ {
+ return 1; /* return error */
+ }
+ }
+ temp <<= 1; /* left shift 1 */
+ y++;
+ if ((y - y0) == size) /* reset size */
+ {
+ y = y0; /* set y */
+ x++; /* x++ */
+
+ break; /* break */
+ }
+ }
+ }
+
+ return 0; /* success return 0 */
+}
+
+/**
+ * @brief clear the screen
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @return status code
+ * - 0 success
+ * - 1 clear failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_clear(ssd1306_handle_t *handle)
+{
+ uint8_t i;
+ uint8_t n;
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ for (i = 0; i < 8; i++) /* write 8 page */
+ {
+ if (a_ssd1306_write_byte(handle, SSD1306_CMD_PAGE_ADDR+i, SSD1306_CMD) != 0) /* set page */
+ {
+ handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */
+
+ return 1; /* return error */
+ }
+ if (a_ssd1306_write_byte(handle, SSD1306_CMD_LOWER_COLUMN_START_ADDRESS, SSD1306_CMD) != 0) /* set lower column 0 */
+ {
+ handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */
+
+ return 1; /* return error */
+ }
+ if (a_ssd1306_write_byte(handle, SSD1306_CMD_HIGHER_COLUMN_START_ADDRESS, SSD1306_CMD) != 0) /* set higher column 0 */
+ {
+ handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */
+
+ return 1; /* return error */
+ }
+ for (n = 0; n < 128; n++) /* write 128 */
+ {
+ handle->gram[n][i] = 0x00; /* set black */
+ if (a_ssd1306_write_byte(handle, handle->gram[n][i], SSD1306_DATA) != 0) /* write data */
+ {
+ handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */
+
+ return 1; /* return error */
+ }
+ }
+ }
+
+ return 0; /* success return 0 */
+}
+
+/**
+ * @brief update the gram data
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @return status code
+ * - 0 success
+ * - 1 gram update failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_gram_update(ssd1306_handle_t *handle)
+{
+ uint8_t i;
+ uint8_t n;
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ for (i = 0; i < 8; i++) /* write 8 page */
+ {
+ if (a_ssd1306_write_byte(handle, SSD1306_CMD_PAGE_ADDR+i, SSD1306_CMD) != 0) /* set page */
+ {
+ handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */
+
+ return 1; /* return error */
+ }
+ if (a_ssd1306_write_byte(handle, SSD1306_CMD_LOWER_COLUMN_START_ADDRESS, SSD1306_CMD) != 0) /* set lower column 0 */
+ {
+ handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */
+
+ return 1; /* return error */
+ }
+ if (a_ssd1306_write_byte(handle, SSD1306_CMD_HIGHER_COLUMN_START_ADDRESS, SSD1306_CMD) != 0) /* set higher column 0 */
+ {
+ handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */
+
+ return 1; /* return error */
+ }
+ for (n = 0; n < 128; n++) /* write 128 */
+ {
+ if (a_ssd1306_write_byte(handle, handle->gram[n][i], SSD1306_DATA) != 0) /* write data */
+ {
+ handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */
+
+ return 1; /* return error */
+ }
+ }
+ }
+
+ return 0; /* success return 0 */
+}
+
+/**
+ * @brief write a point
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[in] data is the write data
+ * @return status code
+ * - 0 success
+ * - 1 write point failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 x or y is invalid
+ * @note none
+ */
+uint8_t ssd1306_write_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t data)
+{
+ uint8_t pos;
+ uint8_t bx;
+ uint8_t temp = 0;
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if ((x > 127) || (y > 63)) /* check x, y */
+ {
+ handle->debug_print("ssd1306: x or y is invalid.\n"); /* x or y is invalid */
+
+ return 4; /* return error */
+ }
+
+ pos = y / 8; /* get y page */
+ bx = y % 8; /* get y point */
+ temp = 1 << bx; /* set data */
+ if (data != 0) /* check the data */
+ {
+ handle->gram[x][pos] |= temp; /* set 1 */
+ }
+ else
+ {
+ handle->gram[x][pos] &= ~temp; /* set 0 */
+ }
+ if (a_ssd1306_write_byte(handle, SSD1306_CMD_PAGE_ADDR + pos, SSD1306_CMD) != 0) /* write page addr */
+ {
+ handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */
+
+ return 1; /* return error */
+ }
+ if (a_ssd1306_write_byte(handle, SSD1306_CMD_LOWER_COLUMN_START_ADDRESS|(x&0x0F), SSD1306_CMD) != 0) /* write lower column */
+ {
+ handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */
+
+ return 1; /* return error */
+ }
+ if (a_ssd1306_write_byte(handle, SSD1306_CMD_HIGHER_COLUMN_START_ADDRESS|((x>4)&0x0F), SSD1306_CMD) != 0) /* write higher column */
+ {
+ handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */
+
+ return 1; /* return error */
+ }
+ if (a_ssd1306_write_byte(handle, handle->gram[x][pos], SSD1306_DATA) != 0) /* write data */
+ {
+ handle->debug_print("ssd1306: write byte failed.\n"); /* write byte failed */
+
+ return 1; /* return error */
+ }
+ else
+ {
+ return 0; /* success return 0 */
+ }
+}
+
+/**
+ * @brief read a point
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[out] *data points to a data buffer
+ * @return status code
+ * - 0 success
+ * - 1 read point failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 x or y is invalid
+ * @note none
+ */
+uint8_t ssd1306_read_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t *data)
+{
+ uint8_t pos;
+ uint8_t bx;
+ uint8_t temp = 0;
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if ((x > 127) || (y > 63)) /* check x, y */
+ {
+ handle->debug_print("ssd1306: x or y is invalid.\n"); /* x or y is invalid */
+
+ return 4; /* return error */
+ }
+
+ pos = y / 8; /* get y page */
+ bx = y % 8; /* get y point */
+ temp = 1 << bx; /* set data */
+ if ((handle->gram[x][pos] & temp) != 0) /* get data */
+ {
+ *data = 1; /* set 1 */
+ }
+ else
+ {
+ *data = 0; /* set 0 */
+ }
+
+ return 0; /* success return 0 */
+}
+
+/**
+ * @brief write a point in the gram
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[in] data is the write data
+ * @return status code
+ * - 0 success
+ * - 1 gram write point failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 x or y is invalid
+ * @note none
+ */
+uint8_t ssd1306_gram_write_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t data)
+{
+ uint8_t pos;
+ uint8_t bx;
+ uint8_t temp = 0;
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if ((x > 127) || (y > 63)) /* check x, y */
+ {
+ handle->debug_print("ssd1306: x or y is invalid.\n"); /* x or y is invalid */
+
+ return 4; /* return error */
+ }
+
+ pos = y / 8; /* get y page */
+ bx = y % 8; /* get y point */
+ temp = 1 << bx; /* set data */
+ if (data != 0) /* if 1 */
+ {
+ handle->gram[x][pos] |= temp; /* set 1 */
+ }
+ else
+ {
+ handle->gram[x][pos] &= ~temp; /* set 0 */
+ }
+
+ return 0; /* success return 0 */
+}
+
+/**
+ * @brief read a point from the gram
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[out] *data points to a data buffer
+ * @return status code
+ * - 0 success
+ * - 1 gram read point failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 x or y is invalid
+ * @note none
+ */
+uint8_t ssd1306_gram_read_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t *data)
+{
+ uint8_t pos;
+ uint8_t bx;
+ uint8_t temp = 0;
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if ((x > 127) || (y > 63)) /* check x, y */
+ {
+ handle->debug_print("ssd1306: x or y is invalid.\n"); /* x or y is invalid */
+
+ return 4; /* return error */
+ }
+
+ pos = y / 8; /* get y page */
+ bx = y % 8; /* get y point */
+ temp = 1 << bx; /* set data */
+ if ((handle->gram[x][pos] & temp) != 0) /* get data */
+ {
+ *data = 1; /* set 1 */
+ }
+ else
+ {
+ *data = 0; /* set 0 */
+ }
+
+ return 0; /* success return 0 */
+}
+
+/**
+ * @brief draw a string in the gram
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[in] *str points to a write string address
+ * @param[in] len is the length of the string
+ * @param[in] color is the display color
+ * @param[in] font is the display font size
+ * @return status code
+ * - 0 success
+ * - 1 gram write string failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 x or y is invalid
+ * @note none
+ */
+uint8_t ssd1306_gram_write_string(ssd1306_handle_t *handle, uint8_t x, uint8_t y, char *str, uint16_t len, uint8_t color, ssd1306_font_t font)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if((x > 127) || (y > 63)) /* check x, y */
+ {
+ handle->debug_print("ssd1306: x or y is invalid.\n"); /* x or y is invalid */
+
+ return 4; /* return error */
+ }
+
+ while ((len != 0) && (*str <= '~') && (*str >= ' ')) /* write all string */
+ {
+ if (x > (127 - (font / 2))) /* check x point */
+ {
+ x = 0; /* set x */
+ y += (uint8_t)font; /* set next row */
+ }
+ if (y > (63 - font)) /* check y pont */
+ {
+ y = x = 0; /* reset to 0,0 */
+ }
+ if (a_ssd1306_gram_show_char(handle, x, y, *str, font, color) != 0) /* show a char */
+ {
+ return 1; /* return error */
+ }
+ x += (uint8_t)(font / 2); /* x + font/2 */
+ str++; /* str address++ */
+ len--; /* str length-- */
+ }
+
+ return 0; /* success return 0 */
+}
+
+/**
+ * @brief fill a rectangle in the gram
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] left is the left coordinate x
+ * @param[in] top is the top coordinate y
+ * @param[in] right is the right coordinate x
+ * @param[in] bottom is the bottom coordinate y
+ * @param[in] color is the display color
+ * @return status code
+ * - 0 success
+ * - 1 gram fill rect failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 left or top is invalid
+ * - 5 right or bottom is invalid
+ * - 6 left > right or top > bottom
+ * @note none
+ */
+uint8_t ssd1306_gram_fill_rect(ssd1306_handle_t *handle, uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t color)
+{
+ uint8_t x, y;
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if ((left > 127) || (top > 63)) /* check left top */
+ {
+ handle->debug_print("ssd1306: left or top is invalid.\n"); /* left or top is invalid */
+
+ return 4; /* return error */
+ }
+ if ((right > 127) || (bottom > 63)) /* check right bottom */
+ {
+ handle->debug_print("ssd1306: right or bottom is invalid.\n"); /* right or bottom is invalid */
+
+ return 5; /* return error */
+ }
+ if ((left > right) || (top > bottom)) /* check left right top bottom */
+ {
+ handle->debug_print("ssd1306: left > right or top > bottom.\n"); /* left > right or top > bottom */
+
+ return 6; /* return error */
+ }
+
+ for (x = left; x <= right; x++) /* write x */
+ {
+ for (y = top; y <= bottom; y++) /* write y */
+ {
+ if (a_ssd1306_gram_draw_point(handle, x, y, color) != 0) /* draw point */
+ {
+ return 1; /* return error */
+ }
+ }
+ }
+
+ return 0; /* return error */
+}
+
+/**
+ * @brief draw a picture in the gram
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] left is the left coordinate x
+ * @param[in] top is the top coordinate y
+ * @param[in] right is the right coordinate x
+ * @param[in] bottom is the bottom coordinate y
+ * @param[in] *img points to an image buffer
+ * @return status code
+ * - 0 success
+ * - 1 gram draw picture failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 left or top is invalid
+ * - 5 right or bottom is invalid
+ * - 6 left > right or top > bottom
+ * @note none
+ */
+uint8_t ssd1306_gram_draw_picture(ssd1306_handle_t *handle, uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t *img)
+{
+ uint8_t x, y;
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if ((left > 127) || (top > 63)) /* check left top */
+ {
+ handle->debug_print("ssd1306: left or top is invalid.\n"); /* left or top is invalid */
+
+ return 4; /* return error */
+ }
+ if ((right > 127) || (bottom > 63)) /* check right bottom */
+ {
+ handle->debug_print("ssd1306: right or bottom is invalid.\n"); /* right or bottom is invalid */
+
+ return 5; /* return error */
+ }
+ if ((left > right) || (top > bottom)) /* check left right top bottom */
+ {
+ handle->debug_print("ssd1306: left > right or top > bottom.\n"); /* left > right or top > bottom */
+
+ return 6; /* return error */
+ }
+
+ for (x = left; x <= right; x++) /* write x */
+ {
+ for (y = top; y <= bottom; y++) /* write y */
+ {
+ if (a_ssd1306_gram_draw_point(handle, x, y, *img) != 0) /* draw point */
+ {
+ return 1; /* return error */
+ }
+ img++; /* img++ */
+ }
+ }
+
+ return 0; /* succeed return 0 */
+}
+
+/**
+ * @brief initialize the chip
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @return status code
+ * - 0 success
+ * - 1 iic or spi initialization failed
+ * - 2 handle is NULL
+ * - 3 linked functions is NULL
+ * - 4 reset failed
+ * - 5 command && data init failed
+ * - 6 interface param is invalid
+ * @note none
+ */
+uint8_t ssd1306_init(ssd1306_handle_t *handle)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->debug_print == NULL) /* check debug_print */
+ {
+ return 3; /* return error */
+ }
+ if (handle->iic_init == NULL) /* check iic_init */
+ {
+ handle->debug_print("ssd1306: iic_init is null.\n"); /* iic_init is null */
+
+ return 3; /* return error */
+ }
+ if (handle->iic_deinit == NULL) /* check iic_deinit */
+ {
+ handle->debug_print("ssd1306: iic_deinit is null.\n"); /* iic_deinit is null */
+
+ return 3; /* return error */
+ }
+ if (handle->iic_write == NULL) /* check iic_write */
+ {
+ handle->debug_print("ssd1306: iic_write is null.\n"); /* iic_write is null */
+
+ return 3; /* return error */
+ }
+ if (handle->spi_init == NULL) /* check spi_init */
+ {
+ handle->debug_print("ssd1306: spi_init is null.\n"); /* spi_init is null */
+
+ return 3; /* return error */
+ }
+ if (handle->spi_deinit == NULL) /* check spi_deinit */
+ {
+ handle->debug_print("ssd1306: spi_deinit is null.\n"); /* spi_deinit is null */
+
+ return 3; /* return error */
+ }
+ if (handle->spi_write_cmd == NULL) /* check spi_write_cmd */
+ {
+ handle->debug_print("ssd1306: spi_write_cmd is null.\n"); /* spi_write_cmd is null */
+
+ return 3; /* return error */
+ }
+ if (handle->delay_ms == NULL) /* check delay_ms */
+ {
+ handle->debug_print("ssd1306: delay_ms is null.\n"); /* delay_ms is null */
+
+ return 3; /* return error */
+ }
+ if (handle->spi_cmd_data_gpio_init == NULL) /* check spi_cmd_data_gpio_init */
+ {
+ handle->debug_print("ssd1306: spi_cmd_data_gpio_init is null.\n"); /* spi_cmd_data_gpio_init is null */
+
+ return 3; /* return error */
+ }
+ if (handle->spi_cmd_data_gpio_deinit == NULL) /* check spi_cmd_data_gpio_deinit */
+ {
+ handle->debug_print("ssd1306: spi_cmd_data_gpio_deinit is null.\n"); /* spi_cmd_data_gpio_deinit is null */
+
+ return 3; /* return error */
+ }
+ if (handle->spi_cmd_data_gpio_write == NULL) /* check spi_cmd_data_gpio_write */
+ {
+ handle->debug_print("ssd1306: spi_cmd_data_gpio_write is null.\n"); /* spi_cmd_data_gpio_write is null */
+
+ return 3; /* return error */
+ }
+ if (handle->reset_gpio_init == NULL) /* check reset_gpio_init */
+ {
+ handle->debug_print("ssd1306: reset_gpio_init is null.\n"); /* reset_gpio_init is null */
+
+ return 3; /* return error */
+ }
+ if (handle->reset_gpio_deinit == NULL) /* check reset_gpio_deinit */
+ {
+ handle->debug_print("ssd1306: reset_gpio_deinit is null.\n"); /* reset_gpio_deinit is null */
+
+ return 3; /* return error */
+ }
+ if(handle->reset_gpio_write == NULL) /* check reset_gpio_write */
+ {
+ handle->debug_print("ssd1306: reset_gpio_write is null.\n"); /* reset_gpio_write is null */
+
+ return 3; /* return error */
+ }
+
+ if (handle->spi_cmd_data_gpio_init() != 0) /* check spi_cmd_data_gpio_init */
+ {
+ handle->debug_print("ssd1306: spi cmd data gpio init failed.\n"); /* spi cmd data gpio init failed */
+
+ return 5; /* return error */
+ }
+ if (handle->reset_gpio_init() != 0) /* reset gpio init */
+ {
+ handle->debug_print("ssd1306: reset gpio init failed.\n"); /* reset gpio init failed */
+ (void)handle->spi_cmd_data_gpio_deinit(); /* spi_cmd_data_gpio_deinit */
+
+ return 4; /* return error */
+ }
+ if (handle->reset_gpio_write(0) != 0) /* write 0 */
+ {
+ handle->debug_print("ssd1306: reset gpio write failed.\n"); /* reset gpio write failed */
+ (void)handle->spi_cmd_data_gpio_deinit(); /* spi_cmd_data_gpio_deinit */
+ (void)handle->reset_gpio_deinit(); /* reset_gpio_deinit */
+
+ return 4; /* return error */
+ }
+ handle->delay_ms(100); /* delay 100 ms */
+ if (handle->reset_gpio_write(1) != 0) /* write 1 */
+ {
+ handle->debug_print("ssd1306: reset gpio write failed.\n"); /* reset gpio write failed */
+ (void)handle->spi_cmd_data_gpio_deinit(); /* spi_cmd_data_gpio_deinit */
+ (void)handle->reset_gpio_deinit(); /* reset_gpio_deinit */
+
+ return 4; /* return error */
+ }
+ if (handle->iic_spi == SSD1306_INTERFACE_IIC) /* if iic interface */
+ {
+ if (handle->iic_init() != 0) /* iic init */
+ {
+ handle->debug_print("ssd1306: iic init failed.\n"); /* iic init failed */
+ (void)handle->spi_cmd_data_gpio_deinit(); /* spi_cmd_data_gpio_deinit */
+ (void)handle->reset_gpio_deinit(); /* reset_gpio_deinit */
+
+ return 1; /* return error */
+ }
+ }
+ else if (handle->iic_spi == SSD1306_INTERFACE_SPI) /* if spi interface */
+ {
+ if (handle->spi_init() != 0) /* spi init */
+ {
+ handle->debug_print("ssd1306: spi init failed.\n"); /* spi init failed */
+ (void)handle->spi_cmd_data_gpio_deinit(); /* spi_cmd_data_gpio_deinit */
+ (void)handle->reset_gpio_deinit(); /* reset_gpio_deinit */
+
+ return 1; /* return error */
+ }
+ }
+ else
+ {
+ handle->debug_print("ssd1306: interface is invalid.\n"); /* interface is invalid */
+ (void)handle->spi_cmd_data_gpio_deinit(); /* spi_cmd_data_gpio_deinit */
+ (void)handle->reset_gpio_deinit(); /* reset_gpio_deinit */
+
+ return 6; /* return error */
+ }
+ handle->inited = 1; /* flag inited */
+
+ return 0; /* success return 0 */
+}
+
+/**
+ * @brief close the chip
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @return status code
+ * - 0 success
+ * - 1 iic or spi deinit failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 power down failed
+ * - 5 reset gpio deinit failed
+ * - 6 command && data deinit failed
+ * - 7 interface param is invalid
+ * @note none
+ */
+uint8_t ssd1306_deinit(ssd1306_handle_t *handle)
+{
+ uint8_t buf[2];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_CHARGE_PUMP_SETTING; /* charge pump off */
+ buf[1] = 0x10 | (0 << 2); /* set charge pump */
+ if (a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD) != 0) /* write command */
+ {
+ handle->debug_print("ssd1306: write command failed.\n"); /* write command failed */
+
+ return 4; /* return error */
+ }
+ if (a_ssd1306_write_byte(handle, SSD1306_CMD_DISPLAY_OFF, SSD1306_CMD) != 0) /* write display off */
+ {
+ handle->debug_print("ssd1306: write command failed.\n"); /* write command failed */
+
+ return 4; /* return error */
+ }
+ if (handle->reset_gpio_deinit() != 0) /* reset gpio deinit */
+ {
+ handle->debug_print("ssd1306: reset gpio deinit failed.\n"); /* reset gpio deinit failed */
+
+ return 5; /* return error */
+ }
+ if (handle->spi_cmd_data_gpio_deinit() != 0) /* spi cmd data gpio deinit */
+ {
+ handle->debug_print("ssd1306: spi cmd data gpio deinit failed.\n"); /* spi cmd data gpio deinit failed */
+
+ return 6; /* return error */
+ }
+ if (handle->iic_spi == SSD1306_INTERFACE_IIC) /* if iic interface */
+ {
+ if (handle->iic_deinit() != 0) /* iic deinit */
+ {
+ handle->debug_print("ssd1306: iic deinit failed.\n"); /* iic deinit failed */
+
+ return 1; /* return error */
+ }
+ }
+ else if (handle->iic_spi == SSD1306_INTERFACE_SPI) /* if spi interface */
+ {
+ if (handle->spi_deinit() != 0) /* spi deinit */
+ {
+ handle->debug_print("ssd1306: spi deinit failed.\n"); /* spi deinit failed */
+
+ return 1; /* return error */
+ }
+ }
+ else
+ {
+ handle->debug_print("ssd1306: interface is invalid.\n"); /* interface is invalid */
+
+ return 7; /* return error */
+ }
+ handle->inited = 0; /* flag close */
+
+ return 0; /* success return 0 */
+}
+
+/**
+ * @brief set the chip interface
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] interface is the chip interface
+ * @return status code
+ * - 0 success
+ * - 2 handle is NULL
+ * @note none
+ */
+uint8_t ssd1306_set_interface(ssd1306_handle_t *handle, ssd1306_interface_t interface)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+
+ handle->iic_spi = (uint8_t)interface; /* set interface */
+
+ return 0; /* success return 0 */
+}
+
+/**
+ * @brief get the chip interface
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[out] *interface points to a chip interface buffer
+ * @return status code
+ * - 0 success
+ * - 2 handle is NULL
+ * @note none
+ */
+uint8_t ssd1306_get_interface(ssd1306_handle_t *handle, ssd1306_interface_t *interface)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+
+ *interface = (ssd1306_interface_t)(handle->iic_spi); /* get interface */
+
+ return 0; /* success return 0 */
+}
+
+/**
+ * @brief set the chip iic address
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] addr_pin is the iic address
+ * @return status code
+ * - 0 success
+ * - 2 handle is NULL
+ * @note none
+ */
+uint8_t ssd1306_set_addr_pin(ssd1306_handle_t *handle, ssd1306_address_t addr_pin)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+
+ handle->iic_addr = (uint8_t)addr_pin; /* set addr pin */
+
+ return 0; /* success return 0 */
+}
+
+/**
+ * @brief get the chip iic address
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[out] *addr_pin points to an iic address buffer
+ * @return status code
+ * - 0 success
+ * - 2 handle is NULL
+ * @note none
+ */
+uint8_t ssd1306_get_addr_pin(ssd1306_handle_t *handle, ssd1306_address_t *addr_pin)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+
+ *addr_pin = (ssd1306_address_t)(handle->iic_addr); /* set address */
+
+ return 0; /* success return 0 */
+}
+
+/**
+ * @brief set the low column start address
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] addr is the low column start address
+ * @return status code
+ * - 0 success
+ * - 1 set low column start address failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 addr is invalid
+ * @note addr <= 0xF
+ */
+uint8_t ssd1306_set_low_column_start_address(ssd1306_handle_t *handle, uint8_t addr)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if (addr > 0x0F) /* check addr */
+ {
+ handle->debug_print("ssd1306: addr is invalid.\n"); /* addr is invalid */
+
+ return 4; /* return error */
+ }
+
+ return a_ssd1306_write_byte(handle, SSD1306_CMD_LOWER_COLUMN_START_ADDRESS|(addr&0x0F), SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the high column start address
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] addr is the high column start address
+ * @return status code
+ * - 0 success
+ * - 1 set high column start address failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 addr is invalid
+ * @note addr <= 0xF
+ */
+uint8_t ssd1306_set_high_column_start_address(ssd1306_handle_t *handle, uint8_t addr)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if (addr > 0x0F) /* check addr */
+ {
+ handle->debug_print("ssd1306: addr is invalid.\n"); /* addr is invalid */
+
+ return 4; /* return error */
+ }
+
+ return a_ssd1306_write_byte(handle, SSD1306_CMD_HIGHER_COLUMN_START_ADDRESS|(addr&0x0F), SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the memory addressing mode
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] mode is the memory addressing mode
+ * @return status code
+ * - 0 success
+ * - 1 set memory addressing mode failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_memory_addressing_mode(ssd1306_handle_t *handle, ssd1306_memory_addressing_mode_t mode)
+{
+ uint8_t buf[2];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_MEMORY_ADDRESSING_MODE; /* set command mode */
+ buf[1] = mode; /* set mode */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the column address range
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] start_addr is the column start address
+ * @param[in] end_addr is the column end address
+ * @return status code
+ * - 0 success
+ * - 1 set column address range failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 start addr is invalid
+ * - 5 end addr is invalid
+ * @note start addr and end addr can't be over 0x7F
+ */
+uint8_t ssd1306_set_column_address_range(ssd1306_handle_t *handle, uint8_t start_addr, uint8_t end_addr)
+{
+ uint8_t buf[3];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if (start_addr > 0x7F) /* check start addr */
+ {
+ handle->debug_print("ssd1306: start addr is invalid.\n"); /* start addr is invalid */
+
+ return 4; /* return error */
+ }
+ if (end_addr > 0x7F) /* check end addr */
+ {
+ handle->debug_print("ssd1306: end addr is invalid.\n"); /* end addr is invalid */
+
+ return 5; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_SET_COLUMN_ADDRESS; /* set command */
+ buf[1] = start_addr & 0x7F; /* set start address */
+ buf[2] = end_addr & 0x7F; /* set end address */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 3, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the page address range
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] start_addr is the page start address
+ * @param[in] end_addr is the page end address
+ * @return status code
+ * - 0 success
+ * - 1 set page address range failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 start addr is invalid
+ * - 5 end addr is invalid
+ * @note start addr and end addr can't be over 0x07
+ */
+uint8_t ssd1306_set_page_address_range(ssd1306_handle_t *handle, uint8_t start_addr, uint8_t end_addr)
+{
+ uint8_t buf[3];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if (start_addr > 0x07) /* check start addr */
+ {
+ handle->debug_print("ssd1306: start addr is invalid.\n"); /* start addr is invalid */
+
+ return 4; /* return error */
+ }
+ if (end_addr > 0x07) /* check end addr */
+ {
+ handle->debug_print("ssd1306: end addr is invalid.\n"); /* end_addr is invalid */
+
+ return 5; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_SET_PAGE_ADDRESS; /* set command */
+ buf[1] = start_addr & 0x07; /* set start address */
+ buf[2] = end_addr & 0x07; /* set end address */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 3, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the fade blinking mode
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] mode is the fade blinking mode
+ * @param[in] frames is the fade or blinking frames
+ * @return status code
+ * - 0 success
+ * - 1 set fade blinking mode failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 frames is invalid
+ * @note frames max is 0x0F and div is (frames + 1) * 8
+ */
+uint8_t ssd1306_set_fade_blinking_mode(ssd1306_handle_t *handle, ssd1306_fade_blinking_mode_t mode, uint8_t frames)
+{
+ uint8_t buf[2];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if (frames> 0x0F) /* check frames */
+ {
+ handle->debug_print("ssd1306: frames is invalid.\n"); /* frames is invalid */
+
+ return 4; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_SET_FADE_OUT_AND_BLINKING; /* set command */
+ buf[1] = (uint8_t)((mode << 4) | (frames & 0x0F)); /* set mode */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the right horizontal scroll
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] start_page_addr is the start page address
+ * @param[in] end_page_addr is the end page address
+ * @param[in] frames is the scroll frames
+ * @return status code
+ * - 0 success
+ * - 1 set right horizontal scroll failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 start page addr is invalid
+ * - 5 end page addr is invalid
+ * @note start_page_addr <= 0x07, end_page_addr <= 0x07
+ */
+uint8_t ssd1306_set_right_horizontal_scroll(ssd1306_handle_t *handle, uint8_t start_page_addr, uint8_t end_page_addr,
+ ssd1306_scroll_frame_t frames)
+{
+ uint8_t buf[7];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if (start_page_addr > 0x07) /* check start_page_addr */
+ {
+ handle->debug_print("ssd1306: start page addr is invalid.\n"); /* start page addr is invalid */
+
+ return 4; /* return error */
+ }
+ if (end_page_addr > 0x07) /* check end_page_addr */
+ {
+ handle->debug_print("ssd1306: end page addr is invalid.\n"); /* end page addr is invalid */
+
+ return 5; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_RIGHT_HORIZONTAL_SCROLL; /* set command */
+ buf[1] = 0x00; /* set null */
+ buf[2] = start_page_addr & 0x07; /* set start page address */
+ buf[3] = frames & 0x07; /* set frames */
+ buf[4] = end_page_addr & 0x07; /* set end page address */
+ buf[5] = 0x00; /* set null */
+ buf[6] = 0xFF; /* set frame end */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 7, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the left horizontal scroll
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] start_page_addr is the start page address
+ * @param[in] end_page_addr is the end page address
+ * @param[in] frames is the scroll frames
+ * @return status code
+ * - 0 success
+ * - 1 set left horizontal scroll failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 start_page_addr is invalid
+ * - 5 end_page_addr is invalid
+ * @note start_page_addr <= 0x07, end_page_addr <= 0x07
+ */
+uint8_t ssd1306_set_left_horizontal_scroll(ssd1306_handle_t *handle, uint8_t start_page_addr, uint8_t end_page_addr,
+ ssd1306_scroll_frame_t frames)
+{
+ uint8_t buf[7];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if (start_page_addr > 0x07) /* check start_page_addr */
+ {
+ handle->debug_print("ssd1306: start_page_addr is invalid.\n"); /* start_page_addr is invalid */
+
+ return 4; /* return error */
+ }
+ if (end_page_addr > 0x07) /* check end_page_addr */
+ {
+ handle->debug_print("ssd1306: end_page_addr is invalid.\n"); /* end_page_addr is invalid */
+
+ return 5; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_LEFT_HORIZONTAL_SCROLL; /* set command */
+ buf[1] = 0x00; /* set null */
+ buf[2] = start_page_addr & 0x07; /* set end page addr */
+ buf[3] = frames & 0x07; /* set frames */
+ buf[4] = end_page_addr & 0x07; /* set end page addr */
+ buf[5] = 0x00; /* set null */
+ buf[6] = 0xFF; /* set frame end */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 7, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the vertical right horizontal scroll
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] start_page_addr is the start page address
+ * @param[in] end_page_addr is the end page address
+ * @param[in] rows is the row address
+ * @param[in] frames is the scroll frames
+ * @return status code
+ * - 0 success
+ * - 1 set vertical right horizontal scroll failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 start_page_addr is invalid
+ * - 5 end_page_addr is invalid
+ * - 6 rows is invalid
+ * @note start_page_addr <= 0x07, end_page_addr <= 0x07, rows <= 0x3F
+ */
+uint8_t ssd1306_set_vertical_right_horizontal_scroll(ssd1306_handle_t *handle, uint8_t start_page_addr, uint8_t end_page_addr,
+ uint8_t rows, ssd1306_scroll_frame_t frames)
+{
+ uint8_t buf[6];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if (start_page_addr > 0x07) /* check start_page_addr */
+ {
+ handle->debug_print("ssd1306: start_page_addr is invalid.\n"); /* start_page_addr is invalid */
+
+ return 4; /* return error */
+ }
+ if (end_page_addr > 0x07) /* check end page addr */
+ {
+ handle->debug_print("ssd1306: end_page_addr is invalid.\n"); /* end_page_addr is invalid */
+
+ return 5; /* return error */
+ }
+ if (rows > 0x3F) /* check rows */
+ {
+ handle->debug_print("ssd1306: rows is invalid.\n"); /* rows is invalid */
+
+ return 6; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_VERTICAL_RIGHT_HORIZONTAL_SCROLL; /* set command */
+ buf[1] = 0x00; /* set null */
+ buf[2] = start_page_addr & 0x07; /* set start page addr */
+ buf[3] = frames & 0x07; /* set frames */
+ buf[4] = end_page_addr & 0x07; /* set end page addr */
+ buf[5] = rows & 0x3F; /* set rows */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 6, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the vertical left horizontal scroll
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] start_page_addr is the start page address
+ * @param[in] end_page_addr is the end page address
+ * @param[in] rows is the row address
+ * @param[in] frames is the scroll frames
+ * @return status code
+ * - 0 success
+ * - 1 set vertical left horizontal scroll failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 start_page_addr is invalid
+ * - 5 end_page_addr is invalid
+ * - 6 rows is invalid
+ * @note start_page_addr <= 0x07, end_page_addr <= 0x07, rows <= 0x3F
+ */
+uint8_t ssd1306_set_vertical_left_horizontal_scroll(ssd1306_handle_t *handle, uint8_t start_page_addr, uint8_t end_page_addr,
+ uint8_t rows, ssd1306_scroll_frame_t frames)
+{
+ uint8_t buf[6];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if (start_page_addr > 0x07) /* check start_page_addr */
+ {
+ handle->debug_print("ssd1306: start_page_addr is invalid.\n"); /* start_page_addr is invalid */
+
+ return 4; /* return error */
+ }
+ if (end_page_addr > 0x07) /* check end_page_addr */
+ {
+ handle->debug_print("ssd1306: end_page_addr is invalid.\n"); /* end_page_addr is invalid */
+
+ return 5; /* return error */
+ }
+ if (rows > 0x3F) /* check rows */
+ {
+ handle->debug_print("ssd1306: rows is invalid.\n"); /* rows is invalid */
+
+ return 6; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_VERTICAL_LEFT_HORIZONTAL_SCROLL; /* set command */
+ buf[1] = 0x00; /* set null */
+ buf[2] = start_page_addr & 0x07; /* set start page addr */
+ buf[3] = frames & 0x07; /* set frames */
+ buf[4] = end_page_addr & 0x07; /* set end page addr */
+ buf[5] = rows & 0x3F; /* set rows */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 6, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief deactivate the scroll
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @return status code
+ * - 0 success
+ * - 1 deactivate scroll failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_deactivate_scroll(ssd1306_handle_t *handle)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ return a_ssd1306_write_byte(handle, SSD1306_CMD_DEACTIVATE_SCROLL, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief activate the scroll
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @return status code
+ * - 0 success
+ * - 1 activate scroll failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_activate_scroll(ssd1306_handle_t *handle)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ return a_ssd1306_write_byte(handle, SSD1306_CMD_ACTIVATE_SCROLL, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the display start line
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] l is the start line
+ * @return status code
+ * - 0 success
+ * - 1 set display start line failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 line is invalid
+ * @note line <= 0x3F
+ */
+uint8_t ssd1306_set_display_start_line(ssd1306_handle_t *handle, uint8_t l)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if (l > 0x3F) /* check line */
+ {
+ handle->debug_print("ssd1306: line is invalid.\n"); /* line is invalid */
+
+ return 4; /* return error */
+ }
+
+ return a_ssd1306_write_byte(handle, SSD1306_CMD_DISPLAY_START_LINE|(l&0x3F), SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the display contrast
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] contrast is the display contrast
+ * @return status code
+ * - 0 success
+ * - 1 set contrast failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_contrast(ssd1306_handle_t *handle, uint8_t contrast)
+{
+ uint8_t buf[2];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_CONTRAST_CONTROL; /* set command */
+ buf[1] = contrast; /* set contrast */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief enable or disable the charge pump
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] enable is a bool value
+ * @return status code
+ * - 0 success
+ * - 1 set charge pump failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_charge_pump(ssd1306_handle_t *handle, ssd1306_charge_pump_t enable)
+{
+ uint8_t buf[2];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_CHARGE_PUMP_SETTING; /* set command */
+ buf[1] = (uint8_t)(0x10 | (enable << 2)); /* set charge pump */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the segment remap
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] remap is the segment remap param
+ * @return status code
+ * - 0 success
+ * - 1 set segment remap failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_segment_remap(ssd1306_handle_t *handle, ssd1306_segment_column_remap_t remap)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ if (remap != 0) /* check remap */
+ {
+ return a_ssd1306_write_byte(handle, SSD1306_CMD_COLUMN_127_MAPPED_TO_SEG0, SSD1306_CMD); /* write remap */
+ }
+ else
+ {
+ return a_ssd1306_write_byte(handle, SSD1306_CMD_COLUMN_0_MAPPED_TO_SEG0, SSD1306_CMD); /* write remap */
+ }
+}
+
+/**
+ * @brief set the vertical scroll area
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] start_row is the start row
+ * @param[in] end_row is the end row
+ * @return status code
+ * - 0 success
+ * - 1 set vertical scroll area failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 start_row is invalid
+ * - 5 end_row is invalid
+ * - 6 end_row > start_row
+ * @note start_row <= 0x3F, end_row <= 0x7F, start_row >= end_row
+ */
+uint8_t ssd1306_set_vertical_scroll_area(ssd1306_handle_t *handle, uint8_t start_row, uint8_t end_row)
+{
+ uint8_t buf[3];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if (start_row > 0x3F) /* check start row */
+ {
+ handle->debug_print("ssd1306: start_row is invalid.\n"); /* start_row is invalid */
+
+ return 4; /* return error */
+ }
+ if (end_row > 0x7F) /* check end_row */
+ {
+ handle->debug_print("ssd1306: end_row is invalid.\n"); /* end_row is invalid */
+
+ return 5; /* return error */
+ }
+ if (end_row > start_row) /* check start_row and end_row */
+ {
+ handle->debug_print("ssd1306: end_row > start_row.\n"); /* end_row > start_row */
+
+ return 6; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_VERTICAL_SCROLL_AREA; /* set command */
+ buf[1] = start_row; /* set start row */
+ buf[2] = end_row; /* set end row */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 3, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief enable or disable the entire display
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] enable is a bool value
+ * @return status code
+ * - 0 success
+ * - 1 set entire display failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_entire_display(ssd1306_handle_t *handle, ssd1306_entire_display_t enable)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ if (enable != 0) /* if enable */
+ {
+ return a_ssd1306_write_byte(handle, SSD1306_CMD_ENTIRE_DISPLAY_ON, SSD1306_CMD); /* write command */
+ }
+ else
+ {
+ return a_ssd1306_write_byte(handle, SSD1306_CMD_ENTIRE_DISPLAY_OFF, SSD1306_CMD); /* write command */
+ }
+}
+
+/**
+ * @brief set the display mode
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] mode is the display mode
+ * @return status code
+ * - 0 success
+ * - 1 set display mode failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_display_mode(ssd1306_handle_t *handle, ssd1306_display_mode_t mode)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ if (mode != 0) /* check mode */
+ {
+ return a_ssd1306_write_byte(handle, SSD1306_CMD_INVERSE_DISPLAY, SSD1306_CMD); /* write command */
+ }
+ else
+ {
+ return a_ssd1306_write_byte(handle, SSD1306_CMD_NORMAL_DISPLAY, SSD1306_CMD); /* write command */
+ }
+}
+
+/**
+ * @brief set the multiplex ratio
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] multiplex is the multiplex ratio
+ * @return status code
+ * - 0 success
+ * - 1 set multiplex ratio failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 multiplex is too small
+ * - 5 multiplex is too large
+ * @note multiplex must be over 0x0E and less than 0x40
+ */
+uint8_t ssd1306_set_multiplex_ratio(ssd1306_handle_t *handle, uint8_t multiplex)
+{
+ uint8_t buf[2];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if (multiplex < 0x0F) /* check multiplex */
+ {
+ handle->debug_print("ssd1306: multiplex is too small.\n"); /* multiplex is too small */
+
+ return 4; /* return error */
+ }
+ if (multiplex > 0x3F) /* check multiplex */
+ {
+ handle->debug_print("ssd1306: multiplex is too large.\n"); /* multiplex is too large */
+
+ return 5; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_MULTIPLEX_RATIO ; /* set command */
+ buf[1] = multiplex; /* set multiplex */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief enable or disable the display
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] on_off is a bool value
+ * @return status code
+ * - 0 success
+ * - 1 set display failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_display(ssd1306_handle_t *handle, ssd1306_display_t on_off)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ if (on_off != 0) /* check on off */
+ {
+ return a_ssd1306_write_byte(handle, SSD1306_CMD_DISPLAY_ON, SSD1306_CMD); /* write command */
+ }
+ else
+ {
+ return a_ssd1306_write_byte(handle, SSD1306_CMD_DISPLAY_OFF, SSD1306_CMD); /* write command */
+ }
+}
+
+/**
+ * @brief set the page address
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] addr is the page address
+ * @return status code
+ * - 0 success
+ * - 1 set page address failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 addr is invalid
+ * @note addr <= 0x07
+ */
+uint8_t ssd1306_set_page_address(ssd1306_handle_t *handle, uint8_t addr)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if (addr > 0x07) /* check addr */
+ {
+ handle->debug_print("ssd1306: addr is invalid.\n"); /* addr is invalid */
+
+ return 4; /* return error */
+ }
+
+ return a_ssd1306_write_byte(handle, SSD1306_CMD_PAGE_ADDR|(addr&0x07), SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the scan direction
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] dir is the scan direction
+ * @return status code
+ * - 0 success
+ * - 1 set scan direction failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_scan_direction(ssd1306_handle_t *handle, ssd1306_scan_direction_t dir)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ if (dir != 0) /* choose dir */
+ {
+ return a_ssd1306_write_byte(handle, SSD1306_CMD_SCAN_DIRECTION_COMN_1_START, SSD1306_CMD); /* write command */
+ }
+ else
+ {
+ return a_ssd1306_write_byte(handle, SSD1306_CMD_SCAN_DIRECTION_COM0_START, SSD1306_CMD); /* write command */
+ }
+}
+
+/**
+ * @brief set the display offset
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] offset is the display offset
+ * @return status code
+ * - 0 success
+ * - 1 set display offset failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 offset is invalid
+ * @note offset <= 0x3F
+ */
+uint8_t ssd1306_set_display_offset(ssd1306_handle_t *handle, uint8_t offset)
+{
+ uint8_t buf[2];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if (offset > 0x3F) /* check offset */
+ {
+ handle->debug_print("ssd1306: offset is invalid.\n"); /* offset is invalid */
+
+ return 4; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_DISPLAY_OFFSET ; /* set command */
+ buf[1] = offset; /* set offset */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the display clock
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] oscillator_frequency is the oscillator frequency
+ * @param[in] clock_divide is the clock divide
+ * @return status code
+ * - 0 success
+ * - 1 set display clock failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 oscillator frequency is invalid
+ * - 5 clock divide is invalid
+ * @note oscillator_frequency <= 0x0F, clock_divide <= 0x0F
+ */
+uint8_t ssd1306_set_display_clock(ssd1306_handle_t *handle, uint8_t oscillator_frequency, uint8_t clock_divide)
+{
+ uint8_t buf[2];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if (oscillator_frequency> 0x0F) /* check oscillator_frequency */
+ {
+ handle->debug_print("ssd1306: oscillator frequency is invalid.\n"); /* oscillator frequency is invalid */
+
+ return 4; /* return error */
+ }
+ if (clock_divide> 0x0F) /* check clock_divide */
+ {
+ handle->debug_print("ssd1306: clock divide is invalid.\n"); /* clock divide is invalid */
+
+ return 5; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_DISPLAY_CLOCK_DIVIDE ; /* set command */
+ buf[1] = (oscillator_frequency<<4) | clock_divide; /* set oscillator frequency and clock divide */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the display zoom in
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] zoom is the display zoom in
+ * @return status code
+ * - 0 success
+ * - 1 set zoom in failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_zoom_in(ssd1306_handle_t *handle, ssd1306_zoom_in_t zoom)
+{
+ uint8_t buf[2];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_SET_ZOOM_IN ; /* set command */
+ buf[1] = zoom; /* set zoom */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the pre charge period
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] phase1_period is the phase1 period
+ * @param[in] phase2_period is the phase2 period
+ * @return status code
+ * - 0 success
+ * - 1 set pre charge period failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 phase1 period is invalid
+ * - 5 phase2 period is invalid
+ * @note phase1_period <= 0x0F, phase2_period <= 0x0F
+ */
+uint8_t ssd1306_set_precharge_period(ssd1306_handle_t *handle, uint8_t phase1_period, uint8_t phase2_period)
+{
+ uint8_t buf[2];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+ if (phase1_period> 0x0F) /* check phase1 period */
+ {
+ handle->debug_print("ssd1306: phase1 period is invalid.\n"); /* phase1 period is invalid */
+
+ return 4; /* return error */
+ }
+ if (phase2_period> 0x0F) /* check phase2 period */
+ {
+ handle->debug_print("ssd1306: phase2 period is invalid.\n"); /* phase2 period is invalid */
+
+ return 5; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_PRE_CHARGE_PERIOD; /* set command */
+ buf[1] = (phase2_period << 4) | phase1_period; /* set period */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the hardware com pins
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] conf is the pin conf
+ * @param[in] remap is the left right remap
+ * @return status code
+ * - 0 success
+ * - 1 set com pins hardware conf failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_com_pins_hardware_conf(ssd1306_handle_t *handle, ssd1306_pin_conf_t conf, ssd1306_left_right_remap_t remap)
+{
+ uint8_t buf[2];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_COM_PINS_CONF; /* set command */
+ buf[1] = (uint8_t)((conf<<4) | (remap<<5) |0x02); /* set com pins */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief set the deselect level
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] level is the deselect level
+ * @return status code
+ * - 0 success
+ * - 1 set deselect level failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_deselect_level(ssd1306_handle_t *handle, ssd1306_deselect_level_t level)
+{
+ uint8_t buf[2];
+
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ buf[0] = SSD1306_CMD_COMH_DESLECT_LEVEL; /* set command */
+ buf[1] = (uint8_t)(level << 4); /* set level */
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, 2, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief write the register command
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] *buf points to a data buffer
+ * @param[in] len is the data length
+ * @return status code
+ * - 0 success
+ * - 1 write failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_write_cmd(ssd1306_handle_t *handle, uint8_t *buf, uint8_t len)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, len, SSD1306_CMD); /* write command */
+}
+
+/**
+ * @brief write the register data
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] *buf points to a data buffer
+ * @param[in] len is the data length
+ * @return status code
+ * - 0 success
+ * - 1 write failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_write_data(ssd1306_handle_t *handle, uint8_t *buf, uint8_t len)
+{
+ if (handle == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+ if (handle->inited != 1) /* check handle initialization */
+ {
+ return 3; /* return error */
+ }
+
+ return a_ssd1306_multiple_write_byte(handle, (uint8_t *)buf, len, SSD1306_DATA); /* write data */
+}
+
+/**
+ * @brief get chip's information
+ * @param[out] *info points to an ssd1306 info structure
+ * @return status code
+ * - 0 success
+ * - 2 handle is NULL
+ * @note none
+ */
+uint8_t ssd1306_info(ssd1306_info_t *info)
+{
+ if (info == NULL) /* check handle */
+ {
+ return 2; /* return error */
+ }
+
+ memset(info, 0, sizeof(ssd1306_info_t)); /* initialize ssd1306 info structure */
+ strncpy(info->chip_name, CHIP_NAME, 32); /* copy chip name */
+ strncpy(info->manufacturer_name, MANUFACTURER_NAME, 32); /* copy manufacturer name */
+ strncpy(info->interface, "IIC SPI", 8); /* copy interface name */
+ info->supply_voltage_min_v = SUPPLY_VOLTAGE_MIN; /* set minimal supply voltage */
+ info->supply_voltage_max_v = SUPPLY_VOLTAGE_MAX; /* set maximum supply voltage */
+ info->max_current_ma = MAX_CURRENT; /* set maximum current */
+ info->temperature_max = TEMPERATURE_MAX; /* set minimal temperature */
+ info->temperature_min = TEMPERATURE_MIN; /* set maximum temperature */
+ info->driver_version = DRIVER_VERSION; /* set driver version */
+
+ return 0; /* success return 0 */
+}
diff --git a/app/src/basic/ssd1306/driver_ssd1306.h b/app/src/basic/ssd1306/driver_ssd1306.h
new file mode 100644
index 0000000..4d762f5
--- /dev/null
+++ b/app/src/basic/ssd1306/driver_ssd1306.h
@@ -0,0 +1,1105 @@
+/**
+ * Copyright (c) 2015 - present LibDriver All rights reserved
+ *
+ * The MIT License (MIT)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * @file driver_ssd1306.h
+ * @brief driver ssd1306 header file
+ * @version 2.0.0
+ * @author Shifeng Li
+ * @date 2021-03-30
+ *
+ * history
+ *
+ * Date | Version | Author | Description
+ * |
---|
2021/03/30 | 2.0 | Shifeng Li | format the code
+ * |
2020/12/10 | 1.0 | Shifeng Li | first upload
+ * |
+ */
+
+#ifndef DRIVER_SSD1306_H
+#define DRIVER_SSD1306_H
+
+#include
+#include
+#include
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/**
+ * @defgroup ssd1306_driver ssd1306 driver function
+ * @brief ssd1306 driver modules
+ * @{
+ */
+
+/**
+ * @addtogroup ssd1306_base_driver
+ * @{
+ */
+
+/**
+ * @brief ssd1306 interface enumeration definition
+ */
+typedef enum
+{
+ SSD1306_INTERFACE_IIC = 0x00, /**< interface iic */
+ SSD1306_INTERFACE_SPI = 0x01, /**< interface spi */
+} ssd1306_interface_t;
+
+/**
+ * @brief ssd1306 address pin enumeration definition
+ */
+typedef enum
+{
+ SSD1306_ADDR_SA0_0 = 0x78, /**< address pin GND */
+ SSD1306_ADDR_SA0_1 = 0x7A, /**< address pin VCC */
+} ssd1306_address_t;
+
+/**
+ * @brief ssd1306 memory addressing mode enumeration definition
+ */
+typedef enum
+{
+ SSD1306_MEMORY_ADDRESSING_MODE_HORIZONTAL = 0x00, /**< horizontal addressing mode */
+ SSD1306_MEMORY_ADDRESSING_MODE_VERTICAL = 0x01, /**< vertical addressing mode */
+ SSD1306_MEMORY_ADDRESSING_MODE_PAGE = 0x02, /**< page addressing mode */
+} ssd1306_memory_addressing_mode_t;
+
+/**
+ * @brief ssd1306 fade blinking mode enumeration definition
+ */
+typedef enum
+{
+ SSD1306_FADE_BLINKING_MODE_DISABLE = 0x00, /**< disable fade blinking mode */
+ SSD1306_FADE_BLINKING_MODE_FADE_OUT = 0x02, /**< fade out fade blinking mode */
+ SSD1306_FADE_BLINKING_MODE_BLINKING = 0x03, /**< blinking fade blinking mode */
+} ssd1306_fade_blinking_mode_t;
+
+/**
+ * @brief ssd1306 scroll frame enumeration definition
+ */
+typedef enum
+{
+ SSD1306_SCROLL_FRAME_2 = 0x07, /**< scroll frame 2 */
+ SSD1306_SCROLL_FRAME_3 = 0x04, /**< scroll frame 3 */
+ SSD1306_SCROLL_FRAME_4 = 0x05, /**< scroll frame 4 */
+ SSD1306_SCROLL_FRAME_5 = 0x00, /**< scroll frame 5 */
+ SSD1306_SCROLL_FRAME_25 = 0x06, /**< scroll frame 25 */
+ SSD1306_SCROLL_FRAME_64 = 0x01, /**< scroll frame 64 */
+ SSD1306_SCROLL_FRAME_128 = 0x02, /**< scroll frame 128 */
+ SSD1306_SCROLL_FRAME_256 = 0x03, /**< scroll frame 256 */
+} ssd1306_scroll_frame_t;
+
+/**
+ * @brief ssd1306 charge pump enumeration definition
+ */
+typedef enum
+{
+ SSD1306_CHARGE_PUMP_DISABLE = 0x00, /**< charge pump disable */
+ SSD1306_CHARGE_PUMP_ENABLE = 0x01, /**< charge pump enable */
+} ssd1306_charge_pump_t;
+
+/**
+ * @brief ssd1306 segment column remap enumeration definition
+ */
+typedef enum
+{
+ SSD1306_SEGMENT_COLUMN_ADDRESS_0 = 0x00, /**< segment column remap address 0 */
+ SSD1306_SEGMENT_COLUMN_ADDRESS_127 = 0x01, /**< segment column remap address 127 */
+} ssd1306_segment_column_remap_t;
+
+/**
+ * @brief ssd1306 entire display enumeration definition
+ */
+typedef enum
+{
+ SSD1306_ENTIRE_DISPLAY_OFF = 0x00, /**< entire display off */
+ SSD1306_ENTIRE_DISPLAY_ON = 0x01, /**< entire display on */
+} ssd1306_entire_display_t;
+
+/**
+ * @brief ssd1306 display mode enumeration definition
+ */
+typedef enum
+{
+ SSD1306_DISPLAY_MODE_NORMAL = 0x00, /**< display mode normal */
+ SSD1306_DISPLAY_MODE_INVERSE = 0x01, /**< display mode inverse */
+} ssd1306_display_mode_t;
+
+/**
+ * @brief ssd1306 display enumeration definition
+ */
+typedef enum
+{
+ SSD1306_DISPLAY_OFF = 0x00, /**< close display */
+ SSD1306_DISPLAY_ON = 0x01, /**< open display */
+} ssd1306_display_t;
+
+/**
+ * @brief ssd1306 scan direction enumeration definition
+ */
+typedef enum
+{
+ SSD1306_SCAN_DIRECTION_COM0_START = 0x00, /**< scan direction com 0 start */
+ SSD1306_SCAN_DIRECTION_COMN_1_START = 0x01, /**< scan direction com N-1 start */
+} ssd1306_scan_direction_t;
+
+/**
+ * @brief ssd1306 zoom in enumeration definition
+ */
+typedef enum
+{
+ SSD1306_ZOOM_IN_DISABLE = 0x00, /**< disable zoom in */
+ SSD1306_ZOOM_IN_ENABLE = 0x01, /**< enable zoom in */
+} ssd1306_zoom_in_t;
+
+/**
+ * @brief ssd1306 pin conf enumeration definition
+ */
+typedef enum
+{
+ SSD1306_PIN_CONF_SEQUENTIAL = 0x00, /**< pin conf sequential */
+ SSD1306_PIN_CONF_ALTERNATIVE = 0x01, /**< pin conf alternative */
+} ssd1306_pin_conf_t;
+
+/**
+ * @brief ssd1306 left right remap enumeration definition
+ */
+typedef enum
+{
+ SSD1306_LEFT_RIGHT_REMAP_DISABLE = 0x00, /**< disable left right remap */
+ SSD1306_LEFT_RIGHT_REMAP_ENABLE = 0x01, /**< enable left right remap */
+} ssd1306_left_right_remap_t;
+
+/**
+ * @brief ssd1306 deselect level enumeration definition
+ */
+typedef enum
+{
+ SSD1306_DESELECT_LEVEL_0P65 = 0x00, /**< deselect level 0.65 */
+ SSD1306_DESELECT_LEVEL_0P77 = 0x02, /**< deselect level 0.77 */
+ SSD1306_DESELECT_LEVEL_0P83 = 0x03, /**< deselect level 0.83 */
+} ssd1306_deselect_level_t;
+
+/**
+ * @brief ssd1306 font enumeration definition
+ */
+typedef enum
+{
+ SSD1306_FONT_12 = 0x0C, /**< font 12 */
+ SSD1306_FONT_16 = 0x10, /**< font 16 */
+ SSD1306_FONT_24 = 0x18, /**< font 24 */
+} ssd1306_font_t;
+
+/**
+ * @brief ssd1306 handle structure definition
+ */
+typedef struct ssd1306_handle_s
+{
+ uint8_t (*iic_init)(void); /**< point to an iic_init function address */
+ uint8_t (*iic_deinit)(void); /**< point to an iic_deinit function address */
+ uint8_t (*iic_write)(uint8_t addr, uint8_t reg, uint8_t *buf, uint16_t len); /**< point to an iic_write function address */
+ uint8_t (*spi_init)(void); /**< point to a spi_init function address */
+ uint8_t (*spi_deinit)(void); /**< point to a spi_deinit function address */
+ uint8_t (*spi_write_cmd)(uint8_t *buf, uint16_t len); /**< point to a spi_write_cmd function address */
+ uint8_t (*spi_cmd_data_gpio_init)(void); /**< point to a spi_cmd_data_gpio_init function address */
+ uint8_t (*spi_cmd_data_gpio_deinit)(void); /**< point to a spi_cmd_data_gpio_deinit function address */
+ uint8_t (*spi_cmd_data_gpio_write)(uint8_t value); /**< point to a spi_cmd_data_gpio_write function address */
+ uint8_t (*reset_gpio_init)(void); /**< point to a reset_gpio_init function address */
+ uint8_t (*reset_gpio_deinit)(void); /**< point to a reset_gpio_deinit function address */
+ uint8_t (*reset_gpio_write)(uint8_t value); /**< point to a reset_gpio_write function address */
+ void (*debug_print)(const char *const fmt, ...); /**< point to a debug_print function address */
+ void (*delay_ms)(uint32_t ms); /**< point to a delay_ms function address */
+ uint8_t inited; /**< inited flag */
+ uint8_t iic_addr; /**< iic address */
+ uint8_t iic_spi; /**< iic spi type */
+ uint8_t gram[128][8]; /**< gram buffer */
+} ssd1306_handle_t;
+
+/**
+ * @brief ssd1306 information structure definition
+ */
+typedef struct ssd1306_info_s
+{
+ char chip_name[32]; /**< chip name */
+ char manufacturer_name[32]; /**< manufacturer name */
+ char interface[8]; /**< chip interface name */
+ float supply_voltage_min_v; /**< chip min supply voltage */
+ float supply_voltage_max_v; /**< chip max supply voltage */
+ float max_current_ma; /**< chip max current */
+ float temperature_min; /**< chip min operating temperature */
+ float temperature_max; /**< chip max operating temperature */
+ uint32_t driver_version; /**< driver version */
+} ssd1306_info_t;
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup ssd1306_link_driver ssd1306 link driver function
+ * @brief ssd1306 link driver modules
+ * @ingroup ssd1306_driver
+ * @{
+ */
+
+/**
+ * @brief initialize ssd1306_handle_t structure
+ * @param[in] HANDLE points to an ssd1306 handle structure
+ * @param[in] STRUCTURE is ssd1306_handle_t
+ * @note none
+ */
+#define DRIVER_SSD1306_LINK_INIT(HANDLE, STRUCTURE) memset(HANDLE, 0, sizeof(STRUCTURE))
+
+/**
+ * @brief link iic_init function
+ * @param[in] HANDLE points to an ssd1306 handle structure
+ * @param[in] FUC points to an iic_init function address
+ * @note none
+ */
+#define DRIVER_SSD1306_LINK_IIC_INIT(HANDLE, FUC) (HANDLE)->iic_init = FUC
+
+/**
+ * @brief link iic_deinit function
+ * @param[in] HANDLE points to an ssd1306 handle structure
+ * @param[in] FUC points to an iic_deinit function address
+ * @note none
+ */
+#define DRIVER_SSD1306_LINK_IIC_DEINIT(HANDLE, FUC) (HANDLE)->iic_deinit = FUC
+
+/**
+ * @brief link iic_write function
+ * @param[in] HANDLE points to an ssd1306 handle structure
+ * @param[in] FUC points to an iic_write function address
+ * @note none
+ */
+#define DRIVER_SSD1306_LINK_IIC_WRITE(HANDLE, FUC) (HANDLE)->iic_write = FUC
+
+/**
+ * @brief link spi_init function
+ * @param[in] HANDLE points to an ssd1306 handle structure
+ * @param[in] FUC points to a spi_init function address
+ * @note none
+ */
+#define DRIVER_SSD1306_LINK_SPI_INIT(HANDLE, FUC) (HANDLE)->spi_init = FUC
+
+/**
+ * @brief link spi_deinit function
+ * @param[in] HANDLE points to an ssd1306 handle structure
+ * @param[in] FUC points to a spi_deinit function address
+ * @note none
+ */
+#define DRIVER_SSD1306_LINK_SPI_DEINIT(HANDLE, FUC) (HANDLE)->spi_deinit = FUC
+
+/**
+ * @brief link spi_write_cmd function
+ * @param[in] HANDLE points to an ssd1306 handle structure
+ * @param[in] FUC points to a spi_write_cmd function address
+ * @note none
+ */
+#define DRIVER_SSD1306_LINK_SPI_WRITE_COMMAND(HANDLE, FUC) (HANDLE)->spi_write_cmd = FUC
+
+/**
+ * @brief link spi_cmd_data_gpio_init function
+ * @param[in] HANDLE points to an ssd1306 handle structure
+ * @param[in] FUC points to a spi_cmd_data_gpio_init function address
+ * @note none
+ */
+#define DRIVER_SSD1306_LINK_SPI_COMMAND_DATA_GPIO_INIT(HANDLE, FUC) (HANDLE)->spi_cmd_data_gpio_init = FUC
+
+/**
+ * @brief link spi_cmd_data_gpio_deinit function
+ * @param[in] HANDLE points to an ssd1306 handle structure
+ * @param[in] FUC points to a spi_cmd_data_gpio_deinit function address
+ * @note none
+ */
+#define DRIVER_SSD1306_LINK_SPI_COMMAND_DATA_GPIO_DEINIT(HANDLE, FUC) (HANDLE)->spi_cmd_data_gpio_deinit = FUC
+
+/**
+ * @brief link spi_cmd_data_gpio_write function
+ * @param[in] HANDLE points to an ssd1306 handle structure
+ * @param[in] FUC points to a spi_cmd_data_gpio_write function address
+ * @note none
+ */
+#define DRIVER_SSD1306_LINK_SPI_COMMAND_DATA_GPIO_WRITE(HANDLE, FUC) (HANDLE)->spi_cmd_data_gpio_write = FUC
+
+/**
+ * @brief link reset_gpio_init function
+ * @param[in] HANDLE points to an ssd1306 handle structure
+ * @param[in] FUC points to a reset_gpio_init function address
+ * @note none
+ */
+#define DRIVER_SSD1306_LINK_RESET_GPIO_INIT(HANDLE, FUC) (HANDLE)->reset_gpio_init = FUC
+
+/**
+ * @brief link reset_gpio_deinit function
+ * @param[in] HANDLE points to an ssd1306 handle structure
+ * @param[in] FUC points to a reset_gpio_deinit function address
+ * @note none
+ */
+#define DRIVER_SSD1306_LINK_RESET_GPIO_DEINIT(HANDLE, FUC) (HANDLE)->reset_gpio_deinit = FUC
+
+/**
+ * @brief link reset_gpio_write function
+ * @param[in] HANDLE points to an ssd1306 handle structure
+ * @param[in] FUC points to a reset_gpio_write function address
+ * @note none
+ */
+#define DRIVER_SSD1306_LINK_RESET_GPIO_WRITE(HANDLE, FUC) (HANDLE)->reset_gpio_write = FUC
+
+/**
+ * @brief link delay_ms function
+ * @param[in] HANDLE points to an ssd1306 handle structure
+ * @param[in] FUC points to a delay_ms function address
+ * @note none
+ */
+#define DRIVER_SSD1306_LINK_DELAY_MS(HANDLE, FUC) (HANDLE)->delay_ms = FUC
+
+/**
+ * @brief link debug_print function
+ * @param[in] HANDLE points to an ssd1306 handle structure
+ * @param[in] FUC points to a debug_print function address
+ * @note none
+ */
+#define DRIVER_SSD1306_LINK_DEBUG_PRINT(HANDLE, FUC) (HANDLE)->debug_print = FUC
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup ssd1306_base_driver ssd1306 base driver function
+ * @brief ssd1306 base driver modules
+ * @ingroup ssd1306_driver
+ * @{
+ */
+
+/**
+ * @brief get chip's information
+ * @param[out] *info points to an ssd1306 info structure
+ * @return status code
+ * - 0 success
+ * - 2 handle is NULL
+ * @note none
+ */
+uint8_t ssd1306_info(ssd1306_info_t *info);
+
+/**
+ * @brief set the chip interface
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] interface is the chip interface
+ * @return status code
+ * - 0 success
+ * - 2 handle is NULL
+ * @note none
+ */
+uint8_t ssd1306_set_interface(ssd1306_handle_t *handle, ssd1306_interface_t interface);
+
+/**
+ * @brief get the chip interface
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[out] *interface points to a chip interface buffer
+ * @return status code
+ * - 0 success
+ * - 2 handle is NULL
+ * @note none
+ */
+uint8_t ssd1306_get_interface(ssd1306_handle_t *handle, ssd1306_interface_t *interface);
+
+/**
+ * @brief set the chip iic address
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] addr_pin is the iic address
+ * @return status code
+ * - 0 success
+ * - 2 handle is NULL
+ * @note none
+ */
+uint8_t ssd1306_set_addr_pin(ssd1306_handle_t *handle, ssd1306_address_t addr_pin);
+
+/**
+ * @brief get the chip iic address
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[out] *addr_pin points to an iic address buffer
+ * @return status code
+ * - 0 success
+ * - 2 handle is NULL
+ * @note none
+ */
+uint8_t ssd1306_get_addr_pin(ssd1306_handle_t *handle, ssd1306_address_t *addr_pin);
+
+/**
+ * @brief initialize the chip
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @return status code
+ * - 0 success
+ * - 1 iic or spi initialization failed
+ * - 2 handle is NULL
+ * - 3 linked functions is NULL
+ * - 4 reset failed
+ * - 5 command && data init failed
+ * - 6 interface param is invalid
+ * @note none
+ */
+uint8_t ssd1306_init(ssd1306_handle_t *handle);
+
+/**
+ * @brief close the chip
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @return status code
+ * - 0 success
+ * - 1 iic or spi deinit failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 power down failed
+ * - 5 reset gpio deinit failed
+ * - 6 command && data deinit failed
+ * - 7 interface param is invalid
+ * @note none
+ */
+uint8_t ssd1306_deinit(ssd1306_handle_t *handle);
+
+/**
+ * @brief clear the screen
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @return status code
+ * - 0 success
+ * - 1 clear failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_clear(ssd1306_handle_t *handle);
+
+/**
+ * @brief update the gram data
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @return status code
+ * - 0 success
+ * - 1 gram update failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_gram_update(ssd1306_handle_t *handle);
+
+/**
+ * @brief write a point
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[in] data is the write data
+ * @return status code
+ * - 0 success
+ * - 1 write point failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 x or y is invalid
+ * @note none
+ */
+uint8_t ssd1306_write_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t data);
+
+/**
+ * @brief read a point
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[out] *data points to a data buffer
+ * @return status code
+ * - 0 success
+ * - 1 read point failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 x or y is invalid
+ * @note none
+ */
+uint8_t ssd1306_read_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t *data);
+
+/**
+ * @brief write a point in the gram
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[in] data is the write data
+ * @return status code
+ * - 0 success
+ * - 1 gram write point failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 x or y is invalid
+ * @note none
+ */
+uint8_t ssd1306_gram_write_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t data);
+
+/**
+ * @brief read a point from the gram
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[out] *data points to a data buffer
+ * @return status code
+ * - 0 success
+ * - 1 gram read point failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 x or y is invalid
+ * @note none
+ */
+uint8_t ssd1306_gram_read_point(ssd1306_handle_t *handle, uint8_t x, uint8_t y, uint8_t *data);
+
+/**
+ * @brief draw a string in the gram
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[in] *str points to a write string address
+ * @param[in] len is the length of the string
+ * @param[in] color is the display color
+ * @param[in] font is the display font size
+ * @return status code
+ * - 0 success
+ * - 1 gram write string failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 x or y is invalid
+ * @note none
+ */
+uint8_t ssd1306_gram_write_string(ssd1306_handle_t *handle, uint8_t x, uint8_t y, char *str, uint16_t len, uint8_t color, ssd1306_font_t font);
+
+/**
+ * @brief fill a rectangle in the gram
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] left is the left coordinate x
+ * @param[in] top is the top coordinate y
+ * @param[in] right is the right coordinate x
+ * @param[in] bottom is the bottom coordinate y
+ * @param[in] color is the display color
+ * @return status code
+ * - 0 success
+ * - 1 gram fill rect failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 left or top is invalid
+ * - 5 right or bottom is invalid
+ * - 6 left > right or top > bottom
+ * @note none
+ */
+uint8_t ssd1306_gram_fill_rect(ssd1306_handle_t *handle, uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t color);
+
+/**
+ * @brief draw a picture in the gram
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] left is the left coordinate x
+ * @param[in] top is the top coordinate y
+ * @param[in] right is the right coordinate x
+ * @param[in] bottom is the bottom coordinate y
+ * @param[in] *img points to an image buffer
+ * @return status code
+ * - 0 success
+ * - 1 gram draw picture failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 left or top is invalid
+ * - 5 right or bottom is invalid
+ * - 6 left > right or top > bottom
+ * @note none
+ */
+uint8_t ssd1306_gram_draw_picture(ssd1306_handle_t *handle, uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t *img);
+
+/**
+ * @brief set the low column start address
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] addr is the low column start address
+ * @return status code
+ * - 0 success
+ * - 1 set low column start address failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 addr is invalid
+ * @note addr <= 0xF
+ */
+uint8_t ssd1306_set_low_column_start_address(ssd1306_handle_t *handle, uint8_t addr);
+
+/**
+ * @brief set the high column start address
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] addr is the high column start address
+ * @return status code
+ * - 0 success
+ * - 1 set high column start address failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 addr is invalid
+ * @note addr <= 0xF
+ */
+uint8_t ssd1306_set_high_column_start_address(ssd1306_handle_t *handle, uint8_t addr);
+
+/**
+ * @brief set the memory addressing mode
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] mode is the memory addressing mode
+ * @return status code
+ * - 0 success
+ * - 1 set memory addressing mode failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_memory_addressing_mode(ssd1306_handle_t *handle, ssd1306_memory_addressing_mode_t mode);
+
+/**
+ * @brief set the column address range
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] start_addr is the column start address
+ * @param[in] end_addr is the column end address
+ * @return status code
+ * - 0 success
+ * - 1 set column address range failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 start addr is invalid
+ * - 5 end addr is invalid
+ * @note start addr and end addr can't be over 0x7F
+ */
+uint8_t ssd1306_set_column_address_range(ssd1306_handle_t *handle, uint8_t start_addr, uint8_t end_addr);
+
+/**
+ * @brief set the page address range
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] start_addr is the page start address
+ * @param[in] end_addr is the page end address
+ * @return status code
+ * - 0 success
+ * - 1 set page address range failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 start addr is invalid
+ * - 5 end addr is invalid
+ * @note start addr and end addr can't be over 0x07
+ */
+uint8_t ssd1306_set_page_address_range(ssd1306_handle_t *handle, uint8_t start_addr, uint8_t end_addr);
+
+/**
+ * @brief set the fade blinking mode
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] mode is the fade blinking mode
+ * @param[in] frames is the fade or blinking frames
+ * @return status code
+ * - 0 success
+ * - 1 set fade blinking mode failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 frames is invalid
+ * @note frames max is 0x0F and div is (frames + 1) * 8
+ */
+uint8_t ssd1306_set_fade_blinking_mode(ssd1306_handle_t *handle, ssd1306_fade_blinking_mode_t mode, uint8_t frames);
+
+/**
+ * @brief set the right horizontal scroll
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] start_page_addr is the start page address
+ * @param[in] end_page_addr is the end page address
+ * @param[in] frames is the scroll frames
+ * @return status code
+ * - 0 success
+ * - 1 set right horizontal scroll failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 start page addr is invalid
+ * - 5 end page addr is invalid
+ * @note start_page_addr <= 0x07, end_page_addr <= 0x07
+ */
+uint8_t ssd1306_set_right_horizontal_scroll(ssd1306_handle_t *handle, uint8_t start_page_addr, uint8_t end_page_addr,
+ ssd1306_scroll_frame_t frames);
+
+/**
+ * @brief set the left horizontal scroll
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] start_page_addr is the start page address
+ * @param[in] end_page_addr is the end page address
+ * @param[in] frames is the scroll frames
+ * @return status code
+ * - 0 success
+ * - 1 set left horizontal scroll failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 start_page_addr is invalid
+ * - 5 end_page_addr is invalid
+ * @note start_page_addr <= 0x07, end_page_addr <= 0x07
+ */
+uint8_t ssd1306_set_left_horizontal_scroll(ssd1306_handle_t *handle, uint8_t start_page_addr, uint8_t end_page_addr,
+ ssd1306_scroll_frame_t frames);
+
+/**
+ * @brief set the vertical right horizontal scroll
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] start_page_addr is the start page address
+ * @param[in] end_page_addr is the end page address
+ * @param[in] rows is the row address
+ * @param[in] frames is the scroll frames
+ * @return status code
+ * - 0 success
+ * - 1 set vertical right horizontal scroll failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 start_page_addr is invalid
+ * - 5 end_page_addr is invalid
+ * - 6 rows is invalid
+ * @note start_page_addr <= 0x07, end_page_addr <= 0x07, rows <= 0x3F
+ */
+uint8_t ssd1306_set_vertical_right_horizontal_scroll(ssd1306_handle_t *handle, uint8_t start_page_addr, uint8_t end_page_addr,
+ uint8_t rows, ssd1306_scroll_frame_t frames);
+
+/**
+ * @brief set the vertical left horizontal scroll
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] start_page_addr is the start page address
+ * @param[in] end_page_addr is the end page address
+ * @param[in] rows is the row address
+ * @param[in] frames is the scroll frames
+ * @return status code
+ * - 0 success
+ * - 1 set vertical left horizontal scroll failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 start_page_addr is invalid
+ * - 5 end_page_addr is invalid
+ * - 6 rows is invalid
+ * @note start_page_addr <= 0x07, end_page_addr <= 0x07, rows <= 0x3F
+ */
+uint8_t ssd1306_set_vertical_left_horizontal_scroll(ssd1306_handle_t *handle, uint8_t start_page_addr, uint8_t end_page_addr,
+ uint8_t rows, ssd1306_scroll_frame_t frames);
+
+/**
+ * @brief deactivate the scroll
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @return status code
+ * - 0 success
+ * - 1 deactivate scroll failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_deactivate_scroll(ssd1306_handle_t *handle);
+
+/**
+ * @brief activate the scroll
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @return status code
+ * - 0 success
+ * - 1 activate scroll failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_activate_scroll(ssd1306_handle_t *handle);
+
+/**
+ * @brief set the display start line
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] l is the start line
+ * @return status code
+ * - 0 success
+ * - 1 set display start line failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 line is invalid
+ * @note line <= 0x3F
+ */
+uint8_t ssd1306_set_display_start_line(ssd1306_handle_t *handle, uint8_t l);
+
+/**
+ * @brief set the display contrast
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] contrast is the display contrast
+ * @return status code
+ * - 0 success
+ * - 1 set contrast failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_contrast(ssd1306_handle_t *handle, uint8_t contrast);
+
+/**
+ * @brief enable or disable the charge pump
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] enable is a bool value
+ * @return status code
+ * - 0 success
+ * - 1 set charge pump failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_charge_pump(ssd1306_handle_t *handle, ssd1306_charge_pump_t enable);
+
+/**
+ * @brief set the segment remap
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] remap is the segment remap param
+ * @return status code
+ * - 0 success
+ * - 1 set segment remap failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_segment_remap(ssd1306_handle_t *handle, ssd1306_segment_column_remap_t remap);
+
+/**
+ * @brief set the vertical scroll area
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] start_row is the start row
+ * @param[in] end_row is the end row
+ * @return status code
+ * - 0 success
+ * - 1 set vertical scroll area failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 start_row is invalid
+ * - 5 end_row is invalid
+ * - 6 end_row > start_row
+ * @note start_row <= 0x3F, end_row <= 0x7F, start_row >= end_row
+ */
+uint8_t ssd1306_set_vertical_scroll_area(ssd1306_handle_t *handle, uint8_t start_row, uint8_t end_row);
+
+/**
+ * @brief enable or disable the entire display
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] enable is a bool value
+ * @return status code
+ * - 0 success
+ * - 1 set entire display failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_entire_display(ssd1306_handle_t *handle, ssd1306_entire_display_t enable);
+
+/**
+ * @brief set the display mode
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] mode is the display mode
+ * @return status code
+ * - 0 success
+ * - 1 set display mode failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_display_mode(ssd1306_handle_t *handle, ssd1306_display_mode_t mode);
+
+/**
+ * @brief set the multiplex ratio
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] multiplex is the multiplex ratio
+ * @return status code
+ * - 0 success
+ * - 1 set multiplex ratio failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 multiplex is too small
+ * - 5 multiplex is too large
+ * @note multiplex must be over 0x0E and less than 0x40
+ */
+uint8_t ssd1306_set_multiplex_ratio(ssd1306_handle_t *handle, uint8_t multiplex);
+
+/**
+ * @brief enable or disable the display
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] on_off is a bool value
+ * @return status code
+ * - 0 success
+ * - 1 set display failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_display(ssd1306_handle_t *handle, ssd1306_display_t on_off);
+
+/**
+ * @brief set the page address
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] addr is the page address
+ * @return status code
+ * - 0 success
+ * - 1 set page address failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 addr is invalid
+ * @note addr <= 0x07
+ */
+uint8_t ssd1306_set_page_address(ssd1306_handle_t *handle, uint8_t addr);
+
+/**
+ * @brief set the scan direction
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] dir is the scan direction
+ * @return status code
+ * - 0 success
+ * - 1 set scan direction failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_scan_direction(ssd1306_handle_t *handle, ssd1306_scan_direction_t dir);
+
+/**
+ * @brief set the display offset
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] offset is the display offset
+ * @return status code
+ * - 0 success
+ * - 1 set display offset failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 offset is invalid
+ * @note offset <= 0x3F
+ */
+uint8_t ssd1306_set_display_offset(ssd1306_handle_t *handle, uint8_t offset);
+
+/**
+ * @brief set the display clock
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] oscillator_frequency is the oscillator frequency
+ * @param[in] clock_divide is the clock divide
+ * @return status code
+ * - 0 success
+ * - 1 set display clock failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 oscillator frequency is invalid
+ * - 5 clock divide is invalid
+ * @note oscillator_frequency <= 0x0F, clock_divide <= 0x0F
+ */
+uint8_t ssd1306_set_display_clock(ssd1306_handle_t *handle, uint8_t oscillator_frequency, uint8_t clock_divide);
+
+/**
+ * @brief set the display zoom in
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] zoom is the display zoom in
+ * @return status code
+ * - 0 success
+ * - 1 set zoom in failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_zoom_in(ssd1306_handle_t *handle, ssd1306_zoom_in_t zoom);
+
+/**
+ * @brief set the pre charge period
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] phase1_period is the phase1 period
+ * @param[in] phase2_period is the phase2 period
+ * @return status code
+ * - 0 success
+ * - 1 set pre charge period failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * - 4 phase1 period is invalid
+ * - 5 phase2 period is invalid
+ * @note phase1_period <= 0x0F, phase2_period <= 0x0F
+ */
+uint8_t ssd1306_set_precharge_period(ssd1306_handle_t *handle, uint8_t phase1_period, uint8_t phase2_period);
+
+/**
+ * @brief set the hardware com pins
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] conf is the pin conf
+ * @param[in] remap is the left right remap
+ * @return status code
+ * - 0 success
+ * - 1 set com pins hardware conf failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_com_pins_hardware_conf(ssd1306_handle_t *handle, ssd1306_pin_conf_t conf, ssd1306_left_right_remap_t remap);
+
+/**
+ * @brief set the deselect level
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] level is the deselect level
+ * @return status code
+ * - 0 success
+ * - 1 set deselect level failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_set_deselect_level(ssd1306_handle_t *handle, ssd1306_deselect_level_t level);
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup ssd1306_extend_driver ssd1306 extend driver function
+ * @brief ssd1306 extend driver modules
+ * @ingroup ssd1306_driver
+ * @{
+ */
+
+/**
+ * @brief write the register command
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] *buf points to a data buffer
+ * @param[in] len is the data length
+ * @return status code
+ * - 0 success
+ * - 1 write failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_write_cmd(ssd1306_handle_t *handle, uint8_t *buf, uint8_t len);
+
+/**
+ * @brief write the register data
+ * @param[in] *handle points to an ssd1306 handle structure
+ * @param[in] *buf points to a data buffer
+ * @param[in] len is the data length
+ * @return status code
+ * - 0 success
+ * - 1 write failed
+ * - 2 handle is NULL
+ * - 3 handle is not initialized
+ * @note none
+ */
+uint8_t ssd1306_write_data(ssd1306_handle_t *handle, uint8_t *buf, uint8_t len);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/app/src/basic/ssd1306/driver_ssd1306_basic.c b/app/src/basic/ssd1306/driver_ssd1306_basic.c
new file mode 100644
index 0000000..79806e7
--- /dev/null
+++ b/app/src/basic/ssd1306/driver_ssd1306_basic.c
@@ -0,0 +1,577 @@
+/**
+ * Copyright (c) 2015 - present LibDriver All rights reserved
+ *
+ * The MIT License (MIT)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * @file driver_ssd1306_basic.c
+ * @brief driver ssd1306 basic source file
+ * @version 2.0.0
+ * @author Shifeng Li
+ * @date 2021-03-30
+ *
+ * history
+ *
+ * Date | Version | Author | Description
+ * |
---|
2021/03/30 | 2.0 | Shifeng Li | format the code
+ * |
2020/12/10 | 1.0 | Shifeng Li | first upload
+ * |
+ */
+
+#include "driver_ssd1306_basic.h"
+
+static ssd1306_handle_t gs_handle; /**< ssd1306 handle */
+
+/**
+ * @brief basic example init
+ * @param[in] interface is the interface type
+ * @param[in] addr is the iic device address
+ * @return status code
+ * - 0 success
+ * - 1 init failed
+ * @note none
+ */
+uint8_t ssd1306_basic_init(ssd1306_interface_t interface, ssd1306_address_t addr)
+{
+ uint8_t res;
+
+ /* link functions */
+ DRIVER_SSD1306_LINK_INIT(&gs_handle, ssd1306_handle_t);
+ DRIVER_SSD1306_LINK_IIC_INIT(&gs_handle, ssd1306_interface_iic_init);
+ DRIVER_SSD1306_LINK_IIC_DEINIT(&gs_handle, ssd1306_interface_iic_deinit);
+ DRIVER_SSD1306_LINK_IIC_WRITE(&gs_handle, ssd1306_interface_iic_write);
+ DRIVER_SSD1306_LINK_SPI_INIT(&gs_handle, ssd1306_interface_spi_init);
+ DRIVER_SSD1306_LINK_SPI_DEINIT(&gs_handle, ssd1306_interface_spi_deinit);
+ DRIVER_SSD1306_LINK_SPI_WRITE_COMMAND(&gs_handle, ssd1306_interface_spi_write_cmd);
+ DRIVER_SSD1306_LINK_SPI_COMMAND_DATA_GPIO_INIT(&gs_handle, ssd1306_interface_spi_cmd_data_gpio_init);
+ DRIVER_SSD1306_LINK_SPI_COMMAND_DATA_GPIO_DEINIT(&gs_handle, ssd1306_interface_spi_cmd_data_gpio_deinit);
+ DRIVER_SSD1306_LINK_SPI_COMMAND_DATA_GPIO_WRITE(&gs_handle, ssd1306_interface_spi_cmd_data_gpio_write);
+ DRIVER_SSD1306_LINK_RESET_GPIO_INIT(&gs_handle, ssd1306_interface_reset_gpio_init);
+ DRIVER_SSD1306_LINK_RESET_GPIO_DEINIT(&gs_handle, ssd1306_interface_reset_gpio_deinit);
+ DRIVER_SSD1306_LINK_RESET_GPIO_WRITE(&gs_handle, ssd1306_interface_reset_gpio_write);
+ DRIVER_SSD1306_LINK_DELAY_MS(&gs_handle, ssd1306_interface_delay_ms);
+ DRIVER_SSD1306_LINK_DEBUG_PRINT(&gs_handle, ssd1306_interface_debug_print);
+
+ /* set interface */
+ res = ssd1306_set_interface(&gs_handle, interface);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set interface failed.\n");
+
+ return 1;
+ }
+
+ /* set addr pin */
+ res = ssd1306_set_addr_pin(&gs_handle, addr);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set addr failed.\n");
+
+ return 1;
+ }
+
+ /* ssd1306 init */
+ res = ssd1306_init(&gs_handle);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: init failed.\n");
+
+ return 1;
+ }
+
+ /* close display */
+ res = ssd1306_set_display(&gs_handle, SSD1306_DISPLAY_OFF);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set display failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set column address range */
+ res = ssd1306_set_column_address_range(&gs_handle, SSD1306_BASIC_DEFAULT_COLUMN_ADDRESS_RANGE_START, SSD1306_BASIC_DEFAULT_COLUMN_ADDRESS_RANGE_END);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set column address range failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set page address range */
+ res = ssd1306_set_page_address_range(&gs_handle, SSD1306_BASIC_DEFAULT_PAGE_ADDRESS_RANGE_START, SSD1306_BASIC_DEFAULT_PAGE_ADDRESS_RANGE_END);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set page address range failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set low column start address */
+ res = ssd1306_set_low_column_start_address(&gs_handle, SSD1306_BASIC_DEFAULT_LOW_COLUMN_START_ADDRESS);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set low column start address failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set high column start address */
+ res = ssd1306_set_high_column_start_address(&gs_handle, SSD1306_BASIC_DEFAULT_HIGH_COLUMN_START_ADDRESS);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set high column start address failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set display start line */
+ res = ssd1306_set_display_start_line(&gs_handle, SSD1306_BASIC_DEFAULT_DISPLAY_START_LINE);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set display start line failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set fade blinking mode */
+ res = ssd1306_set_fade_blinking_mode(&gs_handle, SSD1306_BASIC_DEFAULT_FADE_BLINKING_MODE, SSD1306_BASIC_DEFAULT_FADE_FRAMES);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set fade blinking failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* deactivate scroll */
+ res = ssd1306_deactivate_scroll(&gs_handle);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set deactivate scroll failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set zoom in */
+ res = ssd1306_set_zoom_in(&gs_handle, SSD1306_BASIC_DEFAULT_ZOOM_IN);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set set zoom in failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set contrast */
+ res = ssd1306_set_contrast(&gs_handle, SSD1306_BASIC_DEFAULT_CONTRAST);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set contrast failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set segment remap */
+ res = ssd1306_set_segment_remap(&gs_handle, SSD1306_BASIC_DEFAULT_SEGMENT);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set segment remap failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set scan direction */
+ res = ssd1306_set_scan_direction(&gs_handle, SSD1306_BASIC_DEFAULT_SCAN_DIRECTION);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set scan direction failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set display mode */
+ res = ssd1306_set_display_mode(&gs_handle, SSD1306_BASIC_DEFAULT_DISPLAY_MODE);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set display mode failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set multiplex ratio */
+ res = ssd1306_set_multiplex_ratio(&gs_handle, SSD1306_BASIC_DEFAULT_MULTIPLEX_RATIO);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set multiplex ratio failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set display offset */
+ res = ssd1306_set_display_offset(&gs_handle, SSD1306_BASIC_DEFAULT_DISPLAY_OFFSET);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set display offset failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set display clock */
+ res = ssd1306_set_display_clock(&gs_handle, SSD1306_BASIC_DEFAULT_OSCILLATOR_FREQUENCY, SSD1306_BASIC_DEFAULT_CLOCK_DIVIDE);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set display clock failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set pre charge period */
+ res = ssd1306_set_precharge_period(&gs_handle, SSD1306_BASIC_DEFAULT_PHASE1_PERIOD, SSD1306_BASIC_DEFAULT_PHASE2_PERIOD);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set pre charge period failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set hardware pins conf */
+ res = ssd1306_set_com_pins_hardware_conf(&gs_handle, SSD1306_BASIC_DEFAULT_PIN_CONF, SSD1306_BASIC_DEFAULT_LEFT_RIGHT_REMAP);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set com pins hardware conf failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set deselect level 0.77 */
+ res = ssd1306_set_deselect_level(&gs_handle, SSD1306_BASIC_DEFAULT_DESELECT_LEVEL);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set deselect level failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* set page memory addressing mode */
+ res = ssd1306_set_memory_addressing_mode(&gs_handle, SSD1306_MEMORY_ADDRESSING_MODE_PAGE);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set memory addressing level failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* enable charge pump */
+ res = ssd1306_set_charge_pump(&gs_handle, SSD1306_CHARGE_PUMP_ENABLE);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set charge pump failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* entire display off */
+ res = ssd1306_set_entire_display(&gs_handle, SSD1306_ENTIRE_DISPLAY_OFF);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set entire display failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* enable display */
+ res = ssd1306_set_display(&gs_handle, SSD1306_DISPLAY_ON);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: set display failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ /* clear screen */
+ res = ssd1306_clear(&gs_handle);
+ if (res != 0)
+ {
+ ssd1306_interface_debug_print("ssd1306: clear failed.\n");
+ (void)ssd1306_deinit(&gs_handle);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * @brief basic example deinit
+ * @return status code
+ * - 0 success
+ * - 1 deinit failed
+ * @note none
+ */
+uint8_t ssd1306_basic_deinit(void)
+{
+ /* deinit ssd1306 */
+ if (ssd1306_deinit(&gs_handle) != 0)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/**
+ * @brief basic example display on
+ * @return status code
+ * - 0 success
+ * - 1 display on failed
+ * @note none
+ */
+uint8_t ssd1306_basic_display_on(void)
+{
+ uint8_t res;
+
+ /* display on */
+ res = ssd1306_set_display(&gs_handle, SSD1306_DISPLAY_ON);
+ if (res != 0)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/**
+ * @brief basic example display off
+ * @return status code
+ * - 0 success
+ * - 1 display off failed
+ * @note none
+ */
+uint8_t ssd1306_basic_display_off(void)
+{
+ uint8_t res;
+
+ /* display off */
+ res = ssd1306_set_display(&gs_handle, SSD1306_DISPLAY_OFF);
+ if (res != 0)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/**
+ * @brief basic example clear
+ * @return status code
+ * - 0 success
+ * - 1 clear failed
+ * @note none
+ */
+uint8_t ssd1306_basic_clear(void)
+{
+ /* clear */
+ if (ssd1306_clear(&gs_handle) != 0)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/**
+ * @brief basic example write a point
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[in] data is the written data
+ * @return status code
+ * - 0 success
+ * - 1 write point failed
+ * @note none
+ */
+uint8_t ssd1306_basic_write_point(uint8_t x, uint8_t y, uint8_t data)
+{
+ uint8_t res;
+
+ /* write point */
+ res = ssd1306_write_point(&gs_handle, x, y, data);
+ if (res != 0)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * @brief basic example read a point
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[out] *data points to a data buffer
+ * @return status code
+ * - 0 success
+ * - 1 read point failed
+ * @note none
+ */
+uint8_t ssd1306_basic_read_point(uint8_t x, uint8_t y, uint8_t *data)
+{
+ uint8_t res;
+
+ /* read point in gram */
+ res = ssd1306_read_point(&gs_handle, x, y, data);
+ if (res != 0)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * @brief basic example draw a string
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[in] *str points to a written string address
+ * @param[in] len is the length of the string
+ * @param[in] color is the display color
+ * @param[in] font is the display font size
+ * @return status code
+ * - 0 success
+ * - 1 write string failed
+ * @note none
+ */
+uint8_t ssd1306_basic_string(uint8_t x, uint8_t y, char *str, uint16_t len, uint8_t color, ssd1306_font_t font)
+{
+ uint8_t res;
+
+ /* write string in gram */
+ res = ssd1306_gram_write_string(&gs_handle, x, y, str, len, color, font);
+ if (res != 0)
+ {
+ return 1;
+ }
+
+ /* update gram */
+ if (ssd1306_gram_update(&gs_handle) != 0)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/**
+ * @brief basic example fill a rectangle
+ * @param[in] left is the left coordinate x
+ * @param[in] top is the top coordinate y
+ * @param[in] right is the right coordinate x
+ * @param[in] bottom is the bottom coordinate y
+ * @param[in] color is the display color
+ * @return status code
+ * - 0 success
+ * - 1 fill rect failed
+ * @note none
+ */
+uint8_t ssd1306_basic_rect(uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t color)
+{
+ uint8_t res;
+
+ /* fill rect in gram */
+ res = ssd1306_gram_fill_rect(&gs_handle, left, top, right, bottom, color);
+ if (res != 0)
+ {
+ return 1;
+ }
+
+ /* update gram */
+ if (ssd1306_gram_update(&gs_handle) != 0)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/**
+ * @brief basic example draw a picture
+ * @param[in] left is the left coordinate x
+ * @param[in] top is the top coordinate y
+ * @param[in] right is the right coordinate x
+ * @param[in] bottom is the bottom coordinate y
+ * @param[in] *img points to a image buffer
+ * @return status code
+ * - 0 success
+ * - 1 draw picture failed
+ * @note none
+ */
+uint8_t ssd1306_basic_picture(uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t *img)
+{
+ uint8_t res;
+
+ /* draw picture in gram */
+ res = ssd1306_gram_draw_picture(&gs_handle, left, top, right, bottom, img);
+ if (res != 0)
+ {
+ return 1;
+ }
+
+ /* update gram */
+ if (ssd1306_gram_update(&gs_handle) != 0)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
diff --git a/app/src/basic/ssd1306/driver_ssd1306_basic.h b/app/src/basic/ssd1306/driver_ssd1306_basic.h
new file mode 100644
index 0000000..0480830
--- /dev/null
+++ b/app/src/basic/ssd1306/driver_ssd1306_basic.h
@@ -0,0 +1,203 @@
+/**
+ * Copyright (c) 2015 - present LibDriver All rights reserved
+ *
+ * The MIT License (MIT)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * @file driver_ssd1306_basic.h
+ * @brief driver ssd1306 basic header file
+ * @version 2.0.0
+ * @author Shifeng Li
+ * @date 2021-03-30
+ *
+ * history
+ *
+ * Date | Version | Author | Description
+ * |
---|
2021/03/30 | 2.0 | Shifeng Li | format the code
+ * |
2020/12/10 | 1.0 | Shifeng Li | first upload
+ * |
+ */
+
+#ifndef DRIVER_SSD1306_BASIC_H
+#define DRIVER_SSD1306_BASIC_H
+
+#include "driver_ssd1306_interface.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/**
+ * @defgroup ssd1306_example_driver ssd1306 example driver function
+ * @brief ssd1306 example driver modules
+ * @ingroup ssd1306_driver
+ * @{
+ */
+
+/**
+ * @brief ssd1306 basic example default definition
+ */
+#define SSD1306_BASIC_DEFAULT_DESELECT_LEVEL SSD1306_DESELECT_LEVEL_0P77 /**< set deselect level 0.77 */
+#define SSD1306_BASIC_DEFAULT_LEFT_RIGHT_REMAP SSD1306_LEFT_RIGHT_REMAP_DISABLE /**< disable remap */
+#define SSD1306_BASIC_DEFAULT_PIN_CONF SSD1306_PIN_CONF_ALTERNATIVE /**< set alternative */
+#define SSD1306_BASIC_DEFAULT_PHASE1_PERIOD 0x01 /**< set phase 1 */
+#define SSD1306_BASIC_DEFAULT_PHASE2_PERIOD 0x0F /**< set phase F */
+#define SSD1306_BASIC_DEFAULT_OSCILLATOR_FREQUENCY 0x08 /**< set 8 */
+#define SSD1306_BASIC_DEFAULT_CLOCK_DIVIDE 0x00 /**< set clock div 0 */
+#define SSD1306_BASIC_DEFAULT_DISPLAY_OFFSET 0x00 /**< set display offset */
+#define SSD1306_BASIC_DEFAULT_MULTIPLEX_RATIO 0x3F /**< set ratio */
+#define SSD1306_BASIC_DEFAULT_DISPLAY_MODE SSD1306_DISPLAY_MODE_NORMAL /**< set normal mode */
+#define SSD1306_BASIC_DEFAULT_SCAN_DIRECTION SSD1306_SCAN_DIRECTION_COMN_1_START /**< set scan 1 */
+#define SSD1306_BASIC_DEFAULT_SEGMENT SSD1306_SEGMENT_COLUMN_ADDRESS_127 /**< set column 127 */
+#define SSD1306_BASIC_DEFAULT_CONTRAST 0xCF /**< set contrast CF */
+#define SSD1306_BASIC_DEFAULT_ZOOM_IN SSD1306_ZOOM_IN_DISABLE /**< disable zoom in */
+#define SSD1306_BASIC_DEFAULT_FADE_BLINKING_MODE SSD1306_FADE_BLINKING_MODE_DISABLE /**< disable fade */
+#define SSD1306_BASIC_DEFAULT_FADE_FRAMES 0x00 /**< set frame 0 */
+#define SSD1306_BASIC_DEFAULT_DISPLAY_START_LINE 0x00 /**< set start line 0 */
+#define SSD1306_BASIC_DEFAULT_HIGH_COLUMN_START_ADDRESS 0x00 /**< set high start 0 */
+#define SSD1306_BASIC_DEFAULT_LOW_COLUMN_START_ADDRESS 0x00 /**< set low start 0 */
+#define SSD1306_BASIC_DEFAULT_PAGE_ADDRESS_RANGE_START 0x00 /**< set page range start */
+#define SSD1306_BASIC_DEFAULT_PAGE_ADDRESS_RANGE_END 0x07 /**< set page range end */
+#define SSD1306_BASIC_DEFAULT_COLUMN_ADDRESS_RANGE_START 0x00 /**< set range start */
+#define SSD1306_BASIC_DEFAULT_COLUMN_ADDRESS_RANGE_END 0x7F /**< set range end */
+
+/**
+ * @brief basic example init
+ * @param[in] interface is the interface type
+ * @param[in] addr is the iic device address
+ * @return status code
+ * - 0 success
+ * - 1 init failed
+ * @note none
+ */
+uint8_t ssd1306_basic_init(ssd1306_interface_t interface, ssd1306_address_t addr);
+
+/**
+ * @brief basic example deinit
+ * @return status code
+ * - 0 success
+ * - 1 deinit failed
+ * @note none
+ */
+uint8_t ssd1306_basic_deinit(void);
+
+/**
+ * @brief basic example display on
+ * @return status code
+ * - 0 success
+ * - 1 display on failed
+ * @note none
+ */
+uint8_t ssd1306_basic_display_on(void);
+
+/**
+ * @brief basic example display off
+ * @return status code
+ * - 0 success
+ * - 1 display off failed
+ * @note none
+ */
+uint8_t ssd1306_basic_display_off(void);
+
+/**
+ * @brief basic example clear
+ * @return status code
+ * - 0 success
+ * - 1 clear failed
+ * @note none
+ */
+uint8_t ssd1306_basic_clear(void);
+
+/**
+ * @brief basic example write a point
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[in] data is the written data
+ * @return status code
+ * - 0 success
+ * - 1 write point failed
+ * @note none
+ */
+uint8_t ssd1306_basic_write_point(uint8_t x, uint8_t y, uint8_t data);
+
+/**
+ * @brief basic example read a point
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[out] *data points to a data buffer
+ * @return status code
+ * - 0 success
+ * - 1 read point failed
+ * @note none
+ */
+uint8_t ssd1306_basic_read_point(uint8_t x, uint8_t y, uint8_t *data);
+
+/**
+ * @brief basic example draw a string
+ * @param[in] x is the coordinate x
+ * @param[in] y is the coordinate y
+ * @param[in] *str points to a written string address
+ * @param[in] len is the length of the string
+ * @param[in] color is the display color
+ * @param[in] font is the display font size
+ * @return status code
+ * - 0 success
+ * - 1 write string failed
+ * @note none
+ */
+uint8_t ssd1306_basic_string(uint8_t x, uint8_t y, char *str, uint16_t len, uint8_t color, ssd1306_font_t font);
+
+/**
+ * @brief basic example fill a rectangle
+ * @param[in] left is the left coordinate x
+ * @param[in] top is the top coordinate y
+ * @param[in] right is the right coordinate x
+ * @param[in] bottom is the bottom coordinate y
+ * @param[in] color is the display color
+ * @return status code
+ * - 0 success
+ * - 1 fill rect failed
+ * @note none
+ */
+uint8_t ssd1306_basic_rect(uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t color);
+
+/**
+ * @brief basic example draw a picture
+ * @param[in] left is the left coordinate x
+ * @param[in] top is the top coordinate y
+ * @param[in] right is the right coordinate x
+ * @param[in] bottom is the bottom coordinate y
+ * @param[in] *img points to a image buffer
+ * @return status code
+ * - 0 success
+ * - 1 draw picture failed
+ * @note none
+ */
+uint8_t ssd1306_basic_picture(uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t *img);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/app/src/basic/ssd1306/driver_ssd1306_font.h b/app/src/basic/ssd1306/driver_ssd1306_font.h
new file mode 100644
index 0000000..1734127
--- /dev/null
+++ b/app/src/basic/ssd1306/driver_ssd1306_font.h
@@ -0,0 +1,350 @@
+/**
+ * Copyright (c) 2015 - present LibDriver All rights reserved
+ *
+ * The MIT License (MIT)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * @file driver_ssd1306_font.h
+ * @brief driver ssd1306 font header file
+ * @version 2.0.0
+ * @author Shifeng Li
+ * @date 2021-03-30
+ *
+ * history
+ *
+ * Date | Version | Author | Description
+ * |
---|
2021/03/30 | 2.0 | Shifeng Li | format the code
+ * |
2020/12/10 | 1.0 | Shifeng Li | first upload
+ * |
+ */
+
+#ifndef DRIVER_SSD1306_FONT_H
+#define DRIVER_SSD1306_FONT_H
+
+#include
+#include
+#include
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+static const uint8_t gsc_ssd1306_ascii_1206[95][12] =
+{
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*" ", 0*/
+ {0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"!", 1*/
+ {0x00, 0x00, 0x30, 0x00, 0x40, 0x00, 0x30, 0x00, 0x40, 0x00, 0x00, 0x00}, /*""", 2*/
+ {0x09, 0x00, 0x0B, 0xC0, 0x3D, 0x00, 0x0B, 0xC0, 0x3D, 0x00, 0x09, 0x00}, /*"#", 3*/
+ {0x18, 0xC0, 0x24, 0x40, 0x7F, 0xE0, 0x22, 0x40, 0x31, 0x80, 0x00, 0x00}, /*"$", 4*/
+ {0x18, 0x00, 0x24, 0xC0, 0x1B, 0x00, 0x0D, 0x80, 0x32, 0x40, 0x01, 0x80}, /*"%", 5*/
+ {0x03, 0x80, 0x1C, 0x40, 0x27, 0x40, 0x1C, 0x80, 0x07, 0x40, 0x00, 0x40}, /*"&", 6*/
+ {0x10, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"'", 7*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x80, 0x20, 0x40, 0x40, 0x20}, /*"(", 8*/
+ {0x00, 0x00, 0x40, 0x20, 0x20, 0x40, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00}, /*")", 9*/
+ {0x09, 0x00, 0x06, 0x00, 0x1F, 0x80, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00}, /*"*", 10*/
+ {0x04, 0x00, 0x04, 0x00, 0x3F, 0x80, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00}, /*"+", 11*/
+ {0x00, 0x10, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*", ", 12*/
+ {0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00}, /*"-", 13*/
+ {0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*".", 14*/
+ {0x00, 0x20, 0x01, 0xC0, 0x06, 0x00, 0x38, 0x00, 0x40, 0x00, 0x00, 0x00}, /*"/", 15*/
+ {0x1F, 0x80, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x1F, 0x80, 0x00, 0x00}, /*"0", 16*/
+ {0x00, 0x00, 0x10, 0x40, 0x3F, 0xC0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00}, /*"1", 17*/
+ {0x18, 0xC0, 0x21, 0x40, 0x22, 0x40, 0x24, 0x40, 0x18, 0x40, 0x00, 0x00}, /*"2", 18*/
+ {0x10, 0x80, 0x20, 0x40, 0x24, 0x40, 0x24, 0x40, 0x1B, 0x80, 0x00, 0x00}, /*"3", 19*/
+ {0x02, 0x00, 0x0D, 0x00, 0x11, 0x00, 0x3F, 0xC0, 0x01, 0x40, 0x00, 0x00}, /*"4", 20*/
+ {0x3C, 0x80, 0x24, 0x40, 0x24, 0x40, 0x24, 0x40, 0x23, 0x80, 0x00, 0x00}, /*"5", 21*/
+ {0x1F, 0x80, 0x24, 0x40, 0x24, 0x40, 0x34, 0x40, 0x03, 0x80, 0x00, 0x00}, /*"6", 22*/
+ {0x30, 0x00, 0x20, 0x00, 0x27, 0xC0, 0x38, 0x00, 0x20, 0x00, 0x00, 0x00}, /*"7", 23*/
+ {0x1B, 0x80, 0x24, 0x40, 0x24, 0x40, 0x24, 0x40, 0x1B, 0x80, 0x00, 0x00}, /*"8", 24*/
+ {0x1C, 0x00, 0x22, 0xC0, 0x22, 0x40, 0x22, 0x40, 0x1F, 0x80, 0x00, 0x00}, /*"9", 25*/
+ {0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*":", 26*/
+ {0x00, 0x00, 0x00, 0x00, 0x04, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*";", 27*/
+ {0x00, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x11, 0x00, 0x20, 0x80, 0x40, 0x40}, /*"<", 28*/
+ {0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00, 0x00}, /*"=", 29*/
+ {0x00, 0x00, 0x40, 0x40, 0x20, 0x80, 0x11, 0x00, 0x0A, 0x00, 0x04, 0x00}, /*">", 30*/
+ {0x18, 0x00, 0x20, 0x00, 0x23, 0x40, 0x24, 0x00, 0x18, 0x00, 0x00, 0x00}, /*"?", 31*/
+ {0x1F, 0x80, 0x20, 0x40, 0x27, 0x40, 0x29, 0x40, 0x1F, 0x40, 0x00, 0x00}, /*"@", 32*/
+ {0x00, 0x40, 0x07, 0xC0, 0x39, 0x00, 0x0F, 0x00, 0x01, 0xC0, 0x00, 0x40}, /*"A", 33*/
+ {0x20, 0x40, 0x3F, 0xC0, 0x24, 0x40, 0x24, 0x40, 0x1B, 0x80, 0x00, 0x00}, /*"B", 34*/
+ {0x1F, 0x80, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x30, 0x80, 0x00, 0x00}, /*"C", 35*/
+ {0x20, 0x40, 0x3F, 0xC0, 0x20, 0x40, 0x20, 0x40, 0x1F, 0x80, 0x00, 0x00}, /*"D", 36*/
+ {0x20, 0x40, 0x3F, 0xC0, 0x24, 0x40, 0x2E, 0x40, 0x30, 0xC0, 0x00, 0x00}, /*"E", 37*/
+ {0x20, 0x40, 0x3F, 0xC0, 0x24, 0x40, 0x2E, 0x00, 0x30, 0x00, 0x00, 0x00}, /*"F", 38*/
+ {0x0F, 0x00, 0x10, 0x80, 0x20, 0x40, 0x22, 0x40, 0x33, 0x80, 0x02, 0x00}, /*"G", 39*/
+ {0x20, 0x40, 0x3F, 0xC0, 0x04, 0x00, 0x04, 0x00, 0x3F, 0xC0, 0x20, 0x40}, /*"H", 40*/
+ {0x20, 0x40, 0x20, 0x40, 0x3F, 0xC0, 0x20, 0x40, 0x20, 0x40, 0x00, 0x00}, /*"I", 41*/
+ {0x00, 0x60, 0x20, 0x20, 0x20, 0x20, 0x3F, 0xC0, 0x20, 0x00, 0x20, 0x00}, /*"J", 42*/
+ {0x20, 0x40, 0x3F, 0xC0, 0x24, 0x40, 0x0B, 0x00, 0x30, 0xC0, 0x20, 0x40}, /*"K", 43*/
+ {0x20, 0x40, 0x3F, 0xC0, 0x20, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xC0}, /*"L", 44*/
+ {0x3F, 0xC0, 0x3C, 0x00, 0x03, 0xC0, 0x3C, 0x00, 0x3F, 0xC0, 0x00, 0x00}, /*"M", 45*/
+ {0x20, 0x40, 0x3F, 0xC0, 0x0C, 0x40, 0x23, 0x00, 0x3F, 0xC0, 0x20, 0x00}, /*"N", 46*/
+ {0x1F, 0x80, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x1F, 0x80, 0x00, 0x00}, /*"O", 47*/
+ {0x20, 0x40, 0x3F, 0xC0, 0x24, 0x40, 0x24, 0x00, 0x18, 0x00, 0x00, 0x00}, /*"P", 48*/
+ {0x1F, 0x80, 0x21, 0x40, 0x21, 0x40, 0x20, 0xE0, 0x1F, 0xA0, 0x00, 0x00}, /*"Q", 49*/
+ {0x20, 0x40, 0x3F, 0xC0, 0x24, 0x40, 0x26, 0x00, 0x19, 0xC0, 0x00, 0x40}, /*"R", 50*/
+ {0x18, 0xC0, 0x24, 0x40, 0x24, 0x40, 0x22, 0x40, 0x31, 0x80, 0x00, 0x00}, /*"S", 51*/
+ {0x30, 0x00, 0x20, 0x40, 0x3F, 0xC0, 0x20, 0x40, 0x30, 0x00, 0x00, 0x00}, /*"T", 52*/
+ {0x20, 0x00, 0x3F, 0x80, 0x00, 0x40, 0x00, 0x40, 0x3F, 0x80, 0x20, 0x00}, /*"U", 53*/
+ {0x20, 0x00, 0x3E, 0x00, 0x01, 0xC0, 0x07, 0x00, 0x38, 0x00, 0x20, 0x00}, /*"V", 54*/
+ {0x38, 0x00, 0x07, 0xC0, 0x3C, 0x00, 0x07, 0xC0, 0x38, 0x00, 0x00, 0x00}, /*"W", 55*/
+ {0x20, 0x40, 0x39, 0xC0, 0x06, 0x00, 0x39, 0xC0, 0x20, 0x40, 0x00, 0x00}, /*"X", 56*/
+ {0x20, 0x00, 0x38, 0x40, 0x07, 0xC0, 0x38, 0x40, 0x20, 0x00, 0x00, 0x00}, /*"Y", 57*/
+ {0x30, 0x40, 0x21, 0xC0, 0x26, 0x40, 0x38, 0x40, 0x20, 0xC0, 0x00, 0x00}, /*"Z", 58*/
+ {0x00, 0x00, 0x00, 0x00, 0x7F, 0xE0, 0x40, 0x20, 0x40, 0x20, 0x00, 0x00}, /*"[", 59*/
+ {0x00, 0x00, 0x70, 0x00, 0x0C, 0x00, 0x03, 0x80, 0x00, 0x40, 0x00, 0x00}, /*"\", 60*/
+ {0x00, 0x00, 0x40, 0x20, 0x40, 0x20, 0x7F, 0xE0, 0x00, 0x00, 0x00, 0x00}, /*"]", 61*/
+ {0x00, 0x00, 0x20, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"^", 62*/
+ {0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10}, /*"_", 63*/
+ {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"`", 64*/
+ {0x00, 0x00, 0x02, 0x80, 0x05, 0x40, 0x05, 0x40, 0x03, 0xC0, 0x00, 0x40}, /*"a", 65*/
+ {0x20, 0x00, 0x3F, 0xC0, 0x04, 0x40, 0x04, 0x40, 0x03, 0x80, 0x00, 0x00}, /*"b", 66*/
+ {0x00, 0x00, 0x03, 0x80, 0x04, 0x40, 0x04, 0x40, 0x06, 0x40, 0x00, 0x00}, /*"c", 67*/
+ {0x00, 0x00, 0x03, 0x80, 0x04, 0x40, 0x24, 0x40, 0x3F, 0xC0, 0x00, 0x40}, /*"d", 68*/
+ {0x00, 0x00, 0x03, 0x80, 0x05, 0x40, 0x05, 0x40, 0x03, 0x40, 0x00, 0x00}, /*"e", 69*/
+ {0x00, 0x00, 0x04, 0x40, 0x1F, 0xC0, 0x24, 0x40, 0x24, 0x40, 0x20, 0x00}, /*"f", 70*/
+ {0x00, 0x00, 0x02, 0xE0, 0x05, 0x50, 0x05, 0x50, 0x06, 0x50, 0x04, 0x20}, /*"g", 71*/
+ {0x20, 0x40, 0x3F, 0xC0, 0x04, 0x40, 0x04, 0x00, 0x03, 0xC0, 0x00, 0x40}, /*"h", 72*/
+ {0x00, 0x00, 0x04, 0x40, 0x27, 0xC0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00}, /*"i", 73*/
+ {0x00, 0x10, 0x00, 0x10, 0x04, 0x10, 0x27, 0xE0, 0x00, 0x00, 0x00, 0x00}, /*"j", 74*/
+ {0x20, 0x40, 0x3F, 0xC0, 0x01, 0x40, 0x07, 0x00, 0x04, 0xC0, 0x04, 0x40}, /*"k", 75*/
+ {0x20, 0x40, 0x20, 0x40, 0x3F, 0xC0, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00}, /*"l", 76*/
+ {0x07, 0xC0, 0x04, 0x00, 0x07, 0xC0, 0x04, 0x00, 0x03, 0xC0, 0x00, 0x00}, /*"m", 77*/
+ {0x04, 0x40, 0x07, 0xC0, 0x04, 0x40, 0x04, 0x00, 0x03, 0xC0, 0x00, 0x40}, /*"n", 78*/
+ {0x00, 0x00, 0x03, 0x80, 0x04, 0x40, 0x04, 0x40, 0x03, 0x80, 0x00, 0x00}, /*"o", 79*/
+ {0x04, 0x10, 0x07, 0xF0, 0x04, 0x50, 0x04, 0x40, 0x03, 0x80, 0x00, 0x00}, /*"p", 80*/
+ {0x00, 0x00, 0x03, 0x80, 0x04, 0x40, 0x04, 0x50, 0x07, 0xF0, 0x00, 0x10}, /*"q", 81*/
+ {0x04, 0x40, 0x07, 0xC0, 0x02, 0x40, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00}, /*"r", 82*/
+ {0x00, 0x00, 0x06, 0x40, 0x05, 0x40, 0x05, 0x40, 0x04, 0xC0, 0x00, 0x00}, /*"s", 83*/
+ {0x00, 0x00, 0x04, 0x00, 0x1F, 0x80, 0x04, 0x40, 0x00, 0x40, 0x00, 0x00}, /*"t", 84*/
+ {0x04, 0x00, 0x07, 0x80, 0x00, 0x40, 0x04, 0x40, 0x07, 0xC0, 0x00, 0x40}, /*"u", 85*/
+ {0x04, 0x00, 0x07, 0x00, 0x04, 0xC0, 0x01, 0x80, 0x06, 0x00, 0x04, 0x00}, /*"v", 86*/
+ {0x06, 0x00, 0x01, 0xC0, 0x07, 0x00, 0x01, 0xC0, 0x06, 0x00, 0x00, 0x00}, /*"w", 87*/
+ {0x04, 0x40, 0x06, 0xC0, 0x01, 0x00, 0x06, 0xC0, 0x04, 0x40, 0x00, 0x00}, /*"x", 88*/
+ {0x04, 0x10, 0x07, 0x10, 0x04, 0xE0, 0x01, 0x80, 0x06, 0x00, 0x04, 0x00}, /*"y", 89*/
+ {0x00, 0x00, 0x04, 0x40, 0x05, 0xC0, 0x06, 0x40, 0x04, 0x40, 0x00, 0x00}, /*"z", 90*/
+ {0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x7B, 0xE0, 0x40, 0x20, 0x00, 0x00}, /*"{", 91*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00}, /*"|", 92*/
+ {0x00, 0x00, 0x40, 0x20, 0x7B, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"}", 93*/
+ {0x40, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x20, 0x00, 0x40, 0x00}, /*"~", 94*/
+};
+
+static const uint8_t gsc_ssd1306_ascii_1608[95][16] =
+{
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*" ", 0*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xCC, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"!", 1*/
+ {0x00, 0x00, 0x08, 0x00, 0x30, 0x00, 0x60, 0x00, 0x08, 0x00, 0x30, 0x00, 0x60, 0x00, 0x00, 0x00}, /*""", 2*/
+ {0x02, 0x20, 0x03, 0xFC, 0x1E, 0x20, 0x02, 0x20, 0x03, 0xFC, 0x1E, 0x20, 0x02, 0x20, 0x00, 0x00}, /*"#", 3*/
+ {0x00, 0x00, 0x0E, 0x18, 0x11, 0x04, 0x3F, 0xFF, 0x10, 0x84, 0x0C, 0x78, 0x00, 0x00, 0x00, 0x00}, /*"$", 4*/
+ {0x0F, 0x00, 0x10, 0x84, 0x0F, 0x38, 0x00, 0xC0, 0x07, 0x78, 0x18, 0x84, 0x00, 0x78, 0x00, 0x00}, /*"%", 5*/
+ {0x00, 0x78, 0x0F, 0x84, 0x10, 0xC4, 0x11, 0x24, 0x0E, 0x98, 0x00, 0xE4, 0x00, 0x84, 0x00, 0x08}, /*"&", 6*/
+ {0x08, 0x00, 0x68, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"'", 7*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x18, 0x18, 0x20, 0x04, 0x40, 0x02, 0x00, 0x00}, /*"(", 8*/
+ {0x00, 0x00, 0x40, 0x02, 0x20, 0x04, 0x18, 0x18, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*")", 9*/
+ {0x02, 0x40, 0x02, 0x40, 0x01, 0x80, 0x0F, 0xF0, 0x01, 0x80, 0x02, 0x40, 0x02, 0x40, 0x00, 0x00}, /*"*", 10*/
+ {0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x0F, 0xF8, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00}, /*"+", 11*/
+ {0x00, 0x01, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*", ", 12*/
+ {0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80}, /*"-", 13*/
+ {0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*".", 14*/
+ {0x00, 0x00, 0x00, 0x06, 0x00, 0x18, 0x00, 0x60, 0x01, 0x80, 0x06, 0x00, 0x18, 0x00, 0x20, 0x00}, /*"/", 15*/
+ {0x00, 0x00, 0x07, 0xF0, 0x08, 0x08, 0x10, 0x04, 0x10, 0x04, 0x08, 0x08, 0x07, 0xF0, 0x00, 0x00}, /*"0", 16*/
+ {0x00, 0x00, 0x08, 0x04, 0x08, 0x04, 0x1F, 0xFC, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, /*"1", 17*/
+ {0x00, 0x00, 0x0E, 0x0C, 0x10, 0x14, 0x10, 0x24, 0x10, 0x44, 0x11, 0x84, 0x0E, 0x0C, 0x00, 0x00}, /*"2", 18*/
+ {0x00, 0x00, 0x0C, 0x18, 0x10, 0x04, 0x11, 0x04, 0x11, 0x04, 0x12, 0x88, 0x0C, 0x70, 0x00, 0x00}, /*"3", 19*/
+ {0x00, 0x00, 0x00, 0xE0, 0x03, 0x20, 0x04, 0x24, 0x08, 0x24, 0x1F, 0xFC, 0x00, 0x24, 0x00, 0x00}, /*"4", 20*/
+ {0x00, 0x00, 0x1F, 0x98, 0x10, 0x84, 0x11, 0x04, 0x11, 0x04, 0x10, 0x88, 0x10, 0x70, 0x00, 0x00}, /*"5", 21*/
+ {0x00, 0x00, 0x07, 0xF0, 0x08, 0x88, 0x11, 0x04, 0x11, 0x04, 0x18, 0x88, 0x00, 0x70, 0x00, 0x00}, /*"6", 22*/
+ {0x00, 0x00, 0x1C, 0x00, 0x10, 0x00, 0x10, 0xFC, 0x13, 0x00, 0x1C, 0x00, 0x10, 0x00, 0x00, 0x00}, /*"7", 23*/
+ {0x00, 0x00, 0x0E, 0x38, 0x11, 0x44, 0x10, 0x84, 0x10, 0x84, 0x11, 0x44, 0x0E, 0x38, 0x00, 0x00}, /*"8", 24*/
+ {0x00, 0x00, 0x07, 0x00, 0x08, 0x8C, 0x10, 0x44, 0x10, 0x44, 0x08, 0x88, 0x07, 0xF0, 0x00, 0x00}, /*"9", 25*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0C, 0x03, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*":", 26*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*";", 27*/
+ {0x00, 0x00, 0x00, 0x80, 0x01, 0x40, 0x02, 0x20, 0x04, 0x10, 0x08, 0x08, 0x10, 0x04, 0x00, 0x00}, /*"<", 28*/
+ {0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x00, 0x00}, /*"=", 29*/
+ {0x00, 0x00, 0x10, 0x04, 0x08, 0x08, 0x04, 0x10, 0x02, 0x20, 0x01, 0x40, 0x00, 0x80, 0x00, 0x00}, /*">", 30*/
+ {0x00, 0x00, 0x0E, 0x00, 0x12, 0x00, 0x10, 0x0C, 0x10, 0x6C, 0x10, 0x80, 0x0F, 0x00, 0x00, 0x00}, /*"?", 31*/
+ {0x03, 0xE0, 0x0C, 0x18, 0x13, 0xE4, 0x14, 0x24, 0x17, 0xC4, 0x08, 0x28, 0x07, 0xD0, 0x00, 0x00}, /*"@", 32*/
+ {0x00, 0x04, 0x00, 0x3C, 0x03, 0xC4, 0x1C, 0x40, 0x07, 0x40, 0x00, 0xE4, 0x00, 0x1C, 0x00, 0x04}, /*"A", 33*/
+ {0x10, 0x04, 0x1F, 0xFC, 0x11, 0x04, 0x11, 0x04, 0x11, 0x04, 0x0E, 0x88, 0x00, 0x70, 0x00, 0x00}, /*"B", 34*/
+ {0x03, 0xE0, 0x0C, 0x18, 0x10, 0x04, 0x10, 0x04, 0x10, 0x04, 0x10, 0x08, 0x1C, 0x10, 0x00, 0x00}, /*"C", 35*/
+ {0x10, 0x04, 0x1F, 0xFC, 0x10, 0x04, 0x10, 0x04, 0x10, 0x04, 0x08, 0x08, 0x07, 0xF0, 0x00, 0x00}, /*"D", 36*/
+ {0x10, 0x04, 0x1F, 0xFC, 0x11, 0x04, 0x11, 0x04, 0x17, 0xC4, 0x10, 0x04, 0x08, 0x18, 0x00, 0x00}, /*"E", 37*/
+ {0x10, 0x04, 0x1F, 0xFC, 0x11, 0x04, 0x11, 0x00, 0x17, 0xC0, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00}, /*"F", 38*/
+ {0x03, 0xE0, 0x0C, 0x18, 0x10, 0x04, 0x10, 0x04, 0x10, 0x44, 0x1C, 0x78, 0x00, 0x40, 0x00, 0x00}, /*"G", 39*/
+ {0x10, 0x04, 0x1F, 0xFC, 0x10, 0x84, 0x00, 0x80, 0x00, 0x80, 0x10, 0x84, 0x1F, 0xFC, 0x10, 0x04}, /*"H", 40*/
+ {0x00, 0x00, 0x10, 0x04, 0x10, 0x04, 0x1F, 0xFC, 0x10, 0x04, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00}, /*"I", 41*/
+ {0x00, 0x03, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x1F, 0xFE, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00}, /*"J", 42*/
+ {0x10, 0x04, 0x1F, 0xFC, 0x11, 0x04, 0x03, 0x80, 0x14, 0x64, 0x18, 0x1C, 0x10, 0x04, 0x00, 0x00}, /*"K", 43*/
+ {0x10, 0x04, 0x1F, 0xFC, 0x10, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00}, /*"L", 44*/
+ {0x10, 0x04, 0x1F, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x1F, 0xFC, 0x10, 0x04, 0x00, 0x00}, /*"M", 45*/
+ {0x10, 0x04, 0x1F, 0xFC, 0x0C, 0x04, 0x03, 0x00, 0x00, 0xE0, 0x10, 0x18, 0x1F, 0xFC, 0x10, 0x00}, /*"N", 46*/
+ {0x07, 0xF0, 0x08, 0x08, 0x10, 0x04, 0x10, 0x04, 0x10, 0x04, 0x08, 0x08, 0x07, 0xF0, 0x00, 0x00}, /*"O", 47*/
+ {0x10, 0x04, 0x1F, 0xFC, 0x10, 0x84, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x0F, 0x00, 0x00, 0x00}, /*"P", 48*/
+ {0x07, 0xF0, 0x08, 0x18, 0x10, 0x24, 0x10, 0x24, 0x10, 0x1C, 0x08, 0x0A, 0x07, 0xF2, 0x00, 0x00}, /*"Q", 49*/
+ {0x10, 0x04, 0x1F, 0xFC, 0x11, 0x04, 0x11, 0x00, 0x11, 0xC0, 0x11, 0x30, 0x0E, 0x0C, 0x00, 0x04}, /*"R", 50*/
+ {0x00, 0x00, 0x0E, 0x1C, 0x11, 0x04, 0x10, 0x84, 0x10, 0x84, 0x10, 0x44, 0x1C, 0x38, 0x00, 0x00}, /*"S", 51*/
+ {0x18, 0x00, 0x10, 0x00, 0x10, 0x04, 0x1F, 0xFC, 0x10, 0x04, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00}, /*"T", 52*/
+ {0x10, 0x00, 0x1F, 0xF8, 0x10, 0x04, 0x00, 0x04, 0x00, 0x04, 0x10, 0x04, 0x1F, 0xF8, 0x10, 0x00}, /*"U", 53*/
+ {0x10, 0x00, 0x1E, 0x00, 0x11, 0xE0, 0x00, 0x1C, 0x00, 0x70, 0x13, 0x80, 0x1C, 0x00, 0x10, 0x00}, /*"V", 54*/
+ {0x1F, 0xC0, 0x10, 0x3C, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0xE0, 0x10, 0x3C, 0x1F, 0xC0, 0x00, 0x00}, /*"W", 55*/
+ {0x10, 0x04, 0x18, 0x0C, 0x16, 0x34, 0x01, 0xC0, 0x01, 0xC0, 0x16, 0x34, 0x18, 0x0C, 0x10, 0x04}, /*"X", 56*/
+ {0x10, 0x00, 0x1C, 0x00, 0x13, 0x04, 0x00, 0xFC, 0x13, 0x04, 0x1C, 0x00, 0x10, 0x00, 0x00, 0x00}, /*"Y", 57*/
+ {0x08, 0x04, 0x10, 0x1C, 0x10, 0x64, 0x10, 0x84, 0x13, 0x04, 0x1C, 0x04, 0x10, 0x18, 0x00, 0x00}, /*"Z", 58*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x00, 0x00}, /*"[", 59*/
+ {0x00, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x03, 0x80, 0x00, 0x60, 0x00, 0x1C, 0x00, 0x03, 0x00, 0x00}, /*"\", 60*/
+ {0x00, 0x00, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"]", 61*/
+ {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00, 0x00}, /*"^", 62*/
+ {0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01}, /*"_", 63*/
+ {0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"`", 64*/
+ {0x00, 0x00, 0x00, 0x98, 0x01, 0x24, 0x01, 0x44, 0x01, 0x44, 0x01, 0x44, 0x00, 0xFC, 0x00, 0x04}, /*"a", 65*/
+ {0x10, 0x00, 0x1F, 0xFC, 0x00, 0x88, 0x01, 0x04, 0x01, 0x04, 0x00, 0x88, 0x00, 0x70, 0x00, 0x00}, /*"b", 66*/
+ {0x00, 0x00, 0x00, 0x70, 0x00, 0x88, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x00, 0x88, 0x00, 0x00}, /*"c", 67*/
+ {0x00, 0x00, 0x00, 0x70, 0x00, 0x88, 0x01, 0x04, 0x01, 0x04, 0x11, 0x08, 0x1F, 0xFC, 0x00, 0x04}, /*"d", 68*/
+ {0x00, 0x00, 0x00, 0xF8, 0x01, 0x44, 0x01, 0x44, 0x01, 0x44, 0x01, 0x44, 0x00, 0xC8, 0x00, 0x00}, /*"e", 69*/
+ {0x00, 0x00, 0x01, 0x04, 0x01, 0x04, 0x0F, 0xFC, 0x11, 0x04, 0x11, 0x04, 0x11, 0x00, 0x18, 0x00}, /*"f", 70*/
+ {0x00, 0x00, 0x00, 0xD6, 0x01, 0x29, 0x01, 0x29, 0x01, 0x29, 0x01, 0xC9, 0x01, 0x06, 0x00, 0x00}, /*"g", 71*/
+ {0x10, 0x04, 0x1F, 0xFC, 0x00, 0x84, 0x01, 0x00, 0x01, 0x00, 0x01, 0x04, 0x00, 0xFC, 0x00, 0x04}, /*"h", 72*/
+ {0x00, 0x00, 0x01, 0x04, 0x19, 0x04, 0x19, 0xFC, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, /*"i", 73*/
+ {0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x01, 0x01, 0x19, 0x01, 0x19, 0xFE, 0x00, 0x00, 0x00, 0x00}, /*"j", 74*/
+ {0x10, 0x04, 0x1F, 0xFC, 0x00, 0x24, 0x00, 0x40, 0x01, 0xB4, 0x01, 0x0C, 0x01, 0x04, 0x00, 0x00}, /*"k", 75*/
+ {0x00, 0x00, 0x10, 0x04, 0x10, 0x04, 0x1F, 0xFC, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, /*"l", 76*/
+ {0x01, 0x04, 0x01, 0xFC, 0x01, 0x04, 0x01, 0x00, 0x01, 0xFC, 0x01, 0x04, 0x01, 0x00, 0x00, 0xFC}, /*"m", 77*/
+ {0x01, 0x04, 0x01, 0xFC, 0x00, 0x84, 0x01, 0x00, 0x01, 0x00, 0x01, 0x04, 0x00, 0xFC, 0x00, 0x04}, /*"n", 78*/
+ {0x00, 0x00, 0x00, 0xF8, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x00, 0xF8, 0x00, 0x00}, /*"o", 79*/
+ {0x01, 0x01, 0x01, 0xFF, 0x00, 0x85, 0x01, 0x04, 0x01, 0x04, 0x00, 0x88, 0x00, 0x70, 0x00, 0x00}, /*"p", 80*/
+ {0x00, 0x00, 0x00, 0x70, 0x00, 0x88, 0x01, 0x04, 0x01, 0x04, 0x01, 0x05, 0x01, 0xFF, 0x00, 0x01}, /*"q", 81*/
+ {0x01, 0x04, 0x01, 0x04, 0x01, 0xFC, 0x00, 0x84, 0x01, 0x04, 0x01, 0x00, 0x01, 0x80, 0x00, 0x00}, /*"r", 82*/
+ {0x00, 0x00, 0x00, 0xCC, 0x01, 0x24, 0x01, 0x24, 0x01, 0x24, 0x01, 0x24, 0x01, 0x98, 0x00, 0x00}, /*"s", 83*/
+ {0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x07, 0xF8, 0x01, 0x04, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00}, /*"t", 84*/
+ {0x01, 0x00, 0x01, 0xF8, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x01, 0x08, 0x01, 0xFC, 0x00, 0x04}, /*"u", 85*/
+ {0x01, 0x00, 0x01, 0x80, 0x01, 0x70, 0x00, 0x0C, 0x00, 0x10, 0x01, 0x60, 0x01, 0x80, 0x01, 0x00}, /*"v", 86*/
+ {0x01, 0xF0, 0x01, 0x0C, 0x00, 0x30, 0x01, 0xC0, 0x00, 0x30, 0x01, 0x0C, 0x01, 0xF0, 0x01, 0x00}, /*"w", 87*/
+ {0x00, 0x00, 0x01, 0x04, 0x01, 0x8C, 0x00, 0x74, 0x01, 0x70, 0x01, 0x8C, 0x01, 0x04, 0x00, 0x00}, /*"x", 88*/
+ {0x01, 0x01, 0x01, 0x81, 0x01, 0x71, 0x00, 0x0E, 0x00, 0x18, 0x01, 0x60, 0x01, 0x80, 0x01, 0x00}, /*"y", 89*/
+ {0x00, 0x00, 0x01, 0x84, 0x01, 0x0C, 0x01, 0x34, 0x01, 0x44, 0x01, 0x84, 0x01, 0x0C, 0x00, 0x00}, /*"z", 90*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3E, 0xFC, 0x40, 0x02, 0x40, 0x02}, /*"{", 91*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"|", 92*/
+ {0x00, 0x00, 0x40, 0x02, 0x40, 0x02, 0x3E, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"}", 93*/
+ {0x00, 0x00, 0x60, 0x00, 0x80, 0x00, 0x80, 0x00, 0x40, 0x00, 0x40, 0x00, 0x20, 0x00, 0x20, 0x00}, /*"~", 94*/
+};
+
+static const uint8_t gsc_ssd1306_ascii_2412[95][36] =
+{
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*" ", 0*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x80, 0x38, 0x0F, 0xFE, 0x38, 0x0F, 0x80, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"!", 1*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x00, 0x31, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00}, /*""", 2*/
+ {0x00, 0x00, 0x00, 0x00, 0x61, 0x80, 0x00, 0x67, 0xF8, 0x07, 0xF9, 0x80, 0x00, 0x61, 0x80, 0x00, 0x61, 0x80, 0x00, 0x61, 0x80, 0x00, 0x61, 0x80, 0x00, 0x67, 0xF8, 0x07, 0xF9, 0x80, 0x00, 0x61, 0x80, 0x00, 0x00, 0x00}, /*"#", 3*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xC0, 0xE0, 0x03, 0xE0, 0xF0, 0x06, 0x30, 0x08, 0x04, 0x18, 0x08, 0x1F, 0xFF, 0xFE, 0x04, 0x0E, 0x08, 0x07, 0x87, 0xF0, 0x03, 0x81, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"$", 4*/
+ {0x01, 0xF0, 0x00, 0x06, 0x0C, 0x00, 0x04, 0x04, 0x08, 0x06, 0x0C, 0x70, 0x01, 0xF9, 0xC0, 0x00, 0x0E, 0x00, 0x00, 0x3B, 0xE0, 0x00, 0xEC, 0x18, 0x07, 0x08, 0x08, 0x04, 0x0C, 0x18, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00}, /*"%", 5*/
+ {0x00, 0x01, 0xE0, 0x00, 0x07, 0xF0, 0x03, 0xF8, 0x18, 0x04, 0x1C, 0x08, 0x04, 0x17, 0x08, 0x07, 0xE1, 0xD0, 0x03, 0xC0, 0xE0, 0x00, 0x23, 0xB0, 0x00, 0x3C, 0x08, 0x00, 0x20, 0x08, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, /*"&", 6*/
+ {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x31, 0x00, 0x00, 0x32, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"'", 7*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x01, 0xFF, 0xC0, 0x07, 0x80, 0xF0, 0x0C, 0x00, 0x18, 0x10, 0x00, 0x04, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00}, /*"(", 8*/
+ {0x00, 0x00, 0x00, 0x20, 0x00, 0x02, 0x10, 0x00, 0x04, 0x0C, 0x00, 0x18, 0x07, 0x80, 0xF0, 0x01, 0xFF, 0xC0, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*")", 9*/
+ {0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x66, 0x00, 0x00, 0x66, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x18, 0x00, 0x03, 0xFF, 0xC0, 0x00, 0x18, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x66, 0x00, 0x00, 0x66, 0x00, 0x00, 0x42, 0x00}, /*"*", 10*/
+ {0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00}, /*"+", 11*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x31, 0x00, 0x00, 0x32, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*", ", 12*/
+ {0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00}, /*"-", 13*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x38, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*".", 14*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x70, 0x00, 0x01, 0x80, 0x00, 0x0E, 0x00, 0x00, 0x38, 0x00, 0x00, 0xC0, 0x00, 0x07, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"/", 15*/
+ {0x00, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x01, 0xFF, 0xE0, 0x03, 0x80, 0x70, 0x06, 0x00, 0x18, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x06, 0x00, 0x18, 0x03, 0x80, 0x70, 0x01, 0xFF, 0xE0, 0x00, 0x7F, 0x80, 0x00, 0x00, 0x00}, /*"0", 16*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x01, 0x00, 0x08, 0x01, 0x00, 0x08, 0x03, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"1", 17*/
+ {0x00, 0x00, 0x00, 0x01, 0xC0, 0x38, 0x02, 0xC0, 0x58, 0x04, 0x00, 0x98, 0x04, 0x01, 0x18, 0x04, 0x02, 0x18, 0x04, 0x04, 0x18, 0x06, 0x1C, 0x18, 0x03, 0xF8, 0x18, 0x01, 0xE0, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"2", 18*/
+ {0x00, 0x00, 0x00, 0x01, 0xC0, 0xE0, 0x03, 0xC0, 0xF0, 0x04, 0x00, 0x08, 0x04, 0x08, 0x08, 0x04, 0x08, 0x08, 0x06, 0x18, 0x08, 0x03, 0xF4, 0x18, 0x01, 0xE7, 0xF0, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"3", 19*/
+ {0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x11, 0x00, 0x00, 0x61, 0x00, 0x00, 0x81, 0x08, 0x03, 0x01, 0x08, 0x07, 0xFF, 0xF8, 0x0F, 0xFF, 0xF8, 0x00, 0x01, 0x08, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00}, /*"4", 20*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0xFC, 0xD0, 0x06, 0x08, 0x08, 0x06, 0x10, 0x08, 0x06, 0x10, 0x08, 0x06, 0x10, 0x08, 0x06, 0x18, 0x38, 0x06, 0x0F, 0xF0, 0x06, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"5", 21*/
+ {0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x01, 0xFF, 0xE0, 0x03, 0x84, 0x30, 0x02, 0x08, 0x18, 0x04, 0x10, 0x08, 0x04, 0x10, 0x08, 0x04, 0x10, 0x08, 0x07, 0x18, 0x10, 0x03, 0x0F, 0xF0, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x00}, /*"6", 22*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x07, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0xF8, 0x06, 0x07, 0xF8, 0x06, 0x18, 0x00, 0x06, 0xE0, 0x00, 0x07, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"7", 23*/
+ {0x00, 0x00, 0x00, 0x01, 0xE1, 0xE0, 0x03, 0xF7, 0xF0, 0x06, 0x34, 0x10, 0x04, 0x18, 0x08, 0x04, 0x18, 0x08, 0x04, 0x0C, 0x08, 0x04, 0x0C, 0x08, 0x06, 0x16, 0x18, 0x03, 0xF3, 0xF0, 0x01, 0xC1, 0xE0, 0x00, 0x00, 0x00}, /*"8", 24*/
+ {0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x03, 0xFC, 0x30, 0x03, 0x06, 0x38, 0x04, 0x02, 0x08, 0x04, 0x02, 0x08, 0x04, 0x02, 0x08, 0x04, 0x04, 0x10, 0x03, 0x08, 0xF0, 0x01, 0xFF, 0xC0, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00}, /*"9", 25*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x38, 0x00, 0x70, 0x38, 0x00, 0x70, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*":", 26*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x1A, 0x00, 0x30, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*";", 27*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x14, 0x00, 0x00, 0x22, 0x00, 0x00, 0x41, 0x00, 0x00, 0x80, 0x80, 0x01, 0x00, 0x40, 0x02, 0x00, 0x20, 0x04, 0x00, 0x10, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00}, /*"<", 28*/
+ {0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00}, /*"=", 29*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x04, 0x00, 0x10, 0x02, 0x00, 0x20, 0x01, 0x00, 0x40, 0x00, 0x80, 0x80, 0x00, 0x41, 0x00, 0x00, 0x22, 0x00, 0x00, 0x14, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00}, /*">", 30*/
+ {0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x04, 0xC0, 0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x38, 0x08, 0x0F, 0x38, 0x08, 0x08, 0x38, 0x08, 0x10, 0x00, 0x0C, 0x30, 0x00, 0x07, 0xE0, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x00}, /*"?", 31*/
+ {0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0xFF, 0xE0, 0x03, 0x80, 0x70, 0x02, 0x0F, 0x10, 0x06, 0x70, 0x88, 0x04, 0xC0, 0x88, 0x04, 0x83, 0x08, 0x04, 0x7F, 0x88, 0x02, 0xC0, 0x90, 0x03, 0x01, 0x20, 0x00, 0xFE, 0x40}, /*"@", 32*/
+ {0x00, 0x00, 0x08, 0x00, 0x00, 0x18, 0x00, 0x01, 0xF8, 0x00, 0x3E, 0x08, 0x01, 0xC2, 0x00, 0x07, 0x02, 0x00, 0x07, 0xE2, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x1F, 0xC8, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x38, 0x00, 0x00, 0x08}, /*"A", 33*/
+ {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x08, 0x08, 0x04, 0x08, 0x08, 0x04, 0x08, 0x08, 0x04, 0x08, 0x08, 0x06, 0x18, 0x08, 0x03, 0xF4, 0x18, 0x01, 0xE7, 0xF0, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00}, /*"B", 34*/
+ {0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x01, 0xFF, 0xE0, 0x03, 0x80, 0x70, 0x02, 0x00, 0x18, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x04, 0x00, 0x10, 0x06, 0x00, 0x20, 0x07, 0x80, 0xC0, 0x00, 0x00, 0x00}, /*"C", 35*/
+ {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x04, 0x00, 0x18, 0x02, 0x00, 0x10, 0x03, 0x80, 0x70, 0x01, 0xFF, 0xE0, 0x00, 0x7F, 0x80, 0x00, 0x00, 0x00}, /*"D", 36*/
+ {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x08, 0x08, 0x04, 0x08, 0x08, 0x04, 0x08, 0x08, 0x04, 0x08, 0x08, 0x04, 0x3E, 0x08, 0x04, 0x00, 0x08, 0x06, 0x00, 0x18, 0x01, 0x00, 0x60, 0x00, 0x00, 0x00}, /*"E", 37*/
+ {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x08, 0x08, 0x04, 0x08, 0x00, 0x04, 0x08, 0x00, 0x04, 0x08, 0x00, 0x04, 0x3E, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00}, /*"F", 38*/
+ {0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x01, 0xFF, 0xE0, 0x03, 0x80, 0x70, 0x06, 0x00, 0x18, 0x04, 0x00, 0x08, 0x04, 0x02, 0x08, 0x04, 0x02, 0x08, 0x02, 0x03, 0xF0, 0x07, 0x83, 0xF0, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00}, /*"G", 39*/
+ {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x04, 0x08, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x00, 0x08}, /*"H", 40*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"I", 41*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x07, 0x00, 0x00, 0x01, 0x04, 0x00, 0x01, 0x04, 0x00, 0x01, 0x04, 0x00, 0x03, 0x07, 0xFF, 0xFE, 0x07, 0xFF, 0xFC, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00}, /*"J", 42*/
+ {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x0C, 0x08, 0x00, 0x18, 0x00, 0x00, 0x3E, 0x00, 0x04, 0xC7, 0x80, 0x05, 0x03, 0xC8, 0x06, 0x00, 0xF8, 0x04, 0x00, 0x38, 0x04, 0x00, 0x18, 0x00, 0x00, 0x08}, /*"K", 43*/
+ {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00}, /*"L", 44*/
+ {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0x80, 0x08, 0x07, 0xFC, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x03, 0xF8, 0x00, 0x07, 0xC0, 0x00, 0x78, 0x00, 0x07, 0x80, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x00, 0x08}, /*"M", 45*/
+ {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0x00, 0x08, 0x03, 0xC0, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x38, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x00, 0x00, 0x01, 0xC0, 0x04, 0x00, 0xF0, 0x07, 0xFF, 0xF8, 0x04, 0x00, 0x00}, /*"N", 46*/
+ {0x00, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x01, 0xFF, 0xE0, 0x03, 0x80, 0x70, 0x06, 0x00, 0x18, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x06, 0x00, 0x18, 0x03, 0x00, 0x30, 0x01, 0xFF, 0xE0, 0x00, 0x7F, 0x80, 0x00, 0x00, 0x00}, /*"O", 47*/
+ {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x04, 0x08, 0x04, 0x04, 0x00, 0x04, 0x04, 0x00, 0x04, 0x04, 0x00, 0x04, 0x04, 0x00, 0x06, 0x0C, 0x00, 0x03, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00}, /*"P", 48*/
+ {0x00, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x01, 0xFF, 0xE0, 0x03, 0x80, 0x70, 0x06, 0x00, 0x88, 0x04, 0x00, 0x88, 0x04, 0x00, 0xC8, 0x06, 0x00, 0x3C, 0x03, 0x00, 0x3E, 0x01, 0xFF, 0xE6, 0x00, 0x7F, 0x84, 0x00, 0x00, 0x00}, /*"Q", 49*/
+ {0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x08, 0x08, 0x04, 0x08, 0x00, 0x04, 0x0C, 0x00, 0x04, 0x0F, 0x00, 0x04, 0x0B, 0xC0, 0x06, 0x10, 0xF0, 0x03, 0xF0, 0x38, 0x01, 0xE0, 0x08, 0x00, 0x00, 0x08}, /*"R", 50*/
+ {0x00, 0x00, 0x00, 0x01, 0xE0, 0xF8, 0x03, 0xF0, 0x30, 0x06, 0x30, 0x10, 0x04, 0x18, 0x08, 0x04, 0x18, 0x08, 0x04, 0x0C, 0x08, 0x04, 0x0C, 0x08, 0x02, 0x06, 0x18, 0x02, 0x07, 0xF0, 0x07, 0x81, 0xE0, 0x00, 0x00, 0x00}, /*"S", 51*/
+ {0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x04, 0x00, 0x08, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0x80, 0x00}, /*"T", 52*/
+ {0x04, 0x00, 0x00, 0x07, 0xFF, 0xE0, 0x07, 0xFF, 0xF0, 0x04, 0x00, 0x18, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x04, 0x00, 0x10, 0x07, 0xFF, 0xE0, 0x04, 0x00, 0x00}, /*"U", 53*/
+ {0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x07, 0xFE, 0x00, 0x04, 0x1F, 0xE0, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x38, 0x00, 0x01, 0xE0, 0x04, 0x3E, 0x00, 0x07, 0xC0, 0x00, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00}, /*"V", 54*/
+ {0x04, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x07, 0xFF, 0xC0, 0x04, 0x1F, 0xF8, 0x00, 0x07, 0xC0, 0x07, 0xF8, 0x00, 0x07, 0xFF, 0x80, 0x04, 0x3F, 0xF8, 0x00, 0x07, 0xC0, 0x04, 0xF8, 0x00, 0x07, 0x00, 0x00, 0x04, 0x00, 0x00}, /*"W", 55*/
+ {0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x06, 0x00, 0x18, 0x07, 0xC0, 0x78, 0x05, 0xF1, 0xC8, 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x80, 0x04, 0x63, 0xE8, 0x07, 0x80, 0xF8, 0x06, 0x00, 0x18, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00}, /*"X", 56*/
+ {0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x07, 0x80, 0x00, 0x07, 0xE0, 0x08, 0x04, 0x7C, 0x08, 0x00, 0x1F, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x18, 0x08, 0x04, 0xE0, 0x08, 0x07, 0x00, 0x00, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00}, /*"Y", 57*/
+ {0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x06, 0x00, 0x38, 0x04, 0x00, 0xF8, 0x04, 0x03, 0xE8, 0x04, 0x0F, 0x08, 0x04, 0x7C, 0x08, 0x05, 0xF0, 0x08, 0x07, 0xC0, 0x08, 0x07, 0x00, 0x18, 0x04, 0x00, 0x60, 0x00, 0x00, 0x00}, /*"Z", 58*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x20, 0x00, 0x02, 0x20, 0x00, 0x02, 0x20, 0x00, 0x02, 0x20, 0x00, 0x02, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00}, /*"[", 59*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x38, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x30, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}, /*"\", 60*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x02, 0x20, 0x00, 0x02, 0x20, 0x00, 0x02, 0x20, 0x00, 0x02, 0x20, 0x00, 0x02, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"]", 61*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x00, 0x00, 0x30, 0x00, 0x00, 0x20, 0x00, 0x00, 0x30, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"^", 62*/
+ {0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01}, /*"_", 63*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"`", 64*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x19, 0xF8, 0x00, 0x1B, 0x18, 0x00, 0x22, 0x08, 0x00, 0x26, 0x08, 0x00, 0x24, 0x08, 0x00, 0x24, 0x10, 0x00, 0x3F, 0xF8, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x18}, /*"a", 65*/
+ {0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07, 0xFF, 0xF8, 0x0F, 0xFF, 0xF0, 0x00, 0x18, 0x18, 0x00, 0x10, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x30, 0x18, 0x00, 0x1F, 0xF0, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00}, /*"b", 66*/
+ {0x00, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x18, 0x30, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x3C, 0x08, 0x00, 0x1C, 0x10, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"c", 67*/
+ {0x00, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x38, 0x18, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x04, 0x10, 0x10, 0x07, 0xFF, 0xF8, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, /*"d", 68*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x12, 0x30, 0x00, 0x22, 0x18, 0x00, 0x22, 0x08, 0x00, 0x22, 0x08, 0x00, 0x32, 0x08, 0x00, 0x1E, 0x10, 0x00, 0x0E, 0x20, 0x00, 0x00, 0x00}, /*"e", 69*/
+ {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x01, 0xFF, 0xF8, 0x03, 0xFF, 0xF8, 0x06, 0x20, 0x08, 0x04, 0x20, 0x08, 0x04, 0x20, 0x08, 0x07, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"f", 70*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x0E, 0x6E, 0x00, 0x1F, 0xF3, 0x00, 0x31, 0xB1, 0x00, 0x20, 0xB1, 0x00, 0x20, 0xB1, 0x00, 0x31, 0x91, 0x00, 0x1F, 0x13, 0x00, 0x2E, 0x1E, 0x00, 0x20, 0x0E, 0x00, 0x30, 0x00}, /*"g", 71*/
+ {0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x0F, 0xFF, 0xF8, 0x00, 0x10, 0x08, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x08, 0x00, 0x3F, 0xF8, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00}, /*"h", 72*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x06, 0x3F, 0xF8, 0x06, 0x3F, 0xF8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"i", 73*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x20, 0x01, 0x00, 0x20, 0x01, 0x00, 0x20, 0x03, 0x06, 0x3F, 0xFE, 0x06, 0x3F, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"j", 74*/
+ {0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x0F, 0xFF, 0xF8, 0x00, 0x01, 0x88, 0x00, 0x03, 0x00, 0x00, 0x2F, 0xC0, 0x00, 0x38, 0xF8, 0x00, 0x20, 0x38, 0x00, 0x20, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00}, /*"k", 75*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x04, 0x00, 0x08, 0x07, 0xFF, 0xF8, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"l", 76*/
+ {0x00, 0x20, 0x08, 0x00, 0x3F, 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x10, 0x08, 0x00, 0x20, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x10, 0x08, 0x00, 0x20, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x08}, /*"m", 77*/
+ {0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x00, 0x3F, 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x10, 0x08, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x08, 0x00, 0x3F, 0xF8, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00}, /*"n", 78*/
+ {0x00, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x18, 0x30, 0x00, 0x30, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x30, 0x08, 0x00, 0x18, 0x30, 0x00, 0x0F, 0xF0, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x00}, /*"o", 79*/
+ {0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x3F, 0xFF, 0x00, 0x3F, 0xFF, 0x00, 0x10, 0x11, 0x00, 0x20, 0x09, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x30, 0x38, 0x00, 0x1F, 0xF0, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00}, /*"p", 80*/
+ {0x00, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x38, 0x18, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x09, 0x00, 0x10, 0x11, 0x00, 0x1F, 0xFF, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}, /*"q", 81*/
+ {0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x3F, 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x08, 0x08, 0x00, 0x10, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x00, 0x00, 0x30, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00}, /*"r", 82*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x78, 0x00, 0x1E, 0x18, 0x00, 0x33, 0x08, 0x00, 0x23, 0x08, 0x00, 0x21, 0x08, 0x00, 0x21, 0x88, 0x00, 0x21, 0x98, 0x00, 0x30, 0xF0, 0x00, 0x38, 0x60, 0x00, 0x00, 0x00}, /*"s", 83*/
+ {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0xFF, 0xF0, 0x03, 0xFF, 0xF8, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"t", 84*/
+ {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x18, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x20, 0x10, 0x00, 0x3F, 0xF8, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00}, /*"u", 85*/
+ {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x30, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x23, 0xF0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x70, 0x00, 0x23, 0x80, 0x00, 0x3C, 0x00, 0x00, 0x30, 0x00, 0x00, 0x20, 0x00}, /*"v", 86*/
+ {0x00, 0x20, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x23, 0xF8, 0x00, 0x00, 0xE0, 0x00, 0x27, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x21, 0xF8, 0x00, 0x01, 0xE0, 0x00, 0x3E, 0x00, 0x00, 0x20, 0x00}, /*"w", 87*/
+ {0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x00, 0x20, 0x08, 0x00, 0x38, 0x38, 0x00, 0x3E, 0x68, 0x00, 0x27, 0x80, 0x00, 0x03, 0xC8, 0x00, 0x2C, 0xF8, 0x00, 0x38, 0x38, 0x00, 0x20, 0x18, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00}, /*"x", 88*/
+ {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x30, 0x03, 0x00, 0x3C, 0x01, 0x00, 0x3F, 0x83, 0x00, 0x23, 0xEC, 0x00, 0x00, 0x70, 0x00, 0x23, 0x80, 0x00, 0x3C, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00}, /*"y", 89*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x08, 0x00, 0x20, 0x38, 0x00, 0x20, 0xF8, 0x00, 0x23, 0xE8, 0x00, 0x2F, 0x88, 0x00, 0x3E, 0x08, 0x00, 0x38, 0x08, 0x00, 0x20, 0x18, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00}, /*"z", 90*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x14, 0x00, 0x1F, 0xF7, 0xFC, 0x30, 0x00, 0x06, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"{", 91*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"|", 92*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x02, 0x30, 0x00, 0x06, 0x1F, 0xF7, 0xFC, 0x00, 0x14, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*"}", 93*/
+ {0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x10, 0x00, 0x00}, /*"~", 94*/
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/app/src/basic/ssd1306/driver_ssd1306_interface.c b/app/src/basic/ssd1306/driver_ssd1306_interface.c
new file mode 100644
index 0000000..b710232
--- /dev/null
+++ b/app/src/basic/ssd1306/driver_ssd1306_interface.c
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2015 - present LibDriver All rights reserved
+ *
+ * The MIT License (MIT)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * @file driver_ssd1306_interface_template.c
+ * @brief driver ssd1306 interface template source file
+ * @version 2.0.0
+ * @author Shifeng Li
+ * @date 2021-03-30
+ *
+ * history
+ *
+ * Date | Version | Author | Description
+ * |
---|
2021/03/30 | 2.0 | Shifeng Li | format the code
+ * |
2020/12/10 | 1.0 | Shifeng Li | first upload
+ * |
+ */
+
+#include "basic/ssd1306/driver_ssd1306_interface.h"
+
+
+extern uint8_t SingleLeadECG_spi_init(void);
+extern uint8_t SingleLeadECG_spi_deinit(void);
+extern uint8_t SingleLeadECG_spi_write_cmd(uint8_t *buf, uint16_t len);
+extern void SingleLeadECG_delay_ms(uint32_t ms);
+extern void SingleLeadECG_debug_print(const char *const fmt, ...);
+extern uint8_t SingleLeadECG_spi_cmd_data_gpio_init(void);
+extern uint8_t SingleLeadECG_spi_cmd_data_gpio_deinit(void);
+extern uint8_t SingleLeadECG_spi_cmd_data_gpio_write(uint8_t value);
+extern uint8_t SingleLeadECG_reset_gpio_init(void);
+extern uint8_t SingleLeadECG_reset_gpio_deinit(void);
+extern uint8_t SingleLeadECG_reset_gpio_write(uint8_t value);
+
+
+uint8_t ssd1306_interface_iic_init(void) { return 0; }
+uint8_t ssd1306_interface_iic_deinit(void) { return 0; }
+uint8_t ssd1306_interface_iic_write(uint8_t addr, uint8_t reg, uint8_t *buf, uint16_t len) { return 0; }
+
+uint8_t ssd1306_interface_spi_init(void) { return SingleLeadECG_spi_init(); }
+uint8_t ssd1306_interface_spi_deinit(void) { return SingleLeadECG_spi_deinit(); }
+uint8_t ssd1306_interface_spi_write_cmd(uint8_t *buf, uint16_t len) { return SingleLeadECG_spi_write_cmd(buf, len); }
+void ssd1306_interface_delay_ms(uint32_t ms) { SingleLeadECG_delay_ms(ms); }
+void ssd1306_interface_debug_print(const char *const fmt, ...) { SingleLeadECG_debug_print(fmt); }
+uint8_t ssd1306_interface_spi_cmd_data_gpio_init(void) { return SingleLeadECG_spi_cmd_data_gpio_init(); }
+uint8_t ssd1306_interface_spi_cmd_data_gpio_deinit(void) { return SingleLeadECG_spi_cmd_data_gpio_deinit(); }
+uint8_t ssd1306_interface_spi_cmd_data_gpio_write(uint8_t value) { return SingleLeadECG_spi_cmd_data_gpio_write(value); }
+uint8_t ssd1306_interface_reset_gpio_init(void) { return SingleLeadECG_reset_gpio_init(); }
+uint8_t ssd1306_interface_reset_gpio_deinit(void) { return SingleLeadECG_reset_gpio_deinit(); }
+uint8_t ssd1306_interface_reset_gpio_write(uint8_t value) { return SingleLeadECG_reset_gpio_write(value); }
diff --git a/app/src/basic/ssd1306/driver_ssd1306_interface.h b/app/src/basic/ssd1306/driver_ssd1306_interface.h
new file mode 100644
index 0000000..093ed1d
--- /dev/null
+++ b/app/src/basic/ssd1306/driver_ssd1306_interface.h
@@ -0,0 +1,192 @@
+/**
+ * Copyright (c) 2015 - present LibDriver All rights reserved
+ *
+ * The MIT License (MIT)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * @file driver_ssd1306_interface.h
+ * @brief driver ssd1306 interface header file
+ * @version 2.0.0
+ * @author Shifeng Li
+ * @date 2021-03-30
+ *
+ * history
+ *
+ * Date | Version | Author | Description
+ * |
---|
2021/03/30 | 2.0 | Shifeng Li | format the code
+ * |
2020/12/10 | 1.0 | Shifeng Li | first upload
+ * |
+ */
+
+#ifndef DRIVER_SSD1306_INTERFACE_H
+#define DRIVER_SSD1306_INTERFACE_H
+
+#include "driver_ssd1306.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/**
+ * @defgroup ssd1306_interface_driver ssd1306 interface driver function
+ * @brief ssd1306 interface driver modules
+ * @ingroup ssd1306_driver
+ * @{
+ */
+
+/**
+ * @brief interface iic bus init
+ * @return status code
+ * - 0 success
+ * - 1 iic init failed
+ * @note none
+ */
+uint8_t ssd1306_interface_iic_init(void);
+
+/**
+ * @brief interface iic bus deinit
+ * @return status code
+ * - 0 success
+ * - 1 iic deinit failed
+ * @note none
+ */
+uint8_t ssd1306_interface_iic_deinit(void);
+
+/**
+ * @brief interface iic bus write
+ * @param[in] addr is the iic device write address
+ * @param[in] reg is the iic register address
+ * @param[in] *buf points to a data buffer
+ * @param[in] len is the length of the data buffer
+ * @return status code
+ * - 0 success
+ * - 1 write failed
+ * @note none
+ */
+uint8_t ssd1306_interface_iic_write(uint8_t addr, uint8_t reg, uint8_t *buf, uint16_t len);
+
+/**
+ * @brief interface spi bus init
+ * @return status code
+ * - 0 success
+ * - 1 spi init failed
+ * @note none
+ */
+uint8_t ssd1306_interface_spi_init(void);
+
+/**
+ * @brief interface spi bus deinit
+ * @return status code
+ * - 0 success
+ * - 1 spi deinit failed
+ * @note none
+ */
+uint8_t ssd1306_interface_spi_deinit(void);
+
+/**
+ * @brief interface spi bus write
+ * @param[in] *buf points to a data buffer
+ * @param[in] len is the length of data buffer
+ * @return status code
+ * - 0 success
+ * - 1 write failed
+ * @note none
+ */
+uint8_t ssd1306_interface_spi_write_cmd(uint8_t *buf, uint16_t len);
+
+/**
+ * @brief interface delay ms
+ * @param[in] ms
+ * @note none
+ */
+void ssd1306_interface_delay_ms(uint32_t ms);
+
+/**
+ * @brief interface print format data
+ * @param[in] fmt is the format data
+ * @note none
+ */
+void ssd1306_interface_debug_print(const char *const fmt, ...);
+
+/**
+ * @brief interface command && data gpio init
+ * @return status code
+ * - 0 success
+ * - 1 gpio init failed
+ * @note none
+ */
+uint8_t ssd1306_interface_spi_cmd_data_gpio_init(void);
+
+/**
+ * @brief interface command && data gpio deinit
+ * @return status code
+ * - 0 success
+ * - 1 gpio deinit failed
+ * @note none
+ */
+uint8_t ssd1306_interface_spi_cmd_data_gpio_deinit(void);
+
+/**
+ * @brief interface command && data gpio write
+ * @param[in] value is the written value
+ * @return status code
+ * - 0 success
+ * - 1 gpio write failed
+ * @note none
+ */
+uint8_t ssd1306_interface_spi_cmd_data_gpio_write(uint8_t value);
+
+/**
+ * @brief interface reset gpio init
+ * @return status code
+ * - 0 success
+ * - 1 gpio init failed
+ * @note none
+ */
+uint8_t ssd1306_interface_reset_gpio_init(void);
+
+/**
+ * @brief interface reset gpio deinit
+ * @return status code
+ * - 0 success
+ * - 1 gpio deinit failed
+ * @note none
+ */
+uint8_t ssd1306_interface_reset_gpio_deinit(void);
+
+/**
+ * @brief interface reset gpio write
+ * @param[in] value is the written value
+ * @return status code
+ * - 0 success
+ * - 1 gpio write failed
+ * @note none
+ */
+uint8_t ssd1306_interface_reset_gpio_write(uint8_t value);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/app/src/one_conduction/one_conduction_board.c b/app/src/one_conduction/one_conduction_board.c
index e69de29..cbeb1ba 100644
--- a/app/src/one_conduction/one_conduction_board.c
+++ b/app/src/one_conduction/one_conduction_board.c
@@ -0,0 +1,280 @@
+#include "one_conduction_board.h"
+
+#include "sys.h"
+//
+#include "app_timer.h"
+#include "diskio_blkdev.h"
+#include "ff.h"
+#include "nrf_block_dev_sdc.h"
+#include "nrf_delay.h"
+#include "nrf_drv_pwm.h"
+#include "nrf_drv_saadc.h"
+#include "nrf_drv_twi.h"
+#include "nrf_drv_wdt.h"
+#include "nrf_gpio.h"
+
+#define SCREEN_SPI_INSTANCE 0
+#define SCREEN_RESET_PIN 20
+#define SCREEN_POWER_PIN 30
+#define SCREEN_A0PIN 31
+#define SCREEN_CS_PIN 29
+#define SCREEN_CLK_PIN 4
+#define SCREEN_MOSI_PIN 11
+
+#define LED_GREEN_PIN 9
+#define LED_BLUE_PIN 10
+
+#define ECG_NLOD_PIN 3
+#define ECG_PLOD_PIN 28
+#define ECG_ADC_PIN NRF_SAADC_INPUT_AIN2
+#define ECG_ADC_CHANNEL 0 // 不重复即可
+
+#define BATTERY_ADC_PIN NRF_SAADC_INPUT_VDD
+#define BATTERY_ADC_CHANNEL 1 // 不重复即可
+
+#define EEPROM_I2C_SCL_M 15 // I2C SCL引脚
+#define EEPROM_I2C_SDA_M 17 // I2C SDA引脚
+#define EEPROM_I2C_INSTANCE 1 // I2C使用的硬件控制器ID
+
+/*******************************************************************************
+ * TOOLS *
+ *******************************************************************************/
+
+static void znrf_gpio_cfg_output(uint32_t pin_number, nrf_gpio_pin_pull_t pull) { //
+ nrf_gpio_cfg(pin_number, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, pull, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE);
+}
+
+static int16_t adc_channel_read_val(uint16_t channel) {
+ nrf_saadc_value_t value;
+ ret_code_t err_code;
+ err_code = nrfx_saadc_sample_convert(channel, &value);
+ if (err_code != NRF_SUCCESS) {
+ ZLOGE("nrfx_saadc_sample_convert(%d) fail err_code:%d", channel, err_code);
+ return 0;
+ }
+ return value;
+}
+
+/*******************************************************************************
+ * ADC *
+ *******************************************************************************/
+void SingleLeadECG_adc_module_init() {
+ nrf_drv_saadc_config_t adccfg = NRFX_SAADC_DEFAULT_CONFIG;
+ adccfg.resolution = NRF_SAADC_RESOLUTION_12BIT; // 4096 等于满采样率
+ ZERROR_CHECK(nrf_drv_saadc_init(&adccfg, NULL));
+}
+
+/*******************************************************************************
+ * 蜂鸣器 *
+ *******************************************************************************/
+static nrf_drv_pwm_t m_beep_pwm0 = NRF_DRV_PWM_INSTANCE(0);
+static nrf_pwm_values_individual_t m_beep_pwm0_seq_values = {0};
+static nrf_pwm_sequence_t const m_beep_pwm0_seq = {
+ .values.p_individual = &m_beep_pwm0_seq_values,
+ .length = NRF_PWM_VALUES_LENGTH(m_beep_pwm0_seq_values),
+ .repeats = 0,
+ .end_delay = 0,
+};
+static nrf_drv_pwm_config_t const m_beep_pwm0_config0 = {
+ .output_pins = {11},
+ .irq_priority = APP_IRQ_PRIORITY_LOWEST,
+ .base_clock = NRF_PWM_CLK_125kHz,
+ .count_mode = NRF_PWM_MODE_UP,
+ .top_value = 46, // 125kHz / 46 = 2.717k
+ .load_mode = NRF_PWM_LOAD_INDIVIDUAL,
+ .step_mode = NRF_PWM_STEP_AUTO,
+};
+void SingleLeadECG_beep_init() { APP_ERROR_CHECK(nrfx_pwm_init(&m_beep_pwm0, &m_beep_pwm0_config0, NULL)); }
+void SingleLeadECG_beep_set_state(bool state) {
+ if (state) {
+ m_beep_pwm0_seq_values.channel_0 = 23; // 设置占空比,数值最大不超过 top_value
+ nrfx_pwm_simple_playback(&m_beep_pwm0, &m_beep_pwm0_seq, 1, NRF_DRV_PWM_FLAG_LOOP);
+ } else {
+ nrfx_pwm_stop(&m_beep_pwm0, true);
+ }
+}
+/*******************************************************************************
+ * SCREEN *
+ *******************************************************************************/
+
+typedef struct {
+ // BASIC IF
+ uint32_t reset_pin;
+ uint32_t power_pin;
+ uint32_t a0pin; // cmd/data
+ // SPI IF
+ uint32_t cs_pin;
+ uint32_t clk_pin;
+ uint32_t mosi_pin;
+
+} screen_handler_t;
+
+static screen_handler_t m_screen_handler = {
+ .reset_pin = SCREEN_RESET_PIN,
+ .power_pin = SCREEN_POWER_PIN,
+ .a0pin = SCREEN_A0PIN,
+ .cs_pin = SCREEN_CS_PIN,
+ .clk_pin = SCREEN_CLK_PIN,
+ .mosi_pin = SCREEN_MOSI_PIN,
+};
+static const nrf_drv_spi_t m_screen_spi = NRF_DRV_SPI_INSTANCE(SCREEN_SPI_INSTANCE); /**< SPI instance. */
+
+void SingleLeadECG_screen_init() {
+ znrf_gpio_cfg_output(SCREEN_RESET_PIN, NRF_GPIO_PIN_NOPULL);
+ znrf_gpio_cfg_output(SCREEN_POWER_PIN, NRF_GPIO_PIN_NOPULL);
+ znrf_gpio_cfg_output(SCREEN_A0PIN, NRF_GPIO_PIN_NOPULL);
+
+ nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
+ spi_config.ss_pin = SCREEN_CS_PIN; // NRF_DRV_SPI_PIN_NOT_USED
+ spi_config.miso_pin = NRF_DRV_SPI_PIN_NOT_USED;
+ spi_config.mosi_pin = SCREEN_MOSI_PIN;
+ spi_config.sck_pin = SCREEN_CLK_PIN;
+ spi_config.frequency = NRF_DRV_SPI_FREQ_1M;
+ ZERROR_CHECK(nrf_drv_spi_init(&m_screen_spi, &spi_config, NULL, NULL));
+}
+
+void SingleLeadECG_screen_deinit() {
+ // TODO
+}
+uint8_t SingleLeadECG_spi_init(void) { return 0; }
+uint8_t SingleLeadECG_spi_deinit(void) { return 0; }
+uint8_t SingleLeadECG_spi_cmd_data_gpio_init(void) { return 0; }
+uint8_t SingleLeadECG_spi_cmd_data_gpio_deinit(void) { return 0; }
+void SingleLeadECG_debug_print(const char *const fmt, ...) {}
+uint8_t SingleLeadECG_reset_gpio_init(void) { return 0; }
+uint8_t SingleLeadECG_reset_gpio_deinit(void) { return 0; }
+uint8_t SingleLeadECG_spi_write_cmd(uint8_t *buf, uint16_t len) { //
+ ZERROR_CHECK(nrf_drv_spi_transfer(&m_screen_spi, buf, len, NULL, 0));
+ return 0;
+}
+void SingleLeadECG_delay_ms(uint32_t ms) { nrf_delay_ms(ms); }
+uint8_t SingleLeadECG_spi_cmd_data_gpio_write(uint8_t value) {
+ if (value) {
+ nrf_gpio_pin_set(SCREEN_A0PIN);
+ } else {
+ nrf_gpio_pin_clear(SCREEN_A0PIN);
+ }
+ return 0;
+}
+uint8_t SingleLeadECG_reset_gpio_write(uint8_t value) {
+ if (value) {
+ nrf_gpio_pin_set(SCREEN_RESET_PIN);
+ } else {
+ nrf_gpio_pin_clear(SCREEN_RESET_PIN);
+ }
+ return 0;
+}
+
+/*******************************************************************************
+ * LED *
+ *******************************************************************************/
+void SingleLeadECG_led_init() {
+ znrf_gpio_cfg_output(LED_GREEN_PIN, NRF_GPIO_PIN_NOPULL);
+ znrf_gpio_cfg_output(LED_BLUE_PIN, NRF_GPIO_PIN_NOPULL);
+}
+void SingleLeadECG_led_green_set_state(bool state) {
+ if (state) {
+ nrf_gpio_pin_set(LED_GREEN_PIN);
+ } else {
+ nrf_gpio_pin_clear(LED_GREEN_PIN);
+ }
+}
+void SingleLeadECG_led_blue_set_state(bool state) {
+ if (state) {
+ nrf_gpio_pin_set(LED_BLUE_PIN);
+ } else {
+ nrf_gpio_pin_clear(LED_BLUE_PIN);
+ }
+}
+
+/*******************************************************************************
+ * ecg *
+ *******************************************************************************/
+
+void SingleLeadECG_ecg_init() {
+ nrf_saadc_channel_config_t channel_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(ECG_ADC_PIN);
+ channel_config.acq_time = NRF_SAADC_ACQTIME_40US;
+ ZERROR_CHECK(nrfx_saadc_channel_init(ECG_ADC_CHANNEL, &channel_config));
+
+ nrf_gpio_cfg_sense_input(ECG_NLOD_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE);
+ nrf_gpio_cfg_sense_input(ECG_PLOD_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE);
+}
+
+bool SingleLeadECG_ecg_nlod_get_connected_state() { return nrf_gpio_pin_read(ECG_NLOD_PIN) == 0; }
+bool SingleLeadECG_ecg_plod_get_connected_state() { return nrf_gpio_pin_read(ECG_PLOD_PIN) == 0; }
+int16_t SingleLeadECG_ecg_plod_get_ecg_val() { return adc_channel_read_val(ECG_ADC_CHANNEL); }
+
+/*******************************************************************************
+ * BATTERY *
+ *******************************************************************************/
+void SingleLeadECG_battery_init() {
+ nrf_saadc_channel_config_t channel_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(BATTERY_ADC_PIN);
+ channel_config.acq_time = NRF_SAADC_ACQTIME_10US;
+ ZERROR_CHECK(nrfx_saadc_channel_init(BATTERY_ADC_CHANNEL, &channel_config));
+}
+int16_t SingleLeadECG_battery_get_adc_val() {
+ int16_t val = adc_channel_read_val(BATTERY_ADC_CHANNEL);
+ return val;
+}
+
+/*******************************************************************************
+ * eeprom *
+ *******************************************************************************/
+static const nrf_drv_twi_t m_eeprom_twi_master = NRF_DRV_TWI_INSTANCE(EEPROM_I2C_INSTANCE);
+
+void SingleLeadECG_eeprom_init() {
+ const nrf_drv_twi_config_t config = {
+ .scl = EEPROM_I2C_SCL_M,
+ .sda = EEPROM_I2C_SDA_M,
+ .frequency = NRF_DRV_TWI_FREQ_100K,
+ .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
+ .clear_bus_init = false,
+ };
+
+ ZERROR_CHECK(nrf_drv_twi_init(&m_eeprom_twi_master, &config, NULL, NULL));
+ nrf_drv_twi_enable(&m_eeprom_twi_master);
+}
+static uint8_t eeprom_cache[EEPROM_PAGE + 2];
+
+static void assign_i2c_add(uint32_t add, bool wr, uint8_t *i2cadd, uint8_t *memadd0, uint8_t *memadd1) {
+ // DEVICE SELECT
+ // bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
+ // 1 0 1 0 E2 A17 A16 RW(W=0)
+ //
+ // PS: E2 参考原理图中的电平为0,所以bit3为0
+ //
+ // MEM0
+ // bit15 bit14 bit13 bit12 bit11 bit10 bit9 bit8
+ // MEM1
+ // bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
+ //
+
+ *i2cadd = 0xA0;
+ uint8_t a16a17 = (add >> 16) & 0x03;
+ *i2cadd |= a16a17 << 1;
+
+ *i2cadd = wr ? *i2cadd & 0xFE : *i2cadd | 0x01;
+
+ *memadd0 = add >> 8;
+ *memadd1 = add & 0xFF;
+}
+
+void SingleLeadECG_eeprom_write(uint16_t page, uint8_t *data, uint16_t len) { //
+ uint32_t addr = page * EEPROM_PAGE;
+ len = len > EEPROM_PAGE ? EEPROM_PAGE : len;
+ uint8_t deviceSelect = 0;
+
+ assign_i2c_add(addr, true, &deviceSelect, &eeprom_cache[0], &eeprom_cache[1]);
+ nrf_drv_twi_tx(&m_eeprom_twi_master, deviceSelect, eeprom_cache, len + 2, false);
+}
+
+void SingleLeadECG_eeprom_read(uint32_t add, uint8_t *data, uint16_t len) {
+ uint8_t deviceSelect = 0;
+ uint8_t wadd[2] = {0};
+
+ assign_i2c_add(add, false, &deviceSelect, &wadd[0], &wadd[1]);
+ nrf_drv_twi_tx(&m_eeprom_twi_master, deviceSelect, wadd, 2, false);
+
+ deviceSelect |= 0x01; // read
+ nrf_drv_twi_rx(&m_eeprom_twi_master, deviceSelect, data, len);
+}
diff --git a/app/src/one_conduction/one_conduction_board.h b/app/src/one_conduction/one_conduction_board.h
index 95300f1..2f1cd12 100644
--- a/app/src/one_conduction/one_conduction_board.h
+++ b/app/src/one_conduction/one_conduction_board.h
@@ -1,4 +1,65 @@
#pragma once
-#define VERSION 1
-#define MANUFACTURER_NAME "iflytop"
-#define BLE_NAME "iflytop_test"
\ No newline at end of file
+#define VERSION 1
+#define MANUFACTURER_NAME "iflytop"
+#define BLE_NAME "iflytop_test"
+
+/*******************************************************************************
+ * INCLUDE *
+ *******************************************************************************/
+#include
+
+#include "basic/ssd1306/driver_ssd1306_interface.h"
+
+/*******************************************************************************
+ * basic *
+ *******************************************************************************/
+void SingleLeadECG_adc_module_init();
+
+/*******************************************************************************
+ * 蜂鸣器 *
+ *******************************************************************************/
+void SingleLeadECG_beep_init();
+void SingleLeadECG_beep_set_state(bool state);
+
+/*******************************************************************************
+ * EEPROM *
+ *******************************************************************************/
+/**
+ *
+ * PageSize 256byte
+ *
+ */
+#define EEPROM_PAGE 256
+void SingleLeadECG_eeprom_init();
+void SingleLeadECG_eeprom_write_page(uint16_t page, uint8_t* data, uint16_t len);
+void SingleLeadECG_eeprom_read(uint32_t add, uint8_t* data, uint16_t len);
+
+/*******************************************************************************
+ * SCREEN *
+ *******************************************************************************/
+
+void SingleLeadECG_screen_init();
+void SingleLeadECG_screen_deinit();
+
+/*******************************************************************************
+ * LED *
+ *******************************************************************************/
+void SingleLeadECG_led_init();
+void SingleLeadECG_led_green_set_state(bool state);
+void SingleLeadECG_led_blue_set_state(bool state);
+
+/*******************************************************************************
+ * ECG *
+ *******************************************************************************/
+
+void SingleLeadECG_ecg_init();
+bool SingleLeadECG_ecg_nlod_get_connected_state();
+bool SingleLeadECG_ecg_plod_get_connected_state();
+int16_t SingleLeadECG_ecg_plod_get_ecg_val();
+
+/*******************************************************************************
+ * BATTERY *
+ *******************************************************************************/
+
+void SingleLeadECG_battery_init();
+int16_t SingleLeadECG_battery_get_adc_val();
\ No newline at end of file
diff --git a/m24m02-dr.pdf b/m24m02-dr.pdf
new file mode 100644
index 0000000..67a6ec6
Binary files /dev/null and b/m24m02-dr.pdf differ