Stimulate/main/esp32_s3_szp.c

485 lines
15 KiB
C
Raw Permalink Normal View History

2025-09-25 18:50:48 +08:00
#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显示屏 ↑ *************************/
/***********************************************************/