u8g2移植前半部分基本一样,都是将u8g2的源码加入所在工程文件,随后删减部分文件和代码。不多赘述,本文主要说明移植需要的接口文件和移植过程中的事项。
可以参考这篇esp32 idf移植u8g2,采用软件spi:[002] [ESP32开发笔记] u8g2移植到esp32-idf
不过需要注意使用component创建u8g2的文件夹,参考这篇文章:
esp32 u8g2 idf移植
不过对于window用idf.py指令,window安装idf后,一般都会自动在桌面创建这两个快捷方式。
双击点开任意一个都行,使用window的命令行跳转至工程所在文件夹,再执行
idf.py create-component -C components/ u8g2
至于Kconfig我没设置,好像没什么影响。
然后再main文件下新建.c、.h文件
新建esp32_oled.c文件
#include "esp32_oled.h"
#include "stdlib.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "sys/unistd.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
static spi_device_handle_t spi;
static spi_bus_config_t buscfg={
.miso_io_num=-1,//MISO信号线,可复用为QSPI的D0
.mosi_io_num=PIN_OLED_DIN,//MOSI信号线,可复用为QSPI的D1
.sclk_io_num=PIN_OLED_CLK,//SCLK信号线
.quadwp_io_num=-1,//WP信号线,专用于QSPI的D2
.quadhd_io_num=-1,//HD信号线,专用于QSPI的D3
.max_transfer_sz=4094,//最大传输数据大小,单位字节,默认为4094
//.intr_flags,//中断指示位
};
void oled_spi_init(void)
{
esp_err_t ret;
esp_rom_gpio_pad_select_gpio(PIN_OLED_CS); // 选择一个GPIO
gpio_set_direction(PIN_OLED_CS, GPIO_MODE_OUTPUT);// 把这个GPIO作为输出
esp_rom_gpio_pad_select_gpio(PIN_OLED_DC); // 选择一个GPIO
gpio_set_direction(PIN_OLED_DC, GPIO_MODE_OUTPUT);// 把这个GPIO作为输出
esp_rom_gpio_pad_select_gpio(PIN_OLED_RES); // 选择一个GPIO
gpio_set_direction(PIN_OLED_RES, GPIO_MODE_OUTPUT);// 把这个GPIO作为输出
//对于ESP32 超过26Mhz会报错,C系列、S系列未知
spi_device_interface_config_t devcfg={
.clock_speed_hz =SPI_MASTER_FREQ_26M, // Clock out at 26 MHz,
.mode = 0, // SPI mode 0
.spics_io_num = -1,
.queue_size = 6, // 传输队列大小,决定了等待传输数据的数量
};
//Initialize the SPI bus
ret = spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);
// ESP_ERROR_CHECK(ret);
ret = spi_bus_add_device(SPI2_HOST, &devcfg, &spi);
// ESP_ERROR_CHECK(ret);
}
uint8_t u8x8_byte_hard_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
/* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */
spi_transaction_t spi_trans;
esp_err_t ret;
printf("msg:%d,arg_int:%d\r\n",msg,arg_int);
switch(msg){
case U8X8_MSG_BYTE_SEND: /*通过SPI发送arg_int个字节数据*/
{
memset(&spi_trans, 0, sizeof(spi_trans)); //Zero out the transaction
spi_trans.length=arg_int*8; //Len is in bytes, transaction length is in bits.
spi_trans.tx_buffer=arg_ptr; //Data
spi_trans.user=(void*)1; //D/C needs to be set to 1
ret=spi_device_polling_transmit(spi, &spi_trans); //Transmit!
assert(ret==ESP_OK);
}
break;
case U8X8_MSG_BYTE_INIT: /*初始化函数*/
// oled_spi_init();
break;
case U8X8_MSG_BYTE_SET_DC:
arg_int==1?OLED_DC_Set():OLED_DC_Clr();
// esp_rom_delay_us(1);
break;
case U8X8_MSG_BYTE_START_TRANSFER:
OLED_CS_Clr();
// esp_rom_delay_us(1);
break;
case U8X8_MSG_BYTE_END_TRANSFER:
OLED_CS_Set();
// esp_rom_delay_us(1);
break;
default:
return 0;
}
return 1;
}
uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
//采用硬件spi,部分分支可以忽略不写
switch (msg)
{
//Initialize SPI peripheral
case U8X8_MSG_GPIO_AND_DELAY_INIT:
break;
//Function which implements a delay, arg_int contains the amount of ms
case U8X8_MSG_DELAY_MILLI:
// vTaskDelay(pdMS_TO_TICKS(arg_int));
break;
//Function which delays 10us
case U8X8_MSG_DELAY_10MICRO:
// esp_rom_delay_us(10);
break;
// Function to define the logic level of the CS line
case U8X8_MSG_GPIO_CS:
// arg_int==1?OLED_CS_Set():OLED_CS_Clr();
break;
//Function to define the logic level of the Data/ Command line
case U8X8_MSG_GPIO_DC:
// arg_int==1?OLED_DC_Set():OLED_DC_Clr();
break;
//Function to define the logic level of the RESET line
case U8X8_MSG_GPIO_RESET:
break;
default:
return 0; //A message was received which is not implemented, return 0 to indicate an error
}
return 1;
}
void u8g2Init(u8g2_t *u8g2)
{
u8g2_Setup_ssd1306_128x64_noname_f(u8g2, U8G2_R0, u8x8_byte_hard_spi, u8x8_gpio_and_delay);
u8g2_InitDisplay(u8g2);
u8g2_SetPowerSave(u8g2, 0);
u8g2_ClearBuffer(u8g2);
}
新建esp32_oled.h文件
#ifndef ESP32_OLED_H_
#define ESP32_OLED_H_
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "u8g2.h"
#include "u8x8.h"
#include "stdlib.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
// GND
// VCC 3.3v
// D0 CLK
// D1 DIN
// RES RES
// DC DC
// CS CS
#define PIN_OLED_CLK 23
#define PIN_OLED_DIN 22
#define PIN_OLED_RES 19
#define PIN_OLED_DC 18
#define PIN_OLED_CS 5
#define OLED_CS_Clr() gpio_set_level(PIN_OLED_CS, 0)//CS
#define OLED_CS_Set() gpio_set_level(PIN_OLED_CS, 1)
#define OLED_REST_Clr() gpio_set_level(PIN_OLED_RES, 0)//RES
#define OLED_REST_Set() gpio_set_level(PIN_OLED_RES, 1)
#define OLED_DC_Clr() gpio_set_level(PIN_OLED_DC, 0)//DC
#define OLED_DC_Set() gpio_set_level(PIN_OLED_DC, 1)
void u8g2Init(u8g2_t *u8g2);
void oled_spi_init(void);
#endif /* ESP32_OLED_H_ */
此外,在main.c中初始化时,需先初始化spi,在初始u8g2,否则容易出现雪花屏,代码如下
//需要先初始化spi,否则可能出现会雪花屏
oled_spi_init();
//复位OLED
OLED_REST_Set();
vTaskDelay(50 / portTICK_PERIOD_MS);
OLED_REST_Clr();
vTaskDelay(5 / portTICK_PERIOD_MS);
OLED_REST_Set();
vTaskDelay(50 / portTICK_PERIOD_MS);
//初始化u8g2
u8g2_t u8g2;
u8g2Init(&u8g2);
这是esp_idf移植u8g2驱动oled的代码,硬件IIC和硬件SPI都有
https://gitee.com/zero-speed-of-light/esp_idf_u8g2_oled.git
移植的代码,包括硬件spi(4线)和硬件IIC:https://gitee.com/zero-speed-of-light/esp_idf_u8g2_oled.git