优化工程目录

This commit is contained in:
2026-02-18 20:08:58 +08:00
parent 118d4bf528
commit ee80965d58
67 changed files with 376 additions and 2210 deletions
-184
View File
@@ -1,184 +0,0 @@
#include "lcd.h"
static const char *TAG = "LCD";
/******************************************************************************
函数说明:设置起始和结束地址
入口数据:x1,x2 设置列的起始和结束地址
y1,y2 设置行的起始和结束地址
返回值: 无
******************************************************************************/
void LCD_Address_Set(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
#if USE_HORIZONTAL == 0
lcd_spi_reg(0x2a); // 列地址设置
lcd_spi_write16(x1);
lcd_spi_write16(x2);
lcd_spi_reg(0x2b); // 行地址设置
lcd_spi_write16(y1);
lcd_spi_write16(y2);
lcd_spi_reg(0x2c); // 储存器写
#elif USE_HORIZONTAL == 1
lcd_spi_reg(0x2a); // 列地址设置
lcd_spi_write16(x1);
lcd_spi_write16(x2);
lcd_spi_reg(0x2b); // 行地址设置
lcd_spi_write16(y1 + 80);
lcd_spi_write16(y2 + 80);
lcd_spi_reg(0x2c); // 储存器写
#elif USE_HORIZONTAL == 2
lcd_spi_reg(0x2a); // 列地址设置
lcd_spi_write16(x1);
lcd_spi_write16(x2);
lcd_spi_reg(0x2b); // 行地址设置
lcd_spi_write16(y1);
lcd_spi_write16(y2);
lcd_spi_reg(0x2c); // 储存器写
#elif USE_HORIZONTAL == 3
lcd_spi_reg(0x2a); // 列地址设置
lcd_spi_write16(x1 + 80);
lcd_spi_write16(x2 + 80);
lcd_spi_reg(0x2b); // 行地址设置
lcd_spi_write16(y1);
lcd_spi_write16(y2);
lcd_spi_reg(0x2c); // 储存器写
#endif
}
void LCD_Clear(uint16_t Color)
{
uint16_t i, j;
LCD_Address_Set(0, 0, LCD_WW - 1, LCD_HH - 1);
for (i = 0; i < LCD_WW; i++)
{
for (j = 0; j < LCD_HH; j++)
{
lcd_spi_write16(Color);
}
}
}
void lcd_init()
{
ESP_LOGI(TAG, "等待初始化LCD");
vTaskDelay(25); //
ESP_LOGI(TAG, "初始化LCD");
lcd_spi_reg(0x36);
if (USE_HORIZONTAL == 0)
lcd_spi_write8(0x00);
else if (USE_HORIZONTAL == 1)
lcd_spi_write8(0xC0);
else if (USE_HORIZONTAL == 2)
lcd_spi_write8(0x70);
else
lcd_spi_write8(0xA0);
lcd_spi_reg(0x3A);
lcd_spi_write8(0x05);
lcd_spi_reg(0xB2);
lcd_spi_write8(0x0C);
lcd_spi_write8(0x0C);
lcd_spi_write8(0x00);
lcd_spi_write8(0x33);
lcd_spi_write8(0x33);
lcd_spi_reg(0xB7);
lcd_spi_write8(0x35);
lcd_spi_reg(0xBB);
lcd_spi_write8(0x19);
lcd_spi_reg(0xC0);
lcd_spi_write8(0x2C);
lcd_spi_reg(0xC2);
lcd_spi_write8(0x01);
lcd_spi_reg(0xC3);
lcd_spi_write8(0x12);
lcd_spi_reg(0xC4);
lcd_spi_write8(0x20);
lcd_spi_reg(0xC6);
lcd_spi_write8(0x0F);
lcd_spi_reg(0xD0);
lcd_spi_write8(0xA4);
lcd_spi_write8(0xA1);
lcd_spi_reg(0xE0);
lcd_spi_write8(0xD0);
lcd_spi_write8(0x04);
lcd_spi_write8(0x0D);
lcd_spi_write8(0x11);
lcd_spi_write8(0x13);
lcd_spi_write8(0x2B);
lcd_spi_write8(0x3F);
lcd_spi_write8(0x54);
lcd_spi_write8(0x4C);
lcd_spi_write8(0x18);
lcd_spi_write8(0x0D);
lcd_spi_write8(0x0B);
lcd_spi_write8(0x1F);
lcd_spi_write8(0x23);
lcd_spi_reg(0xE1);
lcd_spi_write8(0xD0);
lcd_spi_write8(0x04);
lcd_spi_write8(0x0C);
lcd_spi_write8(0x11);
lcd_spi_write8(0x13);
lcd_spi_write8(0x2C);
lcd_spi_write8(0x3F);
lcd_spi_write8(0x44);
lcd_spi_write8(0x51);
lcd_spi_write8(0x2F);
lcd_spi_write8(0x1F);
lcd_spi_write8(0x1F);
lcd_spi_write8(0x20);
lcd_spi_write8(0x23);
lcd_spi_reg(0x21);
lcd_spi_reg(0x11);
vTaskDelay(12);
lcd_spi_reg(0x29);
ESP_LOGI(TAG, "初始化LCD完成");
LCD_Clear(0xffff);
}
void LCD_test()
{
uint16_t i, j, k , x=100,y=100;
lcd_spi_reg(0x2a); // 列地址设置
lcd_spi_write16(0);
lcd_spi_write16(x - 1);
lcd_spi_reg(0x2b); // 行地址设置
lcd_spi_write16(0);
lcd_spi_write16(y - 1);
lcd_spi_reg(0x2c); // 储存器写
for (i = 0; i < y; i++)
{
k = rand();
for (j = 0; j < x; j++)
{
lcd_spi_write16(k);
}
}
}
-167
View File
@@ -1,167 +0,0 @@
#include "spi.h"
static const char *TAG = "SPI_2";
spi_device_handle_t lcd_spi;
void spi_init()
{
ESP_LOGI(TAG, "配置GPIO");
// 1. 配置GPIO
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << LCD_DS), // LCD_DS
.mode = GPIO_MODE_OUTPUT, // 输出模式
.pull_up_en = GPIO_PULLUP_DISABLE, //
.pull_down_en = GPIO_PULLDOWN_DISABLE, //
.intr_type = GPIO_INTR_DISABLE // 禁用中断
};
// 2. 应用配置
gpio_config(&io_conf);
// 3. 设置初始电平
gpio_set_level(LCD_DS, 0); // 输出低电平
// 1. 配置 GPIO 驱动能力 (ESP32-C3 支持)
// gpio_set_drive_capability(VSPI_MISO, GPIO_DRIVE_CAP_3); // 最大驱动
gpio_set_drive_capability(VSPI_MOSI, GPIO_DRIVE_CAP_3);
gpio_set_drive_capability(VSPI_SCLK, GPIO_DRIVE_CAP_3);
ESP_LOGI(TAG, "配置GPIO完成");
ESP_LOGI(TAG,"初始化SPI IO总线");
esp_err_t ret;
// 1. SPI 总线配置
spi_bus_config_t buscfg = {
.miso_io_num = VSPI_MISO, // MISO 引脚
.mosi_io_num = VSPI_MOSI, // MOSI 引脚
.sclk_io_num = VSPI_SCLK, // 时钟引脚
.quadwp_io_num = -1, // 不使用 QWP
.quadhd_io_num = -1, // 不使用 QHD
.max_transfer_sz = 16, // 最大传输大小
.flags = 0,
.intr_flags = 0,
};
// 2. 初始化 SPI 总线
ret = spi_bus_initialize(SPI2_HOST, &buscfg,SPI_DMA_CH_AUTO );
if (ret != ESP_OK) {
ESP_LOGE(TAG, "SPI2 IO总线初始化失败");
return;
}
ESP_LOGI(TAG,"SPI IO总线初始化成功");
ESP_LOGI(TAG,"挂载设备片选IO");
spi_device_interface_config_t devcfg = {
.mode = 0, // SPI 模式 0
.clock_speed_hz = 40000000, //
.spics_io_num = LCD_CS,
.queue_size = 7, // 队列深度
.flags = SPI_DEVICE_NO_DUMMY, // 禁用 dummy 周期
.input_delay_ns = 0,
.pre_cb = NULL,
.post_cb = NULL,
};
ret = spi_bus_add_device(SPI2_HOST, &devcfg, &lcd_spi);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "挂载设备片选IO失败");
return;
}
}
// 高速数据传输函数
esp_err_t spi_transfer_fast(spi_device_handle_t spi, uint8_t *tx_data, uint8_t *rx_data, size_t len)
{
spi_transaction_t t = {
.flags = 0,
.cmd = 0,
.addr = 0,
.length = 8 * len,
.tx_buffer = tx_data,
.rx_buffer = rx_data,
};
// 使用轮询传输(小数据量更快)
return spi_device_polling_transmit(spi, &t);
}
// SPI 写数据
esp_err_t lcd_spi_write8(uint8_t data) {
// spi_transaction_t trans = {
// .length = 8, // 数据位数
// .tx_buffer = &data, // 发送缓冲区
// .rx_buffer = NULL, // 不接收
// };
// return spi_device_transmit(lcd_spi, &trans);
return spi_transfer_fast(lcd_spi,&data,NULL,1);
}
// SPI 写数据
esp_err_t lcd_spi_write16(uint16_t data) {
uint8_t tx_buf[2];
tx_buf[1] = data ;
tx_buf[0] = (data >> 8) ;
// spi_transaction_t trans = {
// .length = 16, // 数据位数
// .tx_buffer = tx_buf, // 发送缓冲区
// .rx_buffer = NULL, // 不接收
// };
// return spi_device_transmit(lcd_spi, &trans);
return spi_transfer_fast(lcd_spi,tx_buf,NULL,2);
}
// SPI 写命令
esp_err_t lcd_spi_reg(uint8_t data) {
esp_err_t err;
gpio_set_level(LCD_DS, 0);
err=lcd_spi_write8(data);
gpio_set_level(LCD_DS, 1);
if (err != ESP_OK) {
ESP_LOGE(TAG, "命令发送失败");
}
return err;
}
void lcd_ds_test()
{
esp_err_t err;
static uint8_t this_flag=0;
if(this_flag)
{
this_flag=0;
err=gpio_set_level(LCD_DS, 0);
}else{
this_flag=1;
err=gpio_set_level(LCD_DS, 1);
}
if (err != ESP_OK) {
ESP_LOGE(TAG, "GPIO失败");
}
}
-5
View File
@@ -1,5 +0,0 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
-10
View File
@@ -1,10 +0,0 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}
-37
View File
@@ -1,37 +0,0 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the convention is to give header files names that end with `.h'.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
-46
View File
@@ -1,46 +0,0 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into the executable file.
The source code of each library should be placed in a separate directory
("lib/your_library_name/[Code]").
For example, see the structure of the following example libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
Example contents of `src/main.c` using Foo and Bar:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
The PlatformIO Library Dependency Finder will find automatically dependent
libraries by scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html
-14
View File
@@ -1,14 +0,0 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:seeed_xiao_esp32c3]
platform = espressif32
board = seeed_xiao_esp32c3
framework = arduino
-18
View File
@@ -1,18 +0,0 @@
#include <Arduino.h>
#include "lcd.h"
// put function declarations here:
int myFunction(int, int);
void setup()
{
// put your setup code here, to run once:
lcd_init();
LCD_Clear(rand());
}
void loop()
{
// put your main code here, to run repeatedly:
LCD_Clear(rand());
}
-11
View File
@@ -1,11 +0,0 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
@@ -9,6 +9,7 @@
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"
@@ -19,6 +20,18 @@
#include "lcd.h"
TimerHandle_t periodic_timer = NULL;
// 定时器回调函数(在定时器服务任务中执行)
void periodic_timer_callback(TimerHandle_t xTimer)
{
//printf("每秒执行一次的函数\n");
// 在这里执行你的周期性任务
// 注意:此回调函数应尽快返回,避免阻塞定时器服务任务
lcd_one_second_task();
}
void app_main(void)
{
printf("Hello world!\n");
@@ -49,17 +62,36 @@ void app_main(void)
printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size());
printf("sizeof(int) ==%d\n",sizeof(int));
printf("sizeof(int) ==%d\n", sizeof(int));
spi_init();
lcd_init();
//LCD_Clear(0x1234);
// 配置一个每隔一秒运行一次的函数 用于计算fps等
// 创建周期性软件定时器
// 参数: 定时器名称, 周期(单位: Tick), 自动重载, 回调参数, 回调函数
periodic_timer = xTimerCreate(
"PeriodicTimer", // 定时器名称
pdMS_TO_TICKS(1000), // 周期:1000毫秒 (转换为Tick)
pdTRUE, // 自动重载 (pdTRUE为周期性,pdFALSE为单次)
(void *)0, // 传递给回调函数的参数
periodic_timer_callback // 回调函数
);
if (periodic_timer != NULL)
{
// 启动定时器 (0 ticks后启动)
xTimerStart(periodic_timer, 0);
}
else
{
printf("创建定时器失败!\n");
}
while (1)
{
LCD_Clear(rand());
lcd_clear_buf(rand());
lcd_send_full_buf();
vTaskDelay(1); // 必须让出CPU
}
}
+263
View File
@@ -0,0 +1,263 @@
#include "lcd.h"
static const char *TAG = "LCD";
// uint16_t dis_buff[LCD_WW][LCD_HH];
lcd_t lcd_main;
// SPI 写数据
esp_err_t lcd_spi_send_data_8(uint8_t data)
{
spi_transaction_t trans = {
.length = 8, // 数据位数
.flags = SPI_TRANS_USE_TXDATA, // 必须加这个标志
};
trans.tx_data[0] = (data);
esp_err_t err = spi_device_transmit(lcd_spi, &trans);
return err;
}
// SPI 写数据
esp_err_t lcd_spi_send_data_16(uint16_t data)
{
spi_transaction_t trans = {
.length = 16, // 数据位数
.flags = SPI_TRANS_USE_TXDATA, // 必须加这个标志
};
trans.tx_data[0] = (data >> 8);
trans.tx_data[1] = (data);
esp_err_t err = spi_device_transmit(lcd_spi, &trans);
return err;
}
esp_err_t lcd_spi_send_data_any(uint8_t *data, uint16_t len)
{
spi_transaction_t trans = {
.length = len * 8,
.tx_buffer = data,
};
esp_err_t err = spi_device_transmit(lcd_spi, &trans);
return err;
}
// SPI 写命令
void lcd_spi_send_cmd(uint8_t data)
{
esp_err_t err;
gpio_set_level(LCD_DS, 0);
err = lcd_spi_send_data_8(data);
gpio_set_level(LCD_DS, 1);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "命令发送失败:%x", err);
}
}
/******************************************************************************
函数说明:设置起始和结束地址
入口数据:x1,x2 设置列的起始和结束地址
y1,y2 设置行的起始和结束地址
返回值: 无
******************************************************************************/
void lcd_set_window(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
#if USE_HORIZONTAL == 0
lcd_spi_send_cmd(0x2a); // 列地址设置
lcd_spi_send_data_16(x1);
lcd_spi_send_data_16(x2);
lcd_spi_send_cmd(0x2b); // 行地址设置
lcd_spi_send_data_16(y1);
lcd_spi_send_data_16(y2);
lcd_spi_send_cmd(0x2c); // 储存器写
#elif USE_HORIZONTAL == 1
lcd_spi_send_cmd(0x2a); // 列地址设置
lcd_spi_send_data_16(x1);
lcd_spi_send_data_16(x2);
lcd_spi_send_cmd(0x2b); // 行地址设置
lcd_spi_send_data_16(y1 + 80);
lcd_spi_send_data_16(y2 + 80);
lcd_spi_send_cmd(0x2c); // 储存器写
#elif USE_HORIZONTAL == 2
lcd_spi_send_cmd(0x2a); // 列地址设置
lcd_spi_send_data_16(x1);
lcd_spi_send_data_16(x2);
lcd_spi_send_cmd(0x2b); // 行地址设置
lcd_spi_send_data_16(y1);
lcd_spi_send_data_16(y2);
lcd_spi_send_cmd(0x2c); // 储存器写
#elif USE_HORIZONTAL == 3
lcd_spi_send_cmd(0x2a); // 列地址设置
lcd_spi_send_data_16(x1 + 80);
lcd_spi_send_data_16(x2 + 80);
lcd_spi_send_cmd(0x2b); // 行地址设置
lcd_spi_send_data_16(y1);
lcd_spi_send_data_16(y2);
lcd_spi_send_cmd(0x2c); // 储存器写
#endif
}
void lcd_one_second_task()
{
lcd_main.fps=lcd_main.fps_count;
lcd_main.fps_count=0;
ESP_LOGI(TAG, "FPS:%d",lcd_main.fps);
}
void lcd_send_full_buf()
{
gpio_set_level(LCD_CS, 0);
lcd_set_window(0, 0, LCD_WW - 1, LCD_HH - 1);
// 分包发送 单次9600 分16次发送
spi_transaction_t trans = {
.length = 9600 * 8, // 数据位数
};
uint8_t *d_buf = (uint8_t *)(lcd_main.buf);
for (uint16_t i = 0; i < 16; i++)
{
// trans.length=9600*8;
trans.tx_buffer = d_buf + (i * 9600);
spi_device_transmit(lcd_spi, &trans);
}
gpio_set_level(LCD_CS, 1);
//发送成功 帧计数+1
lcd_main.fps_count+=1;
}
void lcd_clear_buf(uint16_t color)
{
for (uint32_t i = 0; i < (LCD_WW * LCD_HH); i++)
{
lcd_main.buf[i] = color;
}
}
void lcd_init()
{
ESP_LOGI(TAG, "配置GPIO");
// 初始化屏幕IO
// 配置GPIO
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << LCD_DS) | (1ULL << LCD_CS), // LCD_DS LCD_CS
.mode = GPIO_MODE_OUTPUT, // 输出模式
.pull_up_en = GPIO_PULLUP_DISABLE, //
.pull_down_en = GPIO_PULLDOWN_DISABLE, //
.intr_type = GPIO_INTR_DISABLE // 禁用中断
};
// 应用配置
gpio_config(&io_conf);
// 配置 GPIO 驱动能力 (ESP32-C3 支持)
// gpio_set_drive_capability(VSPI_MISO, GPIO_DRIVE_CAP_3); // 最大驱动
gpio_set_drive_capability(VSPI_MOSI, GPIO_DRIVE_CAP_3);
gpio_set_drive_capability(VSPI_SCLK, GPIO_DRIVE_CAP_3);
ESP_LOGI(TAG, "配置GPIO完成");
// 设置初始电平
gpio_set_level(LCD_DS, 0); // 输出低电平
gpio_set_level(LCD_CS, 0);
ESP_LOGI(TAG, "等待初始化LCD");
vTaskDelay(25); //
// uint8_t data_tmp[16];//数据缓存
ESP_LOGI(TAG, "初始化LCD");
lcd_spi_send_cmd(0x36);
if (USE_HORIZONTAL == 0)
lcd_spi_send_data_8(0x00);
else if (USE_HORIZONTAL == 1)
lcd_spi_send_data_8(0xC0);
else if (USE_HORIZONTAL == 2)
lcd_spi_send_data_8(0x70);
else
lcd_spi_send_data_8(0xA0);
lcd_spi_send_cmd(0x3A);
lcd_spi_send_data_8(0x05);
lcd_spi_send_cmd(0xB2);
lcd_spi_send_data_8(0x0C);
lcd_spi_send_data_8(0x0C);
lcd_spi_send_data_8(0x00);
lcd_spi_send_data_8(0x33);
lcd_spi_send_data_8(0x33);
lcd_spi_send_cmd(0xB7);
lcd_spi_send_data_8(0x35);
lcd_spi_send_cmd(0xBB);
lcd_spi_send_data_8(0x19);
lcd_spi_send_cmd(0xC0);
lcd_spi_send_data_8(0x2C);
lcd_spi_send_cmd(0xC2);
lcd_spi_send_data_8(0x01);
lcd_spi_send_cmd(0xC3);
lcd_spi_send_data_8(0x12);
lcd_spi_send_cmd(0xC4);
lcd_spi_send_data_8(0x20);
lcd_spi_send_cmd(0xC6);
lcd_spi_send_data_8(0x0F);
lcd_spi_send_cmd(0xD0);
lcd_spi_send_data_8(0xA4);
lcd_spi_send_data_8(0xA1);
lcd_spi_send_cmd(0xE0);
lcd_spi_send_data_8(0xD0);
lcd_spi_send_data_8(0x04);
lcd_spi_send_data_8(0x0D);
lcd_spi_send_data_8(0x11);
lcd_spi_send_data_8(0x13);
lcd_spi_send_data_8(0x2B);
lcd_spi_send_data_8(0x3F);
lcd_spi_send_data_8(0x54);
lcd_spi_send_data_8(0x4C);
lcd_spi_send_data_8(0x18);
lcd_spi_send_data_8(0x0D);
lcd_spi_send_data_8(0x0B);
lcd_spi_send_data_8(0x1F);
lcd_spi_send_data_8(0x23);
lcd_spi_send_cmd(0xE1);
lcd_spi_send_data_8(0xD0);
lcd_spi_send_data_8(0x04);
lcd_spi_send_data_8(0x0C);
lcd_spi_send_data_8(0x11);
lcd_spi_send_data_8(0x13);
lcd_spi_send_data_8(0x2C);
lcd_spi_send_data_8(0x3F);
lcd_spi_send_data_8(0x44);
lcd_spi_send_data_8(0x51);
lcd_spi_send_data_8(0x2F);
lcd_spi_send_data_8(0x1F);
lcd_spi_send_data_8(0x1F);
lcd_spi_send_data_8(0x20);
lcd_spi_send_data_8(0x23);
lcd_spi_send_cmd(0x21);
lcd_spi_send_cmd(0x11);
vTaskDelay(12);
lcd_spi_send_cmd(0x29);
lcd_clear_buf(0xffff);
gpio_set_level(LCD_CS, 1);
ESP_LOGI(TAG, "初始化LCD完成");
}
@@ -6,15 +6,28 @@
#include "esp_log.h"
#include "spi.h"
#define LCD_CS 7
#define LCD_DS 6
#define USE_HORIZONTAL 2 //设置横屏或者竖屏显示 0或1为竖屏 2或3为横屏
#define LCD_WW 320
#define LCD_HH 240
typedef struct{
uint16_t buf[LCD_WW*LCD_HH];
uint16_t fps_count;
uint16_t fps;
}lcd_t;
extern lcd_t lcd_main;
void LCD_Address_Set(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2);
void lcd_init();
void LCD_Clear(uint16_t Color);
void lcd_clear_buf(uint16_t Color);
void lcd_send_full_buf();
void lcd_one_second_task();
void LCD_test();
#endif
+60
View File
@@ -0,0 +1,60 @@
#include "spi.h"
#define SPI_HOST SPI2_HOST
static const char *TAG = "SPI_2";
spi_device_handle_t lcd_spi;
void spi_init()
{
ESP_LOGI(TAG, "初始化SPI IO总线");
esp_err_t ret;
// 1. SPI 总线配置
spi_bus_config_t buscfg = {
.miso_io_num = VSPI_MISO, // MISO 引脚
.mosi_io_num = VSPI_MOSI, // MOSI 引脚
.sclk_io_num = VSPI_SCLK, // 时钟引脚
.quadwp_io_num = -1, // 不使用 QWP
.quadhd_io_num = -1, // 不使用 QHD
.max_transfer_sz = 9600, // 最大传输大小
// .flags = 0,
// .intr_flags = 0,
};
// 2. 初始化 SPI 总线
ret = spi_bus_initialize(SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "IO总线初始化失败");
return;
}
ESP_LOGI(TAG, "SPI IO总线初始化成功");
ESP_LOGI(TAG, "SPI 设备配置");
spi_device_interface_config_t devcfg = {
.command_bits = 0, // 无命令位
.address_bits = 0, // 无地址位
.dummy_bits = 0,
.mode = 0, // SPI 模式 0
.clock_speed_hz = 80000000, //
.spics_io_num = -1,
.queue_size = 7, // 队列深度
.flags = SPI_DEVICE_NO_DUMMY, // 禁用 dummy 周期
.input_delay_ns = 0,
.pre_cb = NULL,
.post_cb = NULL,
};
ret = spi_bus_add_device(SPI_HOST, &devcfg, &lcd_spi);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "SPI 设备配置失败");
return;
}
}
@@ -12,21 +12,11 @@
#define VSPI_MOSI 3
#define VSPI_SCLK 2
#define LCD_CS 7
#define LCD_DS 6
void spi_init();
extern spi_device_handle_t lcd_spi;
// SPI 写数据
esp_err_t lcd_spi_write8(uint8_t data);
// SPI 写数据
esp_err_t lcd_spi_write16(uint16_t data);
// SPI 写命令
esp_err_t lcd_spi_reg(uint8_t data);
void lcd_ds_test();
#endif /* SPI_H */
-2
View File
@@ -1,2 +0,0 @@
CompileFlags:
Remove: [-f*, -m*]
@@ -1,13 +0,0 @@
ARG DOCKER_TAG=latest
FROM espressif/idf:${DOCKER_TAG}
ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8
RUN apt-get update -y && apt-get install udev -y
RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc
ENTRYPOINT [ "/opt/esp/entrypoint.sh" ]
CMD ["/bin/bash", "-c"]
@@ -1,19 +0,0 @@
{
"name": "ESP-IDF QEMU",
"build": {
"dockerfile": "Dockerfile"
},
"customizations": {
"vscode": {
"settings": {
"terminal.integrated.defaultProfile.linux": "bash",
"idf.gitPath": "/usr/bin/git"
},
"extensions": [
"espressif.esp-idf-extension",
"espressif.esp-idf-web"
]
}
},
"runArgs": ["--privileged"]
}
-78
View File
@@ -1,78 +0,0 @@
# macOS
.DS_Store
.AppleDouble
.LSOverride
# Directory metadata
.directory
# Temporary files
*~
*.swp
*.swo
*.bak
*.tmp
# Log files
*.log
# Build artifacts and directories
**/build/
build/
*.o
*.a
*.out
*.exe # For any host-side utilities compiled on Windows
# ESP-IDF specific build outputs
*.bin
*.elf
*.map
flasher_args.json # Generated in build directory
sdkconfig.old
sdkconfig
# ESP-IDF dependencies
# For older versions or manual component management
/components/.idf/
**/components/.idf/
# For modern ESP-IDF component manager
managed_components/
# If ESP-IDF tools are installed/referenced locally to the project
.espressif/
# CMake generated files
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
install_manifest.txt
CTestTestfile.cmake
# Python environment files
*.pyc
*.pyo
*.pyd
__pycache__/
*.egg-info/
dist/
# Virtual environment folders
venv/
.venv/
env/
# Language Servers
.clangd/
.ccls-cache/
compile_commands.json
# Windows specific
Thumbs.db
ehthumbs.db
Desktop.ini
# User-specific configuration files
*.user
*.workspace # General workspace files, can be from various tools
*.suo # Visual Studio Solution User Options
*.sln.docstates # Visual Studio
-19
View File
@@ -1,19 +0,0 @@
{
"configurations": [
{
"name": "ESP-IDF",
"compilerPath": "C:\\Espressif\\tools\\riscv32-esp-elf\\esp-13.2.0_20240530\\riscv32-esp-elf\\bin\\riscv32-esp-elf-gcc.exe",
"compileCommands": "${config:idf.buildPath}/compile_commands.json",
"includePath": [
"${workspaceFolder}/**"
],
"browse": {
"path": [
"${workspaceFolder}"
],
"limitSymbolsToIncludedHeaders": true
}
}
],
"version": 4
}
-10
View File
@@ -1,10 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "gdbtarget",
"request": "attach",
"name": "Eclipse CDT GDB Adapter"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"C_Cpp.intelliSenseEngine": "default",
"idf.openOcdConfigs": [
"board/esp32c3-builtin.cfg"
],
"idf.portWin": "detect",
"idf.currentSetup": "C:/Espressif/frameworks/esp-idf-v5.3.1/",
"idf.customExtraVars": {
"IDF_TARGET": "esp32c3"
},
"clangd.path": "C:\\Espressif\\tools\\esp-clang\\16.0.1-fe4f10a809\\esp-clang\\bin\\clangd.exe",
"clangd.arguments": [
"--background-index",
"--query-driver=**",
"--compile-commands-dir=c:\\Users\\wuwen\\Documents\\prj\\hantai_project\\code\\spi_lcd_driver\\build"
]
}
-7
View File
@@ -1,7 +0,0 @@
cmake_minimum_required(VERSION 3.16)
# 添加ESP_LCD组件依赖
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/peripherals/lcd)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(spi_lcd_driver)
-53
View File
@@ -1,53 +0,0 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | Linux |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | ----- |
# Hello World Example
Starts a FreeRTOS task to print "Hello World".
(See the README.md file in the upper level 'examples' directory for more information about examples.)
## How to use example
Follow detailed instructions provided specifically for this example.
Select the instructions depending on Espressif chip installed on your development board:
- [ESP32 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/index.html)
- [ESP32-S2 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/get-started/index.html)
## Example folder contents
The project **hello_world** contains one source file in C language [hello_world_main.c](main/hello_world_main.c). The file is located in folder [main](main).
ESP-IDF projects are built using CMake. The project build configuration is contained in `CMakeLists.txt` files that provide set of directives and instructions describing the project's source files and targets (executable, library, or both).
Below is short explanation of remaining files in the project folder.
```
├── CMakeLists.txt
├── pytest_hello_world.py Python script used for automated testing
├── main
│ ├── CMakeLists.txt
│ └── hello_world_main.c
└── README.md This is the file you are currently reading
```
For more information on structure and contents of ESP-IDF projects, please refer to Section [Build System](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html) of the ESP-IDF Programming Guide.
## Troubleshooting
* Program upload failure
* Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs.
* The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again.
## Technical support and feedback
Please use the following feedback channels:
* For technical queries, go to the [esp32.com](https://esp32.com/) forum
* For a feature request or bug report, create a [GitHub issue](https://github.com/espressif/esp-idf/issues)
We will get back to you as soon as possible.
-5
View File
@@ -1,5 +0,0 @@
idf_component_register(
SRCS "main.c" "lcd_driver.c"
INCLUDE_DIRS "."
REQUIRES driver esp_lcd heap
)
@@ -1,63 +0,0 @@
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "lcd_driver.h"
static const char *TAG = "MAIN";
void app_main(void)
{
ESP_LOGI(TAG, "ESP32-C3 SPI LCD驱动示例");
ESP_LOGI(TAG, "ESP-IDF版本: %s", esp_get_idf_version());
// 初始化LCD驱动结构
lcd_driver_t lcd = {
.spi_handle = NULL,
.panel_handle = NULL,
.cs_gpio = LCD_PIN_NUM_CS,
.dc_gpio = LCD_PIN_NUM_DC,
.rst_gpio = LCD_PIN_NUM_RST,
.bckl_gpio = LCD_PIN_NUM_BCKL,
.type = LCD_TYPE_ST7789,
};
// 初始化LCD
esp_err_t ret = lcd_driver_init(&lcd, LCD_TYPE_ST7789);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "LCD初始化失败!");
return;
}
// 清屏
ESP_LOGI(TAG, "清屏测试...");
lcd_clear(&lcd, COLOR_BLACK);
vTaskDelay(pdMS_TO_TICKS(500));
// 填充颜色测试
ESP_LOGI(TAG, "颜色填充测试...");
lcd_fill_rect(&lcd, 0, 0, LCD_H_RES/2, LCD_V_RES/2, COLOR_RED);
lcd_fill_rect(&lcd, LCD_H_RES/2, 0, LCD_H_RES/2, LCD_V_RES/2, COLOR_GREEN);
lcd_fill_rect(&lcd, 0, LCD_V_RES/2, LCD_H_RES/2, LCD_V_RES/2, COLOR_BLUE);
lcd_fill_rect(&lcd, LCD_H_RES/2, LCD_V_RES/2, LCD_H_RES/2, LCD_V_RES/2, COLOR_YELLOW);
vTaskDelay(pdMS_TO_TICKS(2000));
// 清屏
lcd_clear(&lcd, COLOR_BLACK);
// 绘制测试图案
ESP_LOGI(TAG, "绘制测试图案...");
for (int i = 0; i < 10; i++) {
lcd_fill_rect(&lcd, i * 20, i * 20, LCD_H_RES - i * 40, LCD_V_RES - i * 40,
(i % 2) ? COLOR_CYAN : COLOR_MAGENTA);
vTaskDelay(pdMS_TO_TICKS(200));
}
ESP_LOGI(TAG, "LCD测试完成!");
// 保持运行
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
-302
View File
@@ -1,302 +0,0 @@
#include "lcd_driver.h"
#include "esp_log.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_ops.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static const char *TAG = "LCD_DRIVER";
// ============ ST7789 初始化序列 ============
static const uint8_t st7789_init_cmds[] = {
0x11, 0, 120, // SLPOUT - 退出睡眠模式
0x3A, 1, 0, 0x55, // COLMOD - 像素格式: 16bit
0x36, 1, 0, 0x00, // MADCTL - 内存数据访问控制
0xB2, 5, 0, 0x0C, 0x0C, 0x00, 0x33, 0x33, // PORCTRL - 帧率控制
0xB7, 1, 0, 0x35, // GCTRL - 门控制
0xBB, 1, 0, 0x19, // VCOMS - VCOM电压
0xC0, 1, 0, 0x2C, // LCMCTRL - LCD控制
0xC2, 2, 0, 0x01, 0xFF, // VDVVRHEN - VDV和VRH命令使能
0xC3, 1, 0, 0x11, // VRHSET - VRH设置
0xC4, 1, 0, 0x20, // VDVS - VDV设置
0xC6, 1, 0, 0x0F, // FRCTRL2 - 帧率控制2
0xD0, 2, 0, 0xA4, 0xA1, // PWCTRL1 - 电源控制1
0xE0, 14, 0, 0xD0, 0x04, 0x0D, 0x11, 0x13, 0x2B, 0x3F, 0x54,
0x4C, 0x18, 0x0D, 0x0B, 0x1F, 0x23, // PVGAMCTRL - 正伽马
0xE1, 14, 0, 0xD0, 0x04, 0x0C, 0x11, 0x13, 0x2C, 0x3F, 0x44,
0x51, 0x2F, 0x1F, 0x1F, 0x20, 0x23, // NVGAMCTRL - 负伽马
0x21, 0, 0, // INVON - 显示反转开启
0x29, 0, 120, // DISPON - 显示开启
};
// ============ 初始化SPI总线 ============
static esp_err_t init_spi_bus(spi_host_device_t host, gpio_num_t mosi, gpio_num_t sclk)
{
spi_bus_config_t bus_cfg = {
.mosi_io_num = mosi,
.miso_io_num = -1, // LCD通常不需要MISO
.sclk_io_num = sclk,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = LCD_H_RES * LCD_BIT_PER_PIXEL / 8 * 8,
.flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_GPIO_PINS,
};
esp_err_t ret = spi_bus_initialize(host, &bus_cfg, SPI_DMA_CH_AUTO);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "SPI总线初始化失败: %s", esp_err_to_name(ret));
}
return ret;
}
// ============ 初始化SPI设备 ============
static esp_err_t init_spi_device(spi_host_device_t host, gpio_num_t cs,
spi_device_handle_t *spi_handle)
{
spi_device_interface_config_t dev_cfg = {
.clock_speed_hz = LCD_SPI_SPEED_HZ, // 80MHz
.mode = 0, // SPI Mode 0
.spics_io_num = cs,
.queue_size = 7,
.flags = SPI_DEVICE_NO_DUMMY,
.pre_cb = NULL,
.post_cb = NULL,
};
esp_err_t ret = spi_bus_add_device(host, &dev_cfg, spi_handle);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "SPI设备添加失败: %s", esp_err_to_name(ret));
}
return ret;
}
// ============ 创建LCD面板IO ============
static esp_err_t create_lcd_panel_io(spi_device_handle_t spi_handle, gpio_num_t dc_gpio,
esp_lcd_panel_io_handle_t *io_handle)
{
esp_lcd_panel_io_spi_config_t io_config = {
.dc_gpio_num = dc_gpio,
.cs_gpio_num = -1, // 已在SPI设备中配置
.pclk_hz = LCD_SPI_SPEED_HZ,
.trans_queue_depth = 10,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
.spi_mode = 0,
.flags = {
.dc_low_on_data = 0,
.octal_mode = 0,
.sio_mode = 0,
.lsb_first = 0,
.cs_high_active = 0,
},
};
esp_err_t ret = esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)spi_handle,
&io_config, io_handle);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "创建LCD面板IO失败: %s", esp_err_to_name(ret));
}
return ret;
}
// ============ 创建LCD面板 ============
static esp_err_t create_lcd_panel(esp_lcd_panel_io_handle_t io_handle,
esp_lcd_panel_handle_t *panel_handle,
lcd_type_t type)
{
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = -1, // 手动控制复位
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = LCD_BIT_PER_PIXEL,
};
esp_err_t ret;
switch (type) {
case LCD_TYPE_ST7789:
ret = esp_lcd_new_panel_st7789(io_handle, &panel_config, panel_handle);
break;
case LCD_TYPE_ILI9341:
ret = esp_lcd_new_panel_ili9341(io_handle, &panel_config, panel_handle);
break;
case LCD_TYPE_GC9A01:
ret = esp_lcd_new_panel_st7789(io_handle, &panel_config, panel_handle);
break;
default:
ret = ESP_ERR_INVALID_ARG;
}
if (ret != ESP_OK) {
ESP_LOGE(TAG, "创建LCD面板失败: %s", esp_err_to_name(ret));
}
return ret;
}
// ============ 驱动初始化 ============
esp_err_t lcd_driver_init(lcd_driver_t *lcd, lcd_type_t type)
{
esp_err_t ret;
// 初始化GPIO
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << lcd->dc_gpio) | (1ULL << lcd->rst_gpio) | (1ULL << lcd->bckl_gpio),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
};
gpio_config(&io_conf);
// 复位LCD
gpio_set_level(lcd->rst_gpio, 0);
vTaskDelay(pdMS_TO_TICKS(10));
gpio_set_level(lcd->rst_gpio, 1);
vTaskDelay(pdMS_TO_TICKS(120));
// 初始化SPI总线
ret = init_spi_bus(lcd->spi_handle ? LCD_SPI_HOST : LCD_SPI_HOST,
LCD_PIN_NUM_MOSI, LCD_PIN_NUM_SCLK);
if (ret != ESP_OK) return ret;
// 初始化SPI设备
spi_device_interface_config_t dev_cfg = {
.clock_speed_hz = LCD_SPI_SPEED_HZ,
.mode = 0,
.spics_io_num = lcd->cs_gpio,
.queue_size = 7,
.flags = SPI_DEVICE_NO_DUMMY,
};
ret = spi_bus_add_device(LCD_SPI_HOST, &dev_cfg, &lcd->spi_handle);
if (ret != ESP_OK) return ret;
// 创建面板IO
esp_lcd_panel_io_handle_t io_handle = NULL;
ret = create_lcd_panel_io(lcd->spi_handle, lcd->dc_gpio, &io_handle);
if (ret != ESP_OK) return ret;
// 创建面板
ret = create_lcd_panel(io_handle, &lcd->panel_handle, type);
if (ret != ESP_OK) return ret;
// 初始化面板
ret = esp_lcd_panel_reset(lcd->panel_handle);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "面板复位失败,继续执行...");
}
ret = esp_lcd_panel_init(lcd->panel_handle);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "面板初始化失败: %s", esp_err_to_name(ret));
return ret;
}
// 关闭睡眠模式
esp_lcd_panel_disp_on_off(lcd->panel_handle, true);
// 设置默认背光
lcd_set_backlight(lcd, 100);
ESP_LOGI(TAG, "LCD初始化完成,SPI速度: %d MHz", LCD_SPI_SPEED_HZ / 1000000);
return ESP_OK;
}
// ============ 驱动反初始化 ============
esp_err_t lcd_driver_deinit(lcd_driver_t *lcd)
{
if (lcd->panel_handle) {
esp_lcd_panel_del(lcd->panel_handle);
lcd->panel_handle = NULL;
}
if (lcd->spi_handle) {
spi_bus_remove_device(lcd->spi_handle);
lcd->spi_handle = NULL;
}
spi_bus_free(LCD_SPI_HOST);
ESP_LOGI(TAG, "LCD驱动已释放");
return ESP_OK;
}
// ============ 绘制单个像素 ============
esp_err_t lcd_draw_pixel(lcd_driver_t *lcd, uint16_t x, uint16_t y, uint16_t color)
{
if (x >= LCD_H_RES || y >= LCD_V_RES) {
return ESP_ERR_INVALID_ARG;
}
esp_lcd_panel_set_window(lcd->panel_handle, x, y, x, y);
uint16_t data = color;
esp_lcd_panel_draw_bitmap(lcd->panel_handle, x, y, x + 1, y + 1, &data);
return ESP_OK;
}
// ============ 填充矩形 ============
esp_err_t lcd_fill_rect(lcd_driver_t *lcd, uint16_t x, uint16_t y,
uint16_t w, uint16_t h, uint16_t color)
{
if (x >= LCD_H_RES || y >= LCD_V_RES) {
return ESP_ERR_INVALID_ARG;
}
// 限制宽高
if (x + w > LCD_H_RES) w = LCD_H_RES - x;
if (y + h > LCD_V_RES) h = LCD_V_RES - y;
uint16_t *buf = heap_caps_malloc(w * h * sizeof(uint16_t), MALLOC_CAP_DMA);
if (!buf) {
ESP_LOGE(TAG, "内存分配失败");
return ESP_ERR_NO_MEM;
}
// 填充缓冲区
for (int i = 0; i < w * h; i++) {
buf[i] = color;
}
esp_lcd_panel_set_window(lcd->panel_handle, x, y, x + w - 1, y + h - 1);
esp_lcd_panel_draw_bitmap(lcd->panel_handle, x, y, x + w, y + h, buf);
heap_caps_free(buf);
return ESP_OK;
}
// ============ 绘制图像 ============
esp_err_t lcd_draw_image(lcd_driver_t *lcd, uint16_t x, uint16_t y,
uint16_t w, uint16_t h, const uint16_t *data)
{
if (x >= LCD_H_RES || y >= LCD_V_RES || !data) {
return ESP_ERR_INVALID_ARG;
}
if (x + w > LCD_H_RES) w = LCD_H_RES - x;
if (y + h > LCD_V_RES) h = LCD_V_RES - y;
esp_lcd_panel_set_window(lcd->panel_handle, x, y, x + w - 1, y + h - 1);
esp_lcd_panel_draw_bitmap(lcd->panel_handle, x, y, x + w, y + h, data);
return ESP_OK;
}
// ============ 设置旋转 ============
esp_err_t lcd_set_rotation(lcd_driver_t *lcd, uint8_t rotation)
{
return esp_lcd_panel_set_gap(lcd->panel_handle, 0, 0);
}
// ============ 设置背光 ============
esp_err_t lcd_set_backlight(lcd_driver_t *lcd, uint8_t brightness)
{
if (brightness > 100) brightness = 100;
// 使用LED PWM控制背光
// 注意:ESP32-C3使用LEDC需要不同配置
#if CONFIG_IDF_TARGET_ESP32C3
// ESP32-C3的PWM配置
#endif
gpio_set_level(lcd->bckl_gpio, (brightness > 0) ? 1 : 0);
return ESP_OK;
}
// ============ 清屏 ============
esp_err_t lcd_clear(lcd_driver_t *lcd, uint16_t color)
{
return lcd_fill_rect(lcd, 0, 0, LCD_H_RES, LCD_V_RES, color);
}
-70
View File
@@ -1,70 +0,0 @@
#ifndef LCD_DRIVER_H
#define LCD_DRIVER_H
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_vendor.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "esp_err.h"
// ============ 引脚配置 (根据实际硬件修改) ============
#define LCD_PIN_NUM_MOSI 7 // SPI MOSI
#define LCD_PIN_NUM_SCLK 6 // SPI SCLK
#define LCD_PIN_NUM_CS 5 // 片选
#define LCD_PIN_NUM_DC 4 // 数据/命令选择
#define LCD_PIN_NUM_RST 3 // 复位
#define LCD_PIN_NUM_BCKL 2 // 背光控制
// ============ 屏幕参数 ============
#define LCD_H_RES 240 // 水平分辨率
#define LCD_V_RES 240 // 垂直分辨率
#define LCD_BIT_PER_PIXEL 16 // 16位色深 (RGB565)
// ============ SPI配置 ============
#define LCD_SPI_HOST SPI2_HOST
#define LCD_SPI_SPEED_HZ (80 * 1000 * 1000) // 80MHz
// ============ 屏幕类型 ============
typedef enum {
LCD_TYPE_ST7789,
LCD_TYPE_ILI9341,
LCD_TYPE_GC9A01
} lcd_type_t;
// ============ 驱动句柄 ============
typedef struct {
spi_device_handle_t spi_handle;
esp_lcd_panel_handle_t panel_handle;
gpio_num_t cs_gpio;
gpio_num_t dc_gpio;
gpio_num_t rst_gpio;
gpio_num_t bckl_gpio;
lcd_type_t type;
} lcd_driver_t;
// ============ 函数声明 ============
esp_err_t lcd_driver_init(lcd_driver_t *lcd, lcd_type_t type);
esp_err_t lcd_driver_deinit(lcd_driver_t *lcd);
esp_err_t lcd_draw_pixel(lcd_driver_t *lcd, uint16_t x, uint16_t y, uint16_t color);
esp_err_t lcd_fill_rect(lcd_driver_t *lcd, uint16_t x, uint16_t y,
uint16_t w, uint16_t h, uint16_t color);
esp_err_t lcd_draw_image(lcd_driver_t *lcd, uint16_t x, uint16_t y,
uint16_t w, uint16_t h, const uint16_t *data);
esp_err_t lcd_set_rotation(lcd_driver_t *lcd, uint8_t rotation);
esp_err_t lcd_set_backlight(lcd_driver_t *lcd, uint8_t brightness);
// ============ 颜色宏 ============
#define COLOR_BLACK 0x0000
#define COLOR_WHITE 0xFFFF
#define COLOR_RED 0xF800
#define COLOR_GREEN 0x07E0
#define COLOR_BLUE 0x001F
#define COLOR_YELLOW 0xFFE0
#define COLOR_CYAN 0x07FF
#define COLOR_MAGENTA 0xF81F
#define COLOR_GRAY 0x8410
// RGB565转换宏
#define RGB565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
#endif // LCD_DRIVER_H
-53
View File
@@ -1,53 +0,0 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import hashlib
import logging
from typing import Callable
import pytest
from pytest_embedded_idf.dut import IdfDut
from pytest_embedded_qemu.app import QemuApp
from pytest_embedded_qemu.dut import QemuDut
@pytest.mark.supported_targets
@pytest.mark.preview_targets
@pytest.mark.generic
def test_hello_world(
dut: IdfDut, log_minimum_free_heap_size: Callable[..., None]
) -> None:
dut.expect('Hello world!')
log_minimum_free_heap_size()
@pytest.mark.linux
@pytest.mark.host_test
def test_hello_world_linux(dut: IdfDut) -> None:
dut.expect('Hello world!')
def verify_elf_sha256_embedding(app: QemuApp, sha256_reported: str) -> None:
sha256 = hashlib.sha256()
with open(app.elf_file, 'rb') as f:
sha256.update(f.read())
sha256_expected = sha256.hexdigest()
logging.info(f'ELF file SHA256: {sha256_expected}')
logging.info(f'ELF file SHA256 (reported by the app): {sha256_reported}')
# the app reports only the first several hex characters of the SHA256, check that they match
if not sha256_expected.startswith(sha256_reported):
raise ValueError('ELF file SHA256 mismatch')
@pytest.mark.esp32 # we only support qemu on esp32 for now
@pytest.mark.host_test
@pytest.mark.qemu
def test_hello_world_host(app: QemuApp, dut: QemuDut) -> None:
sha256_reported = (
dut.expect(r'ELF file SHA256:\s+([a-f0-9]+)').group(1).decode('utf-8')
)
verify_elf_sha256_embedding(app, sha256_reported)
dut.expect('Hello world!')
View File
-241
View File
@@ -1,241 +0,0 @@
#include "lcd.h"
#include <SPI.h>
SPIClass * vspi = NULL;
/******************************************************************************
函数说明:LCD写入命令
入口数据:dat 写入的命令
返回值: 无
******************************************************************************/
void LCD_WR_REG(uint8_t dat)
{
digitalWrite(LCD_DS,0);//写命令
vspi->transfer(dat);
digitalWrite(LCD_DS,1);//写数据
}
/******************************************************************************
函数说明:设置起始和结束地址
入口数据:x1,x2 设置列的起始和结束地址
y1,y2 设置行的起始和结束地址
返回值: 无
******************************************************************************/
void LCD_Address_Set(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
{
#if USE_HORIZONTAL==0
LCD_WR_REG(0x2a);//列地址设置
vspi->transfer16(x1);
vspi->transfer16(x2);
LCD_WR_REG(0x2b);//行地址设置
vspi->transfer16(y1);
vspi->transfer16(y2);
LCD_WR_REG(0x2c);//储存器写
#elif USE_HORIZONTAL==1
LCD_WR_REG(0x2a);//列地址设置
vspi->transfer16(x1);
vspi->transfer16(x2);
LCD_WR_REG(0x2b);//行地址设置
vspi->transfer16(y1+80);
vspi->transfer16(y2+80);
LCD_WR_REG(0x2c);//储存器写
#elif USE_HORIZONTAL==2
LCD_WR_REG(0x2a);//列地址设置
vspi->transfer16(x1);
vspi->transfer16(x2);
LCD_WR_REG(0x2b);//行地址设置
vspi->transfer16(y1);
vspi->transfer16(y2);
LCD_WR_REG(0x2c);//储存器写
#elif USE_HORIZONTAL==3
LCD_WR_REG(0x2a);//列地址设置
vspi->transfer16(x1+80);
vspi->transfer16(x2+80);
LCD_WR_REG(0x2b);//行地址设置
vspi->transfer16(y1);
vspi->transfer16(y2);
LCD_WR_REG(0x2c);//储存器写
#endif
}
void LCD_fillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color)
{
LCD_Address_Set(x,y,width+x-1,height+y-1);
for(uint16_t i=0;i<height;i++)
{
for (uint16_t j=0;j<width;j++)
{
vspi->transfer16(color);
//delay(100);
}
}
}
/******************************************************************************
函数说明:LCD清屏函数
入口数据:无
返回值: 无
******************************************************************************/
void LCD_Clear(uint16_t Color)
{
uint16_t i,j;
LCD_Address_Set(0,0,LCD_W-1,LCD_H-1);
for(i=0;i<LCD_W;i++)
{
for (j=0;j<LCD_H;j++)
{
vspi->transfer16(Color);
}
}
}
void LCD_Clear_Rand()
{
uint16_t i,j;
LCD_Address_Set(0,0,LCD_W-1,LCD_H-1);
for(i=0;i<LCD_W;i++)
{
for (j=0;j<LCD_H;j++)
{
vspi->transfer16(rand());
}
}
}
unsigned int rgb555torgb565(unsigned int c)
{
c=c&0x7fff;
unsigned int r=c>>10;
c=c&0x03ff;
unsigned int g=c>>5;
c=c&0x001f;
unsigned int b=c;
unsigned int output=0;
g=g*2;
output= (r<<11)|(g<<5)|(b);
return output;
}
void lcd_init()
{
pinMode(LCD_SDA, OUTPUT);
pinMode(LCD_SCL, OUTPUT);
pinMode(LCD_CS, OUTPUT);
pinMode(LCD_DS, OUTPUT);
digitalWrite(LCD_SDA,0);
digitalWrite(LCD_SCL,0);
digitalWrite(LCD_CS,0);
digitalWrite(LCD_DS,0);
vspi = new SPIClass(VSPI);
vspi->begin(LCD_SCL, 0, LCD_SDA, LCD_CS);
vspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
pinMode(vspi->pinSS(), OUTPUT); //HSPI SS
digitalWrite(vspi->pinSS(), LOW); //pull SS slow to prep other end for transfer
//************* Start Initial Sequence **********//
//delay(120);
//LCD_WR_REG(0x01);
//上电后硬件会自己复位
delay(220);
LCD_WR_REG(0x36);
if(USE_HORIZONTAL==0)vspi->transfer(0x00);
else if(USE_HORIZONTAL==1)vspi->transfer(0xC0);
else if(USE_HORIZONTAL==2)vspi->transfer(0x70);
else vspi->transfer(0xA0);
LCD_WR_REG(0x3A);
vspi->transfer(0x05);
LCD_WR_REG(0xB2);
vspi->transfer(0x0C);
vspi->transfer(0x0C);
vspi->transfer(0x00);
vspi->transfer(0x33);
vspi->transfer(0x33);
LCD_WR_REG(0xB7);
vspi->transfer(0x35);
LCD_WR_REG(0xBB);
vspi->transfer(0x19);
LCD_WR_REG(0xC0);
vspi->transfer(0x2C);
LCD_WR_REG(0xC2);
vspi->transfer(0x01);
LCD_WR_REG(0xC3);
vspi->transfer(0x12);
LCD_WR_REG(0xC4);
vspi->transfer(0x20);
LCD_WR_REG(0xC6);
vspi->transfer(0x0F);
LCD_WR_REG(0xD0);
vspi->transfer(0xA4);
vspi->transfer(0xA1);
LCD_WR_REG(0xE0);
vspi->transfer(0xD0);
vspi->transfer(0x04);
vspi->transfer(0x0D);
vspi->transfer(0x11);
vspi->transfer(0x13);
vspi->transfer(0x2B);
vspi->transfer(0x3F);
vspi->transfer(0x54);
vspi->transfer(0x4C);
vspi->transfer(0x18);
vspi->transfer(0x0D);
vspi->transfer(0x0B);
vspi->transfer(0x1F);
vspi->transfer(0x23);
LCD_WR_REG(0xE1);
vspi->transfer(0xD0);
vspi->transfer(0x04);
vspi->transfer(0x0C);
vspi->transfer(0x11);
vspi->transfer(0x13);
vspi->transfer(0x2C);
vspi->transfer(0x3F);
vspi->transfer(0x44);
vspi->transfer(0x51);
vspi->transfer(0x2F);
vspi->transfer(0x1F);
vspi->transfer(0x1F);
vspi->transfer(0x20);
vspi->transfer(0x23);
LCD_WR_REG(0x21);
LCD_WR_REG(0x11);
delay(120);
LCD_WR_REG(0x29);
}
-33
View File
@@ -1,33 +0,0 @@
#ifndef LCD_H
#define LCD_H
#include <arduino.h>
//硬件spi貌似接错线了
#define LCD_SDA 3
#define LCD_SCL 2
#define LCD_CS 7
#define LCD_DS 6
#define USE_HORIZONTAL 2 //设置横屏或者竖屏显示 0或1为竖屏 2或3为横屏
#define LCD_W 320
#define LCD_H 240
#define OLED_CMD 0 //写命令
#define OLED_DATA 1 //写数据
#define VSPI FSPI
static const long spiClk = 80000000; // 80 MHz
void lcd_init();
void LCD_Clear(uint16_t Color);
void LCD_fillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color);
#endif
-2
View File
@@ -1,2 +0,0 @@
CompileFlags:
Remove: [-f*, -m*]
-16
View File
@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<storageModule moduleId="org.eclipse.cdt.core.settings">
<cconfiguration id="org.eclipse.cdt.core.default.config.395313844">
<storageModule buildSystemId="org.eclipse.cdt.core.defaultConfigDataProvider" id="org.eclipse.cdt.core.default.config.395313844" moduleId="org.eclipse.cdt.core.settings" name="Configuration">
<externalSettings/>
<extensions/>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
</cconfiguration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.pathentry">
<pathentry excluding="**/CMakeFiles/**" kind="out" path="build"/>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
</cproject>
-13
View File
@@ -1,13 +0,0 @@
ARG DOCKER_TAG=latest
FROM espressif/idf:${DOCKER_TAG}
ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8
RUN apt-get update -y && apt-get install udev -y
RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc
ENTRYPOINT [ "/opt/esp/entrypoint.sh" ]
CMD ["/bin/bash", "-c"]
@@ -1,19 +0,0 @@
{
"name": "ESP-IDF QEMU",
"build": {
"dockerfile": "Dockerfile"
},
"customizations": {
"vscode": {
"settings": {
"terminal.integrated.defaultProfile.linux": "bash",
"idf.gitPath": "/usr/bin/git"
},
"extensions": [
"espressif.esp-idf-extension",
"espressif.esp-idf-web"
]
}
},
"runArgs": ["--privileged"]
}
-78
View File
@@ -1,78 +0,0 @@
# macOS
.DS_Store
.AppleDouble
.LSOverride
# Directory metadata
.directory
# Temporary files
*~
*.swp
*.swo
*.bak
*.tmp
# Log files
*.log
# Build artifacts and directories
**/build/
build/
*.o
*.a
*.out
*.exe # For any host-side utilities compiled on Windows
# ESP-IDF specific build outputs
*.bin
*.elf
*.map
flasher_args.json # Generated in build directory
sdkconfig.old
sdkconfig
# ESP-IDF dependencies
# For older versions or manual component management
/components/.idf/
**/components/.idf/
# For modern ESP-IDF component manager
managed_components/
# If ESP-IDF tools are installed/referenced locally to the project
.espressif/
# CMake generated files
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
install_manifest.txt
CTestTestfile.cmake
# Python environment files
*.pyc
*.pyo
*.pyd
__pycache__/
*.egg-info/
dist/
# Virtual environment folders
venv/
.venv/
env/
# Language Servers
.clangd/
.ccls-cache/
compile_commands.json
# Windows specific
Thumbs.db
ehthumbs.db
Desktop.ini
# User-specific configuration files
*.user
*.workspace # General workspace files, can be from various tools
*.suo # Visual Studio Solution User Options
*.sln.docstates # Visual Studio
-20
View File
@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>espidfcode</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.cdt.core.cBuilder</name>
<triggers>clean,full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.cdt.core.cnature</nature>
<nature>org.eclipse.cdt.core.ccnature</nature>
<nature>org.eclipse.cdt.cmake.core.cmakeNature</nature>
</natures>
</projectDescription>
-19
View File
@@ -1,19 +0,0 @@
{
"configurations": [
{
"name": "ESP-IDF",
"compilerPath": "C:\\Espressif\\tools\\xtensa-esp-elf\\esp-13.2.0_20240530\\xtensa-esp-elf\\bin\\xtensa-esp32-elf-gcc.exe",
"compileCommands": "${config:idf.buildPath}/compile_commands.json",
"includePath": [
"${workspaceFolder}/**"
],
"browse": {
"path": [
"${workspaceFolder}"
],
"limitSymbolsToIncludedHeaders": true
}
}
],
"version": 4
}
-10
View File
@@ -1,10 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "gdbtarget",
"request": "attach",
"name": "Eclipse CDT GDB Adapter"
}
]
}
-5
View File
@@ -1,5 +0,0 @@
{
"idf.currentSetup": "C:/Espressif/frameworks/esp-idf-v5.3.1/",
"idf.flashType": "UART",
"idf.portWin": "COM3"
}
-6
View File
@@ -1,6 +0,0 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(espidfcode)
-53
View File
@@ -1,53 +0,0 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | Linux |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | ----- |
# Hello World Example
Starts a FreeRTOS task to print "Hello World".
(See the README.md file in the upper level 'examples' directory for more information about examples.)
## How to use example
Follow detailed instructions provided specifically for this example.
Select the instructions depending on Espressif chip installed on your development board:
- [ESP32 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/index.html)
- [ESP32-S2 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/get-started/index.html)
## Example folder contents
The project **hello_world** contains one source file in C language [hello_world_main.c](main/hello_world_main.c). The file is located in folder [main](main).
ESP-IDF projects are built using CMake. The project build configuration is contained in `CMakeLists.txt` files that provide set of directives and instructions describing the project's source files and targets (executable, library, or both).
Below is short explanation of remaining files in the project folder.
```
├── CMakeLists.txt
├── pytest_hello_world.py Python script used for automated testing
├── main
│ ├── CMakeLists.txt
│ └── hello_world_main.c
└── README.md This is the file you are currently reading
```
For more information on structure and contents of ESP-IDF projects, please refer to Section [Build System](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html) of the ESP-IDF Programming Guide.
## Troubleshooting
* Program upload failure
* Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs.
* The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again.
## Technical support and feedback
Please use the following feedback channels:
* For technical queries, go to the [esp32.com](https://esp32.com/) forum
* For a feature request or bug report, create a [GitHub issue](https://github.com/espressif/esp-idf/issues)
We will get back to you as soon as possible.
-6
View File
@@ -1,6 +0,0 @@
# 收集当前目录下所有 .c 文件
file(GLOB_RECURSE SRC_LIST "*.c")
idf_component_register(SRCS ${SRC_LIST}
PRIV_REQUIRES spi_flash esp_driver_spi esp_driver_gpio
INCLUDE_DIRS "")
-155
View File
@@ -1,155 +0,0 @@
#include "lcd.h"
static const char *TAG = "LCD";
/******************************************************************************
函数说明:设置起始和结束地址
入口数据:x1,x2 设置列的起始和结束地址
y1,y2 设置行的起始和结束地址
返回值: 无
******************************************************************************/
void LCD_Address_Set(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
{
#if USE_HORIZONTAL==0
lcd_spi_reg(0x2a);//列地址设置
lcd_spi_write8(x1);
lcd_spi_write8(x2);
lcd_spi_reg(0x2b);//行地址设置
lcd_spi_write8(y1);
lcd_spi_write8(y2);
lcd_spi_reg(0x2c);//储存器写
#elif USE_HORIZONTAL==1
lcd_spi_reg(0x2a);//列地址设置
lcd_spi_write8(x1);
lcd_spi_write8(x2);
lcd_spi_reg(0x2b);//行地址设置
lcd_spi_write8(y1+80);
lcd_spi_write8(y2+80);
lcd_spi_reg(0x2c);//储存器写
#elif USE_HORIZONTAL==2
lcd_spi_reg(0x2a);//列地址设置
lcd_spi_write8(x1);
lcd_spi_write8(x2);
lcd_spi_reg(0x2b);//行地址设置
lcd_spi_write8(y1);
lcd_spi_write8(y2);
lcd_spi_reg(0x2c);//储存器写
#elif USE_HORIZONTAL==3
lcd_spi_reg(0x2a);//列地址设置
lcd_spi_write8(x1+80);
lcd_spi_write8(x2+80);
lcd_spi_reg(0x2b);//行地址设置
lcd_spi_write8(y1);
lcd_spi_write8(y2);
lcd_spi_reg(0x2c);//储存器写
#endif
}
void lcd_init(){
ESP_LOGI(TAG,"等待初始化LCD");
vTaskDelay(25); //
ESP_LOGI(TAG,"初始化LCD");
lcd_spi_reg(0x36);
if(USE_HORIZONTAL==0)lcd_spi_write8(0x00);
else if(USE_HORIZONTAL==1)lcd_spi_write8(0xC0);
else if(USE_HORIZONTAL==2)lcd_spi_write8(0x70);
else lcd_spi_write8(0xA0);
lcd_spi_reg(0x3A);
lcd_spi_write8(0x05);
lcd_spi_reg(0xB2);
lcd_spi_write8(0x0C);
lcd_spi_write8(0x0C);
lcd_spi_write8(0x00);
lcd_spi_write8(0x33);
lcd_spi_write8(0x33);
lcd_spi_reg(0xB7);
lcd_spi_write8(0x35);
lcd_spi_reg(0xBB);
lcd_spi_write8(0x19);
lcd_spi_reg(0xC0);
lcd_spi_write8(0x2C);
lcd_spi_reg(0xC2);
lcd_spi_write8(0x01);
lcd_spi_reg(0xC3);
lcd_spi_write8(0x12);
lcd_spi_reg(0xC4);
lcd_spi_write8(0x20);
lcd_spi_reg(0xC6);
lcd_spi_write8(0x0F);
lcd_spi_reg(0xD0);
lcd_spi_write8(0xA4);
lcd_spi_write8(0xA1);
lcd_spi_reg(0xE0);
lcd_spi_write8(0xD0);
lcd_spi_write8(0x04);
lcd_spi_write8(0x0D);
lcd_spi_write8(0x11);
lcd_spi_write8(0x13);
lcd_spi_write8(0x2B);
lcd_spi_write8(0x3F);
lcd_spi_write8(0x54);
lcd_spi_write8(0x4C);
lcd_spi_write8(0x18);
lcd_spi_write8(0x0D);
lcd_spi_write8(0x0B);
lcd_spi_write8(0x1F);
lcd_spi_write8(0x23);
lcd_spi_reg(0xE1);
lcd_spi_write8(0xD0);
lcd_spi_write8(0x04);
lcd_spi_write8(0x0C);
lcd_spi_write8(0x11);
lcd_spi_write8(0x13);
lcd_spi_write8(0x2C);
lcd_spi_write8(0x3F);
lcd_spi_write8(0x44);
lcd_spi_write8(0x51);
lcd_spi_write8(0x2F);
lcd_spi_write8(0x1F);
lcd_spi_write8(0x1F);
lcd_spi_write8(0x20);
lcd_spi_write8(0x23);
lcd_spi_reg(0x21);
lcd_spi_reg(0x11);
vTaskDelay(12);
lcd_spi_reg(0x29);
ESP_LOGI(TAG,"初始化LCD完成");
}
void LCD_Clear(uint16_t Color)
{
uint16_t i,j;
LCD_Address_Set(0,0,LCD_WW-1,LCD_HH-1);
for(i=0;i<LCD_WW;i++)
{
for (j=0;j<LCD_HH;j++)
{
lcd_spi_write16(Color);
}
}
}
-18
View File
@@ -1,18 +0,0 @@
#ifndef LCD_H
#define LCD_H
#include <stdio.h>
#include <inttypes.h>
#include "esp_log.h"
#include "spi.h"
#define USE_HORIZONTAL 0 //设置横屏或者竖屏显示 0或1为竖屏 2或3为横屏
#define LCD_WW 240
#define LCD_HH 320
void LCD_Address_Set(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2);
void lcd_init();
void LCD_Clear(uint16_t Color);
#endif
-142
View File
@@ -1,142 +0,0 @@
#include "spi.h"
static const char *TAG = "SPI_2";
spi_device_handle_t lcd_spi;
void spi_init()
{
ESP_LOGI(TAG, "配置GPIO");
// 1. 配置GPIO
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << LCD_DS), // LCD_DS
.mode = GPIO_MODE_OUTPUT, // 输出模式
.pull_up_en = GPIO_PULLUP_DISABLE, //
.pull_down_en = GPIO_PULLDOWN_DISABLE, //
.intr_type = GPIO_INTR_DISABLE // 禁用中断
};
// 2. 应用配置
gpio_config(&io_conf);
// io_conf.pin_bit_mask=LCD_CS;
// gpio_config(&io_conf);
// io_conf.pin_bit_mask=VSPI_SCLK;
// gpio_config(&io_conf);
// io_conf.pin_bit_mask=VSPI_MOSI;
// gpio_config(&io_conf);
// 3. 设置初始电平
gpio_set_level(LCD_DS, 0); // 输出低电平
// gpio_set_level(LCD_CS,0);
// gpio_set_level(VSPI_SCLK,0);
// gpio_set_level(VSPI_MOSI,0);
ESP_LOGI(TAG, "配置GPIO完成");
ESP_LOGI(TAG,"初始化SPI IO总线");
esp_err_t ret;
// 1. SPI 总线配置
spi_bus_config_t buscfg = {
.miso_io_num = VSPI_MISO, // MISO 引脚
.mosi_io_num = VSPI_MOSI, // MOSI 引脚
.sclk_io_num = VSPI_SCLK, // 时钟引脚
.quadwp_io_num = -1, // 不使用 QWP
.quadhd_io_num = -1, // 不使用 QHD
.max_transfer_sz = 4096, // 最大传输大小
};
// 2. 初始化 SPI 总线
ret = spi_bus_initialize(SPI2_HOST, &buscfg,SPI_DMA_DISABLED );
if (ret != ESP_OK) {
ESP_LOGE(TAG, "SPI2 IO总线初始化失败");
return;
}
ESP_LOGI(TAG,"SPI IO总线初始化成功");
ESP_LOGI(TAG,"挂载设备片选IO");
spi_device_interface_config_t devcfg = {
.mode = 0, // SPI 模式 0
.clock_speed_hz = 40 * 1000 * 1000, //
.spics_io_num = LCD_CS,
.queue_size = 7, // 队列深度
.flags = 0, // 可选标志
};
ret = spi_bus_add_device(SPI2_HOST, &devcfg, &lcd_spi);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "挂载设备片选IO失败");
return;
}
}
// SPI 写数据
esp_err_t lcd_spi_write8(uint8_t data) {
spi_transaction_t trans = {
.length = 8, // 数据位数
.tx_buffer = &data, // 发送缓冲区
.rx_buffer = NULL, // 不接收
};
return spi_device_transmit(lcd_spi, &trans);
}
// SPI 写数据
esp_err_t lcd_spi_write16(uint16_t data) {
spi_transaction_t trans = {
.length = 16, // 数据位数
.tx_buffer = &data, // 发送缓冲区
.rx_buffer = NULL, // 不接收
};
return spi_device_transmit(lcd_spi, &trans);
}
// SPI 写命令
esp_err_t lcd_spi_reg(uint8_t data) {
esp_err_t err;
gpio_set_level(LCD_DS, 0);
err=lcd_spi_write8(data);
gpio_set_level(LCD_DS, 1);
if (err != ESP_OK) {
ESP_LOGE(TAG, "命令发送失败");
}
return err;
}
void lcd_ds_test()
{
esp_err_t err;
static uint8_t this_flag=0;
if(this_flag)
{
this_flag=0;
err=gpio_set_level(LCD_DS, 0);
}else{
this_flag=1;
err=gpio_set_level(LCD_DS, 1);
}
if (err != ESP_OK) {
ESP_LOGE(TAG, "GPIO失败");
}
}
-32
View File
@@ -1,32 +0,0 @@
#ifndef SPI_H
#define SPI_H
#include <stdio.h>
#include <inttypes.h>
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_log.h"
#include "esp_system.h"
#define VSPI_MISO -1 //接收引脚不使用,仅发送
#define VSPI_MOSI 3
#define VSPI_SCLK 2
#define LCD_CS 7
#define LCD_DS 6
void spi_init();
// SPI 写数据
esp_err_t lcd_spi_write8(uint8_t data);
// SPI 写数据
esp_err_t lcd_spi_write16(uint16_t data);
// SPI 写命令
esp_err_t lcd_spi_reg(uint8_t data);
void lcd_ds_test();
#endif /* SPI_H */
-66
View File
@@ -1,66 +0,0 @@
/*
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"
#include "esp_log.h"
#include "spi.h"
#include "lcd.h"
static const char *TAG = "SYS";
void app_main(void)
{
ESP_LOGI(TAG,"Hello world!\n");
/* Print chip information */
esp_chip_info_t chip_info;
uint32_t flash_size;
esp_chip_info(&chip_info);
ESP_LOGI(TAG,"This is %s chip with %d CPU core(s), %s%s%s%s, ",
CONFIG_IDF_TARGET,
chip_info.cores,
(chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "",
(chip_info.features & CHIP_FEATURE_BT) ? "BT" : "",
(chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "",
(chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : "");
unsigned major_rev = chip_info.revision / 100;
unsigned minor_rev = chip_info.revision % 100;
ESP_LOGI(TAG,"silicon revision v%d.%d, ", major_rev, minor_rev);
if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) {
ESP_LOGE(TAG,"Get flash size failed");
return;
}
ESP_LOGI(TAG,"%" PRIu32 "MB %s flash\n", flash_size / (uint32_t)(1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
ESP_LOGI(TAG,"Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size());
ESP_LOGI(TAG,"复位原因: %d\n", esp_reset_reason());
spi_init();
lcd_init();
LCD_Clear(0x1234);
while(1){
//LCD_Clear(rand());
// lcd_ds_test();
vTaskDelay(1); // 必须让出CPU
}
}
-55
View File
@@ -1,55 +0,0 @@
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import hashlib
import logging
from typing import Callable
import pytest
from pytest_embedded_idf.dut import IdfDut
from pytest_embedded_idf.utils import idf_parametrize
from pytest_embedded_qemu.app import QemuApp
from pytest_embedded_qemu.dut import QemuDut
@pytest.mark.generic
@idf_parametrize('target', ['supported_targets', 'preview_targets'], indirect=['target'])
def test_hello_world(dut: IdfDut, log_minimum_free_heap_size: Callable[..., None]) -> None:
dut.expect('Hello world!')
log_minimum_free_heap_size()
@pytest.mark.host_test
@idf_parametrize('target', ['linux'], indirect=['target'])
def test_hello_world_linux(dut: IdfDut) -> None:
dut.expect('Hello world!')
@pytest.mark.host_test
@pytest.mark.macos_shell
@idf_parametrize('target', ['linux'], indirect=['target'])
def test_hello_world_macos(dut: IdfDut) -> None:
dut.expect('Hello world!')
def verify_elf_sha256_embedding(app: QemuApp, sha256_reported: str) -> None:
sha256 = hashlib.sha256()
with open(app.elf_file, 'rb') as f:
sha256.update(f.read())
sha256_expected = sha256.hexdigest()
logging.info(f'ELF file SHA256: {sha256_expected}')
logging.info(f'ELF file SHA256 (reported by the app): {sha256_reported}')
# the app reports only the first several hex characters of the SHA256, check that they match
if not sha256_expected.startswith(sha256_reported):
raise ValueError('ELF file SHA256 mismatch')
@pytest.mark.host_test
@pytest.mark.qemu
@idf_parametrize('target', ['esp32', 'esp32c3'], indirect=['target'])
def test_hello_world_host(app: QemuApp, dut: QemuDut) -> None:
sha256_reported = dut.expect(r'ELF file SHA256:\s+([a-f0-9]+)').group(1).decode('utf-8')
verify_elf_sha256_embedding(app, sha256_reported)
dut.expect('Hello world!')
View File
Binary file not shown.