移植 uGFX 到 ESP32

移植 uGFX 到 ESP32

准备

ESP8266火爆之后就开始关注ESPRESSIF公司的新产品,新品ESP32具有令人兴奋的性能,令人兴奋的通信能力(wifi+bluetooth),令人兴奋的价格….

ESP32官方的SDKESP-IDF是基于Makefile构建的,并且uGFX也是基于Makefile,虽然看起来一样,可整合起来还是很麻烦的。

配置环境

1
2
3
4
cd workspace/projects/hello_esp32  
mkdir components
cd components
git clone https://git.ugfx.io/uGFX/uGFX --depth=1
1
2
3
4
5
6
7
8
9
10
11
.  
├── build
├── components
│ └── uGFX
├── main
│ ├── component.mk
│ ├── hello_world_main.c
├── Makefile
├── README.md
├── sdkconfig
└── sdkconfig.old

整合Makefile

问题

但问题是,uGFX中’GFXINC’列表中文件路径都是绝对路径,而COMPONENT_ADD_INCLUDEDIRS要求的是相对路径(相对于component);COMPONENT_SRCDIRS要求的是Sources的目录,而GFXSRC提供的是待编译的源代码文件的列表。

解决方案(uGFX/component.mk)

1
2
3
GFXLIB := $(COMPONENT_PATH)  

include $(GFXLIB)/gfx.mk

这个后期会用到

1
include $(GFXLIB)/drivers/gdisp/SSD1306/driver.mk

强制把绝对路径转成相对路径解决Inc问题

1
COMPONENT_ADD_INCLUDEDIRS :=$(shell realpath --relative-to $(COMPONENT_PATH) $(GFXINC))

SRC问题只好手动解决了….
由于uGFX是纯C写的,这里只考虑了.c文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
define CUSTOM_GenerateCompileTargets  
\# $(1) - directory containing source files, !NOT! relative to $(COMPONENT_PATH)
$(info \[${1}\])
$(1).o: $(addsuffix .c,$(1))
$$(summary) CC $$@
$$(CC) $$(CFLAGS) $$(CPPFLAGS) $$(addprefix -I ,$$(COMPONENT_INCLUDES)) -I$(1) -c $$< -o $$@
endef

$(foreach cfile,$(GFXSRC), $(eval $(call CUSTOM_GenerateCompileTargets,$(basename $(cfile)))))

COMPONENT_OWNBUILDTARGET := 1
.PHONY: build
build: $(COMPONENT_LIBRARY)
@mkdir -p $(COMPONENT_SRCDIRS)

$(COMPONENT_LIBRARY): $(addsuffix .o,$(basename $(GFXSRC)))

$(summary) AR $@
rm -f $@
$(AR) cru $@ $^

配置uGFX

拷贝gfxconf.example.hmain/include/gfxconf.h中。
调整几个开关。

1
2
3
4
5
#define GFX_USE_OS_FREERTOS                          TRUE  
#define GFX_OS_NO_INIT TRUE
#define GFX_USE_GDISP TRUE
#define GDISP_NEED_VALIDATION TRUE
#define GDISP_NEED_CLIP TRUE

hello_esp32目录下执行make没什么问题就可写屏幕驱动了。

SSD1306 OLED驱动移植

uGFX果真功能强大,内置了对OLED的驱动SSD1306的支持,只需要编写几个I2C通信函数与esp-idf的I2C驱动对接即可。

开启uGFX对SSD1306支持

component.mk中添加

1
include $(GFXLIB)/drivers/gdisp/SSD1306/driver.mk

复制components/uGFX/drivers/gdisp/SSD1306/board_SSD1306_template.hmain/include/board_SSD1306.h

寻找I2C地址

模块买的时间长了,找不到当初的链接,找不到I2C地址就无法进行通信。
不过好在有个I2C Scanner可以用.link

对接I2C驱动

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
#include "driver/i2c.h"  
#define I2C_OLED 0x78
#define SDA 19
#define SCL 18
static i2c_cmd_handle_t cmd_handle;


static GFXINLINE void init_board(GDisplay \*g) {
i2c_config_t conf;
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = 18;
conf.scl_io_num = 19;
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf.master.clk_speed = 100000;

i2c_param_config(I2C_NUM_0, &conf);
i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0);
}

static GFXINLINE void write_cmd(GDisplay \*g, uint8_t cmd) {
cmd_handle = i2c_cmd_link_create();
i2c_master_start(cmd_handle);
i2c_master_write_byte(cmd_handle,I2C_OLED,false);
i2c_master_write_byte(cmd_handle,0,false);
i2c_master_write_byte(cmd_handle,cmd,false);
i2c_master_stop(cmd_handle);
int ret = i2c_master_cmd_begin(I2C_NUM_0, cmd_handle, 1000 / portTICK_RATE_MS);
#printf("cmd result %d \\n",ret);
if (ret == ESP_FAIL) {
printf("error %d",ret);
}
i2c_cmd_link_delete(cmd_handle);
}

static GFXINLINE void write_data(GDisplay \*g, uint8_t\* data, uint16_t length) {
cmd_handle = i2c_cmd_link_create();
i2c_master_start(cmd_handle);
i2c_master_write_byte(cmd_handle,I2C_OLED,true);
i2c_master_write_byte(cmd_handle,0x40,true);
i2c_master_write(cmd_handle,data,length,true);
i2c_master_stop(cmd_handle);
int ret = i2c_master_cmd_begin(I2C_NUM_0, cmd_handle, 1000 / portTICK_RATE_MS);
#printf("data result %d \\n\\n\\n\\n\\n",ret);
if (ret == ESP_FAIL) {
printf("error %d",ret);
}
i2c_cmd_link_delete(cmd_handle);
}

虽然代码并不多,可真的调试了一大上午TAT…

写点测试代码(hello_world_main.c)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#...  
#include "gfx.h"
void gfx_task(void \*pvParameters)
{
printf("it works? \\n");
gfxInit();
int width = gdispGetWidth();
int height = gdispGetHeight();

gdispDrawBox(10, 10, width / 2, height / 2, Black);
gdispFillArea(width / 2, height / 2, width / 2 - 10, height / 2 - 10, Black);
gdispDrawLine(5, 30, width - 50, height - 40, Red);
int i, j;
for (i = 5, j = 0; i < width && j < height; i += 7, j += i / 20)
gdispDrawPixel(i, j, Black);

gdispFlush();
while (TRUE)
{
gfxSleepMilliseconds(500);
}
}

别忘了启动task

1
2

xTaskCreate(&gfx_task, "gfx", 2048, 0, 5, 0);

结果

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×