/** * @brief Reads an amount of data from the QSPI memory. * @param pData: Pointer to data to be read * @param ReadAddr: Read start address * @param Size: Size of data to read * @retval QSPI memory status */ uint8_t BSP_QSPI_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size) { QSPI_CommandTypeDef s_command; /* Initialize the read command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = QUAD_OUT_FAST_READ_CMD; s_command.AddressMode = QSPI_ADDRESS_1_LINE; s_command.AddressSize = QSPI_ADDRESS_32_BITS; s_command.Address = ReadAddr; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_4_LINES; s_command.DummyCycles = N25Q512A_DUMMY_CYCLES_READ_QUAD; s_command.NbData = Size; 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, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } return QSPI_OK; }
/** * @brief This function reads the ID of the QSPI Memory and fills the info struct * @param pqspi_info: pointer to the Info Typedef strcture * @retval None */ static uint8_t QSPI_ReadID(QSPI_InfoTypeDef *pqspi_info) { QSPI_CommandTypeDef s_command; uint8_t reg[6]; /* Configure automatic polling mode to wait for memory ready */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = READ_ID_CMD2; /* same value on both memory types */ s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_1_LINE; s_command.NbData = 6; 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; 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, reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Check the received ID of the QSPI Memory */ if (reg[0] == JEDEC_MANUF_ID_MICRON) { pqspi_info->ManufID = QSPI_N25Q512A; pqspi_info->FlashSize = (reg[2]<<21) & 0xFFFFFFFF; pqspi_info->EraseSectorSize = N25Q512A_SECTOR_SIZE; pqspi_info->EraseSectorsNumber = (N25Q512A_FLASH_SIZE/N25Q512A_SECTOR_SIZE); pqspi_info->ProgPageSize = N25Q512A_PAGE_SIZE; pqspi_info->ProgPagesNumber = (N25Q512A_FLASH_SIZE/N25Q512A_PAGE_SIZE); pqspi_info->DummyCyclesRead = 10; pqspi_info->SectorEraseMaxTime = N25Q512A_SECTOR_ERASE_MAX_TIME; pqspi_info->BulkEraseMaxTime = N25Q512A_BULK_ERASE_MAX_TIME; } if (reg[0] == JEDEC_MANUF_ID_SPANSION) { pqspi_info->ManufID = QSPI_S25FL512S; pqspi_info->FlashSize = (reg[2]<<21) & 0xFFFFFFFF; pqspi_info->EraseSectorSize = S25FL512S_SECTOR_SIZE; pqspi_info->EraseSectorsNumber = (S25FL512S_FLASH_SIZE/S25FL512S_SECTOR_SIZE); pqspi_info->ProgPageSize = S25FL512S_PAGE_SIZE; pqspi_info->ProgPagesNumber = (S25FL512S_FLASH_SIZE/S25FL512S_PAGE_SIZE); pqspi_info->DummyCyclesRead = 8; pqspi_info->SectorEraseMaxTime = S25FL512S_SECTOR_ERASE_MAX_TIME; pqspi_info->BulkEraseMaxTime = S25FL512S_BULK_ERASE_MAX_TIME; } 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 Reads current status of the QSPI memory. * @retval QSPI memory status */ uint8_t BSP_QSPI_GetStatus(void) { QSPI_CommandTypeDef s_command; uint8_t reg; /* Initialize the read flag status register command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = READ_FLAG_STATUS_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, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Check the value of the register */ if ((reg & (N25Q512A_FSR_PRERR | N25Q512A_FSR_VPPERR | N25Q512A_FSR_PGERR | N25Q512A_FSR_ERERR)) != 0) { return QSPI_ERROR; } else if ((reg & (N25Q512A_FSR_PGSUS | N25Q512A_FSR_ERSUS)) != 0) { return QSPI_SUSPENDED; } else if ((reg & N25Q512A_FSR_READY) != 0) { return QSPI_OK; } else { return QSPI_BUSY; } }
/** * @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(); } }
//-------------------------------------------------------------- // lesen von einem 8bit Datenblock vom QFlash // start_adr : start adresse von der gelesen wird // size : anzahl der daten die gelesen werden // data_buf : pointer zu einem Puffer in dem die Daten landen // // return : QSPI_OK, wenn alles ok //-------------------------------------------------------------- uint8_t UB_QFlash_Read_Block8b(uint32_t start_adr, uint32_t size, uint8_t *data_buf) { QSPI_CommandTypeDef s_command; if (start_adr >= N25Q128A_FLASH_SIZE) return QSPI_ERROR; if ((start_adr + size) >= N25Q128A_FLASH_SIZE) return QSPI_ERROR; if (size == 0) return QSPI_ERROR; // Initialize the read command s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = QUAD_INOUT_FAST_READ_CMD; s_command.AddressMode = QSPI_ADDRESS_4_LINES; s_command.AddressSize = QSPI_ADDRESS_24_BITS; s_command.Address = start_adr; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_4_LINES; s_command.DummyCycles = N25Q128A_DUMMY_CYCLES_READ_QUAD; s_command.NbData = size; 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, data_buf, 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 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 Reads current status of the QSPI memory. * @retval QSPI memory status */ uint8_t BSP_QSPI_GetStatus(void) { QSPI_CommandTypeDef s_command; uint8_t reg1, reg2; if (QspiInfo.ManufID == QSPI_N25Q512A) { /* Initialize the read flag status register command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = READ_FLAG_STATUS_REG_CMD; /* same value on both memory types */ 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; } /* Check the value of the register */ if ((reg1 & (N25Q512A_FSR_PRERR | N25Q512A_FSR_VPPERR | N25Q512A_FSR_PGERR | N25Q512A_FSR_ERERR)) != 0) { return QSPI_ERROR; } else if ((reg1 & (N25Q512A_FSR_PGSUS | N25Q512A_FSR_ERSUS)) != 0) { return QSPI_SUSPENDED; } else if ((reg1 & N25Q512A_FSR_READY) != 0) { return QSPI_OK; } else { return QSPI_BUSY; } } else { /* Initialize the read flag 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, ®1, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Initialize the read flag status register2 command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = S25FL512S_READ_STATUS_REG2_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, ®2, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Check the value of the register */ if ((reg1 & (S25FL512S_SR1_ERERR | S25FL512S_SR1_PGERR | S25FL512S_SR1_SRWD )) != 0) { return QSPI_ERROR; } if ((reg1 & (S25FL512S_SR1_BP0 | S25FL512S_SR1_BP1 | S25FL512S_SR1_BP2)) != 0) { return QSPI_PROTECTED; } if ((reg2 & (S25FL512S_SR2_PS | S25FL512S_SR2_ES)) != 0) { return QSPI_SUSPENDED; } if ((reg1 & (S25FL512S_SR1_WIP | S25FL512S_SR1_WREN)) == 0) { return QSPI_OK; } else { return QSPI_BUSY; } } }
static rt_uint32_t qspixfer(struct rt_spi_device *device, struct rt_spi_message *message) { rt_size_t len = 0; RT_ASSERT(device != RT_NULL); RT_ASSERT(device->bus != RT_NULL); struct rt_qspi_message *qspi_message = (struct rt_qspi_message *)message; struct stm32_qspi_bus *qspi_bus = device->bus->parent.user_data; #ifdef BSP_QSPI_USING_SOFTCS struct stm32_hw_spi_cs *cs = device->parent.user_data; #endif const rt_uint8_t *sndb = message->send_buf; rt_uint8_t *rcvb = message->recv_buf; rt_int32_t length = message->length; #ifdef BSP_QSPI_USING_SOFTCS if (message->cs_take) { rt_pin_write(cs->pin, 0); } #endif /* send data */ if (sndb) { qspi_send_cmd(qspi_bus, qspi_message); if (qspi_message->parent.length != 0) { if (HAL_QSPI_Transmit(&qspi_bus->QSPI_Handler, (rt_uint8_t *)sndb, 5000) == HAL_OK) { len = length; } else { LOG_E("QSPI send data failed(%d)!", qspi_bus->QSPI_Handler.ErrorCode); qspi_bus->QSPI_Handler.State = HAL_QSPI_STATE_READY; goto __exit; } } else { len = 1; } } else if (rcvb)/* recv data */ { qspi_send_cmd(qspi_bus, qspi_message); #ifdef BSP_QSPI_USING_DMA if (HAL_QSPI_Receive_DMA(&qspi_bus->QSPI_Handler, rcvb) == HAL_OK) #else if (HAL_QSPI_Receive(&qspi_bus->QSPI_Handler, rcvb, 5000) == HAL_OK) #endif { len = length; #ifdef BSP_QSPI_USING_DMA while (qspi_bus->QSPI_Handler.RxXferCount != 0); #endif } else { LOG_E("QSPI recv data failed(%d)!", qspi_bus->QSPI_Handler.ErrorCode); qspi_bus->QSPI_Handler.State = HAL_QSPI_STATE_READY; goto __exit; } } __exit: #ifdef BSP_QSPI_USING_SOFTCS if (message->cs_release) { rt_pin_write(cs->pin, 1); } #endif return len; }