485 lines
15 KiB
C
485 lines
15 KiB
C
#include <stdio.h>
|
||
#include "esp32_s3_szp.h"
|
||
|
||
static const char *TAG = "esp32_s3_szp";
|
||
|
||
/******************************************************************************/
|
||
/*************************** LED ↓ *******************************************/
|
||
void LED_init(void)
|
||
{
|
||
gpio_config_t io_conf = {};
|
||
|
||
// 配置LDAC
|
||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||
io_conf.pin_bit_mask = (1ULL << LED_PIN);
|
||
io_conf.pull_down_en = 0;
|
||
io_conf.pull_up_en = 0;
|
||
gpio_config(&io_conf);
|
||
|
||
|
||
gpio_set_level(LED_PIN, 1);
|
||
}
|
||
/*************************** LED ↑ *******************************************/
|
||
/*******************************************************************************/
|
||
|
||
/******************************************************************************/
|
||
/*************************** I2C ↓ *******************************************/
|
||
esp_err_t bsp_i2c_init(void)
|
||
{
|
||
i2c_config_t i2c_conf = {
|
||
.mode = I2C_MODE_MASTER,
|
||
.sda_io_num = BSP_I2C_SDA,
|
||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||
.scl_io_num = BSP_I2C_SCL,
|
||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||
.master.clk_speed = BSP_I2C_FREQ_HZ
|
||
};
|
||
i2c_param_config(BSP_I2C_NUM, &i2c_conf);
|
||
|
||
return i2c_driver_install(BSP_I2C_NUM, i2c_conf.mode, 0, 0, 0);
|
||
}
|
||
/*************************** I2C ↑ *******************************************/
|
||
/*******************************************************************************/
|
||
|
||
|
||
/******************************************************************************/
|
||
/*************************** AD5328BRUZ ↓ ******************************************/
|
||
// 全局SPI2设备句柄
|
||
spi_device_handle_t handle;
|
||
// 初始化SPI总线
|
||
esp_err_t init_spi() {
|
||
spi_bus_config_t bus_config = {
|
||
.miso_io_num = GPIO_NUM_NC, // 不使用MISO
|
||
.mosi_io_num = PIN_MOSI, // MOSI引脚
|
||
.sclk_io_num = PIN_SCK, // SCK引脚
|
||
.quadhd_io_num = GPIO_NUM_NC,
|
||
.quadwp_io_num = GPIO_NUM_NC,
|
||
};
|
||
|
||
esp_err_t ret = spi_bus_initialize(SPI_HOST, &bus_config, 0);
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE("SPI2", "Failed to initialize SPI bus.");
|
||
return ret;
|
||
}
|
||
|
||
return ESP_OK;
|
||
}
|
||
|
||
// 初始化SPI设备(AD5328BRUZ)
|
||
esp_err_t init_spi_device() {
|
||
spi_device_interface_config_t dev_config = {
|
||
.clock_speed_hz = 1000000, // 1 MHz SPI时钟
|
||
.mode = 0, // SPI模式0
|
||
.spics_io_num = PIN_CS, // SPI片选引脚
|
||
.queue_size = 1, // 队列大小
|
||
.flags = SPI_DEVICE_HALFDUPLEX, // 半双工模式
|
||
};
|
||
|
||
esp_err_t ret = spi_bus_add_device(SPI_HOST, &dev_config, &handle);
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE("SPI2", "Failed to add SPI device.");
|
||
return ret;
|
||
}
|
||
|
||
// 确保设备句柄有效
|
||
if (handle == NULL) {
|
||
ESP_LOGE("SPI2", "Invalid device handle.");
|
||
return ESP_FAIL;
|
||
}
|
||
|
||
return ESP_OK;
|
||
}
|
||
|
||
// 配置LDAC引脚
|
||
void configure_ldac() {
|
||
gpio_config_t io_conf = {};
|
||
|
||
// 配置LDAC
|
||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||
io_conf.pin_bit_mask = (1ULL << PIN_LDAC);
|
||
io_conf.pull_down_en = 0;
|
||
io_conf.pull_up_en = 0;
|
||
gpio_config(&io_conf);
|
||
|
||
// 配置DAC_EN
|
||
io_conf.pin_bit_mask = (1ULL << DAC_EN);
|
||
gpio_config(&io_conf);
|
||
gpio_set_level(DAC_EN, 1);
|
||
}
|
||
|
||
// 设置LDAC电平
|
||
void set_ldac_level(bool level) {
|
||
gpio_set_level(PIN_LDAC, level);
|
||
|
||
}
|
||
|
||
// 计算并设置指定通道的输出电压
|
||
void set_channel_voltage(uint8_t channel, float voltage) {
|
||
if (channel > 7) {
|
||
ESP_LOGE("DAC", "Invalid channel: %d. Only channels 0-7 are valid.", channel);
|
||
return;
|
||
}
|
||
|
||
// 将电压转换为12位数字值
|
||
uint16_t dac_value = (uint16_t)((voltage / V_REF) * 4095);
|
||
|
||
// 准备SPI数据包
|
||
uint8_t tx_data[2] = {
|
||
((channel & 0x07) << 4) | ((dac_value >> 8) & 0x0F), // 高字节:通道位和高4位DAC值
|
||
(dac_value & 0xFF) // 低字节:低8位DAC值
|
||
};
|
||
|
||
// 向AD5328BRUZ写入数据
|
||
spi_transaction_t t = {
|
||
.length = 16, // 数据长度 16位
|
||
.tx_buffer = tx_data, // 发送缓冲区
|
||
.rx_buffer = NULL // 不接收数据
|
||
};
|
||
|
||
esp_err_t ret = spi_device_transmit(handle, &t);
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE("SPI", "Failed to send DAC data for channel %d.", channel);
|
||
}
|
||
}
|
||
|
||
// 配置AD5328增益和Vref缓冲
|
||
void configure_gain_and_vref() {
|
||
uint8_t cmd[2] ={0x80,0x00}; // 设置增益为2倍,启用Vref缓冲
|
||
// 向AD5328BRUZ写入数据
|
||
spi_transaction_t t = {
|
||
.length = 16, // 数据长度 16位
|
||
.tx_buffer = cmd, // 发送缓冲区
|
||
.rx_buffer = NULL // 不接收数据
|
||
};
|
||
esp_err_t ret = spi_device_transmit(handle,&t);
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE("SPI", "Failed to configure gain and Vref.");
|
||
}
|
||
}
|
||
|
||
void init_ad5328(void)
|
||
{
|
||
esp_err_t ret;
|
||
|
||
// 初始化SPI总线
|
||
ret = init_spi();
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE("SPI2", "SPI initialization failed.");
|
||
return;
|
||
}
|
||
|
||
// 初始化SPI设备
|
||
ret = init_spi_device();
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE("SPI2", "SPI device initialization failed.");
|
||
return;
|
||
}
|
||
|
||
// 配置LDAC引脚
|
||
configure_ldac();
|
||
|
||
// 启动LDAC
|
||
set_ldac_level(0); // 高电平启动LDAC
|
||
|
||
configure_gain_and_vref();
|
||
|
||
set_channel_voltage(0, 1.5f);
|
||
set_channel_voltage(1, 1.5f);
|
||
set_channel_voltage(2, 1.5f);
|
||
set_channel_voltage(3, 1.5f);
|
||
|
||
set_channel_voltage(4, 1.5f);
|
||
set_channel_voltage(5, 1.5f);
|
||
set_channel_voltage(6, 1.5f);
|
||
set_channel_voltage(7, 1.5f);
|
||
|
||
ESP_LOGI("SPI2", "SPI and AD5328BRUZ initialized successfully.");
|
||
}
|
||
|
||
/*************************** AD5328BRUZ ↑ *****************************************/
|
||
/*******************************************************************************/
|
||
|
||
|
||
/***********************************************************/
|
||
/**************** LCD显示屏 ↓ *************************/
|
||
// 背光PWM初始化
|
||
esp_err_t bsp_display_brightness_init(void)
|
||
{
|
||
// Setup LEDC peripheral for PWM backlight control
|
||
const ledc_channel_config_t LCD_backlight_channel = {
|
||
.gpio_num = BSP_LCD_BACKLIGHT,
|
||
.speed_mode = LEDC_LOW_SPEED_MODE,
|
||
.channel = LCD_LEDC_CH,
|
||
.intr_type = LEDC_INTR_DISABLE,
|
||
.timer_sel = 0,
|
||
.duty = 0,
|
||
.hpoint = 0,
|
||
.flags.output_invert = true
|
||
};
|
||
const ledc_timer_config_t LCD_backlight_timer = {
|
||
.speed_mode = LEDC_LOW_SPEED_MODE,
|
||
.duty_resolution = LEDC_TIMER_10_BIT,
|
||
.timer_num = 0,
|
||
.freq_hz = 5000,
|
||
.clk_cfg = LEDC_AUTO_CLK
|
||
};
|
||
|
||
ESP_ERROR_CHECK(ledc_timer_config(&LCD_backlight_timer));
|
||
ESP_ERROR_CHECK(ledc_channel_config(&LCD_backlight_channel));
|
||
|
||
return ESP_OK;
|
||
}
|
||
|
||
// 背光亮度设置
|
||
esp_err_t bsp_display_brightness_set(int brightness_percent)
|
||
{
|
||
if (brightness_percent > 100) {
|
||
brightness_percent = 100;
|
||
} else if (brightness_percent < 0) {
|
||
brightness_percent = 0;
|
||
}
|
||
|
||
ESP_LOGI(TAG, "Setting LCD backlight: %d%%", brightness_percent);
|
||
// LEDC resolution set to 10bits, thus: 100% = 1023
|
||
uint32_t duty_cycle = (1023 * brightness_percent) / 100;
|
||
ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LCD_LEDC_CH, duty_cycle));
|
||
ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LCD_LEDC_CH));
|
||
|
||
return ESP_OK;
|
||
}
|
||
|
||
// 关闭背光
|
||
esp_err_t bsp_display_backlight_off(void)
|
||
{
|
||
return bsp_display_brightness_set(0);
|
||
}
|
||
|
||
// 打开背光 最亮
|
||
esp_err_t bsp_display_backlight_on(void)
|
||
{
|
||
return bsp_display_brightness_set(100);
|
||
}
|
||
|
||
// 定义液晶屏句柄
|
||
static esp_lcd_panel_handle_t panel_handle = NULL;
|
||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||
static esp_lcd_touch_handle_t tp; // 触摸屏句柄
|
||
static lv_disp_t *disp; // 指向液晶屏
|
||
static lv_indev_t *disp_indev = NULL; // 指向触摸屏
|
||
|
||
// 液晶屏初始化
|
||
esp_err_t bsp_display_new(void)
|
||
{
|
||
esp_err_t ret = ESP_OK;
|
||
// 背光初始化
|
||
ESP_RETURN_ON_ERROR(bsp_display_brightness_init(), TAG, "Brightness init failed");
|
||
// 初始化SPI总线
|
||
ESP_LOGD(TAG, "Initialize SPI bus");
|
||
const spi_bus_config_t buscfg = {
|
||
.sclk_io_num = BSP_LCD_SPI_CLK,
|
||
.mosi_io_num = BSP_LCD_SPI_MOSI,
|
||
.miso_io_num = GPIO_NUM_NC,
|
||
.quadwp_io_num = GPIO_NUM_NC,
|
||
.quadhd_io_num = GPIO_NUM_NC,
|
||
//.max_transfer_sz = BSP_LCD_H_RES * BSP_LCD_V_RES * sizeof(uint16_t),
|
||
.max_transfer_sz = BSP_LCD_H_RES * 40 * sizeof(uint16_t),
|
||
};
|
||
ESP_RETURN_ON_ERROR(spi_bus_initialize(BSP_LCD_SPI_NUM, &buscfg, SPI_DMA_CH_AUTO), TAG, "SPI init failed");
|
||
// 液晶屏控制IO初始化
|
||
ESP_LOGD(TAG, "Install panel IO");
|
||
const esp_lcd_panel_io_spi_config_t io_config = {
|
||
.dc_gpio_num = BSP_LCD_DC,
|
||
.cs_gpio_num = BSP_LCD_SPI_CS,
|
||
.pclk_hz = BSP_LCD_PIXEL_CLOCK_HZ,
|
||
.lcd_cmd_bits = LCD_CMD_BITS,
|
||
.lcd_param_bits = LCD_PARAM_BITS,
|
||
.spi_mode = 2,
|
||
.trans_queue_depth = 10,
|
||
};
|
||
ESP_GOTO_ON_ERROR(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)BSP_LCD_SPI_NUM, &io_config, &io_handle), err, TAG, "New panel IO failed");
|
||
// 初始化液晶屏驱动芯片ST7789
|
||
ESP_LOGD(TAG, "Install LCD driver");
|
||
const esp_lcd_panel_dev_config_t panel_config = {
|
||
.reset_gpio_num = BSP_LCD_RST,
|
||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||
.bits_per_pixel = BSP_LCD_BITS_PER_PIXEL,
|
||
};
|
||
ESP_GOTO_ON_ERROR(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle), err, TAG, "New panel failed");
|
||
|
||
esp_lcd_panel_reset(panel_handle); // 液晶屏复位
|
||
//lcd_cs(0); // 拉低CS引脚
|
||
esp_lcd_panel_init(panel_handle); // 初始化配置寄存器
|
||
esp_lcd_panel_invert_color(panel_handle, true); // 颜色反转
|
||
esp_lcd_panel_swap_xy(panel_handle, true); // 显示翻转
|
||
esp_lcd_panel_mirror(panel_handle, true, false); // 镜像
|
||
|
||
return ret;
|
||
|
||
err:
|
||
if (panel_handle) {
|
||
esp_lcd_panel_del(panel_handle);
|
||
}
|
||
if (io_handle) {
|
||
esp_lcd_panel_io_del(io_handle);
|
||
}
|
||
spi_bus_free(BSP_LCD_SPI_NUM);
|
||
return ret;
|
||
}
|
||
|
||
// LCD显示初始化
|
||
esp_err_t bsp_lcd_init(void)
|
||
{
|
||
esp_err_t ret = ESP_OK;
|
||
|
||
|
||
ret = bsp_display_new(); // 液晶屏驱动初始化
|
||
lcd_set_color(0x0000); // 设置整屏背景黑色
|
||
ret = esp_lcd_panel_disp_on_off(panel_handle, true); // 打开液晶屏显示
|
||
ret = bsp_display_backlight_on(); // 打开背光显示
|
||
|
||
return ret;
|
||
}
|
||
|
||
// 液晶屏初始化+添加LVGL接口
|
||
static lv_disp_t *bsp_display_lcd_init(void)
|
||
{
|
||
/* 初始化液晶屏 */
|
||
bsp_display_new(); // 液晶屏驱动初始化
|
||
lcd_set_color(0xffff); // 设置整屏背景白色
|
||
esp_lcd_panel_disp_on_off(panel_handle, true); // 打开液晶屏显示
|
||
|
||
/* 液晶屏添加LVGL接口 */
|
||
ESP_LOGD(TAG, "Add LCD screen");
|
||
const lvgl_port_display_cfg_t disp_cfg = {
|
||
.io_handle = io_handle,
|
||
.panel_handle = panel_handle,
|
||
.buffer_size = BSP_LCD_H_RES * BSP_LCD_DRAW_BUF_HEIGHT, // LVGL缓存大小
|
||
.double_buffer = true, // 是否开启双缓存
|
||
.hres = BSP_LCD_H_RES, // 液晶屏的宽
|
||
.vres = BSP_LCD_V_RES, // 液晶屏的高
|
||
.monochrome = false, // 是否单色显示器
|
||
/* Rotation的值必须和液晶屏初始化里面设置的 翻转 和 镜像 一样 */
|
||
.rotation = {
|
||
.swap_xy = true, // 是否翻转
|
||
.mirror_x = true, // x方向是否镜像
|
||
.mirror_y = false, // y方向是否镜像
|
||
},
|
||
.flags = {
|
||
.buff_dma = true, // 是否使用DMA 注意:dma与spiram不能同时为true
|
||
.buff_spiram = false, // 是否使用PSRAM 注意:dma与spiram不能同时为true
|
||
}
|
||
};
|
||
|
||
return lvgl_port_add_disp(&disp_cfg);
|
||
}
|
||
|
||
// 触摸屏初始化
|
||
esp_err_t bsp_touch_new(esp_lcd_touch_handle_t *ret_touch)
|
||
{
|
||
/* Initialize touch */
|
||
esp_lcd_touch_config_t tp_cfg = {
|
||
.x_max = BSP_LCD_V_RES,
|
||
.y_max = BSP_LCD_H_RES,
|
||
.rst_gpio_num = GPIO_NUM_NC, // Shared with LCD reset
|
||
.int_gpio_num = GPIO_NUM_NC,
|
||
.levels = {
|
||
.reset = 0,
|
||
.interrupt = 0,
|
||
},
|
||
.flags = {
|
||
.swap_xy = 1,
|
||
.mirror_x = 1,
|
||
.mirror_y = 0,
|
||
},
|
||
};
|
||
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
|
||
esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_FT5x06_CONFIG();
|
||
|
||
ESP_RETURN_ON_ERROR(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)BSP_I2C_NUM, &tp_io_config, &tp_io_handle), TAG, "");
|
||
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_ft5x06(tp_io_handle, &tp_cfg, ret_touch));
|
||
|
||
return ESP_OK;
|
||
}
|
||
|
||
// 触摸屏初始化+添加LVGL接口
|
||
static lv_indev_t *bsp_display_indev_init(lv_disp_t *disp)
|
||
{
|
||
/* 初始化触摸屏 */
|
||
ESP_ERROR_CHECK(bsp_touch_new(&tp));
|
||
assert(tp);
|
||
|
||
/* 添加LVGL接口 */
|
||
const lvgl_port_touch_cfg_t touch_cfg = {
|
||
.disp = disp,
|
||
.handle = tp,
|
||
};
|
||
|
||
return lvgl_port_add_touch(&touch_cfg);
|
||
}
|
||
|
||
// 开发板显示初始化
|
||
void bsp_lvgl_start(void)
|
||
{
|
||
/* 初始化LVGL */
|
||
lvgl_port_cfg_t lvgl_cfg = ESP_LVGL_PORT_INIT_CONFIG();
|
||
lvgl_port_init(&lvgl_cfg);
|
||
|
||
/* 初始化液晶屏 并添加LVGL接口 */
|
||
disp = bsp_display_lcd_init();
|
||
|
||
/* 初始化触摸屏 并添加LVGL接口 */
|
||
disp_indev = bsp_display_indev_init(disp);
|
||
|
||
/* 打开液晶屏背光 */
|
||
bsp_display_backlight_on();
|
||
|
||
}
|
||
|
||
// 显示图片
|
||
void lcd_draw_pictrue(int x_start, int y_start, int x_end, int y_end, const unsigned char *gImage)
|
||
{
|
||
// 分配内存 分配了需要的字节大小 且指定在外部SPIRAM中分配
|
||
size_t pixels_byte_size = (x_end - x_start)*(y_end - y_start) * 2;
|
||
uint16_t *pixels = (uint16_t *)heap_caps_malloc(pixels_byte_size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
|
||
if (NULL == pixels)
|
||
{
|
||
ESP_LOGE(TAG, "Memory for bitmap is not enough");
|
||
return;
|
||
}
|
||
memcpy(pixels, gImage, pixels_byte_size); // 把图片数据拷贝到内存
|
||
esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_end, y_end, (uint16_t *)pixels); // 显示整张图片数据
|
||
heap_caps_free(pixels); // 释放内存
|
||
}
|
||
|
||
// 设置液晶屏颜色
|
||
void lcd_set_color(uint16_t color)
|
||
{
|
||
// 分配内存 这里分配了液晶屏一行数据需要的大小
|
||
uint16_t *buffer = (uint16_t *)heap_caps_malloc(BSP_LCD_H_RES * sizeof(uint16_t), MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
|
||
|
||
if (NULL == buffer)
|
||
{
|
||
ESP_LOGE(TAG, "Memory for bitmap is not enough");
|
||
}
|
||
else
|
||
{
|
||
for (size_t i = 0; i < BSP_LCD_H_RES; i++) // 给缓存中放入颜色数据
|
||
{
|
||
buffer[i] = color;
|
||
}
|
||
for (int y = 0; y < 240; y++) // 显示整屏颜色
|
||
{
|
||
esp_lcd_panel_draw_bitmap(panel_handle, 0, y, 320, y+1, buffer);
|
||
}
|
||
free(buffer); // 释放内存
|
||
}
|
||
}
|
||
/*************** LCD显示屏 ↑ *************************/
|
||
/***********************************************************/
|
||
|
||
|
||
|
||
|