FSMC 驱动解析

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情

FSMC是STA2x65的一个控制模块,全名Flexible Static Memory Controller (FSMC)

The Flexible Static Controller (FSMC) supports, with two chip selects
● ROM
● Static RAM
● NOR type flash memories, not multiplexed
● NOR type flash memories, multiplexed
It also supports, with two additional separate chip selects:
● NAND type flash memories, SLC small or large page
● NAND type flash memories, MLC
For NAND type of memories, the FSMC has been enhanced to implement an error correction in
hardware, based on the Bose-Chaudhuri-Hocquenghem (BCH) code, able to correct up to 8-bit
over 512 bytes+syndrome. The BCH code will calculate, in hardware, the syndrome only. The
actual correction will be implemented through S/W intervention.

FSMC 相关的驱动代码在 arch/arm/mach-cartesio/fsmc.c 中。

1. init/exit:

static int __init cartesio_fsmc_init(void)
{
        return amba_driver_register(&cartesio_fsmc_driver);
}

static void __exit cartesio_fsmc_exit(void)
{
        amba_driver_unregister(&cartesio_fsmc_driver);
}

arch_initcall(cartesio_fsmc_init);
module_exit(cartesio_fsmc_exit);

MODULE_AUTHOR("STMicroelectronics");
MODULE_DESCRIPTION("Flexible Static Memory Controller driver");
MODULE_LICENSE("GPL");

static struct amba_driver cartesio_fsmc_driver = {
        .drv = {
                .name   = "fsmc",
                .owner  = THIS_MODULE,
        },
        .probe          = cartesio_fsmc_probe,
        .remove         = cartesio_fsmc_remove,
        .suspend        = cartesio_fsmc_suspend,
        .resume         = cartesio_fsmc_resume,
        .id_table       = cartesio_fsmc_ids,
};
static struct amba_id cartesio_fsmc_ids[] = {
        {
                .id     = 0x00080090,
                .mask   = 0x000FFFFF,
        },
        { 0, 0 },
};
amba_driver:

struct amba_driver {
        struct device_driver    drv;
        int                     (*probe)(struct amba_device *, struct amba_id *);
        int                     (*remove)(struct amba_device *);
        void                    (*shutdown)(struct amba_device *);
        int                     (*suspend)(struct amba_device *, pm_message_t);
        int                     (*resume)(struct amba_device *);
        struct amba_id          *id_table;
};
amba_id:

struct amba_id {
        unsigned int            id;
        unsigned int            mask;
        void                    *data;
};
2. cartesio_fsmc_probe():

static int cartesio_fsmc_probe(struct amba_device *dev, struct amba_id *id)
{
        struct fsmc_platform_data *plat = dev->dev.platform_data;
        struct cartesio_fsmc_info *info;
        int i, ret;

        /* must have platform data */
        if (!plat) {
                dev_err(&dev->dev, "missing platform data\n");
                return -EINVAL;
        }

        ret = amba_request_regions(dev, NULL);
        if (ret < 0)
                return -EBUSY;

        info = kzalloc(sizeof(struct cartesio_fsmc_info), GFP_KERNEL);
        if (info == NULL) {
                dev_err(&dev->dev, "%s, not enough memory\n", __func__);
                amba_release_regions(dev);
                return -ENOMEM;
        }

        amba_set_drvdata(dev, info);

        /* initialize fsmc_info */
        info->base = ioremap(dev->res.start, dev->res.end - dev->res.start + 1);

        for (i = 0; i < FSMC_BANK_NUM; i++) {
                writel(plat->bank[i].control, info->base + FSMC_BCR(i));
                writel(plat->bank[i].timing,  info->base + FSMC_BTR(i));
        }

        for (i = 0; i < FSMC_DEVICE_NUM; i++) {
                writel(plat->device[i].control,   info->base + FSMC_PCR(i));
                writel(plat->device[i].cm_timing, info->base + FSMC_PMEM(i));
                writel(plat->device[i].am_timing, info->base + FSMC_PATT(i));
                writel(plat->device[i].io_timing, info->base + FSMC_PIO(i));
        }

        dev_info(&dev->dev, "started at 0x%p\n", info->base);
        return 0;
}
fsmc_platform_data:

/*
 * Interface for FSMC driver configuration
 */
struct fsmc_platform_data {
        struct bank_cfg bank[FSMC_BANK_NUM];
        struct device_cfg device[FSMC_DEVICE_NUM];
};
/*
 * Number of SRAM/NOR-Flash banks supported by FSMC
 */
#define FSMC_BANK_NUM           3

/*
 * Number of PC-Card/NAND-Flash devices supported by FSMC
 */
#define FSMC_DEVICE_NUM         2
bank_cfg:

/*
 * SRAM/NOR-Flash bank configuration
 */
struct bank_cfg {
        u32 control;
        u32 timing;
};
device_cfg:

/*
 * PC-Card/NAND-Flash device configuration
 */
struct device_cfg {
        u32 control;
        u32 cm_timing;  /* Common Memory Space Timing    */
        u32 am_timing;  /* Attribute Memory Space Timing */
        u32 io_timing;  /* I/O Space Timing              */
};

cartesio_fsmc_info:

/*
 * FSMC driver context
 */
struct cartesio_fsmc_info {
        void __iomem *base;

        struct bank_cfg bank[FSMC_BANK_NUM];
        struct device_cfg device[FSMC_DEVICE_NUM];
};
3. cartesio_fsmc_remove:

static int cartesio_fsmc_remove(struct amba_device *dev)
{
        struct cartesio_fsmc_info *info;

        info = amba_get_drvdata(dev);

        iounmap(info->base);
        amba_release_regions(dev);
        kfree(info);

        dev_info(&dev->dev, "module stopped and unloaded\n");
        return 0;
}
4. PM: suspend/resume:

#ifdef CONFIG_PM
static int cartesio_fsmc_suspend(struct amba_device *dev, pm_message_t state)
{
        struct cartesio_fsmc_info *info;
        int i;

        info = amba_get_drvdata(dev);

        for (i = 0; i < FSMC_BANK_NUM; i++) {
                info->bank[i].control = readl(info->base + FSMC_BCR(i));
                info->bank[i].timing  = readl(info->base + FSMC_BTR(i));
        }

        for (i = 0; i < FSMC_DEVICE_NUM; i++) {
                info->device[i].control   = readl(info->base + FSMC_PCR(i));
                info->device[i].cm_timing = readl(info->base + FSMC_PMEM(i));
                info->device[i].am_timing = readl(info->base + FSMC_PATT(i));
                info->device[i].io_timing = readl(info->base + FSMC_PIO(i));
        }

        return 0;
}

static int cartesio_fsmc_resume(struct amba_device *dev)
{
        struct cartesio_fsmc_info *info;
        int i;

        info = amba_get_drvdata(dev);

        for (i = 0; i < FSMC_BANK_NUM; i++) {
                writel(info->bank[i].control, info->base + FSMC_BCR(i));
                writel(info->bank[i].timing , info->base + FSMC_BTR(i));
        }

        for (i = 0; i < FSMC_DEVICE_NUM; i++) {
                writel(info->device[i].control,   info->base + FSMC_PCR(i));
                writel(info->device[i].cm_timing, info->base + FSMC_PMEM(i));
                writel(info->device[i].am_timing, info->base + FSMC_PATT(i));
                writel(info->device[i].io_timing, info->base + FSMC_PIO(i));
        }

        return 0;
}
#else
#define cartesio_fsmc_suspend   NULL
#define cartesio_fsmc_resume    NULL
#endif
5. other functions:

fsmc_device_enable:

void fsmc_device_enable(struct device *dev, int device)
{
        struct cartesio_fsmc_info *info;
        struct amba_device *adev;
        u32 val;

        if (device >= FSMC_DEVICE_NUM) {
                dev_err(dev, "device ID is out of range: %d\n", device);
                return;
        }

        adev = container_of(dev, struct amba_device, dev);
        info = amba_get_drvdata(adev);

        val = readl(info->base + FSMC_PCR(device));
        val |= FSMC_PBKEN;
        writel(val, info->base + FSMC_PCR(device));
}
EXPORT_SYMBOL(fsmc_device_enable);
fsmc_set_ecc:

void fsmc_set_ecc(struct device *dev, int device, enum ecc_state state)
{
#ifdef CONFIG_BCH_8
        struct cartesio_fsmc_info *info;
        struct amba_device *adev;
        u32 val;

        if (device >= FSMC_DEVICE_NUM) {
                dev_err(dev, "device ID is out of range: %d\n", device);
                return;
        }

        adev = container_of(dev, struct amba_device, dev);
        info = amba_get_drvdata(adev);

        val = readl(info->base + FSMC_PCR(device));
        switch (state) {
        case ECC_PAGE_512:
                val &= ~FSMC_PECCP_256;
                break;
        case ECC_PAGE_256:
                val |= FSMC_PECCP_256;
                break;
        case ECC_RESET:
                /* disable hardware ECC and then re-enable to reset */
                val &= ~FSMC_PECCEN;
                writel(val, info->base + FSMC_PCR(device));
                break;
        }
        val |= FSMC_PECCEN;
        writel(val, info->base + FSMC_PCR(device));
#endif
}
EXPORT_SYMBOL(fsmc_set_ecc);
fsmc_get_parity:

int fsmc_get_parity(struct device *dev, int device, uint8_t *ecc_code)
{
        struct cartesio_fsmc_info *info;
        struct amba_device *adev;
        u32 val;

        if (device >= FSMC_DEVICE_NUM) {
                dev_err(dev, "device ID out of range: %d\n", device);
                return -ENODEV;
        }

        adev = container_of(dev, struct amba_device, dev);
        info = amba_get_drvdata(adev);

#ifdef CONFIG_BCH_8
        do {
                val = readl(info->base + FSMC_STATUS(device));
        } while (!(val & STATUS_ECCRDY));

        val = readl(info->base + FSMC_ECCR(device));
        ecc_code[0] = (val >>  0) & 0xFF;
        ecc_code[1] = (val >>  8) & 0xFF;
        ecc_code[2] = (val >> 16) & 0xFF;
        ecc_code[3] = (val >> 24) & 0xFF;

        val = readl(info->base + FSMC_ECC2R(device));
        ecc_code[4] = (val >>  0) & 0xFF;
        ecc_code[5] = (val >>  8) & 0xFF;
        ecc_code[6] = (val >> 16) & 0xFF;
        ecc_code[7] = (val >> 24) & 0xFF;

        val = readl(info->base + FSMC_ECC3R(device));
        ecc_code[8] = (val >>  0) & 0xFF;
        ecc_code[9] = (val >>  8) & 0xFF;
        ecc_code[10] = (val >> 16) & 0xFF;
        ecc_code[11] = (val >> 24) & 0xFF;

        val = readl(info->base + FSMC_STATUS(device));
        if (!(val & 0x4000)) {
                ecc_code[12] = (val >>  8) & 0xFF;
                ecc_code[13] = (val >> 16) & 0xFF;
        } else {
                ecc_code[12] = (val >> 16) & 0xFF;
                ecc_code[13] = 0x0;
        }
        val = readl(info->base + FSMC_STATUS(device));
        val &= ~0x8000;
        writel(val, info->base + FSMC_STATUS(device));
#else
        val = readl(info->base + FSMC_ECCR(device));
        ecc_code[0] = (val >>  0) & 0xFF;
        ecc_code[1] = (val >>  8) & 0xFF;
        ecc_code[2] = (val >> 16) & 0xFF;
#endif
        return 0;
}
EXPORT_SYMBOL(fsmc_get_parity);











STM32 FSMC驱动TFT-LCD显示BMP图片全栈解析 嵌入式图形显示的核心在于将CPU指令高效转化为LCD可识别的时序信号。FSMC(灵活静态存储控制器)作为STM32连接并行TFT-LCD的关键硬件接口,通过地址线复用(如A0映射为RS信号)和可配置时序参数(ADDSET/DATAST),实现了对ILI9341等LCD控制器的无软件延时驱动。其技术价值在于卸载GPIO模拟开销、保障纳秒级时序精度,并天然支持内存映射式编程。典型应用场景包括工业HMI、智能仪表及资源受限设备的Logo/图标显示。本文围绕FSMC硬件配置、BMP转RGB565预处理、GRAM窗口 阅读详情

相关推荐

STM32 FSMC驱动LCD的8080时序配置全解析

FSMC(灵活静态存储控制器)是STM32中用于扩展并行外设的关键硬件模块,其本质是一种可编程异步总线时序控制器。通过精确配置地址建立、数据建立等关键时序参数,FSMC能模拟工业标准8080并行接口协议,从而驱动TFT-LCD屏幕。该方案无需专用显示外设,显著降低BOM成本与设计复杂度,在STM32F4系列MCU中被广泛应用于中小尺寸RGB565显示屏。技术价值体现在高确定性时序控制、零额外IP开销及与HAL库的良好集成;典型应用场景包括工业HMI、嵌入式人机界面及低成本智能终端。本文聚焦FSMC在LCD驱

weixin_32306683的博客 433

STM32F407驱动电容触摸屏全栈解析FSMC+I²C+PWM

电容触摸屏是嵌入式人机交互的核心外设,其稳定运行依赖于显示控制、触摸采集与背光调节三大技术模块的协同。在STM32平台中,FSMC总线提供高速并行显存访问能力,精准匹配TFT驱动IC的8080接口时序;I²C协议则以地址寻址机制实现多设备共存,支撑触摸控制器坐标上报;而PWM调光与GPIO开关构成双模背光控制体系,兼顾能效与体验。这些技术共同构成嵌入式GUI底层驱动的基础能力,广泛应用于工业HMI、医疗设备及智能终端。本文以STM32F407为平台,深入剖析FSMC地址映射、I²C寄存器访问与PWM占空比调

x8y9z0的博客 1086

深入解析单片机FSMC驱动8080 LCD的配置与优化

本文深入解析了单片机通过FSMC(灵活静态存储控制器)驱动8080接口LCD屏幕的硬件配置与软件优化方法。详细阐述了FSMC如何通过地址映射高效模拟8080时序,将CPU从繁重的刷屏任务中解放出来,并提供了从引脚配置、地址计算、时序参数设定到性能优化的完整实战指南,帮助开发者实现稳定、高速的显示驱动

weixin_29171129的博客 221

STM32 FSMC+I²C驱动电容触摸屏全栈解析

电容触摸屏在嵌入式人机交互系统中是核心输入输出设备,其稳定运行依赖于显示与触控双通道的协同通信。从硬件接口原理看,TFT驱动芯片常被抽象为PSRAM设备,需通过FSMC总线实现高速像素级内存映射;而GT911等触摸控制器则基于I²C协议完成寄存器级数据交互。该架构兼顾带宽效率与引脚复用性,广泛应用于工业HMI、智能终端等场景。FSMC时序配置、A18地址选通机制、I²C多设备地址管理及中断驱动的触摸事件处理,共同构成可靠触控体验的技术基础。本文聚焦STM32F407平台,详解FSMC与I²C双总线协同设计的

x8y9z0的博客 751

【STM32】FSMC驱动LCD屏幕的实战解析与优化技巧

本文深入解析了STM32的FSMC外设驱动LCD屏幕的核心原理与优化技巧。通过硬件连接配置、时序参数调优、HAL库适配及常见问题排查,帮助开发者高效实现LCD驱动,提升显示性能与稳定性。特别针对FSMC的时序优化和DMA加速技巧进行了详细探讨。

weixin_30329623的博客 436

STM32F103 FSMC驱动LCD:时序匹配与硬件地址映射实战解析

本文深入解析STM32F103 FSMC模块驱动LCD屏幕的实战技巧,重点探讨时序匹配与硬件地址映射两大核心问题。通过8080接口时序分析、地址线巧妙模拟DCX信号等实用方法,结合NT35310驱动芯片的配置实例,提供从硬件连接到软件初始化的完整解决方案,并分享常见问题排查与性能优化经验。

weixin_30819085的博客 566

STM32 FSMC驱动SSD1963 LCD:8080时序硬件解析与实战

在嵌入式显示开发中,并行接口时序控制是连接MCU与外部设备的核心基础。8080并行接口作为一种经典的通信协议,广泛应用于LCD驱动芯片。其原理是通过数据总线、片选、读写使能等信号线的精确时序配合,完成命令与数据的传输。传统GPIO模拟方式代码臃肿且时序易偏差,而利用MCU内置的FSMC(灵活静态存储器控制器)硬件外设,可将外部设备映射为存储地址,自动生成符合规范的时序波形,极大提升通信效率和可靠性。这种硬件加速方案尤其适用于SSD1963这类支持高分辨率、真彩色的显示驱动芯片,在工业HMI、智能设备界面等场

weixin_30530339的博客 363

FSMC驱动NT35510:基于STM32的8080并口时序深度解析与实战

本文深入解析了STM32通过FSMC驱动NT35510 LCD控制器的8080并口时序与实战技巧。详细介绍了硬件连接、地址计算、时序优化及软件驱动开发,帮助开发者高效实现高性能TFT LCD显示,特别适合嵌入式系统应用。

weixin_29164497的博客 316

STM32 FSMC驱动TFTLCD 难点解析

本文适合学过LCD显示,但是不是很理解的同学,博主用的是战舰STM32 本篇文章博主将和大家讨论三个主题:FSMC有关配置、一串字符显示原理、汉字显示原理。。下面进入正题→_→ 一、FSMC的有关配置(博主用的是FSMC_A10):       先给大家来个了解FSMC的好文,来自别人家的博客http://blog.csdn.net/jxnu_xiaobing/article/details

后起的博客 2万+

野火指南者LCD驱动FSMC时序配置与CubeMX实战解析

本文详细解析了野火指南者开发板上使用STM32的FSMC控制器驱动LCD显示屏的实战方法。通过CubeMX配置FSMC时序参数,实现高效的8080接口通信,涵盖时序计算、GPIO设置及常见问题调试技巧,帮助开发者快速掌握硬件加速的LCD驱动方案。

u6v7w8x的博客 791

STM32与AD7606高效集成:基于FSMC驱动程序解析

STM32与AD7606高效集成:基于FSMC驱动程序解析 【下载地址】基于STM32的FSMCAD7606驱动程序 本项目提供了基于STM32微控制器与AD7606模数转换器的硬件连接和驱动程序,专注于通过FSMC接口实现高效通信。AD7606是一款6通道同步采样ADC,适用于高速数据采集场景。程序设计简洁,无需复杂...

gitblog_06717的博客 750

STM32CubeMX实战:FSMC与GPIO模拟8080协议驱动TFT-LCD全解析

本文详细解析了如何使用STM32CubeMX配置FSMC与GPIO模拟8080协议驱动TFT-LCD屏幕。通过对比FSMC硬件方案和GPIO软件模拟方案的性能差异,提供了选型建议和优化技巧,帮助开发者快速实现高效显示驱动

weixin_32770423的博客 196

STM32 FSMC驱动外部SRAM:时序配置与性能优化实战解析

本文深入解析了STM32 FSMC驱动外部SRAM的时序配置与性能优化实战。通过详细讲解FSMC控制器工作原理、硬件连接设计、时序参数配置及性能优化技巧,帮助开发者高效扩展嵌入式系统内存资源。特别针对IS62WV51216等SRAM芯片,提供了实验代码和常见问题排查指南,适用于GUI缓存、高速数据采集等应用场景。

weixin_30340819的博客 354

STM32 FSMC驱动LCD:8080时序模拟与地址映射实战解析

本文深入解析STM32 FSMC外设驱动LCD显示屏的核心原理与实践方法,重点讲解8080时序模拟与地址映射计算。通过FSMC的NOR Flash模式B配置,自动生成正确的读写时序,大幅提升显示驱动效率。详细介绍了时序参数计算、硬件连接指南及STM32CubeMX配置步骤,帮助开发者快速掌握FSMC驱动LCD的技术要点。

vscode6remote的博客 172

深入解析STM32 FSMC:如何高效驱动ILI9341 LCD屏

本文深入解析STM32 FSMC外设如何高效驱动ILI9341 LCD屏,详细介绍了FSMC的地址映射机制、硬件连接要点、时序配置原理及HAL库实战配置。通过FSMC替代GPIO模拟8080时序,可大幅提升显示刷新速度并降低CPU占用率,实现流畅的图形显示效果。

alice7model的博客 704

HAL库FSMC驱动LCD实战:从时序模拟到8080接口的深度解析(附代码与调试技巧)

本文深度解析如何使用STM32的HAL库和FSMC控制器驱动8080接口LCD屏幕。通过详细的时序配置、地址映射原理和实战代码,帮助开发者快速掌握硬件加速显示技术,并提供调试技巧与常见问题解决方案,大幅提升嵌入式显示性能。

water的专栏 786

STM32F4硬核实战:FSMC驱动TFTLCD从原理到代码全解析,附避坑指南+调试干货

你是否曾在配置FSMC时序时因参数匹配问题抓耳挠腮?是否在驱动LCD时被地址映射、数据宽度等细节搞得晕头转向?这篇文章将从底层原理出发,带你打通“FSMC驱动TFTLCD”的任督二脉:从FSMC的存储区块划分、信号引脚功能,到TFTLCD的接口类型、驱动芯片指令集,再到硬件电路与代码的深度耦合实现,每一个环节都配有原理图解析、时序图说明和调试案例。

smart_boy__的博客 1860

FSMC驱动TFTLCD:从SRAM映射到8080时序的实战解析

本文详细解析FSMC驱动TFTLCD的核心原理与实战技巧,从SRAM映射到8080时序的配置方法。通过硬件连接方案、时序参数计算及驱动代码实现,帮助开发者高效点亮TFTLCD并优化性能,解决常见问题如白屏和数据错位。

weixin_42520573的博客 349

STM32 FSMC高效驱动LCD:从时序解析到实战优化

本文深入解析STM32 FSMC外设驱动LCD屏幕的技术原理与实战优化。通过将LCD映射为SRAM设备,FSMC硬件自动生成精确的8080接口时序,大幅提升刷新率并降低CPU负载。详细介绍了时序配置、地址映射、硬件连接及DMA协同等核心技巧,帮助开发者高效解决LCD驱动中的常见问题。

redis7keeper的博客 714
上一篇: 查看用户命令id_finger和查看用户组命令groups
下一篇: cartesio_nand.c
lamdoc
博客等级 码龄18年 155粉丝 655原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值