summaryrefslogtreecommitdiff
path: root/bsp/hc32/tests/test_soft_i2c.c
blob: 4cce95dabde951d77e89d7405468434f422a4f6a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
/*
 * Copyright (c) 2022-2024, Xiaohua Semiconductor Co., Ltd.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-12-30     CDT          first version
 */

/*
 * 程序清单:这是 Soft I2C 设备使用例程。
 * 例程导出了 sw_i2c_sample 到控制终端。
 * 命令调用格式:sw_i2c_sample cmd_id [options]
 * 命令解释:命令第二个参数是要使用的Soft I2C设备的命令,为空则打印命令使用说明
 * 程序功能:查找Soft I2C设备,读写I2C设备寄存器。
 * 注意:测试要用逻辑分析仪或示波器抓取信号
*/

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include "rtconfig.h"
#include "rtdef.h"

#if defined(RT_USING_I2C)

#if defined(BSP_USING_I2C1_SW)

/* using i2c1 control oled12864 */
#define SW_I2C_NAME         "i2c1_sw"
#define SSD1306_ADDR        (0x78U >> 1)
#define SSD1306_MD_CMD      (0x00U)
#define SSD1306_MD_DATA     (0x40U)

/* symbol parameters: width pixles, lenght pixels */
#define SYM_W_PIX           (8U)
#define SYM_H_PIX           (8U)
/* ssd ohysical parameters */
#define SSD_PAGE_SIZE       (8U)
#define SSD_COL_SIZE        (128U)
/* each page 8 pix */
#define PAGE_PIX_SIZE       (8U)

/* each byte set horizontal 1 pix */
#define SYM_W_BYTE          (SYM_W_PIX / 1)
/* each byte set vertical 8 pix */
#define SYM_H_BYTE          (SYM_H_PIX / 8)
/* each character occupis */
#define SYM_BYTE_SIZE       (SYM_W_BYTE * SYM_H_BYTE)

/* soft i2c command defines */
enum SW_I2C_CMD
{
    SW_I2C_INIT = 0x01,
    SSD1306_CMD_INIT,
    SSD1306_CMD_DISPLAY,
    SSD1306_CMD_DEINIT,
};

/* local variables */
struct rt_i2c_msg msg;
rt_uint8_t ssd_init_array[30];
rt_uint8_t logo_array[5][SYM_BYTE_SIZE];

/* local functions */
static void ssd1306_init(struct rt_i2c_bus_device *i2c_dev);
static void ssd1306_roll_display(struct rt_i2c_bus_device *i2c_dev);
static void ssd1306_deinit(struct rt_i2c_bus_device *i2c_dev);

/* write_reg ssd1306 basic opertion */
static void ssd1306_write_single_reg(struct rt_i2c_bus_device *i2c_dev,
                                     rt_bool_t is_write_cmd, rt_uint8_t data)
{
    rt_uint8_t buff[2];
    struct rt_i2c_msg msgs;

    msgs.addr = SSD1306_ADDR;
    msgs.flags = RT_I2C_WR;

    if (RT_TRUE == is_write_cmd)
    {
        buff[0] = SSD1306_MD_CMD;
    }
    else
    {
        buff[0] = SSD1306_MD_DATA;
    }

    buff[1] = data;
    msgs.buf = buff;
    msgs.len = 2;

    if (1 != rt_i2c_transfer(i2c_dev, &msgs, 1))
    {
        rt_kprintf("failed to send cmd\n");
    }
}

/* write_reg ssd1306 basic opertion */
static void ssd1306_write_mult_reg(struct rt_i2c_bus_device *i2c_dev,
                                   rt_bool_t is_write_cmd, rt_uint8_t len, rt_uint8_t *data
                                   /*rt_uint8_t data*/)
{
    rt_uint8_t *buff = NULL;
    struct rt_i2c_msg msgs;

    msgs.addr = SSD1306_ADDR;
    msgs.flags = RT_I2C_WR;
    buff = (rt_uint8_t *)rt_malloc((len + 1) * sizeof(rt_uint8_t));

    if (RT_TRUE == is_write_cmd)
    {
        buff[0] = SSD1306_MD_CMD;
    }
    else
    {
        buff[0] = SSD1306_MD_DATA;
    }
    rt_memcpy(buff + 1, data, len);
    msgs.buf = buff;
    msgs.len = len + 1;

    if (1 != rt_i2c_transfer(i2c_dev, &msgs, 1))
    {
        rt_kprintf("failed to send cmd\n");
    }
    rt_free(buff);
    buff = NULL;
}

static int sw_i2c_sample(int argc, char *argv[])
{
    static struct rt_i2c_bus_device *rt_i2c_dev;
    /* print soft i2c usage */
    if (argc <= 1)
    {
        rt_kprintf("soft i2c usage as following:\n");
        rt_kprintf("sw_i2c_sample %d: soft i2c init\n", SW_I2C_INIT);
        rt_kprintf("sw_i2c_sample %d: oled ssd1306 init\n", SSD1306_CMD_INIT);
        rt_kprintf("sw_i2c_sample %d: write ssd1306 \n", SSD1306_CMD_DISPLAY);
        rt_kprintf("sw_i2c_sample %d: turn off ssd1306\n", SSD1306_CMD_DEINIT);
        return -RT_ERROR;
    }

    switch (*argv[1] - '0')
    {
    case SW_I2C_INIT:
        rt_i2c_dev = (struct rt_i2c_bus_device *)rt_device_find(SW_I2C_NAME);
        if (NULL == rt_i2c_dev)
        {
            rt_kprintf("failed to find i2c device %s\n", SW_I2C_NAME);
            return -RT_ERROR;
        }
        break;
    /* communicate with eeprom to soft i2c read function */
    case SSD1306_CMD_INIT:
        ssd1306_init(rt_i2c_dev);
        break;
    /* communicate with ssd1306 to soft i2c read function */
    case SSD1306_CMD_DISPLAY:
        ssd1306_roll_display(rt_i2c_dev);
        break;
    case SSD1306_CMD_DEINIT:
        ssd1306_deinit(rt_i2c_dev);
        break;
    default:
        rt_kprintf("unkwon command\n");
        break;
    }

    return RT_EOK;
}

/* ssd1306 de-init and turn off */
static void ssd1306_deinit(struct rt_i2c_bus_device *i2c_dev)
{
    rt_uint8_t ssd_deinit_array[] =
    {
        0X8D, /* set charge pump */
        0X10, /* turn off charge pump */
        0XAE, /* OLED sleep */
    };

    ssd1306_write_mult_reg(i2c_dev, RT_TRUE,
                           sizeof(ssd_deinit_array) / sizeof(ssd_deinit_array[0]),
                           ssd_deinit_array);
}

/* ssd oled initialize */
static void ssd1306_init(struct rt_i2c_bus_device *i2c_dev)
{
    ssd1306_write_mult_reg(i2c_dev, RT_TRUE,
                           sizeof(ssd_init_array) / sizeof(ssd_init_array[0]),
                           ssd_init_array);
}

/*
    Function:   write a heigh * width = 16 *16 --->pixel: 16 * 8character
    Input:      void
    Output:     void
    Data:       20210828
*/

void mOledWriteCharHnWm(struct rt_i2c_bus_device *i2c_dev,
                        uint8_t page, uint8_t col, uint8_t *ArrChar)
{
    if (ArrChar == NULL)
        return;
    rt_kprintf("x=%3d, y=%d\n", col, page);
    for (uint8_t page_idx = 0; page_idx < SYM_H_BYTE; page_idx++)
    {
        /* set start page: page0-page1 */
        ssd1306_write_single_reg(i2c_dev, RT_TRUE, 0xb0 + page + page_idx);
        /* lower 4-bit address of column start */
        ssd1306_write_single_reg(i2c_dev, RT_TRUE, 0x00 + ((col & 0x0F) >> 0));
        /* higher 4-bit address of column start */
        ssd1306_write_single_reg(i2c_dev, RT_TRUE, 0x10 + ((col & 0xF0) >> 4));
        /* send a character(total BYTE_CHAR byte) from array */
        ssd1306_write_mult_reg(i2c_dev, RT_FALSE, SYM_W_BYTE,
                               ArrChar + SYM_W_BYTE * page_idx);
    }
}

/* fill oled with character "XHSC" */
static void ssd1306_roll_display(struct rt_i2c_bus_device *i2c_dev)
{
    rt_uint8_t base_col, base_page;
    rt_uint8_t offset_page, offset_col;
    rt_uint16_t idx;
    /* using a write times related variable control position */
    static rt_uint16_t u16WriteTimes = 0;

    if (u16WriteTimes >= (SSD_COL_SIZE / SYM_W_PIX) * (SSD_PAGE_SIZE / (SYM_H_PIX / PAGE_PIX_SIZE)))
    {
        u16WriteTimes = 0;
    }
    /* each page write, eg. base_page = 7 / (128 / 8) = 0 */
    base_page = u16WriteTimes / (SSD_COL_SIZE / SYM_W_PIX);
    /* eg. base_col = (7 % (128 / 8)) * 8 = 56 */
    base_col = (u16WriteTimes % (SSD_COL_SIZE / SYM_W_PIX)) * SYM_W_PIX;
    offset_page = 0;
    offset_col = 0;
    /* each write cycle finish the data writing in array */
    for (idx = 0; idx < sizeof(logo_array) / sizeof(logo_array[0]); idx++)
    {
        offset_col = idx * SYM_W_PIX;
        if (base_col + offset_col >= SSD_COL_SIZE)
        {
            /*
                base_col + offset_col = [128, 256), page_offset = 1,
                base_col + offset_col = [256, 384), page_offset = 2,
                ...
            */
            offset_page = (base_col + offset_col) / SSD_COL_SIZE;
        }
        mOledWriteCharHnWm(i2c_dev, ((base_page + offset_page) * SYM_H_BYTE) % SSD_PAGE_SIZE, (base_col + offset_col) % SSD_COL_SIZE, *(logo_array + idx));
    }
    u16WriteTimes++;
}

rt_uint8_t ssd_init_array[] =
{
    0xAE, /* display off */
    0x20, /* Set Memory Addressing Mode */
    0x10, /* Set addressing orient */
    0xB0, /* Set Page Start Address for Page Addressing Mode,0-7 */
    0xC8, /* Set COM Output Scan Direction */
    0x00, /* set low column address */
    0x10, /* set high column address */
    0x40, /* set start line address */
    0x81, /* set contrast control register */
    0xFF, /* breightness 0x00~0xff */
    0xA1, /* set segment re-map 0 to 127 */
    0xA6, /* set normal display */
    0xA8, /* set multiplex ratio(1 to 64) */
    0x3F, /*      */
    0xC8, /*     */
    0xA4, /* 0xa4,Output follows RAM content;0xa5,Output ignores RAM content */
    0xD3, /* set display offset */
    0x00, /* not offset */
    0xD5, /* set display clock divide ratio/oscillator frequency */
    0xF0, /* set divide ratio */
    0xD9, /* set pre-charge period */
    0x22, /*  */
    0xDA, /* set com pins hardware configuration */
    0x12, /*  */
    0xDB, /* set vcomh */
    0x20, /* 0x20,0.77xVcc */
    0x8D, /* set DC-DC enable */
    0x14, /*  */
    0xAF, /* --turn on oled panel */
};


rt_uint8_t logo_array[][SYM_BYTE_SIZE] =
{
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x44, 0x44, 0x6C, 0x74, 0x54, 0x6C, 0x44, 0x44, /*"X"*/
    0x44, 0x7C, 0x54, 0x10, 0x10, 0x54, 0x7C, 0x44, /*"H"*/
    0x00, 0x68, 0x54, 0x54, 0x54, 0x54, 0x24, 0x00, /*"S"*/
    0x38, 0x6C, 0x44, 0x44, 0x44, 0x44, 0x24, 0x00, /*"C"*/
};

MSH_CMD_EXPORT(sw_i2c_sample, soft i2c sample);

#endif /* BSP_USING_I2C1_SW */

#endif/* RT_USING_I2C */
/*
EOF
*/