如图所示,这个板子的OLED驱动在开源例程里给出,但是不是基于Keil MDK来开发的,只是用CubeMX生成了对应的驱动源码,现在我将它的驱动移植到Keil MDK上来,屏的代码可以参考:
https://github.com/alibaba/AliOSThings/tree/rel_3.0.0/app/example/dk/dk_gui
一、LCD的管脚定义以及在开发板上对应的IO
屏在开发板上的连接,参考开发板在github上提供的文档关于CubeMX配置,可以找到LCD相关的管脚。
相关的管脚连接
即是下面这几个核心的管脚:
二、开始stm32CubeMX的配置
2.1 时钟配置
2.2 SPI配置
2.3 GPIO配置
三、生成代码与LCD驱动移植
LCD的初始化代码以及寄存器手册详情可参考:
https://download.csdn.net/download/bhtlbhtl123/8963365
接下来看一下我移植过来的ST7789.h
#ifndef __ST7789_H #define __ST7789_H #include "main.h" #include "spi.h" #define WIDTH 240 #define HEIGHT 240 #define BPP 16 #define LCD_MAX_MEM16_BLOCK (1 << 6) #define LCD_PIXEL_PER_BLOCK (LCD_MAX_MEM16_BLOCK >> 1) /* Init script function */ struct st7789_function { uint8_t cmd; uint16_t data; }; /* Init script commands */ enum st7789_cmd { ST7789_START, ST7789_END, ST7789_CMD, ST7789_DATA, ST7789_DELAY }; /* ST7789 Commands */ #define ST7789_CASET 0x2A #define ST7789_RASET 0x2B #define ST7789_RAMWR 0x2C #define ST7789_RAMRD 0x2E //LCD初始化 int st7789_init(void); //写寄存器 void LcdWriteReg(uint8_t Data); //写数据 void LcdWriteData(uint8_t Data); //将多个值写入显示寄存器 void LcdWriteDataMultiple(uint8_t * pData, int NumItems); //写一个像素到指定位置 void ST7789H2_WritePixel(uint16_t Xpos, uint16_t Ypos, uint16_t RGBCode); //写一行数据 void ST7789H2_WriteLine(uint16_t Xpos, uint16_t Ypos, uint16_t *RGBCode, uint16_t pointNum); //显示图片 void st7789_display_picture(void); #endif //__ST7789_H
ST7789.c
#include "ST7789.h" static SPI_HandleTypeDef *hspi_lcd = NULL; uint8_t black_gui[480] = {0}; uint8_t endian_buffer[480]; //参考LCD的寄存器手册 static struct st7789_function st7789_cfg_script[] = { {ST7789_START, ST7789_START}, {ST7789_CMD, 0x11}, {ST7789_DELAY, 120}, {ST7789_CMD, 0x36}, {ST7789_DATA, 0x00}, {ST7789_CMD, 0x3a}, {ST7789_DATA, 0x05}, {ST7789_CMD, 0xb2}, {ST7789_DATA, 0x0c}, {ST7789_DATA, 0x0c}, {ST7789_DATA, 0x00}, {ST7789_DATA, 0x33}, {ST7789_DATA, 0x33}, {ST7789_CMD, 0xb7}, {ST7789_DATA, 0x72}, {ST7789_CMD, 0xbb}, {ST7789_DATA, 0x3d}, {ST7789_CMD, 0xc2}, {ST7789_DATA, 0x01}, {ST7789_CMD, 0xc3}, {ST7789_DATA, 0x19}, {ST7789_CMD, 0xc4}, {ST7789_DATA, 0x20}, {ST7789_CMD, 0xc6}, {ST7789_DATA, 0x0f}, {ST7789_CMD, 0xd0}, {ST7789_DATA, 0xa4}, {ST7789_DATA, 0xa1}, {ST7789_CMD, 0xe0}, {ST7789_DATA, 0x70}, {ST7789_DATA, 0x04}, {ST7789_DATA, 0x08}, {ST7789_DATA, 0x09}, {ST7789_DATA, 0x09}, {ST7789_DATA, 0x05}, {ST7789_DATA, 0x2a}, {ST7789_DATA, 0x33}, {ST7789_DATA, 0x41}, {ST7789_DATA, 0x07}, {ST7789_DATA, 0x13}, {ST7789_DATA, 0x13}, {ST7789_DATA, 0x29}, {ST7789_DATA, 0x2f}, {ST7789_CMD, 0xe1}, {ST7789_DATA, 0x70}, {ST7789_DATA, 0x03}, {ST7789_DATA, 0x09}, {ST7789_DATA, 0x0a}, {ST7789_DATA, 0x09}, {ST7789_DATA, 0x06}, {ST7789_DATA, 0x2b}, {ST7789_DATA, 0x34}, {ST7789_DATA, 0x41}, {ST7789_DATA, 0x07}, {ST7789_DATA, 0x12}, {ST7789_DATA, 0x14}, {ST7789_DATA, 0x28}, {ST7789_DATA, 0x2e}, {ST7789_CMD, 0x21}, {ST7789_CMD, 0x29}, {ST7789_CMD, 0x2a}, {ST7789_DATA, 0x00}, {ST7789_DATA, 0x00}, {ST7789_DATA, 0x00}, {ST7789_DATA, 0xef}, {ST7789_CMD, 0x2b}, {ST7789_DATA, 0x00}, {ST7789_DATA, 0x00}, {ST7789_DATA, 0x00}, {ST7789_DATA, 0xef}, {ST7789_CMD, 0x2c}, {ST7789_END, ST7789_END}, }; //ST7789复位 static void st7789_reset(void) { HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_SET); HAL_Delay(1); HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_RESET); HAL_Delay(10); HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_SET); HAL_Delay(120); } //打开LCD电源 void st7789_power_on(void) { HAL_GPIO_WritePin(LCD_PWR_GPIO_Port, LCD_PWR_Pin, GPIO_PIN_SET); } //ST7789写函数 static HAL_StatusTypeDef st7789_write(int is_cmd, uint8_t data) { uint8_t pData[2] = {0}; assert_param(NULL != hspi_lcd); pData[0] = data; if (is_cmd) HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_RESET); else HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_SET); return HAL_SPI_Transmit(hspi_lcd, pData, 1, HAL_MAX_DELAY); } static HAL_StatusTypeDef st7789_write_fb(uint16_t *data, uint16_t size) { assert_param(NULL != hspi_lcd); return HAL_SPI_Transmit(hspi_lcd, (uint8_t *)data, size, HAL_MAX_DELAY); } /******************************************************************** * * LcdWriteReg * * Function description: * Sets display register */ void LcdWriteReg(uint8_t Data) { HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(&hspi1, &Data, 1, 10); } /******************************************************************** * * LcdWriteData * * Function description: * Writes a value to a display register */ void LcdWriteData(uint8_t Data) { HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_SET); HAL_SPI_Transmit(&hspi1, &Data, 1, 10); } /******************************************************************** * * LcdWriteDataMultiple * * Function description: * Writes multiple values to a display register. */ void LcdWriteDataMultiple(uint8_t * pData, int NumItems) { HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_SET); HAL_SPI_Transmit(&hspi1, pData, NumItems, 10); } //配置启动参数 static void st7789_run_cfg_script(void) { uint8_t data[2] = {0}; int i = 0; int end_script = 0; do { switch (st7789_cfg_script[i].cmd) { case ST7789_START: break; case ST7789_CMD: data[0] = st7789_cfg_script[i].data & 0xff; st7789_write(1, data[0]); break; case ST7789_DATA: data[0] = st7789_cfg_script[i].data & 0xff; st7789_write(0, data[0]); break; case ST7789_DELAY: HAL_Delay(120); break; case ST7789_END: end_script = 1; } i++; } while (!end_script); } //设置地址 static void st7789_set_addr_win(uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye) { uint8_t col_data[4] = {0}; uint8_t row_data[4] = {0}; col_data[0] = xs >> 8 & 0xff; col_data[1] = xs & 0xff; col_data[2] = xe >> 8 & 0xff; col_data[3] = xe & 0xff; row_data[0] = ys >> 8 & 0xff; row_data[1] = ys & 0xff; row_data[2] = ye >> 8 & 0xff; row_data[3] = ye & 0xff; st7789_write(1, ST7789_CASET); st7789_write(0, col_data[0]); st7789_write(0, col_data[1]); st7789_write(0, col_data[2]); st7789_write(0, col_data[3]); st7789_write(1, ST7789_RASET); st7789_write(0, row_data[0]); st7789_write(0, row_data[1]); st7789_write(0, row_data[2]); st7789_write(0, row_data[3]); } //发送到显示区域 static void spec_send_fb(uint16_t color, uint16_t pixel_num) { int i; int count, remain; uint16_t real_mem[LCD_MAX_MEM16_BLOCK] = {0}; for (i = 0; i < LCD_MAX_MEM16_BLOCK; ++i) { real_mem[i] = color; } HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_SET); if (pixel_num <= LCD_MAX_MEM16_BLOCK) { st7789_write_fb(real_mem, pixel_num << 1); } else { count = pixel_num / LCD_MAX_MEM16_BLOCK; remain = pixel_num % LCD_MAX_MEM16_BLOCK; for (i = 0; i < count; ++i) { st7789_write_fb(real_mem, LCD_MAX_MEM16_BLOCK << 1); } st7789_write_fb(real_mem, remain << 1); } } //显示图片 void st7789_display_picture(void) { st7789_write(1, ST7789_RAMWR); spec_send_fb(0x0, WIDTH * HEIGHT / 4); spec_send_fb(0x1111, WIDTH * HEIGHT / 4); spec_send_fb(0x7777, WIDTH * HEIGHT / 4); spec_send_fb(0xeeee, WIDTH * HEIGHT / 4); } //写寄存器 void ST7789H2_WriteReg(uint8_t Command, uint8_t *Parameters, uint8_t NbParameters) { uint8_t i; /* Send command */ LcdWriteReg(Command); /* Send command's parameters if any */ for (i=0; i<NbParameters; i++) { LcdWriteData(Parameters[i]); } } //在指定位置设置光标 void ST7789H2_SetCursor(uint16_t Xpos, uint16_t Ypos) { uint8_t parameter[4]; /* CASET: Comumn Addrses Set */ parameter[0] = 0x00; parameter[1] = 0x00 + Xpos; parameter[2] = 0x00; parameter[3] = 0xEF + Xpos; ST7789H2_WriteReg(0x2A, parameter, 4); /* RASET: Row Addrses Set */ parameter[0] = 0x00; parameter[1] = 0x00 + Ypos; parameter[2] = 0x00; parameter[3] = 0xEF + Ypos; ST7789H2_WriteReg(0x2B, parameter, 4); } //清屏 void BSP_LCD_Clear(void) { uint32_t counter = 0; uint32_t y_size = 0; memset(black_gui, 0x00, sizeof(black_gui)); for (counter = 0; counter < 240; counter++) { /* Set Cursor */ ST7789H2_SetCursor(0, counter); /* Prepare to write to LCD RAM */ ST7789H2_WriteReg(0x2C, (uint8_t*)NULL, 0); /* RAM write data command */ LcdWriteDataMultiple(black_gui, 480); } } //往指定区域写一个像素 void ST7789H2_WritePixel(uint16_t Xpos, uint16_t Ypos, uint16_t data) { uint8_t dataB = 0; /* Set Cursor */ ST7789H2_SetCursor(Xpos, Ypos); /* Prepare to write to LCD RAM */ ST7789H2_WriteReg(0x2C, (uint8_t*)NULL, 0); /* RAM write data command */ /* Write RAM data */ dataB = (uint8_t)(data >> 8); LcdWriteData(dataB); dataB = (uint8_t)data; LcdWriteData(dataB); } //往指定区域写一行数据 void ST7789H2_WriteLine(uint16_t Xpos, uint16_t Ypos, uint16_t *RGBCode, uint16_t pointNum) { int i = 0; /* Set Cursor */ ST7789H2_SetCursor(Xpos, Ypos); /* Prepare to write to LCD RAM */ ST7789H2_WriteReg(0x2C, (uint8_t*)NULL, 0); /* RAM write data command */ for (i = 0; i < pointNum; i++) { endian_buffer[2*i] = (uint8_t)(RGBCode[i] >> 8); endian_buffer[2*i + 1] = (uint8_t)RGBCode[i]; } /* Write RAM data */ LcdWriteDataMultiple(endian_buffer, pointNum*2); } //ST7789初始化 int st7789_init(void) { hspi_lcd = &hspi1; st7789_power_on(); st7789_reset(); st7789_run_cfg_script(); return HAL_OK; }
在main.c中添加逻辑:
/** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_SPI1_Init(); /* USER CODE BEGIN 2 */ st7789_init(); st7789_display_picture(); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); HAL_Delay(200); } /* USER CODE END 3 */ }
四、运行结果
由于这个板子遗留较多硬件问题且诺行不愿在开发板出厂时修复;开发板相关文档较乱,所以只能靠自己慢慢探索咯,总体来说,这个板子还是非常强大的,可以用做日常学习,详情可看:
https://github.com/alibaba/AliOS-Things/wiki/Developer-Kit-Tutorial