当前位置: 首页 > ops >正文

桌面小屏幕实战课程:DesktopScreen 11 SPI 水墨屏

飞书文档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_电子墨水屏幕-大连佳显电子

http://www.xdnf.cn/news/14649.html

相关文章:

  • 基于SpringBoot和Leaflet的区域冲突可视化-以伊以冲突为例
  • Robyn高性能Web框架系列06:使用WebSocket实现产品智能助理
  • SQL学习笔记3
  • 图像质量对比感悟
  • 智表ZCELL产品V3.2 版发布,新增拖动调整行列功能,修复了插件引用相对路径等问题
  • 【C++11】右值引用和移动语义
  • Hive3.1.3加载paimon-hive-connector-3.1-1.1.1.jar报错UnsatisfiedLinkError
  • 解决uniapp vue3版本封装组件后:deep()样式穿透不生效的问题
  • 【攻防篇】解决:阿里云docker 容器中自动启动xmrig挖矿
  • 超实用AI工具分享——ViiTor AI视频配音功能教程(附图文)
  • php项目部署----------酒店项目
  • 知攻善防应急靶机 Windows web 3
  • LVS-DR负载均衡群集深度实践:高性能架构设计与排障指南
  • 笔记02:布线-差分对的设置与添加
  • Liunx操作系统笔记2
  • 《解锁前端潜力:自动化流程搭建秘籍》
  • Boosting:从理论到实践——集成学习中的偏差征服者
  • linux-修改文件命令(补充)
  • Jenkins Pipeline 与 Python 脚本之间使用环境变量通信
  • 数的三次方根
  • 【深度学习新浪潮】空间计算的医疗应用技术分析(简要版)
  • TCP/UDP协议深度解析(二):TCP连接管理全解,三次握手四次挥手的完整流程
  • Linux docker拉取镜像报错解决
  • 空间理解模型 SpatialLM 正式发布首份技术报告
  • 数据结构 顺序表与链表
  • 一步部署APache编译安装脚本
  • 基于SSM框架+mysql实现的监考安排管理系统[含源码+数据库+项目开发技术手册]
  • 使用VIVADO合并FPGA bit文件和Microblaze elf
  • SQL学习笔记2
  • 【大厂机试题解法笔记】可以组成网络的服务器