initial commit
This commit is contained in:
23
components/port_bsp/CMakeLists.txt
Normal file
23
components/port_bsp/CMakeLists.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
idf_component_register(
|
||||
SRCS
|
||||
"i2c_bsp.cpp"
|
||||
"display_bsp.cpp"
|
||||
"sdcard_bsp.cpp"
|
||||
"./src/multi_button/multi_button.c"
|
||||
"button_bsp.c"
|
||||
"./codec_bsp.cpp"
|
||||
"./i2c_equipment.cpp"
|
||||
"./adc_bsp.cpp"
|
||||
PRIV_REQUIRES
|
||||
driver
|
||||
SensorLib
|
||||
esp_timer
|
||||
codec_board
|
||||
esp_adc
|
||||
REQUIRES
|
||||
esp_driver_sdmmc
|
||||
fatfs
|
||||
INCLUDE_DIRS
|
||||
"./"
|
||||
"./src/multi_button"
|
||||
EMBED_FILES "./pcm/canon.pcm")
|
||||
50
components/port_bsp/adc_bsp.cpp
Normal file
50
components/port_bsp/adc_bsp.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#include <stdio.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include "adc_bsp.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static adc_cali_handle_t cali_handle;
|
||||
static adc_oneshot_unit_handle_t adc1_handle;
|
||||
|
||||
|
||||
void Adc_PortInit() {
|
||||
adc_cali_curve_fitting_config_t cali_config = {};
|
||||
cali_config.unit_id = ADC_UNIT_1;
|
||||
cali_config.atten = ADC_ATTEN_DB_12;
|
||||
cali_config.bitwidth = ADC_BITWIDTH_12;
|
||||
ESP_ERROR_CHECK(adc_cali_create_scheme_curve_fitting(&cali_config, &cali_handle));
|
||||
|
||||
adc_oneshot_unit_init_cfg_t init_config1 = {};
|
||||
init_config1.unit_id = ADC_UNIT_1;
|
||||
ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle));
|
||||
adc_oneshot_chan_cfg_t config = {};
|
||||
config.bitwidth = ADC_BITWIDTH_12;
|
||||
config.atten = ADC_ATTEN_DB_12;
|
||||
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, ADC_CHANNEL_3, &config));
|
||||
}
|
||||
|
||||
float Adc_GetBatteryVoltage() {
|
||||
int value;
|
||||
int tage = 0;
|
||||
float vol = 0;
|
||||
esp_err_t err;
|
||||
err = adc_oneshot_read(adc1_handle,ADC_CHANNEL_3,&value);
|
||||
if(err == ESP_OK) {
|
||||
adc_cali_raw_to_voltage(cali_handle,value,&tage);
|
||||
vol = 0.001 * tage * 3;
|
||||
}
|
||||
return vol;
|
||||
}
|
||||
|
||||
uint8_t Adc_GetBatteryLevel() {
|
||||
float vol = Adc_GetBatteryVoltage();
|
||||
if(vol < 3.0) {
|
||||
return 0;
|
||||
}
|
||||
if(vol > 4.12) {
|
||||
return 100;
|
||||
}
|
||||
float level = ((vol - 3.0) / 1.12) * 100;
|
||||
//ESP_LOGW("Battery","Voltage: %.3f V, Level: %.1f %%",vol,level);
|
||||
return (uint8_t)level;
|
||||
}
|
||||
7
components/port_bsp/adc_bsp.h
Normal file
7
components/port_bsp/adc_bsp.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <esp_adc/adc_oneshot.h>
|
||||
|
||||
void Adc_PortInit();
|
||||
float Adc_GetBatteryVoltage();
|
||||
uint8_t Adc_GetBatteryLevel();
|
||||
103
components/port_bsp/button_bsp.c
Normal file
103
components/port_bsp/button_bsp.c
Normal file
@@ -0,0 +1,103 @@
|
||||
#include <stdio.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_timer.h>
|
||||
#include "button_bsp.h"
|
||||
#include "multi_button.h"
|
||||
|
||||
EventGroupHandle_t BootButtonGroups;
|
||||
EventGroupHandle_t GP18ButtonGroups;
|
||||
|
||||
static Button BootButton; // Application button
|
||||
#define BOOT_KEY_PIN 0 // Actual GPIO
|
||||
#define BOOT_ID 1 // Button ID
|
||||
#define BOOT_Active 0 // Valid level
|
||||
|
||||
static Button GP18Button;
|
||||
#define GP18_KEY_PIN 18
|
||||
#define GP18_ID 2
|
||||
#define GP18_Active 0
|
||||
|
||||
/*******************Callback event declaration***************/
|
||||
static void on_boot_single_click(Button *btn_handle) {
|
||||
xEventGroupSetBits(BootButtonGroups, set_bit_button(0));
|
||||
}
|
||||
|
||||
static void on_boot_double_click(Button *btn_handle) {
|
||||
xEventGroupSetBits(BootButtonGroups, set_bit_button(1));
|
||||
}
|
||||
|
||||
static void on_boot_long_press_start(Button *btn_handle) {
|
||||
xEventGroupSetBits(BootButtonGroups, set_bit_button(2));
|
||||
}
|
||||
|
||||
static void on_gp18_single_click(Button *btn_handle) {
|
||||
xEventGroupSetBits(GP18ButtonGroups, set_bit_button(0));
|
||||
}
|
||||
|
||||
static void on_gp18_double_click(Button *btn_handle) {
|
||||
xEventGroupSetBits(GP18ButtonGroups, set_bit_button(1));
|
||||
}
|
||||
|
||||
static void on_gp18_long_press_start(Button *btn_handle) {
|
||||
xEventGroupSetBits(GP18ButtonGroups, set_bit_button(2));
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
|
||||
static void clock_task_callback(void *arg) {
|
||||
button_ticks();
|
||||
}
|
||||
|
||||
static uint8_t read_button_GPIO(uint8_t Button_ID) {
|
||||
switch (Button_ID) {
|
||||
case BOOT_ID:
|
||||
return gpio_get_level(BOOT_KEY_PIN);
|
||||
case GP18_ID:
|
||||
return gpio_get_level(GP18_KEY_PIN);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void gpio_init(void) {
|
||||
gpio_config_t gpio_conf = {};
|
||||
gpio_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
gpio_conf.mode = GPIO_MODE_INPUT;
|
||||
gpio_conf.pin_bit_mask = (0x1ULL << BOOT_KEY_PIN) | (0x1ULL << GP18_KEY_PIN);
|
||||
gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(gpio_config(&gpio_conf));
|
||||
}
|
||||
|
||||
void Custom_ButtonInit(void) {
|
||||
BootButtonGroups = xEventGroupCreate();
|
||||
GP18ButtonGroups = xEventGroupCreate();
|
||||
gpio_init();
|
||||
|
||||
button_init(&BootButton, read_button_GPIO, BOOT_Active, BOOT_ID); // Initialization: Initialize object, callback function, trigger level, key ID
|
||||
button_attach(&BootButton, BTN_SINGLE_CLICK, on_boot_single_click); // Single click event
|
||||
button_attach(&BootButton, BTN_DOUBLE_CLICK, on_boot_double_click); // Double click event
|
||||
button_attach(&BootButton, BTN_LONG_PRESS_START, on_boot_long_press_start); // Long press event
|
||||
|
||||
button_init(&GP18Button, read_button_GPIO, BOOT_Active, GP18_ID);
|
||||
button_attach(&GP18Button, BTN_SINGLE_CLICK, on_gp18_single_click);
|
||||
button_attach(&GP18Button, BTN_DOUBLE_CLICK, on_gp18_double_click);
|
||||
button_attach(&GP18Button, BTN_LONG_PRESS_START, on_gp18_long_press_start);
|
||||
|
||||
esp_timer_create_args_t clock_tick_timer_args = {};
|
||||
clock_tick_timer_args.callback = &clock_task_callback;
|
||||
clock_tick_timer_args.name = "clock_task";
|
||||
clock_tick_timer_args.arg = NULL;
|
||||
esp_timer_handle_t clock_tick_timer = NULL;
|
||||
ESP_ERROR_CHECK(esp_timer_create(&clock_tick_timer_args, &clock_tick_timer));
|
||||
ESP_ERROR_CHECK(esp_timer_start_periodic(clock_tick_timer, 1000 * 5)); // 5ms
|
||||
button_start(&BootButton);
|
||||
button_start(&GP18Button);
|
||||
}
|
||||
|
||||
uint8_t user_boot_get_repeat_count(void) {
|
||||
return (button_get_repeat_count(&BootButton));
|
||||
}
|
||||
31
components/port_bsp/button_bsp.h
Normal file
31
components/port_bsp/button_bsp.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef BUTTON_BSP_H
|
||||
#define BUTTON_BSP_H
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern EventGroupHandle_t BootButtonGroups;
|
||||
extern EventGroupHandle_t GP18ButtonGroups;
|
||||
|
||||
|
||||
#define set_bit_button(x) ((uint32_t)(0x01)<<(x))
|
||||
#define get_bit_button(x,y) (((uint32_t)(x)>>(y)) & 0x01)
|
||||
#define set_bit_all 0x00ffffff
|
||||
|
||||
|
||||
//set bit
|
||||
#define set_bit_data(x,y) (x |= (0x01<<y))
|
||||
#define clr_bit_data(x,y) (x &= ~(0x01<<y))
|
||||
#define get_bit_data(x,y) ((x>>y) & 0x01)
|
||||
#define rset_bit_data(x) ((uint32_t)0x01<<(x))
|
||||
|
||||
void Custom_ButtonInit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
140
components/port_bsp/codec_bsp.cpp
Normal file
140
components/port_bsp/codec_bsp.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <esp_log.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include "codec_bsp.h"
|
||||
#include "i2c_bsp.h"
|
||||
|
||||
extern const uint8_t music_pcm_start[] asm("_binary_canon_pcm_start");
|
||||
extern const uint8_t music_pcm_end[] asm("_binary_canon_pcm_end");
|
||||
|
||||
void CodecPort::CodecPort_MusicTask(void *arg) {
|
||||
CodecPort *codec = (CodecPort *)arg;
|
||||
codec->CodecPort_SetSpeakerVol(80);
|
||||
for(;;) {
|
||||
size_t bytes_write = 0;
|
||||
size_t bytes_sizt = music_pcm_end - music_pcm_start;
|
||||
uint8_t *data_ptr = (uint8_t *)music_pcm_start;
|
||||
codec->CodecPort_SetInfo("es8311",1,24000,2,16);
|
||||
do
|
||||
{
|
||||
codec->CodecPort_PlayWrite(data_ptr, 256);
|
||||
data_ptr += 256;
|
||||
bytes_write += 256;
|
||||
} while (bytes_write < bytes_sizt);
|
||||
}
|
||||
}
|
||||
|
||||
void CodecPort::CodecPort_EchoTask(void *arg) {
|
||||
CodecPort *codec = (CodecPort *)arg;
|
||||
codec->CodecPort_SetSpeakerVol(80);
|
||||
codec->CodecPort_SetMicGain(25);
|
||||
uint8_t *data_ptr = (uint8_t *)heap_caps_malloc(1024 * sizeof(uint8_t), MALLOC_CAP_SPIRAM);
|
||||
codec->CodecPort_SetInfo("es8311 & es7210",1,24000,2,16);
|
||||
for(;;)
|
||||
{
|
||||
if(ESP_CODEC_DEV_OK == codec->CodecPort_EchoRead(data_ptr, 1024))
|
||||
{
|
||||
codec->CodecPort_PlayWrite(data_ptr, 1024);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CodecPort::CodecPort(I2cMasterBus& i2cbus,const char *strName) :
|
||||
i2cbus_(i2cbus)
|
||||
{
|
||||
set_codec_board_type(strName);
|
||||
codec_init_cfg_t codec_cfg = {};
|
||||
codec_cfg.in_mode = CODEC_I2S_MODE_TDM;
|
||||
codec_cfg.out_mode = CODEC_I2S_MODE_TDM;
|
||||
codec_cfg.in_use_tdm = false;
|
||||
codec_cfg.reuse_dev = false;
|
||||
ESP_ERROR_CHECK(init_codec(&codec_cfg));
|
||||
playback = get_playback_handle();
|
||||
record = get_record_handle();
|
||||
|
||||
i2c_master_bus_handle_t I2cMasterBus = i2cbus_.Get_I2cBusHandle();
|
||||
i2c_device_config_t dev_cfg = {};
|
||||
dev_cfg.dev_addr_length = I2C_ADDR_BIT_LEN_7;
|
||||
dev_cfg.device_address = Es8311Address;
|
||||
dev_cfg.scl_speed_hz = 400000;
|
||||
ESP_ERROR_CHECK(i2c_master_bus_add_device(I2cMasterBus, &dev_cfg, &I2c_DevEs8311));
|
||||
|
||||
dev_cfg.device_address = Es7210Address;
|
||||
ESP_ERROR_CHECK(i2c_master_bus_add_device(I2cMasterBus, &dev_cfg, &I2c_DevEs7210));
|
||||
}
|
||||
|
||||
CodecPort::~CodecPort() {
|
||||
}
|
||||
|
||||
void CodecPort::Codec_SetCodecReg(const char *str, uint8_t reg, uint8_t data) {
|
||||
if (!strcmp(str, "es8311"))
|
||||
i2cbus_.i2c_write_buff(I2c_DevEs8311, reg, &data, 1);
|
||||
if (!strcmp(str, "es7210"))
|
||||
i2cbus_.i2c_write_buff(I2c_DevEs7210, reg, &data, 1);
|
||||
}
|
||||
|
||||
uint8_t CodecPort::Codec_GetCodecReg(const char *str, uint8_t reg) {
|
||||
uint8_t data = 0x00;
|
||||
if (!strcmp(str, "es8311"))
|
||||
i2cbus_.i2c_read_buff(I2c_DevEs8311, reg, &data, 1);
|
||||
if (!strcmp(str, "es7210"))
|
||||
i2cbus_.i2c_read_buff(I2c_DevEs7210, reg, &data, 1);
|
||||
return data;
|
||||
}
|
||||
|
||||
void CodecPort::CodecPort_SetSpeakerVol(int vol) {
|
||||
esp_codec_dev_set_out_vol(playback, vol);
|
||||
}
|
||||
|
||||
void CodecPort::CodecPort_SetMicGain(float db_value) {
|
||||
esp_codec_dev_set_in_gain(record, db_value);
|
||||
}
|
||||
|
||||
void CodecPort::CodecPort_CloseSpeaker(void) {
|
||||
esp_codec_dev_close(playback);
|
||||
}
|
||||
|
||||
void CodecPort::CodecPort_CloseMic(void) {
|
||||
esp_codec_dev_close(record);
|
||||
}
|
||||
|
||||
int CodecPort::CodecPort_PlayWrite(void *ptr,int ptr_len) {
|
||||
return esp_codec_dev_write(playback, ptr, ptr_len);
|
||||
}
|
||||
|
||||
int CodecPort::CodecPort_EchoRead(void *ptr,int ptr_len) {
|
||||
return esp_codec_dev_read(record, ptr, ptr_len);
|
||||
}
|
||||
|
||||
void CodecPort::CodecPort_SetInfo(const char *strName,int open_en,int sample_rate,int channel,int bits_per_sample) {
|
||||
esp_codec_dev_sample_info_t fs = {};
|
||||
fs.sample_rate = sample_rate;
|
||||
fs.channel = channel;
|
||||
fs.bits_per_sample = bits_per_sample;
|
||||
if(open_en) {
|
||||
if(!strcmp(strName,"es8311")) {
|
||||
esp_codec_dev_open(playback, &fs);
|
||||
} else if(!strcmp(strName,"es7210")) {
|
||||
esp_codec_dev_open(record, &fs);
|
||||
} else {
|
||||
esp_codec_dev_open(playback, &fs);
|
||||
esp_codec_dev_open(record, &fs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CodecPort::CodecPort_CreateMusicTask(void) {
|
||||
xTaskCreate(CodecPort_MusicTask, "CodecPort_MusicTask", 4 * 1024, (void *)this, 2, NULL);
|
||||
}
|
||||
|
||||
void CodecPort::CodecPort_CreateEchoTask(void) {
|
||||
xTaskCreate(CodecPort_EchoTask, "CodecPort_EchoTask", 4 * 1024, (void *)this, 2, NULL);
|
||||
}
|
||||
|
||||
uint8_t *CodecPort::CodecPort_GetPcmData(uint32_t *len) {
|
||||
*len = (music_pcm_end - music_pcm_start);
|
||||
return (uint8_t *)music_pcm_start;
|
||||
}
|
||||
|
||||
44
components/port_bsp/codec_bsp.h
Normal file
44
components/port_bsp/codec_bsp.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "codec_board.h"
|
||||
#include "codec_init.h"
|
||||
#include "i2c_bsp.h"
|
||||
|
||||
class CodecPort
|
||||
{
|
||||
private:
|
||||
esp_codec_dev_handle_t playback = NULL;
|
||||
esp_codec_dev_handle_t record = NULL;
|
||||
I2cMasterBus& i2cbus_;
|
||||
i2c_master_dev_handle_t I2c_DevEs8311;
|
||||
i2c_master_dev_handle_t I2c_DevEs7210;
|
||||
const uint8_t Es8311Address = 0x18;
|
||||
const uint8_t Es7210Address = 0x40;
|
||||
|
||||
static void CodecPort_MusicTask(void *arg);
|
||||
static void CodecPort_EchoTask(void *arg);
|
||||
public:
|
||||
CodecPort(I2cMasterBus& i2cbus,const char *strName);
|
||||
~CodecPort();
|
||||
|
||||
void Codec_SetCodecReg(const char * str,uint8_t reg,uint8_t data);
|
||||
uint8_t Codec_GetCodecReg(const char *str, uint8_t reg);
|
||||
|
||||
void CodecPort_SetSpeakerVol(int vol);
|
||||
void CodecPort_SetMicGain(float db_value);
|
||||
|
||||
void CodecPort_CloseSpeaker(void);
|
||||
void CodecPort_CloseMic(void);
|
||||
|
||||
int CodecPort_PlayWrite(void *ptr,int ptr_len);
|
||||
int CodecPort_EchoRead(void *ptr,int ptr_len);
|
||||
|
||||
void CodecPort_CreateMusicTask(void);
|
||||
void CodecPort_CreateEchoTask(void);
|
||||
|
||||
void CodecPort_SetInfo(const char *strName,int open_en,int sample_rate,int channel,int bits_per_sample);
|
||||
|
||||
uint8_t *CodecPort_GetPcmData(uint32_t *len);
|
||||
|
||||
};
|
||||
|
||||
483
components/port_bsp/display_bsp.cpp
Normal file
483
components/port_bsp/display_bsp.cpp
Normal file
@@ -0,0 +1,483 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <esp_log.h>
|
||||
#include "display_bsp.h"
|
||||
|
||||
DisplayPort::DisplayPort(int mosi, int scl, int dc, int cs, int rst, int width, int height, spi_host_device_t spihost) :
|
||||
mosi_(mosi),
|
||||
scl_(scl),
|
||||
dc_(dc),
|
||||
cs_(cs),
|
||||
rst_(rst),
|
||||
width_(width),
|
||||
height_(height)
|
||||
{
|
||||
esp_err_t ret;
|
||||
spi_bus_config_t buscfg = {};
|
||||
int transfer = width_ * height_;
|
||||
buscfg.miso_io_num = -1;
|
||||
buscfg.mosi_io_num = mosi;
|
||||
buscfg.sclk_io_num = scl;
|
||||
buscfg.quadwp_io_num = -1;
|
||||
buscfg.quadhd_io_num = -1;
|
||||
buscfg.max_transfer_sz = transfer;
|
||||
ret = spi_bus_initialize(spihost, &buscfg, SPI_DMA_CH_AUTO);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
esp_lcd_panel_io_spi_config_t io_config = {};
|
||||
io_config.dc_gpio_num = dc_;
|
||||
io_config.cs_gpio_num = cs_;
|
||||
io_config.pclk_hz = 10 * 1000 * 1000;
|
||||
io_config.lcd_cmd_bits = 8;
|
||||
io_config.lcd_param_bits = 8;
|
||||
io_config.spi_mode = 0;
|
||||
io_config.trans_queue_depth = 10;
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)spihost, &io_config, &io_handle));
|
||||
|
||||
gpio_config_t gpio_conf = {};
|
||||
gpio_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
gpio_conf.mode = GPIO_MODE_OUTPUT;
|
||||
gpio_conf.pin_bit_mask = (0x1ULL << rst_);
|
||||
gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(gpio_config(&gpio_conf));
|
||||
|
||||
Set_ResetIOLevel(1);
|
||||
|
||||
DisplayLen = transfer >> 3; //(1byte 8ipex)
|
||||
DispBuffer = (uint8_t *) heap_caps_malloc(DisplayLen, MALLOC_CAP_SPIRAM);
|
||||
assert(DispBuffer);
|
||||
|
||||
#if (AlgorithmOptimization == 3)
|
||||
PixelIndexLUT = (uint16_t (*)[300])heap_caps_malloc(transfer * sizeof(uint16_t), MALLOC_CAP_SPIRAM);
|
||||
PixelBitLUT = (uint8_t (*)[300])heap_caps_malloc(transfer * sizeof(uint8_t), MALLOC_CAP_SPIRAM);
|
||||
assert(PixelIndexLUT);
|
||||
assert(PixelBitLUT);
|
||||
if(width_ == 400) {
|
||||
InitLandscapeLUT();
|
||||
} else {
|
||||
InitPortraitLUT();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
DisplayPort::~DisplayPort() {
|
||||
}
|
||||
|
||||
void DisplayPort::RLCD_Init() {
|
||||
RLCD_Reset();
|
||||
|
||||
RLCD_SendCommand(0xD6); // NVM Load Control
|
||||
RLCD_SendData(0x17);
|
||||
RLCD_SendData(0x02);
|
||||
|
||||
RLCD_SendCommand(0xD1); //Booster Enable
|
||||
RLCD_SendData(0x01);
|
||||
|
||||
RLCD_SendCommand(0xC0); //Gate Voltage Control
|
||||
RLCD_SendData(0x11);
|
||||
RLCD_SendData(0x04);
|
||||
|
||||
RLCD_SendCommand(0xC1); //VSHP Setting
|
||||
RLCD_SendData(0x41);
|
||||
RLCD_SendData(0x41);
|
||||
RLCD_SendData(0x41);
|
||||
RLCD_SendData(0x41);
|
||||
|
||||
RLCD_SendCommand(0xC2);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
|
||||
RLCD_SendCommand(0xC4);
|
||||
RLCD_SendData(0x41);
|
||||
RLCD_SendData(0x41);
|
||||
RLCD_SendData(0x41);
|
||||
RLCD_SendData(0x41);
|
||||
|
||||
RLCD_SendCommand(0xC5);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
|
||||
RLCD_SendCommand(0xD8);
|
||||
RLCD_SendData(0xA6);
|
||||
RLCD_SendData(0xE9);
|
||||
|
||||
RLCD_SendCommand(0xB2);
|
||||
RLCD_SendData(0x05);
|
||||
|
||||
RLCD_SendCommand(0xB3);
|
||||
RLCD_SendData(0xE5);
|
||||
RLCD_SendData(0xF6);
|
||||
RLCD_SendData(0x05);
|
||||
RLCD_SendData(0x46);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x76);
|
||||
RLCD_SendData(0x45);
|
||||
|
||||
RLCD_SendCommand(0xB4);
|
||||
RLCD_SendData(0x05);
|
||||
RLCD_SendData(0x46);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x76);
|
||||
RLCD_SendData(0x45);
|
||||
|
||||
RLCD_SendCommand(0x62);
|
||||
RLCD_SendData(0x32);
|
||||
RLCD_SendData(0x03);
|
||||
RLCD_SendData(0x1F);
|
||||
|
||||
RLCD_SendCommand(0xB7);
|
||||
RLCD_SendData(0x13);
|
||||
|
||||
RLCD_SendCommand(0xB0);
|
||||
RLCD_SendData(0x64);
|
||||
|
||||
RLCD_SendCommand(0x11);
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
RLCD_SendCommand(0xC9);
|
||||
RLCD_SendData(0x00);
|
||||
|
||||
RLCD_SendCommand(0x36);
|
||||
RLCD_SendData(0x48);
|
||||
|
||||
RLCD_SendCommand(0x3A);
|
||||
RLCD_SendData(0x11);
|
||||
|
||||
RLCD_SendCommand(0xB9);
|
||||
RLCD_SendData(0x20);
|
||||
|
||||
RLCD_SendCommand(0xB8);
|
||||
RLCD_SendData(0x29);
|
||||
|
||||
RLCD_SendCommand(0x21);
|
||||
|
||||
RLCD_SendCommand(0x2A);
|
||||
RLCD_SendData(0x12);
|
||||
RLCD_SendData(0x2A);
|
||||
|
||||
RLCD_SendCommand(0x2B);
|
||||
RLCD_SendData(0x00);
|
||||
RLCD_SendData(0xC7);
|
||||
|
||||
RLCD_SendCommand(0x35);
|
||||
RLCD_SendData(0x00);
|
||||
|
||||
RLCD_SendCommand(0xD0);
|
||||
RLCD_SendData(0xFF);
|
||||
|
||||
RLCD_SendCommand(0x38);
|
||||
RLCD_SendCommand(0x29);
|
||||
|
||||
RLCD_ColorClear(ColorWhite);
|
||||
}
|
||||
|
||||
void DisplayPort::RLCD_ColorClear(uint8_t color) {
|
||||
memset(DispBuffer, color, DisplayLen);
|
||||
}
|
||||
|
||||
void DisplayPort::RLCD_Display() {
|
||||
RLCD_SendCommand(0x2A); // Column Address Set
|
||||
RLCD_SendData(0x12);
|
||||
RLCD_SendData(0x2A);
|
||||
|
||||
RLCD_SendCommand(0x2B); // Page Address Set
|
||||
RLCD_SendData(0x00);
|
||||
RLCD_SendData(0xC7);
|
||||
|
||||
RLCD_SendCommand(0x2c); // Page Address Set
|
||||
|
||||
RLCD_Sendbuffera(DispBuffer,DisplayLen);
|
||||
}
|
||||
|
||||
void DisplayPort::RLCD_Reset(void) {
|
||||
Set_ResetIOLevel(1);
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
Set_ResetIOLevel(0);
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
Set_ResetIOLevel(1);
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
}
|
||||
|
||||
void DisplayPort::RLCD_SendCommand(uint8_t Reg) {
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_io_tx_param(io_handle, Reg, NULL, 0));
|
||||
}
|
||||
|
||||
void DisplayPort::RLCD_SendData(uint8_t Data) {
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_io_tx_param(io_handle, -1, &Data, 1));
|
||||
}
|
||||
|
||||
void DisplayPort::RLCD_Sendbuffera(uint8_t *Data, int len) {
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_io_tx_color(io_handle, -1, Data, len));
|
||||
}
|
||||
|
||||
void DisplayPort::Set_ResetIOLevel(uint8_t level) {
|
||||
gpio_set_level((gpio_num_t) rst_, level ? 1 : 0);
|
||||
}
|
||||
#if (AlgorithmOptimization != 3)
|
||||
|
||||
void DisplayPort::RLCD_SetPortraitPixel(uint16_t x, uint16_t y, uint8_t color) {
|
||||
if((x >= width_) || (y >= height_)) {
|
||||
ESP_LOGE("Pixel","Beyond the limit : (%d,%d)",x ,y);
|
||||
return;
|
||||
}
|
||||
#if (AlgorithmOptimization == 2)
|
||||
const uint16_t W4 = width_ >> 2;
|
||||
|
||||
uint16_t byte_x = x >> 2;
|
||||
uint16_t byte_y = y >> 1;
|
||||
|
||||
uint32_t index = byte_y * W4 + byte_x;
|
||||
|
||||
uint8_t local_x = x & 0x03;
|
||||
uint8_t local_y = y & 0x01;
|
||||
|
||||
uint8_t bit = 7 - ((local_x << 1) | local_y);
|
||||
|
||||
uint8_t mask = 1 << bit;
|
||||
|
||||
if (color)
|
||||
DispBuffer[index] |= mask;
|
||||
else
|
||||
DispBuffer[index] &= ~mask;
|
||||
#else
|
||||
uint16_t byte_x = x / 4;
|
||||
uint16_t byte_y = y / 2;
|
||||
|
||||
uint32_t index = byte_y * (width_ / 4) + byte_x;
|
||||
|
||||
uint8_t local_x = x % 4;
|
||||
uint8_t local_y = y % 2;
|
||||
uint8_t bit = 7 - (local_x * 2 + local_y);
|
||||
if (color)
|
||||
DispBuffer[index] |= (1 << bit);
|
||||
else
|
||||
DispBuffer[index] &= ~(1 << bit);
|
||||
#endif
|
||||
}
|
||||
|
||||
void DisplayPort::RLCD_SetLandscapePixel(uint16_t x, uint16_t y, uint8_t color) {
|
||||
if (x >= width_ || y >= height_)
|
||||
return;
|
||||
#if (AlgorithmOptimization == 2)
|
||||
|
||||
uint16_t inv_y = (height_ - 1 - y);
|
||||
const uint16_t H4 = height_ >> 2;
|
||||
uint16_t byte_x = x >> 1;
|
||||
uint16_t block_y = inv_y >> 2;
|
||||
uint32_t index = byte_x * H4 + block_y;
|
||||
uint8_t local_x = x & 0x01;
|
||||
uint8_t local_y = inv_y & 0x03;
|
||||
uint8_t bit = 7 - ((local_y << 1) | local_x);
|
||||
uint8_t mask = 1 << bit;
|
||||
if (color)
|
||||
DispBuffer[index] |= mask;
|
||||
else
|
||||
DispBuffer[index] &= ~mask;
|
||||
#else
|
||||
uint16_t inv_y = height_ - 1 - y;
|
||||
|
||||
uint16_t byte_x = x / 2; // 0..199
|
||||
uint16_t block_y = inv_y / 4; // 0..74
|
||||
|
||||
uint32_t index = byte_x * (height_ / 4) + block_y;
|
||||
|
||||
uint8_t local_x = x % 2; // 0 or 1
|
||||
uint8_t local_y = inv_y % 4; // 0..3
|
||||
|
||||
uint8_t bit = 7 - (local_y * 2 + local_x);
|
||||
|
||||
if (color)
|
||||
DispBuffer[index] |= (1 << bit);
|
||||
else
|
||||
DispBuffer[index] &= ~(1 << bit);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if (AlgorithmOptimization == 3)
|
||||
|
||||
void DisplayPort::InitPortraitLUT() {
|
||||
uint16_t W4 = width_ >> 2;
|
||||
for (uint16_t y = 0; y < height_; y++)
|
||||
{
|
||||
uint16_t byte_y = y >> 1;
|
||||
uint8_t local_y = y & 1;
|
||||
|
||||
for (uint16_t x = 0; x < width_; x++)
|
||||
{
|
||||
uint16_t byte_x = x >> 2;
|
||||
uint8_t local_x = x & 3;
|
||||
|
||||
uint32_t index = byte_y * W4 + byte_x;
|
||||
uint8_t bit = 7 - ((local_x << 1) | local_y);
|
||||
|
||||
PixelIndexLUT[x][y] = index;
|
||||
PixelBitLUT [x][y] = (1 << bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayPort::InitLandscapeLUT() {
|
||||
uint16_t H4 = height_ >> 2;
|
||||
|
||||
for (uint16_t y = 0; y < height_; y++)
|
||||
{
|
||||
uint16_t inv_y = height_ - 1 - y;
|
||||
uint16_t block_y = inv_y >> 2;
|
||||
uint8_t local_y = inv_y & 3;
|
||||
|
||||
for (uint16_t x = 0; x < width_; x++)
|
||||
{
|
||||
uint16_t byte_x = x >> 1;
|
||||
uint8_t local_x = x & 1;
|
||||
|
||||
uint32_t index = byte_x * H4 + block_y;
|
||||
uint8_t bit = 7 - ((local_y << 1) | local_x);
|
||||
|
||||
PixelIndexLUT[x][y] = index;
|
||||
PixelBitLUT [x][y] = (1 << bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayPort::RLCD_SetPixel(uint16_t x, uint16_t y, uint8_t color) {
|
||||
uint32_t idx = PixelIndexLUT[x][y];
|
||||
uint8_t mask = PixelBitLUT[x][y];
|
||||
|
||||
uint8_t *p = &DispBuffer[idx];
|
||||
|
||||
if (color)
|
||||
*p |= mask;
|
||||
else
|
||||
*p &= ~mask;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
RLCD_SendCommand(0xD6); // NVM Load Control
|
||||
RLCD_SendData(0x17);
|
||||
RLCD_SendData(0x02);
|
||||
|
||||
RLCD_SendCommand(0xD1); //Booster Enable
|
||||
RLCD_SendData(0x01);
|
||||
|
||||
RLCD_SendCommand(0xC0); //Gate Voltage Control
|
||||
RLCD_SendData(0x11);
|
||||
RLCD_SendData(0x04);
|
||||
|
||||
RLCD_SendCommand(0xC1); //VSHP Setting
|
||||
RLCD_SendData(0x41);
|
||||
RLCD_SendData(0x41);
|
||||
RLCD_SendData(0x41);
|
||||
RLCD_SendData(0x41);
|
||||
|
||||
RLCD_SendCommand(0xC2);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
|
||||
RLCD_SendCommand(0xC4);
|
||||
RLCD_SendData(0x41);
|
||||
RLCD_SendData(0x41);
|
||||
RLCD_SendData(0x41);
|
||||
RLCD_SendData(0x41);
|
||||
|
||||
RLCD_SendCommand(0xC5);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
RLCD_SendData(0x19);
|
||||
|
||||
RLCD_SendCommand(0xD8);
|
||||
RLCD_SendData(0xA6);
|
||||
RLCD_SendData(0xE9);
|
||||
|
||||
RLCD_SendCommand(0xB2);
|
||||
RLCD_SendData(0x05);
|
||||
|
||||
RLCD_SendCommand(0xB3);
|
||||
RLCD_SendData(0xE5);
|
||||
RLCD_SendData(0xF6);
|
||||
RLCD_SendData(0x05);
|
||||
RLCD_SendData(0x46);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x76);
|
||||
RLCD_SendData(0x45);
|
||||
|
||||
RLCD_SendCommand(0xB4);
|
||||
RLCD_SendData(0x05);
|
||||
RLCD_SendData(0x46);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x77);
|
||||
RLCD_SendData(0x76);
|
||||
RLCD_SendData(0x45);
|
||||
|
||||
RLCD_SendCommand(0x62);
|
||||
RLCD_SendData(0x32);
|
||||
RLCD_SendData(0x03);
|
||||
RLCD_SendData(0x1F);
|
||||
|
||||
RLCD_SendCommand(0xB7);
|
||||
RLCD_SendData(0x13);
|
||||
|
||||
RLCD_SendCommand(0xB0);
|
||||
RLCD_SendData(0x64);
|
||||
|
||||
RLCD_SendCommand(0x11);
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
RLCD_SendCommand(0xC9);
|
||||
RLCD_SendData(0x00);
|
||||
|
||||
RLCD_SendCommand(0x36);
|
||||
RLCD_SendData(0x48);
|
||||
|
||||
RLCD_SendCommand(0x3A);
|
||||
RLCD_SendData(0x11);
|
||||
|
||||
RLCD_SendCommand(0xB9);
|
||||
RLCD_SendData(0x20);
|
||||
|
||||
RLCD_SendCommand(0xB8);
|
||||
RLCD_SendData(0x29);
|
||||
|
||||
RLCD_SendCommand(0x21);
|
||||
|
||||
RLCD_SendCommand(0x2A);
|
||||
RLCD_SendData(0x12);
|
||||
RLCD_SendData(0x2A);
|
||||
|
||||
RLCD_SendCommand(0x2B);
|
||||
RLCD_SendData(0x00);
|
||||
RLCD_SendData(0xC7);
|
||||
|
||||
RLCD_SendCommand(0x35);
|
||||
RLCD_SendData(0x00);
|
||||
|
||||
RLCD_SendCommand(0xD0);
|
||||
RLCD_SendData(0xFF);
|
||||
|
||||
RLCD_SendCommand(0x38);
|
||||
RLCD_SendCommand(0x29);
|
||||
#endif
|
||||
58
components/port_bsp/display_bsp.h
Normal file
58
components/port_bsp/display_bsp.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_vendor.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
|
||||
|
||||
#define AlgorithmOptimization 3 //1:原始算法 2:采用移位算法 3:查表法 来优化CPU
|
||||
|
||||
enum ColorSelection {
|
||||
ColorBlack = 0,
|
||||
ColorWhite = 0xff
|
||||
};
|
||||
|
||||
class DisplayPort {
|
||||
private:
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
uint32_t i2c_data_pdMS_TICKS = 0;
|
||||
uint32_t i2c_done_pdMS_TICKS = 0;
|
||||
const char *TAG = "Display";
|
||||
int mosi_;
|
||||
int scl_;
|
||||
int dc_;
|
||||
int cs_;
|
||||
int rst_;
|
||||
int width_;
|
||||
int height_;
|
||||
uint8_t *DispBuffer = NULL;
|
||||
int DisplayLen;
|
||||
#if (AlgorithmOptimization == 3)
|
||||
uint16_t (*PixelIndexLUT)[300];
|
||||
uint8_t (*PixelBitLUT )[300];
|
||||
void InitPortraitLUT();
|
||||
void InitLandscapeLUT();
|
||||
#endif
|
||||
|
||||
void Set_ResetIOLevel(uint8_t level);
|
||||
void RLCD_SendCommand(uint8_t Reg);
|
||||
void RLCD_SendData(uint8_t Data);
|
||||
void RLCD_Sendbuffera(uint8_t *Data, int len);
|
||||
void RLCD_Reset(void);
|
||||
|
||||
public:
|
||||
DisplayPort(int mosi, int scl, int dc, int cs, int rst, int width, int height, spi_host_device_t spihost = SPI3_HOST);
|
||||
~DisplayPort();
|
||||
void RLCD_Init();
|
||||
void RLCD_ColorClear(uint8_t color);
|
||||
void RLCD_Display();
|
||||
#if (AlgorithmOptimization != 3)
|
||||
void RLCD_SetPortraitPixel(uint16_t x, uint16_t y, uint8_t color); //竖屏显示
|
||||
void RLCD_SetLandscapePixel(uint16_t x, uint16_t y, uint8_t color); //横屏显示
|
||||
#endif
|
||||
#if (AlgorithmOptimization == 3)
|
||||
void RLCD_SetPixel(uint16_t x, uint16_t y, uint8_t color);
|
||||
#endif
|
||||
};
|
||||
73
components/port_bsp/i2c_bsp.cpp
Normal file
73
components/port_bsp/i2c_bsp.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#include <stdio.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include "i2c_bsp.h"
|
||||
|
||||
static uint32_t i2c_data_pdMS_TICKS = 0;
|
||||
static uint32_t i2c_done_pdMS_TICKS = 0;
|
||||
|
||||
I2cMasterBus::I2cMasterBus(int scl_pin,int sda_pin,int i2c_port) {
|
||||
i2c_data_pdMS_TICKS = pdMS_TO_TICKS(5000);
|
||||
i2c_done_pdMS_TICKS = pdMS_TO_TICKS(1000);
|
||||
|
||||
i2c_master_bus_config_t i2c_bus_config = {};
|
||||
i2c_bus_config.clk_source = I2C_CLK_SRC_DEFAULT;
|
||||
i2c_bus_config.i2c_port = (i2c_port_t)i2c_port;
|
||||
i2c_bus_config.scl_io_num = (gpio_num_t)scl_pin;
|
||||
i2c_bus_config.sda_io_num = (gpio_num_t)sda_pin;
|
||||
i2c_bus_config.glitch_ignore_cnt = 7;
|
||||
i2c_bus_config.flags.enable_internal_pullup = true;
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_config, &user_i2c_handle));
|
||||
}
|
||||
|
||||
I2cMasterBus::~I2cMasterBus() {
|
||||
|
||||
}
|
||||
|
||||
int I2cMasterBus::i2c_write_buff(i2c_master_dev_handle_t dev_handle, int reg, uint8_t *buf, uint8_t len) {
|
||||
int ret;
|
||||
uint8_t *pbuf = NULL;
|
||||
ret = i2c_master_bus_wait_all_done(user_i2c_handle, i2c_done_pdMS_TICKS);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
if (reg == -1) {
|
||||
ret = i2c_master_transmit(dev_handle, buf, len, i2c_data_pdMS_TICKS);
|
||||
} else {
|
||||
pbuf = (uint8_t *) malloc(len + 1);
|
||||
pbuf[0] = reg;
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
pbuf[i + 1] = buf[i];
|
||||
}
|
||||
ret = i2c_master_transmit(dev_handle, pbuf, len + 1, i2c_data_pdMS_TICKS);
|
||||
free(pbuf);
|
||||
pbuf = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int I2cMasterBus::i2c_master_write_read_dev(i2c_master_dev_handle_t dev_handle, uint8_t *writeBuf, uint8_t writeLen, uint8_t *readBuf, uint8_t readLen) {
|
||||
int ret;
|
||||
ret = i2c_master_bus_wait_all_done(user_i2c_handle, i2c_done_pdMS_TICKS);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
ret = i2c_master_transmit_receive(dev_handle, writeBuf, writeLen, readBuf, readLen, i2c_data_pdMS_TICKS);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int I2cMasterBus::i2c_read_buff(i2c_master_dev_handle_t dev_handle, int reg, uint8_t *buf, uint8_t len) {
|
||||
int ret;
|
||||
uint8_t addr = 0;
|
||||
ret = i2c_master_bus_wait_all_done(user_i2c_handle, i2c_done_pdMS_TICKS);
|
||||
if (ret != ESP_OK)
|
||||
return ret;
|
||||
if (reg == -1) {
|
||||
ret = i2c_master_receive(dev_handle, buf, len, i2c_data_pdMS_TICKS);
|
||||
} else {
|
||||
addr = (uint8_t) reg;
|
||||
ret = i2c_master_transmit_receive(dev_handle, &addr, 1, buf, len, i2c_data_pdMS_TICKS);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_master_bus_handle_t I2cMasterBus::Get_I2cBusHandle() {
|
||||
return user_i2c_handle;
|
||||
}
|
||||
20
components/port_bsp/i2c_bsp.h
Normal file
20
components/port_bsp/i2c_bsp.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef I2C_BSP_H
|
||||
#define I2C_BSP_H
|
||||
|
||||
#include <driver/i2c_master.h>
|
||||
|
||||
class I2cMasterBus
|
||||
{
|
||||
private:
|
||||
i2c_master_bus_handle_t user_i2c_handle = NULL;
|
||||
public:
|
||||
I2cMasterBus(int scl_pin,int sda_pin,int i2c_port);
|
||||
~I2cMasterBus();
|
||||
|
||||
int i2c_write_buff(i2c_master_dev_handle_t dev_handle,int reg,uint8_t *buf,uint8_t len);
|
||||
int i2c_master_write_read_dev(i2c_master_dev_handle_t dev_handle,uint8_t *writeBuf,uint8_t writeLen,uint8_t *readBuf,uint8_t readLen);
|
||||
int i2c_read_buff(i2c_master_dev_handle_t dev_handle,int reg,uint8_t *buf,uint8_t len);
|
||||
i2c_master_bus_handle_t Get_I2cBusHandle();
|
||||
};
|
||||
|
||||
#endif
|
||||
229
components/port_bsp/i2c_equipment.cpp
Normal file
229
components/port_bsp/i2c_equipment.cpp
Normal file
@@ -0,0 +1,229 @@
|
||||
#include <stdio.h>
|
||||
#include <esp_log.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include "i2c_equipment.h"
|
||||
#include "i2c_bsp.h"
|
||||
#include "SensorPCF85063.hpp"
|
||||
|
||||
Shtc3Port::Shtc3Port(I2cMasterBus& i2cbus) :
|
||||
i2cbus_(i2cbus) {
|
||||
i2c_master_bus_handle_t I2cMasterBus = i2cbus_.Get_I2cBusHandle();
|
||||
i2c_device_config_t dev_cfg = {};
|
||||
dev_cfg.dev_addr_length = I2C_ADDR_BIT_LEN_7;
|
||||
dev_cfg.device_address = Shtc3Address;
|
||||
dev_cfg.scl_speed_hz = 400000;
|
||||
ESP_ERROR_CHECK(i2c_master_bus_add_device(I2cMasterBus, &dev_cfg, &I2c_DevShtc3));
|
||||
|
||||
Shtc3_Wakeup();
|
||||
Shtc3_SoftReset();
|
||||
vTaskDelay(pdMS_TO_TICKS(20)); //20MS
|
||||
Shtc3_GetId();
|
||||
ESP_LOGI(TAG, "ID:%04x", shtc3_id);
|
||||
}
|
||||
|
||||
Shtc3Port::~Shtc3Port() {
|
||||
}
|
||||
|
||||
etError Shtc3Port::Shtc3_GetId() {
|
||||
uint8_t senBuf[2] = {(READ_ID >> 8), (READ_ID & 0xff)};
|
||||
uint8_t readBuf[3] = {0, 0, 0};
|
||||
int err = i2cbus_.i2c_master_write_read_dev(I2c_DevShtc3, senBuf, 2, readBuf, 3);
|
||||
etError error = (err == ESP_OK) ? NO_ERROR : ACK_ERROR;
|
||||
if (error != NO_ERROR) {
|
||||
ESP_LOGE("shtc3", "GetId WRITE Failure");
|
||||
return error;
|
||||
}
|
||||
error = Shtc3_CheckCrc(readBuf, 2, readBuf[2]);
|
||||
if (error != NO_ERROR) {
|
||||
ESP_LOGE("shtc3", "GetId CRC Failure");
|
||||
return error;
|
||||
}
|
||||
shtc3_id = ((readBuf[0] << 8) | readBuf[1]);
|
||||
return error;
|
||||
}
|
||||
|
||||
uint16_t Shtc3Port::Shtc3_GetShtc3Id() {
|
||||
return shtc3_id;
|
||||
}
|
||||
|
||||
// wake up the sensor from sleep mode
|
||||
etError Shtc3Port::Shtc3_Wakeup() {
|
||||
uint8_t senBuf[2] = {(WAKEUP >> 8), (WAKEUP & 0xff)};
|
||||
int err = i2cbus_.i2c_write_buff(I2c_DevShtc3, -1, senBuf, 2);
|
||||
etError error = (err == ESP_OK) ? NO_ERROR : ACK_ERROR;
|
||||
//esp_rom_delay_us(100); //100us
|
||||
vTaskDelay(pdMS_TO_TICKS(50)); //50MS
|
||||
if (error != NO_ERROR)
|
||||
ESP_LOGE("shtc3", "Wakeup Failure");
|
||||
return error;
|
||||
}
|
||||
|
||||
etError Shtc3Port::Shtc3_SoftReset() {
|
||||
uint8_t senBuf[2] = {(SOFT_RESET >> 8), (SOFT_RESET & 0xff)};
|
||||
int err = i2cbus_.i2c_write_buff(I2c_DevShtc3, -1, senBuf, 2);
|
||||
etError error = (err == ESP_OK) ? NO_ERROR : ACK_ERROR;
|
||||
if (error != NO_ERROR)
|
||||
ESP_LOGE("shtc3", "SoftReset Failure");
|
||||
return error;
|
||||
}
|
||||
|
||||
etError Shtc3Port::Shtc3_CheckCrc(uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum) {
|
||||
uint8_t bit; // bit mask
|
||||
uint8_t crc = 0xFF; // calculated checksum
|
||||
uint8_t byteCtr; // byte counter
|
||||
|
||||
// calculates 8-Bit checksum with given polynomial
|
||||
for (byteCtr = 0; byteCtr < nbrOfBytes; byteCtr++) {
|
||||
crc ^= (data[byteCtr]);
|
||||
for (bit = 8; bit > 0; --bit) {
|
||||
if (crc & 0x80) {
|
||||
crc = (crc << 1) ^ CRC_POLYNOMIAL;
|
||||
} else {
|
||||
crc = (crc << 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// verify checksum
|
||||
if (crc != checksum) {
|
||||
return CHECKSUM_ERROR;
|
||||
} else {
|
||||
return NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
float Shtc3Port::Shtc3_CalcTemperature(uint16_t rawValue) {
|
||||
// calculate temperature [°C]
|
||||
// T = -45 + 175 * rawValue / 2^16
|
||||
return 175 * (float) rawValue / 65536.0f - 45.0f - SHTC3_PETP_VOL;
|
||||
}
|
||||
|
||||
float Shtc3Port::Shtc3_CalcHumidity(uint16_t rawValue) {
|
||||
// calculate relative humidity [%RH]
|
||||
// RH = rawValue / 2^16 * 100
|
||||
return 100 * (float) rawValue / 65536.0f;
|
||||
}
|
||||
|
||||
etError Shtc3Port::Shtc3_GetTempAndHumiPolling(float *temp, float *humi) {
|
||||
int err = 0;
|
||||
etError error; // error code
|
||||
uint16_t rawValueTemp; // temperature raw value from sensor
|
||||
uint16_t rawValueHumi; // humidity raw value from sensor
|
||||
uint8_t bytes[6] = {0};
|
||||
;
|
||||
uint8_t senBuf[2] = {(MEAS_T_RH_POLLING >> 8), (MEAS_T_RH_POLLING & 0xff)};
|
||||
err = i2cbus_.i2c_write_buff(I2c_DevShtc3, -1, senBuf, 2);
|
||||
error = (err == ESP_OK) ? NO_ERROR : ACK_ERROR;
|
||||
if (error != NO_ERROR) {
|
||||
ESP_LOGE("shtc3", "GetTempAndHumi WRITE Failure");
|
||||
return error;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
|
||||
// if no error, read temperature and humidity raw values
|
||||
err = i2cbus_.i2c_read_buff(I2c_DevShtc3, -1, bytes, 6);
|
||||
error = (err == ESP_OK) ? NO_ERROR : ACK_ERROR;
|
||||
if (error != NO_ERROR) {
|
||||
ESP_LOGE("shtc3", "GetTempAndHumi READ Failure");
|
||||
return error;
|
||||
}
|
||||
error = Shtc3_CheckCrc(bytes, 2, bytes[2]);
|
||||
if (error != NO_ERROR) {
|
||||
ESP_LOGE("shtc3", "GetTempAndHumi TempCRC Failure");
|
||||
return error;
|
||||
}
|
||||
error = Shtc3_CheckCrc(&bytes[3], 2, bytes[5]);
|
||||
if (error != NO_ERROR) {
|
||||
ESP_LOGE("shtc3", "GetTempAndHumi humidityCRC Failure");
|
||||
return error;
|
||||
}
|
||||
// if no error, calculate temperature in °C and humidity in %RH
|
||||
rawValueTemp = (bytes[0] << 8) | bytes[1];
|
||||
rawValueHumi = (bytes[3] << 8) | bytes[4];
|
||||
*temp = Shtc3_CalcTemperature(rawValueTemp);
|
||||
*humi = Shtc3_CalcHumidity(rawValueHumi);
|
||||
return error;
|
||||
}
|
||||
|
||||
etError Shtc3Port::Shtc3_Sleep() {
|
||||
uint8_t senBuf[2] = {(SLEEP >> 8), (SLEEP & 0xff)};
|
||||
int err = i2cbus_.i2c_write_buff(I2c_DevShtc3, -1, senBuf, 2);
|
||||
etError error = (err == ESP_OK) ? NO_ERROR : ACK_ERROR;
|
||||
if (error != NO_ERROR)
|
||||
ESP_LOGE("shtc3", "Sleep Failure");
|
||||
return error;
|
||||
}
|
||||
|
||||
uint8_t Shtc3Port::Shtc3_ReadTempHumi(float *t,float *h) {
|
||||
etError error;
|
||||
Shtc3_Wakeup();
|
||||
error = Shtc3_GetTempAndHumiPolling(t, h);
|
||||
if (error != NO_ERROR) {
|
||||
ESP_LOGW("shtc3", "error:%d", error);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
Shtc3_Sleep();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static i2c_master_dev_handle_t I2cRTCdev = NULL;
|
||||
static uint8_t I2cRTCAddress;
|
||||
static I2cMasterBus *I2cbus_ = NULL;
|
||||
SensorPCF85063 rtc;
|
||||
|
||||
static bool I2cDevCallback(uint8_t address, uint8_t reg, uint8_t *buf, size_t len, bool writeReg, bool isWrite) {
|
||||
int ret;
|
||||
i2c_master_dev_handle_t dev_handle = NULL;
|
||||
dev_handle = I2cRTCdev;
|
||||
if (isWrite) {
|
||||
if (writeReg) {
|
||||
ret = I2cbus_->i2c_write_buff(dev_handle, reg, buf, len);
|
||||
} else {
|
||||
ret = I2cbus_->i2c_write_buff(dev_handle, -1, buf, len);
|
||||
}
|
||||
} else {
|
||||
if (writeReg) {
|
||||
ret = I2cbus_->i2c_read_buff(dev_handle, reg, buf, len);
|
||||
} else {
|
||||
ret = I2cbus_->i2c_read_buff(dev_handle, -1, buf, len);
|
||||
}
|
||||
}
|
||||
return (ret == ESP_OK) ? true : false;
|
||||
}
|
||||
|
||||
void Rtc_Setup(I2cMasterBus *i2cbus,uint8_t dev_addr) {
|
||||
if (I2cbus_ == NULL) {
|
||||
I2cbus_ = i2cbus;
|
||||
}
|
||||
if (I2cRTCdev == NULL) {
|
||||
i2c_master_bus_handle_t BusHandle = i2cbus->Get_I2cBusHandle();
|
||||
i2c_device_config_t dev_cfg = {};
|
||||
dev_cfg.dev_addr_length = I2C_ADDR_BIT_LEN_7;
|
||||
dev_cfg.scl_speed_hz = 300000;
|
||||
dev_cfg.device_address = dev_addr;
|
||||
ESP_ERROR_CHECK(i2c_master_bus_add_device(BusHandle, &dev_cfg, &I2cRTCdev));
|
||||
I2cRTCAddress = dev_addr;
|
||||
}
|
||||
if (rtc.begin(I2cDevCallback)) {
|
||||
ESP_LOGI("rtc", "InitWill");
|
||||
} else {
|
||||
ESP_LOGE("rtc", "InitFailure");
|
||||
}
|
||||
}
|
||||
|
||||
void Rtc_SetTime(uint16_t year,uint8_t month,uint8_t day,uint8_t hour,uint8_t minute,uint8_t second) {
|
||||
rtc.setDateTime(year, month, day, hour, minute, second);
|
||||
}
|
||||
|
||||
void Rtc_GetTime(rtcTimeStruct_t *time) {
|
||||
RTC_DateTime datetime = rtc.getDateTime();
|
||||
time->year = datetime.getYear();
|
||||
time->month = datetime.getMonth();
|
||||
time->day = datetime.getDay();
|
||||
time->hour = datetime.getHour();
|
||||
time->minute = datetime.getMinute();
|
||||
time->second = datetime.getSecond();
|
||||
time->week = datetime.getWeek();
|
||||
}
|
||||
69
components/port_bsp/i2c_equipment.h
Normal file
69
components/port_bsp/i2c_equipment.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#ifndef I2C_EQUIPMENT_H
|
||||
#define I2C_EQUIPMENT_H
|
||||
|
||||
|
||||
#include "i2c_bsp.h"
|
||||
|
||||
typedef enum{
|
||||
NO_ERROR = 0x00, // no error
|
||||
ACK_ERROR = 0x01, // no acknowledgment error
|
||||
CHECKSUM_ERROR = 0x02 // checksum mismatch error
|
||||
}etError;
|
||||
|
||||
typedef enum{
|
||||
READ_ID = 0xEFC8, // command: read ID register
|
||||
SOFT_RESET = 0x805D, // soft reset
|
||||
SLEEP = 0xB098, // sleep
|
||||
WAKEUP = 0x3517, // wakeup
|
||||
MEAS_T_RH_POLLING = 0x7866, // meas. read T first, clock stretching disabled
|
||||
MEAS_T_RH_CLOCKSTR = 0x7CA2, // meas. read T first, clock stretching enabled
|
||||
MEAS_RH_T_POLLING = 0x58E0, // meas. read RH first, clock stretching disabled
|
||||
MEAS_RH_T_CLOCKSTR = 0x5C24 // meas. read RH first, clock stretching enabled
|
||||
}etCommands;
|
||||
|
||||
|
||||
class Shtc3Port
|
||||
{
|
||||
private:
|
||||
const char *TAG = "SHTC3";
|
||||
uint16_t shtc3_id = 0x00;
|
||||
const uint16_t CRC_POLYNOMIAL = 0x131;
|
||||
const uint8_t SHTC3_PETP_VOL = 4;
|
||||
const uint8_t Shtc3Address = 0x70;
|
||||
I2cMasterBus& i2cbus_;
|
||||
i2c_master_dev_handle_t I2c_DevShtc3;
|
||||
|
||||
etError Shtc3_GetId();
|
||||
etError Shtc3_CheckCrc(uint8_t data[], uint8_t nbrOfBytes,uint8_t checksum);
|
||||
etError Shtc3_GetTempAndHumiPolling(float *temp, float *humi);
|
||||
float Shtc3_CalcTemperature(uint16_t rawValue);
|
||||
float Shtc3_CalcHumidity(uint16_t rawValue);
|
||||
|
||||
public:
|
||||
Shtc3Port(I2cMasterBus& i2cbus);
|
||||
~Shtc3Port();
|
||||
|
||||
etError Shtc3_Wakeup();
|
||||
etError Shtc3_Sleep();
|
||||
etError Shtc3_SoftReset();
|
||||
uint16_t Shtc3_GetShtc3Id();
|
||||
uint8_t Shtc3_ReadTempHumi(float *t,float *h);
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int year;
|
||||
int month;
|
||||
int day;
|
||||
int hour;
|
||||
int minute;
|
||||
int second;
|
||||
int week;
|
||||
}rtcTimeStruct_t;
|
||||
|
||||
void Rtc_Setup(I2cMasterBus *i2cbus,uint8_t dev_addr);
|
||||
void Rtc_SetTime(uint16_t year,uint8_t month,uint8_t day,uint8_t hour,uint8_t minute,uint8_t second);
|
||||
void Rtc_GetTime(rtcTimeStruct_t *time);
|
||||
|
||||
#endif
|
||||
BIN
components/port_bsp/pcm/canon.pcm
Normal file
BIN
components/port_bsp/pcm/canon.pcm
Normal file
Binary file not shown.
144
components/port_bsp/sdcard_bsp.cpp
Normal file
144
components/port_bsp/sdcard_bsp.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
#include <stdio.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include "sdcard_bsp.h"
|
||||
|
||||
CustomSDPort::CustomSDPort(const char *SdName,int clk,int cmd,int d0,int width) :
|
||||
SdName_(SdName)
|
||||
{
|
||||
esp_vfs_fat_sdmmc_mount_config_t mount_config = {};
|
||||
mount_config.format_if_mount_failed = false;
|
||||
mount_config.max_files = 5;
|
||||
mount_config.allocation_unit_size = 16 * 1024 * 3;
|
||||
|
||||
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
|
||||
|
||||
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
|
||||
slot_config.width = width;
|
||||
slot_config.clk = (gpio_num_t)clk;
|
||||
slot_config.cmd = (gpio_num_t)cmd;
|
||||
slot_config.d0 = (gpio_num_t)d0;
|
||||
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_vfs_fat_sdmmc_mount(SdName_, &host, &slot_config, &mount_config, &sdcard_host));
|
||||
|
||||
if (sdcard_host != NULL) {
|
||||
sdmmc_card_print_info(stdout, sdcard_host);
|
||||
is_SdcardInitOK = 1;
|
||||
} else {
|
||||
is_SdcardInitOK = 0;
|
||||
}
|
||||
}
|
||||
|
||||
CustomSDPort::~CustomSDPort() {
|
||||
|
||||
}
|
||||
|
||||
int CustomSDPort::SDPort_WriteFile(const char *path, const void *data, size_t data_len) {
|
||||
if (sdcard_host == NULL) {
|
||||
ESP_LOGE(TAG, "SD card not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (sdmmc_get_status(sdcard_host) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SD card not ready");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
FILE *f = fopen(path, "wb");
|
||||
if (f == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to open file for writing: %s", path);
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
size_t written = fwrite(data, 1, data_len, f);
|
||||
fclose(f);
|
||||
|
||||
if (written != data_len) {
|
||||
ESP_LOGE(TAG, "Write failed (%zu/%zu bytes)", written, data_len);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int CustomSDPort::SDPort_ReadFile(const char *path, uint8_t *buffer, size_t *outLen) {
|
||||
if (sdcard_host == NULL) {
|
||||
ESP_LOGE(TAG, "SD card not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (sdmmc_get_status(sdcard_host) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SD card not ready");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (f == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to open file: %s", path);
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
long file_size = ftell(f);
|
||||
if (file_size <= 0) {
|
||||
ESP_LOGE(TAG, "Invalid file size");
|
||||
fclose(f);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
size_t bytes_read = fread(buffer, 1, file_size, f);
|
||||
fclose(f);
|
||||
|
||||
if (outLen) *outLen = bytes_read;
|
||||
return (bytes_read > 0) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
int CustomSDPort::SDPort_ReadOffset(const char *path, void *buffer, size_t len, size_t offset) {
|
||||
if (sdcard_host == NULL) {
|
||||
ESP_LOGE(TAG, "SD card not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (sdmmc_get_status(sdcard_host) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SD card not ready");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (f == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to open file: %s", path);
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
fseek(f, offset, SEEK_SET);
|
||||
size_t bytes_read = fread(buffer, 1, len, f);
|
||||
fclose(f);
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
int CustomSDPort::SDPort_WriteOffset(const char *path, const void *data, size_t len, bool append) {
|
||||
if (sdcard_host == NULL) {
|
||||
ESP_LOGE(TAG, "SD card not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (sdmmc_get_status(sdcard_host) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SD card not ready");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
const char *mode = append ? "ab" : "wb";
|
||||
FILE *f = fopen(path, mode);
|
||||
if (f == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to open file: %s", path);
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
size_t bytes_written = fwrite(data, 1, len, f);
|
||||
fclose(f);
|
||||
|
||||
if (!append && len == 0) {
|
||||
ESP_LOGI(TAG, "File cleared: %s", path);
|
||||
return ESP_OK;
|
||||
}
|
||||
return bytes_written;
|
||||
}
|
||||
23
components/port_bsp/sdcard_bsp.h
Normal file
23
components/port_bsp/sdcard_bsp.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <esp_vfs_fat.h>
|
||||
#include <sdmmc_cmd.h>
|
||||
#include <driver/sdmmc_host.h>
|
||||
|
||||
class CustomSDPort
|
||||
{
|
||||
private:
|
||||
const char *TAG = "SDPort";
|
||||
const char *SdName_;
|
||||
int is_SdcardInitOK = 0;
|
||||
sdmmc_card_t *sdcard_host = NULL;
|
||||
public:
|
||||
CustomSDPort(const char *SdName,int clk = 38,int cmd = 21,int d0 = 39,int width = 1);
|
||||
~CustomSDPort();
|
||||
|
||||
int SDPort_GetStatus() {return is_SdcardInitOK;}
|
||||
int SDPort_WriteFile(const char *path, const void *data, size_t data_len);
|
||||
int SDPort_ReadFile(const char *path, uint8_t *buffer, size_t *outLen);
|
||||
int SDPort_ReadOffset(const char *path, void *buffer, size_t len, size_t offset);
|
||||
int SDPort_WriteOffset(const char *path, const void *data, size_t len, bool append);
|
||||
};
|
||||
292
components/port_bsp/src/multi_button/multi_button.c
Normal file
292
components/port_bsp/src/multi_button/multi_button.c
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
#include "multi_button.h"
|
||||
|
||||
// Macro for callback execution with null check
|
||||
#define EVENT_CB(ev) do { if(handle->cb[ev]) handle->cb[ev](handle); } while(0)
|
||||
|
||||
// Button handle list head
|
||||
static Button* head_handle = NULL;
|
||||
|
||||
// Forward declarations
|
||||
static void button_handler(Button* handle);
|
||||
static inline uint8_t button_read_level(Button* handle);
|
||||
|
||||
/**
|
||||
* @brief Initialize the button struct handle
|
||||
* @param handle: the button handle struct
|
||||
* @param pin_level: read the HAL GPIO of the connected button level
|
||||
* @param active_level: pressed GPIO level
|
||||
* @param button_id: the button id
|
||||
* @retval None
|
||||
*/
|
||||
void button_init(Button* handle, uint8_t(*pin_level)(uint8_t), uint8_t active_level, uint8_t button_id)
|
||||
{
|
||||
if (!handle || !pin_level) return; // parameter validation
|
||||
|
||||
memset(handle, 0, sizeof(Button));
|
||||
handle->event = (uint8_t)BTN_NONE_PRESS;
|
||||
handle->hal_button_level = pin_level;
|
||||
handle->button_level = !active_level; // initialize to opposite of active level
|
||||
handle->active_level = active_level;
|
||||
handle->button_id = button_id;
|
||||
handle->state = BTN_STATE_IDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Attach the button event callback function
|
||||
* @param handle: the button handle struct
|
||||
* @param event: trigger event type
|
||||
* @param cb: callback function
|
||||
* @retval None
|
||||
*/
|
||||
void button_attach(Button* handle, ButtonEvent event, BtnCallback cb)
|
||||
{
|
||||
if (!handle || event >= BTN_EVENT_COUNT) return; // parameter validation
|
||||
handle->cb[event] = cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Detach the button event callback function
|
||||
* @param handle: the button handle struct
|
||||
* @param event: trigger event type
|
||||
* @retval None
|
||||
*/
|
||||
void button_detach(Button* handle, ButtonEvent event)
|
||||
{
|
||||
if (!handle || event >= BTN_EVENT_COUNT) return; // parameter validation
|
||||
handle->cb[event] = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the button event that happened
|
||||
* @param handle: the button handle struct
|
||||
* @retval button event
|
||||
*/
|
||||
ButtonEvent button_get_event(Button* handle)
|
||||
{
|
||||
if (!handle) return BTN_NONE_PRESS;
|
||||
return (ButtonEvent)(handle->event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the repeat count of button presses
|
||||
* @param handle: the button handle struct
|
||||
* @retval repeat count
|
||||
*/
|
||||
uint8_t button_get_repeat_count(Button* handle)
|
||||
{
|
||||
if (!handle) return 0;
|
||||
return handle->repeat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset button state to idle
|
||||
* @param handle: the button handle struct
|
||||
* @retval None
|
||||
*/
|
||||
void button_reset(Button* handle)
|
||||
{
|
||||
if (!handle) return;
|
||||
handle->state = BTN_STATE_IDLE;
|
||||
handle->ticks = 0;
|
||||
handle->repeat = 0;
|
||||
handle->event = (uint8_t)BTN_NONE_PRESS;
|
||||
handle->debounce_cnt = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if button is currently pressed
|
||||
* @param handle: the button handle struct
|
||||
* @retval 1: pressed, 0: not pressed, -1: error
|
||||
*/
|
||||
int button_is_pressed(Button* handle)
|
||||
{
|
||||
if (!handle) return -1;
|
||||
return (handle->button_level == handle->active_level) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read button level with inline optimization
|
||||
* @param handle: the button handle struct
|
||||
* @retval button level
|
||||
*/
|
||||
static inline uint8_t button_read_level(Button* handle)
|
||||
{
|
||||
return handle->hal_button_level(handle->button_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Button driver core function, driver state machine
|
||||
* @param handle: the button handle struct
|
||||
* @retval None
|
||||
*/
|
||||
static void button_handler(Button* handle)
|
||||
{
|
||||
uint8_t read_gpio_level = button_read_level(handle);
|
||||
|
||||
// Increment ticks counter when not in idle state
|
||||
if (handle->state > BTN_STATE_IDLE) {
|
||||
handle->ticks++;
|
||||
}
|
||||
|
||||
/*------------Button debounce handling---------------*/
|
||||
if (read_gpio_level != handle->button_level) {
|
||||
// Continue reading same new level for debounce
|
||||
if (++(handle->debounce_cnt) >= DEBOUNCE_TICKS) {
|
||||
handle->button_level = read_gpio_level;
|
||||
handle->debounce_cnt = 0;
|
||||
}
|
||||
} else {
|
||||
// Level not changed, reset counter
|
||||
handle->debounce_cnt = 0;
|
||||
}
|
||||
|
||||
/*-----------------State machine-------------------*/
|
||||
switch (handle->state) {
|
||||
case BTN_STATE_IDLE:
|
||||
if (handle->button_level == handle->active_level) {
|
||||
// Button press detected
|
||||
handle->event = (uint8_t)BTN_PRESS_DOWN;
|
||||
EVENT_CB(BTN_PRESS_DOWN);
|
||||
handle->ticks = 0;
|
||||
handle->repeat = 1;
|
||||
handle->state = BTN_STATE_PRESS;
|
||||
} else {
|
||||
handle->event = (uint8_t)BTN_NONE_PRESS;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTN_STATE_PRESS:
|
||||
if (handle->button_level != handle->active_level) {
|
||||
// Button released
|
||||
handle->event = (uint8_t)BTN_PRESS_UP;
|
||||
EVENT_CB(BTN_PRESS_UP);
|
||||
handle->ticks = 0;
|
||||
handle->state = BTN_STATE_RELEASE;
|
||||
} else if (handle->ticks > LONG_TICKS) {
|
||||
// Long press detected
|
||||
handle->event = (uint8_t)BTN_LONG_PRESS_START;
|
||||
EVENT_CB(BTN_LONG_PRESS_START);
|
||||
handle->state = BTN_STATE_LONG_HOLD;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTN_STATE_RELEASE:
|
||||
if (handle->button_level == handle->active_level) {
|
||||
// Button pressed again
|
||||
handle->event = (uint8_t)BTN_PRESS_DOWN;
|
||||
EVENT_CB(BTN_PRESS_DOWN);
|
||||
if (handle->repeat < PRESS_REPEAT_MAX_NUM) {
|
||||
handle->repeat++;
|
||||
}
|
||||
EVENT_CB(BTN_PRESS_REPEAT);
|
||||
handle->ticks = 0;
|
||||
handle->state = BTN_STATE_REPEAT;
|
||||
} else if (handle->ticks > SHORT_TICKS) {
|
||||
// Timeout reached, determine click type
|
||||
if (handle->repeat == 1) {
|
||||
handle->event = (uint8_t)BTN_SINGLE_CLICK;
|
||||
EVENT_CB(BTN_SINGLE_CLICK);
|
||||
} else if (handle->repeat == 2) {
|
||||
handle->event = (uint8_t)BTN_DOUBLE_CLICK;
|
||||
EVENT_CB(BTN_DOUBLE_CLICK);
|
||||
}
|
||||
handle->state = BTN_STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTN_STATE_REPEAT:
|
||||
if (handle->button_level != handle->active_level) {
|
||||
// Button released
|
||||
handle->event = (uint8_t)BTN_PRESS_UP;
|
||||
EVENT_CB(BTN_PRESS_UP);
|
||||
if (handle->ticks < SHORT_TICKS) {
|
||||
handle->ticks = 0;
|
||||
handle->state = BTN_STATE_RELEASE; // Continue waiting for more presses
|
||||
} else {
|
||||
handle->state = BTN_STATE_IDLE; // End of sequence
|
||||
}
|
||||
} else if (handle->ticks > SHORT_TICKS) {
|
||||
// Held down too long, treat as normal press
|
||||
handle->state = BTN_STATE_PRESS;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTN_STATE_LONG_HOLD:
|
||||
if (handle->button_level == handle->active_level) {
|
||||
// Continue holding
|
||||
handle->event = (uint8_t)BTN_LONG_PRESS_HOLD;
|
||||
EVENT_CB(BTN_LONG_PRESS_HOLD);
|
||||
} else {
|
||||
// Released from long press
|
||||
handle->event = (uint8_t)BTN_PRESS_UP;
|
||||
EVENT_CB(BTN_PRESS_UP);
|
||||
handle->state = BTN_STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Invalid state, reset to idle
|
||||
handle->state = BTN_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start the button work, add the handle into work list
|
||||
* @param handle: target handle struct
|
||||
* @retval 0: succeed, -1: already exist, -2: invalid parameter
|
||||
*/
|
||||
int button_start(Button* handle)
|
||||
{
|
||||
if (!handle) return -2; // invalid parameter
|
||||
|
||||
Button* target = head_handle;
|
||||
while (target) {
|
||||
if (target == handle) return -1; // already exist
|
||||
target = target->next;
|
||||
}
|
||||
|
||||
handle->next = head_handle;
|
||||
head_handle = handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop the button work, remove the handle from work list
|
||||
* @param handle: target handle struct
|
||||
* @retval None
|
||||
*/
|
||||
void button_stop(Button* handle)
|
||||
{
|
||||
if (!handle) return; // parameter validation
|
||||
|
||||
Button** curr;
|
||||
for (curr = &head_handle; *curr; ) {
|
||||
Button* entry = *curr;
|
||||
if (entry == handle) {
|
||||
*curr = entry->next;
|
||||
entry->next = NULL; // clear next pointer
|
||||
return;
|
||||
} else {
|
||||
curr = &entry->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Background ticks, timer repeat invoking interval 5ms
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void button_ticks(void)
|
||||
{
|
||||
Button* target;
|
||||
for (target = head_handle; target; target = target->next) {
|
||||
button_handler(target);
|
||||
}
|
||||
}
|
||||
84
components/port_bsp/src/multi_button/multi_button.h
Normal file
84
components/port_bsp/src/multi_button/multi_button.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
#ifndef _MULTI_BUTTON_H_
|
||||
#define _MULTI_BUTTON_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
// Configuration constants - can be modified according to your needs
|
||||
#define TICKS_INTERVAL 5 // ms - timer interrupt interval
|
||||
#define DEBOUNCE_TICKS 3 // MAX 7 (0 ~ 7) - debounce filter depth
|
||||
#define SHORT_TICKS (300 / TICKS_INTERVAL) // short press threshold
|
||||
#define LONG_TICKS (1000 / TICKS_INTERVAL) // long press threshold
|
||||
#define PRESS_REPEAT_MAX_NUM 15 // maximum repeat counter value
|
||||
|
||||
// Forward declaration
|
||||
typedef struct _Button Button;
|
||||
|
||||
// Button callback function type
|
||||
typedef void (*BtnCallback)(Button* btn_handle);
|
||||
|
||||
// Button event types
|
||||
typedef enum {
|
||||
BTN_PRESS_DOWN = 0, // button pressed down
|
||||
BTN_PRESS_UP, // button released
|
||||
BTN_PRESS_REPEAT, // repeated press detected
|
||||
BTN_SINGLE_CLICK, // single click completed
|
||||
BTN_DOUBLE_CLICK, // double click completed
|
||||
BTN_LONG_PRESS_START, // long press started
|
||||
BTN_LONG_PRESS_HOLD, // long press holding
|
||||
BTN_EVENT_COUNT, // total number of events
|
||||
BTN_NONE_PRESS // no event
|
||||
} ButtonEvent;
|
||||
|
||||
// Button state machine states
|
||||
typedef enum {
|
||||
BTN_STATE_IDLE = 0, // idle state
|
||||
BTN_STATE_PRESS, // pressed state
|
||||
BTN_STATE_RELEASE, // released state waiting for timeout
|
||||
BTN_STATE_REPEAT, // repeat press state
|
||||
BTN_STATE_LONG_HOLD // long press hold state
|
||||
} ButtonState;
|
||||
|
||||
// Button structure
|
||||
struct _Button {
|
||||
uint16_t ticks; // tick counter
|
||||
uint8_t repeat : 4; // repeat counter (0-15)
|
||||
uint8_t event : 4; // current event (0-15)
|
||||
uint8_t state : 3; // state machine state (0-7)
|
||||
uint8_t debounce_cnt : 3; // debounce counter (0-7)
|
||||
uint8_t active_level : 1; // active GPIO level (0 or 1)
|
||||
uint8_t button_level : 1; // current button level
|
||||
uint8_t button_id; // button identifier
|
||||
uint8_t (*hal_button_level)(uint8_t button_id); // HAL function to read GPIO
|
||||
BtnCallback cb[BTN_EVENT_COUNT]; // callback function array
|
||||
Button* next; // next button in linked list
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Public API functions
|
||||
void button_init(Button* handle, uint8_t(*pin_level)(uint8_t), uint8_t active_level, uint8_t button_id);
|
||||
void button_attach(Button* handle, ButtonEvent event, BtnCallback cb);
|
||||
void button_detach(Button* handle, ButtonEvent event);
|
||||
ButtonEvent button_get_event(Button* handle);
|
||||
int button_start(Button* handle);
|
||||
void button_stop(Button* handle);
|
||||
void button_ticks(void);
|
||||
|
||||
// Utility functions
|
||||
uint8_t button_get_repeat_count(Button* handle);
|
||||
void button_reset(Button* handle);
|
||||
int button_is_pressed(Button* handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user