3037 views|0 replies

282

Posts

2

Resources
The OP
 

[ESP32-S2-Kaluga-1 Review] 5. Image display, button and RGB LED operation [Copy link]

 

This week I tinkered with the onboard buttons and RGB LEDs.

Let's talk about the specific functions implemented below. Use the official routines to modify and display your own logo picture.

Next, we will operate the RGB LED and modify the official example. The code is as follows:

The meaning of changing the code is that red, blue and green are displayed alternately:

The display effect is as follows:


Next is the button control. The buttons of ESP32S2 are connected to the ADC, so the ADC needs to be used to read the corresponding voltage values. Different buttons or combination buttons have different voltage values when pressed, which need to be collected by the ADC.

The circuit diagram is as follows:

Note that the voltage value of button 1 on this schematic is not marked correctly. When I first used button K1, I used 2.41V and it was not correct. It could not be detected. Other buttons were all OK. Then I debugged it with the serial port and found that K1 was 2.3V.

As shown below:

Then use 2.3V to identify it normally.

The program I wrote uses two different tasks for RGB LED and button respectively. Pressing button K1 pauses the RGB LED task, and releasing button K1 resumes the RGB LED task.

The effect is as follows:


f((1 == key_pressed_status[0]) && (0 == Last_key_pressed_status[0])){     // pressed
        vTaskSuspend(RGBLEDTask_Handler);  
        ESP_LOGI(TAG, "K1 activated");
    }else if((0 == key_pressed_status[0]) && (1 == Last_key_pressed_status[0])){      // released
        vTaskResume(RGBLEDTask_Handler);
        ESP_LOGI(TAG, "K1 inactivated");
    }else{

    }

I'll paste the source code below.

But it should be noted that in addition to modifying the code in main.c, you also need to modify the Kconfig.probuild and CMakeLists.txt files

Source code (main.c):

/* 
Autor: hehung
*/
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>

#include "esp_wifi.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "esp_spiffs.h"

#include "lcd.h"
#include "jpeg.h"
#include "board.h"
#include "sccb.h"
#include "cam.h"

#include "ov2640.h"
#include "ov3660.h"
#include "sensor.h"

#include "driver/gpio.h"
#include "driver/adc.h"
#include "driver/rmt.h"
#include "led_strip.h"

static const char *TAG = "main";

/******** Start Macro Definition ********/
/* Picture - Start up picture */
/* LCD */
#define IMAGE_MAX_SIZE (100 * 1024)/**< The maximum size of a single picture in the boot animation */
#define IMAGE_WIDTH    (320) /*!< width of jpeg file */
#define IMAGE_HIGHT    (240) /*!< height of jpeg file */

/* Camera */
#define CAM_WIDTH   (320)       /* camera width */
#define CAM_HIGH    (240)       /* camera height */

/* ADC Button */
#define DEFAULT_VREF    1100                            /*!< Use adc2_vref_to_gpio() to obtain a better estimate */
#define NO_OF_SAMPLES   64
#define SAMPLE_TIME     200                             /*!< Sampling time(ms) */
#define DEVIATION 0.1
/******** End Macro Definition ********/

/******** Start Variables Declaration  ********/
/* LED */
static led_strip_t *strip;
/* ADC Button */
static const adc_channel_t channel = ADC_CHANNEL_5;     /*!< PIO7 if ADC1, GPIO17 if ADC2 */
static const adc_bits_width_t width = ADC_WIDTH_BIT_13;

static const adc_atten_t atten = ADC_ATTEN_DB_11;
static const adc_unit_t unit = ADC_UNIT_1;
static xQueueHandle adc_queue = NULL;

/* freertos tasks handler */
TaskHandle_t RGBLEDTask_Handler;		//RGB LED任务句柄
TaskHandle_t ButtonTask_Handler;		//RGB LED任务句柄
TaskHandle_t CameraTask_Handler;		//RGB LED任务句柄
/******** End Variables Declaration  ********/

/******** Start Function Declaration  ********/
static void start_display(void);
static void cam_task(void *arg);
void button_task(void *arg);
void led_task(void *arg);
esp_err_t Rmt_init(uint8_t gpio_num, int led_number, uint8_t rmt_channel);
void adc_init(void);
void button_task(void *arg);
double adc_voltage_conversion(uint32_t adc_reading);
void Button_Selection(double voltage);
/******** End Function Declaration  ********/


/******** Start Function Definition  ********/
/* main */
void app_main()
{
    /* Show a picture */
    start_display();

    adc_queue = xQueueCreate(1, sizeof(double));
    adc_init();

    /* Show the Camera */
 //   xTaskCreate(cam_task, "cam_task", 2048, NULL, 3, &CameraTask_Handler);
    /*  */
    xTaskCreate(&button_task, "button_task", 3*1024, NULL, 4, &ButtonTask_Handler);
    xTaskCreate(&led_task, "led_task", 3*1024, NULL, 5, &RGBLEDTask_Handler);
//    vTaskStartScheduler();          //this is write in cpu_start.c
}

/*initialization the ADC */
void adc_init(void)
{
    if (unit == ADC_UNIT_1) {
        adc1_config_width(width);
        adc1_config_channel_atten(channel, atten);
    } else {
        adc2_config_channel_atten((adc2_channel_t)channel, atten);
    }

}

/* ADC conversion */
double adc_voltage_conversion(uint32_t adc_reading)
{
    double voltage = 0;

    voltage = (2.60 * adc_reading) / 8191;

    return voltage;
}

/* button task */
void button_task(void *arg)
{
     /*!<Continuously sample ADC1*/
    while (1) {
        uint32_t adc_reading = 0;
        double voltage = 0;

        /*!< Multisampling */
        for (int i = 0; i < NO_OF_SAMPLES; i++) {
            if (unit == ADC_UNIT_1) {
                adc_reading += adc1_get_raw((adc1_channel_t)channel);
            } else {
                int raw;
                adc2_get_raw((adc2_channel_t)channel, width, &raw);
                adc_reading += raw;
            }
        }

        adc_reading /= NO_OF_SAMPLES;

        voltage = adc_voltage_conversion(adc_reading);
        ESP_LOGD(TAG, "ADC%d CH%d Raw: %d   ; Voltage: %0.2lfV", unit, channel, adc_reading, voltage);
        ESP_LOGI(TAG, "Voltage: %0.2lfV", voltage);
        xQueueSend(adc_queue, (double *)&voltage, 0);
    //    xQueueReceive(adc_queue, &voltage, portMAX_DELAY);
        Button_Selection(voltage);
        vTaskDelay(pdMS_TO_TICKS(SAMPLE_TIME));
    }

    vTaskDelete(NULL);
}

/* Button Selection */
void Button_Selection(double voltage)
{
//    double voltage = 0;
//    xQueueReceive(adc_queue, &voltage, portMAX_DELAY);

    static bool key_pressed_status[6] = {0};
    static bool Last_key_pressed_status[6] = {0};

    if (voltage > 2.30 - DEVIATION  && voltage <= 2.30 + DEVIATION) {
        key_pressed_status[0] = 1;
        ESP_LOGI(TAG, "K1 Pressed");
    } else if (voltage > 1.98 - DEVIATION && voltage <= 1.98 + DEVIATION) {
        key_pressed_status[1] = 1;
        ESP_LOGI(TAG, "K2 Pressed");
    } else if (voltage > 1.65 - DEVIATION && voltage <= 1.65 + DEVIATION) {
        key_pressed_status[2] = 1;
        ESP_LOGI(TAG, "K3 Pressed");
    } else if (voltage > 1.11 - DEVIATION && voltage <= 1.11 + DEVIATION) {
        key_pressed_status[3] = 1;
        ESP_LOGI(TAG, "K4 Pressed");
    } else if (voltage > 0.82 - DEVIATION && voltage <= 0.82 + DEVIATION) {
        key_pressed_status[4] = 1;
        ESP_LOGI(TAG, "K5 Pressed");
    } else if (voltage > 0.38 - DEVIATION && voltage <= 0.38 + DEVIATION) {
        key_pressed_status[5] = 1;
        ESP_LOGI(TAG, "K6 Pressed");
    }else{
        key_pressed_status[0] = 0;
        key_pressed_status[1] = 0;
        key_pressed_status[2] = 0;
        key_pressed_status[3] = 0;
        key_pressed_status[4] = 0;
        key_pressed_status[5] = 0;
    }

    if((1 == key_pressed_status[0]) && (0 == Last_key_pressed_status[0])){     // pressed
        vTaskSuspend(RGBLEDTask_Handler);  
        ESP_LOGI(TAG, "K1 activated");
    }else if((0 == key_pressed_status[0]) && (1 == Last_key_pressed_status[0])){      // released
        vTaskResume(RGBLEDTask_Handler);
        ESP_LOGI(TAG, "K1 inactivated");
    }else{

    }

    Last_key_pressed_status[0] = key_pressed_status[0];
    Last_key_pressed_status[1] = key_pressed_status[1];
    Last_key_pressed_status[2] = key_pressed_status[2];
    Last_key_pressed_status[3] = key_pressed_status[3];
    Last_key_pressed_status[4] = key_pressed_status[4];
    Last_key_pressed_status[5] = key_pressed_status[5];

}

/* RGB LED Initialization */
esp_err_t Rmt_init(uint8_t gpio_num, int led_number, uint8_t rmt_channel)
{
    ESP_LOGI(TAG, "Initializing WS2812");
    rmt_config_t config = RMT_DEFAULT_CONFIG_TX(gpio_num, rmt_channel);

    /*!< set counter clock to 40MHz */
    config.clk_div = 2;

    ESP_ERROR_CHECK(rmt_config(&config));
    ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));

    led_strip_config_t strip_config = LED_STRIP_DEFAULT_CONFIG(led_number, (led_strip_dev_t)config.channel);
    strip = led_strip_new_rmt_ws2812(&strip_config);

    if (!strip) {
        ESP_LOGE(TAG, "install WS2812 driver failed");
        return ESP_FAIL;
    }

    /*!< Clear LED strip (turn off all LEDs) */
    ESP_ERROR_CHECK(strip->clear(strip, 100));
    /*!< Show simple rainbow chasing pattern */

    return ESP_OK;
}

/* led task */
void led_task(void *arg)
{
    static unsigned char LED_change_count1 = 0u;
    static unsigned char LED_change_count2 = 0u;
    static unsigned char LED_change_count3 = 0u;

    /*!< WS2812 init*/
    ESP_ERROR_CHECK(Rmt_init(45, 4, RMT_CHANNEL_0));
    ESP_ERROR_CHECK(strip->set_pixel(strip, 0, 0, 0, 0));

    while (1) {
        if((LED_change_count1 != 255)
            && (LED_change_count2 == 0)
            && (LED_change_count3 == 0))
        {
            LED_change_count1 ++;
        }else if((LED_change_count1 == 255)
            && (LED_change_count2 != 255)
            && (LED_change_count3 == 0))
        {
            LED_change_count2 ++;
        }else if((LED_change_count1 == 255)
            && (LED_change_count2 == 255)
            && (LED_change_count3 != 255))
        {
            LED_change_count3 ++;
        }else if((LED_change_count1 != 0)
            && (LED_change_count2 == 255)
            && (LED_change_count3 == 255))
        {
            LED_change_count1 --;
        }else if((LED_change_count1 == 0)
            && (LED_change_count2 != 0)
            && (LED_change_count3 == 255))
        {
            LED_change_count2 --;
        }else if((LED_change_count1 == 0)
            && (LED_change_count2 == 0)
            && (LED_change_count3 != 0))
        {
            LED_change_count3 --;
        }else
        {
            
        }
        
        ESP_LOGI(TAG, "R-%d,G-%d,B-%d", LED_change_count1, LED_change_count2, LED_change_count3);
        ESP_ERROR_CHECK(strip->set_pixel(strip, 0, LED_change_count1, LED_change_count2, LED_change_count3));
        ESP_ERROR_CHECK(strip->refresh(strip, 0));
        
        vTaskDelay(pdMS_TO_TICKS(10));
    }

    vTaskDelete(NULL);
}

/* Cmera task */
static void cam_task(void *arg)
{
    cam_config_t cam_config = {
        .bit_width    = 8,
#ifdef CONFIG_CAMERA_JPEG_MODE
        .mode.jpeg    = 1,
#else
        .mode.jpeg    = 0,
#endif
        .xclk_fre     = 16 * 1000 * 1000,
        .pin  = {
            .xclk     = CAM_XCLK,
            .pclk     = CAM_PCLK,
            .vsync    = CAM_VSYNC,
            .hsync    = CAM_HSYNC,
        },
        .pin_data     = {CAM_D0, CAM_D1, CAM_D2, CAM_D3, CAM_D4, CAM_D5, CAM_D6, CAM_D7},
        .vsync_invert = true,
        .hsync_invert = false,
        .size = {
            .width    = CAM_WIDTH,
            .high     = CAM_HIGH,
        },
        .max_buffer_size = 8 * 1024,
        .task_stack      = 1024,
        .task_pri        = configMAX_PRIORITIES
    };

    /*!< With PingPang buffers, the frame rate is higher, or you can use a separate buffer to save memory */
    cam_config.frame1_buffer = (uint8_t *)heap_caps_malloc(CAM_WIDTH * CAM_HIGH * 2 * sizeof(uint8_t), MALLOC_CAP_SPIRAM);
    cam_config.frame2_buffer = (uint8_t *)heap_caps_malloc(CAM_WIDTH * CAM_HIGH * 2 * sizeof(uint8_t), MALLOC_CAP_SPIRAM);

    cam_init(&cam_config);

    sensor_t sensor;
    int camera_version = 0;      /*!<If the camera version is determined, it can be set to manual mode */
    SCCB_Init(CAM_SDA, CAM_SCL);
    sensor.slv_addr = SCCB_Probe();
    ESP_LOGI(TAG, "sensor_id: 0x%x\n", sensor.slv_addr);

#ifdef CONFIG_CAMERA_OV2640
    camera_version = 2640;
#endif
#ifdef CONFIG_CAMERA_OV3660
    camera_version = 3660;
#endif
#ifdef CONFIG_CAMERA_AUTO
    /*!< If you choose this mode, Dont insert the Audio board, audio will affect the camera register read. */
#endif
    if (sensor.slv_addr == 0x30 || camera_version == 2640) { /*!< Camera: OV2640 */
        ESP_LOGI(TAG, "OV2640 init start...");

        if (OV2640_Init(0, 1) != 0) {
            goto fail;
        }

        if (cam_config.mode.jpeg) {
            OV2640_JPEG_Mode();
        } else {
            OV2640_RGB565_Mode(false);	/*!< RGB565 mode */
        }

        OV2640_ImageSize_Set(800, 600);
        OV2640_ImageWin_Set(0, 0, 800, 600);
        OV2640_OutSize_Set(CAM_WIDTH, CAM_HIGH);
    } else if (sensor.slv_addr == 0x3C || camera_version == 3660) { /*!< Camera: OV3660 */

        sensor.slv_addr = 0x3C; /*!< In special cases, slv_addr may change */
        ESP_LOGI(TAG, "OV3660 init start...");
        ov3660_init(&sensor);
        sensor.init_status(&sensor);

        if (sensor.reset(&sensor) != 0) {
            goto fail;
        }

        if (cam_config.mode.jpeg) {
            sensor.set_pixformat(&sensor, PIXFORMAT_JPEG);
        } else {
            sensor.set_pixformat(&sensor, PIXFORMAT_RGB565);
        }

        /*!< TotalX gets smaller, frame rate goes up */
        /*!< TotalY gets smaller, frame rate goes up, vsync gets shorter */
        sensor.set_res_raw(&sensor, 0, 0, 2079, 1547, 8, 2, 1920, 800, CAM_WIDTH, CAM_HIGH, true, true);
        sensor.set_vflip(&sensor, 1);
        sensor.set_hmirror(&sensor, 1);
        sensor.set_pll(&sensor, false, 15, 1, 0, false, 0, true, 5); /*!< ov3660: 39 fps */
    } else {
        ESP_LOGE(TAG, "sensor is temporarily not supported\n");
        goto fail;
    }

    ESP_LOGI(TAG, "camera init done\n");
    cam_start();

    while (1) {
        uint8_t *cam_buf = NULL;
        cam_take(&cam_buf);
#ifdef CONFIG_CAMERA_JPEG_MODE

        int w, h;
        uint8_t *img = jpeg_decode(cam_buf, &w, &h);

        if (img) {
            ESP_LOGI(TAG, "jpeg: w: %d, h: %d\n", w, h);
            lcd_set_index(0, 0, w - 1, h - 1);
            lcd_write_data(img, w * h * sizeof(uint16_t));
            free(img);
        }

#else
        lcd_set_index(0, 0, CAM_WIDTH - 1, CAM_HIGH - 1);
        lcd_write_data(cam_buf, CAM_WIDTH * CAM_HIGH * 2);
#endif
        cam_give(cam_buf);
        /*!< Use a logic analyzer to observe the frame rate */
        gpio_set_level(LCD_BK, 1);
        gpio_set_level(LCD_BK, 0);
    }

fail:
    free(cam_config.frame1_buffer);
    free(cam_config.frame2_buffer);
    cam_deinit();
    vTaskDelete(NULL);
}

/*start display show*/
static void start_display(void)
{
    lcd_config_t lcd_config = {
#ifdef CONFIG_LCD_ST7789
        .clk_fre         = 80 * 1000 * 1000, /*!< ILI9341 Stable frequency configuration */
#endif
#ifdef CONFIG_LCD_ILI9341
        .clk_fre         = 40 * 1000 * 1000, /*!< ILI9341 Stable frequency configuration */
#endif
        .pin_clk         = LCD_CLK,
        .pin_mosi        = LCD_MOSI,
        .pin_dc          = LCD_DC,
        .pin_cs          = LCD_CS,
        .pin_rst         = LCD_RST,
        .pin_bk          = LCD_BK,
        .max_buffer_size = 2 * 1024,
        .horizontal      = 2 /*!< 2: UP, 3: DOWN */
    };

    lcd_init(&lcd_config);

    ESP_LOGI(TAG, "My Project Start ....");
    esp_vfs_spiffs_conf_t conf = {
        .base_path = "/spiffs",
        .partition_label = NULL,
        .max_files = 5,
        .format_if_mount_failed = false
    };

    /*!< Use settings defined above to initialize and mount SPIFFS filesystem. */
    /*!< Note: esp_vfs_spiffs_register is an all-in-one convenience function. */
    ESP_ERROR_CHECK(esp_vfs_spiffs_register(&conf));
    size_t total = 0, used = 0;
    ESP_ERROR_CHECK(esp_spiffs_info(NULL, &total, &used));

    uint8_t *img = NULL;
    uint8_t *buf = malloc(IMAGE_MAX_SIZE);
    int read_bytes = 0;
    int width = 0, height = 0;

    FILE *fd = fopen("/spiffs/1.jpg", "r");

    read_bytes = fread(buf, 1, IMAGE_MAX_SIZE, fd);
    ESP_LOGI(TAG, "spiffs:read_bytes:%d  fd: %p", read_bytes, fd);
    fclose(fd);

    img = jpeg_decode(buf, &width, &height);
    lcd_set_index(0, 0, IMAGE_WIDTH - 1, IMAGE_HIGHT - 1);
    lcd_write_data(img, IMAGE_WIDTH * IMAGE_HIGHT * sizeof(uint16_t));
    free(buf);
    vTaskDelay(2000 / portTICK_RATE_MS);
}
/******** End Function Definition  ********/

Kconfig.probuild file, this file is the routine configuration file of mebuconfig:

menu "Example Configuration"
  
    choice CAMERA_PAD_TYPE
        prompt "camera pad type"
        default CAMERA_PAD_ESP32_S2_KALUGA_V1_3
        config CAMERA_PAD_ESP32_S2_KALUGA_V1_3
            bool "ESP32-S2-KALUGA_V1.3"
        config CAMERA_PAD_ESP32_S2_KALUGA_V1_2
            bool "ESP32-S2-KALUGA_V1.2"
        config CAMERA_PAD_ESP32_S2_KALUGA_V1_1
            bool "ESP32-S2-KALUGA_V1.1"
    endchoice

    choice LCD_PAD_TYPE
       prompt "LCD pad type"
        default LCD_PAD_ESP32_S2_KALUGA_V1_3
        config LCD_PAD_ESP32_S2_KALUGA_V1_3
            bool "ESP32-S2-KALUGA_V1.3"
        config LCD_PAD_ESP32_S2_KALUGA_V1_2
            bool "ESP32-S2-KALUGA_V1.2"
        config LCD_PAD_ESP32_S2_KALUGA_V1_1
            bool "ESP32-S2-KALUGA_V1.1"
    endchoice

    choice CAMERA_VERSION
        prompt "Camera version"
        default CAMERA_OV2640
        config CAMERA_OV2640
            bool "OV2640"
        config CAMERA_OV3660
            bool "OV3660"
        config CAMERA_AUTO
            bool "Auto (If you choose this mode, Dont insert the Audio board!)"
        help
            Set camera version
    endchoice

    choice LCD_VERSION
        prompt "LCD version"
        default ILI9341
        config LCD_ST7789
            bool "ST7789"
        config LCD_ILI9341
            bool "ILI9341"
        help
            Set LCD version
    endchoice
        
    config  CAMERA_JPEG_MODE
        bool "jpeg mode"
        
endmenu

CmakeLists.txt file:

# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)

set(EXTRA_COMPONENT_DIRS "../../components/board"
                         "../../components/lcd"
                         "../../components/jpeg"
                         "../../components/cam"
                         "../../components/sensors"
                         "../../components/led_strip"
)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
add_compile_options (-fdiagnostics-color=always)
project(esp32-s2-hmi)

Then use the terminal to enter the project folder and set the environment variables: $HOME/esp/esp-idf/export.sh

Set the compilation type and enter menuconfig for configuration: idf.py set-target esp32s2 menuconfig

The setup is as follows:

Compile: idf.py build

Download: idf.py -p /dev/ttyUSB1 flash

Monitoring: idf.py -p /dev/ttyUSB1 monitor

knock off

This post is from Domestic Chip Exchange
 
 

Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list