这里已经假设SFUD代码已经移植到工程下面成功了,如果读者对SFUD移植还不了解。可以参考笔者这篇文章:SFUD (Serial Flash Universal Driver)之KEIL移植
这里主要介绍测试和应用
1 硬件设计
这里采用windbond 的W25Q32这款芯片用于SFUD测试。
W25Q32是一款由Winbond(温邦)公司生产的串行闪存器件,具有以下特点和规格:
容量: W25Q32的容量为32 Megabits(Mb),即4 Megabytes(MB)。
接口: 采用串行外围接口(SPI)进行通信,支持快速的串行数据传输。
工作电压: 标准的工作电压范围为2.7V至3.6V,也有一些版本支持低电压工作(1.65V至2.0V)。
速度: 支持不同的时钟速度,例如在单线SPI模式下,最高速度可达到104MHz。
擦除和编程: 支持扇区擦除和页编程操作,有多种擦除模式可选。
保护功能: 支持硬件数据保护功能,可以通过设置保护位来保护特定的存储区域。
W25Q32广泛应用于嵌入式系统中,如智能手机、数字相机、网络设备、工业控制系统等,用于存储固件、配置数据、日志记录等信息。它的高速度、可靠性和丰富的功能使其成为许多嵌入式系统中的理想选择。
主控芯片采用gd32f103系列芯片,远远满足固件移植的需要。 引脚对应的接口,用是SPI0接口。
2 驱动准备
2.1 硬件驱动移植
打开sfud_port.c 文件, 这里需要添加对应的驱动,添加硬件驱动代码
static void rcc_configuration(void) {
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_SPI0);
rcu_periph_clock_enable(RCU_AF);
}
static void gpio_configuration(void)
{
/* SPI0 GPIO config:SCK/PA5, MOSI/PA7, NSS/PA4 */
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4 | GPIO_PIN_5|GPIO_PIN_7);
/* SPI0 GPIO config: MISO/PA6*/
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
}
static void spi_configuration(void) {
spi_parameter_struct spi_init_struct;
/* deinitilize SPI and the parameters */
spi_i2s_deinit(SPI0);
spi_struct_para_init(&spi_init_struct);
/* configure SPI0 parameter */
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_init_struct.device_mode = SPI_MASTER;
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
spi_init_struct.nss = SPI_NSS_SOFT;
spi_init_struct.prescale = SPI_PSC_2; // 54MHz
spi_init_struct.endian = SPI_ENDIAN_MSB;
spi_init(SPI0, &spi_init_struct);
spi_nss_output_enable(SPI0);
spi_enable(SPI0);
}
static void spi_lock(void) {
__disable_irq();
}
static void spi_unlock(void) {
__enable_irq();
}
2.1.1 添加初始化代码
在以下的地方添加初始化代码:
/* about 100 microsecond delay */
static void retry_delay_100us(void) {
uint32_t delay = 120;
while(delay--);
}
sfud_err sfud_spi_port_init(sfud_flash *flash) {
sfud_err result = SFUD_SUCCESS;
* add your port spi bus and device object initialize code like this:
* 1. rcc initialize
* 2. gpio initialize
* 3. spi device initialize
* 4. flash->spi and flash->retry item initialize
* flash->spi.wr = spi_write_read; //Required
* flash->spi.qspi_read = qspi_read; //Required when QSPI mode enable
* flash->spi.lock = spi_lock;
* flash->spi.unlock = spi_unlock;
* flash->spi.user_data = &spix;
* flash->retry.delay = null;
* flash->retry.times = 10000; //Required
*/
```c
switch (flash->index) {
case SFUD_XXXX_DEVICE_INDEX: {
/* RCC 初始化 */
rcc_configuration();
/* GPIO 初始化 */
gpio_configuration();
/* SPI 外设初始化 */
spi_configuration();
/* 同步 Flash 移植所需的接口及数据 */
flash->spi.wr = spi_write_read;
flash->spi.lock = spi_lock;
flash->spi.unlock = spi_unlock;
//flash->spi.user_data = &spi1;
/* about 100 microsecond delay */
flash->retry.delay = retry_delay_100us;
/* adout 60 seconds timeout */
flash->retry.times = 60 * 10000;
break;
}
return result;
}
2.1.2 添加读写代码
2.2 软件驱动准备
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);
}