AIR32F103(十一) 在AIR32F103上移植微雪墨水屏驱动

科技资讯 投稿 5500 0 评论

AIR32F103(十一) 在AIR32F103上移植微雪墨水屏驱动

目录

    AIR32F103(一 合宙AIR32F103CBT6开发板上手报告
  • AIR32F103(二 Linux环境和LibOpenCM3项目模板
  • AIR32F103(三 Linux环境基于标准外设库的项目模板
  • AIR32F103(四 27倍频216MHz,CoreMark跑分测试
  • AIR32F103(五 FreeRTOSv202112核心库的集成和示例代码
  • AIR32F103(六 ADC,I2S,DMA和ADPCM实现的录音播放功能
  • AIR32F103(七 AIR32F103CBT6/CCT6启用96K内存
  • AIR32F103(八 集成Helix MP3解码库播放MP3
  • AIR32F103(九 CAN总线的通信和ID过滤机制及实例
  • AIR32F103(十 在无系统环境和FreeRTOS环境集成LVGL
  • AIR32F103(十一 在AIR32F103上移植微雪墨水屏驱动

电子墨水屏 Electronic Paper, Digital Paper

之前在合宙上买了一片1.54寸的墨水屏一直在吃灰, 这次趁点亮的机会把AIR32F103上的驱动示例给做了。

微雪驱动库

他们维护了一个品类众多(45种的墨水屏型号列表, 在 GitHub 上有一个专门的代码仓库

微雪的这个驱动库代码质量还是不错的. 里面带了针对 RaspberryPi, Arduino 和 STM32 的驱动, STM32的这个驱动, 用的硬件是 STM32F103ZET6, 迁移到AIR32F103很方便。

EPD_1IN54
EPD_1IN54B_V2
EPD_1IN54B
EPD_1IN54C
EPD_1IN64G
EPD_2IN7_V2
EPD_2IN7
EPD_2IN7B_V2
EPD_2IN7B
EPD_2IN9_V2
EPD_2IN9
EPD_2IN9B_V3
EPD_2IN9BC
EPD_2IN9D
EPD_2IN13_V2
EPD_2IN13_V3
EPD_2IN13
EPD_2IN13B_V3
EPD_2IN13B_V4
EPD_2IN13BC
EPD_2IN13D
EPD_2IN36G
EPD_2IN66
EPD_2IN66B
EPD_3IN0G
EPD_3IN7
EPD_3IN52
EPD_4IN01F
EPD_4IN2
EPD_4IN2B_V2
EPD_4IN2BC
EPD_4IN37G
EPD_5IN65F
EPD_5IN83_V2
EPD_5IN83
EPD_5IN83B_V2
EPD_5IN83BC
EPD_7IN3F
EPD_7IN3G
EPD_7IN5_HD
EPD_7IN5_V2
EPD_7IN5
EPD_7IN5B_HD
EPD_7IN5B_V2
EPD_7IN5BC

将微雪驱动库移植到AIR32F103

添加驱动库代码

将微雪仓库导出, 需要的部分都在 STM32/STM32-F103ZET6/User 目录下, 将其中代码部分复制到AIR32F103的库目录下, 形成目录结构为

Libraries
├── AIR32F10xLib
├── CMSIS
├── Debug
├── DeviceSupport
├── EPaper
│    ├── Config            # 配置文件
│    ├── e-Paper           # 对应每一个型号的 .c 和 .h 文件, 驱动的核心
│    ├── Examples          # 对应每一个型号的测试示例, 都实现了 EPD_test(void 这个方法
│    ├── Fonts             # 字体, 5个英文字体, 2个中文字体(只是少数几个汉字
│    └── GUI               # 点线面的绘制方法

因为目的是要在 GNU GCC 下使用 Makefile 编译, 所以有些地方需要优化一下

    将目录重命名一下, e-Paper 改为 Lib
  1. 将 Debug.h 删除, 其内容集成到 DEV_Config.h
  2. 将 DEV_Config.c 和 DEV_Config.h 的公用部分(固定部分提取为 EPD_Common.c 和 EPD_Common.h, 放到 Lib 下
  3. 将 DEV_Config.h 中的配置部分提出来创建 EPD_Config_Template.h, 这个文件在创建项目时, 可以更名为 EPD_Config.h 放到项目目录下.

├── EPaper
│    ├── EPD_Config_Template.h
│    ├── Examples
│    ├── Fonts
│    ├── GUI
│    └── Lib

进一步将每一个型号提取为宏, 然后对 Lib 和 Examples 下的每个驱动和测试 c 文件, 增加宏判断

#ifdef EPD_1IN54

...

#endif

这样可以在 EPD_Config.h 中使用宏配置启用哪一个型号, 例如对于合宙这块1.54的屏, 只需要启用 1N54 这个宏

/**
 * Uncomment the part number to enable
*/

// #define EPD_1IN02
// #define EPD_1IN54_V2
#define EPD_1IN54
// #define EPD_1IN54B_V2
// #define EPD_1IN54B
// #define EPD_1IN54C
// #define EPD_1IN64G
...
...
// #define EPD_7IN5B_V2
// #define EPD_7IN5BC

这样编译时未启用的型号, 其驱动和测试会直接跳过

修改 Makefile

# Build with Waveshare e-paper lib, y:yes, n:no
USE_EPAPER    ?= y

以及对应的编译包含项, 这里使用的是修改过名称后的目录名

ifeq ($(USE_EPAPER,y
CDIRS   += Libraries/EPaper/Lib \
      Libraries/EPaper/Examples \
      Libraries/EPaper/Fonts \
      Libraries/EPaper/GUI

INCLUDES  += Libraries/EPaper/Lib \
      Libraries/EPaper/Examples \
      Libraries/EPaper/Fonts \
      Libraries/EPaper/GUI
endif

驱动墨水屏的示例项目

硬件部分

    AIR32F103CBT6, 墨水屏驱动编译完只有30多KByte, 所以用哪个型号都可以
  • 合宙的1.54寸墨水屏. 如果使用其它墨水屏, 记得修改启用对应的宏

接线是典型的 SPI 接线方式, 和普通LCD一样, 但是没有背光, 增加了一个 Busy 脚

 * Waveshare 1.54' E-Paper Demo
 * 
 * AIR32        E-Paper
 * - PA2        BUSY
 * - PA3        CS
 * - PA4        DC(Data/Command
 * - PA5        SCK/SCL
 * - PA6        RES
 * - PA7        SI/SDA
 * - GND        GND
 * - 3.3V       VCC

软件部分

设置 EPD_Config.h

    将 EPD_Config_Template.h 复制到项目目录下, 更名为 EPD_Config.h 并打开编辑
  1. 启用 EPD_1IN54, 将其反注释
  2. EPD_DEBUG设为1, 可以开启串口日志输出
  3. 定义 RESET, DC, CS, BUSY 这几个 GPIO 对应的 PORT和 PIN, 这些 PIN 脚随后需要在程序中初始化
  4. 定义几个关键方法的宏

/**
 * Uncomment to enable the part
*/
// #define EPD_1IN02
// #define EPD_1IN54_V2
#define EPD_1IN54
// #define EPD_1IN54B_V2
// ...
// #define EPD_7IN5BC

#define EPD_DEBUG 1

/**
 * e-Paper GPIO
 */
#define EPD_RST_PIN     GPIOA, GPIO_Pin_6
#define EPD_DC_PIN      GPIOA, GPIO_Pin_4
#define EPD_CS_PIN      GPIOA, GPIO_Pin_3
#define EPD_BUSY_PIN    GPIOA, GPIO_Pin_2

/**
 * GPIO read and write
 */
#define EPD_Digital_Write(_pin, _value GPIO_WriteBit(_pin, _value == 0? Bit_RESET:Bit_SET
#define EPD_Digital_Read(_pin          GPIO_ReadInputDataBit(_pin
#define EPD_SPI_WriteByte(_value       SPI_TxRx(_value
#define EPD_Delay_ms(__xms             Delay_Ms(__xms

#endif

初始化外设

因为是示例项目, 就不单独分文件了, 都添加到 main.c。

void APP_GPIO_Config(void
{
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE;

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_6;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure;
  GPIO_SetBits(GPIOA, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_6;

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure;
  GPIO_SetBits(GPIOA, GPIO_Pin_2;
}

初始化SPI1, 这里用 PA5作为SCL, PA7作为SDA

void APP_SPI_Config(void
{
  GPIO_InitTypeDef GPIO_InitStructure;
  SPI_InitTypeDef  SPI_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE;

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure;

  GPIO_SetBits(GPIOA,GPIO_Pin_5 | GPIO_Pin_7;

  SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 0;
  SPI_Init(SPI1, &SPI_InitStructure;

  SPI_Cmd(SPI1, ENABLE;
}

对应 EPD_Config.h 中的 EPD_SPI_WriteByte( 宏定义, 创建 SPI 的字节读写方法

uint8_t SPI_TxRx(uint8_t data
{
  uint8_t retry = 0;
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE == RESET && ++retry;
  SPI_I2S_SendData(SPI1, data;
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE == RESET && ++retry;
  return SPI_I2S_ReceiveData(SPI1;
}

运行驱动测试

在 main( 中初始化后直接调用微雪自带的测试函数. 这个测试会写入图, 然后写入文字, 局部刷新, 最后清屏, 进入睡眠。

int main(void
{
  //...

  APP_GPIO_Config(;
  APP_SPI_Config(;

  EPD_test(;

  while (1;
}

遇到的问题

字体编译错误

原驱动库中文使用的是 GB2312 的编码, 而我在 Ubuntu 下肯定是不用 GBK 的, 所以会乱码, 我把这部分都改成 UTF-8 了, 因此对应的汉字的字节数也从2变成了3, 需要做对应的修改

typedef struct
{
  unsigned char index[3];                                  //<-- 从 2 改成 3
  const char matrix[MAX_HEIGHT_FONT*MAX_WIDTH_FONT/8];
} CH_CN;

GUI_Paint.c

void Paint_DrawString_CN(UWORD Xstart, UWORD Ystart, const char * pString, cFONT* font,
                        UWORD Color_Foreground, UWORD Color_Background
{
//...

            /* Point on the next character */
            p_text += 3;                                  //<-- 从 2 改成 3
//...

原先的字体定义方式为

/*--  文字:  好  --*/
/*--  微软雅黑12;  此字体下对应的点阵为:宽x高=16x21   --*/
{"好",
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x73,0xFF,0x70,0x0F,0xFE,0x1E,
0x7E,0x3C,0x6E,0x38,0xEE,0x30,0xEF,0xFF,0xFC,0x30,0x7C,0x30,0x38,0x30,0x3E,0x30,
0x7E,0x30,0xE0,0x30,0xC1,0xF0,0x00,0x00,0x00,0x00},

这种初始化赋值应该是 ARM GCC 支持, 但是 GUN GCC 不支持, 编译会报错, 两个struct成员变量不能用同一个花括号, 需要改为

  /*--  文字:  好  --*/
/*--  微软雅黑12;  此字体下对应的点阵为:宽x高=16x21   --*/
{
  index:"好",
  matrix: {
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x73,0xFF,0x70,0x0F,0xFE,0x1E,
    0x7E,0x3C,0x6E,0x38,0xEE,0x30,0xEF,0xFF,0xFC,0x30,0x7C,0x30,0x38,0x30,0x3E,0x30,
    0x7E,0x30,0xE0,0x30,0xC1,0xF0,0x00,0x00,0x00,0x00}
},

或者下面这种形式

  /*--  文字:  好  --*/
/*--  微软雅黑12;  此字体下对应的点阵为:宽x高=16x21   --*/
{
  "好",
  {
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x73,0xFF,0x70,0x0F,0xFE,0x1E,
    0x7E,0x3C,0x6E,0x38,0xEE,0x30,0xEF,0xFF,0xFC,0x30,0x7C,0x30,0x38,0x30,0x3E,0x30,
    0x7E,0x30,0xE0,0x30,0xC1,0xF0,0x00,0x00,0x00,0x00}
},

经过以上的修改, 就可以正常编译了。

示例项目源代码

https://github.com/IOsetting/air32f103-template/tree/master/Examples/NonFreeRTOS/SPI/Waveshare_1N54_E-Paper

如果需要驱动其它型号的墨水屏, 编辑 EPD_Config.h 将#define EPD_1IN54注释掉, 再将需要启用的型号取消注释即可。

编程笔记 » AIR32F103(十一) 在AIR32F103上移植微雪墨水屏驱动

赞同 (28) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽