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