飛書文檔https://x509p6c8to.feishu.cn/docx/doxcnlzpIgj3gosCZufBTCZxlMb
SPI說明
SPI是串行外設接口(Serial Peripheral Interface)的縮寫,是一種高速的,全雙工,同步的通信總線,并且在芯片的管腳上占用四根線。
參考源碼位置
/home/kemp/work/esp/esp-idf/examples/peripherals/spi_master
源碼下載方式參考:
源碼下載方式
屏幕接口
SCLK IO25 SPI 串口通信時鐘信號線。
SDI? IO26 SPI 串口通信數據信號線。
CS? IO27 片選,低電平有效。
D/C IO14 數據/命令 讀寫選擇,高電平為數據,低電平為命令。
RES IO12 電子紙復位信號,低電平有效。
BUSY IO13 電子紙刷新時,BUSY 引腳發出忙信號給主 MCU,此時 MCU 無法對電子紙驅動 IC 進行讀寫操作;電子紙刷新完成后,BUSY 引腳發出閑置狀態信號,此時 MCU 可以對 電子紙驅動 IC 進行讀寫操作。GDEW 系列電子紙 BUSY 引腳忙狀態為高電平(GDEH 系列為低電平),BUSY 引腳空閑狀態反之。
墨水屏原理
152*152個像素 19Byte=152Bit 19*152的數組
152*152??? 19BYTE?? 1BYTE=8BIT? 0000 0000? 1111 1111
更多屏幕相關手冊
1.54寸電子紙屏/ 152x152分辨率電子紙/ 四灰階/ 支持局部刷新電子墨水屏 GDEW0154T8D_電子紙屏-大連佳顯電子有限公司
代碼說明
SPI部分
SPI Master Driver - - ? ESP-IDF 編程指南 release-v4.1 文檔
/* SPI Master exampleThis example code is in the Public Domain (or CC0 licensed, at your option.)Unless required by applicable law or agreed to in writing, thissoftware is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES ORCONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"#include "ds_gpio.h"//#define PIN_NUM_MISO 1? //屏幕只寫不讀,此引腳不用
#define PIN_NUM_MOSI 26
#define PIN_NUM_CLK? 25
#define PIN_NUM_CS?? 27spi_device_handle_t spi;void spi_send_cmd(const uint8_t cmd)
{esp_err_t ret;spi_transaction_t t;//設置發送指令ds_gpio_set_screen_dc(0);//設置片選模塊ds_gpio_set_screen_cs(0);memset(&t, 0, sizeof(t));?????? //Zero out the transaction// t.flags=SPI_TRANS_USE_TXDATA;t.length=8;???????????????????? //Command is 8 bitst.tx_buffer=&cmd;?????????????? //The data is the cmd itselft.user=(void*)0;??????????????? //D/C needs to be set to 0//發送指令ret=spi_device_polling_transmit(spi, &t);? //Transmit!//取消片選模塊ds_gpio_set_screen_cs(1);assert(ret==ESP_OK);??????????? //Should have had no issues.
}void spi_send_data(const uint8_t data)
{esp_err_t ret;spi_transaction_t t;//設置發送數據ds_gpio_set_screen_dc(1);//設置片選模塊ds_gpio_set_screen_cs(0);memset(&t, 0, sizeof(t));?????? //Zero out the transactiont.length=8;???????????????? //Len is in bytes, transaction length is in bits.t.tx_buffer=&data;?????????????? //Datat.user=(void*)1;??????????????? //D/C needs to be set to 1//發送數據ret=spi_device_polling_transmit(spi, &t);? //Transmit!//取消片選模塊ds_gpio_set_screen_cs(1);assert(ret==ESP_OK);??????????? //Should have had no issues.
}//This function is called (in irq context!) just before a transmission starts. It will
//set the D/C line to the value indicated in the user field.
void spi_pre_transfer_callback(spi_transaction_t *t)
{int dc=(int)t->user;printf("dc callback\n");ds_gpio_set_screen_dc(dc);
}void screen_spi_init(void)
{esp_err_t ret;//IO設置spi_bus_config_t buscfg={.miso_io_num = PIN_NUM_MISO,??????????????? // MISO信號線.mosi_io_num = PIN_NUM_MOSI,??????????????? // MOSI信號線.sclk_io_num = PIN_NUM_CLK,???????????????? // SCLK信號線.quadwp_io_num = -1,??????????????????????? // WP信號線,專用于QSPI的D2.quadhd_io_num = -1,??????????????????????? // HD信號線,專用于QSPI的D3.max_transfer_sz = 64*8,??????????????????? // 最大傳輸數據大小};//速率 模式設置spi_device_interface_config_t devcfg={.clock_speed_hz=15*1000*1000,??????????? //Clock out at 26 MHz.mode=0,??????????????????????????????? //SPI mode 0.queue_size=7,????????????????????????? //We want to be able to queue 7 transactions at a time// .pre_cb=spi_pre_transfer_callback,? //Specify pre-transfer callback to handle D/C line};//Initialize the SPI busret=spi_bus_initialize(HSPI_HOST, &buscfg, 0);ESP_ERROR_CHECK(ret);//Attach the LCD to the SPI busret=spi_bus_add_device(HSPI_HOST, &devcfg, &spi);ESP_ERROR_CHECK(ret);}void screen_spi_test(){spi_send_cmd(0x55);vTaskDelay(10 / portTICK_PERIOD_MS);spi_send_data(0x55);
}
屏幕驅動部分
注意:這里的代碼和視頻中不太一樣,因為舊版本屏幕停產,更換了屏幕型號,下方代碼為0154B-D67的屏幕驅動代碼,和最新版本屏幕是一致的。
#include <string.h>
#include <stdio.h>#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"#include "ds_screen.h"
#include "ds_gpio.h"
#include "ds_spi.h"
#include "ds_data_image.h"// Detection busy
static void lcd_chkstatus(void)
{int count = 0;unsigned char busy;while (1){busy = ds_gpio_get_screen_busy();busy = (busy & 0x01);//=1 BUSYif (busy == 0)break;vTaskDelay(10 / portTICK_PERIOD_MS);count++;if (count >= 1000){printf("---------------time out ---\n");break;}}
}static void init_display()
{vTaskDelay(10 / portTICK_PERIOD_MS);ds_gpio_set_screen_rst(0); // Module resetvTaskDelay(10 / portTICK_PERIOD_MS);ds_gpio_set_screen_rst(1);vTaskDelay(100 / portTICK_PERIOD_MS);lcd_chkstatus();spi_send_cmd(0x12); // SWRESETlcd_chkstatus();spi_send_cmd(0x01); // Driver output controlspi_send_data(0xC7);spi_send_data(0x00);spi_send_data(0x01);spi_send_cmd(0x11); // data entry modespi_send_data(0x01);spi_send_cmd(0x44); // set Ram-X address start/end positionspi_send_data(0x00);spi_send_data(0x18); // 0x0C-->(18+1)*8=200spi_send_cmd(0x45);? // set Ram-Y address start/end positionspi_send_data(0xC7); // 0xC7-->(199+1)=200spi_send_data(0x00);spi_send_data(0x00);spi_send_data(0x00);spi_send_cmd(0x3C); // BorderWavefromspi_send_data(0x05);spi_send_cmd(0x18); // Read built-in temperature sensorspi_send_data(0x80);spi_send_cmd(0x4E); // set RAM x address count to 0;spi_send_data(0x00);spi_send_cmd(0x4F); // set RAM y address count to 0X199;spi_send_data(0xC7);spi_send_data(0x00);vTaskDelay(100 / portTICK_PERIOD_MS);lcd_chkstatus();
}/Enter deep sleep mode
void deep_sleep(void) // Enter deep sleep mode
{spi_send_cmd(0x10); // enter deep sleepspi_send_data(0x01);vTaskDelay(100 / portTICK_PERIOD_MS);
}void refresh(void)
{spi_send_cmd(0x22); // Display Update Controlspi_send_data(0xF7);spi_send_cmd(0x20); // Activate Display Update Sequencelcd_chkstatus();
}void refresh_part(void)
{spi_send_cmd(0x22); // Display Update Controlspi_send_data(0xFF);spi_send_cmd(0x20); // Activate Display Update Sequencelcd_chkstatus();
}// 圖片全刷-全白函數
static void ds_screen_display_white(void)
{unsigned int i, k;spi_send_cmd(0x24); // write RAM for black(0)/white (1)for (k = 0; k < 250; k++){for (i = 0; i < 25; i++){spi_send_data(0xff);}}
}// 圖片全刷-數據函數
void ds_screen_full_display_data(const uint8_t *data)
{unsigned int i;spi_send_cmd(0x24); // write RAM for black(0)/white (1)for (i = 0; i < 5000; i++){spi_send_data(*data);data++;}
}// 全刷 不帶數據
void ds_screen_full_display(void pic_display(void))
{init_display();pic_display(); // picturerefresh();???? // EPD_refreshdeep_sleep();
}// 全刷 帶數據
void ds_screen_full_display_bydata(void display_func(const uint8_t *data), const uint8_t *data)
{init_display();display_func(data); // picturerefresh();????????? // EPD_refreshdeep_sleep();
}// 局部刷 不帶數據
void ds_screen_partial_display(unsigned int x_start, unsigned int y_start, void partial_new(void), unsigned int PART_COLUMN, unsigned int PART_LINE)
{unsigned int i;unsigned int x_end, y_start1, y_start2, y_end1, y_end2;x_start = x_start / 8;x_end = x_start + PART_LINE / 8 - 1;y_start1 = 0;y_start2 = 200 - y_start;if (y_start >= 256){y_start1 = y_start2 / 256;y_start2 = y_start2 % 256;}y_end1 = 0;y_end2 = y_start2 + PART_COLUMN - 1;if (y_end2 >= 256){y_end1 = y_end2 / 256;y_end2 = y_end2 % 256;}// Add hardware reset to prevent background color changeds_gpio_set_screen_rst(0); // Module resetvTaskDelay(10 / portTICK_PERIOD_MS);ds_gpio_set_screen_rst(1);vTaskDelay(10 / portTICK_PERIOD_MS);// Lock the border to prevent flashingspi_send_cmd(0x3C); // BorderWavefrom,spi_send_data(0x80);spi_send_cmd(0x44);????? // set RAM x address start/end, in page 35spi_send_data(x_start);? // RAM x address start at 00h;spi_send_data(x_end);??? // RAM x address end at 0fh(15+1)*8->128spi_send_cmd(0x45);????? // set RAM y address start/end, in page 35spi_send_data(y_start2); // RAM y address start at 0127h;spi_send_data(y_start1); // RAM y address start at 0127h;spi_send_data(y_end2);?? // RAM y address end at 00h;spi_send_data(y_end1);?? // ????=0spi_send_cmd(0x4E); // set RAM x address count to 0;spi_send_data(x_start);spi_send_cmd(0x4F); // set RAM y address count to 0X127;spi_send_data(y_start2);spi_send_data(y_start1);spi_send_cmd(0x24); // Write Black and White image to RAMpartial_new();refresh_part();deep_sleep();
}// 局部刷 帶數據
void ds_screen_partial_display_bydata(unsigned int x_start, unsigned int y_start,void partial_new(const uint8_t *data), const uint8_t *new_data,unsigned int PART_COLUMN, unsigned int PART_LINE)
{printf("x_start=%d x_end=%d y_start=%d y_end=%d\n", x_start, y_start, PART_COLUMN, PART_LINE);unsigned int i;unsigned int x_end, y_start1, y_start2, y_end1, y_end2;x_start = x_start / 8;x_end = x_start + PART_LINE / 8 - 1;y_start1 = 0;y_start2 = 200 - y_start;if (y_start >= 256){y_start1 = y_start2 / 256;y_start2 = y_start2 % 256;}y_end1 = 0;y_end2 = y_start2 + PART_COLUMN - 1;if (y_end2 >= 256){y_end1 = y_end2 / 256;y_end2 = y_end2 % 256;}// Add hardware reset to prevent background color changeds_gpio_set_screen_rst(0); // Module resetvTaskDelay(10 / portTICK_PERIOD_MS);ds_gpio_set_screen_rst(1);vTaskDelay(10 / portTICK_PERIOD_MS);// Lock the border to prevent flashingspi_send_cmd(0x3C); // BorderWavefrom,spi_send_data(0x80);spi_send_cmd(0x44);????? // set RAM x address start/end, in page 35spi_send_data(x_start);? // RAM x address start at 00h;spi_send_data(x_end);??? // RAM x address end at 0fh(15+1)*8->128spi_send_cmd(0x45);????? // set RAM y address start/end, in page 35spi_send_data(y_start2); // RAM y address start at 0127h;spi_send_data(y_start1); // RAM y address start at 0127h;spi_send_data(y_end2);?? // RAM y address end at 00h;spi_send_data(y_end1);?? // ????=0spi_send_cmd(0x4E); // set RAM x address count to 0;spi_send_data(x_start);spi_send_cmd(0x4F); // set RAM y address count to 0X127;spi_send_data(y_start2);spi_send_data(y_start1);spi_send_cmd(0x24); // Write Black and White image to RAMpartial_new(new_data);
}uint8_t partial_data[200][25];
uint8_t partial_data_array[5000];void ds_screen_partial_data_init()
{for (int index = 0; index < 200; index++){for (int yindex = 0; yindex < 25; yindex++){partial_data[index][yindex] = 0xff;}}
}void ds_screen_partial_data_add(unsigned int x_start, unsigned int x_end, unsigned int y_start, unsigned int y_end, const uint8_t *data)
{uint8_t x_len = x_end - x_start;// uint8_t y_len = y_end - y_start;uint8_t x_data_location = x_start / 8;uint8_t x_size = x_len / 8;int data_index = 0;// int move = x_start % 8;if (x_start % 8 != 0){x_data_location++;}if (x_len % 8 != 0){x_size++;}for (int x_index = y_start; x_index < y_end; x_index++){for (int y_index = x_data_location; y_index < (x_data_location + x_size); y_index++){partial_data[x_index][y_index] = (~data[data_index]);data_index++;}}
}// 圖片全刷-全白函數
static void ds_screen_display_data(void)
{unsigned int i;spi_send_cmd(0x24);for (i = 0; i < 5000; i++){spi_send_data(partial_data_array[i]);}spi_send_cmd(0x26);for (i = 0; i < 5000; i++){spi_send_data(partial_data_array[i]);}
}// 局刷數據-復制
void ds_screen_partial_data_copy()
{int data_index = 0;for (int index = 0; index < 200; index++){for (int yindex = 0; yindex < 25; yindex++){partial_data_array[data_index] = partial_data[index][yindex];data_index++;}}ds_screen_full_display(ds_screen_display_data);
}// 接口初始化
void init_screen_interface()
{ds_screen_gpio_init();screen_spi_init();
}// 清屏為白色
void ds_screen_clean_white()
{ds_screen_init();vTaskDelay(2000 / portTICK_PERIOD_MS);
}// 初始化
void ds_screen_init()
{ds_screen_full_display(ds_screen_display_white); // EPD_sleep
}
參考:
【科普貼】SPI接口詳解_湉湉家的小虎子的博客-CSDN博客_spi
1.54寸高頻刷新 快刷1.5秒電子墨水屏 分辨率200x200 SPI串口 GDEY0154D67_電子墨水屏幕-大連佳顯電子