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
文件目录结构如图:
MM32F3273G8P火龙果开发板MindSDK开发教程18 -sfud库的移植_第1张图片

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、现象

烧录后打印如下:
MM32F3273G8P火龙果开发板MindSDK开发教程18 -sfud库的移植_第2张图片

7、代码

代码下载

你可能感兴趣的:(火龙果MM32F3273G8P,单片机,物联网,嵌入式硬件)