[MCU] 【兆易GD32H759I-EVAL】GD25x512ME读写测试

TL-LED   2024-6-12 21:53 楼主

测试板卡上GD25x512ME芯片 SPI方式读写测试。

 

一、电路部分

 

1.1、GD25x512ME芯片部分电路图

使用SPI方式,需要将JP64选择QSPI0功能。

001.jpg

 

1.2、GD25x512手册部分

 

GD25x512是一颗512M-bit FLASH芯片,支持SPI模式和OPI模式。

芯片内部框图

002.jpg

存储结构

003.jpg

 

1.3、OSPI接口

 

1.3.1、GD32H759的OSPI简介

 

OSPI是一种专用于和外部存储器通信的接口,支持单线,双线,四线和八线SPI模式。

 

1.3.2、主要特征

-三种模式:
- 间接模式:使用OSPI的寄存器执行所有操作。
- 状态轮询模式:周期性读取并检测外部存储器的状态寄存器值。
- 内存映射模式:外部存储器映射到MCU地址空间(OSPI0: 0x9000 0000 - 0x9FFFFFFF, OSPI1: 0x7000 0000- 0x 7FFF FFFF),和访问内部存储空间一样访问存储器。
 支持内存映射模式下读;
 支持单线、双线、四线和八线通信;
 可用于间接模式和内存映射模式的完全可编程命令格式;
 支持SDR(单倍数据速率)和DTR(双倍传输速率,仅支持读GD25LX512ME);
 接收和发送的FIFO功能;
 允许8位、 16位或32位数据访问;
 间接模式支持DMA操作;
 中断: FIFO达到阈值,状态匹配、传输完成、访问错误中断。

 

1.3.3、8线通信模式结构框图

004.jpg

1.3.4、4线通信模式结构框图

005.jpg

 

二、程序部分

 

2.1、gd25x512me.c

 

/*!
    \file    gd25x512me.c
    \brief   OSPI flash gd25x512 driver

    \version 2024-01-05, V1.2.0, demo for GD32H7xx
*/

/*
    Copyright (c) 2024, GigaDevice Semiconductor Inc.

    Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of its contributors
       may be used to endorse or promote products derived from this software without
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/

#include "gd25x512me.h"
#include "gd32h7xx.h"

/*!
    \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);
}

/*!
    \brief      read the flah id
    \param[in]  ospi_periph: OSPIx(x=0,1)
    \param[in]  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
    \param[in]  mode: flash interface mode
                only one parameter can be selected which is shown as below:
      \arg        SPI_MODE: SPI mode
      \arg        OSPI_MODE: OSPI mode
    \retval     none
*/
uint32_t ospi_flash_read_id(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode)
{
    uint8_t temp_id[4];
    ospi_regular_cmd_struct cmd_struct = {0};

    /* initialize read ID command */
    if(SPI_MODE == mode) {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
        cmd_struct.addr_mode = OSPI_ADDRESS_NONE;
        cmd_struct.data_mode = OSPI_DATA_1_LINE;
        cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_0;
    } else {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_8_LINES;
        cmd_struct.addr_mode = OSPI_ADDRESS_NONE;
        cmd_struct.data_mode = OSPI_DATA_8_LINES;
        cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_8;
    }
    cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG;
    cmd_struct.instruction = GD25X512ME_READ_ID_CMD;
    cmd_struct.ins_size = OSPI_INSTRUCTION_8_BITS;
    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_dtr_mode = OSPI_DADTR_MODE_DISABLE;
    cmd_struct.nbdata = 4;

    /* send the command */
    ospi_command_config(ospi_periph, ospi_struct, &cmd_struct);

    /* receive data */
    ospi_receive(ospi_periph, temp_id);
    return (temp_id[0] << 24) | (temp_id[1] << 16) | (temp_id[2] << 8) | temp_id[3];
}

/*!
    \brief      enable flash reset
    \param[in]  ospi_periph: OSPIx(x=0,1)
    \param[in]  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
    \param[in]  mode: flash interface mode
                only one parameter can be selected which is shown as below:
      \arg        SPI_MODE: SPI mode
      \arg        OSPI_MODE: OSPI mode
    \retval     none
*/
void ospi_flash_reset_enable(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode)
{
    ospi_regular_cmd_struct cmd_struct = {0};

    /* initialize enable flash reset command */
    if(SPI_MODE == mode) {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
    } else {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_8_LINES;
    }
    cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG;
    cmd_struct.instruction = GD25X512ME_RESET_ENABLE_CMD;
    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(ospi_periph, ospi_struct, &cmd_struct);
}

/*!
    \brief      reset the flash
    \param[in]  ospi_periph: OSPIx(x=0,1)
    \param[in]  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
    \param[in]  mode: flash interface mode
                only one parameter can be selected which is shown as below:
      \arg        SPI_MODE: SPI mode
      \arg        OSPI_MODE: OSPI mode
    \retval     none
*/
void ospi_flash_reset_memory(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode)
{
    ospi_regular_cmd_struct cmd_struct = {0};

    /* initialize flash reset command */
    if(SPI_MODE == mode) {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
    } else {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_8_LINES;
    }
    cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG;
    cmd_struct.instruction = GD25X512ME_RESET_MEMORY_CMD;
    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(ospi_periph, ospi_struct, &cmd_struct);
}

/*!
    \brief      enable flash write
    \param[in]  ospi_periph: OSPIx(x=0,1)
    \param[in]  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
    \param[in]  mode: flash interface mode
                only one parameter can be selected which is shown as below:
      \arg        SPI_MODE: SPI mode
      \arg        OSPI_MODE: OSPI mode
    \retval     none
*/
void ospi_flash_write_enbale(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode)
{
    ospi_autopolling_struct autopl_cfg_struct = {0};
    ospi_regular_cmd_struct cmd_struct = {0};

    /* initialize write enable command */
    if(SPI_MODE == mode) {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
    } else {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_8_LINES;
    }
    cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG;
    cmd_struct.instruction = GD25X512ME_WRITE_ENABLE_CMD;
    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(ospi_periph, ospi_struct, &cmd_struct);

    /* configure automatic polling mode to wait for write enabling */
    if(SPI_MODE == mode) {
        cmd_struct.data_mode = OSPI_DATA_1_LINE;
        cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_0;
    } else {
        cmd_struct.data_mode = OSPI_DATA_8_LINES;
        cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_8;
    }
    cmd_struct.instruction = GD25X512ME_READ_STATUS_REG_CMD;
    cmd_struct.addr_dtr_mode = OSPI_ADDRDTR_MODE_DISABLE;
    cmd_struct.nbdata = 1;

    /* send the command */
    ospi_command_config(ospi_periph, ospi_struct, &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 = GD25X512ME_AUTOPOLLING_INTERVAL_TIME;
    autopl_cfg_struct.automatic_stop = OSPI_AUTOMATIC_STOP_MATCH;
    ospi_autopolling_mode(ospi_periph, ospi_struct, &autopl_cfg_struct);
}

/*!
    \brief      write flash volatile configuration register
    \param[in]  ospi_periph: OSPIx(x=0,1)
    \param[in]  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
    \param[in]  mode: flash interface mode
                only one parameter can be selected which is shown as below:
      \arg        SPI_MODE: SPI mode
      \arg        OSPI_MODE: OSPI mode
    \param[in]  addr_size: the size of address
    \param[in]  value: the value of transmit
    \retval     none
*/
void ospi_flash_write_volatilecfg_register(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode, addr_size addr_size,
        uint32_t addr, uint8_t value)
{
    ospi_regular_cmd_struct cmd_struct = {0};

    /* initialize write enable for volatile status register command */
    if(SPI_MODE == mode) {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
    } else {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_8_LINES;
    }
    cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG;
    cmd_struct.instruction = GD25X512ME_WRITE_ENABLE_VOLATILE_STATUS_CFG_CMD;
    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(ospi_periph, ospi_struct, &cmd_struct);

    /* initialize write volatile configuration register command */
    if(SPI_MODE == mode) {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
        cmd_struct.addr_mode = OSPI_ADDRESS_1_LINE;
        cmd_struct.data_mode = OSPI_DATA_1_LINE;
    } else {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_8_LINES;
        cmd_struct.addr_mode = OSPI_ADDRESS_8_LINES;
        cmd_struct.data_mode = OSPI_DATA_8_LINES;
    }
    if(GD25X512ME_3BYTES_SIZE == addr_size) {
        cmd_struct.addr_size = OSPI_ADDRESS_24_BITS;
    } else {
        cmd_struct.addr_size = OSPI_ADDRESS_32_BITS;
    }
    cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG;
    cmd_struct.instruction = GD25X512ME_WRITE_VOLATILE_CFG_REG_CMD;
    cmd_struct.ins_size = OSPI_INSTRUCTION_8_BITS;
    cmd_struct.address = addr;
    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_dtr_mode = OSPI_DADTR_MODE_DISABLE;
    cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_0;
    cmd_struct.nbdata = 1;

    /* send the command */
    ospi_command_config(ospi_periph, ospi_struct, &cmd_struct);
    ospi_transmit(ospi_periph, &value);
}

/*!
    \brief      polling WIP(Write In Progress) bit become to 0
    \param[in]  ospi_periph: OSPIx(x=0,1)
    \param[in]  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
    \param[in]  mode: flash interface mode
                only one parameter can be selected which is shown as below:
      \arg        SPI_MODE: SPI mode
      \arg        OSPI_MODE: OSPI mode
    \retval     none
*/
void ospi_flash_autopolling_mem_ready(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode)
{
    ospi_autopolling_struct autopl_cfg_struct = {0};
    ospi_regular_cmd_struct cmd_struct = {0};

    /* initialize read status register command */
    if(SPI_MODE == mode) {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
        cmd_struct.addr_mode = OSPI_ADDRESS_NONE;
        cmd_struct.data_mode = OSPI_DATA_1_LINE;
        cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_0;
    } else {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_8_LINES;
        cmd_struct.addr_mode = OSPI_ADDRESS_NONE;
        cmd_struct.data_mode = OSPI_DATA_8_LINES;
        cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_8;
    }
    cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG;
    cmd_struct.ins_size = OSPI_INSTRUCTION_8_BITS;
    cmd_struct.instruction = GD25X512ME_READ_STATUS_REG_CMD;
    cmd_struct.addr_dtr_mode = OSPI_ADDRDTR_MODE_DISABLE;
    cmd_struct.addr_size = OSPI_ADDRESS_24_BITS;
    cmd_struct.address = 0U;
    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_dtr_mode = OSPI_DADTR_MODE_DISABLE;
    cmd_struct.nbdata = 1;

    /* send the command */
    ospi_command_config(ospi_periph, ospi_struct, &cmd_struct);

    /* configure the OSPI automatic polling mode */
    autopl_cfg_struct.match = 0U;
    autopl_cfg_struct.mask  = GD25X512ME_SR_WIP;
    autopl_cfg_struct.match_mode = OSPI_MATCH_MODE_AND;
    autopl_cfg_struct.interval = GD25X512ME_AUTOPOLLING_INTERVAL_TIME;
    autopl_cfg_struct.automatic_stop = OSPI_AUTOMATIC_STOP_MATCH;
    ospi_autopolling_mode(ospi_periph, ospi_struct, &autopl_cfg_struct);
}

/*!
    \brief      erase the specified block of the flash
    \param[in]  ospi_periph: OSPIx(x=0,1)
    \param[in]  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
    \param[in]  mode: flash interface mode
                only one parameter can be selected which is shown as below:
      \arg        SPI_MODE: SPI mode
      \arg        OSPI_MODE: OSPI mode
    \param[in]  addr_size: the size of address
    \param[in]  address: address of erase
    \param[in]  block_size: block size to erase
    \retval     none
*/
void ospi_flash_block_erase(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode, addr_size addr_size, uint32_t addr,
                            erase_size block_size)
{
    ospi_regular_cmd_struct cmd_struct = {0};

    /* initialize block erase command */
    if(SPI_MODE == mode) {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
        cmd_struct.addr_mode = OSPI_ADDRESS_1_LINE;
    } else {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_8_LINES;
        cmd_struct.addr_mode = OSPI_ADDRESS_8_LINES;
    }
    if(GD25X512ME_ERASE_64K == block_size) {
        if(GD25X512ME_3BYTES_SIZE == addr_size) {
            cmd_struct.instruction = GD25X512ME_BLOCK_ERASE_64K_CMD;
        } else {
            cmd_struct.instruction = GD25X512ME_4_BYTE_BLOCK_ERASE_64K_CMD;
        }
    } else {
        if(GD25X512ME_3BYTES_SIZE == addr_size) {
            cmd_struct.instruction = GD25X512ME_SECTOR_ERASE_4K_CMD;
        } else {
            cmd_struct.instruction = GD25X512ME_4_BYTE_SECTOR_ERASE_4K_CMD;
        }
    }
    cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG;
    cmd_struct.ins_size = OSPI_INSTRUCTION_8_BITS;
    cmd_struct.addr_size = OSPI_ADDRESS_24_BITS;
    cmd_struct.address = addr;
    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(ospi_periph, ospi_struct, &cmd_struct);
}

/*!
    \brief      erase the the entire flash
    \param[in]  ospi_periph: OSPIx(x=0,1)
    \param[in]  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
    \param[in]  mode: flash interface mode
                only one parameter can be selected which is shown as below:
      \arg        SPI_MODE: SPI mode
      \arg        OSPI_MODE: OSPI mode
    \retval     none
*/
void ospi_flash_chip_erase(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode)
{
    ospi_regular_cmd_struct cmd_struct = {0};

    /* initialize block erase command */
    if(SPI_MODE == mode) {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
    } else {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_8_LINES;
    }

    cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG;
    cmd_struct.ins_size = OSPI_INSTRUCTION_8_BITS;
    cmd_struct.instruction = GD25X512ME_CHIP_ERASE_CMD;
    cmd_struct.addr_mode = OSPI_ADDRESS_NONE;
    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(ospi_periph, ospi_struct, &cmd_struct);
}

/*!
    \brief      write data to the flash
    \param[in]  ospi_periph: OSPIx(x=0,1)
    \param[in]  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
    \param[in]  mode: flash interface mode
                only one parameter can be selected which is shown as below:
      \arg        SPI_MODE: SPI mode
      \arg        OSPI_MODE: OSPI mode
    \param[in]  addr_size: the size of address
    \param[in]  pdata: pointer to data to be written
    \param[in]  addr: write start address
    \param[in]  data_size: size of data to write
    \retval     none
*/
void ospi_flash_page_program(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode, addr_size addr_size, uint8_t *pdata,
                             uint32_t addr, uint32_t data_size)
{
    ospi_regular_cmd_struct cmd_struct = {0};

    /* initialize program command */
    if(SPI_MODE == mode) {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
        cmd_struct.addr_mode = OSPI_ADDRESS_1_LINE;
        cmd_struct.data_mode = OSPI_DATA_1_LINE;
    } else {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_8_LINES;
        cmd_struct.addr_mode = OSPI_ADDRESS_8_LINES;
        cmd_struct.data_mode = OSPI_DATA_8_LINES;
    }
    if(GD25X512ME_3BYTES_SIZE == addr_size) {
        cmd_struct.instruction = GD25X512ME_PAGE_PROG_CMD;
        cmd_struct.addr_size = OSPI_ADDRESS_24_BITS;
    } else {
        cmd_struct.instruction = GD25X512ME_4_BYTE_PAGE_PROG_CMD;
        cmd_struct.addr_size = OSPI_ADDRESS_32_BITS;
    }
    cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG;
    cmd_struct.ins_size = OSPI_INSTRUCTION_8_BITS;
    cmd_struct.addr_dtr_mode = OSPI_ADDRDTR_MODE_DISABLE;
    cmd_struct.address = addr;
    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_dtr_mode = OSPI_DADTR_MODE_DISABLE;
    cmd_struct.nbdata = data_size;
    cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_0;

    /* send the command */
    ospi_command_config(ospi_periph, ospi_struct, &cmd_struct);
    /* transmission of the data */
    ospi_transmit(ospi_periph, pdata);
}

/*!
    \brief      read data from the flash
    \param[in]  ospi_periph: OSPIx(x=0,1)
    \param[in]  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
    \param[in]  mode: flash interface mode
                only one parameter can be selected which is shown as below:
      \arg        SPI_MODE: SPI mode
      \arg        OSPI_MODE: OSPI mode
    \param[in]  addr_size: the size of address
    \param[in]  pdata: pointer to data to be read
    \param[in]  addr: read start address
    \param[in]  data_size: size of data to read
    \retval     none
*/
void ospi_flash_read(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode, addr_size addr_size, uint8_t *pdata,
                     uint32_t addr, uint32_t data_size)
{
    ospi_regular_cmd_struct cmd_struct = {0};

    /* initialize read command */
    if(SPI_MODE == mode) {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
        cmd_struct.addr_mode = OSPI_ADDRESS_1_LINE;
        cmd_struct.data_mode = OSPI_DATA_1_LINE;
        cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_8;
    } else {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_8_LINES;
        cmd_struct.addr_mode = OSPI_ADDRESS_8_LINES;
        cmd_struct.data_mode = OSPI_DATA_8_LINES;
        cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_16;
    }
    if(GD25X512ME_3BYTES_SIZE == addr_size) {
        cmd_struct.instruction = GD25X512ME_FAST_READ_CMD;
        cmd_struct.addr_size = OSPI_ADDRESS_24_BITS;
    } else {
        cmd_struct.instruction = GD25X512ME_4_BYTE_ADDR_FAST_READ_CMD;
        cmd_struct.addr_size = OSPI_ADDRESS_32_BITS;
    }
    cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG;
    cmd_struct.ins_size = OSPI_INSTRUCTION_8_BITS;
    cmd_struct.addr_dtr_mode = OSPI_ADDRDTR_MODE_DISABLE;
    cmd_struct.address = addr;
    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_dtr_mode = OSPI_DADTR_MODE_DISABLE;
    cmd_struct.nbdata = data_size;

    /* send the command */
    ospi_command_config(ospi_periph, ospi_struct, &cmd_struct);

    /* reception of the data */
    ospi_receive(ospi_periph, pdata);
}

int32_t ospi_read_status_register(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode)
{
    uint8_t status;
    ospi_regular_cmd_struct cmd_struct = {0};
     
    /* initialize read command */
    if(SPI_MODE == mode) {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
        cmd_struct.data_mode = OSPI_DATA_1_LINE;
        cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_0;
    } else {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_8_LINES;
        cmd_struct.data_mode = OSPI_DATA_8_LINES;
        cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_8;
    }
    
    cmd_struct.operation_type = OSPI_OPTYPE_COMMON_CFG;
    cmd_struct.ins_size = OSPI_INSTRUCTION_8_BITS;
    cmd_struct.instruction = GD25X512ME_READ_STATUS_REG_CMD;
    cmd_struct.addr_mode = OSPI_ADDRESS_NONE;
    cmd_struct.alter_bytes_mode = OSPI_ALTERNATE_BYTES_NONE;
    cmd_struct.data_dtr_mode = OSPI_DADTR_MODE_DISABLE;
    cmd_struct.nbdata = 1;
    
    /* send the command */
    ospi_command_config(ospi_periph, ospi_struct, &cmd_struct);
   
    /* reception of the data */
    ospi_receive(ospi_periph, &status);
    
    return status;
}

/*!
    \brief      enable memory mapped mode
    \param[in]  ospi_periph: OSPIx(x=0,1)
    \param[in]  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
    \param[in]  mode: flash interface mode
                only one parameter can be selected which is shown as below:
      \arg        SPI_MODE: SPI mode
      \arg        OSPI_MODE: OSPI mode
    \param[in]  addr_size: the size of address
    \retval     none
*/
void ospi_flash_memory_map_mode_enable(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode, addr_size addr_size)
{
    ospi_regular_cmd_struct cmd_struct = {0};

    /* initialize read command */
    if(SPI_MODE == mode) {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
    } else {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_8_LINES;
    }
    if(GD25X512ME_3BYTES_SIZE == addr_size) {
        cmd_struct.instruction = GD25X512ME_OCTAL_IO_FAST_READ_CMD;
        cmd_struct.addr_size = OSPI_ADDRESS_24_BITS;
    } else {
        cmd_struct.instruction = GD25X512ME_4_BYTE_ADDR_OCTAL_IO_FAST_READ_CMD;
        cmd_struct.addr_size = OSPI_ADDRESS_32_BITS;
    }
    cmd_struct.operation_type = OSPI_OPTYPE_READ_CFG;
    cmd_struct.ins_size = OSPI_INSTRUCTION_8_BITS;
    cmd_struct.addr_mode = OSPI_ADDRESS_8_LINES;
    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_8_LINES;
    cmd_struct.data_dtr_mode = OSPI_DADTR_MODE_DISABLE;
    cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_16;

    /* send the command */
    ospi_command_config(ospi_periph, ospi_struct, &cmd_struct);

    /* initialize program command */
    cmd_struct.operation_type = OSPI_OPTYPE_WRITE_CFG;
    cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_0;

    if(GD25X512ME_3BYTES_SIZE == addr_size) {
        cmd_struct.instruction = GD25X512ME_EXT_OCTAL_PAGE_PROG_CMD;
    } else {
        cmd_struct.instruction = GD25X512ME_4_BYTE_EXT_OCTAL_PAGE_PROG_CMD;
    }

    /* send the command */
    ospi_command_config(ospi_periph, ospi_struct, &cmd_struct);

    /* wait BUSY bit to 0 */
    while(RESET != ospi_flag_get(ospi_periph, OSPI_FLAG_BUSY)) {
    }

    /* configure OSPI memory mapped mode */
    ospi_functional_mode_config(ospi_periph, OSPI_MEMORY_MAPPED);
}

/*!
    \brief      enable memory mapped mode with wrap
    \param[in]  ospi_periph: OSPIx(x=0,1)
    \param[in]  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
    \param[in]  mode: flash interface mode
                only one parameter can be selected which is shown as below:
      \arg        SPI_MODE: SPI mode
      \arg        OSPI_MODE: OSPI mode
    \param[in]  addr_size: the size of address
    \retval     none
*/
void ospi_flash_memory_map_mode_wrap_enable(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode, addr_size addr_size)
{
    ospi_regular_cmd_struct cmd_struct = {0};

    /* initialize read command */
    if(SPI_MODE == mode) {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_1_LINE;
    } else {
        cmd_struct.ins_mode = OSPI_INSTRUCTION_8_LINES;
    }
    if(GD25X512ME_3BYTES_SIZE == addr_size) {
        cmd_struct.instruction = GD25X512ME_OCTAL_IO_FAST_READ_CMD;
        cmd_struct.addr_size = OSPI_ADDRESS_24_BITS;
    } else {
        cmd_struct.instruction = GD25X512ME_4_BYTE_ADDR_OCTAL_IO_FAST_READ_CMD;
        cmd_struct.addr_size = OSPI_ADDRESS_32_BITS;
    }
    cmd_struct.operation_type = OSPI_OPTYPE_WRAP_CFG;
    cmd_struct.ins_size = OSPI_INSTRUCTION_8_BITS;
    cmd_struct.addr_mode = OSPI_ADDRESS_8_LINES;
    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_8_LINES;
    cmd_struct.data_dtr_mode = OSPI_DADTR_MODE_DISABLE;
    cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_16;

    /* send the command */
    ospi_command_config(ospi_periph, ospi_struct, &cmd_struct);

    /* initialize program command */
    cmd_struct.operation_type = OSPI_OPTYPE_WRITE_CFG;
    cmd_struct.dummy_cycles = OSPI_DUMYC_CYCLES_0;

    if(GD25X512ME_3BYTES_SIZE == addr_size) {
        cmd_struct.instruction = GD25X512ME_EXT_OCTAL_PAGE_PROG_CMD;
    } else {
        cmd_struct.instruction = GD25X512ME_4_BYTE_EXT_OCTAL_PAGE_PROG_CMD;
    }

    /* send the command */
    ospi_command_config(ospi_periph, ospi_struct, &cmd_struct);

    /* wait BUSY bit to 0 */
    while(RESET != ospi_flag_get(ospi_periph, OSPI_FLAG_BUSY)) {
    }

    /* configure OSPI memory mapped mode */
    ospi_functional_mode_config(ospi_periph, OSPI_MEMORY_MAPPED);
}

 

2.2、gd25x512me.h

/*!
    \file    gd25x512me.h
    \brief   the header file of OSPI flash gd25x512me driver

    \version 2024-01-05, V1.2.0, demo for GD32H7xx
*/

/*
    Copyright (c) 2024, GigaDevice Semiconductor Inc.

    Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of its contributors
       may be used to endorse or promote products derived from this software without
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/

#ifndef GD25X512ME_H
#define GD25X512ME_H

#include "gd32h7xx_ospi.h"

/* GD25X512ME size configuration */
#define GD25X512ME_BLOCK_64K                    (uint32_t)(16*4*1024)                 /* 16 sectors of 64KBytes */
#define GD25X512ME_SECTOR_4K                    (uint32_t)(4 * 1024)                  /* 1 sectors of 4KBytes */

#define GD25X512ME_FLASH_SIZE                   (uint32_t)(512*1024*1024/8)           /* 512 Mbits => 64MBytes */
#define GD25X512ME_PAGE_SIZE                    (uint32_t)256                         /* 262144 pages of 256 Bytes */

/* GD25X512ME timing configuration */
#define GD25X512ME_BULK_ERASE_MAX_TIME          460000U
#define GD25X512ME_SECTOR_ERASE_MAX_TIME        1000U
#define GD25X512ME_SUBSECTOR_4K_ERASE_MAX_TIME  400U
#define GD25X512ME_WRITE_REG_MAX_TIME           40U

#define GD25X512ME_RESET_MAX_TIME               100U                                  /* when SWreset during erase operation */

#define GD25X512ME_AUTOPOLLING_INTERVAL_TIME    0x10U

/*  GD25X512ME Error codes */
#define GD25X512ME_OK                           (0)
#define GD25X512ME_ERROR                        (-1)

/* GD25X512ME commands */
/* READ/WRITE MEMORY operations with 3-bytes address */
#define GD25X512ME_READ_CMD                                   0x03U       /* normal read 3 bytes address */
#define GD25X512ME_FAST_READ_CMD                              0x0BU       /* fast read 3 bytes address */
#define GD25X512ME_OCTAL_OUTPUT_FAST_READ_CMD                 0x8BU       /* octal output fast read 3 bytes address */
#define GD25X512ME_OCTAL_IO_FAST_READ_CMD                     0xCBU       /* octal I/O fast read 3 bytes address */

#define GD25X512ME_PAGE_PROG_CMD                              0x02U       /* page program 3 bytes address */
#define GD25X512ME_OCTAL_PAGE_PROG_CMD                        0x82U       /* octal page program 3 bytes address */
#define GD25X512ME_EXT_OCTAL_PAGE_PROG_CMD                    0xC2U       /* extended octal page program 3 bytes address */

#define GD25X512ME_SECTOR_ERASE_4K_CMD                        0x20U       /* sector erase 4KB 3 bytes address */
#define GD25X512ME_BLOCK_ERASE_32K_CMD                        0x52U       /* block erase 32KB 3 bytes address */
#define GD25X512ME_BLOCK_ERASE_64K_CMD                        0xD8U       /* block erase 64KB 3 bytes address */
#define GD25X512ME_CHIP_ERASE_CMD                             0x60U       /* chip erase */

/* READ/WRITE MEMORY operations with 4-bytes address */
#define GD25X512ME_4_BYTE_ADDR_READ_CMD                       0x13U       /* normal read 4 bytes address */
#define GD25X512ME_4_BYTE_ADDR_FAST_READ_CMD                  0x0CU       /* fast read 4 bytes address */
#define GD25X512ME_4_BYTE_ADDR_OCTAL_OUTPUT_FAST_READ_CMD     0x7CU       /* octal output fast read 4 bytes address */
#define GD25X512ME_4_BYTE_ADDR_OCTAL_IO_FAST_READ_CMD         0xCCU       /* octal I/O fast read 4 bytes address */
#define GD25X512ME_4_BYTE_ADDR_OCTAL_IO_DTR_FAST_READ_CMD     0xFDU       /* octal I/O DTR fast read 4 bytes address */

#define GD25X512ME_4_BYTE_PAGE_PROG_CMD                       0x12U       /* page program 4 bytes address */
#define GD25X512ME_4_BYTE_OCTAL_PAGE_PROG_CMD                 0x84U       /* octal page program 4 bytes address */
#define GD25X512ME_4_BYTE_EXT_OCTAL_PAGE_PROG_CMD             0x8EU       /* extended octal page program 4 byte address */

#define GD25X512ME_4_BYTE_SECTOR_ERASE_4K_CMD                 0x21U       /* sector erase 4KB 4 bytes address */
#define GD25X512ME_4_BYTE_BLOCK_ERASE_32K_CMD                 0x5CU       /* block erase 32KB 4 byte address */
#define GD25X512ME_4_BYTE_BLOCK_ERASE_64K_CMD                 0xDCU       /* block erase 64KB 4 byte address */

/* setting commands */
#define GD25X512ME_WRITE_ENABLE_CMD                           0x06U       /* write enable */
#define GD25X512ME_WRITE_DISABLE_CMD                          0x04U       /* write disable */
#define GD25X512ME_PROG_ERASE_SUSPEND_CMD                     0x75U       /* program/erase suspend */
#define GD25X512ME_PROG_ERASE_RESUME_CMD                      0x7AU       /* program/erase resume */
#define GD25X512ME_ENTER_DEEP_POWER_DOWN_CMD                  0xB9U       /* enter deep power down */
#define GD25X512ME_RELEASE_FROM_DEEP_POWER_DOWN_CMD           0xABU       /* release form deep power down */
#define GD25X512ME_ENABLE_4_BYTE_ADDR_CMD                     0xB7U       /* enable 4 byte address mode */
#define GD25X512ME_DISABLE_4_BYTE_ADDR_CMD                    0xE9U       /* disable 4 byte address mode */

/* advanced sector protection commands */
#define GD25X512ME_INDIVIDUAL_BLOCK_SECTOR_LOCK_CMD           0x36U       /* individual block/sector lock */
#define GD25X512ME_INDIVIDUAL_BLOCK_SECTOR_UNLOCK_CMD         0x39U       /* individual block/sector unlock */
#define GD25X512ME_READ_INDIVIDUAL_BLOCK_SECTOR_LOCK_CMD      0x3DU       /* read individual block/sector lock */
#define GD25X512ME_GLOBAL_BLOCK_SECTOR_LOCK_CMD               0x7EU       /* global block/sector lock */
#define GD25X512ME_GLOBAL_BLOCK_SECTOR_UNLOCK_CMD             0x98U       /* global block/sector unlock */

/* RESET commands */
#define GD25X512ME_RESET_ENABLE_CMD                           0x66U       /*!< reset enable */
#define GD25X512ME_RESET_MEMORY_CMD                           0x99U       /*!< reset memory */

/* register commands (SPI) */
#define GD25X512ME_READ_ID_CMD                                0x9FU       /* read identification */
#define GD25X512ME_READ_SERIAL_FLASH_DISCO_PARAM_CMD          0x5AU       /* read serial flash discoverable parameter */
#define GD25X512ME_READ_UNIQUE_ID_CMD                         0x4BU       /* read unique identification */

#define GD25X512ME_READ_STATUS_REG_CMD                        0x05U       /* read status register */
#define GD25X512ME_READ_FLAG_STATUS_REG_CMD                   0x70U       /* read flag status register */
#define GD25X512ME_READ_EXT_ADDR_REG_CMD                      0xC8U       /* read extended address register */
#define GD25X512ME_READ_NONVOLATILE_CFG_REG_CMD               0xB5U       /* read nonvolatile configuration register */
#define GD25X512ME_READ_VOLATILE_CFG_REG_CMD                  0x85U       /* read volatile configuration register */

#define GD25X512ME_WRITE_STATUS_REG_CMD                       0x01U       /* write status register */
#define GD25X512ME_WRITE_EXT_ADDR_REG_CMD                     0xC5U       /* write extended address register */
#define GD25X512ME_WRITE_ENABLE_VOLATILE_STATUS_CFG_CMD       0x50U       /* write enable for volatile status register */
#define GD25X512ME_WRITE_NONVOLATILE_CFG_REG_CMD              0xB1U       /* write nonvolatile configuration register */
#define GD25X512ME_WRITE_VOLATILE_CFG_REG_CMD                 0x81U       /* write volatile configuration register */

#define GD25X512ME_READ_SECURITY_REG_CMD                      0x48U       /* read security register */
#define GD25X512ME_PROG_SECURITY_REG_CMD                      0x42U       /* program security register */
#define GD25X512ME_ERASE_SECURITY_REG_CMD                     0x44U       /* erase Security register */

/* GD25X512ME registers */
/* status register */
#define GD25X512ME_SR_WIP                                     0x01U       /* write in progress */
#define GD25X512ME_SR_WEL                                     0x02U       /* write enable latch */
#define GD25X512ME_SR_PB                                      0x3CU       /* block protected against program and erase operations */

/* flag status register */
#define GD25X512ME_FSR_ADS                                    0x01U       /* current address mode */
#define GD25X512ME_FSR_PTE                                    0x02U       /* protection error bit */
#define GD25X512ME_FSR_SUS2                                   0x04U       /* program suspend */
#define GD25X512ME_FSR_PE                                     0x10U       /* program error bit */
#define GD25X512ME_FSR_EE                                     0x20U       /* erase error bit */
#define GD25X512ME_FSR_SUS1                                   0x40U       /* erase suspend */
#define GD25X512ME_FSR_RY_BY                                  0x80U       /* ready/busy */

/* extended address register */
#define GD25X512ME_EAR_A24                                    0x01U       /* address bit 24 */
#define GD25X512ME_EAR_A25                                    0x02U       /* address bit 25 */
#define GD25X512ME_EAR_SEC                                    0x80U       /* single error correction bit */

/* configuration register */
/* address : 0x00000000 */
#define GD25X512ME_CFG_REG0_ADDR                              0x00000000U  /* CFG register address 0x00000000 */
#define GD25X512ME_CFG_SPI                                    0xFFU        /* SPI */
#define GD25X512ME_CFG_SPI_WO                                 0xDFU        /* SPI W/O */
#define GD25X512ME_CFG_OCTAL_DTR                              0xE7U        /* Octal DTR with */
#define GD25X512ME_CFG_OCTAL_DTR_WO                           0xC7U        /* Octal DTR W/O */
#define GD25X512ME_CFG_OCTAL_STR                              0xB7U        /* Octal STR with */
#define GD25X512ME_CFG_OCTAL_STR_WO                           0x97U        /* Octal STR W/O */

/* address : 0x00000001 */
#define GD25X512ME_CFG_REG1_ADDR                              0x00000001U                         /* CFG register address 0x00000001 */
#define GD25X512ME_CFG_DUMMY_CYCLE(regval)                    (BITS(0,5) & (uint32_t)(regval))    /* 5~30 dummy cycle */
#define GD25X512ME_CFG_6_DUMMY_CYCLES                         0x06U                               /* 6 dummy cycles */
#define GD25X512ME_CFG_8_DUMMY_CYCLES                         0x08U                               /* 8 dummy cycles */
#define GD25X512ME_CFG_10_DUMMY_CYCLES                        0x0AU                               /* 10 dummy cycles */
#define GD25X512ME_CFG_12_DUMMY_CYCLES                        0x0CU                               /* 12 dummy cycles */
#define GD25X512ME_CFG_14_DUMMY_CYCLES                        0x0EU                               /* 14 dummy cycles */
#define GD25X512ME_CFG_16_DUMMY_CYCLES                        0x10U                               /* 16 dummy cycles(default) */
#define GD25X512ME_CFG_18_DUMMY_CYCLES                        0x12U                               /* 18 dummy cycles */
#define GD25X512ME_CFG_20_DUMMY_CYCLES                        0x14U                               /* 20 dummy cycles */

/* address : 0x00000002 */
#define GD25X512ME_CFG_REG2_ADDR                              0x00000002U                         /* CFG register address 0x00000002 */
#define GD25X512ME_CFG_SECURITY_REG_UNLOCKED                  0xF0U                               /* security register unlocked(default) */
#define GD25X512ME_CFG_SECURITY_REG_LOCKED                    0xF1U                               /* security register locked */
#define GD25X512ME_CFG_SRP1_UNLOCKED                          0x0FU                               /* SRP1 unlocked(default) */
#define GD25X512ME_CFG_SRP1_LOCKED                            0x1FU                               /* SRP1 locked */

/* Address : 0x00000003 */
#define GD25X512ME_CFG_REG3_ADDR                              0x00000003U                         /* CFG register address 0x00000003 */
#define GD25X512ME_CFG_50_OHM                                 0xFFU                               /* driver strength configuration 50 Ohm(default) */
#define GD25X512ME_CFG_35_OHM                                 0xFEU                               /* driver strength configuration 35 Ohm */
#define GD25X512ME_CFG_25_OHM                                 0xFDU                               /* driver strength configuration 25 Ohm */
#define GD25X512ME_CFG_18_OHM                                 0xFCU                               /* driver strength configuration 18 Ohm */

/* Address : 0x00000004 */
#define GD25X512ME_CFG_REG4_ADDR                              0x00000004U                         /* CFG register address 0x00000004 */
#define GD25X512ME_CFG_REG4(regval)                          (BITS(0,1) & (uint32_t)(regval))     /* follow below table */

/* address : 0x00000005 */
#define GD25X512ME_CFG_REG5_ADDR                              0x00000005U                         /* CFG register address 0x00000005 */
#define GD25X512ME_CFG_3_BYTE_ADDR                            0xFFU                               /* 3-bytes address(default) */
#define GD25X512ME_CFG_4_BYTE_ADDR                            0xFEU                               /* 4-bytes address */

/* Address : 0x00000006 */
#define GD25X512ME_CFG_REG6_ADDR                              0x00000006U                         /* CFG register address 0x00000006 */
#define GD25X512ME_CFG_XIP_DISABLE                            0xFFU                               /* XIP disable(default) */
#define GD25X512ME_CFG_XIP_ENABLE                             0xFEU                               /*!< XIP enable */

/* Address : 0x00000007 */
#define GD25X512ME_CFG_REG7_ADDR                              0x00000007U                         /*!< CFG register address 0x00000007 */
#define GD25X512ME_CFG_WRAP_DISABLE                           0xFFU                               /*!< Wrap disable(default) */
#define GD25X512ME_CFG_WRAP_64_BYTE                           0xFEU                               /*!< 64-Byte wrap */
#define GD25X512ME_CFG_WRAP_32_BYTE                           0xFDU                               /*!< 32-Byte wrap */
#define GD25X512ME_CFG_WRAP_16_BYTE                           0xFCU                               /*!< 16-Byte wrap */

#define DUMMY_CYCLES_READ_FAST                   8U
#define DUMMY_CYCLES_READ_FAST_OCTAL             16U
#define DUMMY_CYCLES_READ_OCTAL_OUTPUT           8U
#define DUMMY_CYCLES_READ_OCTAL_IO               16U
#define DUMMY_CYCLES_READ_SR_OCTAL               8U
#define DUMMY_CYCLES_READ_FSR_OCTAL              8U
#define DUMMY_CYCLES_READ_EAR_OCTAL              8U
#define DUMMY_CYCLES_READ_NONVOLATILE_CFG        8U
#define DUMMY_CYCLES_READ_VOLATILE_CFG           8U

typedef enum {
    SPI_MODE = 0,                             /* 1-1-1 commands, power on H/W default setting  */
    OSPI_MODE                                 /* 8-8-8 commands */
} interface_mode;

typedef enum {
    GD25X512ME_3BYTES_SIZE = 0,              /* 3 Bytes address mode */
    GD25X512ME_4BYTES_SIZE                   /* 4 Bytes address mode */
} addr_size;

typedef enum {
    GD25X512ME_ERASE_4K = 0,                 /* 4K size sector erase */
    GD25X512ME_ERASE_64K,                    /* 64K size block erase */
    GD25X512ME_ERASE_CHIP                    /* whole bulk erase */
} erase_size;

/* initialize OSPI/OSPIM and GPIO */
void ospi_flash_init(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct);
/* read the flah id */
uint32_t ospi_flash_read_id(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode);
/* enable flash reset */
void ospi_flash_reset_enable(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode);
/* reset the flash */
void ospi_flash_reset_memory(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode);
/* enable flash write */
void ospi_flash_write_enbale(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode);
/* write flash volatile configuration register */
void ospi_flash_write_volatilecfg_register(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode, addr_size addr_size,
        uint32_t addr, uint8_t value);
/* polling WIP(Write In Progress) bit become to 0 */
void ospi_flash_autopolling_mem_ready(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode);
/* erase the specified block of the flash */
void ospi_flash_block_erase(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode, addr_size addr_size, uint32_t addr,
                            erase_size block_size);
/* erase the the entire flash */
void ospi_flash_chip_erase(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode);
/* write data to the flash */
void ospi_flash_page_program(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode, addr_size addr_size, uint8_t *pdata,
                             uint32_t addr, uint32_t data_size);
/* read data from the flash */
void ospi_flash_read(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode, addr_size addr_size, uint8_t *pdata,
                     uint32_t addr, uint32_t data_size);
/* enable memory mapped mode */
void ospi_flash_memory_map_mode_enable(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode, addr_size addr_size);
/* enable memory mapped mode with wrap */
void ospi_flash_memory_map_mode_wrap_enable(uint32_t ospi_periph, ospi_parameter_struct *ospi_struct, interface_mode mode, addr_size addr_size);

#endif /* #define GD25X512ME_H */

 

2.3、main.c

#include "main.h"

#define GD25X512ME_ID              0xC8481AFF
#define OSPI_INTERFACE             OSPI0

uint8_t  txbuf[512];
uint8_t  rxbuf[512];

ospi_parameter_struct ospi_struct = {0};
uint32_t flashid = 0;

void cache_enable(void);

int main(void)
{
	cache_enable();
	systick_config();
	init_usart(115200);
	
	printf("\n\rGD25X512ME read/write test!\n\r");
	
	ospi_flash_init(OSPI_INTERFACE, &ospi_struct);
	
	/* reset ospi flash */
	ospi_flash_reset_enable(OSPI_INTERFACE, &ospi_struct, SPI_MODE);
	ospi_flash_reset_memory(OSPI_INTERFACE, &ospi_struct, SPI_MODE);
	
	/* 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);
		
			printf("\r\nwrite data buf:\r\n");
			for(uint16_t i=0;i<256;i++)
			{
				txbuf[i]=i;
				printf("%02x ",txbuf[i]);
			}
			
			/* 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_block_erase(OSPI_INTERFACE, &ospi_struct, SPI_MODE, GD25X512ME_3BYTES_SIZE, 0x000000, 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_page_program(OSPI_INTERFACE, &ospi_struct, SPI_MODE, GD25X512ME_3BYTES_SIZE, txbuf, 0x000000, 256);
			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);
			ospi_flash_read(OSPI_INTERFACE, &ospi_struct, SPI_MODE, GD25X512ME_3BYTES_SIZE, rxbuf, 0x000000, 256);

			printf("\r\nread data buf:\r\n");
			for(uint16_t x=0; x<256;x++)
			{
				printf("%02x ",rxbuf[x]);
			}
			
	}
	while(1)
	{
		
	}
}

void cache_enable(void)
{
    /* enable i-cache */
    SCB_EnableICache();

    /* enable d-cache */
    SCB_EnableDCache();
}

 

三、测试结果

 

下载程序后,串口输出内容

006.jpg

四、附件

 

程序源码:
gd32h759_prj_eeworld_ospi.rar (864.48 KB)
(下载次数: 5, 2024-6-12 21:52 上传)

 

 

本帖最后由 TL-LED 于 2024-6-12 21:52 编辑

回复评论 (1)

代码还是挺长的

最后给开发板供电,观察串口输出。如果一切正常,能看到从GD25x512ME Flash读取到的数据,与写入的数据一致。测试成功

点赞  2024-6-14 07:31
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复