本帖最后由 tpgf 于 2022-7-6 12:03 编辑
前言:大部分单片机移植lvgl的步骤都可以参考以下内容,内容从spi驱动,再到液晶驱动,再到lvgl移植,从一个基础工程到移植完成 一、下载LVGL_V8源码 暂时不需要吧 如果使用AT-START-F403开发板时,不需要进行SRAM的扩展,因为403的SRAM默认就为96K。 如果使用AT-START-F413开发板时,强烈建议进行SRAM的扩展,因为413的SRAM默认只有32K, 很容易就会超出范围。 源码地址:LVGL源码https://github.com/lvgl/lvgl 提取出以下文件 1.examples/porting 2.src 3.lvgl.h lv_conf.h 二、SPI驱动 目前只做了spi屏的移植,并口屏后面有机会再补充 1.spi初始化目前使用AT32提供的固件库,刚开始可以不使用SPI DMA,可以验证spi的配置是否正确,再同过DMA提升刷屏速度 #if (SPI_USE_DMA == 0) /** * @brief spi configuration. * @param none * @retval none */ void SPI3_Init(void) { spi_init_type spi_init_struct; //gpio_config(); spi_i2s_reset(SPI3); crm_periph_clock_enable(CRM_SPI3_PERIPH_CLOCK, TRUE); spi_default_para_init(&spi_init_struct); spi_init_struct.transmission_mode = SPI_TRANSMIT_HALF_DUPLEX_TX; spi_init_struct.master_slave_mode = SPI_MODE_MASTER; spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_8; spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB; spi_init_struct.frame_bit_num = SPI_FRAME_8BIT; spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_LOW; spi_init_struct.clock_phase = SPI_CLOCK_PHASE_1EDGE; spi_init_struct.cs_mode_selection = SPI_CS_SOFTWARE_MODE; if(spi_init_struct.cs_mode_selection == SPI_CS_HARDWARE_MODE) { spi_init_struct.cs_mode_selection = SPI_CS_SOFTWARE_MODE; } spi_init(SPI3, &spi_init_struct); spi_enable(SPI3, TRUE); } #else uint8_t spi3_tx_buffer[BUFFER_SIZE]; void SPI3_Init(void) { dma_init_type dma_init_struct; spi_init_type spi_init_struct; /* SPI_MASTER_Tx_DMA_Channel configuration ---------------------------------------------*/ /**************DMA 配置 *****************/ crm_periph_clock_enable(CRM_DMA2_PERIPH_CLOCK, TRUE); dma_reset(SPI_MASTER_Tx_DMA_Channel); dma_default_para_init(&dma_init_struct); dma_init_struct.buffer_size = BUFFER_SIZE; dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL; dma_init_struct.memory_base_addr = (uint32_t)spi3_tx_buffer; dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE; dma_init_struct.memory_inc_enable = TRUE; dma_init_struct.peripheral_base_addr = (uint32_t)&SPI3->dt; dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE; dma_init_struct.peripheral_inc_enable = FALSE; dma_init_struct.priority = DMA_PRIORITY_MEDIUM; dma_init_struct.loop_mode_enable = FALSE; //是否循环模式 dma_init(DMA2_CHANNEL2, &dma_init_struct); /**************SPI 配置 *****************/ crm_periph_clock_enable(CRM_SPI3_PERIPH_CLOCK, TRUE); spi_default_para_init(&spi_init_struct); spi_init_struct.transmission_mode = SPI_TRANSMIT_HALF_DUPLEX_TX; spi_init_struct.master_slave_mode = SPI_MODE_MASTER; spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_8; spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB; spi_init_struct.frame_bit_num = SPI_FRAME_8BIT; spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_HIGH; spi_init_struct.clock_phase = SPI_CLOCK_PHASE_2EDGE; spi_init_struct.cs_mode_selection = SPI_CS_SOFTWARE_MODE; spi_init(SPI3, &spi_init_struct); spi_i2s_dma_transmitter_enable(SPI3, TRUE); //中断配置 /* enable transfer full data intterrupt */ dma_interrupt_enable(SPI_MASTER_Tx_DMA_Channel, DMA_FDT_INT, TRUE); /* dma1 channel1 interrupt nvic init */ nvic_irq_enable(DMA2_Channel2_IRQn, 1, 0); /* config flexible dma for usart2 tx */ dma_flexible_config(DMA2, FLEX_CHANNEL2, DMA_FLEXIBLE_SPI3_TX); spi_enable(SPI3, TRUE); } void DMA2_Channel2_IRQHandler(void) { /*DMA发送完成中断*/ if(dma_flag_get(DMA2_FDT2_FLAG)) { LCD_CS_SET; dma_flag_clear(DMA2_FDT2_FLAG); lv_disp_flush_complete();/* tell lvgl that flushing is done */ dma_channel_enable(DMA2_CHANNEL2, FALSE); } } void disp_spi_dma_send(const void* buf, uint32_t size) { LCD_RS_SET; LCD_CS_CLR; while(spi_i2s_flag_get(SPI3,SPI_I2S_BF_FLAG) == SET){}; dma_channel_enable(DMA2_CHANNEL2, FALSE); /* usart2 tx begin dma transmitting */ DMA2_CHANNEL2->maddr = (uint32_t)buf; DMA2_CHANNEL2->dtcnt = size; dma_channel_enable(DMA2_CHANNEL2, TRUE); /*** 不开DMA完成中断的执行 ***/ // while(spi_i2s_flag_get(SPI3,SPI_I2S_BF_FLAG) == SET){}; // while(dma_flag_get(DMA2_FDT2_FLAG) == RESET){}; // dma_flag_clear(DMA2_FDT2_FLAG); // lv_disp_flush_complete(); }
三、lcd驱动1.spi lcd 驱动移植基本上将以下一个函数实现即可
吐槽一下,液晶技术支持一般就提供一个模拟spi的驱动
虽然通用性强,但是太慢了
static void LCD_WR_BYTE(u8 cmd,u8 regval)
{
int i;
if(cmd)
{
LCD_RS_CLR;
}
else
{
LCD_RS_SET;
}
LCD_CS_CLR;
#if USE_SPI
LCD_WRITE_BYTE(regval);
#else
for(i=0;i<8;i++)
{
if(regval &0x80)
{
LCD_SDA_SET;
}
else LCD_SDA_CLR;
LCD_SCL_CLR;
LCD_SCL_SET;
regval <<=1;
}
#endif
LCD_CS_SET;
}
void LCD_WRITE_BYTE(uint8_t DATA)
{
spi_i2s_data_transmit(LCD_SPI, DATA);
while(spi_i2s_flag_get(LCD_SPI, SPI_I2S_BF_FLAG) == SET ){};
}
2.lcd初始化中需要注意的点1.一般需要更改的就是下面更改刷屏方向,以及RGB排列 LCD_WR_DATA(0x00|MADCTL_MV|MADCTL_RGB);
2. 16位颜色数据高低字节顺序从发送颜色数据的函数可以看出,先发的是16位颜色数据低字节,再发高字节
而 使用SPI DMA发送时是按照 at32 stm32等都是小端模式,即 16位数据 或者32位数据等,是低字节存放在高地址中 使用8位spi传输时,16位像素的低字节被先写入,而高字节被后写入,这就导致了屏幕反色的问题, 解决这个问题,有三种方案, 1 .将SPI写入改为16位模式,这样能够使高字节先写入 2 .写入前先进行字节反转 3 .在LVGL上层进行颜色翻转,lv_conf.h中配置了#define LV_COLOR_16_SWAP 1 这是最简单的方法,后面也会提到。有时候忽略这个就会出现花屏 //发送颜色数据 void Lcd_Write_Data(u16 dat16) { LCD_WR_DATA(dat16>>8); LCD_WR_DATA(dat16); } 三、LVGL配置lv_conf.h中需要注意的几个配置 /*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/ #define LV_COLOR_DEPTH 16 /*Swap the 2 bytes of RGB565 color. Useful if the display has an 8-bit interface (e.g. SPI)*/ #define LV_COLOR_16_SWAP 1 #define LV_MEM_SIZE (24U * 1024U) /*[bytes]*/ #define LV_SPRINTF_CUSTOM 1
1 .LV_COLOR_16_SWAP 1 16位颜色数据高低字节反转 使用spi屏的时候一般都要用
2. LV_MEM_SIZE 一些单片机的SRAM可能只有64k,甚至32k的大小,lvgl直接占48K肯定不合适
3. LVGL lv_label_set_text_fmt 显示只有f
解决方式https://blog.csdn.net/weixin_44684950/article/details/124426341
|