初级会员

- 积分
- 73
- 金钱
- 73
- 注册时间
- 2017-10-25
- 在线时间
- 12 小时
|
GD32H737通过ospi方式与w25n01通信,读写flash过程中发现写入7块0页0列一串数,读3块0页/15块0页...的数据均为写入3块0页0列的数(3块0页/15块0页之前读出来的数据肯定不是目前数据),现在可以确定flash读取函数中数据位置肯定不对,但不清楚写入的时候是否也是将数据写在3块0页,而非7块0页。
ospi方式连接w25n01如图
```
/* 配置使用的OSPIM引脚
OSPIM_P0_SCK(PB2)
OSPIM_P0_CSN(PC11)
OSPIM_P0_IO0(PD11)
OSPIM_P0_IO1(PD12)
OSPIM_P0_IO2(PB13)
OSPIM_P0_IO3(PD13) */
```
初始化函数如下
```
void ospi_flash_init()
{
/* reset the OSPI and OSPIM peripheral */
ospi_deinit(OSPI0); /* 复位OSPI */
ospim_deinit(); /* 复位OSPIM */
/* enable OSPIM and GPIO clock */
rcu_periph_clock_enable(RCU_OSPI0); /* 使能OSPIM时钟 */
rcu_periph_clock_enable(OSPIM_PX_SCK_GPIO_CLK); /* 使能OSPIM_PX_SCK IO口时钟 */
rcu_periph_clock_enable(OSPIM_PX_CSN_GPIO_CLK); /* 使能OSPIM_PX_CSN IO口时钟 */
rcu_periph_clock_enable(OSPIM_PX_IO0_GPIO_CLK); /* 使能OSPIM_PX_IO0 IO口时钟 */
rcu_periph_clock_enable(OSPIM_PX_IO1_GPIO_CLK); /* 使能OSPIM_PX_IO1 IO口时钟 */
rcu_periph_clock_enable(OSPIM_PX_IO2_GPIO_CLK); /* 使能OSPIM_PX_IO2 IO口时钟 */
rcu_periph_clock_enable(OSPIM_PX_IO3_GPIO_CLK); /* 使能OSPIM_PX_IO3 IO口时钟 */
/* 配置OSPIM引脚的复用功能 */
gpio_af_set(OSPIM_PX_SCK_GPIO_PORT, OSPIM_PX_SCK_GPIO_AF, OSPIM_PX_SCK_GPIO_PIN);
gpio_af_set(OSPIM_PX_CSN_GPIO_PORT, OSPIM_PX_CSN_GPIO_AF, OSPIM_PX_CSN_GPIO_PIN);
gpio_af_set(OSPIM_PX_IO0_GPIO_PORT, OSPIM_PX_IO0_GPIO_AF, OSPIM_PX_IO0_GPIO_PIN);
gpio_af_set(OSPIM_PX_IO1_GPIO_PORT, OSPIM_PX_IO1_GPIO_AF, OSPIM_PX_IO1_GPIO_PIN);
gpio_af_set(OSPIM_PX_IO2_GPIO_PORT, OSPIM_PX_IO2_GPIO_AF, OSPIM_PX_IO2_GPIO_PIN);
gpio_af_set(OSPIM_PX_IO3_GPIO_PORT, OSPIM_PX_IO3_GPIO_AF, OSPIM_PX_IO3_GPIO_PIN);
/* OSPIM_PX_SCK引脚模式设置 */
gpio_mode_set(OSPIM_PX_SCK_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, OSPIM_PX_SCK_GPIO_PIN);
gpio_output_options_set(OSPIM_PX_SCK_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, OSPIM_PX_SCK_GPIO_PIN);
/* OSPIM_PX_CSN引脚模式设置 */
gpio_mode_set(OSPIM_PX_CSN_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, OSPIM_PX_CSN_GPIO_PIN);
gpio_output_options_set(OSPIM_PX_CSN_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, OSPIM_PX_CSN_GPIO_PIN);
/* OSPIM_PX_IO0引脚模式设置 */
gpio_mode_set(OSPIM_PX_IO0_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, OSPIM_PX_IO0_GPIO_PIN);
gpio_output_options_set(OSPIM_PX_IO0_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, OSPIM_PX_IO0_GPIO_PIN);
/* OSPIM_PX_IO1引脚模式设置 */
gpio_mode_set(OSPIM_PX_IO1_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, OSPIM_PX_IO1_GPIO_PIN);
gpio_output_options_set(OSPIM_PX_IO1_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, OSPIM_PX_IO1_GPIO_PIN);
/* OSPIM_PX_IO2引脚模式设置 */
gpio_mode_set(OSPIM_PX_IO2_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, OSPIM_PX_IO2_GPIO_PIN);
gpio_output_options_set(OSPIM_PX_IO2_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, OSPIM_PX_IO2_GPIO_PIN);
/* OSPIM_PX_IO3引脚模式设置 */
gpio_mode_set(OSPIM_PX_IO3_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, OSPIM_PX_IO3_GPIO_PIN);
gpio_output_options_set(OSPIM_PX_IO3_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, OSPIM_PX_IO3_GPIO_PIN);
ospim_port_sck_config(OSPIM_PORT0, OSPIM_PORT_SCK_ENABLE); /* 使能OSPIM端口0的SCK */
ospim_port_csn_config(OSPIM_PORT0, OSPIM_PORT_CSN_ENABLE); /* 使能OSPIM端口0的CSN */
ospim_port_io3_0_config(OSPIM_PORT0, OSPIM_IO_LOW_ENABLE); /* 使能OSPIM端口0的IO[3-0] */
rcu_periph_clock_enable(RCU_OSPI0); /* 使能OSPI0时钟 */
ospim_port_sck_source_select(OSPIM_PORT0, OSPIM_SCK_SOURCE_OSPI0_SCK); /* 选择OSPIM端口0的SCK源为OSPI0_SCK */
ospim_port_csn_source_select(OSPIM_PORT0, OSPIM_CSN_SOURCE_OSPI0_CSN); /* 选择OSPIM端口0的CSN源为OSPI0_CSN */
ospim_port_io3_0_source_select(OSPIM_PORT0, OSPIM_SRCPLIO_OSPI0_IO_LOW); /* 选择OSPIM端口0的IO[3-0]源为OSPI0_IO[3-0] */
ospi_struct_init(&QSPIHandle); /* 初始化OSPI结构体参数为默认值 */
QSPIHandle.prescaler = (4 - 1); /* 从内核时钟分频产生OSPI时钟的分频因子 */
/* OSPI时钟来自AHB3时钟,设置使用4分频, 则OSPI时钟为300M / 4 = 75Mhz
*/
QSPIHandle.sample_shift = OSPI_SAMPLE_SHIFTING_HALF_CYCLE; /* 采样移位二分之一个周期 */
QSPIHandle.fifo_threshold = OSPI_CS_HIGH_TIME_4_CYCLE; /* FIFO中的阈值为4个字节 */
QSPIHandle.device_size = OSPI_MESZ_128_MBS; /* 外部存储器大小为128MB(W25N01GVZEIG) */
QSPIHandle.wrap_size = OSPI_DIRECT; /* 外部存储器设备不支持回卷读取 */
QSPIHandle.cs_hightime = OSPI_CS_HIGH_TIME_4_CYCLE; /* 片选高电平时间为4个周期(4*1000/75=53ns),即手册里面的tSHSL参数 */
QSPIHandle.memory_type = OSPI_MICRON_MODE; /* 外部设备类型为Micron模式 */
QSPIHandle.delay_hold_cycle = OSPI_DELAY_HOLD_QUARTER_CYCLE; /* 不延迟保持 */
ospi_init(OSPI0,&QSPIHandle); /* 初始化OSPI参数 */
ospi_enable(OSPI0); /* 使能OSPI */
ospi_flash_Write_StaRegister(0x1f,0xA0,0x00);
ospi_flash_Write_StaRegister(0x1f,0xB0,0x18);
}
void ospi_flash_Write_StaRegister(u8 tmpCMD,u8 tmpAddr,u8 tmpSta)//写状态寄存器
{
ospi_regular_cmd_struct cmd_struct = {0};
ospi_flash_write_enbale();
cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_0;
cmd_struct.instruction = tmpCMD; // 写寄存器指令
cmd_struct.ins_size = OSPI_INSTRUCTION_8_BITS;
cmd_struct.addr_mode = OSPI_ADDRESS_1_LINE;
cmd_struct.address = tmpAddr; // 写入地址
cmd_struct.addr_dtr_mode = OSPI_ADDRDTR_MODE_DISABLE; // 仅支持GD25LX512ME。
cmd_struct.addr_size = OSPI_ADDRESS_8_BITS; // 地址的位数
cmd_struct.data_mode = OSPI_DATA_1_LINE;
cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG; // 选择常规操作
cmd_struct.nbdata = 1;
cmd_struct.data_dtr_mode = OSPI_DADTR_MODE_DISABLE; //仅支持GD25LX512ME。
cmd_struct.alter_bytes_mode = OSPI_ALTERNATE_BYTES_NONE;
/* send the command */
ospi_command_config(OSPI0, &QSPIHandle, &cmd_struct);
ospi_transmit(OSPI0,&tmpSta);
}
```
flash的写使能函数如下
```
void ospi_flash_write_enbale()
{
ospi_autopolling_struct autopl_cfg_struct = {0};
ospi_regular_cmd_struct cmd_struct = {0};
/* initialize write enable command */
cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG;
cmd_struct.instruction = 0x06;
cmd_struct.ins_size = OSPI_INSTRUCTION_8_BITS;
cmd_struct.addr_mode = OSPI_ADDRESS_NONE;
cmd_struct.addr_size = OSPI_ADDRESS_24_BITS;
cmd_struct.addr_dtr_mode = OSPI_ADDRDTR_MODE_DISABLE;
cmd_struct.alter_bytes_mode = OSPI_ALTERNATE_BYTES_NONE;
cmd_struct.alter_bytes_size = OSPI_ALTERNATE_BYTES_24_BITS;
cmd_struct.alter_bytes_dtr_mode = OSPI_ABDTR_MODE_DISABLE;
cmd_struct.data_mode = OSPI_DATA_NONE;
cmd_struct.data_dtr_mode = OSPI_DADTR_MODE_DISABLE;
cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_0;
cmd_struct.nbdata = 0;
/* send the command */
ospi_command_config(OSPI0, &QSPIHandle, &cmd_struct);
/* configure automatic polling mode to wait for write enabling */
cmd_struct.data_mode = OSPI_DATA_1_LINE;
cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_0;
cmd_struct.instruction = W25_REG_STATUS;
cmd_struct.addr_dtr_mode = OSPI_ADDRDTR_MODE_DISABLE;
cmd_struct.nbdata = 1;
/* send the command */
ospi_command_config(OSPI0, &QSPIHandle, &cmd_struct);
autopl_cfg_struct.match = 2U;
autopl_cfg_struct.mask = 2U;
autopl_cfg_struct.match_mode = OSPI_MATCH_MODE_AND;
autopl_cfg_struct.interval = 0x10; //注意该参数
autopl_cfg_struct.automatic_stop = OSPI_AUTOMATIC_STOP_MATCH;
ospi_autopolling_mode(OSPI0, &QSPIHandle, &autopl_cfg_struct);
}
```
块擦除
```
void ospi_flash_block_erase(uint32_t addr)
{
ospi_regular_cmd_struct cmd_struct = {0};
ospi_flash_write_enbale();
cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_8;
cmd_struct.instruction = 0xd8; // 块擦除指令
cmd_struct.ins_size = OSPI_INSTRUCTION_8_BITS;
cmd_struct.addr_mode = OSPI_ADDRESS_1_LINE;
cmd_struct.address = addr; // 写入擦除地址
cmd_struct.addr_dtr_mode = OSPI_ADDRDTR_MODE_DISABLE; // 仅支持GD25LX512ME。
cmd_struct.addr_size = OSPI_ADDRESS_16_BITS; // 地址的位数
cmd_struct.data_mode = OSPI_DATA_NONE;
cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG; // 选择常规操作
cmd_struct.data_dtr_mode = OSPI_DADTR_MODE_DISABLE; // 仅支持GD25LX512ME。
cmd_struct.alter_bytes_mode = OSPI_ALTERNATE_BYTES_NONE;
/* send the command */
ospi_command_config(OSPI0, &QSPIHandle, &cmd_struct);
}
```
读页和缓存代码
```
void ospi_ReadPage(uint32_t _PageAddr)
{
ospi_regular_cmd_struct cmd_struct = {0};
cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_8;
cmd_struct.instruction = 0x13;
cmd_struct.ins_size = OSPI_INSTRUCTION_8_BITS;
cmd_struct.addr_mode = OSPI_ADDRESS_1_LINE;
cmd_struct.address = _PageAddr; // 页读取地址
cmd_struct.addr_dtr_mode = OSPI_ADDRDTR_MODE_DISABLE; //仅支持GD25LX512ME。
cmd_struct.addr_size = OSPI_ADDRESS_16_BITS; // 地址的位数
cmd_struct.data_mode = OSPI_DATA_NONE;
cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG; // 选择常规操作
cmd_struct.data_dtr_mode = OSPI_DADTR_MODE_DISABLE; // 仅支持GD25LX512ME。
cmd_struct.alter_bytes_mode = OSPI_ALTERNATE_BYTES_NONE;
/* send the command */
ospi_command_config(OSPI0, &QSPIHandle, &cmd_struct);
}
void ospi_ReadBuffer(uint8_t * _pBuf, uint32_t ReadColumAddr, uint32_t Size)
{
ospi_regular_cmd_struct cmd_struct = {0};
cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_4;
cmd_struct.instruction = 0xeb;
cmd_struct.ins_size = OSPI_INSTRUCTION_8_BITS;
cmd_struct.addr_mode = OSPI_ADDRESS_4_LINES;
cmd_struct.address = ReadColumAddr; // 读取缓存区地址
cmd_struct.addr_dtr_mode = OSPI_ADDRDTR_MODE_DISABLE; //仅支持GD25LX512ME。
cmd_struct.addr_size = OSPI_ADDRESS_16_BITS; // 地址的位数
cmd_struct.data_mode = OSPI_DATA_4_LINES; // 4线数据读取方式
cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG; // 选择常规操作
cmd_struct.nbdata = Size;
cmd_struct.data_dtr_mode = OSPI_DADTR_MODE_DISABLE; // 仅支持GD25LX512ME。
cmd_struct.alter_bytes_mode = OSPI_ALTERNATE_BYTES_NONE;
/* send the command */
ospi_command_config(OSPI0, &QSPIHandle, &cmd_struct);
ospi_receive(OSPI0,_pBuf);
```
写缓存和写入flash的代码如下
```
void ospi_WriteBuffer(uint8_t *_pBuf, uint32_t WriteColumAddr, uint16_t WriteSize)
{
ospi_regular_cmd_struct cmd_struct = {0};
ospi_flash_write_enbale();
delay_ms(2);
cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_0;
cmd_struct.instruction = 0x34; // 4线写入缓冲区指令 随机加载
cmd_struct.ins_size = OSPI_INSTRUCTION_8_BITS;
cmd_struct.addr_mode = OSPI_ADDRESS_1_LINE; // 1线地址方式
cmd_struct.address = WriteColumAddr; // 写入缓存区列地址
cmd_struct.addr_dtr_mode = OSPI_ADDRDTR_MODE_DISABLE; // 仅支持GD25LX512ME。
cmd_struct.addr_size = OSPI_ADDRESS_16_BITS; // 地址的位数
cmd_struct.data_mode = OSPI_DATA_4_LINES; // 4线数据方式
cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG; // 选择常规操作
cmd_struct.nbdata = WriteSize;
cmd_struct.data_dtr_mode = OSPI_DADTR_MODE_DISABLE; // 仅支持GD25LX512ME。
cmd_struct.alter_bytes_mode = OSPI_ALTERNATE_BYTES_NONE;
/* send the command */
ospi_command_config(OSPI0, &QSPIHandle, &cmd_struct);
ospi_transmit(OSPI0,_pBuf); // 将数据写入缓存区
}
void ospi_Program(uint32_t WritePageAddr)
{
ospi_regular_cmd_struct cmd_struct = {0};
cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_8;
cmd_struct.instruction = 0x10; // 编程指令
cmd_struct.ins_size = OSPI_INSTRUCTION_8_BITS;
cmd_struct.addr_mode = OSPI_ADDRESS_1_LINE;
cmd_struct.address = WritePageAddr; // 写入页地址
cmd_struct.addr_dtr_mode = OSPI_ADDRDTR_MODE_DISABLE; // 仅支持GD25LX512ME。
cmd_struct.addr_size = OSPI_ADDRESS_16_BITS; // 地址的位数
cmd_struct.data_mode = OSPI_DATA_NONE; // 无数据
cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG; // 选择常规操作
cmd_struct.data_dtr_mode = OSPI_DADTR_MODE_DISABLE; // 仅支持GD25LX512ME。
cmd_struct.alter_bytes_mode = OSPI_ALTERNATE_BYTES_NONE;
/* send the command */
ospi_command_config(OSPI0, &QSPIHandle, &cmd_struct);
}
```
代码中写入flash数据的代码
```
//在7块0页的0列开始写入flashwrite_test【12】
ospi_flash_block_erase(0x1c0); //7块0页
delay_ms(20);
ospi_WriteBuffer(flashwrite_test, 0, 12);
delay_ms(10);
ospi_Program(0x1c0);
delay_ms(5);
```
代码中读取flash中数据的代码
```
//flash_test存储3块0页0列的前12个数据
memset(flash_test,0,sizeof(flash_test));
ospi_ReadPage(0xc0);
delay_ms(20);
ospi_ReadBuffer(flash_test, 0, 12);
delay_ms(20);
//flash_test1存储7块0页0列的前12个数据
memset(flash_test1,0,sizeof(flash_test1));
ospi_ReadPage(0x1c0);
delay_ms(20);
ospi_ReadBuffer(flash_test1, 0, 12);
delay_ms(20);
/flash_test2存储15块0页0列的前12个数据
memset(flash_test1,0,sizeof(flash_test2));
ospi_ReadPage(0x1c0);
delay_ms(20);
ospi_ReadBuffer(flash_test2, 0, 12);
delay_ms(20);
```
请有经验的人士指点,是哪个配置有问题?
|
-
|