diff --git a/Makefile b/Makefile index 962f19c..c2de10e 100644 --- a/Makefile +++ b/Makefile @@ -143,6 +143,7 @@ lib_srcs += \ $(lib_dir)/serial.c \ $(lib_dir)/vrom.c \ $(lib_dir)/sdram.c \ + $(lib_dir)/is42s32800g.c \ $(lib_dir)/ymodem.c \ $(lib_dir)/eeprom.c \ diff --git a/cmsis/src/system_stm32f4xx.c b/cmsis/src/system_stm32f4xx.c index c19800a..b623c04 100644 --- a/cmsis/src/system_stm32f4xx.c +++ b/cmsis/src/system_stm32f4xx.c @@ -507,6 +507,9 @@ void SystemInit(void) #if defined(DATA_IN_ExtSRAM) || defined(DATA_IN_ExtSDRAM) SystemInit_ExtMemCtl(); +#elif defined(SDRAM_IS42S32800G) + extern void sdram_init(); + sdram_init(); #endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */ /* Configure the System clock source, PLL Multiplier and Divider factors, diff --git a/lib/is42s32800g.c b/lib/is42s32800g.c new file mode 100644 index 0000000..147f5f1 --- /dev/null +++ b/lib/is42s32800g.c @@ -0,0 +1,348 @@ +#ifdef SDRAM_IS42S32800G +#include "stm32f4xx.h" +#include "sdram.h" + +/** + * @brief Configures the FMC and GPIOs to interface with the SDRAM memory. + * This function must be called before any read/write operation + * on the SDRAM. + * @param None + * @retval None + */ +void sdram_init(void) +{ + FMC_SDRAMInitTypeDef FMC_SDRAMInitStructure; + FMC_SDRAMTimingInitTypeDef FMC_SDRAMTimingInitStructure; + + /* GPIO configuration for FMC SDRAM bank */ + sdram_gpio_config(); + + /* Enable FMC clock */ + RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE); + +/* FMC Configuration ---------------------------------------------------------*/ +/* FMC SDRAM Bank configuration */ + /* Timing configuration for 90 Mhz of SD clock frequency (180Mhz/2) */ + /* TMRD: 2 Clock cycles */ + FMC_SDRAMTimingInitStructure.FMC_LoadToActiveDelay = 2; + /* TXSR: min=70ns (7x11.11ns) */ + FMC_SDRAMTimingInitStructure.FMC_ExitSelfRefreshDelay = 7; + /* TRAS: min=42ns (4x11.11ns) max=120k (ns) */ + FMC_SDRAMTimingInitStructure.FMC_SelfRefreshTime = 4; + /* TRC: min=70 (7x11.11ns) */ + FMC_SDRAMTimingInitStructure.FMC_RowCycleDelay = 7; + /* TWR: min=1+ 7ns (1+1x11.11ns) */ + FMC_SDRAMTimingInitStructure.FMC_WriteRecoveryTime = 2; + /* TRP: 20ns => 2x11.11ns */ + FMC_SDRAMTimingInitStructure.FMC_RPDelay = 2; + /* TRCD: 20ns => 2x11.11ns */ + FMC_SDRAMTimingInitStructure.FMC_RCDDelay = 2; + +/* FMC SDRAM control configuration */ + FMC_SDRAMInitStructure.FMC_Bank = FMC_Bank1_SDRAM; + /* Row addressing: [7:0] */ + FMC_SDRAMInitStructure.FMC_ColumnBitsNumber = FMC_ColumnBits_Number_8b; + /* Column addressing: [10:0] */ + FMC_SDRAMInitStructure.FMC_RowBitsNumber = FMC_RowBits_Number_13b; + FMC_SDRAMInitStructure.FMC_SDMemoryDataWidth = SDRAM_MEMORY_WIDTH; + FMC_SDRAMInitStructure.FMC_InternalBankNumber = FMC_InternalBank_Number_4; + /* CL: Cas Latency = 3 clock cycles */ + FMC_SDRAMInitStructure.FMC_CASLatency = FMC_CAS_Latency_3; + FMC_SDRAMInitStructure.FMC_WriteProtection = FMC_Write_Protection_Disable; + FMC_SDRAMInitStructure.FMC_SDClockPeriod = SDCLOCK_PERIOD; + FMC_SDRAMInitStructure.FMC_ReadBurst = FMC_Read_Burst_Enable; + FMC_SDRAMInitStructure.FMC_ReadPipeDelay = FMC_ReadPipe_Delay_1; + FMC_SDRAMInitStructure.FMC_SDRAMTimingStruct = &FMC_SDRAMTimingInitStructure; + + /* FMC SDRAM bank initialization */ + FMC_SDRAMInit(&FMC_SDRAMInitStructure); + + /* FMC SDRAM device initialization sequence */ + sdram_init_sequence(); +} + +/** + * @brief Configures all SDRAM memory I/Os pins. + * @param None. + * @retval None. + */ +void sdram_gpio_config(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + + /* Enable GPIOs clock */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE | + RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOH | + RCC_AHB1Periph_GPIOI, ENABLE); + +/*-- GPIOs Configuration -----------------------------------------------------*/ +/* + +-------------------+--------------------+--------------------+--------------------+ + + SDRAM pins assignment + + +-------------------+--------------------+--------------------+--------------------+ + | PD0 <-> FMC_D2 | PE0 <-> FMC_NBL0 | PF0 <-> FMC_A0 | PG0 <-> FMC_A10 | + | PD1 <-> FMC_D3 | PE1 <-> FMC_NBL1 | PF1 <-> FMC_A1 | PG1 <-> FMC_A11 | + | PD8 <-> FMC_D13 | PE7 <-> FMC_D4 | PF2 <-> FMC_A2 | PG4 <-> FMC_A14 | + | PD9 <-> FMC_D14 | PE8 <-> FMC_D5 | PF3 <-> FMC_A3 | PG5 <-> FMC_A15 | + | PD10 <-> FMC_D15 | PE9 <-> FMC_D6 | PF4 <-> FMC_A4 | PG8 <-> FC_SDCLK | + | PD14 <-> FMC_D0 | PE10 <-> FMC_D7 | PF5 <-> FMC_A5 | PG15 <-> FMC_NCAS | + | PD15 <-> FMC_D1 | PE11 <-> FMC_D8 | PF11 <-> FC_NRAS |--------------------+ + +-------------------| PE12 <-> FMC_D9 | PF12 <-> FMC_A6 | + | PE13 <-> FMC_D10 | PF13 <-> FMC_A7 | + | PE14 <-> FMC_D11 | PF14 <-> FMC_A8 | + | PE15 <-> FMC_D12 | PF15 <-> FMC_A9 | + +-------------------+--------------------+--------------------+ + | PH2 <-> FMC_SDCKE0| PI4 <-> FMC_NBL2 | + | PH3 <-> FMC_SDNE0 | PI5 <-> FMC_NBL3 | + | PH5 <-> FMC_SDNW |--------------------+ + +-------------------+ + +-------------------+------------------+ + + 32-bits Mode: D31-D16 + + +-------------------+------------------+ + | PH8 <-> FMC_D16 | PI0 <-> FMC_D24 | + | PH9 <-> FMC_D17 | PI1 <-> FMC_D25 | + | PH10 <-> FMC_D18 | PI2 <-> FMC_D26 | + | PH11 <-> FMC_D19 | PI3 <-> FMC_D27 | + | PH12 <-> FMC_D20 | PI6 <-> FMC_D28 | + | PH13 <-> FMC_D21 | PI7 <-> FMC_D29 | + | PH14 <-> FMC_D22 | PI9 <-> FMC_D30 | + | PH15 <-> FMC_D23 | PI10 <-> FMC_D31 | + +------------------+-------------------+ + + +-------------------+ + + Pins remapping + + +-------------------+ + | PC0 <-> FMC_SDNWE | + | PC2 <-> FMC_SDNE0 | + | PC3 <-> FMC_SDCKE0| + +-------------------+ + +*/ + + /* Common GPIO configuration */ + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + + /* GPIOD configuration */ + GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOD, GPIO_PinSource10, GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_FMC); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1 |GPIO_Pin_8 |GPIO_Pin_9 | + GPIO_Pin_10 |GPIO_Pin_14 |GPIO_Pin_15; + + GPIO_Init(GPIOD, &GPIO_InitStructure); + + /* GPIOE configuration */ + GPIO_PinAFConfig(GPIOE, GPIO_PinSource0 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOE, GPIO_PinSource1 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOE, GPIO_PinSource7 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOE, GPIO_PinSource8 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOE, GPIO_PinSource9 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOE, GPIO_PinSource10 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOE, GPIO_PinSource11 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOE, GPIO_PinSource12 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOE, GPIO_PinSource13 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOE, GPIO_PinSource14 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOE, GPIO_PinSource15 , GPIO_AF_FMC); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | 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_Init(GPIOE, &GPIO_InitStructure); + + /* GPIOF configuration */ + GPIO_PinAFConfig(GPIOF, GPIO_PinSource0 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOF, GPIO_PinSource1 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOF, GPIO_PinSource2 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOF, GPIO_PinSource3 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOF, GPIO_PinSource4 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOF, GPIO_PinSource5 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOF, GPIO_PinSource11 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOF, GPIO_PinSource12 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOF, GPIO_PinSource13 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOF, GPIO_PinSource14 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOF, GPIO_PinSource15 , GPIO_AF_FMC); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | + GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_11 | GPIO_Pin_12 | + GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; + + GPIO_Init(GPIOF, &GPIO_InitStructure); + + /* GPIOG configuration */ + GPIO_PinAFConfig(GPIOG, GPIO_PinSource0 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOG, GPIO_PinSource1 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOG, GPIO_PinSource4 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOG, GPIO_PinSource5 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOG, GPIO_PinSource8 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOG, GPIO_PinSource15 , GPIO_AF_FMC); + + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1 |GPIO_Pin_4 |GPIO_Pin_5 | + GPIO_Pin_8 | GPIO_Pin_15; + + GPIO_Init(GPIOG, &GPIO_InitStructure); + + /* GPIOH configuration */ + GPIO_PinAFConfig(GPIOH, GPIO_PinSource2 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOH, GPIO_PinSource3 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOH, GPIO_PinSource5 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOH, GPIO_PinSource8 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOH, GPIO_PinSource9 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOH, GPIO_PinSource10 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOH, GPIO_PinSource11 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOH, GPIO_PinSource12 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOH, GPIO_PinSource13 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOH, GPIO_PinSource14 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOH, GPIO_PinSource15 , GPIO_AF_FMC); + + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_5 | 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_Init(GPIOH, &GPIO_InitStructure); + + /* GPIOI configuration */ + GPIO_PinAFConfig(GPIOI, GPIO_PinSource0 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOI, GPIO_PinSource1 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOI, GPIO_PinSource2 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOI, GPIO_PinSource3 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOI, GPIO_PinSource4 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOI, GPIO_PinSource5 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOI, GPIO_PinSource6 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOI, GPIO_PinSource7 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOI, GPIO_PinSource9 , GPIO_AF_FMC); + GPIO_PinAFConfig(GPIOI, GPIO_PinSource10 , GPIO_AF_FMC); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | + GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 | + GPIO_Pin_9 | GPIO_Pin_10; + + GPIO_Init(GPIOI, &GPIO_InitStructure); + +} + +/** + * @brief Executes the SDRAM memory initialization sequence. + * @param None. + * @retval None. + */ +void sdram_init_sequence(void) +{ + FMC_SDRAMCommandTypeDef FMC_SDRAMCommandStructure; + uint32_t tmpr = 0; + uint32_t timeout = SDRAM_TIMEOUT; + +/* Step 3 --------------------------------------------------------------------*/ + /* Configure a clock configuration enable command */ + FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_CLK_Enabled; + FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank1; + FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1; + FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0; + /* Wait until the SDRAM controller is ready */ + while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0)) + { + timeout--; + } + /* Send the command */ + FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure); + +/* Step 4 --------------------------------------------------------------------*/ + /* Insert 100 ms delay */ + __Delay(10); + +/* Step 5 --------------------------------------------------------------------*/ + /* Configure a PALL (precharge all) command */ + FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_PALL; + FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank1; + FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1; + FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0; + + /* Wait until the SDRAM controller is ready */ + timeout = SDRAM_TIMEOUT; + while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0)) + { + timeout--; + } + /* Send the command */ + FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure); + +/* Step 6 --------------------------------------------------------------------*/ + /* Configure a Auto-Refresh command */ + FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_AutoRefresh; + FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank1; + FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 8; + FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0; + + /* Wait until the SDRAM controller is ready */ + timeout = SDRAM_TIMEOUT; + while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0)) + { + timeout--; + } + /* Send the command */ + FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure); + +/* Step 7 --------------------------------------------------------------------*/ + /* Program the external memory mode register */ + tmpr = (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; + + /* Configure a load Mode register command*/ + FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_LoadMode; + FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank1; + FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1; + FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = tmpr; + + /* Wait until the SDRAM controller is ready */ + timeout = SDRAM_TIMEOUT; + while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0)) + { + timeout--; + } + /* Send the command */ + FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure); + +/* Step 8 --------------------------------------------------------------------*/ + + /* Set the refresh rate counter */ + /* (15.62 us x Freq) - 20 */ + /* Set the device refresh counter */ + FMC_SetRefreshCount(1385); + + /* Wait until the SDRAM controller is ready */ + timeout = SDRAM_TIMEOUT; + while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0)) + { + timeout--; + } +} + +#ifndef USE_Delay +/** + * @brief Inserts a delay time. + * @param nCount: specifies the delay time length. + * @retval None + */ +static void delay(__IO uint32_t nCount) +{ + __IO uint32_t index = 0; + for(index = (100000 * nCount); index != 0; index--) + { + } +} +#endif /* USE_Delay */ +#endif + diff --git a/lib/sdram.c b/lib/sdram.c index 561bd15..91f7d16 100644 --- a/lib/sdram.c +++ b/lib/sdram.c @@ -1,3 +1,4 @@ +#ifdef DATA_IN_ExtSDRAM #include "stm32f4xx.h" #include "sdram.h" @@ -364,4 +365,4 @@ static void delay(__IO uint32_t nCount) } } #endif /* USE_Delay */ - +#endif diff --git a/lib/sdram.h b/lib/sdram.h index 050dbef..79b699b 100644 --- a/lib/sdram.h +++ b/lib/sdram.h @@ -9,10 +9,14 @@ * @{ */ +#ifdef DATA_IN_ExtSDRAM /** * @brief FMC SDRAM Bank address */ #define SDRAM_BANK_ADDR ((uint32_t)0xD0000000) +#else +#define SDRAM_BANK_ADDR ((uint32_t)0xC0000000) +#endif /** * @} */ @@ -21,8 +25,11 @@ * @brief FMC SDRAM Memory Width */ /* #define SDRAM_MEMORY_WIDTH FMC_SDMemory_Width_8b */ +#ifdef DATA_IN_ExtSDRAM #define SDRAM_MEMORY_WIDTH FMC_SDMemory_Width_16b -/* #define SDRAM_MEMORY_WIDTH FMC_SDMemory_Width_32b */ +#else +#define SDRAM_MEMORY_WIDTH FMC_SDMemory_Width_32b +#endif /** * @} */ diff --git a/src/flash.ld b/src/flash.ld index 46aad91..073bb12 100644 --- a/src/flash.ld +++ b/src/flash.ld @@ -7,6 +7,7 @@ MEMORY { ram2 (xrw) : org = 0x2001c000, len = 16K ram3 (xrw) : org = 0x20020000, len = 64K ccmram (rw): org = 0x10000000, len = 64K + sdram (rw): org = 0xc0000000, len = 32M } SECTIONS { .isr_vector : { diff --git a/targets.mk b/targets.mk index e059bb0..456fdfd 100644 --- a/targets.mk +++ b/targets.mk @@ -19,7 +19,7 @@ ifeq ($(TARGET),audio) ROMSZ := 2048k RAMSZ := 192k link_script := $(top_dir)/src/flash.ld - TARGET_CFLAGS += -DSTM32F429xx -DSTM32F429_439xx -DHSE_VALUE=8000000 + TARGET_CFLAGS += -DSTM32F429xx -DSTM32F429_439xx -DHSE_VALUE=8000000 -DSDRAM_IS42S32800G cmsis_srcs += $(stdph_dir)/src/stm32f4xx_fmc.c endif