blob: b1e967e9fba540833b8106de6f587be8afa1613b [file] [log] [blame]
/**
* \addtogroup BSP
* \{
* \addtogroup DEVICES
* \{
* \addtogroup QSPI
* \{
* \brief QSPI Flash Memory Controller
*/
/**
*****************************************************************************************
*
* @file hw_qspi.h
*
* @brief Definition of API for the QSPI Low Level Driver.
*
* Copyright (c) 2016, Dialog Semiconductor
* All rights reserved.
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*****************************************************************************************
*/
#ifndef HW_QSPI_H_
#define HW_QSPI_H_
#if dg_configUSE_HW_QSPI
#include <stdbool.h>
#include <stdint.h>
#include <sdk_defs.h>
/**
* \brief Get the mask of a field of an QSPIC register.
*
* \param [in] reg is the register to access
* \param [in] field is the register field to access
*
*/
#define HW_QSPIC_REG_FIELD_MASK(reg, field) \
(QSPIC_QSPIC_##reg##_REG_##QSPIC_##field##_Msk)
/**
* \brief Get the bit position of a field of an QSPIC register.
*
* \param [in] reg is the register to access
* \param [in] field is the register field to access
*
*/
#define HW_QSPIC_REG_FIELD_POS(reg, field) \
(QSPIC_QSPIC_##reg##_REG_##QSPIC_##field##_Pos)
/**
* \brief Get the value of a field of an QSPIC register.
*
* \param [in] reg is the register to access
* \param [in] field is the register field to write
*
* \return the value of the register field
*
*/
#define HW_QSPIC_REG_GETF(reg, field) \
((QSPIC->QSPIC_##reg##_REG & (QSPIC_QSPIC_##reg##_REG_##QSPIC_##field##_Msk)) >> (QSPIC_QSPIC_##reg##_REG_##QSPIC_##field##_Pos))
/**
* \brief Set the value of a field of an QSPIC register.
*
* \param [in] reg is the register to access
* \param [in] field is the register field to write
* \param [in] new_val is the value to write
*
*/
#define HW_QSPIC_REG_SETF(reg, field, new_val) \
QSPIC->QSPIC_##reg##_REG = ((QSPIC->QSPIC_##reg##_REG & ~(QSPIC_QSPIC_##reg##_REG_##QSPIC_##field##_Msk)) | \
((QSPIC_QSPIC_##reg##_REG_##QSPIC_##field##_Msk) & ((new_val) << (QSPIC_QSPIC_##reg##_REG_##QSPIC_##field##_Pos))))
extern uint8_t dummy_num[];
/*
* ENUMERATION DEFINITIONS
*****************************************************************************************
*/
/**
* \brief Bus mode
*
*/
typedef enum {
HW_QSPI_BUS_MODE_SINGLE, /**< Bus mode in single mode */
HW_QSPI_BUS_MODE_DUAL, /**< Bus mode in dual mode */
HW_QSPI_BUS_MODE_QUAD /**< Bus mode in quad mode */
} HW_QSPI_BUS_MODE;
/**
* \brief Flash memory address size
*
*/
typedef enum {
HW_QSPI_ADDR_SIZE_24, /**< QSPI flash memory uses 24 bits address */
HW_QSPI_ADDR_SIZE_32 /**< QSPI flash memory uses 32 bits address */
} HW_QSPI_ADDR_SIZE;
/**
* \brief Idle clock state
*
*/
typedef enum {
HW_QSPI_POL_LOW = 0, /**< SPI clock will be low at idle */
HW_QSPI_POL_HIGH = 1 /**< SPI clock will be high at idle */
} HW_QSPI_POL;
/**
* \brief Type of QSPI_CLK edge for sampling received data
*
*/
typedef enum {
HW_QSPI_SAMPLING_EDGE_POSITIVE = 0, /**< Sample the received data with the positive edge of the QSPI_SCK */
HW_QSPI_SAMPLING_EDGE_NEGATIVE = 1 /**< Sample the received data with the negative edge of the QSPI_SCK */
} HW_QSPI_SAMPLING_EDGE;
/**
* \brief Selected data size of a wrapping burst
*
*/
typedef enum {
HW_QSPI_WRAP_SIZE_8BITS = 0, /**< Byte access (8-bits) */
HW_QSPI_WRAP_SIZE_16BITS = 1, /**< Half word access (8-bits) */
HW_QSPI_WRAP_SIZE_32BITS = 2, /**< Word access (8-bits) */
} HW_QSPI_WRAP_SIZE;
/**
* \brief Selected data length of a wrapping burst
*
*/
typedef enum {
HW_QSPI_WRAP_LEN_4BEAT = 0, /**< 4 beat wrapping burst */
HW_QSPI_WRAP_LEN_8BEAT = 1, /**< 8 beat wrapping burst */
HW_QSPI_WRAP_LEN_16BEAT = 2, /**< 16 beat wrapping burst */
} HW_QSPI_WRAP_LEN;
/**
* \brief Size of Burst Break Sequence
*
*/
typedef enum {
HW_QSPI_BREAK_SEQ_SIZE_1B = 0, /**< One byte */
HW_QSPI_BREAK_SEQ_SIZE_2B = 1 /**< Two bytes */
} HW_QSPI_BREAK_SEQ_SIZE;
/**
* \brief QSPI pads slew rate control
*
*/
typedef enum {
HW_QSPI_SLEW_RATE_0, /**< xx V/ns (weak) */
HW_QSPI_SLEW_RATE_1, /**< xx V/ns */
HW_QSPI_SLEW_RATE_2, /**< xx V/ns */
HW_QSPI_SLEW_RATE_3 /**< xx V/ns (strong) */
} HW_QSPI_SLEW_RATE;
/**
* \brief QSPI pads drive current
*
*/
typedef enum {
HW_QSPI_DRIVE_CURRENT_4, /**< 4 mA */
HW_QSPI_DRIVE_CURRENT_8, /**< 8 mA */
HW_QSPI_DRIVE_CURRENT_12, /**< 12 mA */
HW_QSPI_DRIVE_CURRENT_16, /**< 16 mA */
} HW_QSPI_DRIVE_CURRENT;
/**
* \brief QSPI clock divider setting
*
*/
typedef enum {
HW_QSPI_DIV_1 = 0, /**< divide by 1 */
HW_QSPI_DIV_2 = 1, /**< divide by 2 */
HW_QSPI_DIV_4 = 2, /**< divide by 4 */
HW_QSPI_DIV_8 = 3 /**< divide by 8 */
} HW_QSPI_DIV;
/**
* \brief QSPI configuration
*
*/
typedef struct {
HW_QSPI_ADDR_SIZE address_size;
HW_QSPI_POL idle_clock;
HW_QSPI_SAMPLING_EDGE sampling_edge;
} qspi_config;
/**
* \brief Enable CS on QSPI bus
*
* Use this in manual mode.
*
*/
static inline void hw_qspi_cs_enable(void) __attribute__((always_inline));
static inline void hw_qspi_cs_enable(void)
{
QSPIC->QSPIC_CTRLBUS_REG = QSPIC_QSPIC_CTRLBUS_REG_QSPIC_EN_CS_Msk;
}
/**
* \brief Disable CS on QSPI bus
*
* Use this in manual mode.
*
*/
static inline void hw_qspi_cs_disable(void) __attribute__((always_inline));
static inline void hw_qspi_cs_disable(void)
{
QSPIC->QSPIC_CTRLBUS_REG = QSPIC_QSPIC_CTRLBUS_REG_QSPIC_DIS_CS_Msk;
}
/**
* \brief Select QSPI bus mode
*
* Use this in manual mode.
*
* \note Selecting QUAD mode will automatically configure pins IO2 and IO3 to input.
*
* \param [in] mode selects single/dual/quad mode for QSPI bus
*
*/
void hw_qspi_set_bus_mode(HW_QSPI_BUS_MODE mode);
/**
* \brief Check is SPI Bus is busy
*
* \return 0 - SPI Bus is idle,
* 1 - SPI Bus is active. ReadData, WriteData or DummyData activity is in progress
*
*/
static inline uint8_t hw_qspi_is_busy(void) __attribute__((always_inline));
static inline uint8_t hw_qspi_is_busy(void)
{
return (uint8_t) QSPIC->QSPIC_STATUS_REG;
}
/**
* \brief Generate 32 bits read transfer on QSPI bus
*
* The data is transferred using the selected mode of the SPI bus (SPI, Dual
* SPI, Quad SPI).
*
* \return data read during read transfer
*
*/
static inline uint32_t hw_qspi_read32(void) __attribute__((always_inline));
static inline uint32_t hw_qspi_read32(void)
{
return QSPIC->QSPIC_READDATA_REG;
}
/**
* \brief Generate 16 bits read transfer on QSPI bus
*
* The data is transferred using the selected mode of the SPI bus (SPI, Dual
* SPI, Quad SPI).
*
* \return data read during read transfer
*
*/
static inline uint16_t hw_qspi_read16(void) __attribute__((always_inline));
static inline uint16_t hw_qspi_read16(void)
{
return *((volatile uint16_t *) &(QSPIC->QSPIC_READDATA_REG));
}
/**
* \brief Generate 8 bits read transfer on QSPI bus
*
* The data is transferred using the selected mode of the SPI bus (SPI, Dual
* SPI, Quad SPI).
*
* \return data read during read transfer
*
*/
static inline uint8_t hw_qspi_read8(void) __attribute__((always_inline));
static inline uint8_t hw_qspi_read8(void)
{
return *((volatile uint8_t *) &(QSPIC->QSPIC_READDATA_REG));
}
/**
* \brief Generate 32 bits write transfer on QSPI bus
*
* The data is transferred using the selected mode of the SPI bus (SPI, Dual
* SPI, Quad SPI).
*
* param [in] data data to transfer
*
*/
static inline void hw_qspi_write32(uint32_t data) __attribute__((always_inline));
static inline void hw_qspi_write32(uint32_t data)
{
QSPIC->QSPIC_WRITEDATA_REG = data;
}
/**
* \brief Generate 16 bits write transfer on QSPI bus
*
* The data is transferred using the selected mode of the SPI bus (SPI, Dual
* SPI, Quad SPI).
*
* param [in] data data to transfer
*
*/
static inline void hw_qspi_write16(uint16_t data) __attribute__((always_inline));
static inline void hw_qspi_write16(uint16_t data)
{
*((volatile uint16_t *) &(QSPIC->QSPIC_WRITEDATA_REG)) = data;
}
/**
* \brief Generate 8 bits write transfer on QSPI bus
*
* The data is transferred using the selected mode of the SPI bus (SPI, Dual
* SPI, Quad SPI).
*
* param [in] data data to transfer
*
*/
static inline void hw_qspi_write8(uint8_t data) __attribute__((always_inline));
static inline void hw_qspi_write8(uint8_t data)
{
*((volatile uint8_t *) &(QSPIC->QSPIC_WRITEDATA_REG)) = data;
}
/**
* \brief Generate a clock pulses to the SPI bus for 32 bits transfer
*
* During this activity in the SPI bus, the QSPI_IOx data pads are in hi-z state.
* Number of pulses depends on selected mode of the SPI bus (SPI, Dual SPI, Quad SPI).
*
*/
static inline void hw_qspi_dummy32(void) __attribute__((always_inline));
static inline void hw_qspi_dummy32(void)
{
QSPIC->QSPIC_DUMMYDATA_REG = 0;
}
/**
* \brief Generate a clock pulses to the SPI bus for 16 bits transfer
*
* During this activity in the SPI bus, the QSPI_IOx data pads are in hi-z state.
* Number of pulses depends on selected mode of the SPI bus (SPI, Dual SPI, Quad SPI).
*
*/
static inline void hw_qspi_dummy16(void) __attribute__((always_inline));
static inline void hw_qspi_dummy16(void)
{
*((volatile uint16_t *) &(QSPIC->QSPIC_DUMMYDATA_REG)) = 0;
}
/**
* \brief Generate a clock pulses to the SPI bus for 8 bits transfer
*
* During this activity in the SPI bus, the QSPI_IOx data pads are in hi-z state.
* Number of pulses depends on selected mode of the SPI bus (SPI, Dual SPI, Quad SPI).
*
*/
static inline void hw_qspi_dummy8(void) __attribute__((always_inline));
static inline void hw_qspi_dummy8(void)
{
*((volatile uint8_t *) &(QSPIC->QSPIC_DUMMYDATA_REG)) = 0;
}
/**
* \brief Specifies address with that flash memory uses
*
* The controller uses 32 of 24 bits for address during Auto mode transfer.
*
* \param [in] size selects 32 or 24 address size
*
*/
static inline void hw_qspi_set_address_size(HW_QSPI_ADDR_SIZE size) __attribute__((always_inline));
static inline void hw_qspi_set_address_size(HW_QSPI_ADDR_SIZE size)
{
HW_QSPIC_REG_SETF(CTRLMODE, USE_32BA, (size == HW_QSPI_ADDR_SIZE_32 ? 1 : 0));
}
/**
* \brief Get address size that flash memory uses
*
* The controller uses 32 of 24 bits for address during Auto mode transfer.
*
* \return currently selected address size
*
* \sa hw_qspi_set_address_size
*
*/
static inline HW_QSPI_ADDR_SIZE hw_qspi_get_address_size(void) __attribute__((always_inline));
static inline HW_QSPI_ADDR_SIZE hw_qspi_get_address_size(void)
{
return (HW_QSPI_ADDR_SIZE) HW_QSPIC_REG_GETF(CTRLMODE, USE_32BA);
}
/**
* \brief Controls translation of burst accesses form AMBA bus to the QSPI bus
*
* \param [in] force 0 - controller translates a burst access on the AMBA bus
* to a burst access on the QSPI bus. That results to a minimum
* command/address phases, but the QSPI_CS is low for as
* long as the access occures,
* 1 - controller will split a burst access on the AMBA bus
* into single accesses on the qspi bus. This results to a separate
* read command to the FLASH memory foreach data
* required. A 4-beat word incremental AMBA access will be
* split into 4 different sequences of reading (command/address/
* extra clock/read data). QSPI_CS will be only high while a qspi
* access occures. This results to lower power dissipation with
* respect to QSPIC_FORCENSEQ_EN=0 at cost of performance
*
*/
static inline void hw_qspi_force_nseq(uint8_t force) __attribute__((always_inline));
static inline void hw_qspi_force_nseq(uint8_t force)
{
HW_QSPIC_REG_SETF(CTRLMODE, FORCENSEQ_EN, force);
}
/**
* \brief Enable or disable auto mode on QSPI
*
* \note Selecting auto mode when any command previously configured has chosen
* QUAD mode for any phase will automatically configure pins IO2 and IO3 to input.
*
* \param [in] automode true auto mode selected,
* false manual mode selected
*
* \sa hw_qspi_set_read_instruction
* \sa hw_qspi_set_read_status_instruction
* \sa hw_qspi_set_suspend_resume_instructions
* \sa hw_qspi_set_write_enable_instruction
* \sa hw_qspi_set_extra_byte
* \sa hw_qspi_set_erase_instruction
* \sa hw_qspi_set_break_sequence
*
*/
void hw_qspi_set_automode(bool automode);
/**
* \brief Read automode state
*
* \return true auto mode is selected,
* false manual mode is selected
*
*/
static inline bool hw_qspi_get_automode(void) __attribute__((always_inline));
static inline bool hw_qspi_get_automode(void)
{
return HW_QSPIC_REG_GETF(CTRLMODE, AUTO_MD);
}
/**
* \brief Get read pipe clock delay
*
* \return read pipe clock delay relative to the falling edge of QSPI_SCK
*
*/
static inline uint8_t hw_qspi_get_read_pipe_clock_delay(void) __attribute__((always_inline));
static inline uint8_t hw_qspi_get_read_pipe_clock_delay(void)
{
return HW_QSPIC_REG_GETF(CTRLMODE, PCLK_MD);
}
/**
* \brief Set read pipe clock delay
*
* \param [in] delay read pipe clock delay relative to the falling edge of QSPI_SCK
* value should be in range 0..7
*
*/
static inline void hw_qspi_set_read_pipe_clock_delay(uint8_t delay) __attribute__((always_inline));
static inline void hw_qspi_set_read_pipe_clock_delay(uint8_t delay)
{
HW_QSPIC_REG_SETF(CTRLMODE, PCLK_MD, delay);
}
/**
* \brief Check if read pipe is enabled
*
* \return 1 if read pipe is enabled, 0 otherwise
*
*/
static inline uint8_t hw_qspi_is_read_pipe_clock_enabled(void) __attribute__((always_inline));
static inline uint8_t hw_qspi_is_read_pipe_clock_enabled(void)
{
return HW_QSPIC_REG_GETF(CTRLMODE, RPIPE_EN);
}
/**
* \brief Enable read pipe
*
* \param [in] enable 1 enable read pipe,
* 0 disable read pipe
*
*/
static inline void hw_qspi_enable_readpipe(uint8_t enable) __attribute__((always_inline));
static inline void hw_qspi_enable_readpipe(uint8_t enable)
{
HW_QSPIC_REG_SETF(CTRLMODE, RPIPE_EN, enable);
}
/**
* \brief Get read sampling edge
*
* \return type of QSPI_CLK edge for sampling received data
*
*/
static inline HW_QSPI_SAMPLING_EDGE hw_qspi_get_read_sampling_edge(void) __attribute__((always_inline));
static inline HW_QSPI_SAMPLING_EDGE hw_qspi_get_read_sampling_edge(void)
{
return HW_QSPIC_REG_GETF(CTRLMODE, RXD_NEG);
}
/**
* \brief Set read sampling edge
*
* \param [in] edge sets whether read samples or taken on rising or falling edge
* of QSPI_SCK
*
*/
static inline void hw_qspi_set_read_sampling_edge(HW_QSPI_SAMPLING_EDGE edge) __attribute__((always_inline));
static inline void hw_qspi_set_read_sampling_edge(HW_QSPI_SAMPLING_EDGE edge)
{
HW_QSPIC_REG_SETF(CTRLMODE, RXD_NEG, edge);
}
/**
* \brief Check if hready signal is used
*
* \return 0 - when wait states are not added via hready signal during access to
* QSPIC_WRITEDATA, QSPIC_READDATA and QSPIC_DUMMYDATA registers,
* 1 - when wait states are added via hready signal during access to
* QSPIC_WRITEDATA, QSPIC_READDATA and QSPIC_DUMMYDATA registers.
* In this case read read QSPI_STATUS register to check the end of
* activity at the SPI bus
*
*/
static inline uint8_t hw_qspi_is_hready_enabled(void) __attribute__((always_inline));
static inline uint8_t hw_qspi_is_hready_enabled(void)
{
return HW_QSPIC_REG_GETF(CTRLMODE, HRDY_MD);
}
/**
* \brief Enable/disable adding wait states during register access
*
* \param [in] enable 0 - wait states will be added in hready signal during access to
* QSPIC_WRITEDATA, QSPIC_READDATA and QSPIC_DUMMYDATA registers
*
*/
static inline void hw_qspi_enable_hready(uint8_t enable) __attribute__((always_inline));
static inline void hw_qspi_enable_hready(uint8_t enable)
{
HW_QSPIC_REG_SETF(CTRLMODE, HRDY_MD, enable);
}
/**
* \brief Get clock mode
*
* \return 0 - SPI mode 0 is used for QSPI_CLK, the QSPI_SCK is low when QSPI_CS is high (idle),
* 1 - SPI mode 3 is used for QSPI_CLK, the QSPI_SCK is high when QSPI_CS is high (idle)
*
*/
static inline uint8_t hw_qspi_get_clock_mode(void) __attribute__((always_inline));
static inline uint8_t hw_qspi_get_clock_mode(void)
{
return HW_QSPIC_REG_GETF(CTRLMODE, CLK_MD);
}
/**
* \brief Set clock mode
*
* \param [in] mode HW_SPI_POL_LOW - SPI mode 0 is used for QSPI_CLK,
* The QSPI_SCK is low when QSPI_CS is high (idle),
* HW_SPI_POL_HIGH - SPI mode 3 is used for QSPI_CLK,
* The QSPI_SCK is high when QSPI_CS is high (idle)
*
*/
static inline void hw_qspi_set_clock_mode(HW_QSPI_POL mode) __attribute__((always_inline));
static inline void hw_qspi_set_clock_mode(HW_QSPI_POL mode)
{
HW_QSPIC_REG_SETF(CTRLMODE, CLK_MD, mode);
}
/**
* \brief Set IO2 direction
*
* \param [in] output QSPI_IO2 output enable. Use this only in SPI or Dual SPI
* mode to control /WP signal. When the Auto Mode is selected
* and the QUAD SPI is used, set this to false.
* false: The QSPI_IO2 pad is input
* true: The QSPI_IO2 pad is output
*
*/
#if (dg_configFLASH_POWER_DOWN == 1)
__attribute__((section("text_retained")))
#endif
static inline void hw_qspi_set_io2_output(bool output) __attribute__((always_inline));
static inline void hw_qspi_set_io2_output(bool output)
{
HW_QSPIC_REG_SETF(CTRLMODE, IO2_OEN, output);
}
/**
* \brief Set IO3 direction
*
* \param [in] output Use this only in SPI or Dual SPI mode to control /HOLD signal.
* When the Auto Mode is selected and the QUAD SPI is used,
* set this to false.
* false: The QSPI_IO3 pad is input,
* true: The QSPI_IO3 pad is output
*
*/
#if (dg_configFLASH_POWER_DOWN == 1)
__attribute__((section("text_retained")))
#endif
static inline void hw_qspi_set_io3_output(bool output) __attribute__((always_inline));
static inline void hw_qspi_set_io3_output(bool output)
{
HW_QSPIC_REG_SETF(CTRLMODE, IO3_OEN, output);
}
/**
* \brief Set state for IO2 when it's configured as output
*
* \param [in] val QSPI_IO2 value to set (0 or 1)
*
* \sa hw_qspi_set_io2_direction
*
*/
static inline void hw_qspi_set_io2(uint8_t val) __attribute__((always_inline));
static inline void hw_qspi_set_io2(uint8_t val)
{
HW_QSPIC_REG_SETF(CTRLMODE, IO2_DAT, val);
}
/**
* \brief Set state for IO3 when it's configured as output
*
* \param [in] val QSPI_IO3 value to set (0 or 1)
*
* \sa hw_qspi_set_io3_direction
*
*/
static inline void hw_qspi_set_io3(uint8_t val) __attribute__((always_inline));
static inline void hw_qspi_set_io3(uint8_t val)
{
HW_QSPIC_REG_SETF(CTRLMODE, IO3_DAT, val);
}
/**
* \brief Read state of IO2 when not in QUAD mode
*
* \return value of IO2 pin (0 or 1)
*
*/
static inline uint8_t hw_qspi_get_io2(void) __attribute__((always_inline));
static inline uint8_t hw_qspi_get_io2(void)
{
return HW_QSPIC_REG_GETF(CTRLMODE, IO2_DAT);
}
/**
* \brief Read state of IO3 when not in QUAD mode
*
* \return value of IO3 pin (0 or 1)
*
*/
static inline uint8_t hw_qspi_get_io3(void) __attribute__((always_inline));
static inline uint8_t hw_qspi_get_io3(void)
{
return HW_QSPIC_REG_GETF(CTRLMODE, IO3_DAT);
}
/**
* \brief Set read instructions for QSPI flash
*
* This function sets up instruction to be sent to flash memory when data is requested
* on AHB bus.
*
* \param [in] inst instruction for Incremental Burst or Single read access.
* This value is the selected instruction at the cases of incremental
* burst or single read access. Also this value is used when a wrapping
* burst is not supported.
* \param [in] send_once 0 - transmit instruction at any burst access,
* 1 - transmit instruction only in the first access after the
* selection of Auto Mode.
* \param [in] dummy_count number of dummy bytes to send 0..4
* \param [in] inst_phase describes the mode of the SPI bus during the instruction phase
* \param [in] addr_phase describes the mode of the SPI bus during the address phase
* \param [in] dummy_phase describes the mode of the SPI bus during the dummy phase
* \param [in] data_phase describes the mode of the SPI bus during the data phase
*
* \sa hw_qspi_set_extra_byte
* \sa hw_qspi_set_wrapping_burst_instruction
*
*/
static inline void hw_qspi_set_read_instruction(uint8_t inst,
uint8_t send_once,
uint8_t dummy_count,
HW_QSPI_BUS_MODE inst_phase,
HW_QSPI_BUS_MODE addr_phase,
HW_QSPI_BUS_MODE dummy_phase,
HW_QSPI_BUS_MODE data_phase)
__attribute((always_inline));
static inline void hw_qspi_set_read_instruction(uint8_t inst,
uint8_t send_once,
uint8_t dummy_count,
HW_QSPI_BUS_MODE inst_phase,
HW_QSPI_BUS_MODE addr_phase,
HW_QSPI_BUS_MODE dummy_phase,
HW_QSPI_BUS_MODE data_phase)
{
QSPIC->QSPIC_BURSTCMDA_REG =
BITS32(QSPIC, QSPIC_BURSTCMDA_REG, QSPIC_INST, inst) |
BITS32(QSPIC, QSPIC_BURSTCMDA_REG, QSPIC_INST_TX_MD, inst_phase) |
BITS32(QSPIC, QSPIC_BURSTCMDA_REG, QSPIC_ADR_TX_MD, addr_phase) |
BITS32(QSPIC, QSPIC_BURSTCMDA_REG, QSPIC_DMY_TX_MD, dummy_phase);
QSPIC->QSPIC_BURSTCMDB_REG =
BITS32(QSPIC, QSPIC_BURSTCMDB_REG, QSPIC_DAT_RX_MD, data_phase) |
BITS32(QSPIC, QSPIC_BURSTCMDB_REG, QSPIC_INST_MD, send_once) |
BITS32(QSPIC, QSPIC_BURSTCMDB_REG, QSPIC_DMY_FORCE, (dummy_count == 3 ? 1 : 0)) |
BITS32(QSPIC, QSPIC_BURSTCMDB_REG, QSPIC_DMY_NUM, dummy_num[dummy_count]);
}
/**
* \brief Set wrapping burst read instructions for QSPI flash
*
* Calling this function will set up wrapping burst instruction to use.
* Use this feature only when the serial FLASH memory supports a special
* instruction for wrapping burst access.
*
* \param [in] inst instruction for Wrapping Burst
* \param [in] len describes the selected length of a wrapping burst
* \param [in] size describes the selected data size of a wrapping burst
*
*/
void hw_qspi_set_wrapping_burst_instruction(uint8_t inst, HW_QSPI_WRAP_LEN len,
HW_QSPI_WRAP_SIZE size);
/**
* \brief Set extra byte to use in read instruction
*
* \param [in] extra_byte the value of an extra byte which will be transferred after
* address. This byte is used for telling memory if it should stay
* in continuous read mode or wait for normal instruction after CS
* goes inactive
* \param [in] bus_mode describes the mode of the SPI bus during the extra byte phase.
* \param [in] half_disable_out 1 - disable (hi-z) output during the transmission
* of bits [3:0] of extra byte
*
* \sa hw_qspi_set_read_instruction
*
*/
static inline void hw_qspi_set_extra_byte(uint8_t extra_byte, HW_QSPI_BUS_MODE bus_mode,
uint8_t half_disable_out) __attribute__((always_inline));
static inline void hw_qspi_set_extra_byte(uint8_t extra_byte, HW_QSPI_BUS_MODE bus_mode,
uint8_t half_disable_out)
{
QSPIC->QSPIC_BURSTCMDA_REG =
(QSPIC->QSPIC_BURSTCMDA_REG &
~(REG_MSK(QSPIC, QSPIC_BURSTCMDA_REG, QSPIC_EXT_BYTE) |
REG_MSK(QSPIC, QSPIC_BURSTCMDA_REG, QSPIC_EXT_TX_MD))) |
BITS32(QSPIC, QSPIC_BURSTCMDA_REG, QSPIC_EXT_BYTE, extra_byte) |
BITS32(QSPIC, QSPIC_BURSTCMDA_REG, QSPIC_EXT_TX_MD, bus_mode);
QSPIC->QSPIC_BURSTCMDB_REG =
(QSPIC->QSPIC_BURSTCMDB_REG &
~(REG_MSK(QSPIC, QSPIC_BURSTCMDB_REG, QSPIC_EXT_BYTE_EN) |
REG_MSK(QSPIC, QSPIC_BURSTCMDB_REG, QSPIC_EXT_HF_DS))) |
BITS32(QSPIC, QSPIC_BURSTCMDB_REG, QSPIC_EXT_BYTE_EN, 1) |
BITS32(QSPIC, QSPIC_BURSTCMDB_REG, QSPIC_EXT_HF_DS, half_disable_out ? 1 : 0);
}
/**
* \brief Set dummy byte count
*
* Number of dummy bytes to send when read instruction is executed.
*
* \param [in] count number of dummy bytes to send 0..4
*
*/
void hw_qspi_set_dummy_bytes_count(uint8_t count);
/**
* \brief Set number of clock when CS stays high
*
* \param [in] clock_count between the transmission of two different instructions to the
* flash memory, the qspi bus stays in idle state (QSPI_CS high)
* for at least this number of spi clock cycles. See the QSPIC_ERS_CS_HI
* register for an exception
*
*/
static inline void hw_qspi_set_min_cs_high(uint8_t clock_count) __attribute__((always_inline));
static inline void hw_qspi_set_min_cs_high(uint8_t clock_count)
{
HW_QSPIC_REG_SETF(BURSTCMDB, CS_HIGH_MIN, clock_count);
}
/**
* \brief Set up erase instructions
*
* Instruction will be send after call to hw_qspi_erase_block.
*
* \param [in] inst code value of the erase instruction
* \param [in] inst_phase mode of the QSPI Bus during the instruction phase of the erase instruction
* \param [in] addr_phase the mode of the QSPI Bus during the address phase of the erase instruction
* \param [in] hclk_cycles the controller must stay without flash memory reading
* requests for this number of AMBA AHB hclk cycles, before
* performs the command of erase or resume 15 - 0
* \param [in] cs_hi_cycles after the execution of instructions: write enable, erase, erase
* suspend and erase resume, the QSPI_CS remains high for at
* least this number of qspi bus clock cycles
*
* \sa hw_qspi_erase_block
*
*/
static inline void hw_qspi_set_erase_instruction(uint8_t inst, HW_QSPI_BUS_MODE inst_phase,
HW_QSPI_BUS_MODE addr_phase, uint8_t hclk_cycles, uint8_t cs_hi_cycles)
__attribute__((always_inline));
static inline void hw_qspi_set_erase_instruction(uint8_t inst, HW_QSPI_BUS_MODE inst_phase,
HW_QSPI_BUS_MODE addr_phase, uint8_t hclk_cycles, uint8_t cs_hi_cycles)
{
HW_QSPIC_REG_SETF(ERASECMDA, ERS_INST, inst);
QSPIC->QSPIC_ERASECMDB_REG =
(QSPIC->QSPIC_ERASECMDB_REG &
~(REG_MSK(QSPIC, QSPIC_ERASECMDB_REG, QSPIC_ERS_TX_MD) |
REG_MSK(QSPIC, QSPIC_ERASECMDB_REG, QSPIC_EAD_TX_MD) |
REG_MSK(QSPIC, QSPIC_ERASECMDB_REG, QSPIC_ERSRES_HLD) |
REG_MSK(QSPIC, QSPIC_ERASECMDB_REG, QSPIC_ERS_CS_HI))) |
BITS32(QSPIC, QSPIC_ERASECMDB_REG, QSPIC_ERS_TX_MD, inst_phase) |
BITS32(QSPIC, QSPIC_ERASECMDB_REG, QSPIC_EAD_TX_MD, addr_phase) |
BITS32(QSPIC, QSPIC_ERASECMDB_REG, QSPIC_ERSRES_HLD, hclk_cycles) |
BITS32(QSPIC, QSPIC_ERASECMDB_REG, QSPIC_ERS_CS_HI, cs_hi_cycles);
}
/**
* \brief Set up write enable instruction
*
* Instruction setup by this function will be executed before erase.
*
* \param [in] write_enable code value of the write enable instruction
* \param [in] inst_phase mode of the QSPI Bus during the instruction phase
*
* \sa hw_qspi_erase_block
* \sa hw_qspi_set_erase_instruction
*
*/
static inline void hw_qspi_set_write_enable_instruction(uint8_t write_enable,
HW_QSPI_BUS_MODE inst_phase)
__attribute((always_inline));
static inline void hw_qspi_set_write_enable_instruction(uint8_t write_enable,
HW_QSPI_BUS_MODE inst_phase)
{
HW_QSPIC_REG_SETF(ERASECMDA, WEN_INST, write_enable);
HW_QSPIC_REG_SETF(ERASECMDB, WEN_TX_MD, inst_phase);
}
/**
* \brief Set up erase suspend/resume instructions
*
* \param [in] erase_suspend_inst code value of the erase suspend instruction.
* \param [in] suspend_inst_phase mode of the QSPI Bus during the instruction phase
* of the suspend instruction
* \param [in] erase_resume_inst code value of the erase resume instruction.
* \param [in] resume_inst_phase mode of the QSPI Bus during the instruction phase
* of the resume instruction
* \param [in] minimum_delay defines the minimum time distance between the instruction
* erase suspend and the previous instruction erase resume.
* This delay will be also applied after the Erase command.
* 0 - don't wait. The controller starts the erase suspend procedure
* immediately,
* 1..63 - controller waits at least this number of 288kHz clock cycles
* before the suspension of erasing. Time starts counting after
* the end of the previous erase resume
*
*/
static inline void hw_qspi_set_suspend_resume_instructions(uint8_t erase_suspend_inst,
HW_QSPI_BUS_MODE suspend_inst_phase,
uint8_t erase_resume_inst,
HW_QSPI_BUS_MODE resume_inst_phase,
uint8_t minimum_delay)
__attribute((always_inline));
static inline void hw_qspi_set_suspend_resume_instructions(uint8_t erase_suspend_inst,
HW_QSPI_BUS_MODE suspend_inst_phase,
uint8_t erase_resume_inst,
HW_QSPI_BUS_MODE resume_inst_phase,
uint8_t minimum_delay)
{
QSPIC->QSPIC_ERASECMDA_REG =
(QSPIC->QSPIC_ERASECMDA_REG &
~(REG_MSK(QSPIC, QSPIC_ERASECMDA_REG, QSPIC_SUS_INST) |
REG_MSK(QSPIC, QSPIC_ERASECMDA_REG, QSPIC_RES_INST))) |
BITS32(QSPIC, QSPIC_ERASECMDA_REG, QSPIC_SUS_INST, erase_suspend_inst) |
BITS32(QSPIC, QSPIC_ERASECMDA_REG, QSPIC_RES_INST, erase_resume_inst);
QSPIC->QSPIC_ERASECMDB_REG =
(QSPIC->QSPIC_ERASECMDB_REG &
~(REG_MSK(QSPIC, QSPIC_ERASECMDB_REG, QSPIC_SUS_TX_MD) |
REG_MSK(QSPIC, QSPIC_ERASECMDB_REG, QSPIC_RES_TX_MD) |
REG_MSK(QSPIC, QSPIC_ERASECMDB_REG, QSPIC_RESSUS_DLY))) |
BITS32(QSPIC, QSPIC_ERASECMDB_REG, QSPIC_SUS_TX_MD, suspend_inst_phase) |
BITS32(QSPIC, QSPIC_ERASECMDB_REG, QSPIC_RES_TX_MD, resume_inst_phase) |
BITS32(QSPIC, QSPIC_ERASECMDB_REG, QSPIC_RESSUS_DLY, minimum_delay);
}
/**
* \brief Set status command
*
* This command will be send by QSPI controller when it needs to check status of flash memory.
* This command is also send indirectly when hw_qspi_get_erase_status is called.
*
* \param [in] inst instruction for read status
* \param [in] inst_phase mode of the QSPI Bus during the instruction phase of the read
* status instruction
* \param [in] receive_phase mode of the QSPI Bus during the receive status phase of
* the read status instruction
* \param [in] busy_pos it describes which bit from the bits of status represents
* the Busy bit (7 - 0)
* \param [in] busy_val defines the value of the Busy bit which means that the flash is busy
* 0 - flash is busy when the Busy bit is equal to 0,
* 1 - flash is busy when the Busy bit is equal to 1
* \param [in] read_delay defines the minimum time distance between the instruction
* read status register and previous instructions like erase or
* resume. The same delay will be also applied after the Erase command.
* 0 - don't wait. The controller starts to read the Flash memory
* status register immediately.
* 1..63 - controller waits at least the number of QSPI_CLK
* cycles and afterwards it starts to read the Flash memory status
* register. Time starts counting after the end of the previous
* erase/resume.
* \param [in] sts_delay defines the register to count the delay to wait for the FLASH Status
* Register read after an erase or erase/ resume command.
* 0 - delay is controlled by the \p read_dealy (QSPIC_RESSTS_DLY)
* which counts on the qspi clock,
* 1 - delay is controlled by the \p minimum_delay value passed to
* hw_qspi_set_suspend_resume_instructions (QSPIC_RESSUS_DLY) which
* counts on the 288 kHz clock
*
* \sa hw_qspi_set_suspend_resume_instructions
* \sa hw_qspi_get_erase_status
*
*/
static inline void hw_qspi_set_read_status_instruction(uint8_t inst,
HW_QSPI_BUS_MODE inst_phase,
HW_QSPI_BUS_MODE receive_phase,
uint8_t busy_pos,
uint8_t busy_val,
uint8_t read_delay,
uint8_t sts_delay)
__attribute((always_inline));
static inline void hw_qspi_set_read_status_instruction(uint8_t inst,
HW_QSPI_BUS_MODE inst_phase,
HW_QSPI_BUS_MODE receive_phase,
uint8_t busy_pos,
uint8_t busy_val,
uint8_t read_delay,
uint8_t sts_delay)
{
QSPIC->QSPIC_STATUSCMD_REG =
BITS32(QSPIC, QSPIC_STATUSCMD_REG, QSPIC_BUSY_VAL, busy_val) |
BITS32(QSPIC, QSPIC_STATUSCMD_REG, QSPIC_BUSY_POS , busy_pos) |
BITS32(QSPIC, QSPIC_STATUSCMD_REG, QSPIC_RSTAT_RX_MD, receive_phase) |
BITS32(QSPIC, QSPIC_STATUSCMD_REG, QSPIC_RSTAT_TX_MD, inst_phase) |
BITS32(QSPIC, QSPIC_STATUSCMD_REG, QSPIC_RSTAT_INST, inst) |
BITS32(QSPIC, QSPIC_STATUSCMD_REG, QSPIC_STSDLY_SEL, sts_delay) |
BITS32(QSPIC, QSPIC_STATUSCMD_REG, QSPIC_RESSTS_DLY, read_delay);
}
/**
* \brief Erase block/sector of flash memory
*
* For this function to work, erase instructions must be set up
* with hw_qspi_set_erase_instruction.
* User should call hw_qspi_get_erase_status to check if block erased.
*
* \note If user doesn't call hw_qspi_get_erase_status that returns status 0
* QSPI controller will not be able to switch to manual mode.
*
* \param [in] addr memory address of block/sector thats is requested to be erased
* for 24 bits addressing, bits [23:12] determine the block/sector
* address bits. Bits [11:0] are ignored by the controller.
* For 32 bits addressing, bits [31:12] determine the block/sectors
* address bits. Bits [11:0] are ignored by the controller
*
* \sa hw_qspi_set_erase_instruction
* \sa hw_qspi_get_erase_status
* \sa hw_qspi_set_automode
*
*/
void hw_qspi_erase_block(uint32_t addr);
/**
* \brief Get erase status
*
* \return progress of sector/block erasing
* 0 = no erase,
* 1 = pending erase request,
* 2 = erase procedure is running,
* 3 = suspended erase procedure,
* 4 = finishing the erase procedure
*
*/
static inline uint8_t hw_qspi_get_erase_status(void) __attribute__((always_inline));
static inline uint8_t hw_qspi_get_erase_status(void)
{
QSPIC->QSPIC_CHCKERASE_REG = 0;
return HW_QSPIC_REG_GETF(ERASECTRL, ERS_STATE);
}
/**
* \brief Set burst break sequence
*
* \param [in] sequence value will be transmitted as the burst break sequence
* \param [in] mode mode of the QSPI Bus during the transmission of the burst break sequence
* \param [in] size size of Burst Break Sequence
* \param [in] dis_out disable output during the transmission of the second half (sequence[3:0]).
* Setting this bit is only useful if size = 1.
* 0 - controller drives the QSPI bus during the transmission
* of the sequence[3:0],
* 1 - controller leaves the QSPI bus in Hi-Z during the transmission
* of the sequence[3:0]
*
*/
static inline void hw_qspi_set_break_sequence(uint16_t sequence, HW_QSPI_BUS_MODE mode,
HW_QSPI_BREAK_SEQ_SIZE size, uint8_t dis_out)
__attribute__((always_inline));
static inline void hw_qspi_set_break_sequence(uint16_t sequence, HW_QSPI_BUS_MODE mode,
HW_QSPI_BREAK_SEQ_SIZE size, uint8_t dis_out)
{
QSPIC->QSPIC_BURSTBRK_REG =
BITS32(QSPIC, QSPIC_BURSTBRK_REG, QSPIC_SEC_HF_DS, dis_out) |
BITS32(QSPIC, QSPIC_BURSTBRK_REG, QSPIC_BRK_SZ, size) |
BITS32(QSPIC, QSPIC_BURSTBRK_REG, QSPIC_BRK_TX_MD, mode) |
BITS32(QSPIC, QSPIC_BURSTBRK_REG, QSPIC_BRK_EN, 1) |
BITS32(QSPIC, QSPIC_BURSTBRK_REG, QSPIC_BRK_WRD, sequence);
}
/**
* \brief Disable burst break sequence
*
*/
static inline void hw_qspi_disable_burst_break_sequence(void) __attribute__((always_inline));
static inline void hw_qspi_disable_burst_break_sequence(void)
{
HW_QSPIC_REG_SETF(BURSTBRK, BRK_EN, 0);
}
/**
* \brief Set configuration of QSPI pads
*
* \param [in] rate QSPI pads slew rate control
* \param [in] current QSPI pads drive current
*
*/
void hw_qspi_set_pads(HW_QSPI_SLEW_RATE rate, HW_QSPI_DRIVE_CURRENT current);
/**
* \brief QSPI controller initialization
*
* This function will enable QSPI controller in manual mode.
*
* \note This function doesn't change QSPI_DIV
*
*/
void hw_qspi_init(const qspi_config *cfg);
/**
* \brief Enable QSPI controller clock
*
*/
static inline void hw_qspi_enable_clock(void) __attribute__((always_inline));
static inline void hw_qspi_enable_clock(void)
{
GLOBAL_INT_DISABLE();
CRG_TOP->CLK_AMBA_REG |= 1 << REG_POS(CRG_TOP, CLK_AMBA_REG, QSPI_ENABLE);
GLOBAL_INT_RESTORE();
}
/**
* \brief Disable QSPI controller clock
*
*/
static inline void hw_qspi_disable_clock(void) __attribute__((always_inline));
static inline void hw_qspi_disable_clock(void)
{
GLOBAL_INT_DISABLE();
CRG_TOP->CLK_AMBA_REG &= ~REG_MSK(CRG_TOP, CLK_AMBA_REG, QSPI_ENABLE);
GLOBAL_INT_RESTORE();
}
/**
* \brief Set the QSPI clock divider
*
* \param [in] div QSPI clock divider
*
* \sa HW_QSPI_DIV
*/
static inline void hw_qspi_set_div(HW_QSPI_DIV div) __attribute__((always_inline));
static inline void hw_qspi_set_div(HW_QSPI_DIV div)
{
GLOBAL_INT_DISABLE();
REG_SETF(CRG_TOP, CLK_AMBA_REG, QSPI_DIV, div);
GLOBAL_INT_RESTORE();
}
/**
* \brief Get the QSPI clock divider
*
* \return the QSPI clock divider setting
*
* \sa HW_QSPI_DIV
*/
static inline HW_QSPI_DIV hw_qspi_get_div(void) __attribute__((always_inline));
static inline HW_QSPI_DIV hw_qspi_get_div(void)
{
return REG_GETF(CRG_TOP, CLK_AMBA_REG, QSPI_DIV);
}
#endif /* dg_configUSE_HW_QSPI */
#endif /* HW_QSPI_H_ */
/**
* \}
* \}
* \}
*/