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

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、代码

代码下载

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是MM32F3277G8P的FSMC配置代码,注释中对每行代码进行了详细解释说明: ```c #include "MM32F3277.h" void FSMC_NAND_Init(void) { // 使能FSMC时钟 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE); // 定义FSMC_NAND初始化结构体 FSMC_NANDInitTypeDef FSMC_NANDInitStructure; FSMC_NAND_PCCARDTimingInitTypeDef p; // 配置FSMC_NAND初始化结构体 p.FSMC_SetupTime = 0x1; p.FSMC_WaitSetupTime = 0x3; p.FSMC_HoldSetupTime = 0x2; p.FSMC_HiZSetupTime = 0x1; FSMC_NANDInitStructure.FSMC_Bank = FSMC_Bank2_NAND; FSMC_NANDInitStructure.FSMC_Waitfeature = FSMC_Waitfeature_Disable; FSMC_NANDInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_8b; FSMC_NANDInitStructure.FSMC_ECC = FSMC_ECC_Enable; FSMC_NANDInitStructure.FSMC_ECCPageSize = FSMC_ECCPageSize_256Bytes; FSMC_NANDInitStructure.FSMC_TCLRSetupTime = 0x00; FSMC_NANDInitStructure.FSMC_TARSetupTime = 0x00; FSMC_NANDInitStructure.FSMC_CommonSpaceTimingStruct = &p; FSMC_NANDInitStructure.FSMC_AttributeSpaceTimingStruct = &p; // 初始化FSMC_NAND FSMC_NANDInit(&FSMC_NANDInitStructure); // 使能FSMC_NAND FSMC_NANDCmd(FSMC_Bank2_NAND, ENABLE); } ``` 解释说明如下: 1. `RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);`:使能FSMC时钟,使得FSMC模块能够正常工作。 2. `FSMC_NANDInitTypeDef FSMC_NANDInitStructure;`:定义FSMC_NAND初始化结构体。 3. `FSMC_NAND_PCCARDTimingInitTypeDef p;`:定义FSMC_NAND_PCCARDTiming初始化结构体。 4. `p.FSMC_SetupTime = 0x1;`:设置NAND芯片的SETUP时间为1个HCLK周期。 5. `p.FSMC_WaitSetupTime = 0x3;`:设置NAND芯片的WAIT时间为3个HCLK周期。 6. `p.FSMC_HoldSetupTime = 0x2;`:设置NAND芯片的HOLD时间为2个HCLK周期。 7. `p.FSMC_HiZSetupTime = 0x1;`:设置NAND芯片的HiZ时间为1个HCLK周期。 8. `FSMC_NANDInitStructure.FSMC_Bank = FSMC_Bank2_NAND;`:设置FSMC_NAND初始化结构体的FSMC_Bank成员为FSMC_Bank2_NAND,表示使用FSMC Bank2来连接NAND Flash。 9. `FSMC_NANDInitStructure.FSMC_Waitfeature = FSMC_Waitfeature_Disable;`:设置FSMC_NAND初始化结构体的FSMC_Waitfeature成员为FSMC_Waitfeature_Disable,表示禁用FSMC的等待特性。 10. `FSMC_NANDInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_8b;`:设置FSMC_NAND初始化结构体的FSMC_MemoryDataWidth成员为FSMC_MemoryDataWidth_8b,表示使用8位数据总线。 11. `FSMC_NANDInitStructure.FSMC_ECC = FSMC_ECC_Enable;`:设置FSMC_NAND初始化结构体的FSMC_ECC成员为FSMC_ECC_Enable,表示启用ECC校验功能。 12. `FSMC_NANDInitStructure.FSMC_ECCPageSize = FSMC_ECCPageSize_256Bytes;`:设置FSMC_NAND初始化结构体的FSMC_ECCPageSize成员为FSMC_ECCPageSize_256Bytes,表示ECC校验的页面大小为256字节。 13. `FSMC_NANDInitStructure.FSMC_TCLRSetupTime = 0x00;`:设置FSMC_NAND初始化结构体的FSMC_TCLRSetupTime成员为0,表示不需要设置CLE到RE的延时。 14. `FSMC_NANDInitStructure.FSMC_TARSetupTime = 0x00;`:设置FSMC_NAND初始化结构体的FSMC_TARSetupTime成员为0,表示不需要设置ALE到RE的延时。 15. `FSMC_NANDInitStructure.FSMC_CommonSpaceTimingStruct = &p;`:设置FSMC_NAND初始化结构体的FSMC_CommonSpaceTimingStruct成员为&p,表示使用前面定义的FSMC_NAND_PCCARDTiming初始化结构体来配置FSMC的时序参数。 16. `FSMC_NANDInitStructure.FSMC_AttributeSpaceTimingStruct = &p;`:设置FSMC_NAND初始化结构体的FSMC_AttributeSpaceTimingStruct成员为&p,表示使用前面定义的FSMC_NAND_PCCARDTiming初始化结构体来配置FSMC的时序参数。 17. `FSMC_NANDInit(&FSMC_NANDInitStructure);`:通过FSMC_NAND初始化结构体来初始化FSMC_NAND。 18. `FSMC_NANDCmd(FSMC_Bank2_NAND, ENABLE);`:使能FSMC Bank2,使得NAND Flash能够正常读写。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值