1 /***************************************************************************//**
2 * \file cyhal_qspi.h
3 *
4 * \brief
5 * Provides a high level interface for interacting with the Infineon Quad-SPI.
6 * This interface abstracts out the chip specific details. If any chip specific
7 * functionality is necessary, or performance is critical the low level functions
8 * can be used directly.
9 *
10 ********************************************************************************
11 * \copyright
12 * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
13 * an affiliate of Cypress Semiconductor Corporation
14 *
15 * SPDX-License-Identifier: Apache-2.0
16 *
17 * Licensed under the Apache License, Version 2.0 (the "License");
18 * you may not use this file except in compliance with the License.
19 * You may obtain a copy of the License at
20 *
21 *     http://www.apache.org/licenses/LICENSE-2.0
22 *
23 * Unless required by applicable law or agreed to in writing, software
24 * distributed under the License is distributed on an "AS IS" BASIS,
25 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26 * See the License for the specific language governing permissions and
27 * limitations under the License.
28 *******************************************************************************/
29 
30 /**
31 * \addtogroup group_hal_qspi QSPI (Quad Serial Peripheral Interface)
32 * \ingroup group_hal
33 * \{
34 * High level interface for interacting with the Quad-SPI interface.
35 *
36 * QSPI is an SPI-based communication interface, often used with external memory devices.
37 * The QSPI driver supports sending and receiving commands to/from from another
38 * device via a single, dual, quad, or octal SPI interface.
39 *
40 * \section subsection_qspi_features Features
41 * * Standard SPI Master interface
42 * * Supports Single/Dual/Quad/Octal SPI memories
43 * * Supports Dual-Quad SPI mode
44 * * Execute-In-Place (XIP) from external Quad SPI Flash
45 * * Supports external serial memory initialization via Serial Flash Discoverable Parameters (SFDP) standard
46 *
47 * \section subsection_qspi_code_snippets Code Snippets
48 * \note The following snippets show commands specific to the
49 * <a href="https://www.cypress.com/documentation/datasheets/s25fl512s-512-mbit-64-mbyte-30v-spi-flash-memory">S25FL512S Cypress NOR Flash device</a>.
50 * Refer to the datasheet of the external memory device for device specific memory commands.
51 * \subsection subsection_qspi_snippet_1 Code Snippet 1: Initializing the cyhal_qspi_command_t structure
52 * The following code snip demonstrates an example for initializing the cyhal_qspi_command_t structure for
53 * any given flash command. The cyhal_qspi_command_t.mode_bits structure has several other components which should
54 * be set as per the command. Mode bits are not required for single SPI read command, hence, mode_bits.disabled
55 * is set to TRUE in the below example code.
56 * \snippet hal_qspi.c snippet_cyhal_qspi_structure_initialisation
57 * \subsection subsection_qspi_snippet_2 Code Snippet 2: QSPI initialization and Reading Flash memory
58 * This example function demonstrates the initialization of the QSPI component and use of the cyhal_qspi_read() function
59 * to complete the read operation and receive the read data in a buffer.
60 * \snippet hal_qspi.c snippet_cyhal_qspi_read
61 * \subsection subsection_qspi_snippet_3 Code Snippet 3: Erasing Flash memory
62 * The following code snippet demonstrates the use of cyhal_qspi_transfer() API for sending single byte instruction
63 * that may or may not need any address or data bytes. It also shows the usage of status register read command within
64 * a while loop to poll the WIP bit status.
65 * \snippet hal_qspi.c snippet_cyhal_qspi_erase
66 * \note Flash memories need erase operation before programming.
67 * \subsection subsection_qspi_snippet_4 Code Snippet 4: Programming Flash memory
68 * This code snippet demonstrates the usage cyhal_qspi_write() API for executing program operation on flash memory.
69 * \snippet hal_qspi.c snippet_cyhal_qspi_program
70 * \subsection subsection_qspi_snippet_5 Code Snippet 5: Configuring multiple memories
71 * This code snippet demonstrates the usage cyhal_qspi_slave_configure() and cyhal_qspi_select_active_ssel() API for
72 * for initialization environment for additional (additional to one, that was initialized in scope of cyhal_qspi_init())
73 * QSPI memory and switching between memories.
74 * \snippet hal_qspi.c snippet_cyhal_qspi_multiple_memories
75 */
76 
77 #pragma once
78 
79 #include <stdint.h>
80 #include <stdbool.h>
81 #include "cy_result.h"
82 #include "cyhal_hw_types.h"
83 
84 #if defined(__cplusplus)
85 extern "C" {
86 #endif
87 
88 /** \addtogroup group_hal_results_qspi QSPI HAL Results
89  *  QSPI specific return codes
90  *  \ingroup group_hal_results
91  *  \{ *//**
92  */
93 
94 /** Bus width Error. */
95 #define CYHAL_QSPI_RSLT_ERR_BUS_WIDTH                   \
96     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_QSPI, 0))
97 /** Pin related Error. */
98 #define CYHAL_QSPI_RSLT_ERR_PIN                         \
99     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_QSPI, 1))
100 /** Data select Error. */
101 #define CYHAL_QSPI_RSLT_ERR_DATA_SEL                    \
102     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_QSPI, 2))
103 /** QSPI instance related error. */
104 #define CYHAL_QSPI_RSLT_ERR_INSTANCE                    \
105     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_QSPI, 3))
106 /** Clock frequency error. */
107 #define CYHAL_QSPI_RSLT_ERR_FREQUENCY                   \
108     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_QSPI, 4))
109 /** Waiting for certain event error. */
110 #define CYHAL_QSPI_RSLT_ERR_TIMEOUT                     \
111     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_QSPI, 5))
112 /** Cannot configure SSEL signal */
113 #define CYHAL_QSPI_RSLT_ERR_CANNOT_CONFIG_SSEL          \
114     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_QSPI, 6))
115 /** Cannot switch to specified SSEL signal */
116 #define CYHAL_QSPI_RSLT_ERR_CANNOT_SWITCH_SSEL          \
117     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_QSPI, 7))
118 /** Data rate error. */
119 #define CYHAL_QSPI_RSLT_ERR_DATARATE                    \
120     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_QSPI, 8))
121 /** Instruction error. */
122 #define CYHAL_QSPI_RSLT_ERR_INSTRUCTION                 \
123     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_QSPI, 9))
124 /** Dummy cycles error. */
125 #define CYHAL_QSPI_RSLT_ERR_DUMMY_CYCLES                \
126     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_QSPI, 10))
127 /** Cannot make changes in user provided clock configuration or provided clock is incorrect. */
128 #define CYHAL_QSPI_RSLT_ERR_CLOCK                       \
129     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_QSPI, 11))
130 /** Requested feature is not supported by this driver. */
131 #define CYHAL_QSPI_RSLT_ERR_UNSUPPORTED                 \
132     (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_QSPI, 12))
133 
134 /**
135  * \}
136  */
137 
138 /** QSPI Bus width. Some parts of commands provide variable bus width. */
139 
140 typedef enum cyhal_qspi_bus_width
141 {
142     CYHAL_QSPI_CFG_BUS_SINGLE       = 1,            /**< Normal SPI Mode */
143     CYHAL_QSPI_CFG_BUS_DUAL         = 2,            /**< Dual SPI Mode */
144     CYHAL_QSPI_CFG_BUS_QUAD         = 4,            /**< Quad SPI Mode */
145     CYHAL_QSPI_CFG_BUS_OCTAL        = 8,            /**< Octal SPI Mode */
146 } cyhal_qspi_bus_width_t;
147 
148 /** Address size in bits */
149 typedef enum cyhal_qspi_size
150 {
151     CYHAL_QSPI_CFG_SIZE_8           = 8,            /**< 8 bits address */
152     CYHAL_QSPI_CFG_SIZE_16          = 16,           /**< 16 bits address */
153     CYHAL_QSPI_CFG_SIZE_24          = 24,           /**< 24 bits address */
154     CYHAL_QSPI_CFG_SIZE_32          = 32,           /**< 32 bits address */
155 } cyhal_qspi_size_t;
156 
157 /** QSPI interrupt triggers */
158 typedef enum
159 {
160     CYHAL_QSPI_EVENT_NONE           = 0,            /**< No event */
161     CYHAL_QSPI_IRQ_TRANSMIT_DONE    = 1 << 0,       /**< Async transmit done */
162     CYHAL_QSPI_IRQ_RECEIVE_DONE     = 1 << 1,       /**< Async receive done */
163 } cyhal_qspi_event_t;
164 
165 /** QSPI data rate */
166 typedef enum
167 {
168     CYHAL_QSPI_DATARATE_SDR         = 0,            /**< Single data rate */
169     CYHAL_QSPI_DATARATE_DDR         = 1,            /**< Double data rate */
170 } cyhal_qspi_datarate_t;
171 
172 /** @brief QSPI command settings */
173 typedef struct cyhal_qspi_command
174 {
175     struct
176     {
177         cyhal_qspi_bus_width_t  bus_width;      /**< Bus width for the instruction */
178         cyhal_qspi_datarate_t   data_rate;      /**< Data rate SDR/DDR */
179         bool                    two_byte_cmd;   /**< Defines whether cmd is 2-byte value, or 1-byte (if false) */
180         uint16_t                value;          /**< Instruction value */
181         bool                    disabled;       /**< Instruction phase skipped if disabled is set to true */
182     } instruction;                              /**< Instruction structure */
183     struct
184     {
185         cyhal_qspi_bus_width_t  bus_width;      /**< Bus width for the address */
186         cyhal_qspi_datarate_t   data_rate;      /**< Data rate SDR/DDR */
187         cyhal_qspi_size_t       size;           /**< Address size */
188         /* Address is specified as argument for write/read functions */
189         bool                    disabled;       /**< Address phase skipped if disabled is set to true */
190     } address;                                  /**< Address structure */
191     struct
192     {
193         cyhal_qspi_bus_width_t  bus_width;      /**< Bus width for mode bits  */
194         cyhal_qspi_datarate_t   data_rate;      /**< Data rate SDR/DDR */
195         cyhal_qspi_size_t       size;           /**< Mode bits size */
196         uint32_t                value;          /**< Mode bits value */
197         bool                    disabled;       /**< Mode bits phase skipped if disabled is set to true */
198     } mode_bits;                                /**< Mode bits structure */
199     struct
200     {
201         cyhal_qspi_bus_width_t  bus_width;      /**< Bus width for mode bits  */
202         cyhal_qspi_datarate_t   data_rate;      /**< Data rate SDR/DDR */
203         uint32_t                dummy_count;    /**< Dummy cycles count */
204     } dummy_cycles;                             /**< Dummy cycles structure */
205     struct
206     {
207         cyhal_qspi_bus_width_t  bus_width;      /**< Bus width for data */
208         cyhal_qspi_datarate_t   data_rate;      /**< Data rate SDR/DDR */
209     } data;                                     /**< Data structure */
210 } cyhal_qspi_command_t;
211 
212 /** @brief QSPI slave pin set. Each pin set should represent the pins connected to a single slave memory device.
213  * Pin io[0] is data[0] signal of the memory (and not necessarily data[0] of underlying QSPI hardware block),
214  * io[1] is the memory IC's data[1] and so on. The ssel is the pin connected to the memory chip's select signal.
215  * The number of data pins configured should match the maximum \ref cyhal_qspi_bus_width_t for transfers. */
216 typedef struct cyhal_qspi_slave_pin_config
217 {
218     cyhal_gpio_t io[8];                         /**< IOx lines of connected memory */
219     cyhal_gpio_t ssel;                          /**< Slave Select line of connected memory */
220 } cyhal_qspi_slave_pin_config_t;
221 
222 /** Handler for QSPI callbacks */
223 typedef void (*cyhal_qspi_event_callback_t)(void *callback_arg, cyhal_qspi_event_t event);
224 
225 
226 /** Initialize QSPI peripheral.
227  *
228  * It should initialize QSPI pins (io0-io7, sclk and ssel), set frequency, clock polarity and phase mode.
229  *  The clock for the peripheral should be enabled
230  *
231  * @param[out] obj      Pointer to a QSPI object. The caller must allocate the memory
232  *  for this object but the init function will initialize its contents.
233  * @param[in]  sclk     The clock pin
234  * @param[in]  pin_set  Set of pins, that will primarily be used for communication with memory. Depends on device,
235  * QSPI HAL can service multiple memories which can be registered and controlled using \ref cyhal_qspi_slave_configure and
236  * \ref cyhal_qspi_select_active_ssel functions. There is no need to call \ref cyhal_qspi_select_active_ssel after
237  * this function - provided ssel pin as part of pin_set parameter become active.
238  * @param[in]  hz       The bus frequency
239  * @param[in]  mode     Clock polarity and phase mode (0 - 3)
240  * @param[in]  clk      The clock to use can be shared, if not provided a new clock will be allocated
241  * @note QSPI HAL cannot make changes into provided clock configuration. In this case \ref cyhal_qspi_set_frequency function
242  * cannot be used and will return error once called. With provided clock only user application can configure QSPI bus frequency by
243  * configuring parameters of shared clock.
244  * @return The status of the init request
245  */
246 cy_rslt_t cyhal_qspi_init(
247     cyhal_qspi_t *obj, cyhal_gpio_t sclk, const cyhal_qspi_slave_pin_config_t *pin_set, uint32_t hz, uint8_t mode,
248     cyhal_clock_t *clk);
249 
250 /** Initialize the QSPI peripheral using a configurator generated configuration struct. This function may not support all
251  * features, that can be configured via configurator. For limitations list please refer to \ref section_hal_impl_qspi_init_cfg section.
252  *
253  * @param[in]  obj                  The QSPI peripheral to configure
254  * @param[in]  cfg                  Configuration structure generated by a configurator.
255  * @return The status of the operation
256  */
257 cy_rslt_t cyhal_qspi_init_cfg(cyhal_qspi_t *obj, const cyhal_qspi_configurator_t *cfg);
258 
259 /** Deinitilize QSPI peripheral
260  *
261  * It should release pins that are associated with the QSPI object, and disable clocks for QSPI peripheral module
262  *  that was associated with the object
263  *
264  * @param[in,out] obj QSPI object
265  */
266 void cyhal_qspi_free(cyhal_qspi_t *obj);
267 
268 /** Set the QSPI baud rate
269  *
270  * Actual frequency may differ from the desired frequency due to available dividers and the bus clock. Function will
271  * apply achieved frequency only if it is in +0% /-10% deviation bounds from desired.
272  * Use @ref cyhal_qspi_get_frequency function to get actual frequency value that was achieved and set.
273  *
274  * @param[in] obj The QSPI object to configure
275  * @param[in] hz  The baud rate in Hz
276  * @return The status of the set_frequency request
277  */
278 cy_rslt_t cyhal_qspi_set_frequency(cyhal_qspi_t *obj, uint32_t hz);
279 
280 /** Get the actual frequency that QSPI is configured for
281  *
282  * @param[in] obj The QSPI object
283  * @return Frequency in Hz
284  */
285 uint32_t cyhal_qspi_get_frequency(cyhal_qspi_t *obj);
286 
287 /** Configure provided set of pins to service additional slave memory.
288  *
289  * Multiple pins can be configured as QSPI slave select pins as well as IO pins may be (or may not be) shared and used
290  * to service multiple connected slave memories. This function can be called multiple times - each call for each additional
291  * slave memory. Please refer to device datasheet for details.
292  * Switching between configured slave select pins is done by \ref cyhal_qspi_select_active_ssel function.
293  * Unless modified with this function, the SSEL pin provided as part of \ref cyhal_qspi_init is the default.
294  * Please refer to \ref subsection_qspi_snippet_5 for example of configuration multiple memory devices and switching between
295  * them.
296  * \note Provided IO pins can overlap with those, that are configured in scope of \ref cyhal_qspi_init function.
297  * @param[in] obj       The QSPI object to configure
298  * @param[in] pin_set   Set of pins, that will be used to service additional slave memory.
299  * @return The status of pin configuration
300  */
301 cy_rslt_t cyhal_qspi_slave_configure(cyhal_qspi_t *obj, const cyhal_qspi_slave_pin_config_t *pin_set);
302 
303 /** Selects an active slave select (SSEL) line from one of available and previously configured.
304  *
305  * Slave memories (in addition to one, that was configured in scope of \ref cyhal_qspi_init) can be added with help of
306  * \ref cyhal_qspi_slave_configure function.
307  * @param[in] obj   The QSPI object to configure
308  * @param[in] ssel  SSEL pin to be set as active
309  * @return CY_RSLT_SUCCESS if slave select was switched successfully, otherwise - CYHAL_QSPI_RSLT_ERR_CANNOT_SWITCH_SSEL
310  */
311 cy_rslt_t cyhal_qspi_select_active_ssel(cyhal_qspi_t *obj, cyhal_gpio_t ssel);
312 
313 /** Receive a command and block of data, synchronously.
314  *
315  * This will read either `length` bytes or the number of bytes that are currently available in the
316  * receive buffer, whichever is less, then return. The value pointed to by `length` will be updated
317  * to reflect the number of bytes that were actually read.
318  *
319  * @param[in]  obj      QSPI object
320  * @param[in]  command  QSPI command
321  * @param[in]  address  Address to access to
322  * @param[out] data     RX buffer
323  * @param[in]  length   RX buffer length in bytes
324  * @return The status of the read request
325  */
326 cy_rslt_t cyhal_qspi_read(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, uint32_t address, void *data, size_t *length);
327 
328 /** Receive a command and block of data in asynchronous mode.
329  *
330  * This will transfer `length` bytes into the buffer pointed to by `data` in the background. When the
331  * requested quantity of data has been read, the @ref CYHAL_QSPI_IRQ_RECEIVE_DONE event will be raised.
332  * See @ref cyhal_qspi_register_callback and @ref cyhal_qspi_enable_event.
333  *
334  * @param[in]  obj      QSPI object
335  * @param[in]  command  QSPI command
336  * @param[in]  address  Address to access to
337  * @param[out] data     RX buffer
338  * @param[in]  length   RX buffer length in bytes
339  * @return The status of the read request
340  */
341 cy_rslt_t cyhal_qspi_read_async(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, uint32_t address, void *data, size_t *length);
342 
343 /** Send a command and block of data, synchronously.
344  *
345  * This will write either `length` bytes or until the write buffer is full, whichever is less,
346  * then return. The value pointed to by `length` will be updated to reflect the number of bytes
347  * that were actually written.
348  *
349  * @param[in] obj      QSPI object
350  * @param[in] command  QSPI command
351  * @param[in] address  Address to access to
352  * @param[in] data     TX buffer
353  * @param[in] length   TX buffer length in bytes
354  * @return The status of the write request
355  */
356 cy_rslt_t cyhal_qspi_write(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, uint32_t address, const void *data, size_t *length);
357 
358 /** Send a command and block of data in asynchronous mode.
359  *
360  * This will transfer `length` bytes into the tx buffer in the background. When the requested
361  * quantity of data has been queued in the transmit buffer, the @ref CYHAL_QSPI_IRQ_TRANSMIT_DONE
362  * event will be raised. See @ref cyhal_qspi_register_callback and @ref cyhal_qspi_enable_event.
363  *
364  * @param[in] obj      QSPI object
365  * @param[in] command  QSPI command
366  * @param[in] address  Address to access to
367  * @param[in] data     TX buffer
368  * @param[in] length   TX buffer length in bytes
369  * @return The status of the write request
370  */
371 cy_rslt_t cyhal_qspi_write_async(cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, uint32_t address, const void *data, size_t *length);
372 
373 /** Send a command (and optionally data) and get the response. Can be used to send/receive device specific commands
374  *
375  * @param[in]  obj      QSPI object
376  * @param[in]  command  QSPI command
377  * @param[in]  address  Address to access to
378  * @param[in]  tx_data  TX buffer
379  * @param[in]  tx_size  TX buffer length in bytes
380  * @param[out] rx_data  RX buffer
381  * @param[in]  rx_size  RX buffer length in bytes
382  * @return The status of the transfer request
383  */
384 cy_rslt_t cyhal_qspi_transfer(
385     cyhal_qspi_t *obj, const cyhal_qspi_command_t *command, uint32_t address, const void *tx_data, size_t tx_size,
386     void *rx_data, size_t rx_size
387 );
388 
389 /** Register a QSPI event handler
390  *
391  * This function will be called when one of the events enabled by \ref cyhal_qspi_enable_event occurs.
392  *
393  * @param[in] obj          The QSPI object
394  * @param[in] callback     The callback handler which will be invoked when the interrupt fires
395  * @param[in] callback_arg Generic argument that will be provided to the handler when called
396  */
397 void cyhal_qspi_register_callback(cyhal_qspi_t *obj, cyhal_qspi_event_callback_t callback, void *callback_arg);
398 
399 /** Configure QSPI interrupt enablement.
400  *
401  * When an enabled event occurs, the function specified by \ref cyhal_qspi_register_callback will be called.
402  *
403  * @param[in] obj            The QSPI object
404  * @param[in] event          The QSPI event type
405  * @param[in] intr_priority  The priority for NVIC interrupt events
406  * @param[in] enable         True to turn on interrupts, False to turn off
407  */
408 void cyhal_qspi_enable_event(cyhal_qspi_t *obj, cyhal_qspi_event_t event, uint8_t intr_priority, bool enable);
409 
410 #if defined(__cplusplus)
411 }
412 #endif
413 
414 #ifdef CYHAL_QSPI_IMPL_HEADER
415 #include CYHAL_QSPI_IMPL_HEADER
416 #endif /* CYHAL_QSPI_IMPL_HEADER */
417 
418 /** \} group_hal_qspi */
419