/** * @brief Erases the entire QSPI memory. * @retval QSPI memory status */ uint8_t BSP_QSPI_Erase_Chip(void) { QSPI_CommandTypeDef s_command; /* Initialize the erase command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = BULK_ERASE_CMD; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_NONE; s_command.DummyCycles = 0; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Enable write operations */ if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) { return QSPI_ERROR; } /* Send the command */ if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Configure automatic polling mode to wait for end of erase */ if (QSPI_AutoPollingMemReady(&QSPIHandle, N25Q512A_BULK_ERASE_MAX_TIME) != QSPI_OK) { return QSPI_ERROR; } return QSPI_OK; }
/** * @brief This function set the QSPI memory in 4-byte address mode * @param hqspi: QSPI handle * @retval None */ static uint8_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi) { QSPI_CommandTypeDef s_command; /* Initialize the command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = ENTER_4_BYTE_ADDR_MODE_CMD; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_NONE; s_command.DummyCycles = 0; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Enable write operations */ if (QSPI_WriteEnable(hqspi) != QSPI_OK) { return QSPI_ERROR; } /* Send the command */ if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Configure automatic polling mode to wait the memory is ready */ if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) { return QSPI_ERROR; } return QSPI_OK; }
/** * @brief This function configure the dummy cycles on memory side. * @param hqspi: QSPI handle * @retval None */ static uint8_t QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi) { QSPI_CommandTypeDef s_command; uint8_t reg; /* Initialize the read volatile configuration register command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = READ_VOL_CFG_REG_CMD; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_1_LINE; s_command.DummyCycles = 0; s_command.NbData = 1; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Configure the command */ if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Reception of the data */ if (HAL_QSPI_Receive(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Enable write operations */ if (QSPI_WriteEnable(hqspi) != QSPI_OK) { return QSPI_ERROR; } /* Update volatile configuration register (with new dummy cycles) */ s_command.Instruction = WRITE_VOL_CFG_REG_CMD; MODIFY_REG(reg, N25Q512A_VCR_NB_DUMMY, (N25Q512A_DUMMY_CYCLES_READ_QUAD << POSITION_VAL(N25Q512A_VCR_NB_DUMMY))); /* Configure the write volatile configuration register command */ if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Transmission of the data */ if (HAL_QSPI_Transmit(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } return QSPI_OK; }
/** * @brief This function configure the dummy cycles on memory side. * @param hqspi: QSPI handle * @retval None */ static void QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi) { QSPI_CommandTypeDef sCommand; uint8_t reg; /* Read Volatile Configuration register --------------------------- */ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; sCommand.Instruction = READ_VOL_CFG_REG_CMD; sCommand.AddressMode = QSPI_ADDRESS_NONE; sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; sCommand.DataMode = QSPI_DATA_1_LINE; sCommand.DummyCycles = 0; sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; sCommand.NbData = 1; if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } /* Enable write operations ---------------------------------------- */ QSPI_WriteEnable(&QSPIHandle); /* Write Volatile Configuration register (with new dummy cycles) -- */ sCommand.Instruction = WRITE_VOL_CFG_REG_CMD; MODIFY_REG(reg, 0xF0, (DUMMY_CLOCK_CYCLES_READ_QUAD << POSITION_VAL(0xF0))); if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } if (HAL_QSPI_Transmit(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } }
/** * @brief Erases the specified block of the QSPI memory. * @param BlockAddress: Block address to erase * @retval QSPI memory status */ uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress) { QSPI_CommandTypeDef s_command; /* Initialize the erase command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = SECTOR_ERASE_CMD; /* same value on both memory types */ s_command.AddressMode = QSPI_ADDRESS_1_LINE; s_command.AddressSize = QSPI_ADDRESS_32_BITS; s_command.Address = BlockAddress; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_NONE; s_command.DummyCycles = 0; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Enable write operations */ if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) { return QSPI_ERROR; } /* Send the command */ if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Configure automatic polling mode to wait for end of erase */ if (QSPI_AutoPollingMemReady(&QSPIHandle, QspiInfo.SectorEraseMaxTime) != QSPI_OK) { return QSPI_ERROR; } return QSPI_OK; }
/** * @brief Writes an amount of data to the QSPI memory. * @param pData: Pointer to data to be written * @param WriteAddr: Write start address * @param Size: Size of data to write * @retval QSPI memory status */ uint8_t BSP_QSPI_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size) { QSPI_CommandTypeDef s_command; uint32_t end_addr, current_size, current_addr; /* Calculation of the size between the write address and the end of the page */ current_addr = 0; while (current_addr <= WriteAddr) { current_addr += N25Q512A_PAGE_SIZE; } current_size = current_addr - WriteAddr; /* Check if the size of the data is less than the remaining place in the page */ if (current_size > Size) { current_size = Size; } /* Initialize the address variables */ current_addr = WriteAddr; end_addr = WriteAddr + Size; /* Initialize the program command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = QUAD_IN_FAST_PROG_CMD; s_command.AddressMode = QSPI_ADDRESS_1_LINE; s_command.AddressSize = QSPI_ADDRESS_32_BITS; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_4_LINES; s_command.DummyCycles = 0; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Perform the write page by page */ do { s_command.Address = current_addr; s_command.NbData = current_size; /* Enable write operations */ if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) { return QSPI_ERROR; } /* Configure the command */ if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Transmission of the data */ if (HAL_QSPI_Transmit(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Configure automatic polling mode to wait for end of program */ if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) { return QSPI_ERROR; } /* Update the address and size variables for next page programming */ current_addr += current_size; pData += current_size; current_size = ((current_addr + N25Q512A_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : N25Q512A_PAGE_SIZE; } while (current_addr < end_addr); return QSPI_OK; }
/** * @brief This function configure the dummy cycles on memory side. * @param hqspi: QSPI handle * @retval None */ static uint8_t QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi) { QSPI_CommandTypeDef s_command; uint8_t reg[2]; /* Command ID differs between N25Q512A and S25FL512S memories */ if (QspiInfo.ManufID == QSPI_N25Q512A) { /* Initialize the read volatile configuration register command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = READ_VOL_CFG_REG_CMD; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_1_LINE; s_command.DummyCycles = 0; s_command.NbData = 1; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Configure the command */ if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Reception of the data */ if (HAL_QSPI_Receive(hqspi, ®[0], HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Enable write operations */ if (QSPI_WriteEnable(hqspi) != QSPI_OK) { return QSPI_ERROR; } /* Update volatile configuration register (with new dummy cycles) */ s_command.Instruction = WRITE_VOL_CFG_REG_CMD; MODIFY_REG(reg[0], N25Q512A_VCR_NB_DUMMY, (N25Q512A_DUMMY_CYCLES_READ_QUAD << POSITION_VAL(N25Q512A_VCR_NB_DUMMY))); /* Configure the write volatile configuration register command */ if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Transmission of the data */ if (HAL_QSPI_Transmit(hqspi, ®[0], HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } } else { /* Initialize the read configuration register command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = S25FL512S_READ_CONFIGURATION_REG1_CMD; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_1_LINE; s_command.DummyCycles = 0; s_command.NbData = 1; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Configure the command */ if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Reception of the data */ if (HAL_QSPI_Receive(&QSPIHandle, ®[1], HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Initialize the read status register1 command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = S25FL512S_READ_STATUS_REG1_CMD; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_1_LINE; s_command.DummyCycles = 0; s_command.NbData = 1; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Configure the command */ if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Reception of the data */ if (HAL_QSPI_Receive(&QSPIHandle, ®[0], HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Enable write operations */ if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) { return QSPI_ERROR; } /* Update configuration register (with new Latency Code) */ s_command.Instruction = S25FL512S_WRITE_STATUS_CMD_REG_CMD; s_command.NbData = 2; MODIFY_REG(reg[1], S25FL512S_CR1_LC_MASK, S25FL512S_CR1_LC1); /* Configure the write volatile configuration register command */ if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Transmission of the data Status Register 1 */ if (HAL_QSPI_Transmit(&QSPIHandle, reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } } return QSPI_OK; }
/** * @brief This function set the QSPI memory in 4-byte address mode * @param hqspi: QSPI handle * @retval None */ static uint8_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi) { QSPI_CommandTypeDef s_command; uint8_t reg1; /* Command ID differs between N25Q512A and S25FL512S memories */ if (QspiInfo.ManufID == QSPI_N25Q512A) { /* Initialize the command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = ENTER_4_BYTE_ADDR_MODE_CMD; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_NONE; s_command.DummyCycles = 0; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Enable write operations */ if (QSPI_WriteEnable(hqspi) != QSPI_OK) { return QSPI_ERROR; } /* Send the command */ if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Configure automatic polling mode to wait the memory is ready */ if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) { return QSPI_ERROR; } return QSPI_OK; } else { /* Initialize the read bank register command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = S25FL512S_READ_BANK_REG_CMD; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_1_LINE; s_command.DummyCycles = 0; s_command.NbData = 1; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Configure the command */ if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Reception of the data */ if (HAL_QSPI_Receive(&QSPIHandle, ®1, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Enable write operations */ if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) { return QSPI_ERROR; } /* Update Bank address register (with 4byte addressing bit) */ s_command.Instruction = S25FL512S_WRITE_BANK_REG_CMD; MODIFY_REG(reg1, S25FL512S_BA_EXTADD, S25FL512S_BA_EXTADD); /* Configure the write volatile configuration register command */ if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Transmission of the data Status Register 1 */ if (HAL_QSPI_Transmit(&QSPIHandle, ®1, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } return QSPI_OK; } }
/** * @brief Main program * @param None * @retval None */ int main(void) { /*!< At this stage the microcontroller clock setting is already configured, this is done through SystemInit() function which is called from startup file startup_stm32f446xx.s) before to branch to application main. To reconfigure the default setting of SystemInit() function, refer to system_stm32f4xx.c file */ uint32_t address = 0, step = 0x00; /* Configure QSPI GPIO */ QSPI_GPIO_Config(); /* Initialize DMA ----------------------------------------------------------*/ DMA_StructInit(&DMA_InitStructure); DMA_DeInit(QSPI_DMA_STREAM); /*DMA configuration*/ DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&QUADSPI->DR ; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Channel = DMA_Channel_3; /* Initialize QuadSPI ------------------------------------------------------*/ QSPI_StructInit(&QSPI_InitStructure); QSPI_InitStructure.QSPI_SShift = QSPI_SShift_HalfCycleShift; QSPI_InitStructure.QSPI_Prescaler = 0x01; /* 90 MHZ */ QSPI_InitStructure.QSPI_CKMode = QSPI_CKMode_Mode0; QSPI_InitStructure.QSPI_CSHTime = QSPI_CSHTime_2Cycle; QSPI_InitStructure.QSPI_FSize = 0x18; QSPI_InitStructure.QSPI_FSelect = QSPI_FSelect_1; QSPI_InitStructure.QSPI_DFlash = QSPI_DFlash_Disable; QSPI_Init(&QSPI_InitStructure); /* Initialize Command Config -----------------------------------------------*/ QSPI_ComConfig_StructInit(&QSPI_ComConfig_InitStructure); QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADSize = QSPI_ComConfig_ADSize_24bit; QSPI_ComConfig_InitStructure.QSPI_ComConfig_IMode = QSPI_ComConfig_IMode_1Line; QSPI_ComConfig_InitStructure.QSPI_ComConfig_ABMode = QSPI_ComConfig_ABMode_NoAlternateByte; QSPI_ComConfig_InitStructure.QSPI_ComConfig_DDRMode = QSPI_ComConfig_DDRMode_Disable; QSPI_ComConfig_InitStructure.QSPI_ComConfig_SIOOMode = QSPI_ComConfig_SIOOMode_Disable; QSPI_ComConfig_InitStructure.QSPI_ComConfig_DHHC = QSPI_ComConfig_DHHC_Enable; QSPI_ComConfig_StructInit(&QSPI_ComConfig_InitStructure); QSPI_Cmd(ENABLE); while(1) { switch(step) { case 0: /* Enable write operations ---------------------------------------------*/ QSPI_Cmd(ENABLE); QSPI_WriteEnable(); /* Erasing Sequence ----------------------------------------------------*/ QSPI_ComConfig_StructInit(&QSPI_ComConfig_InitStructure); QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADSize = QSPI_ComConfig_ADSize_24bit; QSPI_ComConfig_InitStructure.QSPI_ComConfig_IMode = QSPI_ComConfig_IMode_1Line; QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADMode = QSPI_ComConfig_ADMode_1Line; QSPI_ComConfig_InitStructure.QSPI_ComConfig_DMode = QSPI_ComConfig_DMode_NoData; QSPI_ComConfig_InitStructure.QSPI_ComConfig_FMode = QSPI_ComConfig_FMode_Indirect_Write; QSPI_ComConfig_InitStructure.QSPI_ComConfig_Ins = SECTOR_ERASE_CMD; QSPI_ComConfig_Init(&QSPI_ComConfig_InitStructure); /* Set sector address to erase */ QSPI_SetAddress(address); while(QSPI_GetFlagStatus(QSPI_FLAG_TC) == RESET) {} step++; break; case 1: /* Configure automatic polling mode to wait for end of erase -----------*/ QSPI_AutoPollingMemReady(); #if defined(__CC_ARM) FlashAddr = (uint8_t *)(&Load$$QSPI$$Base); MAXTransferSize = (uint32_t)(&Load$$QSPI$$Length); #elif defined(__ICCARM__) FlashAddr = (uint8_t *)(__section_begin(".qspi_init")); MAXTransferSize = __section_size(".qspi_init"); #elif defined(__GNUC__) FlashAddr = (uint8_t *)(&_qspi_init_base); MAXTransferSize = (uint32_t)((uint8_t *)(&_qspi_init_length)); #endif step++; break; case 2: /* Enable write operations ---------------------------------------------*/ QSPI_WriteEnable(); QSPI_DMACmd(ENABLE); /* Writing Sequence ----------------------------------------------------*/ QSPI_SetDataLength(MAXTransferSize); QSPI_ComConfig_StructInit(&QSPI_ComConfig_InitStructure); QSPI_ComConfig_InitStructure.QSPI_ComConfig_IMode = QSPI_ComConfig_IMode_1Line; QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADMode = QSPI_ComConfig_ADMode_1Line; QSPI_ComConfig_InitStructure.QSPI_ComConfig_DMode = QSPI_ComConfig_DMode_4Line; QSPI_ComConfig_InitStructure.QSPI_ComConfig_FMode = QSPI_ComConfig_FMode_Indirect_Write; QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADSize = QSPI_ComConfig_ADSize_32bit; QSPI_ComConfig_InitStructure.QSPI_ComConfig_Ins = QUAD_IN_FAST_PROG_CMD; QSPI_ComConfig_InitStructure.QSPI_ComConfig_DummyCycles = 0; QSPI_ComConfig_Init(&QSPI_ComConfig_InitStructure); /* DMA channel Tx Configuration */ DMA_InitStructure.DMA_BufferSize = MAXTransferSize; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)FlashAddr; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_Priority = DMA_Priority_Low; DMA_Init(QSPI_DMA_STREAM, &DMA_InitStructure); DMA_Cmd(QSPI_DMA_STREAM, ENABLE); /* Wait for the end of Transfer */ while(DMA_GetFlagStatus(QSPI_DMA_STREAM, QSPI_DMA_FLAG_TC) == RESET) {} DMA_ClearFlag(QSPI_DMA_STREAM, QSPI_DMA_FLAG_TC); QSPI_AbortRequest(); DMA_Cmd(QSPI_DMA_STREAM, DISABLE); QSPI_DMACmd(DISABLE); step++; break; case 3: /* Configure automatic polling mode to wait for end of program ---------*/ QSPI_AutoPollingMemReady(); step++; break; case 4: /* Reading Sequence ----------------------------------------------------*/ QSPI_TimeoutCounterCmd(DISABLE); QSPI_MemoryMappedMode_SetTimeout(0); QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADSize = QSPI_ComConfig_ADSize_32bit; QSPI_ComConfig_InitStructure.QSPI_ComConfig_FMode = QSPI_ComConfig_FMode_Memory_Mapped; QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADMode = QSPI_ComConfig_ADMode_4Line; QSPI_ComConfig_InitStructure.QSPI_ComConfig_IMode = QSPI_ComConfig_IMode_1Line; QSPI_ComConfig_InitStructure.QSPI_ComConfig_DMode = QSPI_ComConfig_DMode_4Line; QSPI_ComConfig_InitStructure.QSPI_ComConfig_Ins = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; QSPI_ComConfig_InitStructure.QSPI_ComConfig_DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD; QSPI_ComConfig_Init(&QSPI_ComConfig_InitStructure); GpioToggle(); break; default : TransferStatus = FAILED; break; } } }
/** * @brief Main program * @param None * @retval None */ int main(void) { QSPI_CommandTypeDef sCommand; uint32_t address = 0; uint16_t index; __IO uint8_t step = 0; /* Enable the CPU Cache */ CPU_CACHE_Enable(); /* STM32F7xx HAL library initialization: - Configure the Flash ART accelerator on ITCM interface - Systick timer is configured by default as source of time base, but user can eventually implement his proper time base source (a general purpose timer for example or other time source), keeping in mind that Time base duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and handled in milliseconds basis. - Set NVIC Group Priority to 4 - Low Level Initialization */ HAL_Init(); /* Configure the system clock to 216 MHz */ SystemClock_Config(); BSP_LED_Init(LED1); BSP_LED_Init(LED3); /* Initialize QuadSPI ------------------------------------------------------ */ QSPIHandle.Instance = QUADSPI; HAL_QSPI_DeInit(&QSPIHandle); /* ClockPrescaler set to 2, so QSPI clock = 216MHz / (2+1) = 72MHz */ QSPIHandle.Init.ClockPrescaler = 2; QSPIHandle.Init.FifoThreshold = 4; QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE; QSPIHandle.Init.FlashSize = QSPI_FLASH_SIZE; QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE; QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0; if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) { Error_Handler(); } sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; sCommand.AddressSize = QSPI_ADDRESS_24_BITS; sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; while(1) { switch(step) { case 0: CmdCplt = 0; /* Initialize Reception buffer --------------------------------------- */ for (index = 0; index < BUFFERSIZE; index++) { aRxBuffer[index] = 0; } /* Enable write operations ------------------------------------------- */ QSPI_WriteEnable(&QSPIHandle); /* Erasing Sequence -------------------------------------------------- */ sCommand.Instruction = SECTOR_ERASE_CMD; sCommand.AddressMode = QSPI_ADDRESS_1_LINE; sCommand.Address = address; sCommand.DataMode = QSPI_DATA_NONE; sCommand.DummyCycles = 0; if (HAL_QSPI_Command_IT(&QSPIHandle, &sCommand) != HAL_OK) { Error_Handler(); } step++; break; case 1: if(CmdCplt != 0) { CmdCplt = 0; StatusMatch = 0; /* Configure automatic polling mode to wait for end of erase ------- */ QSPI_AutoPollingMemReady(&QSPIHandle); step++; } break; case 2: if(StatusMatch != 0) { StatusMatch = 0; TxCplt = 0; /* Enable write operations ----------------------------------------- */ QSPI_WriteEnable(&QSPIHandle); /* Writing Sequence ------------------------------------------------ */ sCommand.Instruction = QUAD_IN_FAST_PROG_CMD; sCommand.AddressMode = QSPI_ADDRESS_1_LINE; sCommand.DataMode = QSPI_DATA_4_LINES; sCommand.NbData = BUFFERSIZE; if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } if (HAL_QSPI_Transmit_IT(&QSPIHandle, aTxBuffer) != HAL_OK) { Error_Handler(); } step++; } break; case 3: if(TxCplt != 0) { TxCplt = 0; StatusMatch = 0; /* Configure automatic polling mode to wait for end of program ----- */ QSPI_AutoPollingMemReady(&QSPIHandle); step++; } break; case 4: if(StatusMatch != 0) { StatusMatch = 0; RxCplt = 0; /* Configure Volatile Configuration register (with new dummy cycles) */ QSPI_DummyCyclesCfg(&QSPIHandle); /* Reading Sequence ------------------------------------------------ */ sCommand.Instruction = QUAD_OUT_FAST_READ_CMD; sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD; if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } if (HAL_QSPI_Receive_IT(&QSPIHandle, aRxBuffer) != HAL_OK) { Error_Handler(); } step++; } break; case 5: if (RxCplt != 0) { RxCplt = 0; /* Result comparison ----------------------------------------------- */ for (index = 0; index < BUFFERSIZE; index++) { if (aRxBuffer[index] != aTxBuffer[index]) { BSP_LED_On(LED3); } } BSP_LED_Toggle(LED1); address += QSPI_PAGE_SIZE; if(address >= QSPI_END_ADDR) { address = 0; } step = 0; } break; default : Error_Handler(); } } }
/** * @brief Main program * @param None * @retval None */ int main(void) { QSPI_CommandTypeDef sCommand; QSPI_MemoryMappedTypeDef sMemMappedCfg; uint32_t address = 0; __IO uint8_t *qspi_addr = (__IO uint8_t *)(0x90000000); uint16_t index; __IO uint8_t step = 0; /* STM32F4xx HAL library initialization: - Configure the Flash prefetch, instruction and Data caches - Systick timer is configured by default as source of time base, but user can eventually implement his proper time base source (a general purpose timer for example or other time source), keeping in mind that Time base duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and handled in milliseconds basis. - Set NVIC Group Priority to 4 - Low Level Initialization: global MSP (MCU Support Package) initialization */ HAL_Init(); /* Configure the system clock to 180 MHz */ SystemClock_Config(); BSP_LED_Init(LED1); BSP_LED_Init(LED3); /* Initialize QuadSPI structures ------------------------------------------- */ QSPIHandle.Instance = QUADSPI; QSPIHandle.Init.ClockPrescaler = 1; QSPIHandle.Init.FifoThreshold = 4; QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; QSPIHandle.Init.FlashSize = QSPI_FLASH_SIZE; QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE; QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0; sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; sCommand.AddressSize = QSPI_ADDRESS_24_BITS; sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; while(1) { switch(step) { case 0: CmdCplt = 0; /* Initialize QuadSPI ------------------------------------------------ */ HAL_QSPI_DeInit(&QSPIHandle); if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) { Error_Handler(); } /* Enable write operations ------------------------------------------- */ QSPI_WriteEnable(&QSPIHandle); /* Erasing Sequence -------------------------------------------------- */ sCommand.Instruction = SECTOR_ERASE_CMD; sCommand.AddressMode = QSPI_ADDRESS_1_LINE; sCommand.Address = address; sCommand.DataMode = QSPI_DATA_NONE; sCommand.DummyCycles = 0; if (HAL_QSPI_Command_IT(&QSPIHandle, &sCommand) != HAL_OK) { Error_Handler(); } step++; break; case 1: if(CmdCplt != 0) { CmdCplt = 0; StatusMatch = 0; /* Configure automatic polling mode to wait for end of erase ------- */ QSPI_AutoPollingMemReady(&QSPIHandle); step++; } break; case 2: if(StatusMatch != 0) { StatusMatch = 0; TxCplt = 0; /* Enable write operations ----------------------------------------- */ QSPI_WriteEnable(&QSPIHandle); /* Writing Sequence ------------------------------------------------ */ sCommand.Instruction = EXT_QUAD_IN_FAST_PROG_CMD; sCommand.AddressMode = QSPI_ADDRESS_4_LINES; sCommand.DataMode = QSPI_DATA_4_LINES; sCommand.NbData = BUFFERSIZE; if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } if (HAL_QSPI_Transmit_DMA(&QSPIHandle, aTxBuffer) != HAL_OK) { Error_Handler(); } step++; } break; case 3: if(TxCplt != 0) { TxCplt = 0; StatusMatch = 0; /* Configure automatic polling mode to wait for end of program ----- */ QSPI_AutoPollingMemReady(&QSPIHandle); step++; } break; case 4: if(StatusMatch != 0) { StatusMatch = 0; RxCplt = 0; /* Configure Volatile Configuration register (with new dummy cycles) */ QSPI_DummyCyclesCfg(&QSPIHandle); /* Reading Sequence ------------------------------------------------ */ sCommand.Instruction = QUAD_INOUT_FAST_READ_CMD; sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD; sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; if (HAL_QSPI_MemoryMapped(&QSPIHandle, &sCommand, &sMemMappedCfg) != HAL_OK) { Error_Handler(); } for (index = 0; index < BUFFERSIZE; index++) { if (*qspi_addr != aTxBuffer[index]) { BSP_LED_On(LED3); } qspi_addr++; } BSP_LED_Toggle(LED1); address += QSPI_PAGE_SIZE; if(address >= QSPI_END_ADDR) { address = 0; } qspi_addr = (__IO uint8_t *)(0x90000000 + address); step = 0; } break; default : Error_Handler(); } } }
/** * @brief Main program * @param None * @retval None */ int main(void) { QSPI_CommandTypeDef sCommand; QSPI_MemoryMappedTypeDef sMemMappedCfg; __IO uint32_t qspi_addr = 0; uint8_t *flash_addr; __IO uint8_t step = 0; uint32_t max_size, size; /* STM32F4xx HAL library initialization: - Configure the Flash prefetch, instruction and Data caches - Systick timer is configured by default as source of time base, but user can eventually implement his proper time base source (a general purpose timer for example or other time source), keeping in mind that Time base duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and handled in milliseconds basis. - Set NVIC Group Priority to 4 - Low Level Initialization: global MSP (MCU Support Package) initialization */ HAL_Init(); /* Configure the system clock to 180 MHz */ SystemClock_Config(); BSP_LED_Init(LED1); BSP_LED_Init(LED3); /* Initialize QuadSPI ------------------------------------------------------ */ QSPIHandle.Instance = QUADSPI; HAL_QSPI_DeInit(&QSPIHandle); QSPIHandle.Init.ClockPrescaler = 1; QSPIHandle.Init.FifoThreshold = 4; QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; QSPIHandle.Init.FlashSize = QSPI_FLASH_SIZE; QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE; QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0; if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) { Error_Handler(); } sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; sCommand.AddressSize = QSPI_ADDRESS_24_BITS; sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; flash_addr = 0; size = 0 ; #if defined(__CC_ARM) max_size = (uint32_t)(&Load$$QSPI$$Length); #elif defined(__ICCARM__) max_size = __section_size(".qspi_init"); #elif defined(__GNUC__) max_size = (uint32_t)((uint8_t *)(&_qspi_init_length)); #endif while(1) { switch(step) { case 0: CmdCplt = 0; /* Enable write operations ------------------------------------------- */ QSPI_WriteEnable(&QSPIHandle); /* Erasing Sequence -------------------------------------------------- */ sCommand.Instruction = SECTOR_ERASE_CMD; sCommand.AddressMode = QSPI_ADDRESS_1_LINE; sCommand.Address = qspi_addr; sCommand.DataMode = QSPI_DATA_NONE; sCommand.DummyCycles = 0; if (HAL_QSPI_Command_IT(&QSPIHandle, &sCommand) != HAL_OK) { Error_Handler(); } step++; break; case 1: if(CmdCplt != 0) { CmdCplt = 0; StatusMatch = 0; /* Configure automatic polling mode to wait for end of erase ------- */ QSPI_AutoPollingMemReady(&QSPIHandle); /* Initialize the variables for the data writing ------------------- */ #if defined(__CC_ARM) flash_addr = (uint8_t *)(&Load$$QSPI$$Base); #elif defined(__ICCARM__) flash_addr = (uint8_t *)(__section_begin(".qspi_init")); #elif defined(__GNUC__) flash_addr =(uint8_t *)(&_qspi_init_base); #endif /* Copy only one page if the section is bigger */ if (max_size > QSPI_PAGE_SIZE) { size = QSPI_PAGE_SIZE; } else { size = max_size; } step++; } break; case 2: if(StatusMatch != 0) { StatusMatch = 0; TxCplt = 0; /* Enable write operations ----------------------------------------- */ QSPI_WriteEnable(&QSPIHandle); /* Writing Sequence ------------------------------------------------ */ sCommand.Instruction = EXT_QUAD_IN_FAST_PROG_CMD; sCommand.AddressMode = QSPI_ADDRESS_4_LINES; sCommand.Address = qspi_addr; sCommand.DataMode = QSPI_DATA_4_LINES; sCommand.NbData = size; if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } if (HAL_QSPI_Transmit_DMA(&QSPIHandle, flash_addr) != HAL_OK) { Error_Handler(); } step++; } break; case 3: if(TxCplt != 0) { TxCplt = 0; StatusMatch = 0; /* Configure automatic polling mode to wait for end of program ----- */ QSPI_AutoPollingMemReady(&QSPIHandle); step++; } break; case 4: if(StatusMatch != 0) { qspi_addr += size; flash_addr += size; /* Check if a new page writing is needed */ if (qspi_addr < max_size) { /* Update the remaining size if it is less than the page size */ if ((qspi_addr + size) > max_size) { size = max_size - qspi_addr; } step = 2; } else { StatusMatch = 0; RxCplt = 0; /* Configure Volatile Configuration register (with new dummy cycles) */ QSPI_DummyCyclesCfg(&QSPIHandle); /* Reading Sequence ------------------------------------------------ */ sCommand.Instruction = QUAD_INOUT_FAST_READ_CMD; sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD; sMemMappedCfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; if (HAL_QSPI_MemoryMapped(&QSPIHandle, &sCommand, &sMemMappedCfg) != HAL_OK) { Error_Handler(); } step++; } } break; case 5: /* Execute the code from QSPI memory ------------------------------- */ GpioToggle(); break; default : Error_Handler(); } } }