#include #include #include "driver/spi_master.h" #include "driver/gpio.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "atascii.h" #include "esp_log.h" #define NUM_COL 160 #define NUM_ROW 8 #define CHAR_HEIGHT 8 #define CHAR_WIDTH 8 #define RED 1 #define GREEN 2 #define ORANGE 3 #define PIN_NUM_MISO 12 #define PIN_NUM_MOSI 13 #define PIN_NUM_CLK 14 #define PIN_NUM_CS 15 #define PIN_NUM_R_LATCH 16 #define PIN_NUM_R_CLK 17 #define PIN_NUM_R_ADDR_0 5 #define PIN_NUM_R_ADDR_1 18 #define PIN_NUM_R_ADDR_2 19 #define TAG "led_display" static uint16_t pattern[NUM_ROW][NUM_COL / 8]; // each column is two bits, so 8 can fit in 16-bit integer void draw_char_at_position(char character, uint16_t col_start, uint16_t row_start, uint16_t color) { uint8_t cur_char_row; for(int row = row_start; (row - row_start) < CHAR_HEIGHT && row < NUM_ROW; row++) { cur_char_row = atascii_font[(uint8_t) character][row - row_start]; for(int col = col_start; (col - col_start) < CHAR_WIDTH && col < NUM_COL; col++) { pattern[row][col / 8] = (pattern[row][col / 8] & ~(0b0000000000000011 << (2 * (col - col_start)))); // clear this column (note the bitwise inversion) if((1 << (col - col_start)) & cur_char_row) { pattern[row][col / 8] = ((pattern[row][col / 8]) | color << (2 * (col - col_start))); // write color to column } } } } void app_main(void) { esp_err_t ret; spi_device_handle_t spi; spi_bus_config_t buscfg={ .miso_io_num=PIN_NUM_MISO, .mosi_io_num=PIN_NUM_MOSI, .sclk_io_num=PIN_NUM_CLK, .quadwp_io_num=-1, .quadhd_io_num=-1, .max_transfer_sz=3*600*2*8, .flags=SPICOMMON_BUSFLAG_DUAL }; spi_device_interface_config_t devcfg={ .clock_speed_hz=1*1000*1000, //Clock out at 1 MHz .mode=0, //SPI mode 0 .spics_io_num=PIN_NUM_CS, //CS pin .queue_size=1, //We want to be able to queue 7 transactions at a time .flags=SPI_DEVICE_HALFDUPLEX, //Needed to use both data lines for output }; //Initialize the SPI bus and attach our device handle ret=spi_bus_initialize(HSPI_HOST, &buscfg, SPI_DMA_CH_AUTO); ESP_ERROR_CHECK(ret); ret=spi_bus_add_device(HSPI_HOST, &devcfg, &spi); ESP_ERROR_CHECK(ret); ESP_LOGI(TAG, "Initialized SPI host."); gpio_set_direction(PIN_NUM_R_LATCH, GPIO_MODE_OUTPUT); gpio_set_direction(PIN_NUM_R_CLK, GPIO_MODE_OUTPUT); gpio_set_direction(PIN_NUM_R_ADDR_0, GPIO_MODE_OUTPUT); gpio_set_direction(PIN_NUM_R_ADDR_1, GPIO_MODE_OUTPUT); gpio_set_direction(PIN_NUM_R_ADDR_2, GPIO_MODE_OUTPUT); ESP_LOGI(TAG, "Setup GPIO."); char* text = "Hello World!! 1234567890"; for(int i = 0; i < strlen(text); i++) { draw_char_at_position(text[i], i * CHAR_WIDTH, 0, RED); } ESP_LOG_BUFFER_HEX(TAG, pattern[0], 16); ESP_LOG_BUFFER_HEX(TAG, pattern[1], 16); ESP_LOG_BUFFER_HEX(TAG, pattern[2], 16); ESP_LOG_BUFFER_HEX(TAG, pattern[3], 16); ESP_LOG_BUFFER_HEX(TAG, pattern[4], 16); ESP_LOG_BUFFER_HEX(TAG, pattern[5], 16); ESP_LOG_BUFFER_HEX(TAG, pattern[6], 16); ESP_LOG_BUFFER_HEX(TAG, pattern[7], 16); ESP_LOGI(TAG, "Done drawing pattern."); ESP_LOGI(TAG, "Ticks per MS: %i", (int) portTICK_PERIOD_MS); TickType_t xLastWakeTime; const TickType_t xFrequency = 1 / portTICK_PERIOD_MS; xLastWakeTime = xTaskGetTickCount(); ESP_LOGI(TAG, "Ticks between updates: %i", (int) xFrequency); uint8_t current_row = 0; uint16_t refresh_count = 0; TickType_t startMillis = xTaskGetTickCount(); TickType_t endMillis; uint8_t i = 0; uint16_t data; while(true) { vTaskDelayUntil(&xLastWakeTime, xFrequency); for(i = 0; i < (NUM_COL / 8); i++) { spi_transaction_t t; memset(&t, 0, sizeof(t)); t.length = 16; data = SPI_SWAP_DATA_TX(pattern[current_row][i], 16); t.tx_buffer = &data; t.flags = SPI_TRANS_MODE_DIO; // output on two data lines. Even bits go to GREEN, odd to RED ret = spi_device_polling_transmit(spi, &t); ESP_ERROR_CHECK(ret); } gpio_set_level(PIN_NUM_R_LATCH, 0); gpio_set_level(PIN_NUM_R_CLK, 1); gpio_set_level(PIN_NUM_R_ADDR_0, 1 & current_row); gpio_set_level(PIN_NUM_R_ADDR_1, 1 & (current_row >> 1)); gpio_set_level(PIN_NUM_R_ADDR_2, 1 & (current_row >> 2)); gpio_set_level(PIN_NUM_R_LATCH, 1); gpio_set_level(PIN_NUM_R_CLK, 0); if(++current_row == NUM_ROW) { current_row = 0; if(++refresh_count == 1000) { endMillis = xTaskGetTickCount(); ESP_LOGI(TAG, "Refresh Rate: %f Hz", (float) refresh_count * 1000 / (endMillis - startMillis)); refresh_count = 0; startMillis = xTaskGetTickCount(); } } } }