MM32F3273G8P火龙果开发板MindSDK开发教程18 -sfud库的移植

news2025/2/12 22:08:08

MM32F3273G8P火龙果开发板MindSDK开发教程18 -sfud库的移植

1、sfud简介

SFUD (Serial Flash Universal Driver) 串行 Flash 通用驱动库
推荐查看官方文档:一款使用 JEDEC SFDP 标准的串行 (SPI) Flash 通用驱动库

2、实验设备

主控:MM32F3273G8P火龙果开发板
spi flash : W25Q32
使用SPI2。(PB12 PB13 PB14 PB15)

3、SPI初始化

在移植sfud之前,我们先初始化spi2,用读取函数,读取一下w25q32的manufacturer_id值,如果能正常读取,说明我们的设备没有问题,spi初始化也正常,然后再来移植sfud库。
初始化gpio的函数如下:
CS采用软件控制的方式,读写之前拉低,读写结束拉高。

static bool SPI_GpioConfig(void)
{
    /* gpio. */
    GPIO_Init_Type gpio_init;
    /* PB12 - SPI_CS. */
    gpio_init.Pins  = GPIO_PIN_12;
    gpio_init.PinMode  = GPIO_PinMode_Out_PushPull;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &gpio_init);
    GPIO_PinAFConf(GPIOB, gpio_init.Pins, GPIO_AF_15);
    GPIO_SetBits(GPIOB, gpio_init.Pins);

    /* PB13 - SPI_SCK. */
    gpio_init.Pins  = GPIO_PIN_13;
    gpio_init.PinMode  = GPIO_PinMode_AF_PushPull;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &gpio_init);
    GPIO_PinAFConf(GPIOB, gpio_init.Pins, GPIO_AF_5);

    /* PB14 - SPI_MISO. */
    gpio_init.Pins  = GPIO_PIN_14;
    gpio_init.PinMode  = GPIO_PinMode_In_PullUp;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &gpio_init);
    GPIO_PinAFConf(GPIOB, gpio_init.Pins, GPIO_AF_5);

    /* PB15 - SPI_MOSI. */
    gpio_init.Pins  = GPIO_PIN_15;
    gpio_init.PinMode  = GPIO_PinMode_AF_PushPull;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &gpio_init);
    GPIO_PinAFConf(GPIOB, gpio_init.Pins, GPIO_AF_5);
    return true;
}

SPI初始化函数:

bool SPI_Config(void)
{
    SPI_GpioConfig();
    /* Setup SPI module. */
    SPI_Master_Init_Type spi_init;
    spi_init.ClockFreqHz = CLOCK_APB1_FREQ;
    spi_init.BaudRate = 400000u;
    spi_init.XferMode = SPI_XferMode_TxRx;
    spi_init.PolPha = SPI_PolPha_Alt1;
    spi_init.DataWidth = SPI_DataWidth_8b;
    spi_init.LSB = false;
    spi_init.AutoCS = true;
    SPI_InitMaster(SPI2, &spi_init);

    /* Enable SPI. */
    SPI_Enable(SPI2, true);
    return true;
}

注意SPI_PolPha_Alt1其实就是spi mode0,这里的定义怪怪的。

spi时钟初始化:

/* GPIOB. */
RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOB, true);
RCC_ResetAHB1Periphs(RCC_AHB1_PERIPH_GPIOB);

/* SPI2. */
RCC_EnableAPB1Periphs(RCC_APB1_PERIPH_SPI2, true);
RCC_ResetAPB1Periphs(RCC_APB1_PERIPH_SPI2);

读取函数:(写入一个读取一个)

static void SPI_WriteReadOnebyte(uint8_t w_data,uint8_t *r_data)
{
    while ( SPI_STATUS_TX_FULL & SPI_GetStatus(SPI2) )
    {}
    SPI_PutData(SPI2, w_data);
    while (0u == (SPI_STATUS_RX_DONE & SPI_GetStatus(SPI2)) )
    {}
    *r_data =  SPI_GetData(SPI2);
}

void SPI_WriteReadData(uint8_t *w_data,uint8_t *r_data,int len)
{
    GPIO_WriteBit(GPIOB,GPIO_PIN_12,0);
    while (len)
    {
        SPI_WriteReadOnebyte(*w_data++,r_data++);
        len--;
    }
    GPIO_WriteBit(GPIOB,GPIO_PIN_12,1);
}

读取 manufacturer_id函数

#define CMD_JEDEC_ID          0x9f
#define CMD_MANUFACURER_ID    0x90

static void w25q32_read_manufacturer_id(uint16_t *id)
{
    uint8_t tx_data[6] = {CMD_MANUFACURER_ID ,0,0,0,0,0};
    uint8_t rx_data[6] = {0};
    SPI_WriteReadData(tx_data,rx_data,6);
	*id = (rx_data[4]<<8)|rx_data[5];
}


static void w25q32_read_jedec_id(uint16_t *id)
{
    uint8_t tx_data[4] = {CMD_JEDEC_ID ,0,0,0};
    uint8_t rx_data[4] = {0};
    SPI_WriteReadData(tx_data,rx_data,4);
	*id = (rx_data[2]<<8)|rx_data[3];
}

void SPI_Test(void)
{
    uint16_t id = 0;
    SPI_Config();
    w25q32_read_manufacturer_id(&id);
    printf("get manufacturer id == 0x%04x\r\n",id);
    w25q32_read_jedec_id(&id);
    printf("get jedec id == 0x%04x\r\n",id);
}

调用SPI_Test函数后,打印如下:
在这里插入图片描述
说明spi2已经正常工作,w25q32也正常,接下来我们来移植sfud库。

4、sfud移植

下载加压后,将sfud中的文件copy到工程中。
因为w25q32是在支持列表中的,我们要修改的其实就两个文件,一个是sfud_cfg.h,另一个为sfud_port.c
文件目录结构如图:
在这里插入图片描述

sfud_cfg.h的修改如下:

#ifndef _SFUD_CFG_H_
#define _SFUD_CFG_H_

//#define SFUD_DEBUG_MODE

#define SFUD_USING_SFDP

#define SFUD_USING_FLASH_INFO_TABLE

enum {
    SFUD_SPI_DEVICE_INDEX = 0,
};

#define SFUD_FLASH_DEVICE_TABLE \
{ \
    [SFUD_SPI_DEVICE_INDEX] = {.name = "W25Q32", .spi.name = "SPI2"}, \
}

#endif /* _SFUD_CFG_H_ */

sfud_port.c的修改

static uint8_t spi_xfer(const uint8_t value)函数修改成自己平台的读写函数。

mm32平台修改如下:

static uint8_t spi_xfer(const uint8_t value)
{
    while(0 == (SPI_GetStatus(SPI2) & SPI_STATUS_TX_EMPTY) )
    {}
    SPI_PutData(SPI2, value);

    while(0 == (SPI_GetStatus(SPI2) & SPI_STATUS_RX_DONE) )
    {}
    return SPI_GetData(SPI2);
}

static void spi_cs_control(bool enable)函数,修改成自己平台控制gpio的函数。mm平台修改如下:

/* control the cs pin output. */
static void spi_cs_control(bool enable)
{
    if (true == enable)
    {
        GPIO_ClearBits(GPIOB, GPIO_PIN_12);
    }
    else
    {
        GPIO_SetBits(GPIOB, GPIO_PIN_12);
    }
}

sfud_err sfud_spi_port_init(sfud_flash *flash)函数添加spi2的初始化函数。这里添加之前我们定义的 SPI_Config()函数即可。

sfud_err sfud_spi_port_init(sfud_flash *flash)
{
    sfud_err result = SFUD_SUCCESS;
    SPI_Config();

    /* init sfud spi obj. */
    flash->spi.wr           = spi_write_read;
    flash->spi.lock         = spi_lock;
    flash->spi.unlock       = spi_unlock;
    flash->spi.user_data    = NULL;
    flash->retry.delay      = retry_delay_100us;
    flash->retry.times      = 60u * 10000u;

    return result;
}

5、sfud的使用

调用官方的demo

static void sfud_demo(uint32_t addr, size_t size, uint8_t *data)
{
    sfud_err result = SFUD_SUCCESS;
    const sfud_flash *flash = sfud_get_device_table() + 0;
    size_t i;
    /* prepare write data */
    for (i = 0; i < size; i++)
    {
        data[i] = i;
    }
    /* erase test */
    result = sfud_erase(flash, addr, size);
    if (result == SFUD_SUCCESS)
    {
        printf("Erase the %s flash data finish. Start from 0x%08X, size is %ld.\r\n", flash->name, addr,
                       size);
    }
    else
    {
        printf("Erase the %s flash data failed.\r\n", flash->name);
        return;
    }
    /* write test */
    result = sfud_write(flash, addr, size, data);
    if (result == SFUD_SUCCESS)
    {
        printf("Write the %s flash data finish. Start from 0x%08X, size is %ld.\r\n", flash->name, addr,
                       size);
    }
    else
    {
        printf("Write the %s flash data failed.\r\n", flash->name);
        return;
    }
    /* read test */
    result = sfud_read(flash, addr, size, data);
    if (result == SFUD_SUCCESS)
    {
        printf("Read the %s flash data success. Start from 0x%08X, size is %ld. The data is:\r\n", flash->name, addr,
                       size);
        printf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\r\n");
        for (i = 0; i < size; i++)
        {
			if (i % 16 == 0)
			{
                printf("[%08X] ", addr + i);
            }
            printf("%02X ", data[i]);
            if (((i + 1) % 16 == 0) || i == size - 1)
            {
                printf("\r\n");
            }
        }
        printf("\r\n");
    }
    else
    {
        printf("Read the %s flash data failed.\r\n", flash->name);
    }
    /* data check */
    for (i = 0; i < size; i++)
    {
        if (data[i] != i % 256)
        {
            printf("Read and check write data has an error. Write the %s flash data failed.\r\n", flash->name);
                    break;
        }
    }
    if (i == size)
    {
        printf("The %s flash test is success.\r\n", flash->name);
    }
}

main函数调用:

static uint8_t data [256] = {0};

int main(void)
{
	BOARD_InitBootClocks();  // ³õʼ»¯Ê±ÖÓ
	BOARD_InitDebugConsole();
	BOARD_UserKeyInit();
	LED_Init();
	BOARD_TIM6_Init();

	// for mutilbutton init
	button_init(&btn1, read_button_GPIO, 0, btn1_id);
	button_attach(&btn1, PRESS_DOWN,       BTN1_PRESS_DOWN_Handler);
	button_attach(&btn1, PRESS_UP,         BTN1_PRESS_UP_Handler);
	button_start(&btn1);

	BOARD_TIM7_Init();

	BOARD_Delay1Ms(1000);
	
	printf("Board Init Success\r\n");

	sfud_init();
	sfud_demo(0,256,data);
	while(1)
	{
	}	
}

6、现象

烧录后打印如下:
在这里插入图片描述

7、代码

代码下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/645656.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Matlab与ROS---深度学习(九)

0. 简介 在了解完上面8讲内容后&#xff0c;基本上ROS和Matlab最关键的部分已经介绍完毕。我们最后一讲就来简单的讲述一下如何在Matlab中结合ROS来完成障碍物的识别与检测。 1. 在Matlab中使用CUDA 配置SimulinkCoder以从Simulink模型生成和构建的CUDA的ROS节点是我们这一小…

如何选择接口测试工具?

目录 前言&#xff1a; 一、易用性 二、灵活性 三、可靠性 四、成本 如何正确选择接口测试工具 测试用例 接口测试数据 自动化测试 测试报告 总结 前言&#xff1a; 接口测试是一种重要的测试类型&#xff0c;常用于Web应用程序和服务的测试。选择一个合适的接口测…

一分钟了解物联存储柜的特点和功能

物联存储柜是一种智能存储柜&#xff0c;具有多种传感器和通信技术&#xff0c;集成物联网和云计算技术&#xff0c;通过自动化、智能化、网络化将传统存储柜与智能设备相结合&#xff0c;自动识别、存取物品&#xff0c;通过网络进行数据交互&#xff0c;实现远程监测和管理功…

矿业变革进行中,北斗技术赋能智慧矿山

近年来&#xff0c;在国家政策支持和技术创新驱动下&#xff0c;国内矿山一直致力于向智能化、数字化方向发展&#xff0c;智慧矿山建设正在加速推进中。 我国自主研发的北斗导航系统&#xff0c;不断与千行百业融合&#xff0c;广泛应用于生产生活的各个领域。“北斗矿业”也成…

怎么自学网安?过程中遇到问题怎么解决

趁着今天下班&#xff0c;我花了几个小时整理了下&#xff0c;非常不易&#xff0c;希望大家可以点赞收藏支持一波&#xff0c;谢谢。 我的经历&#xff1a; 我 19 年毕业&#xff0c;大学专业是物联网工程&#xff0c;我相信很多人在象牙塔里都很迷茫&#xff0c;到了大三大…

JavaScript数学对象-数字进制转换

关注“大前端私房菜”微信公众号&#xff0c;输入暗号【面试宝典】即可免费领取107页前端面试题。 什么是进制 进制就是达到指定位置时候进一位 常见的进制 十进制: 0 1 2 3 4 5 6 7 8 9 10 11 12 ... 99 100 101 二进制: 0 1 10 11 100 101 110 111 1000 八进制: 0 1 2 3 4 …

在thinkBook16的win11基础上安装ubuntu22.04

简介 背景&#xff1a;联想ThinkBook16 pro 32G/512G&#xff0c;系统盘已安装Win11&#xff0c;加装一条M.2-2T固态&#xff0c;想在2T上分一个300GB的EXT4分区&#xff0c;然后把ubuntu22.04安装在该分区上&#xff0c;并实现Win11Linux多系统共存。 目标&#xff1a;实现多…

【C++】STL基本介绍

目录 1、什么是STL 2、STL六大组件 2.1容器 2.2算法 2.3迭代器 1、什么是STL 概念: STL (standard template libaray - 标准模板库)&#xff1a;是 C 标准库的重要组成部分&#xff0c;不仅是一个可复用的组件库&#xff0c;而且是一个包罗数据结构与算法的软件框架。 …

重回游戏公平,向游戏打金工作室宣战!

什么是打金工作室&#xff1f; 近几年中国游戏市场持续发展&#xff0c;国产自研精品游戏层出不穷&#xff0c;游戏产业精品化、高质量健康发展趋势稳定。根据中国音数协游戏工委&#xff08;GPC&#xff09;与中国游戏产业研究院发布的《2022年中国游戏产业报告》显示&#xf…

总结2023开放原子全球开源峰会,中兴国产操作系统的开源贡献

近年来&#xff0c;随着信息技术的不断发展&#xff0c;催生出越来越多的智能场景&#xff0c;作为信息产业的底层技术&#xff0c;国产操作系统所面临的问题也变得越来越复杂。面对新技术和新场景对国产操作系统提出的新挑战、新要求&#xff0c;如何凝聚生态合作伙伴的优势力…

看了这几个C语言例子,你一定和我一样连说5个卧槽,声音一次比一次大

曾经我一直以为自己C语言学的还挺好的&#xff0c;直到看到这几个例子。 例1 首先来看一下&#xff0c;大师是如何求圆周率的&#xff0c;一口君实在词穷&#xff0c;first卧槽。 #include <stdio.h>long a10000,b0,c10000,d,e,f[10001],g;void main(){for(;b ! c; f[…

Rust 基础语法

Rust 基础语法 变量&#xff0c;基本类型&#xff0c;函数&#xff0c;注释和控制流&#xff0c;这些几乎是每种编程语言都具有的编程概念。 这些基础概念将存在于每个 Rust 程序中&#xff0c;及早学习它们将使你以最快的速度学习 Rust 的使用。 变量 首先必须说明&#x…

AIAgent来了!AutoGPT的新对手

AutoGPT 和 AgentGPT遇到了更强的对手&#xff0c;我来介绍一下 http://AIAgent.app 这个网站。 http://AIAgent.app 是一个可以让你使用人工智能代理来完成各种任务的网站。你只需要设置一个目标&#xff0c;然后选择一个合适的代理&#xff0c;它就会自动为你执行任务&#…

LED显示屏薄膜类型有哪些

LED显示屏薄膜是指应用在LED显示屏的薄膜材料&#xff0c;用于保护LED模块和增强显示效果。以下是LED显示屏薄膜知识的详细说明&#xff1a; 防护膜&#xff08;Protective Film&#xff09;&#xff1a;防护膜是一层透明的薄膜材料&#xff0c;常用于覆盖在LED显示屏的正面&am…

Android 手机自动化测试工具有哪几种?

文章大纲&#xff1a; 1、Android手机自动化测试工具&#xff0c;常用的有这7种 2、化繁为简&#xff0c;补充移动端自动化测试工具 3、这么多工具&#xff0c;工作中该如何选择 4、掌握自动化测试工具的学习建议 一、Android手机自动化测试工具&#xff0c;常用的有这7中&…

退休大厂软件测试面试官给大家的一些建议

最近因为又要增加用人&#xff0c;就又开始忙于招聘&#xff0c;一段时间下来遇到不少有趣的事情&#xff0c;结合之前的面试经验&#xff0c;就简单记录一下。 火眼金睛&#xff1a;识别真假 为什么一开始要说这个&#xff0c;因为最近确实遇到很多编造的简历&#xff0c;给…

如何选择到最合适的DDoS缓解服务?

DDoS缓解服务提供商的数量可能很多&#xff0c;但只有一些提供商提供高效服务的所有必要功能&#xff0c;因此如果要选择正确的 DDoS保护解决方案&#xff0c;必须考虑以下因素&#xff1a; 1.缩小风险范围 选择DDoS缓解服务的第一步&#xff0c;确定您组织的特定需求&#…

DDoS缓解的基本工作原理和关键功能

什么是DDoS缓解&#xff1f; DDoS 缓解是指成功保护目标服务器或网络以抵御分布式拒绝服务 (DDoS) 攻击的过程&#xff0c;目标受害者可以使用专门设计的网络设备或基于云的保护服务缓解传入的威胁。 为什么需要DDoS缓解解决方案&#xff1f; 由于网络构成的基本逻辑&#xf…

Virt-Mnager 虚拟机桥接网络

前言 以下针对linux 下 virt-manager 管理kvm虚拟机配置网络类型&#xff0c;默认为nat。 nat网络模式&#xff0c;虚拟机之间可通信&#xff0c;虚拟机和主机可通信&#xff0c;不可与主机外的网络通信&#xff1b; 桥接网络模式&#xff0c;虚拟机之间可通信&#xff0c;虚拟…

Bluez 的一些概念

目录 1&#xff0c;Linux 和蓝牙架构 2&#xff0c;D-Bus 相关概念 2.1 Message Buses 2.2 Client, Server and Connections 2.3 Object, Interface, Methods, Signals and Properties 2.3.1 Object, Interface, Methods 2.3.2 Signal 2.3.3 Properties 3&#xff0c;St…