/** ******************************************************************************* * @file hc32f4a0_qspi.c * @brief This file provides firmware functions to manage the QSPI. @verbatim Change Logs: Date Author Notes 2020-06-12 Wuze First version 2020-07-15 Wuze Refined QSPI_WriteData(). @endverbatim ******************************************************************************* * Copyright (C) 2020, Huada Semiconductor Co., Ltd. All rights reserved. * * This software component is licensed by HDSC under BSD 3-Clause license * (the "License"); You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ******************************************************************************* */ /******************************************************************************* * Include files ******************************************************************************/ #include "hc32f4a0_qspi.h" #include "hc32f4a0_utility.h" /** * @addtogroup HC32F4A0_DDL_Driver * @{ */ /** * @defgroup DDL_QSPI QSPI * @brief QSPI Driver Library * @{ */ #if (DDL_QSPI_ENABLE == DDL_ON) /******************************************************************************* * Local type definitions ('typedef') ******************************************************************************/ /******************************************************************************* * Local pre-processor symbols/macros ('#define') ******************************************************************************/ /** * @defgroup QSPI_Local_Macros QSPI Local Macros * @{ */ /** * @defgroup QSPI_Configuration_Bit_Mask QSPI Configuration Bit Mask * @{ */ #define QSPI_FLAG_CLR_MSK (QSPI_FLAG_ROM_ACCESS_ERR) /** * @} */ /** * @defgroup QSPI_Common_Instruction QSPI Common Instruction * @{ */ #define QSPI_INS_ENTER_4BA (0xB7U) #define QSPI_INS_EXIT_4BA (0xE9U) /** * @} */ /** * @defgroup QSPI_Check_Parameters_Validity QSPI check parameters validity * @{ */ #define IS_QSPI_CLK_DIV(x) \ ( ((x) >= 2U) && ((x) <= 64U)) #define IS_QSPI_CS_SETUP_TIMING(x) \ ( ((x) == QSPI_CS_SETUP_BEFORE_0P5_CYCLE) || \ ((x) == QSPI_CS_SETUP_BEFORE_1P5_CYCLE)) #define IS_QSPI_CS_RELEASE_TIMING(x) \ ( ((x) == QSPI_CS_RELEASE_AFTER_0P5_CYCLE) || \ ((x) == QSPI_CS_RELEASE_AFTER_1P5_CYCLE)) #define IS_QSPI_CS_IDLE_TIME(x) \ ( ((x) >= 1U) && ((x) <= 16U)) #define IS_QSPI_CS_EXTEND_TIME(x) \ ( ((x) == QSPI_CS_EXTEND_0CYCLE) || \ ((x) == QSPI_CS_EXTEND_32CYCLE) || \ ((x) == QSPI_CS_EXTEND_128CYCLE) || \ ((x) == QSPI_CS_EXTEND_INFINITE)) #define IS_QSPI_SPI_MODE(x) \ ( ((x) == QSPI_SPI_MODE_0) || \ ((x) == QSPI_SPI_MODE_3)) #define IS_QSPI_PREFETCH_STOP_POSITION(x) \ ( ((x) == QSPI_PREFETCH_STOP_BYTE_EDGE) || \ ((x) == QSPI_PREFETCH_STOP_IMMED)) #define IS_QSPI_READ_MODE(x) \ ( ((x) == QSPI_READ_STANDARD_READ) || \ ((x) == QSPI_READ_FAST_READ) || \ ((x) == QSPI_READ_FAST_READ_DUAL_OUTPUT) || \ ((x) == QSPI_READ_FAST_READ_DUAL_IO) || \ ((x) == QSPI_READ_FAST_READ_QUAD_OUTPUT) || \ ((x) == QSPI_READ_FAST_READ_QUAD_IO) || \ ((x) == QSPI_READ_CUSTOM_STANDARD_READ) || \ ((x) == QSPI_READ_CUSTOM_FAST_READ)) #define IS_QSPI_COMM_MODE(x) \ ( ((x) == QSPI_COMM_ROM_ACCESS) || \ ((x) == QSPI_COMM_DIRECT_COMM)) #define IS_QSPI_ADDR_WIDTH(x) \ ( ((x) == QSPI_ADDR_WIDTH_1BYTE) || \ ((x) == QSPI_ADDR_WIDTH_2BYTE) || \ ((x) == QSPI_ADDR_WIDTH_3BYTE) || \ ((x) == QSPI_ADDR_WIDTH_4BYTE)) #define IS_QSPI_DUMMY_CYCLES(x) \ ( ((x) >= 3U) && ((x) <= 18U)) #define IS_QSPI_INSTR_MODE(x) \ ( ((x) == QSPI_INSTR_1LINE) || \ ((x) == QSPI_INSTR_2LINE) || \ ((x) == QSPI_INSTR_4LINE)) #define IS_QSPI_ADDR_MODE(x) \ ( ((x) == QSPI_ADDR_1LINE) || \ ((x) == QSPI_ADDR_2LINE) || \ ((x) == QSPI_ADDR_4LINE)) #define IS_QSPI_DATA_MODE(x) \ ( ((x) == QSPI_DATA_1LINE) || \ ((x) == QSPI_DATA_2LINE) || \ ((x) == QSPI_DATA_4LINE)) #define IS_QSPI_BLOCK_NUM(x) \ ( (x) <= 62U) #define IS_QSPI_PREFETCH_CMD(x) \ ( ((x) == QSPI_PREFETCH_ENABLE) || \ ((x) == QSPI_PREFETCH_DISABLE)) #define IS_QSPI_WP_LEVEL(x) \ ( ((x) == QSPI_WP_LOW) || \ ((x) == QSPI_WP_HIGH)) /** * @} */ /** * @defgroup QSPI_Miscellaneous_Macros QSPI Miscellaneous Macros * @{ */ #define QSPI_WORD_TO_BYTE(__word__, __au8__) \ do { \ (__au8__)[0U] = (uint8_t)(__word__); \ (__au8__)[1U] = (uint8_t)((__word__) >> 8U); \ (__au8__)[2U] = (uint8_t)((__word__) >> 16U); \ (__au8__)[3U] = (uint8_t)((__word__) >> 24U); \ } while (0U) #define QSPI_ROM_MAP_BASE (0x98000000UL) /** * @} */ /** * @} */ /******************************************************************************* * Global variable definitions (declared in header file with 'extern') ******************************************************************************/ /******************************************************************************* * Local function prototypes ('static') ******************************************************************************/ /******************************************************************************* * Local variable definitions ('static') ******************************************************************************/ /******************************************************************************* * Function implementation - global ('extern') and local ('static') ******************************************************************************/ /** * @defgroup QSPI_Global_Functions QSPI Global Functions * @{ */ /** * @brief Initializes QSPI peripheral according to the specified parameters \ * in the structure stc_qspi_init_t * @param [in] pstcInit Pointer to a stc_qspi_init_t structure value that \ * contains the configuration information for QSPI. * @retval An en_result_t enumeration type value. * @arg Ok: No error occurred. * @arg ErrorInvalidParameter: pstcInit == NULL. */ en_result_t QSPI_Init(const stc_qspi_init_t *pstcInit) { uint32_t u32DutyCorrection = 0U; en_result_t enRet = ErrorInvalidParameter; if (pstcInit != NULL) { DDL_ASSERT(IS_QSPI_CLK_DIV(pstcInit->u32ClkDiv)); DDL_ASSERT(IS_QSPI_CS_SETUP_TIMING(pstcInit->u32CSSetupTiming)); DDL_ASSERT(IS_QSPI_CS_RELEASE_TIMING(pstcInit->u32CSReleaseTiming)); DDL_ASSERT(IS_QSPI_CS_IDLE_TIME(pstcInit->u32CSIdleTime)); DDL_ASSERT(IS_QSPI_CS_EXTEND_TIME(pstcInit->u32CSExtendTime)); DDL_ASSERT(IS_QSPI_SPI_MODE(pstcInit->u32SPIMode)); DDL_ASSERT(IS_QSPI_PREFETCH_STOP_POSITION(pstcInit->u32PrefetchStopPos)); DDL_ASSERT(IS_QSPI_PREFETCH_CMD(pstcInit->u32PrefetchCmd)); DDL_ASSERT(IS_QSPI_WP_LEVEL(pstcInit->u32WPLevel)); DDL_ASSERT(IS_QSPI_READ_MODE(pstcInit->u32ReadMode)); DDL_ASSERT(IS_QSPI_COMM_MODE(pstcInit->u32CommMode)); DDL_ASSERT(IS_QSPI_ADDR_WIDTH(pstcInit->u32AddrWidth)); DDL_ASSERT(IS_QSPI_DUMMY_CYCLES(pstcInit->u32DummyCycles)); DDL_ASSERT(IS_QSPI_INSTR_MODE(pstcInit->u32InstrMode)); DDL_ASSERT(IS_QSPI_ADDR_MODE(pstcInit->u32AddrMode)); DDL_ASSERT(IS_QSPI_DATA_MODE(pstcInit->u32DataMode)); if ((pstcInit->u32ClkDiv & 1UL) != 0UL) { u32DutyCorrection = QSPI_FCR_DUTY; } WRITE_REG32(M4_QSPI->CR, (((pstcInit->u32ClkDiv-1UL) << QSPI_CR_DIV_POS) | \ pstcInit->u32SPIMode | \ pstcInit->u32PrefetchStopPos | \ pstcInit->u32PrefetchCmd | \ pstcInit->u32ReadMode | \ pstcInit->u32CommMode | \ pstcInit->u32InstrMode | \ pstcInit->u32AddrMode | \ pstcInit->u32DataMode)); WRITE_REG32(M4_QSPI->CSCR, (pstcInit->u32CSExtendTime | \ (pstcInit->u32CSIdleTime-1UL))); WRITE_REG32(M4_QSPI->FCR, (pstcInit->u32CSSetupTiming | \ pstcInit->u32CSReleaseTiming | \ pstcInit->u32AddrWidth | \ ((pstcInit->u32DummyCycles-3UL) << QSPI_FCR_DMCYCN_POS) | \ pstcInit->u32WPLevel | \ u32DutyCorrection)); WRITE_REG32(M4_QSPI->CCMD, pstcInit->u8RomAccessInstr); enRet = Ok; } return enRet; } /** * @brief De-initializes QSPI peripheral. Reset the registers of QSPI. * @param None * @retval None */ void QSPI_DeInit(void) { WRITE_REG32(M4_QSPI->CR, 0x3F0000UL); WRITE_REG32(M4_QSPI->CSCR, 0xFUL); WRITE_REG32(M4_QSPI->FCR, 0x80B3UL); WRITE_REG32(M4_QSPI->SR, 0x8000UL); WRITE_REG32(M4_QSPI->CCMD, 0x0UL); WRITE_REG32(M4_QSPI->XCMD, 0xFFUL); WRITE_REG32(M4_QSPI->SR2, QSPI_FLAG_ROM_ACCESS_ERR); WRITE_REG32(M4_QSPI->EXAR, 0x0UL); } /** * @brief Set a default value for QSPI initialization structure. * @param [in] pstcInit Pointer to a stc_qspi_init_t structure value that \ * contains the configuration information QSPI. * @retval An en_result_t enumeration type value. * @arg Ok: No error occurred. * @arg ErrorInvalidParameter: pstcInit == NULL. */ en_result_t QSPI_StructInit(stc_qspi_init_t *pstcInit) { en_result_t enRet = ErrorInvalidParameter; if (pstcInit != NULL) { pstcInit->u32ClkDiv = 2UL; pstcInit->u32CSSetupTiming = QSPI_CS_SETUP_BEFORE_0P5_CYCLE; pstcInit->u32CSReleaseTiming = QSPI_CS_RELEASE_AFTER_0P5_CYCLE; pstcInit->u32CSIdleTime = 1UL; pstcInit->u32CSExtendTime = QSPI_CS_EXTEND_0CYCLE; pstcInit->u32SPIMode = QSPI_SPI_MODE_0; pstcInit->u32PrefetchStopPos = QSPI_PREFETCH_STOP_BYTE_EDGE; pstcInit->u32PrefetchCmd = QSPI_PREFETCH_ENABLE; pstcInit->u32WPLevel = QSPI_WP_HIGH; pstcInit->u32CommMode = QSPI_COMM_ROM_ACCESS; pstcInit->u32AddrWidth = QSPI_ADDR_WIDTH_3BYTE; pstcInit->u32InstrMode = QSPI_INSTR_1LINE; pstcInit->u32AddrMode = QSPI_ADDR_1LINE; pstcInit->u32DataMode = QSPI_DATA_1LINE; pstcInit->u32ReadMode = QSPI_READ_STANDARD_READ; pstcInit->u8RomAccessInstr = 0x0U; pstcInit->u32DummyCycles = 3UL; enRet = Ok; } return enRet; } /** * @brief QSPI write data. * @param [in] u32Instr Instruction. * @param [in] u32Address Address. * @param [in] pu8Src Pointer to an array that stores the data to be written. * @param [in] u32SrcSize Size of the data to be written. * @retval An en_result_t enumeration type value. * @arg Ok: No error occurred. * @arg ErrorInvalidParameter: pu8Src == NULL or u32SrcSize == 0U */ en_result_t QSPI_WriteData(uint32_t u32Instr, uint32_t u32Address, \ const uint8_t pu8Src[], uint32_t u32SrcSize) { uint32_t i; uint8_t au8Address[4U]; uint32_t u32AddrWidth; en_result_t enRet = ErrorInvalidParameter; if ((pu8Src != NULL) && (u32SrcSize > 0U)) { QSPI_WORD_TO_BYTE(u32Address, au8Address); u32AddrWidth = (READ_REG32_BIT(M4_QSPI->FCR, QSPI_FCR_AWSL) >> QSPI_FCR_AWSL_POS) + 1U; /* Enter direct communication mode. */ QSPI_EnterDirectCommMode(); /* Send instruction. */ WRITE_REG32(M4_QSPI->DCOM, u32Instr); /* Send ROM address. */ for (i=0U; iDCOM, au8Address[i]); } /* Write data at last. */ for (i=0U; iDCOM, pu8Src[i]); } /* Exit direct communication mode. */ QSPI_ExitDirectCommMode(); enRet = Ok; } return enRet; } /** * @brief QSPI write data. * @param [in] u32Address Address. * @param [in] pu8Dest Pointer to an array that used to store the read data. * @param [in] u32DestSize Size of the data to be read. * @retval An en_result_t enumeration type value. * @arg Ok: No error occurred. * @arg ErrorInvalidParameter: pu8Dest == NULL or u32DestSize == 0U */ en_result_t QSPI_ReadData(uint32_t u32Address, uint8_t pu8Dest[], uint32_t u32DestSize) { uint32_t i = 0U; en_result_t enRet = ErrorInvalidParameter; if ((pu8Dest != NULL) && (u32DestSize > 0U)) { u32Address += QSPI_ROM_MAP_BASE; while (u32DestSize-- != 0U) { pu8Dest[i++] = *(uint8_t *)(u32Address++); } enRet = Ok; } return enRet; } /** * @brief Specifies read mode. * @param [in] u32ReadMode QSPI read mode. * This parameter can be a value of @ref QSPI_Read_Mode * @arg QSPI_READ_STANDARD_READ: Standard read mode (no dummy cycles). * @arg QSPI_READ_FAST_READ: Fast read mode (dummy cycles between address and data). * @arg QSPI_READ_FAST_READ_DUAL_OUTPUT: Fast read dual output mode (data on 2 lines). * @arg QSPI_READ_FAST_READ_DUAL_IO: Fast read dual I/O mode (address and data on 2 lines). * @arg QSPI_READ_FAST_READ_QUAD_OUTPUT: Fast read quad output mode (data on 4 lines). * @arg QSPI_READ_FAST_READ_QUAD_IO: Fast read quad I/O mode (address and data on 4 lines). * @arg QSPI_READ_CUSTOM_STANDARD_READ: Custom standard read mode. * @arg QSPI_READ_CUSTOM_FAST_READ: Custom fast read mode. * @param [in] u8ReadInstr Read instruction of QSPI flash. Tis instruction must correspond to the read mode that specified by parameter 'u32ReadMode'. * @param [in] u32DummyCycles The number of dummy cycles for fast read. It must correspond to the QSPI flash read instruction. * Ignore when u32ReadMode == QSPI_READ_STANDARD_READ. * This parameter can be a value between 3U and 18U, inclusive. * @retval None */ void QSPI_SetReadMode(uint32_t u32ReadMode, uint8_t u8ReadInstr, uint32_t u32DummyCycles) { DDL_ASSERT(IS_QSPI_READ_MODE(u32ReadMode)); DDL_ASSERT(IS_QSPI_DUMMY_CYCLES(u32DummyCycles)); MODIFY_REG32(M4_QSPI->FCR, QSPI_FCR_DMCYCN, (u32DummyCycles-3UL) << QSPI_FCR_DMCYCN_POS); MODIFY_REG32(M4_QSPI->CR, QSPI_CR_MDSEL, u32ReadMode); WRITE_REG32(M4_QSPI->CCMD, u8ReadInstr); } /** * @brief Enable or disable duty correction. * @param [in] enNewState An en_functional_state_t enumeration type value. * @arg Enable: Enable duty correction. * @arg Disable: Disable duty correction. * @retval None */ void QSPI_DutyCorrectCmd(en_functional_state_t enNewState) { DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState)); if (enNewState == Enable) { SET_REG32_BIT(M4_QSPI->FCR, QSPI_FCR_DUTY); } else { CLEAR_REG32_BIT(M4_QSPI->FCR, QSPI_FCR_DUTY); } } /** * @brief Enable or disable prefetch function. * @param [in] enNewState An en_functional_state_t enumeration type value. * @arg Enable: Enable prefetch function. * @arg Disable: Disable prefetch function. * @retval None */ void QSPI_PrefetchCmd(en_functional_state_t enNewState) { DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState)); if (enNewState == Enable) { SET_REG32_BIT(M4_QSPI->CR, QSPI_CR_PFE); } else { CLEAR_REG32_BIT(M4_QSPI->CR, QSPI_CR_PFE); } } /** * @brief Enable or disable XIP mode. * @param [in] enNewState An en_functional_state_t enumeration type value. * @arg Enable: Enable XIP mode. * @arg Disable: Disable XIP mode. * @retval None */ void QSPI_XIPModeCmd(en_functional_state_t enNewState) { DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState)); if (enNewState == Enable) { SET_REG32_BIT(M4_QSPI->CR, QSPI_CR_XIPE); } else { CLEAR_REG32_BIT(M4_QSPI->CR, QSPI_CR_XIPE); } } /** * @brief Specifies the level of WP. * @param [in] u32Level The level of WP. * This parameter can be a value of @ref QSPI_WP_Level * @arg QSPI_WP_LOW: Set WP output low. * @arg QSPI_WP_HIGH: Set WP output high. * @retval None */ void QSPI_SetWPPinLevel(uint32_t u32Level) { DDL_ASSERT(IS_QSPI_WP_LEVEL(u32Level)); MODIFY_REG32(M4_QSPI->FCR, QSPI_FCR_WPOL, u32Level); } /** * @brief Enable or disable 4-byte address mode. * @param [in] enNewState An en_functional_state_t enumeration type value. * @arg Enable: Enable 4-byte address mode. * @arg Disable: Disable 4-byte address mode. * @retval None */ void QSPI_4ByteAddrModeCmd(en_functional_state_t enNewState) { DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState)); if (enNewState == Enable) { SET_REG32_BIT(M4_QSPI->FCR, QSPI_FCR_FOUR_BIC); } else { CLEAR_REG32_BIT(M4_QSPI->FCR, QSPI_FCR_FOUR_BIC); } } /** * @brief Selects the block to access. * @param [in] u32Block External block. A number between 0U and 62U, inclusive. * @retval None */ void QSPI_SelectBlock(uint32_t u32Block) { DDL_ASSERT(IS_QSPI_BLOCK_NUM(u32Block)); WRITE_REG32(M4_QSPI->EXAR, ((u32Block << QSPI_EXAR_EXADR_POS) & QSPI_EXAR_EXADR)); } /** * @brief Get the size of prefetched data. * @param None * @retval A number between 0U and 18U, inclusive. */ uint32_t QSPI_GetPrefetchedSize(void) { return READ_REG32_BIT(M4_QSPI->SR, QSPI_SR_PFNUM) >> QSPI_SR_PFNUM_POS; } /** * @brief Get the status of the specified QSPI flags. * @param [in] u32Flag The status flags of QSPI. * This parameter can be values of @ref QSPI_Status_Flag * @arg QSPI_FLAG_DIRECT_COMM_BUSY: Serial transfer being processed. * @arg QSPI_FLAG_XIP_MODE: XIP mode. * @arg QSPI_FLAG_ROM_ACCESS_ERR: ROM access detection status in direct communication mode. * @arg QSPI_FLAG_PREFETCH_BUF_FULL: Prefetch buffer is full. * @arg QSPI_FLAG_PREFETCH_ACTIVE: Prefetch function operating. * @retval An en_flag_status_t enumeration type value. * @arg Set: At least one of the specified flags is set. * @arg Reset: None of the specified flags is set. */ en_flag_status_t QSPI_GetStatus(uint32_t u32Flag) { en_flag_status_t enFlag = Reset; if (READ_REG32_BIT(M4_QSPI->SR, (u32Flag & QSPI_FLAG_ALL)) != 0UL) { enFlag = Set; } return enFlag; } /** * @brief Clear the specified flag. * @param [in] u32Flag The specified flags to be cleared. * This parameter can only be the following: * @arg QSPI_FLAG_ROM_ACCESS_ERR: ROM access detection status in direct communication mode. * @retval None */ void QSPI_ClrStatus(uint32_t u32Flag) { SET_REG32_BIT(M4_QSPI->SR2, (u32Flag & QSPI_FLAG_CLR_MSK)); } /** * @} */ #endif /* DDL_QSPI_ENABLE */ /** * @} */ /** * @} */ /****************************************************************************** * EOF (not truncated) *****************************************************************************/