Moving ESP-IDF specific files to lv_port
(#175)
* Move disp_spi.c and tp_spi.c to lv_port * Move esp_lcd_backlight to lv_port * Move disp_spi.h and tp_spi.h to lv_port
This commit is contained in:
parent
463721e291
commit
28d663f6b6
7 changed files with 7 additions and 5 deletions
|
@ -1,325 +0,0 @@
|
|||
/**
|
||||
* @file disp_spi.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "esp_system.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#define TAG "disp_spi"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||
#include "lvgl.h"
|
||||
#else
|
||||
#include "lvgl/lvgl.h"
|
||||
#endif
|
||||
|
||||
#include "disp_spi.h"
|
||||
#include "disp_driver.h"
|
||||
|
||||
#include "../lvgl_helpers.h"
|
||||
#include "../lvgl_spi_conf.h"
|
||||
|
||||
/******************************************************************************
|
||||
* Notes about DMA spi_transaction_ext_t structure pooling
|
||||
*
|
||||
* An xQueue is used to hold a pool of reusable SPI spi_transaction_ext_t
|
||||
* structures that get used for all DMA SPI transactions. While an xQueue may
|
||||
* seem like overkill it is an already built-in RTOS feature that comes at
|
||||
* little cost. xQueues are also ISR safe if it ever becomes necessary to
|
||||
* access the pool in the ISR callback.
|
||||
*
|
||||
* When a DMA request is sent, a transaction structure is removed from the
|
||||
* pool, filled out, and passed off to the esp32 SPI driver. Later, when
|
||||
* servicing pending SPI transaction results, the transaction structure is
|
||||
* recycled back into the pool for later reuse. This matches the DMA SPI
|
||||
* transaction life cycle requirements of the esp32 SPI driver.
|
||||
*
|
||||
* When polling or synchronously sending SPI requests, and as required by the
|
||||
* esp32 SPI driver, all pending DMA transactions are first serviced. Then the
|
||||
* polling SPI request takes place.
|
||||
*
|
||||
* When sending an asynchronous DMA SPI request, if the pool is empty, some
|
||||
* small percentage of pending transactions are first serviced before sending
|
||||
* any new DMA SPI transactions. Not too many and not too few as this balance
|
||||
* controls DMA transaction latency.
|
||||
*
|
||||
* It is therefore not the design that all pending transactions must be
|
||||
* serviced and placed back into the pool with DMA SPI requests - that
|
||||
* will happen eventually. The pool just needs to contain enough to float some
|
||||
* number of in-flight SPI requests to speed up the overall DMA SPI data rate
|
||||
* and reduce transaction latency. If however a display driver uses some
|
||||
* polling SPI requests or calls disp_wait_for_pending_transactions() directly,
|
||||
* the pool will reach the full state more often and speed up DMA queuing.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define SPI_TRANSACTION_POOL_SIZE 50 /* maximum number of DMA transactions simultaneously in-flight */
|
||||
|
||||
/* DMA Transactions to reserve before queueing additional DMA transactions. A 1/10th seems to be a good balance. Too many (or all) and it will increase latency. */
|
||||
#define SPI_TRANSACTION_POOL_RESERVE_PERCENTAGE 10
|
||||
#if SPI_TRANSACTION_POOL_SIZE >= SPI_TRANSACTION_POOL_RESERVE_PERCENTAGE
|
||||
#define SPI_TRANSACTION_POOL_RESERVE (SPI_TRANSACTION_POOL_SIZE / SPI_TRANSACTION_POOL_RESERVE_PERCENTAGE)
|
||||
#else
|
||||
#define SPI_TRANSACTION_POOL_RESERVE 1 /* defines minimum size */
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void IRAM_ATTR spi_ready (spi_transaction_t *trans);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static spi_host_device_t spi_host;
|
||||
static spi_device_handle_t spi;
|
||||
static QueueHandle_t TransactionPool = NULL;
|
||||
static transaction_cb_t chained_post_cb;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
void disp_spi_add_device_config(spi_host_device_t host, spi_device_interface_config_t *devcfg)
|
||||
{
|
||||
spi_host=host;
|
||||
chained_post_cb=devcfg->post_cb;
|
||||
devcfg->post_cb=spi_ready;
|
||||
esp_err_t ret=spi_bus_add_device(host, devcfg, &spi);
|
||||
assert(ret==ESP_OK);
|
||||
}
|
||||
|
||||
void disp_spi_add_device(spi_host_device_t host)
|
||||
{
|
||||
disp_spi_add_device_with_speed(host, SPI_TFT_CLOCK_SPEED_HZ);
|
||||
}
|
||||
|
||||
void disp_spi_add_device_with_speed(spi_host_device_t host, int clock_speed_hz)
|
||||
{
|
||||
ESP_LOGI(TAG, "Adding SPI device");
|
||||
ESP_LOGI(TAG, "Clock speed: %dHz, mode: %d, CS pin: %d",
|
||||
clock_speed_hz, SPI_TFT_SPI_MODE, DISP_SPI_CS);
|
||||
|
||||
spi_device_interface_config_t devcfg={
|
||||
.clock_speed_hz = clock_speed_hz,
|
||||
.mode = SPI_TFT_SPI_MODE,
|
||||
.spics_io_num=DISP_SPI_CS, // CS pin
|
||||
.input_delay_ns=DISP_SPI_INPUT_DELAY_NS,
|
||||
.queue_size=SPI_TRANSACTION_POOL_SIZE,
|
||||
.pre_cb=NULL,
|
||||
.post_cb=NULL,
|
||||
#if defined(DISP_SPI_HALF_DUPLEX)
|
||||
.flags = SPI_DEVICE_NO_DUMMY | SPI_DEVICE_HALFDUPLEX, /* dummy bits should be explicitly handled via DISP_SPI_VARIABLE_DUMMY as needed */
|
||||
#else
|
||||
#if defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_FT81X)
|
||||
.flags = 0,
|
||||
#elif defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_RA8875)
|
||||
.flags = SPI_DEVICE_NO_DUMMY,
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
disp_spi_add_device_config(host, &devcfg);
|
||||
|
||||
/* create the transaction pool and fill it with ptrs to spi_transaction_ext_t to reuse */
|
||||
if(TransactionPool == NULL) {
|
||||
TransactionPool = xQueueCreate(SPI_TRANSACTION_POOL_SIZE, sizeof(spi_transaction_ext_t*));
|
||||
assert(TransactionPool != NULL);
|
||||
for (size_t i = 0; i < SPI_TRANSACTION_POOL_SIZE; i++)
|
||||
{
|
||||
spi_transaction_ext_t* pTransaction = (spi_transaction_ext_t*)heap_caps_malloc(sizeof(spi_transaction_ext_t), MALLOC_CAP_DMA);
|
||||
assert(pTransaction != NULL);
|
||||
memset(pTransaction, 0, sizeof(spi_transaction_ext_t));
|
||||
xQueueSend(TransactionPool, &pTransaction, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void disp_spi_change_device_speed(int clock_speed_hz)
|
||||
{
|
||||
if (clock_speed_hz <= 0) {
|
||||
clock_speed_hz = SPI_TFT_CLOCK_SPEED_HZ;
|
||||
}
|
||||
ESP_LOGI(TAG, "Changing SPI device clock speed: %d", clock_speed_hz);
|
||||
disp_spi_remove_device();
|
||||
disp_spi_add_device_with_speed(spi_host, clock_speed_hz);
|
||||
}
|
||||
|
||||
void disp_spi_remove_device()
|
||||
{
|
||||
/* Wait for previous pending transaction results */
|
||||
disp_wait_for_pending_transactions();
|
||||
|
||||
esp_err_t ret=spi_bus_remove_device(spi);
|
||||
assert(ret==ESP_OK);
|
||||
}
|
||||
|
||||
void disp_spi_transaction(const uint8_t *data, size_t length,
|
||||
disp_spi_send_flag_t flags, uint8_t *out,
|
||||
uint64_t addr, uint8_t dummy_bits)
|
||||
{
|
||||
if (0 == length) {
|
||||
return;
|
||||
}
|
||||
|
||||
spi_transaction_ext_t t = {0};
|
||||
|
||||
/* transaction length is in bits */
|
||||
t.base.length = length * 8;
|
||||
|
||||
if (length <= 4 && data != NULL) {
|
||||
t.base.flags = SPI_TRANS_USE_TXDATA;
|
||||
memcpy(t.base.tx_data, data, length);
|
||||
} else {
|
||||
t.base.tx_buffer = data;
|
||||
}
|
||||
|
||||
if (flags & DISP_SPI_RECEIVE) {
|
||||
assert(out != NULL && (flags & (DISP_SPI_SEND_POLLING | DISP_SPI_SEND_SYNCHRONOUS)));
|
||||
t.base.rx_buffer = out;
|
||||
|
||||
#if defined(DISP_SPI_HALF_DUPLEX)
|
||||
t.base.rxlength = t.base.length;
|
||||
t.base.length = 0; /* no MOSI phase in half-duplex reads */
|
||||
#else
|
||||
t.base.rxlength = 0; /* in full-duplex mode, zero means same as tx length */
|
||||
#endif
|
||||
}
|
||||
|
||||
if (flags & DISP_SPI_ADDRESS_8) {
|
||||
t.address_bits = 8;
|
||||
} else if (flags & DISP_SPI_ADDRESS_16) {
|
||||
t.address_bits = 16;
|
||||
} else if (flags & DISP_SPI_ADDRESS_24) {
|
||||
t.address_bits = 24;
|
||||
} else if (flags & DISP_SPI_ADDRESS_32) {
|
||||
t.address_bits = 32;
|
||||
}
|
||||
if (t.address_bits) {
|
||||
t.base.addr = addr;
|
||||
t.base.flags |= SPI_TRANS_VARIABLE_ADDR;
|
||||
}
|
||||
|
||||
#if defined(DISP_SPI_HALF_DUPLEX)
|
||||
if (flags & DISP_SPI_MODE_DIO) {
|
||||
t.base.flags |= SPI_TRANS_MODE_DIO;
|
||||
} else if (flags & DISP_SPI_MODE_QIO) {
|
||||
t.base.flags |= SPI_TRANS_MODE_QIO;
|
||||
}
|
||||
|
||||
if (flags & DISP_SPI_MODE_DIOQIO_ADDR) {
|
||||
t.base.flags |= SPI_TRANS_MODE_DIOQIO_ADDR;
|
||||
}
|
||||
|
||||
if ((flags & DISP_SPI_VARIABLE_DUMMY) && dummy_bits) {
|
||||
t.dummy_bits = dummy_bits;
|
||||
t.base.flags |= SPI_TRANS_VARIABLE_DUMMY;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Save flags for pre/post transaction processing */
|
||||
t.base.user = (void *) flags;
|
||||
|
||||
/* Poll/Complete/Queue transaction */
|
||||
if (flags & DISP_SPI_SEND_POLLING) {
|
||||
disp_wait_for_pending_transactions(); /* before polling, all previous pending transactions need to be serviced */
|
||||
spi_device_polling_transmit(spi, (spi_transaction_t *) &t);
|
||||
} else if (flags & DISP_SPI_SEND_SYNCHRONOUS) {
|
||||
disp_wait_for_pending_transactions(); /* before synchronous queueing, all previous pending transactions need to be serviced */
|
||||
spi_device_transmit(spi, (spi_transaction_t *) &t);
|
||||
} else {
|
||||
|
||||
/* if necessary, ensure we can queue new transactions by servicing some previous transactions */
|
||||
if(uxQueueMessagesWaiting(TransactionPool) == 0) {
|
||||
spi_transaction_t *presult;
|
||||
while(uxQueueMessagesWaiting(TransactionPool) < SPI_TRANSACTION_POOL_RESERVE) {
|
||||
if (spi_device_get_trans_result(spi, &presult, 1) == ESP_OK) {
|
||||
xQueueSend(TransactionPool, &presult, portMAX_DELAY); /* back to the pool to be reused */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spi_transaction_ext_t *pTransaction = NULL;
|
||||
xQueueReceive(TransactionPool, &pTransaction, portMAX_DELAY);
|
||||
memcpy(pTransaction, &t, sizeof(t));
|
||||
if (spi_device_queue_trans(spi, (spi_transaction_t *) pTransaction, portMAX_DELAY) != ESP_OK) {
|
||||
xQueueSend(TransactionPool, &pTransaction, portMAX_DELAY); /* send failed transaction back to the pool to be reused */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void disp_wait_for_pending_transactions(void)
|
||||
{
|
||||
spi_transaction_t *presult;
|
||||
|
||||
while(uxQueueMessagesWaiting(TransactionPool) < SPI_TRANSACTION_POOL_SIZE) { /* service until the transaction reuse pool is full again */
|
||||
if (spi_device_get_trans_result(spi, &presult, 1) == ESP_OK) {
|
||||
xQueueSend(TransactionPool, &presult, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void disp_spi_acquire(void)
|
||||
{
|
||||
esp_err_t ret = spi_device_acquire_bus(spi, portMAX_DELAY);
|
||||
assert(ret == ESP_OK);
|
||||
}
|
||||
|
||||
void disp_spi_release(void)
|
||||
{
|
||||
spi_device_release_bus(spi);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void IRAM_ATTR spi_ready(spi_transaction_t *trans)
|
||||
{
|
||||
disp_spi_send_flag_t flags = (disp_spi_send_flag_t) trans->user;
|
||||
|
||||
if (flags & DISP_SPI_SIGNAL_FLUSH) {
|
||||
lv_disp_t * disp = NULL;
|
||||
|
||||
#if (LVGL_VERSION_MAJOR >= 7)
|
||||
disp = _lv_refr_get_disp_refreshing();
|
||||
#else /* Before v7 */
|
||||
disp = lv_refr_get_disp_refreshing();
|
||||
#endif
|
||||
|
||||
#if LVGL_VERSION_MAJOR < 8
|
||||
lv_disp_flush_ready(&disp->driver);
|
||||
#else
|
||||
lv_disp_flush_ready(disp->driver);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if (chained_post_cb) {
|
||||
chained_post_cb(trans);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
/**
|
||||
* @file disp_spi.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DISP_SPI_H
|
||||
#define DISP_SPI_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <driver/spi_master.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef enum _disp_spi_send_flag_t {
|
||||
DISP_SPI_SEND_QUEUED = 0x00000000,
|
||||
DISP_SPI_SEND_POLLING = 0x00000001,
|
||||
DISP_SPI_SEND_SYNCHRONOUS = 0x00000002,
|
||||
DISP_SPI_SIGNAL_FLUSH = 0x00000004,
|
||||
DISP_SPI_RECEIVE = 0x00000008,
|
||||
DISP_SPI_CMD_8 = 0x00000010, /* Reserved */
|
||||
DISP_SPI_CMD_16 = 0x00000020, /* Reserved */
|
||||
DISP_SPI_ADDRESS_8 = 0x00000040,
|
||||
DISP_SPI_ADDRESS_16 = 0x00000080,
|
||||
DISP_SPI_ADDRESS_24 = 0x00000100,
|
||||
DISP_SPI_ADDRESS_32 = 0x00000200,
|
||||
DISP_SPI_MODE_DIO = 0x00000400,
|
||||
DISP_SPI_MODE_QIO = 0x00000800,
|
||||
DISP_SPI_MODE_DIOQIO_ADDR = 0x00001000,
|
||||
DISP_SPI_VARIABLE_DUMMY = 0x00002000,
|
||||
} disp_spi_send_flag_t;
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
void disp_spi_add_device(spi_host_device_t host);
|
||||
void disp_spi_add_device_config(spi_host_device_t host, spi_device_interface_config_t *devcfg);
|
||||
void disp_spi_add_device_with_speed(spi_host_device_t host, int clock_speed_hz);
|
||||
void disp_spi_change_device_speed(int clock_speed_hz);
|
||||
void disp_spi_remove_device();
|
||||
|
||||
/* Important!
|
||||
All buffers should also be 32-bit aligned and DMA capable to prevent extra allocations and copying.
|
||||
When DMA reading (even in polling mode) the ESP32 always read in 4-byte chunks even if less is requested.
|
||||
Extra space will be zero filled. Always ensure the out buffer is large enough to hold at least 4 bytes!
|
||||
*/
|
||||
void disp_spi_transaction(const uint8_t *data, size_t length,
|
||||
disp_spi_send_flag_t flags, uint8_t *out, uint64_t addr, uint8_t dummy_bits);
|
||||
|
||||
void disp_wait_for_pending_transactions(void);
|
||||
void disp_spi_acquire(void);
|
||||
void disp_spi_release(void);
|
||||
|
||||
static inline void disp_spi_send_data(uint8_t *data, size_t length) {
|
||||
disp_spi_transaction(data, length, DISP_SPI_SEND_POLLING, NULL, 0, 0);
|
||||
}
|
||||
|
||||
static inline void disp_spi_send_colors(uint8_t *data, size_t length) {
|
||||
disp_spi_transaction(data, length,
|
||||
DISP_SPI_SEND_QUEUED | DISP_SPI_SIGNAL_FLUSH,
|
||||
NULL, 0, 0);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*DISP_SPI_H*/
|
|
@ -1,107 +0,0 @@
|
|||
/**
|
||||
* @file esp_lcd_backlight.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "esp_lcd_backlight.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/ledc_periph.h" // to invert LEDC output on IDF version < v4.3
|
||||
|
||||
typedef struct {
|
||||
bool pwm_control; // true: LEDC is used, false: GPIO is used
|
||||
int index; // Either GPIO or LEDC channel
|
||||
} disp_backlight_t;
|
||||
|
||||
static const char *TAG = "disp_backlight";
|
||||
|
||||
disp_backlight_h disp_backlight_new(const disp_backlight_config_t *config)
|
||||
{
|
||||
// Check input parameters
|
||||
if (config == NULL)
|
||||
return NULL;
|
||||
if (!GPIO_IS_VALID_OUTPUT_GPIO(config->gpio_num)) {
|
||||
ESP_LOGW(TAG, "Invalid GPIO number");
|
||||
return NULL;
|
||||
}
|
||||
disp_backlight_t *bckl_dev = calloc(1, sizeof(disp_backlight_t));
|
||||
if (bckl_dev == NULL){
|
||||
ESP_LOGW(TAG, "Not enough memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (config->pwm_control){
|
||||
// Configure LED (Backlight) pin as PWM for Brightness control.
|
||||
bckl_dev->pwm_control = true;
|
||||
bckl_dev->index = config->channel_idx;
|
||||
const ledc_channel_config_t LCD_backlight_channel = {
|
||||
.gpio_num = config->gpio_num,
|
||||
.speed_mode = LEDC_LOW_SPEED_MODE,
|
||||
.channel = config->channel_idx,
|
||||
.intr_type = LEDC_INTR_DISABLE,
|
||||
.timer_sel = config->timer_idx,
|
||||
.duty = 0,
|
||||
.hpoint = 0
|
||||
};
|
||||
const ledc_timer_config_t LCD_backlight_timer = {
|
||||
.speed_mode = LEDC_LOW_SPEED_MODE,
|
||||
.bit_num = LEDC_TIMER_10_BIT,
|
||||
.timer_num = config->timer_idx,
|
||||
.freq_hz = 5000,
|
||||
.clk_cfg = LEDC_AUTO_CLK};
|
||||
|
||||
ESP_ERROR_CHECK(ledc_timer_config(&LCD_backlight_timer));
|
||||
ESP_ERROR_CHECK(ledc_channel_config(&LCD_backlight_channel));
|
||||
gpio_matrix_out(config->gpio_num, ledc_periph_signal[LEDC_LOW_SPEED_MODE].sig_out0_idx + config->channel_idx, config->output_invert, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Configure GPIO for output
|
||||
bckl_dev->index = config->gpio_num;
|
||||
gpio_pad_select_gpio(config->gpio_num);
|
||||
ESP_ERROR_CHECK(gpio_set_direction(config->gpio_num, GPIO_MODE_OUTPUT));
|
||||
gpio_matrix_out(config->gpio_num, SIG_GPIO_OUT_IDX, config->output_invert, false);
|
||||
}
|
||||
|
||||
return (disp_backlight_h)bckl_dev;
|
||||
}
|
||||
|
||||
void disp_backlight_set(disp_backlight_h bckl, int brightness_percent)
|
||||
{
|
||||
// Check input paramters
|
||||
if (bckl == NULL)
|
||||
return;
|
||||
if (brightness_percent > 100)
|
||||
brightness_percent = 100;
|
||||
if (brightness_percent < 0)
|
||||
brightness_percent = 0;
|
||||
|
||||
disp_backlight_t *bckl_dev = (disp_backlight_t *) bckl;
|
||||
ESP_LOGI(TAG, "Setting LCD backlight: %d%%", brightness_percent);
|
||||
|
||||
if (bckl_dev->pwm_control) {
|
||||
uint32_t duty_cycle = (1023 * brightness_percent) / 100; // LEDC resolution set to 10bits, thus: 100% = 1023
|
||||
ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, bckl_dev->index, duty_cycle));
|
||||
ESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, bckl_dev->index));
|
||||
} else {
|
||||
ESP_ERROR_CHECK(gpio_set_level(bckl_dev->index, brightness_percent));
|
||||
}
|
||||
}
|
||||
|
||||
void disp_backlight_delete(disp_backlight_h bckl)
|
||||
{
|
||||
if (bckl == NULL)
|
||||
return;
|
||||
|
||||
disp_backlight_t *bckl_dev = (disp_backlight_t *) bckl;
|
||||
if (bckl_dev->pwm_control) {
|
||||
ledc_stop(LEDC_LOW_SPEED_MODE, bckl_dev->index, 0);
|
||||
} else {
|
||||
gpio_reset_pin(bckl_dev->index);
|
||||
}
|
||||
free (bckl);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue