//******************************************** Включаемые файлы *********************************************

#include "lmcal_cfg.h"
#include "lmcal_exmc_port.h"
#include "lmcal_ptim.h"

#include "gd32f4xx_rcu.h"
#include "gd32f4xx_gpio.h"
#include "gd32f4xx_exmc.h"


//******************************************* Локальные константы *******************************************

/* Define mode register content */
/* Burst Length */
#define SDRAM_MODEREG_BURST_LENGTH_1             ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2             ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4             ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8             ((uint16_t)0x0003)

/* Burst Type */
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL      ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED     ((uint16_t)0x0008)

/* CAS Latency */
#define SDRAM_MODEREG_CAS_LATENCY_2              ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3              ((uint16_t)0x0030)

/* Write Mode */
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE     ((uint16_t)0x0200)

#define SDRAM_MODEREG_OPERATING_MODE_STANDARD    ((uint16_t)0x0000)

#define SDRAM_TIMEOUT                            ((uint32_t)0x0000FFFF)

#define SDRAM_DEVICE0_ADDR                       ((uint32_t)0xC0000000)
#define SDRAM_DEVICE1_ADDR                       ((uint32_t)0xD0000000)



//******************************************* Проверка параметров *******************************************


//******************************************** Определения типов ********************************************


//************************************ Глобальные (публичные) переменные ************************************


//************************************* Локальные (приватные) переменные ************************************


//***********************************************************************************************************
//******************************** Определения локальных (приватных) функций ********************************
//***********************************************************************************************************

static void f_init_pin(u32 port, u32 pin, u32 af, u32 pull)
{
    gpio_af_set(port, af, pin);
    gpio_mode_set(port, GPIO_MODE_AF, pull, pin);
    gpio_output_options_set(port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, pin);
}


//-----------------------------------------------------------------------------------------------------------
// Инициализация всех ножек
//-----------------------------------------------------------------------------------------------------------
static void exmc_pins_init(void)
{
    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);
    rcu_periph_clock_enable(RCU_GPIOF);
    rcu_periph_clock_enable(RCU_GPIOG);
    rcu_periph_clock_enable(RCU_GPIOH);

    // Шина Data
    f_init_pin(LMCAL_SDRAM_D0_PORT, LMCAL_SDRAM_D0_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_D1_PORT, LMCAL_SDRAM_D1_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_D2_PORT, LMCAL_SDRAM_D2_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_D3_PORT, LMCAL_SDRAM_D3_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_D4_PORT, LMCAL_SDRAM_D4_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_D5_PORT, LMCAL_SDRAM_D5_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_D6_PORT, LMCAL_SDRAM_D6_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_D7_PORT, LMCAL_SDRAM_D7_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_D8_PORT, LMCAL_SDRAM_D8_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_D9_PORT, LMCAL_SDRAM_D9_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_D10_PORT, LMCAL_SDRAM_D10_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_D11_PORT, LMCAL_SDRAM_D11_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_D12_PORT, LMCAL_SDRAM_D12_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_D13_PORT, LMCAL_SDRAM_D13_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_D14_PORT, LMCAL_SDRAM_D14_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_D15_PORT, LMCAL_SDRAM_D15_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);

    // Шина Addr
    f_init_pin(LMCAL_SDRAM_A0_PORT, LMCAL_SDRAM_A0_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_A1_PORT, LMCAL_SDRAM_A1_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_A2_PORT, LMCAL_SDRAM_A2_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_A3_PORT, LMCAL_SDRAM_A3_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_A4_PORT, LMCAL_SDRAM_A4_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_A5_PORT, LMCAL_SDRAM_A5_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_A6_PORT, LMCAL_SDRAM_A6_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_A7_PORT, LMCAL_SDRAM_A7_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_A8_PORT, LMCAL_SDRAM_A8_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_A9_PORT, LMCAL_SDRAM_A9_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_A10_PORT, LMCAL_SDRAM_A10_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_A11_PORT, LMCAL_SDRAM_A11_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_A12_PORT, LMCAL_SDRAM_A12_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    // 
    f_init_pin(LMCAL_SDRAM_BA0_PORT, LMCAL_SDRAM_BA0_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_BA1_PORT, LMCAL_SDRAM_BA1_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);

    // NE0, KE0
    f_init_pin(LMCAL_SDRAM_NE0_PORT, LMCAL_SDRAM_NE0_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_KE0_PORT, LMCAL_SDRAM_KE0_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_RAS_PORT, LMCAL_SDRAM_RAS_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_CLK_PORT, LMCAL_SDRAM_CLK_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_CAS_PORT, LMCAL_SDRAM_CAS_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);
    f_init_pin(LMCAL_SDRAM_NWE_PORT, LMCAL_SDRAM_NWE_PIN, GPIO_AF_12, GPIO_PUPD_PULLUP);

} // exmc_pins_init



//-----------------------------------------------------------------------------------------------------------
/*!
    \brief      initialize sdram peripheral
    \param[in]  sdram_device: specify the SDRAM device
    \param[out] none
    \retval     none
*/
//-----------------------------------------------------------------------------------------------------------
static void exmc_synchronous_dynamic_ram_init(uint32_t sdram_device)
{
    exmc_sdram_parameter_struct        sdram_init_struct;
    exmc_sdram_timing_parameter_struct  sdram_timing_init_struct;
    exmc_sdram_command_parameter_struct     sdram_command_init_struct;

    uint32_t command_content = 0, bank_select;
    uint32_t timeout = SDRAM_TIMEOUT;

    /* specify which SDRAM to read and write */
    if(EXMC_SDRAM_DEVICE0 == sdram_device) {
        bank_select = EXMC_SDRAM_DEVICE0_SELECT;
    } else {
        bank_select = EXMC_SDRAM_DEVICE1_SELECT;
    }

    /* EXMC SDRAM device initialization sequence --------------------------------*/
    /* Step 1 : configure SDRAM timing registers --------------------------------*/
    /* LMRD: 2 clock cycles */
    sdram_timing_init_struct.load_mode_register_delay = 2;
    /* XSRD: min = 67ns */
    sdram_timing_init_struct.exit_selfrefresh_delay = 7;
    /* RASD: min=42ns , max=120k (ns) */
    sdram_timing_init_struct.row_address_select_delay = 5;
    /* ARFD: min=60ns */
    sdram_timing_init_struct.auto_refresh_delay = 6;
    /* WRD:  min=1 Clock cycles +6ns */
    sdram_timing_init_struct.write_recovery_delay = 2;
    /* RPD:  min=18ns */
    sdram_timing_init_struct.row_precharge_delay = 2;
    /* RCD:  min=18ns */
    sdram_timing_init_struct.row_to_column_delay = 2;

    /* step 2 : configure SDRAM control registers ---------------------------------*/
    sdram_init_struct.sdram_device = sdram_device;
    sdram_init_struct.column_address_width = EXMC_SDRAM_COW_ADDRESS_9;
    sdram_init_struct.row_address_width = EXMC_SDRAM_ROW_ADDRESS_13;
    sdram_init_struct.data_width = EXMC_SDRAM_DATABUS_WIDTH_16B;
    sdram_init_struct.internal_bank_number = EXMC_SDRAM_4_INTER_BANK;

    sdram_init_struct.cas_latency = EXMC_CAS_LATENCY_2_SDCLK;
    sdram_init_struct.write_protection = DISABLE;
    sdram_init_struct.sdclock_config = EXMC_SDCLK_PERIODS_2_HCLK;
    sdram_init_struct.burst_read_switch = ENABLE;
    sdram_init_struct.pipeline_read_delay = EXMC_PIPELINE_DELAY_1_HCLK;
    sdram_init_struct.timing  = &sdram_timing_init_struct;

    /* EXMC SDRAM bank initialization */
    exmc_sdram_init(&sdram_init_struct);

    /* step 3 : configure CKE high command---------------------------------------*/
    sdram_command_init_struct.command = EXMC_SDRAM_CLOCK_ENABLE;
    sdram_command_init_struct.bank_select = bank_select;
    sdram_command_init_struct.auto_refresh_number = EXMC_SDRAM_AUTO_REFLESH_2_SDCLK;
    sdram_command_init_struct.mode_register_content = 0;

    /* wait until the SDRAM controller is ready */
    while((exmc_flag_get(sdram_device, EXMC_SDRAM_FLAG_NREADY) != RESET) && (timeout > 0)) {
        timeout--;
    }
    /* send the command */
    exmc_sdram_command_config(&sdram_command_init_struct);


    /* step 4 : insert 10ms delay----------------------------------------------*/
    lmcal_ptim_delay(10);


    /* step 5 : configure precharge all command----------------------------------*/
    sdram_command_init_struct.command = EXMC_SDRAM_PRECHARGE_ALL;
    sdram_command_init_struct.bank_select = bank_select;
    sdram_command_init_struct.auto_refresh_number = EXMC_SDRAM_AUTO_REFLESH_2_SDCLK;
    sdram_command_init_struct.mode_register_content = 0;
    
    
    /* wait until the SDRAM controller is ready */
    timeout = SDRAM_TIMEOUT;
    while((exmc_flag_get(sdram_device, EXMC_SDRAM_FLAG_NREADY) != RESET) && (timeout > 0)) {
        timeout--;
    }
    /* send the command */
    exmc_sdram_command_config(&sdram_command_init_struct);

    /* step 6 : configure Auto-Refresh command-----------------------------------*/
    sdram_command_init_struct.command = EXMC_SDRAM_AUTO_REFRESH;
    sdram_command_init_struct.bank_select = bank_select;
    sdram_command_init_struct.auto_refresh_number = EXMC_SDRAM_AUTO_REFLESH_9_SDCLK;
    sdram_command_init_struct.mode_register_content = 0;
    /* wait until the SDRAM controller is ready */
    timeout = SDRAM_TIMEOUT;
    while((exmc_flag_get(sdram_device, EXMC_SDRAM_FLAG_NREADY) != RESET) && (timeout > 0)) {
        timeout--;
    }
    /* send the command */
    exmc_sdram_command_config(&sdram_command_init_struct);

    /* step 7 : configure load mode register command-----------------------------*/
    /* program mode register */
    command_content = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1        |
                                SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |
                                SDRAM_MODEREG_CAS_LATENCY_2           |
                                SDRAM_MODEREG_OPERATING_MODE_STANDARD |
                                SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;         

    sdram_command_init_struct.command = EXMC_SDRAM_LOAD_MODE_REGISTER;
    sdram_command_init_struct.bank_select = bank_select;
    sdram_command_init_struct.auto_refresh_number = EXMC_SDRAM_AUTO_REFLESH_1_SDCLK;
    sdram_command_init_struct.mode_register_content = command_content;

    /* wait until the SDRAM controller is ready */
    timeout = SDRAM_TIMEOUT;
    while((exmc_flag_get(sdram_device, EXMC_SDRAM_FLAG_NREADY) != RESET) && (timeout > 0)) {
        timeout--;
    }
    /* send the command */
    exmc_sdram_command_config(&sdram_command_init_struct);

    /* step 8 : set the auto-refresh rate counter--------------------------------*/
    /* 64ms, 8192-cycle refresh, 64ms/8192=7.81us */
    /* SDCLK_Freq = SYS_Freq/2 */
    /* (7.81 us * SDCLK_Freq) - 20 */
    exmc_sdram_refresh_count_set(761);

    /* wait until the SDRAM controller is ready */
    timeout = SDRAM_TIMEOUT;
    while((exmc_flag_get(sdram_device, EXMC_SDRAM_FLAG_NREADY) != RESET) && (timeout > 0)) {
        timeout--;
    }
}


//***********************************************************************************************************
//******************************** Определения процедур обработки прерываний ********************************
//***********************************************************************************************************



//***********************************************************************************************************
//******************************* Определения глобальных (публичных) функций ********************************
//***********************************************************************************************************

fun_res_t lmcal_exmc_port_init(void)
{
    fun_res_t err = ERR_OK;
    
    // SDRAM

    /* enable EXMC clock */
    rcu_periph_clock_enable(RCU_EXMC);

    // Инициализация ножек
    exmc_pins_init();

    // Примечание:
    // 1) на плате GD32450I_EVAL выполнена доработка: замена PC5 на PC3 для
    // совместной работы SDRAM и ETH
    // 2) Настройки таймингов установлены для HCLK = 200 МГц, где
    // частота CLK SDRAM = HCLK/2
    // Тайминги памяти задаются внутри модуля:
    exmc_synchronous_dynamic_ram_init(EXMC_SDRAM_DEVICE0);
    
    return err;
}


fun_res_t lmcal_exmc_port_deinit(void)
{
    fun_res_t err = ERR_OK;
    
    exmc_sdram_deinit(EXMC_SDRAM_DEVICE0);
    
    return err;
}



//*********************************************** КОНЕЦ ФАЙЛА ***********************************************

#if 0
#define SDRAM_DEFAULT                   (0U)
#define SDRAM_GD32450I_EVAL             (1U) // MT48LC16M16A2P_6AIT
#define SDRAM_LTA                       (2U) // K4S561632H_UI75

#define SDRAM_TYPE                      (SDRAM_GD32450I_EVAL)  

    // Так как шина общая между разными интерфейсами, то выносим наверх инициализацию ног Данных и Адреса

    /* D2(PD0),D3(PD1),D13(PD8),D14(PD9),D15(PD10),D0(PD14),D1(PD15) pin configuration */
    // gpio_af_set(GPIOD, GPIO_AF_12, GPIO_PIN_0  | GPIO_PIN_1  | GPIO_PIN_8 | GPIO_PIN_9 |
    //             GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);
    // gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_0  | GPIO_PIN_1  | GPIO_PIN_8 | GPIO_PIN_9 |
    //             GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);
    // gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0  | GPIO_PIN_1  | GPIO_PIN_8 | GPIO_PIN_9 |
    //                         GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);


    /* D4(PE7),D5(PE8),D6(PE9),D7(PE10),D8(PE11),D9(PE12),D10(PE13),D11(PE14),D12(PE15) pin configuration */
    // gpio_af_set(GPIOE, GPIO_AF_12,  
    //             GPIO_PIN_7  | GPIO_PIN_8 |
    //             GPIO_PIN_9  | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |
    //             GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
    // gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_PULLUP,   
    //             GPIO_PIN_7  | GPIO_PIN_8 |
    //             GPIO_PIN_9  | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |
    //             GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
    // gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,   
    //                         GPIO_PIN_7  | GPIO_PIN_8 |
    //                         GPIO_PIN_9  | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |
    //                         GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);


    /* A0(PF0),A1(PF1),A2(PF2),A3(PF3),A4(PF4),A5(PF5),A6(PF12),A7(PF13),A8(PF14),A9(PF15) pin configuration */
    // gpio_af_set(GPIOF, GPIO_AF_12, 
    //             GPIO_PIN_0  | GPIO_PIN_1  | GPIO_PIN_2  | GPIO_PIN_3  |
    //             GPIO_PIN_4  | GPIO_PIN_5  | GPIO_PIN_12 |
    //             GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
    // gpio_mode_set(GPIOF, GPIO_MODE_AF, GPIO_PUPD_PULLUP, 
    //             GPIO_PIN_0  | GPIO_PIN_1  | GPIO_PIN_2  | GPIO_PIN_3  |
    //             GPIO_PIN_4  | GPIO_PIN_5  | GPIO_PIN_12 |
    //             GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
    // gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, 
    //                         GPIO_PIN_0  | GPIO_PIN_1  | GPIO_PIN_2  | GPIO_PIN_3  |
    //                         GPIO_PIN_4  | GPIO_PIN_5  | GPIO_PIN_12 |
    //                         GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);

    /* A10(PG0),A11(PG1),A12(PG2),A14(PG4),A15(PG5) pin configuration */
    // gpio_af_set(GPIOG, GPIO_AF_12, 
    //             GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 |
    //             GPIO_PIN_5);
    // gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_PULLUP, 
    //             GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 |
    //             GPIO_PIN_5);
    // gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, 
    //                         GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 |
    //                         GPIO_PIN_5);          

    // SDRAM
    
    /* common GPIO configuration */

    /* SDNE0(PC2),SDCKE0(PC3) pin configuration */
    // gpio_af_set(GPIOC, GPIO_AF_12, GPIO_PIN_2 | GPIO_PIN_3);
    // gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2 | GPIO_PIN_3);
    // gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2 | GPIO_PIN_3);

    /* NRAS(PF11) pin configuration */
    // gpio_af_set(GPIOF, GPIO_AF_12, 
    //             GPIO_PIN_11);
    // gpio_mode_set(GPIOF, GPIO_MODE_AF, GPIO_PUPD_PULLUP, 
    //             GPIO_PIN_11);
    // gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, 
    //                         GPIO_PIN_11);

    /*SDCLK(PG8),NCAS(PG15) pin configuration */
    // gpio_af_set(GPIOG, GPIO_AF_12, 
    //             GPIO_PIN_8 | GPIO_PIN_15);
    // gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_PULLUP, 
    //             GPIO_PIN_8 | GPIO_PIN_15);
    // gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, 
    //                         GPIO_PIN_8 | GPIO_PIN_15);
    
    // #if (SDRAM_TYPE == SDRAM_GD32450I_EVAL)
    // /* SDNWE(PH5) pin configuration */
    // gpio_af_set(GPIOH, GPIO_AF_12, GPIO_PIN_5);
    // gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_5);
    // gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5);

    // #elif (SDRAM_TYPE == SDRAM_LTA)
    // /* SDNWE(C0) pin configuration */
    // gpio_af_set(GPIOC, GPIO_AF_12, GPIO_PIN_0);
    // gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_0);
    // gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0);

    // #endif



    #if (SDRAM_TYPE == SDRAM_DEFAULT)
    /* EXMC SDRAM device initialization sequence --------------------------------*/
    /* Step 1 : configure SDRAM timing registers --------------------------------*/
    /* LMRD: 2 clock cycles */
    sdram_timing_init_struct.load_mode_register_delay = 2;
    /* XSRD: min = 67ns */
    sdram_timing_init_struct.exit_selfrefresh_delay = 7;
    /* RASD: min=42ns , max=120k (ns) */
    sdram_timing_init_struct.row_address_select_delay = 5;
    /* ARFD: min=60ns */
    sdram_timing_init_struct.auto_refresh_delay = 6;
    /* WRD:  min=1 Clock cycles +6ns */
    sdram_timing_init_struct.write_recovery_delay = 2;
    /* RPD:  min=18ns */
    sdram_timing_init_struct.row_precharge_delay = 2;
    /* RCD:  min=18ns */
    sdram_timing_init_struct.row_to_column_delay = 2;

    /* step 2 : configure SDRAM control registers ---------------------------------*/
    sdram_init_struct.sdram_device = sdram_device;
    sdram_init_struct.column_address_width = EXMC_SDRAM_COW_ADDRESS_9;
    sdram_init_struct.row_address_width = EXMC_SDRAM_ROW_ADDRESS_13;
    sdram_init_struct.data_width = EXMC_SDRAM_DATABUS_WIDTH_16B;
    sdram_init_struct.internal_bank_number = EXMC_SDRAM_4_INTER_BANK;

    sdram_init_struct.cas_latency = EXMC_CAS_LATENCY_3_SDCLK;
    sdram_init_struct.write_protection = DISABLE;
    sdram_init_struct.sdclock_config = EXMC_SDCLK_PERIODS_3_HCLK;
    sdram_init_struct.burst_read_switch = ENABLE;
    sdram_init_struct.pipeline_read_delay = EXMC_PIPELINE_DELAY_2_HCLK;
    sdram_init_struct.timing  = &sdram_timing_init_struct;
    
    #if (SDRAM_TYPE == SDRAM_DEFAULT)
    command_content = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1        |
                                SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |
                                SDRAM_MODEREG_CAS_LATENCY_3           |
                                SDRAM_MODEREG_OPERATING_MODE_STANDARD |
                                SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;             
    #elif (SDRAM_TYPE == SDRAM_GD32450I_EVAL)
    command_content = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1        |
                                SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |
                                SDRAM_MODEREG_CAS_LATENCY_2           |
                                SDRAM_MODEREG_OPERATING_MODE_STANDARD |
                                SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;    
    #elif (SDRAM_TYPE == SDRAM_LTA)
    command_content = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1        |
                                SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |
                                SDRAM_MODEREG_CAS_LATENCY_2           |
                                SDRAM_MODEREG_OPERATING_MODE_STANDARD |
                                SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;    
    #endif        
#endif


    #if (SDRAM_TYPE == SDRAM_LTA)
    /* EXMC SDRAM device initialization sequence --------------------------------*/
    /* Step 1 : configure SDRAM timing registers --------------------------------*/
    /* LMRD: 2 clock cycles */
    sdram_timing_init_struct.load_mode_register_delay = 2;
    /* XSRD: min = 67ns */
    sdram_timing_init_struct.exit_selfrefresh_delay = 7;
    /* RASD: min=42ns , max=120k (ns) */
    sdram_timing_init_struct.row_address_select_delay = 5;
    /* ARFD: min=60ns */
    sdram_timing_init_struct.auto_refresh_delay = 6;
    /* WRD:  min=1 Clock cycles +6ns */
    sdram_timing_init_struct.write_recovery_delay = 2;
    /* RPD:  min=18ns */
    sdram_timing_init_struct.row_precharge_delay = 2;
    /* RCD:  min=18ns */
    sdram_timing_init_struct.row_to_column_delay = 2;

    /* step 2 : configure SDRAM control registers ---------------------------------*/
    sdram_init_struct.sdram_device = sdram_device;
    sdram_init_struct.column_address_width = EXMC_SDRAM_COW_ADDRESS_9;
    sdram_init_struct.row_address_width = EXMC_SDRAM_ROW_ADDRESS_13;
    sdram_init_struct.data_width = EXMC_SDRAM_DATABUS_WIDTH_16B;
    sdram_init_struct.internal_bank_number = EXMC_SDRAM_4_INTER_BANK;

    sdram_init_struct.cas_latency = EXMC_CAS_LATENCY_2_SDCLK;
    sdram_init_struct.write_protection = DISABLE;
    sdram_init_struct.sdclock_config = EXMC_SDCLK_PERIODS_2_HCLK;
    sdram_init_struct.burst_read_switch = ENABLE;
    sdram_init_struct.pipeline_read_delay = EXMC_PIPELINE_DELAY_1_HCLK;
    sdram_init_struct.timing  = &sdram_timing_init_struct;
    
    #endif
#endif