一、W25Qxx(FLASH)
1、w25qxx驱动
w25qxx.h
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <drv_common.h>
// 制造商ID
// Manufacturer ID: 0xEF (Winbond)
// Device ID: 0x16 (indicating W25Q64)
// Device ID: 0x17 (indicating W25Q128)
#define W25QX_ID 0x17EF
// 寄存器地址
#define W25QX_WriteEnable 0x06
#define W25QX_WriteDisable 0x04
#define W25QX_ReadStatusReg 0x05
#define W25QX_WriteStatusReg 0x01
#define W25QX_ReadData 0x03
#define W25QX_FastReadData 0x0B
#define W25QX_FastReadDual 0x3B
#define W25QX_PageProgram 0x02
#define W25QX_BlockErase 0xD8
#define W25QX_SectorErase 0x20
#define W25QX_ChipErase 0xC7
#define W25QX_PowerDown 0xB9
#define W25QX_ReleasePowerDown 0xAB
#define W25QX_DeviceID 0xAB
#define W25QX_ManufactDeviceID 0x90
#define W25QX_JedecDeviceID 0x9F
/*!
* W25QXX初始化
* @param busName 总线名称
* @param devName 设备名称
* @param cs_gpiox 片选GPIO
* @param cs_gpio_pin 片选PIN
* @return 初始化状态
*/
bool w25qxxInit(char *busName, char *devName, GPIO_TypeDef* cs_gpiox, uint16_t cs_gpio_pin);
/*!
* 读取制造商ID
* @return 制造商ID
*/
uint16_t w25qxxReadID(void);
/*!
* 读取状态寄存器
* @return 状态
*/
uint8_t w25qxxReadSR(void);
/*!
* 写使能
*/
void w25qxxWriteEnable(void);
/*!
* 写禁止
*/
void w25qxxWriteDisable(void);
/*!
* 忙碌等待
*/
void w25qxxWaitBusy(void);
/*!
* 读取数据
* @param addr 地址
* @param data 缓冲区
* @param bytes 字节数
*/
void w25qxxRead(uint32_t addr, void* data, uint16_t bytes);
/*!
* 页写-最大256字节
* @param addr 地址
* @param data 缓冲区
* @param bytes 字节数
*/
void w25qxxWritePage(uint32_t addr, void* data, uint16_t bytes);
/*!
* 跨页写
* @param addr 地址
* @param data 缓冲区
* @param bytes 字节数
*/
void w25qxxWrite(uint32_t addr, void* data, uint16_t bytes);
/*!
* 擦除扇区
* @param addr 地址
*/
void w25qxxEraseSector(uint32_t addr);
/*!
* 全片擦除
*/
void w25qxxEraseChip();
w25qxx.c
#include "w25qxx.h"
#include <rtthread.h>
#include <rtdevice.h>
#include "drv_spi.h"
static struct rt_spi_device *devW25q;
bool w25qxxInit(char *busName, char *devName, GPIO_TypeDef* cs_gpiox, uint16_t cs_gpio_pin)
{
// ---------------------------注册SPI总线设备
rt_hw_spi_device_attach(busName, devName, cs_gpiox, cs_gpio_pin);
// 查找设备
devW25q = (struct rt_spi_device *)rt_device_find(devName);
if (devW25q == RT_NULL) {
rt_kprintf("rt_device_find[%s] failed!\n", devName);
return false;
}
// 配置SPI参数
struct rt_spi_configuration cfg;
cfg.data_width = 8;
cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_3 | RT_SPI_MSB;
cfg.max_hz = 18 * 1000 *1000;
rt_spi_configure(devW25q, &cfg);
// ---------------------------读取制造商ID
if(w25qxxReadID() != W25QX_ID) {
rt_kprintf("w25qxx read id failed!\n");
return false;
}
return true;
}
uint16_t w25qxxReadID(void)
{
uint8_t cmd = W25QX_ManufactDeviceID;
uint8_t id[5] = {0};
rt_spi_send_then_recv(devW25q, &cmd, 1, id, 5);
return id[3] << 8 | id[4];
}
uint8_t w25qxxReadSR(void)
{
uint8_t cmd = W25QX_ReadStatusReg;
uint8_t sr = 0;
rt_spi_send_then_recv(devW25q, &cmd, 1, &sr, 1);
return sr;
}
void w25qxxWriteEnable(void)
{
uint8_t cmd = W25QX_WriteEnable;
rt_spi_send(devW25q, &cmd, 1);
}
void w25qxxWriteDisable(void)
{
uint8_t cmd = W25QX_WriteDisable;
rt_spi_send(devW25q, &cmd, 1);
}
void w25qxxWaitBusy(void)
{
while((w25qxxReadSR()&0x01) == 0x01);
}
void w25qxxRead(uint32_t addr, void* data, uint16_t bytes)
{
uint32_t cmd = (W25QX_ReadData)|(addr<<8);
rt_spi_send_then_recv(devW25q, &cmd, 4, data, bytes);
}
void w25qxxWritePage(uint32_t addr, void* data, uint16_t bytes)
{
w25qxxWriteEnable();
uint32_t cmd = (W25QX_PageProgram)|(addr<<8);
rt_spi_send_then_send(devW25q, &cmd, 4, data, bytes);
w25qxxWaitBusy();
}
void w25qxxWrite(uint32_t addr, void* data, uint16_t bytes)
{
// 数据缓冲区操作指针
uint8_t *ptr = data;
// 页空间剩余字节
uint16_t pageByte;
while(bytes) {
// 计算页空间剩余字节 - 每页256byte
pageByte = 256-addr%256;
if(bytes > pageByte) {
// 待写入字节大于页空间剩余字节 - 分包写入
w25qxxWritePage(addr, ptr, pageByte);
ptr += pageByte;
addr += pageByte;
bytes -= pageByte;
} else if(bytes <= pageByte) {
// 待写入字节小于页空间剩余字节 - 一次性写入
w25qxxWritePage(addr, ptr, bytes);
ptr += bytes;
addr += bytes;
bytes -= bytes;
}
}
}
void w25qxxEraseSector(uint32_t addr)
{
// 计算扇区索引
addr /= 4096;
// 根据索引计算扇区起始地址
addr *= 4096;
w25qxxWriteEnable();
w25qxxWaitBusy();
uint32_t cmd = (W25QX_SectorErase)|(addr<<8);
rt_spi_send(devW25q, &cmd, 4);
w25qxxWaitBusy();
}
void w25qxxEraseChip()
{
w25qxxWriteEnable();
uint8_t cmd = W25QX_ChipErase;
rt_spi_send(devW25q, &cmd, 1);
w25qxxWaitBusy();
}
// FLASH读写测试
#define spiFlashWRTestSize 260
int spiFlashWRTest(void)
{
w25qxxEraseSector(0x2000);
uint8_t testWrite[spiFlashWRTestSize] = {0};
for(int i = 0;i < spiFlashWRTestSize;i++) {
testWrite = i+1;
}
w25qxxWrite(0x2000, testWrite, spiFlashWRTestSize);
uint8_t testRead[spiFlashWRTestSize] = {0};
w25qxxRead(0x2000, testRead, spiFlashWRTestSize);
for(int i = 0;i < spiFlashWRTestSize;i++) {
rt_kprintf("read test[%d]: %d\n", i, testRead);
}
return 0;
}
MSH_CMD_EXPORT(spiFlashWRTest, spiFlashWRTest);
// FLASH全片擦除测试
MSH_CMD_EXPORT(w25qxxEraseChip, spiFlashEraseChip);
使用示例:
w25qxxInit("spi2", "w2qx", GPIOB, GPIO_PIN_12);
2、SFUD/FAL
SFUD(全称 Serial Flash Universal Driver)是一款开源的串行 SPI Flash 通用驱动库;
FAL:Flash 抽象层。
使能组件:
修改board.h:
#define BSP_USING_ON_CHIP_FLASH
#define BSP_USING_SPI2
添加fal_config:
// 修改fal_cfg.h:
/*******************************************
* File: fal_cfg.h
* Describe: FAL_FLASH分区表
* Author: Xiangfu DING
* Time: 2025-02-10
*******************************************/
#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_
#include <rtconfig.h>
#include <board.h>
#ifndef FAL_USING_NOR_FLASH_DEV_NAME
#define NOR_FLASH_DEV_NAME "norflash0"
#else
#define NOR_FLASH_DEV_NAME FAL_USING_NOR_FLASH_DEV_NAME
#endif
// STM32F407VGT6 - 内部 Flash 大小为 1024KB(分为 4 个 16KB 扇区、1 个 64KB 扇区、7 个 128KB 扇区)
#define FLASH_SIZE_GRANULARITY_16K (4 * 16 * 1024)
#define FLASH_SIZE_GRANULARITY_64K (64 * 1024)
#define FLASH_SIZE_GRANULARITY_128K (7 * 128 * 1024)
#define STM32_FLASH_START_ADRESS_16K STM32_FLASH_START_ADRESS
#define STM32_FLASH_START_ADRESS_64K (STM32_FLASH_START_ADRESS_16K + FLASH_SIZE_GRANULARITY_16K)
#define STM32_FLASH_START_ADRESS_128K (STM32_FLASH_START_ADRESS_64K + FLASH_SIZE_GRANULARITY_64K)
/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev stm32_onchip_flash_16k;
extern const struct fal_flash_dev stm32_onchip_flash_64k;
extern const struct fal_flash_dev stm32_onchip_flash_128k;
/* ===================== Flash device Configuration ========================= */
extern struct fal_flash_dev nor_flash0;
/* flash device table */
#define FAL_FLASH_DEV_TABLE \
{ \
&stm32_onchip_flash_16k, \
&stm32_onchip_flash_64k, \
&stm32_onchip_flash_128k, \
&nor_flash0, \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WROD, "app", "onchip_flash", 0 * 1024, 512 * 1024, 0}, \
{FAL_PART_MAGIC_WROD, "download", NOR_FLASH_DEV_NAME, 0 * 1024, 512 * 1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */
#endif /* _FAL_CFG_H_ */
// 初始化
#include "fal.h"
int main(void)
{
// 初始化W25Q64
rt_hw_spi_device_attach("spi2", "spi20", GPIOB, GPIO_PIN_12);
//flash名称要正确
if (RT_NULL == rt_sfud_flash_probe("W25Q64", "spi20")) {
rt_kprintf("rt_sfud_flash_probe failed!\n");
}
// 初始化FAL
fal_init();
... ...
二、FM24CLxx(FRAM)
IIC通信,FM24CLxx(铁电随机存取存储器(FRAM))系列存储容量范围从4 Kbit到1 Mbit不等,型号/存储容量:
FM24CL04B:4 Kbit (512字节)
FM24CL16B:16 Kbit(2 KB)
FM24CL64B:64 Kbit(8 KB)
FM24CL128B:128 Kbit(16 KB)
FM24CL256B:256 Kbit(32 KB)
FM24CL512B:512 Kbit(64 KB)
FM24CL512L:512 Kbit(64 KB)
FM24CL01B:1 Mbit(128 KB)
FM24CL04是一种4Kb的F-RAM(Ferroelectric Random Access Memory),在FM24CL04中,每个字节的地址被表示为一个8位字节地址;
与EEPROM或Flash不同,F-RAM的地址不需要跨页,这意味着可以直接在单个页面(或单个字节)内进行读写操作,而无需担心页边界问题,因此,在FM24CL04中,可以按任意顺序访问和修改存储的数据,而不需要进行复杂的加载和存储算法;
FM24CL04的地址不需要跨页,可以直接访问和操作存储器中的任何地址。
fm24clxx.h
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <drv_common.h>
void fm24clxxInit(rt_base_t pinScl, rt_base_t pinSda);
void fm24clxxWrite(uint16_t addr, void *data, uint16_t length);
void fm24clxxRead(uint16_t addr, void *data, uint16_t length);
fm24clxx.c
#include "fm24clxx.h"
#include "drv_bus_i2c.h"
#define FM24CLXX_ADDR 0xA0
static iicPort_t iicPort;
void fm24clxxInit(rt_base_t pinScl, rt_base_t pinSda)
{
iicPort.pinScl = pinScl;
iicPort.pinSda = pinSda;
iicInit(&iicPort);
}
static void fm24clxxWriteBytes(uint16_t addr, void *data, uint16_t length)
{
uint8_t *buffer = data;
iicStart(&iicPort);
iicSendByte(&iicPort, FM24CLXX_ADDR|(addr&0x0100)>>7);
iicSendByte(&iicPort, (uint8_t)addr&0xFF);
while(length--) {
iicSendByte(&iicPort, *buffer++);
}
iicStop(&iicPort);
}
void fm24clxxWrite(uint16_t addr, void *data, uint16_t length)
{
uint8_t *w_buff = data;
while(length) {
uint16_t free_byte = (256-addr%256);
if(free_byte < length) {
fm24clxxWriteBytes(addr, w_buff, free_byte);
length -= free_byte;
addr += free_byte;
w_buff += free_byte;
} else {
fm24clxxWriteBytes(addr, w_buff, length);
length -= length;
}
}
}
static void fm24clxxReadBytes(uint16_t addr,void *data, uint8_t length)
{
uint8_t *buffer = data;
iicStart(&iicPort);
iicSendByte(&iicPort, FM24CLXX_ADDR|(addr&0x0100)>>7);
iicSendByte(&iicPort, addr&0xFF);
iicStop(&iicPort);
iicStart(&iicPort);
iicSendByte(&iicPort, FM24CLXX_ADDR|(addr&0x0100)>>7|0x01);
length--;
while(length--) {
*buffer++ = iicReadByte(&iicPort, true);
}
*buffer = iicReadByte(&iicPort, false);
iicStop(&iicPort);
}
void fm24clxxRead(uint16_t addr, void *data, uint16_t length)
{
uint8_t *r_buff = data;
while(length) {
uint16_t free_byte = (256-addr%256);
if(free_byte < length) {
fm24clxxReadBytes(addr, r_buff, free_byte);
length -= free_byte;
addr += free_byte;
r_buff += free_byte;
} else {
fm24clxxReadBytes(addr, r_buff, length);
length -= length;
}
}
}
// FRAM读写测试
int iicFramWRTest(void)
{
uint8_t data[20] = {0};
for(int i = 0;i < sizeof(data);i++) {
data = i;
}
fm24clxxWrite(0x10, &data, sizeof(data));
memset(data, 0x00 , sizeof(data));
fm24clxxRead(0x10, &data, sizeof(data));
for(int i = 0;i < sizeof(data);i++) {
rt_kprintf("read test[%d]: %d\n", i, data);
}
return 0;
}
MSH_CMD_EXPORT(iicFramWRTest, iicFramWRTest);
三、SDCARD
1、SPI SD
使用前提:配置好对应的SPI总线。
打开SPI SD/TF卡驱动程序:
使用设备虚拟文件系统:
注册SPI SD设备:
#include "spisd.h"
#include <rtdevice.h>
#include <dfs_fs.h>
#include "drv_spi.h"
#include "spi_msd.h"
static rt_base_t sdinsertPin;
static char *spisdDevName = NULL;
int spisdPreInit(char *busName, char *devName,
GPIO_TypeDef* cs_gpiox, uint16_t cs_gpio_pin, rt_base_t insert_pin)
{
spisdDevName = devName;
rt_hw_spi_device_attach(busName, devName, cs_gpiox, cs_gpio_pin);
sdinsertPin = insert_pin;
return 0;
}
int spisdInit()
{
return msd_init(SD_DEVICE_NAME, spisdDevName);
}
int spisdDeInit()
{
return msd_deinit();
}
bool spisdInsertStatus()
{
uint8_t status = rt_pin_read(sdinsertPin);
if(status == PIN_LOW) return true;
else return false;
}
修改rt-thread\components\drivers\spi\spi_msd.c/h(增加函数):
rt_err_t msd_deinit()
{
return rt_device_unregister(&_msd_device.parent);
}
extern rt_err_t msd_deinit();
热插拔SD卡及文件系统挂载/卸载:
static rt_thread_t thread_Fatfs = RT_NULL;
static void threadEntry_Fatfs(void *parameter)
{
bool sdInsert = false;
bool dfsStatus = false;
while (1) {
sdInsert = spisdInsertStatus();
if(sdInsert) {
// 文件系统挂载
if (!dfsStatus) {
spisdInit();
if(dfs_mount("sd0", "/", "elm", 0, 0) == 0) {
rt_kprintf("Fat filesystem mount ok.\n");
dfsStatus = true;
beeper(BEEPER_SHORT);
} else {
rt_kprintf("Fat filesystem mount failed!\n");
dfsStatus = false;
}
}
} else {
// 文件系统卸载
if (dfsStatus) {
if (dfs_unmount("/")) {
rt_kprintf("Fat filesystem umount failed!\n");
} else {
rt_kprintf("Fat filesystem umount ok.\n");
beeper(BEEPER_SHORT);
}
spisdDeInit();
dfsStatus = false;
}
}
rt_thread_mdelay(100);
}
}
// 其他文件系统操作参考SDIO
2、SDIO SD
参考STM32片上驱动 - SDIO驱动。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/dxf1971738522/article/details/146060793
|
|