l63t89 发表于 2022-3-31 15:59

【AT-START-F425测评】SPI驱动LCD屏

【前言】LCD屏是单片机常用的外设。GC9306是一款240*320的彩色显示屏,这次是用spi1驱动它,也是我学习AT32F425的spi外设的题目之一。【步聚】1、先下载查看了AT32F425数据手册。了解spi1的驱动IO是哪些。用于LCD屏的CS、DC、RES、BLK的普通IO是如何驱动的。            2、查看了spi1的驱动示例,学习如何配置spi1为主从模式。            3、上网学习其他网友的驱动LCD屏的例子。学习他们配置外设的方法。            4、用我原来在CH582M的驱动拷贝过来用在AT32F425的工程上。【具体过程】             1、在RT_Thread Studio的工程目录下面新建一个drives的工程目录,把我原来用在CH582上面的5个文件lcd_init.c、lcd_init.h、lcd.c、lcd.h、lcdfont.h拷贝到这个目录下面。其实单片机学习就象堆积木,用的外设多了,哪怕换一款芯片,使用起来也方便,使用起来没有象以前从头开始、查资料、找驱动===。             2、根据上次驱动gc9306的经验,拷贝文件过来,只需要修改几个参数就行了:1、屏的init,这里主要是改写spi发送数据的这个LCD_Init函数。 2、修改DC、RES、CS、BLK四个IO的驱动(宏配置)。            1)定义驱动的IO如下://生成日期   : 2022-3-27
//最近修改   :
//功能描述   :AT32F425 GC9306
//            说明:
//            ----------------------------------------------------------------
//            GND   电源地
//            VCC   3.3v电源
//            SCL   PA5(SCLK)
//            SDA   PA7(MOSI)
//            RES   PB0                //复位
//            DC    PB1                //命令、数据选择位
//            CS    PA4                //spi片选
//            BLK   PB2                //背光
//            ----------------------------------------------------------------

l63t89 发表于 2022-3-31 16:00

    2)配置spi1的时钟、GPIO等详细见代码注释:

void LCD_GPIO_Init(void)
{
   gpio_init_type gpio_init_struct;
   spi_init_type spi_init_struct;
    /* 使能GPIOA GPIOB时钟 */
   crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
   crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
               
/* set default parameter */
   gpio_default_para_init(&gpio_init_struct);

#if SOFTWARE_SPI_ENABLE      //为模拟spi

      /* configure the led gpio */
      gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; //加强的输出能力跟CH582的 输出20mA与5mA的味道差不多,或者是STM32的推挽输出差不多吧。
      gpio_init_struct.gpio_out_type= GPIO_OUTPUT_PUSH_PULL;             //上拉输出
      gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;                     //输出模式
      gpio_init_struct.gpio_pins = GPIO_PINS_4|GPIO_PINS_5|GPIO_PINS_7;    //选择输出的IO 分别为4、5、7脚是不是由于专利的问题 我看到这个STM32:GPIO_PIN_0,CH582的GPIO_Pin_0
      gpio_init_struct.gpio_pull = GPIO_PULL_NONE;                        //floating for input, no pull for output 也就是stm32的floating的吧
      gpio_init(GPIOA, &gpio_init_struct);                              
      gpio_bits_set(GPIOA,GPIO_PINS_4|GPIO_PINS_5|GPIO_PINS_7);          //初始为高电平

#else    //为硬件spi         
      gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
      gpio_init_struct.gpio_pull         = GPIO_PULL_UP;
      gpio_init_struct.gpio_mode         = GPIO_MODE_OUTPUT;
      gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
      gpio_init_struct.gpio_pins = GPIO_PINS_4;
      gpio_init(GPIOA, &gpio_init_struct);
      
      gpio_bits_set(GPIOA,GPIO_PINS_4);

      gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE5, GPIO_MUX_0);//这个muxing 百度翻译也整不明白,是不是管角复用的意思?看到数据手册是乎是5的第1功能为SPI1
      gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE6, GPIO_MUX_0);
      gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE7, GPIO_MUX_0);
      gpio_default_para_init(&gpio_init_struct);

      gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;

      gpio_init_struct.gpio_pull         = GPIO_PULL_DOWN;
      gpio_init_struct.gpio_mode         = GPIO_MODE_MUX;
      gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
      gpio_init_struct.gpio_pins = GPIO_PINS_5;
      gpio_init(GPIOA, &gpio_init_struct);

      gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
      gpio_init_struct.gpio_pull         = GPIO_PULL_UP;
      gpio_init_struct.gpio_mode         = GPIO_MODE_MUX;
      gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
      gpio_init_struct.gpio_pins = GPIO_PINS_7 | GPIO_PINS_6;
      gpio_init(GPIOA, &gpio_init_struct);

      crm_periph_clock_enable(CRM_SPI1_PERIPH_CLOCK, TRUE);   //使能SPI1的时钟

      spi_default_para_init(&spi_init_struct);               //复位SPI1
      spi_init_struct.transmission_mode = SPI_TRANSMIT_HALF_DUPLEX_TX;    //单线双向半双工模式传输(slben=1和slbtd=1)
      spi_init_struct.master_slave_mode = SPI_MODE_MASTER;                //主机模式
      spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_2;                //2分频,有空测一下频率是多少
      spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB;         //MSB 高位在前?   
      spi_init_struct.frame_bit_num = SPI_FRAME_8BIT;                     //一帧为8位
      spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_HIGH;//sck在空闲状态下保持高
      spi_init_struct.clock_phase = SPI_CLOCK_PHASE_2EDGE;       //数据捕获从第二个时钟边缘开始
      spi_init_struct.cs_mode_selection = SPI_CS_SOFTWARE_MODE;//CS由软件控制
      spi_init(SPI1, &spi_init_struct);

      spi_enable(SPI1, TRUE);
      
#endif      
      //配置DC、RES、BLK
      gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
      gpio_init_struct.gpio_out_type= GPIO_OUTPUT_PUSH_PULL;
      gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
      gpio_init_struct.gpio_pins = GPIO_PINS_0|GPIO_PINS_1|GPIO_PINS_2;
      gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
      gpio_init(GPIOB, &gpio_init_struct);      
      gpio_bits_set(GPIOB,GPIO_PINS_0|GPIO_PINS_1|GPIO_PINS_2);       
}

l63t89 发表于 2022-3-31 16:02

3)改发送函数:
/******************************************************************************
      函数说明:LCD串行数据写入函数
      入口数据:dat要写入的串行数据
      返回值:无
******************************************************************************/
void LCD_Writ_Bus(uint8_t dat)
{       
       
gpio_bits_reset( GPIOA, GPIO_PINS_4 ); //CS拉低,开始发送数数
        #if SOFTWARE_SPI_ENABLE      //模拟发送数据
      u8 i;
      for(i=0;i<8;i++)
      {                        
                LCD_SCLK_LOW();
                if(dat&0x80)
                {
                   LCD_MOSI_HIGH();
                }
                else
                {
                   LCD_MOSI_LOW();
                }
                LCD_SCLK_HIGH();
                dat<<=1;
      }
#else   //使用硬件SPI发送
spi_i2s_data_transmit(SPI1, dat ); //发送数据
while(spi_i2s_flag_get(SPI1, SPI_I2S_TDBE_FLAG) == RESET) {};//等待发送完成,我感觉以后要加超时判断,要不会出问题会阻塞在这里
gpio_bits_set(GPIOA, GPIO_PINS_4 );//CS释放
#endif
}

l63t89 发表于 2022-3-31 16:02

   4)修改DC、RES、BLK的宏配置:
#define RES_PINGPIO_PINS_0
#define DC_PIN   GPIO_PINS_1
#define BLK_PINGPIO_PINS_2

#define CS_PIN   GPIO_PINS_4
//-----------------LCD端口定义----------------

#define LCD_CS_Clr   gpio_bits_reset(GPIOA, CS_PIN)//CS
#define LCD_CS_Set   gpio_bits_set(GPIOA, CS_PIN)

#define LCD_RES_Clrgpio_bits_reset(GPIOB, RES_PIN)//RES
#define LCD_RES_Setgpio_bits_set(GPIOB, RES_PIN)

#define LCD_DC_Clr   gpio_bits_reset(GPIOB, DC_PIN)//DC
#define LCD_DC_Set   gpio_bits_set(GPIOB,DC_PIN)

#define LCD_BLK_Clrgpio_bits_reset(GPIOB,BLK_PIN)//BLK
#define LCD_BLK_Setgpio_bits_set(GPIOB,BLK_PIN)

#define LCD_SCLK_LOW() gpio_bits_reset(GPIOA, GPIO_PINS_5)
#define LCD_SCLK_HIGH() gpio_bits_set(GPIOA, GPIO_PINS_5)

#define LCD_MOSI_LOW() gpio_bits_reset(GPIOA, GPIO_PINS_7)
#define LCD_MOSI_HIGH() gpio_bits_set(GPIOA, GPIO_PINS_7)

l63t89 发表于 2022-3-31 16:03

   5)修改延时函数为rt_thread的rt_thread_mdelay()函数。

编译通过在main函数中添加头文件与显示函数,编译通过就OK了:

l63t89 发表于 2022-3-31 16:04

l63t89 发表于 2022-3-31 16:05

下载后显示如下图:

l63t89 发表于 2022-3-31 16:06

【感受】AT32F425是ARM M4的核心,使用起来跟STM32、N32G45流程是一样的。这次驱动GC9306还是挺轻松的。不过用过沁恒的CH582M后,感觉ARM 配置外设相双RISC-V就复杂很多。AT32F425的在RT_Thread 驱动LCD很流畅。

l63t89 发表于 2022-3-31 16:07

【建议】AT32F425没有中文固件库文档,建议官方的固件库文档有中英文的。还有就是开发板的针脚排列不是按顺序的,印刷的字体很小、而且的斜的,特别是夹在中间的,看起来很吃力,建议如果有下一板适当的调整,提高一下舒适度。

846299599 发表于 2022-6-14 10:54

博主有代码分享一下吗
页: [1]
查看完整版本: 【AT-START-F425测评】SPI驱动LCD屏