STM32F1的FSMC学习笔记


本节使用FSMC来驱动LCD实验,使用LCD模拟8080时序就可以驱动显示器芯片。光与使用8080时序驱动LCD的文章https://blog.csdn.net/qq_42171042/article/details/132236310

FSMC

FSMC,flexible static memory Controller,灵活的静态存储控制器。
用途:用于驱动SRAM,NOR FLASH,NAND FLASH及PC卡类型的存储器。
配置好FSMC,定义一个指向这些地址的指针,通过对指针操作就可以直接修改存储单元的内容,FSMC自动完成读写命令和数据访问操作,不需要程序去实现时序。这里FSMC具体的工作原理还不懂,为什么能够通过读写地址的方式来写数据读数据,通过写命令的方式

F1/ F4(407)系列大容量型号,且引脚数目在100脚以上的芯片都有FSMC接口
F4/F7/H7系列就是FMC接口:他可以驱动sdram

FSMC硬件

FSMC框图介绍

在这里插入图片描述

FSMC通信引脚介绍

在这里插入图片描述

使用FSMC驱动LCD

在这里插入图片描述
在这里插入图片描述

FSMC时序介绍

FSMC是Flexible灵活的,可以产生多种时序来控制外部存储器。
NOR/PSRAM控制器产生的异步时序就有5种,总体分为两类:一类是模式1,其他为拓展模式。
拓展模式相对模式1来说读写时序时间参数设置可以不同,满足存储器读写时序不一样需求。
在这里插入图片描述

FSMC相关寄存器介绍

对于NOR_FLASH/PSRAM控制器(存储块1)配置工作,通过FSMC_BCRx、FSMC_BTRx和FSMC_BWTRx寄存器设置(其中x=1~4,对应4个区)

FSMC_BCR4(片选控制寄存器。包含存储器块的信息(存储器类型/数据宽度等))

在这里插入图片描述
EXTMOD:扩展模式使能位,控制是否允许读写不同的时序。(若读和写用不同的时序,该位设置为1)
WREN:写使能位。向TFTLCD写入数据,该位设置1
MWID[1:0]:存储器数据总线宽度。00,表示8位数据模式;01表示16位数据模式;10和11保留。
MTYP[1:0]:存储器类型。00表示SRAM、ROM;01表示PSRAM;10表示NOR FLASH;11保留。
MBKEN:存储块使能位。该位置1

FSMC_BTR4(片选时序寄存器。设置读操作时序参数(ADDSET/DATAST))

在这里插入图片描述

ACCMOD[1:0]:访问模式。00:模式A;01:模式B;10:模式C;11:模式D。

DATAST[7:0]:数据保持时间,等于DATAST(+1)个HCLK时钟周期,DATAST最大为255。
对于ILI9341来说,其实就是RD低电平持续时间,最小为355ns。
对于F1,一个HCLK = 13.9ns(1/72M),设置为15
对于F4,一个HCLK = 6ns(1/168M),设置为60

ADDSET[3:0]:地址建立时间。表示ADDSET(+1)个HCLK时钟周期,ADDSET最大为15。
对于ILI9341来说,相当于RD高电平持续时间,为90ns。
F1即使设置为0,RD也有超过90ns的高电平,这里设置为1。F4对该位设置为15。
如果未设置上一个寄存器的EXTMOD位,则读写共用这个时序寄存器!

FSMC_BWTR4(写时序寄存器。设置写操作时序参数(ADDSET/DATAST))

在这里插入图片描述

FSMC寄存器组合说明
在ST官方提供的寄存器定义里面,并没有定义FSMC_BCRx、FSMC_BTRx、FSMC_BWTRx
等这个单独的寄存器,而是将他们进行了一些组合,规则如下:

FSMC_BCRx和FSMC_BTRx,组合成BTCR[8]寄存器组,他们的对应关系如下:
BTCR[0]对应FSMC_BCR1,BTCR[1]对应FSMC_BTR1
BTCR[2]对应FSMC_BCR2,BTCR[3]对应FSMC_BTR2
BTCR[4]对应FSMC_BCR3,BTCR[5]对应FSMC_BTR3
BTCR[6]对应FSMC_BCR4,BTCR[7]对应FSMC_BTR4

FSMC_BWTRx则组合成BWTR[7]寄存器组,他们的对应关系如下:
BWTR[0]对应FSMC_BWTR1,BWTR[2]对应FSMC_BWTR2,
BWTR[4]对应FSMC_BWTR3,BWTR[6]对应FSMC_BWTR4,
BWTR[1]、BWTR[3]和BWTR[5]保留,没有用到

硬件IO连接关系

在这里插入图片描述

实验源码

#include "./BSP/LCD/lcd.h"
#include "./SYSTEM/delay/delay.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LCD/lcd_ex.c"
#include "./BSP/LCD/lcdfont.h"

SRAM_HandleTypeDef g_sram_handle;    /* SRAM句柄,初始化FSMC控制LCD) */

/* LCD画笔和背景颜色 */
uint32_t g_point_color = 0XF800;    /* »­±ÊÑÕÉ« */
uint32_t g_back_color  = 0XFFFF;    /* ±³¾°É« */


/* LCD重要参数,基本命令和高宽 */
_lcd_dev lcddev;

/* 写命令*/
void lcd_wr_regno(volatile uint16_t cmd)
{
    cmd = cmd;
    *(uint16_t *)(FSMC_ADDR_CMD) = cmd;
}

/* 写数据 */
void lcd_wr_data(volatile uint16_t data)
{
    data = data;
    *(uint16_t *)(FSMC_ADDR_DATA) = data;
}

/* 写寄存器 */
void lcd_write_reg(uint16_t regno, uint16_t data)
{
    lcd_wr_regno(regno);
    lcd_wr_data(data);
}

/* 读数据,通过读取指定地址的数据来读取所需数据,这里的具体工作原来还不太清楚,FSMC,暂时先放着,以后再研究 */
uint16_t lcd_rd_data(void)
{
    volatile uint16_t ram;
    ram = *(uint16_t *)(FSMC_ADDR_DATA);
    return ram;
}

/* 设置坐标*/
void lcd_set_cursor(uint16_t x, uint16_t y)
{
    lcd_wr_regno(0x2A);
    lcd_wr_data(x >> 8);
    lcd_wr_data(x & 0XFF);
    lcd_wr_regno(0x2B);
    lcd_wr_data(y >> 8);
    lcd_wr_data(y & 0XFF);
}

/* 写数据准备 */
void lcd_write_ram_prepare(void)
{
    lcd_wr_regno(0x2C);
}

/*画点 */
void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color)
{
    lcd_set_cursor(x, y);
    lcd_write_ram_prepare();
    lcd_wr_data(color);
}

/*读点 */
uint16_t lcd_read_point (uint16_t x, uint16_t y)
{
    uint16_t r = 0, g = 0, b = 0;   /* ¶¨Òå±äÁ¿ */
    
    lcd_set_cursor(x, y);           /*设置坐标 */
    lcd_wr_regno(0X2E);             /*发送读命令 */
    r = lcd_rd_data();              /* 假读 */
    r = lcd_rd_data();              /* 读rg */
    b = lcd_rd_data();              /* 读b */
    g = r & 0XFF;                   /* µÃµ½gÖµ */
    return (((r >> 11) << 11) | ((g >> 2) << 5) | (b >> 11));
}

/* lcd清屏*/
void lcd_clear(uint16_t color)
{
    uint32_t totalpoint = 240 * 320;

    lcd_set_cursor(0x0000, 0x0000);
    lcd_write_ram_prepare();
    
    for (uint32_t index; index < totalpoint; index++)
    {
        lcd_wr_data(color);
    }
}

//初始化FSMC
void lcd_init(void)
{
    FSMC_NORSRAM_TimingTypeDef fsmc_read_handle;
    FSMC_NORSRAM_TimingTypeDef fsmc_write_handle;
    
    /* FSMC控制的对象 */
    g_sram_handle.Instance = FSMC_NORSRAM_DEVICE;
    g_sram_handle.Extended = FSMC_NORSRAM_EXTENDED_DEVICE;
    
    g_sram_handle.Init.NSBank               = FSMC_NORSRAM_BANK4;               /* NOR/PSRAM存储块中的BANK4 */
    g_sram_handle.Init.DataAddressMux       = FSMC_DATA_ADDRESS_MUX_DISABLE;    /* 数据线和地址线步复用 */
    g_sram_handle.Init.MemoryType           = FSMC_MEMORY_TYPE_SRAM;            /* 存储器类型SRAM */
    g_sram_handle.Init.MemoryDataWidth      = FSMC_NORSRAM_MEM_BUS_WIDTH_16;    /* 存储器宽度16位 */
    g_sram_handle.Init.BurstAccessMode      = FSMC_BURST_ACCESS_MODE_DISABLE;   /* 是否使能突发访问,仅对同步突发存储器有效,此处未用到*/
    g_sram_handle.Init.WaitSignalPolarity   = FSMC_WAIT_SIGNAL_POLARITY_LOW;    /* 等待信号的极性,仅在突发模式访问下有用*/
    g_sram_handle.Init.WaitSignalActive     = FSMC_WAIT_TIMING_BEFORE_WS;       /*  */
    g_sram_handle.Init.WriteOperation       = FSMC_WRITE_OPERATION_ENABLE;      /*存储器使能 */
    g_sram_handle.Init.WaitSignal           = FSMC_WAIT_SIGNAL_DISABLE;         /*  */
    g_sram_handle.Init.ExtendedMode         = FSMC_EXTENDED_MODE_ENABLE;        /* 读写使用不同的时序 */
    g_sram_handle.Init.AsynchronousWait     = FSMC_ASYNCHRONOUS_WAIT_DISABLE;   /* */
    g_sram_handle.Init.WriteBurst           = FSMC_WRITE_BURST_DISABLE;         /*禁止突发写 */

    /* FSMC读时序控制器*/
    fsmc_read_handle.AccessMode         = FSMC_ACCESS_MODE_A;    /* 模式A */
    fsmc_read_handle.AddressSetupTime   = 1;        /*地址建立时间,HCLK 1/72M = 13.9ns * 2 = 27.8ns (实际 > 200ns) */
    fsmc_read_handle.AddressHoldTime    = 0;        /* 地址保持时间(ADDHLD),模式A没有用到 */
    /* */
    fsmc_read_handle.DataSetupTime      = 15;       /*数据保存时间(DATAST)为16个HCLK = 13.9 * 16 = 222.4ns */

    /* FSMC写时序控制器,波形一致 */
    fsmc_write_handle.AccessMode        = FSMC_ACCESS_MODE_A;   /* ģʽA */
    fsmc_write_handle.AddressSetupTime  = 1;        /* µØÖ·½¨Á¢Ê±¼ä(ADDSET)Ϊ2¸öHCLK = 27.8 ns */
    fsmc_write_handle.AddressHoldTime   = 0;        /* µØÖ·±£³Öʱ¼ä(ADDHLD) ģʽAÊÇûÓÐÓõ½ */
    /* ijЩҺ¾§Çý¶¯ICµÄдÐźÅÂö¿í£¬×îÉÙÒ²µÃ50ns¡£ */
    fsmc_write_handle.DataSetupTime     = 3;        /* 数据保持时间(DATAST)为4个HCLK = 13.9 * 4 = 55.6ns (实际 > 200ns) */
    
    HAL_SRAM_Init(&g_sram_handle, &fsmc_read_handle, &fsmc_write_handle);
    delay_ms(50);

    /* 读取ID */
    lcd_wr_regno(0xD3);
    lcddev.id = lcd_rd_data();  /* ¼Ù¶Á */
    lcddev.id = lcd_rd_data();  /* 00 */
    lcddev.id = lcd_rd_data();  /* 93 */
    lcddev.id <<= 8;
    lcddev.id |= lcd_rd_data();  /* 41 */
    
    printf("lcddev_id:%#x \r\n", lcddev.id);
    
    /* 初始化LCD芯片 */
    if (lcddev.id == 0x9341)
        lcd_ex_ili9341_reginit();
    else
        lcd_ex_st7789_reginit();
    
    /* 对LCD控制结构体赋值 */
    lcddev.width = 240;
    lcddev.height = 320;
    lcddev.setxcmd = 0x2A;
    lcddev.setycmd = 0x2B;
    lcddev.wramcmd = 0x2C;
    
    lcd_wr_regno(lcddev.setxcmd);
    lcd_wr_data(0);
    lcd_wr_data(0);
    lcd_wr_data((lcddev.width - 1) >> 8);
    lcd_wr_data((lcddev.width - 1) & 0XFF);
    lcd_wr_regno(lcddev.setycmd);
    lcd_wr_data(0);
    lcd_wr_data(0);
    lcd_wr_data((lcddev.height - 1) >> 8);
    lcd_wr_data((lcddev.height - 1) & 0XFF);
    
    /* ÉèÖÃɨÃè·½Ïò */
    lcd_write_reg(0x36, 1 << 3);
    
    /* µãÁÁ±³¹â */
    LCD_BL(1);
    
    /* lcd_clear */
    lcd_clear(0xFFFF);
}

//设置使用FSMC模拟8080时序所需要的外设。包括时钟使能和设置GPIO工作模式。这里的SRAM是不是显示器芯片的存储器。
void HAL_SRAM_MspInit(SRAM_HandleTypeDef *hsram)
{
    GPIO_InitTypeDef gpio_init_struct;
    
    __HAL_RCC_FSMC_CLK_ENABLE();            /* 使能FSMC时钟 */
    __HAL_RCC_GPIOD_CLK_ENABLE();           /* ʹÄÜGPIODʱÖÓ */
    __HAL_RCC_GPIOE_CLK_ENABLE();           /* ʹÄÜGPIOEʱÖÓ */
    
    LCD_WR_GPIO_CLK_ENABLE();
    LCD_RD_GPIO_CLK_ENABLE();
    LCD_BL_GPIO_CLK_ENABLE();
    LCD_CS_GPIO_CLK_ENABLE();
    LCD_RS_GPIO_CLK_ENABLE();
    
    gpio_init_struct.Pin = LCD_CS_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_AF_PP;                /* ÍÆÍ츴Óà */
    gpio_init_struct.Pull = GPIO_PULLUP;                    /* ÉÏÀ­ */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* ¸ßËÙ */
    HAL_GPIO_Init(LCD_CS_GPIO_PORT, &gpio_init_struct);     /* ³õʼ»¯LCD_CSÒý½Å */
    
    gpio_init_struct.Pin = LCD_WR_GPIO_PIN;
    HAL_GPIO_Init(LCD_WR_GPIO_PORT, &gpio_init_struct);     /* ³õʼ»¯LCD_WRÒý½Å */

    gpio_init_struct.Pin = LCD_RD_GPIO_PIN;
    HAL_GPIO_Init(LCD_RD_GPIO_PORT, &gpio_init_struct);     /* ³õʼ»¯LCD_RDÒý½Å */

    gpio_init_struct.Pin = LCD_RS_GPIO_PIN;
    HAL_GPIO_Init(LCD_RS_GPIO_PORT, &gpio_init_struct);     /* ³õʼ»¯LCD_RSÒý½Å */
    
    gpio_init_struct.Pin = LCD_BL_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /* ÍÆÍìÊä³ö */
    HAL_GPIO_Init(LCD_BL_GPIO_PORT, &gpio_init_struct);     /* LCD_BLÒý½ÅģʽÉèÖÃ(ÍÆÍìÊä³ö) */
    
    /* Êý¾ÝÏß³õʼ»¯ */
    /* ³õʼ»¯PD0,1,8,9,10,14,15 */
    gpio_init_struct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8 \
                           | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15;
    gpio_init_struct.Mode = GPIO_MODE_AF_PP;                  /* ÍÆÍ츴Óà */
    gpio_init_struct.Pull = GPIO_PULLUP;                      /* ÉÏÀ­ */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;            /* ¸ßËÙ */
    HAL_GPIO_Init(GPIOD, &gpio_init_struct);                  /* ³õʼ»¯ */

    /* ³õʼ»¯PE7,8,9,10,11,12,13,14,15 */
    gpio_init_struct.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 \
                           | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
    HAL_GPIO_Init(GPIOE, &gpio_init_struct);
}

main.c没有变化。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值