HiFi player project, first commit.
This commit is contained in:
commit
4126ea13a1
49 files changed
+6333
No files matched your search
@@ -0,0 +1,35 @@
|
||||
set(src_dirs
|
||||
LED
|
||||
MYIIC
|
||||
XL9555
|
||||
MYSPI
|
||||
SPILCD
|
||||
SPI_SD
|
||||
ES8388
|
||||
MYI2S)
|
||||
|
||||
set(include_dirs
|
||||
LED
|
||||
MYIIC
|
||||
XL9555
|
||||
MYSPI
|
||||
SPILCD
|
||||
SPI_SD
|
||||
ES8388
|
||||
MYI2S)
|
||||
|
||||
set(requires
|
||||
driver
|
||||
esp_driver_gpio
|
||||
esp_driver_i2c
|
||||
esp_driver_i2s
|
||||
esp_driver_spi
|
||||
esp_driver_sdspi
|
||||
esp_driver_sdmmc
|
||||
sdmmc
|
||||
esp_lcd
|
||||
fatfs)
|
||||
|
||||
idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires})
|
||||
|
||||
component_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format)
|
||||
@@ -0,0 +1,294 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file es8388.c
|
||||
* @author 正点原子团队(ALIENTEK)
|
||||
* @version V1.0
|
||||
* @date 2025-01-01
|
||||
* @brief ES8388驱动代码
|
||||
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
|
||||
****************************************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* 实验平台:正点原子 ESP32-S3 开发板
|
||||
* 在线视频:www.yuanzige.com
|
||||
* 技术论坛:www.openedv.com
|
||||
* 公司网址:www.alientek.com
|
||||
* 购买地址:openedv.taobao.com
|
||||
*
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#include "es8388.h"
|
||||
|
||||
|
||||
const char* es8388_tag = "es8388";
|
||||
i2c_master_dev_handle_t es8388_handle = NULL;
|
||||
|
||||
/**
|
||||
* @brief ES8388写寄存器
|
||||
* @param reg_addr:寄存器地址
|
||||
* @param data:写入的数据
|
||||
* @retval 无
|
||||
*/
|
||||
esp_err_t es8388_write_reg(uint8_t reg_addr, uint8_t data)
|
||||
{
|
||||
esp_err_t ret;
|
||||
uint8_t *buf = malloc(2);
|
||||
if (buf == NULL)
|
||||
{
|
||||
ESP_LOGE(es8388_tag, "%s memory failed", __func__);
|
||||
return ESP_ERR_NO_MEM; /* 分配内存失败 */
|
||||
}
|
||||
|
||||
buf[0] = reg_addr;
|
||||
buf[1] = data; /* 拷贝数据至存储区当中 */
|
||||
|
||||
do
|
||||
{
|
||||
i2c_master_bus_wait_all_done(bus_handle, 1000);
|
||||
ret = i2c_master_transmit(es8388_handle, buf, 2, 1000);
|
||||
} while (ret != ESP_OK);
|
||||
|
||||
free(buf); /* 发送完成释放内存 */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ES8388读寄存器
|
||||
* @param reg_add:寄存器地址
|
||||
* @param p_data:读取的数据
|
||||
* @retval 无
|
||||
*/
|
||||
esp_err_t es8388_read_reg(uint8_t reg_addr, uint8_t *pdata)
|
||||
{
|
||||
uint8_t reg_data = 0;
|
||||
i2c_master_transmit_receive(es8388_handle, ®_addr, 1, ®_data, 1, -1);
|
||||
return reg_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ES8388初始化
|
||||
* @param 无
|
||||
* @retval 0,初始化正常
|
||||
* 其他,错误代码
|
||||
*/
|
||||
uint8_t es8388_init(void)
|
||||
{
|
||||
uint8_t ret_val = 0;
|
||||
|
||||
/* 未调用myiic_init初始化IIC */
|
||||
if (bus_handle == NULL)
|
||||
{
|
||||
ESP_ERROR_CHECK(myiic_init());
|
||||
}
|
||||
|
||||
i2c_device_config_t es8388_i2c_dev_conf = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7, /* 从机地址长度 */
|
||||
.scl_speed_hz = IIC_SPEED_CLK, /* 传输速率 */
|
||||
.device_address = ES8388_ADDR, /* 从机7位的地址 */
|
||||
};
|
||||
/* I2C总线上添加ES8388设备 */
|
||||
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &es8388_i2c_dev_conf, &es8388_handle));
|
||||
ESP_ERROR_CHECK(i2c_master_bus_wait_all_done(bus_handle,1000));
|
||||
|
||||
ret_val |= es8388_write_reg(0, 0x80); /* 软复位ES8388 */
|
||||
ret_val |= es8388_write_reg(0, 0x00);
|
||||
vTaskDelay(pdMS_TO_TICKS(200)); /* 等待复位 */
|
||||
|
||||
ret_val |= es8388_write_reg(0x01, 0x58);
|
||||
ret_val |= es8388_write_reg(0x01, 0x50);
|
||||
ret_val |= es8388_write_reg(0x02, 0xF3);
|
||||
ret_val |= es8388_write_reg(0x02, 0xF0);
|
||||
|
||||
ret_val |= es8388_write_reg(0x03, 0x09); /* 麦克风偏置电源关闭 */
|
||||
ret_val |= es8388_write_reg(0x00, 0x06); /* 使能参考 500K驱动使能 */
|
||||
ret_val |= es8388_write_reg(0x04, 0x00); /* DAC电源管理,不打开任何通道 */
|
||||
ret_val |= es8388_write_reg(0x08, 0x00); /* MCLK不分频 */
|
||||
ret_val |= es8388_write_reg(0x2B, 0x80); /* DAC控制 DACLRC与ADCLRC相同 */
|
||||
|
||||
ret_val |= es8388_write_reg(0x09, 0x88); /* ADC L/R PGA增益配置为+24dB */
|
||||
ret_val |= es8388_write_reg(0x0C, 0x4C); /* ADC数据选择为left data = left ADC, right data = left ADC 音频数据为16bit */
|
||||
ret_val |= es8388_write_reg(0x0D, 0x02); /* ADC配置 MCLK/采样率=256 */
|
||||
ret_val |= es8388_write_reg(0x10, 0x00); /* ADC数字音量控制将信号衰减 L 设置为最小!!! */
|
||||
ret_val |= es8388_write_reg(0x11, 0x00); /* ADC数字音量控制将信号衰减 R 设置为最小!!! */
|
||||
|
||||
ret_val |= es8388_write_reg(0x17, 0x18); /* DAC音频数据为16bit */
|
||||
ret_val |= es8388_write_reg(0x18, 0x02); /* DAC配置 MCLK/采样率=256 */
|
||||
ret_val |= es8388_write_reg(0x1A, 0x00); /* DAC数字音量控制将信号衰减 L 设置为最小!!! */
|
||||
ret_val |= es8388_write_reg(0x1B, 0x00); /* DAC数字音量控制将信号衰减 R 设置为最小!!! */
|
||||
ret_val |= es8388_write_reg(0x27, 0xB8); /* L混频器 */
|
||||
ret_val |= es8388_write_reg(0x2A, 0xB8); /* R混频器 */
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
if (ret_val != ESP_OK)
|
||||
{
|
||||
ESP_LOGI(es8388_tag, "ES8388 fail");
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(es8388_tag, "ES8388 success");
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
return 0;
|
||||
}
|
||||
|
||||
es8388_adda_cfg(0, 0); /* 开启DAC关闭ADC */
|
||||
es8388_input_cfg(0); /* 关闭录音输入 */
|
||||
es8388_output_cfg(0, 0); /* DAC选择通道输出 */
|
||||
es8388_hpvol_set(0); /* 设置耳机音量 */
|
||||
es8388_spkvol_set(0); /* 设置喇叭音量 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ES8388反初始化
|
||||
* @param 无
|
||||
* @retval 0,初始化正常
|
||||
* 其他,错误代码
|
||||
*/
|
||||
esp_err_t es8388_deinit(void)
|
||||
{
|
||||
return es8388_write_reg(0x02, 0xFF); /* 复位和暂停ES8388 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置ES8388工作模式
|
||||
* @param fmt : 工作模式
|
||||
* @arg 0, 飞利浦标准I2S;
|
||||
* @arg 1, MSB(左对齐);
|
||||
* @arg 2, LSB(右对齐);
|
||||
* @arg 3, PCM/DSP
|
||||
* @param len : 数据长度
|
||||
* @arg 0, 24bit
|
||||
* @arg 1, 20bit
|
||||
* @arg 2, 18bit
|
||||
* @arg 3, 16bit
|
||||
* @arg 4, 32bit
|
||||
* @retval 无
|
||||
*/
|
||||
void es8388_i2s_cfg(uint8_t fmt, uint8_t len)
|
||||
{
|
||||
fmt &= 0x03;
|
||||
len &= 0x07; /* 限定范围 */
|
||||
es8388_write_reg(23, (fmt << 1) | (len << 3)); /* R23,ES8388工作模式设置 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置耳机音量
|
||||
* @param volume : 音量大小(0 ~ 33)
|
||||
* @retval 无
|
||||
*/
|
||||
void es8388_hpvol_set(uint8_t volume)
|
||||
{
|
||||
if (volume > 33)
|
||||
{
|
||||
volume = 33;
|
||||
}
|
||||
|
||||
es8388_write_reg(0x2E, volume);
|
||||
es8388_write_reg(0x2F, volume);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置喇叭音量
|
||||
* @param volume : 音量大小(0 ~ 33)
|
||||
* @retval 无
|
||||
*/
|
||||
void es8388_spkvol_set(uint8_t volume)
|
||||
{
|
||||
if (volume > 33)
|
||||
{
|
||||
volume = 33;
|
||||
}
|
||||
|
||||
es8388_write_reg(0x30, volume);
|
||||
es8388_write_reg(0x31, volume);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置3D环绕声
|
||||
* @param depth : 0 ~ 7(3D强度,0关闭,7最强)
|
||||
* @retval 无
|
||||
*/
|
||||
void es8388_3d_set(uint8_t depth)
|
||||
{
|
||||
depth &= 0x7; /* 限定范围 */
|
||||
es8388_write_reg(0x1D, depth << 2); /* R7,3D环绕设置 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ES8388 DAC/ADC配置
|
||||
* @param dacen : dac使能(1) / 关闭(0)
|
||||
* @param adcen : adc使能(1) / 关闭(0)
|
||||
* @retval 无
|
||||
*/
|
||||
void es8388_adda_cfg(uint8_t dacen, uint8_t adcen)
|
||||
{
|
||||
uint8_t tempreg = 0;
|
||||
|
||||
tempreg |= !dacen << 0;
|
||||
tempreg |= !adcen << 1;
|
||||
tempreg |= !dacen << 2;
|
||||
tempreg |= !adcen << 3;
|
||||
es8388_write_reg(0x02, tempreg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ES8388 DAC输出通道配置
|
||||
* @param o1en : 通道1使能(1)/禁止(0)
|
||||
* @param o2en : 通道2使能(1)/禁止(0)
|
||||
* @retval 无
|
||||
*/
|
||||
void es8388_output_cfg(uint8_t o1en, uint8_t o2en)
|
||||
{
|
||||
uint8_t tempreg = 0;
|
||||
tempreg |= o1en * (3 << 4);
|
||||
tempreg |= o2en * (3 << 2);
|
||||
es8388_write_reg(0x04, tempreg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ES8388 MIC增益设置(MIC PGA增益)
|
||||
* @param gain : 0~8, 对应0~24dB 3dB/Step
|
||||
* @retval 无
|
||||
*/
|
||||
void es8388_mic_gain(uint8_t gain)
|
||||
{
|
||||
gain &= 0x0F;
|
||||
gain |= gain << 4;
|
||||
es8388_write_reg(0x09, gain); /* R9,左右通道PGA增益设置 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ES8388 ALC设置
|
||||
* @param sel
|
||||
* @arg 0,关闭ALC
|
||||
* @arg 1,右通道ALC
|
||||
* @arg 2,左通道ALC
|
||||
* @arg 3,立体声ALC
|
||||
* @param maxgain : 0~7,对应-6.5~+35.5dB
|
||||
* @param minigain: 0~7,对应-12~+30dB 6dB/STEP
|
||||
* @retval 无
|
||||
*/
|
||||
void es8388_alc_ctrl(uint8_t sel, uint8_t maxgain, uint8_t mingain)
|
||||
{
|
||||
uint8_t tempreg = 0;
|
||||
tempreg = sel << 6;
|
||||
tempreg |= (maxgain & 0x07) << 3;
|
||||
tempreg |= mingain & 0x07;
|
||||
es8388_write_reg(0x12, tempreg); /* R18,ALC设置 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ES8388 ADC输出通道配置
|
||||
* @param in : 输入通道
|
||||
* @arg 0, 通道1输入
|
||||
* @arg 1, 通道2输入
|
||||
* @retval 无
|
||||
*/
|
||||
void es8388_input_cfg(uint8_t in)
|
||||
{
|
||||
es8388_write_reg(0x0A, (5 * in) << 4); /* ADC1 输入通道选择L/R INPUT1 */
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file es8388.h
|
||||
* @author 正点原子团队(ALIENTEK)
|
||||
* @version V1.0
|
||||
* @date 2025-01-01
|
||||
* @brief ES8388驱动代码
|
||||
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
|
||||
****************************************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* 实验平台:正点原子 ESP32-S3 开发板
|
||||
* 在线视频:www.yuanzige.com
|
||||
* 技术论坛:www.openedv.com
|
||||
* 公司网址:www.alientek.com
|
||||
* 购买地址:openedv.taobao.com
|
||||
*
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __ES8388_H_
|
||||
#define __ES8388_H_
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "myiic.h"
|
||||
#include "math.h"
|
||||
#include "string.h"
|
||||
|
||||
#define ES8388_ADDR 0x10 /* ES8388的器件地址,固定为0x10 */
|
||||
|
||||
/* 声明函数 */
|
||||
uint8_t es8388_init(void); /* ES8388初始化 */
|
||||
esp_err_t es8388_deinit(void); /* 复位或者暂停ES8388初始化 */
|
||||
esp_err_t es8388_write_reg(uint8_t reg, uint8_t val); /* ES8388写寄存器 */
|
||||
esp_err_t es8388_read_reg(uint8_t reg_add, uint8_t *p_data); /* ES8388读寄存器 */
|
||||
void es8388_i2s_cfg(uint8_t fmt, uint8_t len); /* 设置ES8388工作模式 */
|
||||
void es8388_hpvol_set(uint8_t volume); /* 设置耳机音量 */
|
||||
void es8388_spkvol_set(uint8_t volume); /* 设置喇叭音量 */
|
||||
void es8388_3d_set(uint8_t depth); /* 设置3D环绕声 */
|
||||
void es8388_adda_cfg(uint8_t dacen, uint8_t adcen); /* ES8388 DAC/ADC配置 */
|
||||
void es8388_output_cfg(uint8_t o1en, uint8_t o2en); /* ES8388 DAC输出通道配置 */
|
||||
void es8388_mic_gain(uint8_t gain); /* ES8388 MIC增益设置(MIC PGA增益) */
|
||||
void es8388_alc_ctrl(uint8_t sel, uint8_t maxgain, uint8_t mingain); /* ES8388 ALC设置 */
|
||||
void es8388_input_cfg(uint8_t in); /* ES8388 ADC输出通道配置 */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file led.c
|
||||
* @author 正点原子团队(ALIENTEK)
|
||||
* @version V1.0
|
||||
* @date 2025-01-01
|
||||
* @brief LED驱动代码
|
||||
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
|
||||
****************************************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* 实验平台:正点原子 ESP32-S3 开发板
|
||||
* 在线视频:www.yuanzige.com
|
||||
* 技术论坛:www.openedv.com
|
||||
* 公司网址:www.alientek.com
|
||||
* 购买地址:openedv.taobao.com
|
||||
*
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#include "led.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief 初始化LED
|
||||
* @param 无
|
||||
* @retval 无
|
||||
*/
|
||||
void led_init(void)
|
||||
{
|
||||
gpio_config_t gpio_init_struct = {0};
|
||||
|
||||
gpio_init_struct.intr_type = GPIO_INTR_DISABLE; /* 失能引脚中断 */
|
||||
gpio_init_struct.mode = GPIO_MODE_INPUT_OUTPUT; /* 输入输出模式 */
|
||||
gpio_init_struct.pull_up_en = GPIO_PULLUP_DISABLE; /* 失能上拉 */
|
||||
gpio_init_struct.pull_down_en = GPIO_PULLDOWN_DISABLE; /* 失能下拉 */
|
||||
gpio_init_struct.pin_bit_mask = 1ull << LED0_GPIO_PIN; /* 设置的引脚的位掩码 */
|
||||
ESP_ERROR_CHECK(gpio_config(&gpio_init_struct)); /* 配置GPIO */
|
||||
|
||||
LED0(1); /* 关闭LED0 */
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file led.h
|
||||
* @author 正点原子团队(ALIENTEK)
|
||||
* @version V1.0
|
||||
* @date 2025-01-01
|
||||
* @brief LED驱动代码
|
||||
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
|
||||
****************************************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* 实验平台:正点原子 ESP32-S3 开发板
|
||||
* 在线视频:www.yuanzige.com
|
||||
* 技术论坛:www.openedv.com
|
||||
* 公司网址:www.alientek.com
|
||||
* 购买地址:openedv.taobao.com
|
||||
*
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __LED_H
|
||||
#define __LED_H
|
||||
|
||||
#include "driver/gpio.h"
|
||||
|
||||
|
||||
/* 引脚定义 */
|
||||
#define LED0_GPIO_PIN GPIO_NUM_1 /* LED0连接的GPIO端口 */
|
||||
|
||||
/* LED0端口定义 */
|
||||
#define LED0(x) do { x ? \
|
||||
gpio_set_level(LED0_GPIO_PIN, 1): \
|
||||
gpio_set_level(LED0_GPIO_PIN, 0); \
|
||||
} while(0) /* LED0翻转 */
|
||||
|
||||
/* LED取反定义 */
|
||||
#define LED0_TOGGLE() do { gpio_set_level(LED0_GPIO_PIN, !gpio_get_level(LED0_GPIO_PIN)); } while(0) /* LED0翻转 */
|
||||
|
||||
/* 函数声明*/
|
||||
void led_init(void); /* 初始化LED */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,221 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file i2s.c
|
||||
* @author 正点原子团队(ALIENTEK)
|
||||
* @version V1.0
|
||||
* @date 2025-01-01
|
||||
* @brief I2S驱动代码
|
||||
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
|
||||
****************************************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* 实验平台:正点原子 ESP32-S3 开发板
|
||||
* 在线视频:www.yuanzige.com
|
||||
* 技术论坛:www.openedv.com
|
||||
* 公司网址:www.alientek.com
|
||||
* 购买地址:openedv.taobao.com
|
||||
*
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#include "myi2s.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
i2s_chan_handle_t tx_handle = NULL; /* I2S发送通道句柄 */
|
||||
i2s_chan_handle_t rx_handle = NULL; /* I2S接收通道句柄 */
|
||||
i2s_std_config_t my_std_cfg; /* 标准模式配置结构体 */
|
||||
static bool s_trx_enabled = false; /* 通道是否已经使能(避免重复 enable/disable) */
|
||||
|
||||
/*
|
||||
* @brief 初始化I2S
|
||||
* @param 无
|
||||
* @retval ESP_OK:初始化成功;其他:失败
|
||||
*/
|
||||
esp_err_t myi2s_init(void)
|
||||
{
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM, I2S_ROLE_MASTER); /* 默认的通道配置(I2S0,主机) */
|
||||
chan_cfg.auto_clear = true; /* 自动清除DMA缓冲区遗留的数据 */
|
||||
chan_cfg.dma_desc_num = 8; /* DMA 描述符数量 */
|
||||
chan_cfg.dma_frame_num = 480; /* 每个描述符的帧数(约 87ms 缓冲 @44.1kHz) */
|
||||
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle)); /* 分配新的I2S通道 */
|
||||
|
||||
i2s_std_config_t std_cfg = { /* 标准通信模式配置 */
|
||||
.clk_cfg = { /* 时钟配置 可用I2S_STD_CLK_DEFAULT_CONFIG(I2S_SAMPLE_RATE)宏函数辅助配置 */
|
||||
.sample_rate_hz = I2S_SAMPLE_RATE, /* I2S采样率 */
|
||||
.clk_src = I2S_CLK_SRC_DEFAULT, /* I2S时钟源 */
|
||||
.mclk_multiple = I2S_MCLK_MULTIPLE, /* I2S主时钟MCLK相对于采样率的倍数(默认256) */
|
||||
},
|
||||
|
||||
.slot_cfg = { /* 声道配置,可用I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO)宏函数辅助配置(支持16位宽采样数据) */
|
||||
.data_bit_width = I2S_DATA_BIT_WIDTH_16BIT, /* 声道支持16位宽的采样数据 */
|
||||
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, /* 通道位宽 */
|
||||
.slot_mode = I2S_SLOT_MODE_STEREO, /* 立体声 */
|
||||
.slot_mask = I2S_STD_SLOT_BOTH, /* 启用通道 */
|
||||
.ws_width = I2S_DATA_BIT_WIDTH_16BIT, /* WS信号位宽 */
|
||||
.ws_pol = false, /* WS信号极性 */
|
||||
.bit_shift = true, /* 位移位(Philips模式下配置) */
|
||||
.left_align = true, /* 左对齐 */
|
||||
.big_endian = false, /* 小端模式 */
|
||||
.bit_order_lsb = false /* MSB */
|
||||
},
|
||||
|
||||
.gpio_cfg = { /* 引脚配置 */
|
||||
.mclk = I2S_MCK_IO, /* 主时钟线 */
|
||||
.bclk = I2S_BCK_IO, /* 位时钟线 */
|
||||
.ws = I2S_WS_IO, /* 字(声道)选择线 */
|
||||
.dout = I2S_DO_IO, /* 串行数据输出线 */
|
||||
.din = I2S_DI_IO, /* 串行数据输入线 */
|
||||
.invert_flags = { /* 引脚翻转(不反相) */
|
||||
.mclk_inv = false,
|
||||
.bclk_inv = false,
|
||||
.ws_inv = false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
my_std_cfg = std_cfg;
|
||||
|
||||
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle, &std_cfg)); /* 初始化TX通道 */
|
||||
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle, &std_cfg)); /* 初始化RX通道 */
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle)); /* 启用TX通道 */
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle)); /* 启用RX通道 */
|
||||
s_trx_enabled = true;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S TRX启动
|
||||
* @param 无
|
||||
* @retval 无
|
||||
*/
|
||||
void i2s_trx_start(void)
|
||||
{
|
||||
if (s_trx_enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle));
|
||||
s_trx_enabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S TRX停止
|
||||
* @param 无
|
||||
* @retval 无
|
||||
*/
|
||||
void i2s_trx_stop(void)
|
||||
{
|
||||
if (!s_trx_enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(i2s_channel_disable(tx_handle));
|
||||
ESP_ERROR_CHECK(i2s_channel_disable(rx_handle));
|
||||
s_trx_enabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S卸载
|
||||
* @param 无
|
||||
* @retval 无
|
||||
*/
|
||||
void i2s_deinit(void)
|
||||
{
|
||||
if (tx_handle != NULL)
|
||||
{
|
||||
i2s_channel_disable(tx_handle);
|
||||
i2s_del_channel(tx_handle);
|
||||
tx_handle = NULL;
|
||||
}
|
||||
|
||||
if (rx_handle != NULL)
|
||||
{
|
||||
i2s_channel_disable(rx_handle);
|
||||
i2s_del_channel(rx_handle);
|
||||
rx_handle = NULL;
|
||||
}
|
||||
|
||||
s_trx_enabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置采样率和位宽
|
||||
* @param sampleRate :采样率
|
||||
* @param bits_sample :位宽(16 / 24 / 32)
|
||||
* @retval 无
|
||||
* @note 调用前会先关闭通道,调用后需要再调用 i2s_trx_start() 才能出声
|
||||
* @note ESP-IDF 限制:slot 位宽为 24bit 时 mclk_multiple 必须是 3 的倍数,
|
||||
* 因此 24bit 用 384 倍(MCLK=384fs,BCLK=48fs,分频比 8 整数),
|
||||
* 16/32bit 保持 256 倍(分频比分别为 8 / 4)。
|
||||
*/
|
||||
void i2s_set_samplerate_bits_sample(int samplerate, int bits_sample)
|
||||
{
|
||||
i2s_data_bit_width_t data_width;
|
||||
i2s_mclk_multiple_t mclk_multiple;
|
||||
|
||||
switch (bits_sample)
|
||||
{
|
||||
case 24:
|
||||
data_width = I2S_DATA_BIT_WIDTH_24BIT;
|
||||
mclk_multiple = I2S_MCLK_MULTIPLE_384; /* 必须是 3 的倍数 */
|
||||
break;
|
||||
|
||||
case 32:
|
||||
data_width = I2S_DATA_BIT_WIDTH_32BIT;
|
||||
mclk_multiple = I2S_MCLK_MULTIPLE_256;
|
||||
break;
|
||||
|
||||
case 16:
|
||||
default:
|
||||
data_width = I2S_DATA_BIT_WIDTH_16BIT;
|
||||
mclk_multiple = I2S_MCLK_MULTIPLE_256;
|
||||
break;
|
||||
}
|
||||
|
||||
i2s_trx_stop();
|
||||
|
||||
/*
|
||||
* 重配 slot 时驱动内部会用当前 mclk_multiple 重算时钟,
|
||||
* 因此 MCLK 倍数必须在改 slot 之前就设好。
|
||||
*/
|
||||
my_std_cfg.clk_cfg.mclk_multiple = mclk_multiple;
|
||||
my_std_cfg.slot_cfg.data_bit_width = data_width; /* 数据位宽 */
|
||||
my_std_cfg.slot_cfg.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO; /* 跟随数据位宽 */
|
||||
my_std_cfg.slot_cfg.ws_width = data_width; /* WS 位宽,与数据位宽一致(50% 占空比) */
|
||||
|
||||
/* 如果需要更新声道或时钟配置,需要在更新前先禁用通道 */
|
||||
ESP_ERROR_CHECK(i2s_channel_reconfig_std_slot(tx_handle, &my_std_cfg.slot_cfg));
|
||||
my_std_cfg.clk_cfg.sample_rate_hz = samplerate; /* 设置采样率 */
|
||||
ESP_ERROR_CHECK(i2s_channel_reconfig_std_clock(tx_handle, &my_std_cfg.clk_cfg));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S传输数据
|
||||
* @param buffer: 数据存储区的首地址
|
||||
* @param frame_size: 数据大小
|
||||
* @retval 发送的数据长度
|
||||
*/
|
||||
size_t i2s_tx_write(uint8_t *buffer, uint32_t frame_size)
|
||||
{
|
||||
size_t bytes_written;
|
||||
ESP_ERROR_CHECK(i2s_channel_write(tx_handle, buffer, frame_size, &bytes_written, 1000));
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S读取数据
|
||||
* @param buffer: 读取数据存储区的首地址
|
||||
* @param frame_size: 读取数据大小
|
||||
* @retval 接收的数据长度
|
||||
*/
|
||||
size_t i2s_rx_read(uint8_t *buffer, uint32_t frame_size)
|
||||
{
|
||||
size_t bytes_written;
|
||||
ESP_ERROR_CHECK(i2s_channel_read(rx_handle, buffer, frame_size, &bytes_written, 1000));
|
||||
return bytes_written;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file i2s.h
|
||||
* @author 正点原子团队(ALIENTEK)
|
||||
* @version V1.0
|
||||
* @date 2025-01-01
|
||||
* @brief I2S驱动代码
|
||||
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
|
||||
****************************************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* 实验平台:正点原子 ESP32-S3 开发板
|
||||
* 在线视频:www.yuanzige.com
|
||||
* 技术论坛:www.openedv.com
|
||||
* 公司网址:www.alientek.com
|
||||
* 购买地址:openedv.taobao.com
|
||||
*
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef _MYI2S_H_
|
||||
#define _MYI2S_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2s_std.h"
|
||||
|
||||
|
||||
#define I2S_NUM (I2S_NUM_0) /* I2S port */
|
||||
#define I2S_BCK_IO (GPIO_NUM_46) /* ES8388_SCLK */
|
||||
#define I2S_WS_IO (GPIO_NUM_9) /* ES8388_LRCK */
|
||||
#define I2S_DO_IO (GPIO_NUM_10) /* ES8388_SDIN */
|
||||
#define I2S_DI_IO (GPIO_NUM_14) /* ES8388_SDOUT */
|
||||
#define I2S_MCK_IO (GPIO_NUM_3) /* ES8388_MCLK */
|
||||
#define I2S_RECV_BUF_SIZE (2400) /* 接收大小 */
|
||||
#define I2S_SAMPLE_RATE (44100) /* 采样率 */
|
||||
#define I2S_MCLK_MULTIPLE (256) /* 如果不使用24位数据宽度,256应该足够了 */
|
||||
|
||||
extern i2s_chan_handle_t tx_handle;
|
||||
extern i2s_chan_handle_t rx_handle;
|
||||
|
||||
/* 函数声明 */
|
||||
esp_err_t myi2s_init(void); /* I2S初始化 */
|
||||
void i2s_trx_start(void); /* 启动I2S */
|
||||
void i2s_trx_stop(void); /* 停止I2S */
|
||||
void i2s_deinit(void); /* 卸载I2S */
|
||||
size_t i2s_tx_write(uint8_t *buffer, uint32_t frame_size); /* I2S传输数据 */
|
||||
size_t i2s_rx_read(uint8_t *buffer, uint32_t frame_size); /* I2S接收数据 */
|
||||
void i2s_set_samplerate_bits_sample(int samplerate,int bits_sample);/* 设置采样率和位宽 */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file iic.c
|
||||
* @author 正点原子团队(ALIENTEK)
|
||||
* @version V1.0
|
||||
* @date 2025-01-01
|
||||
* @brief IIC驱动代码
|
||||
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
|
||||
****************************************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* 实验平台:正点原子 ESP32-S3 开发板
|
||||
* 在线视频:www.yuanzige.com
|
||||
* 技术论坛:www.openedv.com
|
||||
* 公司网址:www.alientek.com
|
||||
* 购买地址:openedv.taobao.com
|
||||
*
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#include "myiic.h"
|
||||
|
||||
|
||||
i2c_master_bus_handle_t bus_handle; /* 总线句柄 */
|
||||
|
||||
/**
|
||||
* @brief 初始化MYIIC
|
||||
* @param 无
|
||||
* @retval ESP_OK:初始化成功
|
||||
*/
|
||||
esp_err_t myiic_init(void)
|
||||
{
|
||||
i2c_master_bus_config_t i2c_bus_config = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT, /* 时钟源 */
|
||||
.i2c_port = IIC_NUM_PORT, /* I2C端口 */
|
||||
.scl_io_num = IIC_SCL_GPIO_PIN, /* SCL管脚 */
|
||||
.sda_io_num = IIC_SDA_GPIO_PIN, /* SDA管脚 */
|
||||
.glitch_ignore_cnt = 7, /* 故障周期 */
|
||||
.flags.enable_internal_pullup = true, /* 内部上拉 */
|
||||
};
|
||||
/* 新建I2C总线 */
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_config, &bus_handle));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file iic.h
|
||||
* @author 正点原子团队(ALIENTEK)
|
||||
* @version V1.0
|
||||
* @date 2025-01-01
|
||||
* @brief IIC驱动代码
|
||||
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
|
||||
****************************************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* 实验平台:正点原子 ESP32-S3 开发板
|
||||
* 在线视频:www.yuanzige.com
|
||||
* 技术论坛:www.openedv.com
|
||||
* 公司网址:www.alientek.com
|
||||
* 购买地址:openedv.taobao.com
|
||||
*
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __MYIIC_H
|
||||
#define __MYIIC_H
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c_master.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
/* 引脚与相关参数定义 */
|
||||
#define IIC_NUM_PORT I2C_NUM_0 /* IIC0 */
|
||||
#define IIC_SPEED_CLK 400000 /* 速率400K */
|
||||
#define IIC_SDA_GPIO_PIN GPIO_NUM_41 /* IIC0_SDA引脚 */
|
||||
#define IIC_SCL_GPIO_PIN GPIO_NUM_42 /* IIC0_SCL引脚 */
|
||||
|
||||
extern i2c_master_bus_handle_t bus_handle; /* 总线句柄 */
|
||||
|
||||
/* 函数声明 */
|
||||
esp_err_t myiic_init(void); /* 初始化MYIIC */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file my_spi.c
|
||||
* @author 正点原子团队(ALIENTEK)
|
||||
* @version V1.0
|
||||
* @date 2025-01-01
|
||||
* @brief MYSPI驱动代码
|
||||
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
|
||||
****************************************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* 实验平台:正点原子 ESP32-S3 开发板
|
||||
* 在线视频:www.yuanzige.com
|
||||
* 技术论坛:www.openedv.com
|
||||
* 公司网址:www.alientek.com
|
||||
* 购买地址:openedv.taobao.com
|
||||
*
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#include "my_spi.h"
|
||||
|
||||
|
||||
/* SD卡设备句柄 */
|
||||
spi_device_handle_t MY_SD_Handle = NULL;
|
||||
|
||||
/**
|
||||
* @brief spi初始化
|
||||
* @param 无
|
||||
* @retval esp_err_t
|
||||
*/
|
||||
esp_err_t my_spi_init(void)
|
||||
{
|
||||
spi_bus_config_t buscfg = {
|
||||
.sclk_io_num = SPI_SCLK_PIN, /* 时钟引脚 */
|
||||
.mosi_io_num = SPI_MOSI_PIN, /* 主机输出从机输入引脚 */
|
||||
.miso_io_num = SPI_MISO_PIN, /* 主机输入从机输出引脚 */
|
||||
.quadwp_io_num = -1, /* 用于Quad模式的WP引脚,未使用时设置为-1 */
|
||||
.quadhd_io_num = -1, /* 用于Quad模式的HD引脚,未使用时设置为-1 */
|
||||
.max_transfer_sz = 320 * 240 * sizeof(uint16_t), /* 最大传输大小(整屏(RGB565格式)) */
|
||||
};
|
||||
/* 初始化SPI总线 */
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(MY_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
|
||||
/* SPI驱动接口配置,SPISD卡时钟是20-25MHz */
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.clock_speed_hz = 20 * 1000 * 1000, /* SPI时钟 */
|
||||
.mode = 0, /* SPI模式0 */
|
||||
.spics_io_num = SD_CS_PIN, /* 片选引脚 */
|
||||
.queue_size = 7, /* 事务队列尺寸 7个 */
|
||||
};
|
||||
|
||||
/* 添加SPI总线设备 */
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(MY_SPI_HOST, &devcfg, &MY_SD_Handle));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file my_spi.h
|
||||
* @author 正点原子团队(ALIENTEK)
|
||||
* @version V1.0
|
||||
* @date 2025-01-01
|
||||
* @brief MYSPI驱动代码
|
||||
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
|
||||
****************************************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* 实验平台:正点原子 ESP32-S3 开发板
|
||||
* 在线视频:www.yuanzige.com
|
||||
* 技术论坛:www.openedv.com
|
||||
* 公司网址:www.alientek.com
|
||||
* 购买地址:openedv.taobao.com
|
||||
*
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __MY_SPI_H
|
||||
#define __MY_SPI_H
|
||||
|
||||
#include <unistd.h>
|
||||
#include "driver/sdspi_host.h"
|
||||
#include "driver/spi_common.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
/* SPI驱动管脚 */
|
||||
#define SPI_SCLK_PIN GPIO_NUM_12
|
||||
#define SPI_MOSI_PIN GPIO_NUM_11
|
||||
#define SPI_MISO_PIN GPIO_NUM_13
|
||||
/* 总线设备引脚定义 */
|
||||
#define SD_CS_PIN GPIO_NUM_2
|
||||
/* SPI端口 */
|
||||
#define MY_SPI_HOST SPI2_HOST
|
||||
/* 设备句柄 */
|
||||
extern spi_device_handle_t MY_SD_Handle; /* SD卡句柄 */
|
||||
|
||||
/* 函数声明 */
|
||||
esp_err_t my_spi_init(void); /* SPI初始化 */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file spilcd.c
|
||||
* @author HiFi Player Project
|
||||
* @version V1.0
|
||||
* @date 2026-01-01
|
||||
* @brief SPI LCD(ST7789,320x240)驱动
|
||||
* @note 初始化流程与引脚定义参考正点原子 DNESP32S3 标准例程(10_spilcd / 30_music),
|
||||
* 并增加了“刷新完成信号量”,方便 LVGL 在 flush 时等待 DMA 传输结束。
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#include "spilcd.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_lcd_panel_st7789.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#define TAG "spilcd"
|
||||
|
||||
/* 1: 2.4 寸 320x240 SPILCD 0: 1.3 寸 240x240 SPILCD */
|
||||
#define SPI_LCD_TYPE 1
|
||||
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
|
||||
static esp_lcd_panel_io_handle_t s_io_handle = NULL; /* LCD SPI IO 句柄 */
|
||||
static SemaphoreHandle_t s_flush_sem = NULL; /* SPI 传输完成信号量 */
|
||||
static uint16_t s_width = SPI_LCD_H_RES;
|
||||
static uint16_t s_height = SPI_LCD_V_RES;
|
||||
|
||||
/**
|
||||
* @brief LCD 颜色传输完成回调(SPI ISR 上下文)
|
||||
*/
|
||||
static bool lcd_color_trans_done_cb(esp_lcd_panel_io_handle_t panel_io,
|
||||
esp_lcd_panel_io_event_data_t *edata,
|
||||
void *user_ctx)
|
||||
{
|
||||
BaseType_t high_task_woken = pdFALSE;
|
||||
|
||||
if (s_flush_sem != NULL)
|
||||
{
|
||||
xSemaphoreGiveFromISR(s_flush_sem, &high_task_woken);
|
||||
}
|
||||
|
||||
(void)panel_io;
|
||||
(void)edata;
|
||||
(void)user_ctx;
|
||||
|
||||
return (high_task_woken == pdTRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化 SPI LCD
|
||||
*/
|
||||
esp_err_t spilcd_init(void)
|
||||
{
|
||||
if (s_flush_sem == NULL)
|
||||
{
|
||||
s_flush_sem = xSemaphoreCreateBinary();
|
||||
if (s_flush_sem == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "create flush semaphore failed");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
/* 打开 LCD 电源 */
|
||||
LCD_PWR(1);
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
|
||||
/* 硬件复位 */
|
||||
LCD_RST(0);
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
LCD_RST(1);
|
||||
vTaskDelay(pdMS_TO_TICKS(120));
|
||||
|
||||
/* ---------------- 挂载到 SPI 总线 ---------------- */
|
||||
esp_lcd_panel_io_spi_config_t io_config = {
|
||||
.dc_gpio_num = LCD_DC_PIN,
|
||||
.cs_gpio_num = LCD_CS_PIN,
|
||||
.pclk_hz = 60 * 1000 * 1000, /* 60MHz */
|
||||
.lcd_cmd_bits = 8,
|
||||
.lcd_param_bits = 8,
|
||||
.spi_mode = 0,
|
||||
.trans_queue_depth = 7,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &s_io_handle));
|
||||
|
||||
/* ---------------- 创建 ST7789 面板 ---------------- */
|
||||
esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = GPIO_NUM_NC, /* 复位由 XL9555 控制 */
|
||||
.rgb_ele_order = COLOR_RGB_ELEMENT_ORDER_RGB,
|
||||
.bits_per_pixel = 16,
|
||||
.data_endian = LCD_RGB_DATA_ENDIAN_BIG, /* 屏幕要求高字节在前 */
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(s_io_handle, &panel_config, &panel_handle));
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
|
||||
|
||||
/* 注册颜色传输完成回调 */
|
||||
const esp_lcd_panel_io_callbacks_t cbs = {
|
||||
.on_color_trans_done = lcd_color_trans_done_cb,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_io_register_event_callbacks(s_io_handle, &cbs, NULL));
|
||||
|
||||
spilcd_display_dir(1); /* 横屏 */
|
||||
spilcd_clear(0x0000); /* 上电先刷黑,避免白屏闪烁 */
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置屏幕方向
|
||||
*/
|
||||
void spilcd_display_dir(uint8_t dir)
|
||||
{
|
||||
if (dir == 0) /* 竖屏 */
|
||||
{
|
||||
s_width = SPI_LCD_V_RES;
|
||||
s_height = SPI_LCD_H_RES;
|
||||
esp_lcd_panel_swap_xy(panel_handle, false);
|
||||
esp_lcd_panel_mirror(panel_handle, false, false);
|
||||
|
||||
if (SPI_LCD_TYPE == 0)
|
||||
{
|
||||
esp_lcd_panel_set_gap(panel_handle, 0, 80);
|
||||
}
|
||||
}
|
||||
else /* 横屏 */
|
||||
{
|
||||
s_width = SPI_LCD_H_RES;
|
||||
s_height = SPI_LCD_V_RES;
|
||||
esp_lcd_panel_swap_xy(panel_handle, true);
|
||||
esp_lcd_panel_mirror(panel_handle, true, false);
|
||||
|
||||
if (SPI_LCD_TYPE == 0)
|
||||
{
|
||||
esp_lcd_panel_set_gap(panel_handle, 80, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将一块数据刷到屏幕,并等待 DMA 传输完成
|
||||
*/
|
||||
void spilcd_flush(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, const void *data)
|
||||
{
|
||||
if ((panel_handle == NULL) || (data == NULL) || (s_flush_sem == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (x2 > s_width) x2 = s_width;
|
||||
if (y2 > s_height) y2 = s_height;
|
||||
if ((x1 >= x2) || (y1 >= y2))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* 丢弃上一次传输残留的信号 */
|
||||
while (xSemaphoreTake(s_flush_sem, 0) == pdTRUE)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
esp_err_t ret = esp_lcd_panel_draw_bitmap(panel_handle, x1, y1, x2, y2, data);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "draw bitmap failed: %s", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
if (xSemaphoreTake(s_flush_sem, pdMS_TO_TICKS(200)) != pdTRUE)
|
||||
{
|
||||
ESP_LOGW(TAG, "wait lcd flush timeout");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 清屏
|
||||
*/
|
||||
void spilcd_clear(uint16_t color)
|
||||
{
|
||||
const uint16_t lines = 24;
|
||||
size_t px_count = (size_t)s_width * lines;
|
||||
|
||||
uint16_t *buffer = heap_caps_malloc(px_count * sizeof(uint16_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
|
||||
if (buffer == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "no memory for clear buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
/* 转换成大端字节序 */
|
||||
uint16_t color_be = (uint16_t)((color << 8) | (color >> 8));
|
||||
for (size_t i = 0; i < px_count; i++)
|
||||
{
|
||||
buffer[i] = color_be;
|
||||
}
|
||||
|
||||
for (uint16_t y = 0; y < s_height; y += lines)
|
||||
{
|
||||
uint16_t y_end = (uint16_t)((y + lines) > s_height ? s_height : (y + lines));
|
||||
spilcd_flush(0, y, s_width, y_end, buffer);
|
||||
}
|
||||
|
||||
heap_caps_free(buffer);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file spilcd.h
|
||||
* @author HiFi Player Project
|
||||
* @version V1.0
|
||||
* @date 2026-01-01
|
||||
* @brief SPI LCD(ST7789,320x240)驱动
|
||||
* @note 引脚与初始化流程参考正点原子 DNESP32S3 标准例程(10_spilcd / 30_music)
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __SPILCD_H
|
||||
#define __SPILCD_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "xl9555.h"
|
||||
|
||||
/* ---------------- 管脚声明 ---------------- */
|
||||
#define LCD_DC_PIN GPIO_NUM_40 /* LCD 数据/命令选择脚 */
|
||||
#define LCD_CS_PIN GPIO_NUM_21 /* LCD 片选脚 */
|
||||
#define LCD_HOST SPI2_HOST /* LCD 与 SD 卡共用 SPI2 */
|
||||
|
||||
/* 背光 / 复位 / 电源由 XL9555 扩展 IO 控制 */
|
||||
#define LCD_PWR(x) do { x ? xl9555_pin_write(SLCD_PWR_IO, 1) : xl9555_pin_write(SLCD_PWR_IO, 0); } while (0)
|
||||
#define LCD_RST(x) do { x ? xl9555_pin_write(SLCD_RST_IO, 1) : xl9555_pin_write(SLCD_RST_IO, 0); } while (0)
|
||||
#define LCD_BL(x) do { x ? xl9555_pin_write(LCD_BL_IO, 1) : xl9555_pin_write(LCD_BL_IO, 0); } while (0)
|
||||
|
||||
/* ---------------- 屏幕分辨率(横屏) ---------------- */
|
||||
#define SPI_LCD_H_RES 320
|
||||
#define SPI_LCD_V_RES 240
|
||||
|
||||
/* 面板句柄,LVGL 移植层需要用到 */
|
||||
extern esp_lcd_panel_handle_t panel_handle;
|
||||
|
||||
/**
|
||||
* @brief 初始化 SPI LCD(SPI 总线必须已由 my_spi_init() 初始化)
|
||||
* @retval ESP_OK 成功
|
||||
*/
|
||||
esp_err_t spilcd_init(void);
|
||||
|
||||
/**
|
||||
* @brief 设置屏幕方向
|
||||
* @param dir 0: 竖屏 1: 横屏
|
||||
*/
|
||||
void spilcd_display_dir(uint8_t dir);
|
||||
|
||||
/**
|
||||
* @brief 用单色清屏
|
||||
*/
|
||||
void spilcd_clear(uint16_t color);
|
||||
|
||||
/**
|
||||
* @brief 将一块 RGB565 图像数据刷到屏幕(阻塞,直到 SPI 传输完成)
|
||||
* @param x1,y1 左上角坐标(包含)
|
||||
* @param x2,y2 右下角坐标(不包含,即 x2-x1 为宽度)
|
||||
* @param data RGB565 像素数据,**按大端字节序存放**(高字节在前)。
|
||||
* 如果是 LVGL 的原生小端数据,需要在调用前自行做字节交换
|
||||
* (参考 lvgl_port.c 中 disp_flush_cb() 的实现)。
|
||||
* @note 该函数供 LVGL 的 flush_cb 调用,也可以在其它地方直接使用
|
||||
*/
|
||||
void spilcd_flush(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, const void *data);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file spi_sdcard.c
|
||||
* @author 正点原子团队(ALIENTEK)
|
||||
* @version V1.0
|
||||
* @date 2025-01-01
|
||||
* @brief SD卡 驱动代码
|
||||
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
|
||||
****************************************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* 实验平台:正点原子 ESP32-S3 开发板
|
||||
* 在线视频:www.yuanzige.com
|
||||
* 技术论坛:www.openedv.com
|
||||
* 公司网址:www.alientek.com
|
||||
* 购买地址:openedv.taobao.com
|
||||
*
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#include "spi_sd.h"
|
||||
|
||||
sdmmc_card_t *card; /* SD / MMC卡结构 */
|
||||
const char mount_point[] = MOUNT_POINT; /* 挂载点/根目录 */
|
||||
esp_err_t ret = ESP_OK;
|
||||
esp_err_t mount_ret = ESP_FAIL;
|
||||
|
||||
/**
|
||||
* @brief SD卡初始化
|
||||
* @param 无
|
||||
* @retval esp_err_t
|
||||
*/
|
||||
esp_err_t sd_spi_init(void)
|
||||
{
|
||||
ret = ESP_OK;
|
||||
|
||||
if (MY_SD_Handle != NULL) /* 再一次挂载或者初始化SD卡 */
|
||||
{
|
||||
if (mount_ret == ESP_OK)
|
||||
{
|
||||
esp_vfs_fat_sdcard_unmount(mount_point, card); /* 取消挂载 */
|
||||
mount_ret = ESP_FAIL;
|
||||
}
|
||||
}
|
||||
else if (MY_SD_Handle == NULL) /* 未初始化SPI驱动 */
|
||||
{
|
||||
my_spi_init(); /* 初始化SPI驱动 */
|
||||
}
|
||||
|
||||
/* 文件系统挂载配置 */
|
||||
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
|
||||
.format_if_mount_failed = false, /* 如果挂载失败:true会重新分区和格式化/false不会重新分区和格式化 */
|
||||
.max_files = 5, /* 打开文件最大数量 */
|
||||
.allocation_unit_size = 4 * 1024 * sizeof(uint8_t) /* 硬盘分区簇的大小 */
|
||||
};
|
||||
|
||||
/* SD卡参数配置 */
|
||||
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
|
||||
|
||||
/* SD卡引脚配置 */
|
||||
sdspi_device_config_t slot_config = {0};
|
||||
slot_config.host_id = host.slot;
|
||||
slot_config.gpio_cs = SD_NUM_CS;
|
||||
slot_config.gpio_cd = GPIO_NUM_NC;
|
||||
slot_config.gpio_wp = GPIO_NUM_NC;
|
||||
slot_config.gpio_int = GPIO_NUM_NC;
|
||||
|
||||
mount_ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card); /* 挂载文件系统 */
|
||||
ret |= mount_ret;
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取SD卡相关信息
|
||||
* @param out_total_bytes:总大小
|
||||
* @param out_free_bytes:剩余大小
|
||||
* @retval 无
|
||||
*/
|
||||
void sd_get_fatfs_usage(size_t *out_total_bytes, size_t *out_free_bytes)
|
||||
{
|
||||
FATFS *fs;
|
||||
size_t free_clusters;
|
||||
int res = f_getfree("0:", (DWORD *)&free_clusters, &fs);
|
||||
assert(res == FR_OK);
|
||||
size_t total_sectors = (fs->n_fatent - 2) * fs->csize;
|
||||
size_t free_sectors = free_clusters * fs->csize;
|
||||
|
||||
size_t sd_total = total_sectors / 1024;
|
||||
size_t sd_total_KB = sd_total * fs->ssize;
|
||||
size_t sd_free = free_sectors / 1024;
|
||||
size_t sd_free_KB = sd_free*fs->ssize;
|
||||
|
||||
/* 假设总大小小于4GiB,对于SPI Flash应该为true */
|
||||
if (out_total_bytes != NULL)
|
||||
{
|
||||
*out_total_bytes = sd_total_KB;
|
||||
}
|
||||
|
||||
if (out_free_bytes != NULL)
|
||||
{
|
||||
*out_free_bytes = sd_free_KB;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file spi_sd.h
|
||||
* @author 正点原子团队(ALIENTEK)
|
||||
* @version V1.0
|
||||
* @date 2025-01-01
|
||||
* @brief SD卡 驱动代码
|
||||
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
|
||||
****************************************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* 实验平台:正点原子 ESP32-S3 开发板
|
||||
* 在线视频:www.yuanzige.com
|
||||
* 技术论坛:www.openedv.com
|
||||
* 公司网址:www.alientek.com
|
||||
* 购买地址:openedv.taobao.com
|
||||
*
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __SPI_SD_H
|
||||
#define __SPI_SD_H
|
||||
|
||||
#include <unistd.h>
|
||||
#include "esp_vfs_fat.h"
|
||||
#include "driver/sdspi_host.h"
|
||||
#include "driver/spi_common.h"
|
||||
#include "sdmmc_cmd.h"
|
||||
#include "driver/sdmmc_host.h"
|
||||
#include "my_spi.h"
|
||||
|
||||
|
||||
/* 引脚定义 */
|
||||
#define SD_NUM_CS GPIO_NUM_2
|
||||
#define MOUNT_POINT "/0:"
|
||||
|
||||
/* 函数声明 */
|
||||
esp_err_t sd_spi_init(void); /* SD卡初始化 */
|
||||
void sd_get_fatfs_usage(size_t *out_total_bytes, size_t *out_free_bytes);
|
||||
#endif
|
||||
@@ -0,0 +1,290 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file xl9555.c
|
||||
* @author 正点原子团队(ALIENTEK)
|
||||
* @version V1.0
|
||||
* @date 2025-01-01
|
||||
* @brief XL9555驱动代码
|
||||
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
|
||||
****************************************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* 实验平台:正点原子 ESP32-S3 开发板
|
||||
* 在线视频:www.yuanzige.com
|
||||
* 技术论坛:www.openedv.com
|
||||
* 公司网址:www.alientek.com
|
||||
* 购买地址:openedv.taobao.com
|
||||
*
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#include "xl9555.h"
|
||||
|
||||
|
||||
const char *xl9555_tag = "xl9555";
|
||||
i2c_master_dev_handle_t xl9555_handle = NULL;
|
||||
|
||||
/**
|
||||
* @brief 读取XL9555的IO值
|
||||
* @param data:读取数据的存储区
|
||||
* @param len:读取数据的大小
|
||||
* @retval ESP_OK:读取成功; 其他:读取失败
|
||||
*/
|
||||
esp_err_t xl9555_read_byte(uint8_t *data, size_t len)
|
||||
{
|
||||
uint8_t reg_addr = XL9555_INPUT_PORT0_REG;
|
||||
|
||||
return i2c_master_transmit_receive(xl9555_handle, ®_addr, 1, data, len, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向XL9555寄存器写入数据
|
||||
* @param reg:寄存器地址
|
||||
* @param data:要写入数据的存储区
|
||||
* @param len:要写入数据的大小
|
||||
* @retval ESP_OK:读取成功; 其他:读取失败
|
||||
*/
|
||||
esp_err_t xl9555_write_byte(uint8_t reg, uint8_t *data, size_t len)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
uint8_t *buf = malloc(1 + len);
|
||||
if (buf == NULL)
|
||||
{
|
||||
ESP_LOGE(xl9555_tag, "%s memory failed", __func__);
|
||||
return ESP_ERR_NO_MEM; /* 分配内存失败 */
|
||||
}
|
||||
|
||||
buf[0] = reg; /* 0号元素为寄存器数值 */
|
||||
memcpy(buf + 1, data, len); /* 拷贝数据至存储区中 */
|
||||
|
||||
ret = i2c_master_transmit(xl9555_handle, buf, len + 1, -1);
|
||||
|
||||
free(buf); /* 发送完成释放内存 */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 控制某个IO的电平
|
||||
* @param pin : 控制的IO
|
||||
* @param val : 电平
|
||||
* @retval 返回所有IO状态
|
||||
*/
|
||||
uint16_t xl9555_pin_write(uint16_t pin, int val)
|
||||
{
|
||||
uint8_t w_data[2];
|
||||
uint16_t temp = 0x0000;
|
||||
|
||||
xl9555_read_byte(w_data, 2);
|
||||
|
||||
if (pin <= 0x0080)
|
||||
{
|
||||
if (val)
|
||||
{
|
||||
w_data[0] |= (uint8_t)(0xFF & pin);
|
||||
}
|
||||
else
|
||||
{
|
||||
w_data[0] &= ~(uint8_t)(0xFF & pin);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (val)
|
||||
{
|
||||
w_data[1] |= (uint8_t)(0xFF & (pin >> 8));
|
||||
}
|
||||
else
|
||||
{
|
||||
w_data[1] &= ~(uint8_t)(0xFF & (pin >> 8));
|
||||
}
|
||||
}
|
||||
|
||||
temp = ((uint16_t)w_data[1] << 8) | w_data[0];
|
||||
|
||||
xl9555_write_byte(XL9555_OUTPUT_PORT0_REG, w_data, 2);
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取某个IO状态
|
||||
* @param pin : 要获取状态的IO
|
||||
* @retval 此IO口的值(状态, 0/1)
|
||||
*/
|
||||
int xl9555_pin_read(uint16_t pin)
|
||||
{
|
||||
uint16_t ret;
|
||||
uint8_t r_data[2];
|
||||
|
||||
xl9555_read_byte(r_data, 2);
|
||||
|
||||
ret = r_data[1] << 8 | r_data[0];
|
||||
|
||||
return (ret & pin) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief XL9555的IO配置
|
||||
* @param config_value:IO配置输入或者输出
|
||||
* @retval 返回设置的数值
|
||||
*/
|
||||
void xl9555_ioconfig(uint16_t config_value)
|
||||
{
|
||||
/* 从机地址 + CMD + data1(P0) + data2(P1) */
|
||||
/* P10、P11、P12、P13和P14为输入,其他引脚为输出 -->0001 1111 0000 0000 注意:0为输出,1为输入*/
|
||||
uint8_t data[2];
|
||||
esp_err_t err;
|
||||
|
||||
data[0] = (uint8_t)(0xFF & config_value);
|
||||
data[1] = (uint8_t)(0xFF & (config_value >> 8));
|
||||
|
||||
do
|
||||
{
|
||||
err = xl9555_write_byte(XL9555_CONFIG_PORT0_REG, data, 2);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(xl9555_tag, "%s configure %X failed, ret: %d", __func__, config_value, err);
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
} while (err != ESP_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 外部中断服务函数
|
||||
* @param arg:中断引脚号
|
||||
* @note IRAM_ATTR: 这里的IRAM_ATTR属性用于将中断处理函数存储在内部RAM中,目的在于减少延迟
|
||||
* @retval 无
|
||||
*/
|
||||
static void IRAM_ATTR xl9555_exit_gpio_isr_handler(void *arg)
|
||||
{
|
||||
uint32_t gpio_num = (uint32_t)arg;
|
||||
|
||||
if (gpio_num == XL9555_INT_IO)
|
||||
{
|
||||
esp_rom_delay_us(20000);
|
||||
|
||||
if (gpio_get_level(XL9555_INT_IO) == 0)
|
||||
{
|
||||
/* 中断处理 */
|
||||
// ESP_DRAM_LOGI("xl9555", "xl9555 int");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 外部中断初始化程序
|
||||
* @param 无
|
||||
* @retval 无
|
||||
*/
|
||||
void xl9555_int_init(void)
|
||||
{
|
||||
gpio_config_t gpio_init_struct;
|
||||
|
||||
/* 配置XL9555器件的INT中断引脚 */
|
||||
gpio_init_struct.mode = GPIO_MODE_INPUT; /* 选择为输入模式 */
|
||||
gpio_init_struct.pull_up_en = GPIO_PULLUP_ENABLE; /* 上拉使能 */
|
||||
gpio_init_struct.pull_down_en = GPIO_PULLDOWN_DISABLE; /* 下拉失能 */
|
||||
gpio_init_struct.intr_type = GPIO_INTR_NEGEDGE; /* 下降沿触发 */
|
||||
gpio_init_struct.pin_bit_mask = 1ull << XL9555_INT_IO; /* 设置的引脚的位掩码 */
|
||||
gpio_config(&gpio_init_struct); /* 配置使能 */
|
||||
|
||||
/* 注册中断服务 */
|
||||
gpio_install_isr_service(0);
|
||||
|
||||
/* 设置GPIO的中断回调函数 */
|
||||
gpio_isr_handler_add(XL9555_INT_IO, xl9555_exit_gpio_isr_handler, (void*)XL9555_INT_IO);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化XL9555
|
||||
* @param 无
|
||||
* @retval ESP_OK:初始化成功
|
||||
*/
|
||||
esp_err_t xl9555_init(void)
|
||||
{
|
||||
uint8_t r_data[2];
|
||||
|
||||
/* 未调用myiic_init初始化IIC */
|
||||
if (bus_handle == NULL)
|
||||
{
|
||||
ESP_ERROR_CHECK(myiic_init());
|
||||
}
|
||||
|
||||
i2c_device_config_t xl9555_i2c_dev_conf = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7, /* 从机地址长度 */
|
||||
.scl_speed_hz = IIC_SPEED_CLK, /* 传输速率 */
|
||||
.device_address = XL9555_ADDR, /* 从机7位的地址 */
|
||||
};
|
||||
/* I2C总线上添加XL9555设备 */
|
||||
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &xl9555_i2c_dev_conf, &xl9555_handle));
|
||||
|
||||
/* 输入模式下,中断才有效(读取IO电平) */
|
||||
// xl9555_int_init();
|
||||
|
||||
/* 上电先读取一次清除中断标志 */
|
||||
xl9555_read_byte(r_data, 2);
|
||||
/* 配置那些扩展管脚为输入输出模式 */
|
||||
xl9555_ioconfig(0xF003);
|
||||
/* 关闭蜂鸣器 */
|
||||
xl9555_pin_write(BEEP_IO, 1);
|
||||
/* 关闭喇叭 */
|
||||
xl9555_pin_write(SPK_EN_IO, 1);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 按键扫描函数
|
||||
* @param mode:0->不连续;1->连续
|
||||
* @retval 键值, 定义如下:
|
||||
* KEY0_PRES, 1, KEY0按下
|
||||
* KEY1_PRES, 2, KEY1按下
|
||||
* KEY2_PRES, 3, KEY2按下
|
||||
* KEY3_PRES, 4, KEY3按下
|
||||
*/
|
||||
uint8_t xl9555_key_scan(uint8_t mode)
|
||||
{
|
||||
uint8_t keyval = 0;
|
||||
static uint8_t key_up = 1; /* 按键按松开标志 */
|
||||
|
||||
if (mode)
|
||||
{
|
||||
key_up = 1; /* 支持连按 */
|
||||
}
|
||||
|
||||
if (key_up && (KEY0 == 0 || KEY1 == 0 || KEY2 == 0 || KEY3 == 0 )) /* 按键松开标志为1, 且有任意一个按键按下了 */
|
||||
{
|
||||
esp_rom_delay_us(100000); /* 去抖动 */
|
||||
key_up = 0;
|
||||
|
||||
if (KEY0 == 0)
|
||||
{
|
||||
keyval = KEY0_PRES;
|
||||
}
|
||||
|
||||
if (KEY1 == 0)
|
||||
{
|
||||
keyval = KEY1_PRES;
|
||||
}
|
||||
|
||||
if (KEY2 == 0)
|
||||
{
|
||||
keyval = KEY2_PRES;
|
||||
}
|
||||
|
||||
if (KEY3 == 0)
|
||||
{
|
||||
keyval = KEY3_PRES;
|
||||
}
|
||||
}
|
||||
else if (KEY0 == 1 && KEY1 == 1 && KEY2 == 1 && KEY3 == 1) /* 没有任何按键按下, 标记按键松开 */
|
||||
{
|
||||
key_up = 1;
|
||||
}
|
||||
|
||||
return keyval; /* 返回键值 */
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
****************************************************************************************************
|
||||
* @file xl9555.h
|
||||
* @author 正点原子团队(ALIENTEK)
|
||||
* @version V1.0
|
||||
* @date 2025-01-01
|
||||
* @brief XL9555驱动代码
|
||||
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
|
||||
****************************************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* 实验平台:正点原子 ESP32-S3开发板
|
||||
* 在线视频:www.yuanzige.com
|
||||
* 技术论坛:www.openedv.com
|
||||
* 公司网址:www.alientek.com
|
||||
* 购买地址:openedv.taobao.com
|
||||
*
|
||||
****************************************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __XL9555_H
|
||||
#define __XL9555_H
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "myiic.h"
|
||||
#include "string.h"
|
||||
|
||||
|
||||
/* 引脚与相关参数定义 */
|
||||
#define XL9555_INT_IO GPIO_NUM_40 /* XL9555_INT引脚 */
|
||||
|
||||
/* XL9555寄存器宏 */
|
||||
#define XL9555_INPUT_PORT0_REG 0 /* 输入寄存器0地址 */
|
||||
#define XL9555_INPUT_PORT1_REG 1 /* 输入寄存器1地址 */
|
||||
#define XL9555_OUTPUT_PORT0_REG 2 /* 输出寄存器0地址 */
|
||||
#define XL9555_OUTPUT_PORT1_REG 3 /* 输出寄存器1地址 */
|
||||
#define XL9555_INVERSION_PORT0_REG 4 /* 极性反转寄存器0地址 */
|
||||
#define XL9555_INVERSION_PORT1_REG 5 /* 极性反转寄存器1地址 */
|
||||
#define XL9555_CONFIG_PORT0_REG 6 /* 方向配置寄存器0地址 */
|
||||
#define XL9555_CONFIG_PORT1_REG 7 /* 方向配置寄存器1地址 */
|
||||
|
||||
#define XL9555_ADDR 0X20 /* XL9555器件7位地址-->请看手册(9.1. Device Address) */
|
||||
|
||||
/* XL9555各个IO的功能 */
|
||||
#define AP_INT_IO 0x0001
|
||||
#define QMA_INT_IO 0x0002
|
||||
#define SPK_EN_IO 0x0004
|
||||
#define BEEP_IO 0x0008
|
||||
#define OV_PWDN_IO 0x0010
|
||||
#define OV_RESET_IO 0x0020
|
||||
#define GBC_LED_IO 0x0040
|
||||
#define GBC_KEY_IO 0x0080
|
||||
#define LCD_BL_IO 0x0100
|
||||
#define CT_RST_IO 0x0200
|
||||
#define SLCD_RST_IO 0x0400
|
||||
#define SLCD_PWR_IO 0x0800
|
||||
#define KEY3_IO 0x1000
|
||||
#define KEY2_IO 0x2000
|
||||
#define KEY1_IO 0x4000
|
||||
#define KEY0_IO 0x8000
|
||||
|
||||
#define KEY0 xl9555_pin_read(KEY0_IO) /* 读取KEY0引脚 */
|
||||
#define KEY1 xl9555_pin_read(KEY1_IO) /* 读取KEY1引脚 */
|
||||
#define KEY2 xl9555_pin_read(KEY2_IO) /* 读取KEY2引脚 */
|
||||
#define KEY3 xl9555_pin_read(KEY3_IO) /* 读取KEY3引脚 */
|
||||
|
||||
#define KEY0_PRES 1 /* KEY0按下 */
|
||||
#define KEY1_PRES 2 /* KEY1按下 */
|
||||
#define KEY2_PRES 3 /* KEY1按下 */
|
||||
#define KEY3_PRES 4 /* KEY1按下 */
|
||||
|
||||
/* 函数声明 */
|
||||
esp_err_t xl9555_init(void); /* 初始化XL9555 */
|
||||
int xl9555_pin_read(uint16_t pin); /* 获取某个IO状态 */
|
||||
uint16_t xl9555_pin_write(uint16_t pin, int val); /* 控制某个IO的电平 */
|
||||
esp_err_t xl9555_read_byte(uint8_t* data, size_t len); /* 读取XL9555的IO值 */
|
||||
esp_err_t xl9555_write_byte(uint8_t reg, uint8_t *data, size_t len); /* 向XL9555寄存器写入数据 */
|
||||
uint8_t xl9555_key_scan(uint8_t mode); /* 扫描扩展按键 */
|
||||
void xl9555_int_init(void); /* 初始化XL9555的中断引脚 */
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user