ESP32S2_Cal/main/impl/impl_epd.c

179 lines
4.9 KiB
C

#include "impl_epd.h"
#define EPD_GPIO_MOSI GPIO_NUM_15
#define EPD_GPIO_SCLK GPIO_NUM_14
#define EPD_GPIO_BUSY GPIO_NUM_11
#define EPD_GPIO_CS GPIO_NUM_13
#define EPD_GPIO_RES GPIO_NUM_10
#define EPD_GPIO_DC GPIO_NUM_12
#define EPD_SPI_HOST SPI2_HOST
#define EPD_SPI_SPEED (16 * 1000 * 1000) /* 16MHz */
#define EPD_SPI_MAX_XFER_SIZE (1024)
/* Pre-transfer callback for SPI driver. */
static void impl_epd_spi_pre_transfer_cb(spi_transaction_t *txn) {
uint32_t dc_value = (uint32_t)txn->user;
gpio_set_level(EPD_GPIO_DC, dc_value);
}
static void IRAM_ATTR impl_epd_busy_irq_handler(void *arg) {
impl_epd_handle_t *epd = arg;
BaseType_t xHigherPriorityTaskWoken;
xSemaphoreGiveFromISR(epd->busy_semaphore, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
esp_err_t impl_epd_init(void *handle) {
esp_err_t ret;
spi_bus_config_t bus_config = {
.mosi_io_num = EPD_GPIO_MOSI,
.sclk_io_num = EPD_GPIO_SCLK,
.miso_io_num = -1,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = EPD_SPI_MAX_XFER_SIZE,
};
spi_device_interface_config_t device_config = {
.clock_speed_hz = EPD_SPI_SPEED,
.mode = 0,
.spics_io_num = EPD_GPIO_CS,
.queue_size = 7,
.pre_cb = impl_epd_spi_pre_transfer_cb,
};
impl_epd_handle_t *epd = handle;
/* Initialize SPI bus */
ret = spi_bus_initialize(EPD_SPI_HOST, &bus_config, SPI_DMA_CH_AUTO);
ESP_ERROR_CHECK(ret);
ret = spi_bus_add_device(EPD_SPI_HOST, &device_config, &epd->spi);
ESP_ERROR_CHECK(ret);
/* Initialize RTOS components */
epd->busy_semaphore = xSemaphoreCreateBinary();
if (epd->busy_semaphore == NULL) {
return ESP_FAIL;
}
/* Initialize auxillary IOs */
gpio_set_direction(EPD_GPIO_BUSY, GPIO_MODE_INPUT);
gpio_set_direction(EPD_GPIO_DC, GPIO_MODE_OUTPUT);
gpio_set_direction(EPD_GPIO_RES, GPIO_MODE_OUTPUT);
// Set up EPD busy interrupt
gpio_pullup_en(EPD_GPIO_BUSY);
gpio_set_intr_type(EPD_GPIO_BUSY, GPIO_INTR_POSEDGE);
gpio_isr_handler_add(EPD_GPIO_BUSY, impl_epd_busy_irq_handler, epd);
/* Release RESET pin */
gpio_set_level(EPD_GPIO_RES, 1);
return ret;
}
epd_ret_t impl_epd_write_command(void *handle, uint8_t *command, uint32_t len) {
esp_err_t ret = EPD_OK;
spi_transaction_t txn;
impl_epd_handle_t *epd = handle;
memset(&txn, 0x0, sizeof(txn));
txn.length = 8;
txn.tx_buffer = command;
txn.user = (void *)0;
ret = spi_device_polling_transmit(epd->spi, &txn);
if (ret != ESP_OK) ret = EPD_FAIL;
if (len > 1) {
txn.length = 8 * (len - 1);
txn.tx_buffer = &command[1];
txn.user = (void *)1;
ret = spi_device_polling_transmit(epd->spi, &txn);
if (ret != ESP_OK) ret = EPD_FAIL;
}
return ret;
}
epd_ret_t impl_epd_write_data(void *handle, uint8_t *data, uint32_t len) {
esp_err_t ret = EPD_OK;
spi_transaction_t txn;
impl_epd_handle_t *epd = handle;
uint8_t *dma_buffer = heap_caps_malloc(EPD_SPI_MAX_XFER_SIZE, MALLOC_CAP_DMA);
if (dma_buffer == NULL) return EPD_FAIL;
memset(&txn, 0x0, sizeof(txn));
uint8_t has_partial = (len % EPD_SPI_MAX_XFER_SIZE ? 1 : 0);
uint32_t txn_count = len / EPD_SPI_MAX_XFER_SIZE + has_partial;
txn.user = (void *)1;
for (uint32_t i = 0; i < txn_count; i++) {
uint16_t txn_bytes = EPD_SPI_MAX_XFER_SIZE;
if ((i == txn_count - 1) && has_partial) {
txn_bytes = len % EPD_SPI_MAX_XFER_SIZE;
}
memcpy(dma_buffer, &data[i * EPD_SPI_MAX_XFER_SIZE], txn_bytes);
txn.length = 8 * txn_bytes;
txn.rxlength = 0;
txn.tx_buffer = dma_buffer;
ret = spi_device_polling_transmit(epd->spi, &txn);
if (ret != ESP_OK) ret = EPD_FAIL;
}
free(dma_buffer);
return ret;
}
epd_ret_t impl_epd_reset(void *handle) {
for (uint8_t i = 0; i < 4; i++) {
gpio_set_level(EPD_GPIO_RES, 0);
vTaskDelay(pdMS_TO_TICKS(10));
gpio_set_level(EPD_GPIO_RES, 1);
vTaskDelay(pdMS_TO_TICKS(10));
}
vTaskDelay(pdMS_TO_TICKS(50));
return EPD_OK;
}
epd_ret_t impl_epd_poll_busy(void *handle) {
impl_epd_handle_t *epd = handle;
if (gpio_get_level(EPD_GPIO_BUSY) == 1) {
return EPD_OK;
}
gpio_intr_enable(EPD_GPIO_BUSY);
if (xSemaphoreTake(epd->busy_semaphore, pdMS_TO_TICKS(10000)) != pdTRUE) {
gpio_intr_disable(EPD_GPIO_BUSY);
return EPD_FAIL;
}
gpio_intr_disable(EPD_GPIO_BUSY);
return EPD_OK;
}
epd_ret_t impl_epd_delay(void *handle, uint32_t msec) {
vTaskDelay(pdMS_TO_TICKS(msec));
return EPD_OK;
}