/* Drivers */ #include "fsl_clock.h" #include "fsl_common.h" #include "fsl_dmamux.h" #include "fsl_edma.h" #include "fsl_gpio.h" /* Board */ #include "peripherals.h" #include "pin_mux.h" /* LCD panel */ #include "epd-spi/panel/lcd_generic_ssd1289.h" /* Private header */ #include "lcd_impl.h" #define IMPL_LCD_DMA_INSTANCE DMA0 #define IMPL_LCD_DMAMUX_INSTANCE DMAMUX0 #define IMPL_LCD_DMA_CHANNEL 0 #define IMPL_LCD_DMA_REQUEST 63 /* Always On Request */ #define IMPL_LCD_COMMAND_BASE ((uint16_t *)0x70000000) #define IMPL_LCD_DATA_BASE ((uint16_t *)0x78000000) static void epd_impl_edma_callback(edma_handle_t *handle, void *userData, bool transferDone, uint32_t tcds) { lcd_impl_t *impl = userData; BaseType_t xHigherPriorityTaskWoken; xSemaphoreGiveFromISR(impl->dma_semphr, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } epd_ret_t epd_impl_init(void *handle) { lcd_impl_t *impl = handle; impl->dma_semphr = xSemaphoreCreateBinary(); if (impl->dma_semphr == NULL) { return EPD_FAIL; } /* Async flush */ xSemaphoreGive(impl->dma_semphr); DMAMUX_SetSource(IMPL_LCD_DMAMUX_INSTANCE, IMPL_LCD_DMA_CHANNEL, IMPL_LCD_DMA_REQUEST); DMAMUX_EnableChannel(IMPL_LCD_DMAMUX_INSTANCE, IMPL_LCD_DMA_CHANNEL); EDMA_CreateHandle(&impl->dma_handle, IMPL_LCD_DMA_INSTANCE, IMPL_LCD_DMA_CHANNEL); EDMA_SetCallback(&impl->dma_handle, epd_impl_edma_callback, impl); return EPD_OK; } epd_ret_t epd_impl_write_command(void *handle, uint8_t *command, uint32_t len) { uint32_t param_len = (len - 1) / 2; *IMPL_LCD_COMMAND_BASE = command[0]; for (uint32_t i = 0; i < param_len; i++) { uint16_t le_param = (command[2 * i + 1] << 8) | command[2 * i + 2]; *IMPL_LCD_DATA_BASE = le_param; } return EPD_OK; } epd_ret_t epd_impl_write_data(void *handle, uint8_t *data, uint32_t len) { lcd_impl_t *impl = handle; uint32_t data_len = (len / 2); edma_transfer_config_t cfg = { .srcAddr = (uint32_t)data, .srcTransferSize = kEDMA_TransferSize2Bytes, .srcOffset = 2U, .destAddr = (uint32_t)IMPL_LCD_DATA_BASE, .destTransferSize = kEDMA_TransferSize2Bytes, .destOffset = 0U, /* Destination is not self-incrementing */ .majorLoopCounts = data_len, .minorLoopBytes = 2, }; /* Wait for DMA transfer complete. */ if (xSemaphoreTake(impl->dma_semphr, portMAX_DELAY) != pdPASS) { return EPD_FAIL; } EDMA_SubmitTransfer(&impl->dma_handle, &cfg); EDMA_StartTransfer(&impl->dma_handle); return EPD_OK; } epd_ret_t epd_impl_reset(void *handle) { GPIO_WritePinOutput(BOARD_INITPINS_TFT_RESET_GPIO, BOARD_INITPINS_TFT_RESET_PIN, 0U); vTaskDelay(pdMS_TO_TICKS(20)); GPIO_WritePinOutput(BOARD_INITPINS_TFT_RESET_GPIO, BOARD_INITPINS_TFT_RESET_PIN, 1U); vTaskDelay(pdMS_TO_TICKS(20)); return EPD_OK; } epd_ret_t epd_impl_delay(void *handle, uint32_t msec) { vTaskDelay(pdMS_TO_TICKS(msec)); return EPD_OK; }