【兆易GD32H759I-EVAL】--14.OSPI Flash读写
[复制链接]
本帖最后由 dirty 于 2024-6-15 23:46 编辑
开发板板载64MB Nor Flash芯片GD25X512MEBIRY,该芯片支持标准SPI与OSPI(Octal-SPI interface).本篇讲述OSPI对Flash读写。
一.原理了解与准备
开发板板载NorFlash芯片原理图如下。由MCU GD32H759IMK6 datasheet可查阅主控支持两个OSPI,这里用到OSPI0.OSPI有三个功能模式:间接模式、状态轮询模式、内存映射模式;支持单线、双线、四线、八线通讯。硬件上,跳线帽JP64、JP67打到OSPI侧。
图1:OSPI Flash原理图
二.代码准备
这里主要实现单线、八线间接模式,内存映射模式对NorFlash写与读,并比较二者是否相同以判别写入是否成功。
1.OSPI初始化。这里包含引脚初始化,使能时钟与片选,OSPI外设口选择及OSPI参数初始化与使能。
/*!
\brief initialize OSPI/OSPIM and GPIO
\param[in] ospi_periph: OSPIx(x=0,1)
\param[out] ospi_struct: OSPI parameter initialization stuct members of the structure
and the member values are shown as below:
prescaler: between 0 and 255
fifo_threshold: OSPI_FIFO_THRESHOLD_x (x = 1, 2, ..., 31, 32)
sample_shift: OSPI_SAMPLE_SHIFTING_NONE, OSPI_SAMPLE_SHIFTING_HALF_CYCLE
device_size: OSPI_MESZ_x_BYTES (x = 2, 4, 8, ..., 512, 1024)
OSPI_MESZ_x_KBS (x = 2, 4, 8, ..., 512, 1024)
OSPI_MESZ_x_MBS (x = 2, 4, 8, ..., 2048, 4096)
cs_hightime: OSPI_CS_HIGH_TIME_x_CYCLE (x = 1, 2, ..., 63, 64)
memory_type: OSPI_MICRON_MODE, OSPI_MACRONIX_MODE, OSPI_STANDARD_MODE
OSPI_MACRONIX_RAM_MODE,
wrap_size: OSPI_DIRECT, OSPI_WRAP_16BYTES, OSPI_WRAP_32BYTES
OSPI_WRAP_64BYTES, OSPI_WRAP_128BYTES
delay_hold_cycle: OSPI_DELAY_HOLD_NONE, OSPI_DELAY_HOLD_QUARTER_CYCLE
\retval none
*/
void ospi_flash_init(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct)
{
/* reset the OSPI and OSPIM peripheral */
ospi_deinit(ospi_periph);
ospim_deinit();
/* enable OSPIM and GPIO clock */
rcu_periph_clock_enable(RCU_OSPIM);
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_GPIOC);
rcu_periph_clock_enable(RCU_GPIOD);
rcu_periph_clock_enable(RCU_GPIOE);
/* configure OSPIM GPIO pin:
OSPIM_P0_IO0(PD11)
OSPIM_P0_IO1(PC10)
OSPIM_P0_IO2(PE2)
OSPIM_P0_IO3(PD13)
OSPIM_P0_IO4(PD4)
OSPIM_P0_IO5(PD5)
OSPIM_P0_IO6(PD6)
OSPIM_P0_IO7(PD7)
OSPIM_P0_CLK(PA3)
OSPIM_P0_NCS(PB10) */
gpio_af_set(GPIOA, GPIO_AF_12, GPIO_PIN_3);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_3);
gpio_af_set(GPIOB, GPIO_AF_9, GPIO_PIN_10);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_10);
gpio_af_set(GPIOC, GPIO_AF_9, GPIO_PIN_10);
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_10);
gpio_af_set(GPIOD, GPIO_AF_10, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
gpio_af_set(GPIOD, GPIO_AF_9, GPIO_PIN_11 | GPIO_PIN_13);
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_11 | GPIO_PIN_13);
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_11 | GPIO_PIN_13);
gpio_af_set(GPIOE, GPIO_AF_9, GPIO_PIN_2);
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_2);
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_2);
/* enable SCK, CSN, IO[3:0] and IO[7:4] for OSPIM port0 */
ospim_port_sck_config(OSPIM_PORT0, OSPIM_PORT_SCK_ENABLE);
ospim_port_csn_config(OSPIM_PORT0, OSPIM_PORT_CSN_ENABLE);
ospim_port_io3_0_config(OSPIM_PORT0, OSPIM_IO_LOW_ENABLE);
ospim_port_io7_4_config(OSPIM_PORT0, OSPIM_IO_HIGH_ENABLE);
switch(ospi_periph) {
case OSPI0:
rcu_periph_clock_enable(RCU_OSPI0);
/* configure OSPIM port0 */
ospim_port_sck_source_select(OSPIM_PORT0, OSPIM_SCK_SOURCE_OSPI0_SCK);
ospim_port_csn_source_select(OSPIM_PORT0, OSPIM_CSN_SOURCE_OSPI0_CSN);
ospim_port_io3_0_source_select(OSPIM_PORT0, OSPIM_SRCPLIO_OSPI0_IO_LOW);
ospim_port_io7_4_source_select(OSPIM_PORT0, OSPIM_SRCPHIO_OSPI0_IO_HIGH);
break;
case OSPI1:
rcu_periph_clock_enable(RCU_OSPI1);
/* configure OSPIM port0 */
ospim_port_sck_source_select(OSPIM_PORT0, OSPIM_SCK_SOURCE_OSPI1_SCK);
ospim_port_csn_source_select(OSPIM_PORT0, OSPIM_CSN_SOURCE_OSPI1_CSN);
ospim_port_io3_0_source_select(OSPIM_PORT0, OSPIM_SRCPLIO_OSPI1_IO_LOW);
ospim_port_io7_4_source_select(OSPIM_PORT0, OSPIM_SRCPHIO_OSPI1_IO_HIGH);
break;
default:
break;
}
/* initialize the parameters of OSPI struct */
ospi_struct_init(ospi_struct);
ospi_struct->prescaler = 9U;
ospi_struct->sample_shift = OSPI_SAMPLE_SHIFTING_NONE;
ospi_struct->fifo_threshold = OSPI_FIFO_THRESHOLD_5;
ospi_struct->device_size = OSPI_MESZ_512_MBS;
ospi_struct->wrap_size = OSPI_DIRECT;
ospi_struct->cs_hightime = OSPI_CS_HIGH_TIME_3_CYCLE;
ospi_struct->memory_type = OSPI_MICRON_MODE;
ospi_struct->delay_hold_cycle = OSPI_DELAY_HOLD_NONE;
/* initialize OSPI parameter */
ospi_init(ospi_periph, ospi_struct);
/* enable OSPI */
ospi_enable(ospi_periph);
}
2.复位OSPI Flash。这里对SPI模式和OSPI模式进行同时处理。
/* reset ospi flash */
ospi_flash_reset_enable(OSPI_INTERFACE, &ospi_struct, SPI_MODE);
ospi_flash_reset_memory(OSPI_INTERFACE, &ospi_struct, SPI_MODE);
ospi_flash_reset_enable(OSPI_INTERFACE, &ospi_struct, OSPI_MODE);
ospi_flash_reset_memory(OSPI_INTERFACE, &ospi_struct, OSPI_MODE);
3.读取flash ID.这里使用SPI模式读出。在读出正确的情况下对Flash进行写、读后比较。
/* read flash ID */
flashid = ospi_flash_read_id(OSPI_INTERFACE, &ospi_struct, SPI_MODE);
if(GD25X512ME_ID == flashid)
{
printf("\n\rThe device ID is 0x%X\n\r", flashid);
}
else
{
printf("\n\rFailed to read device ID\n\r");
while(1){
}
4.单线间接模式写、读后比较
/* 1 line in indirect mode read/write */
printf("\n\rThe data written with 1 line in indirect mode to flash is:");
printf("\n%s\n\r", tx_buffer1);
/* erase specified address */
ospi_flash_autopolling_mem_ready(OSPI_INTERFACE, &ospi_struct, SPI_MODE);
ospi_flash_write_enbale(OSPI_INTERFACE, &ospi_struct, SPI_MODE);
ospi_flash_block_erase(OSPI_INTERFACE, &ospi_struct, SPI_MODE, GD25X512ME_3BYTES_SIZE, FLASH_WRITE_ADDRESS_1, GD25X512ME_ERASE_4K);
ospi_flash_autopolling_mem_ready(OSPI_INTERFACE, &ospi_struct, SPI_MODE);
/* write data of tx_buffer1 to flash */
ospi_flash_autopolling_mem_ready(OSPI_INTERFACE, &ospi_struct, SPI_MODE);
ospi_flash_write_enbale(OSPI_INTERFACE, &ospi_struct, SPI_MODE);
ospi_flash_page_program(OSPI_INTERFACE, &ospi_struct, SPI_MODE, GD25X512ME_3BYTES_SIZE, tx_buffer1, FLASH_WRITE_ADDRESS_1, buffersize1);
ospi_flash_autopolling_mem_ready(OSPI_INTERFACE, &ospi_struct, SPI_MODE);
/* read data from flash */
ospi_flash_read(OSPI_INTERFACE, &ospi_struct, SPI_MODE, GD25X512ME_3BYTES_SIZE, rx_buffer1, FLASH_WRITE_ADDRESS_1, buffersize1);
if(ERROR != memory_compare(tx_buffer1, rx_buffer1, buffersize1)) {
printf("The data read with 1 line in indirect mode from flash is:");
printf("\n%s\n", tx_buffer1);
printf("OSPI read/write with 1 line in indirect test success!\r\n");
} else {
printf("OSPI read/write with 1 line in indirect test failed!\r\n");
while(1){
}
}
5.八线间接模式写、读后比较
/* 8 lines in indirect mode read/write */
printf("\n\rThe data written with 8 lines in indirect mode to flash is:\n");
printf("\n%s\n\r", tx_buffer2);
/* configure OSPI FLASH dummy cycles */
ospi_flash_write_enbale(OSPI_INTERFACE, &ospi_struct, SPI_MODE);
ospi_flash_write_volatilecfg_register(OSPI_INTERFACE, &ospi_struct, SPI_MODE, GD25X512ME_3BYTES_SIZE, GD25X512ME_CFG_REG1_ADDR, GD25X512ME_CFG_16_DUMMY_CYCLES);
/* configure OSPI FLASH enter STR OSPI mode */
ospi_flash_write_enbale(OSPI_INTERFACE, &ospi_struct, SPI_MODE);
ospi_flash_write_volatilecfg_register(OSPI_INTERFACE, &ospi_struct, SPI_MODE, GD25X512ME_3BYTES_SIZE, GD25X512ME_CFG_REG0_ADDR, GD25X512ME_CFG_OCTAL_STR_WO);
ospi_flash_autopolling_mem_ready(OSPI_INTERFACE, &ospi_struct, OSPI_MODE);
/* erase specified address */
ospi_flash_autopolling_mem_ready(OSPI_INTERFACE, &ospi_struct, OSPI_MODE);
ospi_flash_write_enbale(OSPI_INTERFACE, &ospi_struct, OSPI_MODE);
ospi_flash_block_erase(OSPI_INTERFACE, &ospi_struct, OSPI_MODE, GD25X512ME_3BYTES_SIZE, FLASH_WRITE_ADDRESS_2, GD25X512ME_ERASE_4K);
ospi_flash_autopolling_mem_ready(OSPI_INTERFACE, &ospi_struct, OSPI_MODE);
/* write data of tx_buffer to flash */
ospi_flash_autopolling_mem_ready(OSPI_INTERFACE, &ospi_struct, OSPI_MODE);
ospi_flash_write_enbale(OSPI_INTERFACE, &ospi_struct, OSPI_MODE);
ospi_flash_page_program(OSPI_INTERFACE, &ospi_struct, OSPI_MODE, GD25X512ME_3BYTES_SIZE, tx_buffer2, FLASH_WRITE_ADDRESS_2, buffersize2);
ospi_flash_autopolling_mem_ready(OSPI_INTERFACE, &ospi_struct, OSPI_MODE);
/* read data from flash */
ospi_flash_read(OSPI_INTERFACE, &ospi_struct, OSPI_MODE, GD25X512ME_3BYTES_SIZE, rx_buffer2, FLASH_WRITE_ADDRESS_2, buffersize2);
if(ERROR != memory_compare(tx_buffer2, rx_buffer2, buffersize2)) {
printf("\n\rThe data read with 8 lines in indirect mode from flash is:\n");
for(i = 0; i < buffersize2; i++) {
printf("%c", rx_buffer2[i]);
}
printf("\r\n");
printf("OSPI read/write with 8 lines in indirect test success!\r\n");
} else {
printf("OSPI read/write with 8 lines in indirect test failed!\r\n");
while(1){
}
}
6.内存映射模式模式写、读后比较
/* memory mapped mode read/write */
printf("\n\rThe data written in indirect mode to flash is:\n");
for(i = 0; i < buffersize3; i++){
printf("%c", tx_buffer3[i]);
}
/* erase specified address */
ospi_flash_autopolling_mem_ready(OSPI_INTERFACE, &ospi_struct, OSPI_MODE);
ospi_flash_write_enbale(OSPI_INTERFACE, &ospi_struct, OSPI_MODE);
ospi_flash_block_erase(OSPI_INTERFACE, &ospi_struct, OSPI_MODE, GD25X512ME_3BYTES_SIZE, 0x400000, GD25X512ME_ERASE_4K);
/* write data of tx_buffer to flash */
ospi_flash_autopolling_mem_ready(OSPI_INTERFACE, &ospi_struct, OSPI_MODE);
ospi_flash_write_enbale(OSPI_INTERFACE, &ospi_struct, OSPI_MODE);
ospi_flash_memory_map_mode_wrap_enable(OSPI_INTERFACE, &ospi_struct, OSPI_MODE, GD25X512ME_3BYTES_SIZE);
ospi_flash_page_program(OSPI_INTERFACE, &ospi_struct, OSPI_MODE, GD25X512ME_3BYTES_SIZE, tx_buffer3, 0x400000, buffersize3);
ospi_flash_autopolling_mem_ready(OSPI_INTERFACE, &ospi_struct, OSPI_MODE);
ospi_flash_memory_map_mode_wrap_enable(OSPI_INTERFACE, &ospi_struct, OSPI_MODE, GD25X512ME_3BYTES_SIZE);
memory_mapped_read(rx_buffer3, FLASH_WRITE_ADDRESS_3, buffersize3);
if(ERROR != memory_compare(tx_buffer3, rx_buffer3, buffersize3)) {
printf("\n\rThe data read in memory mapped mode from flash is:\n");
for(i = 0; i < buffersize3; i++) {
printf("%c", rx_buffer3[i]);
}
printf("\r\n");
printf("OSPI read in memory mapped mode test success!\r\n");
} else {
printf("OSPI read in memory mapped mode test failed!\r\n");
while(1){
}
}
三.测验
编译烧录后,复位查看日志,可看到三种模式均成功写入与读出,且数据正确。
图2:OSPI Flash读写
至此,实现OSPI对Nor Flash的读写功能。
|