• 树莓派4B-SPI读写flash-FM25CL16B(同时支持FM25CL64等其它系列Flash)


    1.树莓派SPI介绍

     4B的引脚如下图所示:

    其中Pin19、21、23是SPI0,接口定义如下所示:

    • 时钟(SPI CLK, SCLK)
    • 主机输出、从机输入(MOSI)
    • 主机输入、从机输出(MISO)

    在使用 SPI 接口前,你需要使用 gpio 命令来加载 SPI 驱劢到内核中:

    gpio load spi

    如果您需要的缓冲区大于 4KB,需要在命令行迕行指定缓冲区的大小,单位是 KB:

    gpio load spi 100

    上述命令将会分配 100KB 的缓冲区.(您可能很少需要改变返项讴置,默认值对于绝大多数应用程序来说已经足够了). 为了使用 SPI 库,你也需要在你的程序中添加如下语句:

    #include <wiringPiSPI.h>

    程序在编译连接时,仍然需要添加-lwiringPi 选项

    需要用到的函数如下所示:

    int wiringPiSPISetup(int channel, int speed);
    //使用该函数可以初始化一个 SPI 通道,树莓派有两个 SPI 通道(0 和 1)。
    //speed 参数是一个整数值,其范围为 500000~32000000,代表 SPI 时钟速度,单位是 Hz。
    //返回值为-1,则失败。则需要检查一下电路连接和是否开启了树莓派的SPI。
    
    int wiringPiSPIDataRW(int channel, unsigned char* data, int len);
    //该函数执行一个同时读写操作,通过选定的 SPI 总线。缓冲区中的数据,将会被 SPI总线的返回数据所覆盖。
    
    void delay (unsigned int howLong)
    //延时ms,最大传入32位无符号型整数,大约49天。
    
    void delayMicroseconds (unsigned int howLong)
    //延时微秒,最大传入32位无符号型整数,大约71分钟

    2.FM25L16B芯片介绍

        FM25L16是采用先进的铁电工艺制造的1024*16位的非易失性存储器(2048个字节)。铁电随机存储器(FRAM)具有非易失性,并且可以象RAM一样快速读写。FM25L16中的数据在掉电后可以保存45年。相对EEPROM或其他非易失性存储器,FM25L16具有结构更简单,系统可靠性更高等诸多优点。
       与EEPROM系列不同的是,FM25L16以总线速度进行写操作,无须延时。数据发到FM25L16后直接写到具体的单元地址,下一个总线操作可以立即开始,无需数据轮询。此外,FM25L16的读/写次数几乎为无限次,比EEPROM高得多。同时,FM25L16的功耗也远比EEPROM低。

    引脚定义如下所示:

     

    • /CS: 片选,低电平为激活设备
    • SCK: SPI输入时钟,频率最高支持20MHZ
    • /HOLD: 输入保持,比如当我们在进行读写的时候,假如产生了一个中断,由于时序已经在进行了,这时可以给个低电平让芯片保持时序,等待中断处理完成后,再来置高,继续读写数据.
    • /WP: 写保护,为低电平则不能写操作
    • SI、SO: SPI输入输出数据引脚

    指令如下所示:

     

    2.1 状态寄存器(0x01)介绍

    状态寄存器的每个bit位意义如下所示:

     

    其中BP1和BP0是设置写保护区域的.如下图所示:

     

    我们必须将BP1和BP0设置为0,才可以有写所有地址的权限.

     

    2.2 写寄存器(0x06)介绍

    所有对内存数组的写入都以WREN(0X06)操作码开头,下一个操作码是WRITE指令,这个操作码后面跟着一个双字节地址。地址的前5位将被忽略(最多存储2048字节),然后就可以一直写入数据.最后将CS置高则完成写操作.

     

    3.最终代码

    #include<stdio.h>
    #include <cstring>
    #include<wiringPi.h>
    #include <wiringPiSPI.h>
    
    typedef unsigned char u8;
    typedef unsigned short u16;
    
    #define FM25CL16_WREN       0x06       // 写使能
    #define FM25CL16_WRITE      0x02       // 写寄存器
    #define FM25CL16_READ       0x03       // 读寄存器
    #define FM25CL64_WRSR       0x01       // 状态寄存器
    #define FM25L16_CSPIN       21         // 片选引脚
    
    void initSPI()
    {
        //初始化所用到的IO引脚
        pinMode(FM25L16_CSPIN, OUTPUT);
        digitalWrite(FM25L16_CSPIN, HIGH);
    
        //初始化SPI通道0,并设置为速度
        if(wiringPiSPISetup(0,5000000)==-1) {
            printf("init spi failed!
    ");
        }
    }
    
    
    // 片选
    void fm25l16Cs(u8 select)
    {
        if (select == 0) {
           digitalWrite(FM25L16_CSPIN, LOW);
        } else {
           digitalWrite(FM25L16_CSPIN, HIGH);
        }
    }
    
    // 向FLASH写入一个字节数据
    static u8 fm25l16WriteByte(u8 Temp)
    {
        return wiringPiSPIDataRW(0,&Temp,1);
    }
    
    // FLASH写使能
    static void fm25l16WriteEnable()
    {
        fm25l16Cs(0);
        fm25l16WriteByte(FM25CL16_WREN);
        fm25l16Cs(1);
    
    }
    
    // 写入一串数据
    void fm25l16WriteBuff(u16 addr,u8* buff,u16 len)
    {
        u8 buffHead[3]; // 数据头
    
        fm25l16WriteEnable();
        fm25l16Cs(0);
        buffHead[0] = FM25CL16_WRITE;
        buffHead[1] = (addr&0xFF00)>>8;
        buffHead[2] = (addr&0x00FF);
        wiringPiSPIDataRW(0,buffHead,3);
        wiringPiSPIDataRW(0,buff,len);
        fm25l16Cs(1);
    }
    
    
    // 读出一串数据到buff中
    void fm25l16ReadBuff(u16 addr,u8* buff,u16 len)
    {
        u8 buffHead[3]; // 数据头
    
        fm25l16Cs(0);
        buffHead[0] = FM25CL16_READ;
        buffHead[1] = (addr&0xFF00)>>8;
        buffHead[2] = (addr&0x00FF);
        wiringPiSPIDataRW(0,buffHead,3);
        wiringPiSPIDataRW(0,buff,len);
        fm25l16Cs(1);
    }
    
    // 写状态
    void fm25l16Status()
    {
        u8 buff[2] = {FM25CL64_WRSR, 0X00};
        fm25l16WriteEnable();
        fm25l16Cs(0);
        wiringPiSPIDataRW(0,buff,2); // 取消写保护
        fm25l16Cs(1);
    }
    
    int main()
    {
        u8 data[10];
        u8 i=0;
        u8 beginData = 0;
        //初始化wiringPI的库函数
        if(wiringPiSetup()<0) {
            printf("init wiringPi error
    ");
        }
        initSPI();          //spi的初始化
        fm25l16Status();    // 写状态寄存器
        while(1) {
            for(i=0;i<10;i++) {
                data[i] = beginData++;
            }
            fm25l16WriteBuff(0,data,10);
            printf("write ok
    ");
            fm25l16ReadBuff(0,data,10);
            printf("read: ");
            for(i=0;i<10;i++) {
                 printf("%d ",data[i]);
            }
            printf("
    ");
            delay(20);
        }
        return 0;
    } 

    运行效果如下所示:

     


    人间有真情,人间有真爱。

    如果您喜欢这里,感觉对你有帮助,并且有多余的软妹币的话,不妨投个食吧,赞赏的时候,留下美句和你的博客地址哦~   戳这里看谁投食了


  • 相关阅读:
    C/C++内存管理 笔记
    RAII惯用法:C++资源管理的利器
    JS、Flash 实现复制功能 (浏览器兼容)
    JS页面刷新实现方法总结
    php 一些常用的语句
    使用ZeroClipboard解决跨浏览器复制到剪贴板的问题
    window.opener.location.reload() and href()的区别 弹出页修改后刷新父窗体
    查看Mysql数据库大小
    JQUERY操作集锦
    十进制正整数转换成六十二进制
  • 原文地址:https://www.cnblogs.com/lifexy/p/14992847.html
Copyright © 2020-2023  润新知