Update serial-flash to 1.1.0.20805

pull/14787/head
Dustin Crossman 2021-05-25 14:51:14 -07:00
parent f489d579b0
commit 623e799d63
8 changed files with 1082 additions and 365 deletions

View File

@ -1,98 +0,0 @@
/***************************************************************************//**
* \file cy_serial_flash_prog.c
*
* \brief
* Provides variables necessary to inform programming tools how to program the
* attached serial flash memory. The variables used here must be placed at
* specific locations in order to be detected and used by programming tools
* to know that there is an attached memory and its characteristics. Uses the
* configuration provided as part of BSP.
*
********************************************************************************
* \copyright
* Copyright 2018-2020 Cypress Semiconductor Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
/**
* \addtogroup group_board_libs
* \{
* In addition to the APIs for reading and writting to memory at runtime, this library also
* provides support for informing programming tools about the external memory so it can be
* be written at the same time as internal flash. This support can be enabled by defining
* CY_ENABLE_XIP_PROGRAM while building the application. With this define in place, code
* will be generated in the .cy_sflash_user_data & .cy_toc_part2 sections. These locations
* can be read by programming tools (eg: Cypress Programmer, OpenOCD, pyOCD) to know that
* there is a memory device attached and how to program it.
* \} group_board_libs
*/
#include <stdint.h>
#if defined(__cplusplus)
extern "C" {
#endif
#if defined(CY_ENABLE_XIP_PROGRAM)
#include "cycfg_qspi_memslot.h"
typedef struct
{
const cy_stc_smif_block_config_t * smifCfg; /* Pointer to SMIF top-level configuration */
const uint32_t null_t; /* NULL termination */
} stc_smif_ipblocks_arr_t;
/*
* This data can be placed anywhere in the internal memory, but it must be at a location that
* can be determined and used for the calculation of the CRC16 checksum in the cyToc below. There
* are multiple ways this can be accomplished including:
* 1) Placing it in a dedicated memory block with a known address. (as done here)
* 2) Placing it at an absolute location via a the linker script
* 3) Using 'cymcuelftool -S' to recompute the checksum and patch the elf file after linking
*/
CY_SECTION(".cy_sflash_user_data") __attribute__( (used) )
const stc_smif_ipblocks_arr_t smifIpBlocksArr = {&smifBlockConfig, 0x00000000};
/*
* This data is used to populate the table of contents part 2. When present, it is used by the boot
* process and programming tools to determine key characteristics about the memory usage including
* where the boot process should start the application from and what external memories are connected
* (if any). This must consume a full row of flash memory row. The last entry is a checksum of the
* other values in the ToC which must be updated if any other value changes. This can be done manually
* or by running 'cymcuelftool -S' to recompute the checksum.
*/
CY_SECTION(".cy_toc_part2") __attribute__( (used) )
const uint32_t cyToc[128] =
{
0x200-4, /* Offset=0x0000: Object Size, bytes */
0x01211220, /* Offset=0x0004: Magic Number (TOC Part 2, ID) */
0, /* Offset=0x0008: Key Storage Address */
(int)&smifIpBlocksArr, /* Offset=0x000C: This points to a null terminated array of SMIF structures. */
0x10000000u, /* Offset=0x0010: App image start address */
/* Offset=0x0014-0x01F7: Reserved */
[126] = 0x000002C2, /* Offset=0x01F8: Bits[ 1: 0] CLOCK_CONFIG (0=8MHz, 1=25MHz, 2=50MHz, 3=100MHz)
Bits[ 4: 2] LISTEN_WINDOW (0=20ms, 1=10ms, 2=1ms, 3=0ms, 4=100ms)
Bits[ 6: 5] SWJ_PINS_CTL (0/1/3=Disable SWJ, 2=Enable SWJ)
Bits[ 8: 7] APP_AUTHENTICATION (0/2/3=Enable, 1=Disable)
Bits[10: 9] FB_BOOTLOADER_CTL: UNUSED */
[127] = 0x3BB30000 /* Offset=0x01FC: CRC16-CCITT (the upper 2 bytes contain the CRC and the lower 2 bytes are 0) */
};
#endif /* defined(CY_ENABLE_XIP_PROGRAM) */
#if defined(__cplusplus)
}
#endif

View File

@ -1,234 +0,0 @@
/***************************************************************************//**
* \file cy_serial_flash_qspi.c
*
* \brief
* Provides APIs for interacting with an external flash connected to the SPI or
* QSPI interface, uses SFDP to auto-discover memory properties if SFDP is
* enabled in the configuration.
*
********************************************************************************
* \copyright
* Copyright 2018-2020 Cypress Semiconductor Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
#include <stdbool.h>
#include "cy_serial_flash_qspi.h"
#include "cyhal_qspi.h"
#include "cy_utils.h"
#ifdef CY_IP_MXSMIF
#if defined(__cplusplus)
extern "C" {
#endif
/** \cond INTERNAL */
/** Timeout to apply while polling the memory for its ready status after quad
* enable command has been sent out. Quad enable is a non-volatile write.
*/
#define CY_SERIAL_FLASH_QUAD_ENABLE_TIMEOUT_US (5000lu) /* in microseconds */
/* Number of memories supported by the driver */
#define SMIF_MEM_DEVICES (1u)
/* SMIF slot from which the memory configuration is picked up - fixed to 0 as the driver
* supports only one device */
#define MEM_SLOT (0u)
/** \endcond */
static cyhal_qspi_t qspi_obj;
static cy_stc_smif_mem_config_t * qspi_mem_config[SMIF_MEM_DEVICES];
static cy_stc_smif_block_config_t qspi_block_config =
{
/* The number of SMIF memories defined. */
.memCount = SMIF_MEM_DEVICES,
/* The pointer to the array of memory config structures of size memCount. */
.memConfig = (cy_stc_smif_mem_config_t**)qspi_mem_config,
/* The version of the SMIF driver. */
.majorVersion = CY_SMIF_DRV_VERSION_MAJOR,
/* The version of the SMIF driver. */
.minorVersion = CY_SMIF_DRV_VERSION_MINOR
};
/* The driver supports only one memory. When multiple memory configurations
* are generated by the SMIF configurator tool, provide only the
* configuration for memory that need to be supported by the driver.
* Memory configuration can be changed by deinit followed by init with new
* configuration */
cy_rslt_t cy_serial_flash_qspi_init(
const cy_stc_smif_mem_config_t* mem_config,
cyhal_gpio_t io0,
cyhal_gpio_t io1,
cyhal_gpio_t io2,
cyhal_gpio_t io3,
cyhal_gpio_t io4,
cyhal_gpio_t io5,
cyhal_gpio_t io6,
cyhal_gpio_t io7,
cyhal_gpio_t sclk,
cyhal_gpio_t ssel,
uint32_t hz)
{
cy_en_smif_status_t smifStatus = CY_SMIF_SUCCESS;
cy_rslt_t result = cyhal_qspi_init(&qspi_obj, io0, io1, io2, io3, io4, io5, io6, io7,
sclk, ssel, hz, 0);
qspi_mem_config[MEM_SLOT] = (cy_stc_smif_mem_config_t*) mem_config;
if(CY_RSLT_SUCCESS == result)
{
/* Perform SFDP detection and XIP register configuration depending on the
* memory configuration.
*/
smifStatus = Cy_SMIF_MemInit(qspi_obj.base, &qspi_block_config, &qspi_obj.context);
if(CY_SMIF_SUCCESS == smifStatus)
{
/* Enable Quad mode (1-1-4 or 1-4-4 modes) to use all the four I/Os during
* communication.
*/
if(qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->readCmd->dataWidth == CY_SMIF_WIDTH_QUAD
|| qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->programCmd->dataWidth == CY_SMIF_WIDTH_QUAD)
{
bool isQuadEnabled = false;
smifStatus = Cy_SMIF_MemIsQuadEnabled(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT], &isQuadEnabled, &qspi_obj.context);
if(CY_SMIF_SUCCESS == smifStatus)
{
if(!isQuadEnabled)
{
smifStatus = Cy_SMIF_MemEnableQuadMode(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT], CY_SERIAL_FLASH_QUAD_ENABLE_TIMEOUT_US, &qspi_obj.context);
}
}
}
}
}
if((CY_RSLT_SUCCESS != result) || (CY_SMIF_SUCCESS != smifStatus))
{
cy_serial_flash_qspi_deinit();
if(CY_SMIF_SUCCESS != smifStatus)
{
result = (cy_rslt_t)smifStatus;
}
}
return result;
}
void cy_serial_flash_qspi_deinit(void)
{
if (qspi_obj.base != NULL)
{
Cy_SMIF_MemDeInit(qspi_obj.base);
}
cyhal_qspi_free(&qspi_obj);
}
size_t cy_serial_flash_qspi_get_size(void)
{
return (size_t)qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->memSize;
}
/* address is ignored for the memory with uniform sector size. Currently,
* QSPI Configurator does not support memories with hybrid sectors.
*/
size_t cy_serial_flash_qspi_get_erase_size(uint32_t addr)
{
CY_UNUSED_PARAMETER(addr);
return (size_t)qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->eraseSize;
}
size_t cy_serial_flash_qspi_get_prog_size(uint32_t addr)
{
CY_UNUSED_PARAMETER(addr);
return (size_t)qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->programSize;
}
cy_rslt_t cy_serial_flash_qspi_read(uint32_t addr, size_t length, uint8_t *buf)
{
/* Cy_SMIF_MemRead() returns error if (addr + length) > total flash size. */
return (cy_rslt_t)Cy_SMIF_MemRead(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT], addr, buf, length, &qspi_obj.context);
}
cy_rslt_t cy_serial_flash_qspi_write(uint32_t addr, size_t length, const uint8_t *buf)
{
/* Cy_SMIF_MemWrite() returns error if (addr + length) > total flash size. */
return (cy_rslt_t)Cy_SMIF_MemWrite(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT], addr, (uint8_t *)buf, length, &qspi_obj.context);
}
/* Does not support hybrid sectors, sector size must be uniform on the entire
* chip. Use cy_serial_flash_qspi_get_erase_size(addr) to implement hybrid sector
* support when QSPI Configurator and PDL supports memories with hybrid sectors.
*/
cy_rslt_t cy_serial_flash_qspi_erase(uint32_t addr, size_t length)
{
cy_en_smif_status_t smifStatus;
/* If the erase is for the entire chip, use chip erase command */
if((addr == 0u) && (length == cy_serial_flash_qspi_get_size()))
{
smifStatus = Cy_SMIF_MemEraseChip(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT], &qspi_obj.context);
}
else
{
/* Cy_SMIF_MemEraseSector() returns error if (addr + length) > total flash size
* or if addr is not aligned to erase sector size or if (addr + length)
* is not aligned to erase sector size.
*/
smifStatus = Cy_SMIF_MemEraseSector(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT], addr, length, &qspi_obj.context);
}
return (cy_rslt_t)smifStatus;
}
// This function enables or disables XIP on the MCU, does not send any command
// to the serial flash. XIP register configuration is already done as part of
// cy_serial_flash_qspi_init() if MMIO mode is enabled in the QSPI
// Configurator.
cy_rslt_t cy_serial_flash_qspi_enable_xip(bool enable)
{
if(enable)
{
Cy_SMIF_SetMode(qspi_obj.base, CY_SMIF_MEMORY);
}
else
{
Cy_SMIF_SetMode(qspi_obj.base, CY_SMIF_NORMAL);
}
return CY_RSLT_SUCCESS;
}
void cy_serial_flash_qspi_set_interrupt_priority(uint8_t priority)
{
NVIC_SetPriority(smif_interrupt_IRQn, priority);
}
#if defined(__cplusplus)
}
#endif
#endif /* CY_IP_MXSMIF */

View File

@ -0,0 +1,97 @@
/***********************************************************************************************//**
* \file cy_serial_flash_prog.c
*
* \brief
* Provides variables necessary to inform programming tools how to program the
* attached serial flash memory. The variables used here must be placed at
* specific locations in order to be detected and used by programming tools
* to know that there is an attached memory and its characteristics. Uses the
* configuration provided as part of BSP.
*
***************************************************************************************************
* \copyright
* Copyright 2018-2021 Cypress Semiconductor Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**************************************************************************************************/
/**
* \addtogroup group_board_libs
* \{
* In addition to the APIs for reading and writting to memory at runtime, this library also
* provides support for informing programming tools about the external memory so it can be
* be written at the same time as internal flash. This support can be enabled by defining
* CY_ENABLE_XIP_PROGRAM while building the application. With this define in place, code
* will be generated in the .cy_sflash_user_data & .cy_toc_part2 sections. These locations
* can be read by programming tools (eg: Cypress Programmer, OpenOCD, pyOCD) to know that
* there is a memory device attached and how to program it.
* \} group_board_libs
*/
#include <stdint.h>
#if defined(__cplusplus)
extern "C" {
#endif
#if defined(CY_ENABLE_XIP_PROGRAM)
#include "cycfg_qspi_memslot.h"
typedef struct
{
const cy_stc_smif_block_config_t* smifCfg; // Pointer to SMIF top-level configuration
const uint32_t null_t; // NULL termination
} stc_smif_ipblocks_arr_t;
// This data can be placed anywhere in the internal memory, but it must be at a location that
// can be determined and used for the calculation of the CRC16 checksum in the cyToc below. There
// are multiple ways this can be accomplished including:
// 1) Placing it in a dedicated memory block with a known address. (as done here)
// 2) Placing it at an absolute location via a the linker script
// 3) Using 'cymcuelftool -S' to recompute the checksum and patch the elf file after linking
CY_SECTION(".cy_sflash_user_data") __attribute__((used))
const stc_smif_ipblocks_arr_t smifIpBlocksArr = { &smifBlockConfig, 0x00000000 };
// This data is used to populate the table of contents part 2. When present, it is used by the boot
// process and programming tools to determine key characteristics about the memory usage including
// where the boot process should start the application from and what external memories are connected
// (if any). This must consume a full row of flash memory row. The last entry is a checksum of the
// other values in the ToC which must be updated if any other value changes. This can be done
// manually or by running 'cymcuelftool -S' to recompute the checksum.
CY_SECTION(".cy_toc_part2") __attribute__((used))
const uint32_t cyToc[128] =
{
0x200-4, // Offset=0x0000: Object Size, bytes
0x01211220, // Offset=0x0004: Magic Number (TOC Part 2, ID)
0, // Offset=0x0008: Key Storage Address
(int)&smifIpBlocksArr, // Offset=0x000C: This points to a null terminated array of SMIF
// structures.
0x10000000u, // Offset=0x0010: App image start address
// Offset=0x0014-0x01F7: Reserved
[126] = 0x000002C2, // Offset=0x01
// Bits[ 1: 0] CLOCK_CONFIG (0=8MHz, 1=25MHz, 2=50MHz, 3=100MHz)
// Bits[ 4: 2] LISTEN_WINDOW (0=20ms, 1=10ms, 2=1ms, 3=0ms, 4=100ms)
// Bits[ 6: 5] SWJ_PINS_CTL (0/1/3=Disable SWJ, 2=Enable SWJ)
// Bits[ 8: 7] APP_AUTHENTICATION (0/2/3=Enable, 1=Disable)
// Bits[10: 9] FB_BOOTLOADER_CTL: UNUSED
[127] = 0x3BB30000 // Offset=0x01FC: CRC16-CCITT
// (the upper 2 bytes contain the CRC and the lower 2 bytes are 0)
};
#endif // defined(CY_ENABLE_XIP_PROGRAM)
#if defined(__cplusplus)
}
#endif

View File

@ -0,0 +1,868 @@
/***********************************************************************************************//**
* \file cy_serial_flash_qspi.c
*
* \brief
* Provides APIs for interacting with an external flash connected to the SPI or
* QSPI interface, uses SFDP to auto-discover memory properties if SFDP is
* enabled in the configuration.
*
***************************************************************************************************
* \copyright
* Copyright 2018-2021 Cypress Semiconductor Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**************************************************************************************************/
#include <stdbool.h>
#include "cy_serial_flash_qspi.h"
#include "cyhal_qspi.h"
#include "cy_trigmux.h"
#include "cy_dma.h"
#include "cy_utils.h"
#if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE)
#include <stdlib.h>
#include "cyabs_rtos.h"
#endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */
#ifdef CY_IP_MXSMIF
#if defined(__cplusplus)
extern "C" {
#endif
/** \cond INTERNAL */
/** Timeout to apply while polling the memory for its ready status after quad
* enable command has been sent out. Quad enable is a non-volatile write.
*/
#define CY_SERIAL_FLASH_QUAD_ENABLE_TIMEOUT_US (5000lu) // in microseconds
/** Number of loops to run while polling the SMIF for its busy status. */
#define SMIF_BUSY_CHECK_LOOP_COUNT (10lu)
/** Timeout to apply per loop while polling the SMIF for its busy status. */
#define SMIF_BUSY_CHECK_TIMEOUT_MS (1lu) // in milliseconds
// Number of memories supported by the driver
#define SMIF_MEM_DEVICES (1u)
// SMIF slot from which the memory configuration is picked up - fixed to 0 as
// the driver supports only one device
#define MEM_SLOT (0u)
/* Maximum number of bytes that can be read by SMIF in one transfer */
#define SMIF_MAX_RX_COUNT (65536lu)
#define DMA_YCOUNT_ONE_LOOP (1lu)
#define MSB_SHIFT_EIGHT (0x08u)
#define LSB_MASK (0xFFlu)
/* Masks used for checking the flag bits */
#define FLAG_QSPI_HAL_INIT_DONE (0x01lu << 0)
#define FLAG_DMA_INIT_DONE (0x01lu << 1)
#define FLAG_READ_IN_PROGRESS (0x01lu << 2)
#define IS_FLAG_SET(mask) (status_flags & (mask))
#define SET_FLAG(mask) (status_flags |= (mask))
#define CLEAR_FLAG(mask) (status_flags &= ~(mask))
#if defined(CY_DEVICE_PSOC6ABLE2)
/* You cannot simply change these values. The trigger mux connect code in
* _init_dma() needs to be updated correspondingly.
*/
#define RX_DMA_INSTANCE DW1
#define RX_DMA_CHANNEL_NUM (15lu)
#define RX_DMA_CH0_IRQn (cpuss_interrupts_dw1_0_IRQn)
#elif defined(CY_DEVICE_PSOC6A2M) || defined(CY_DEVICE_PSOC6A512K) || defined(CY_DEVICE_PSOC6256K)
/* In these devices, only 1to1 triggers are available between SMIF and a
* specific combination of DW instances and channel numbers.
* i.e. TX trigger request from SMIF can connect only to DW1 CH22 and
* RX trigger request from SMIF can connect only to DW1 CH23.
*/
#define RX_DMA_INSTANCE DW1
#define RX_DMA_CHANNEL_NUM (23lu)
#define RX_DMA_CH0_IRQn (cpuss_interrupts_dw1_0_IRQn)
#define DEVICE_GROUP_1TO1_TRIGGER
#else // if defined(CY_DEVICE_PSOC6ABLE2)
#define DMA_UNSUPPORTED
#endif // if defined(CY_DEVICE_PSOC6ABLE2)
#define DMA_CHANNEL_PRIORITY (3lu)
#define DMA_INTR_PRIORITY (7lu)
/** \endcond */
static cyhal_qspi_t qspi_obj;
static volatile uint32_t status_flags;
static cy_stc_smif_mem_config_t* qspi_mem_config[SMIF_MEM_DEVICES];
static cy_stc_smif_block_config_t qspi_block_config =
{
// The number of SMIF memories defined.
.memCount = SMIF_MEM_DEVICES,
// The pointer to the array of memory config structures of size memCount.
.memConfig = (cy_stc_smif_mem_config_t**)qspi_mem_config,
// The version of the SMIF driver.
.majorVersion = CY_SMIF_DRV_VERSION_MAJOR,
// The version of the SMIF driver.
.minorVersion = CY_SMIF_DRV_VERSION_MINOR
};
#if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE)
static cy_mutex_t serial_flash_mutex;
#endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */
#ifndef DMA_UNSUPPORTED
typedef struct
{
uint32_t addr;
size_t length;
uint8_t* buf;
cy_serial_flash_qspi_read_complete_callback_t callback;
void* callback_arg;
} read_txfr_info_t;
static read_txfr_info_t read_txfr_info;
/* DMA related variables */
static cy_stc_dma_descriptor_t dma_descr;
/* Default DW descriptor config */
static cy_stc_dma_descriptor_config_t dma_descr_config =
{
.retrigger = CY_DMA_RETRIG_4CYC,
.interruptType = CY_DMA_DESCR,
.triggerOutType = CY_DMA_DESCR_CHAIN,
.channelState = CY_DMA_CHANNEL_ENABLED,
.triggerInType = CY_DMA_DESCR,
.dataSize = CY_DMA_BYTE,
.srcTransferSize = CY_DMA_TRANSFER_SIZE_WORD,
.dstTransferSize = CY_DMA_TRANSFER_SIZE_DATA,
.descriptorType = CY_DMA_2D_TRANSFER,
.srcAddress = 0,
.dstAddress = 0,
.srcXincrement = 0U,
.dstXincrement = 1U,
.xCount = 1UL,
.srcYincrement = 0U,
.dstYincrement = CY_DMA_LOOP_COUNT_MAX,
.yCount = 1UL,
.nextDescriptor = &dma_descr,
};
/* Default DW channel config */
static cy_stc_dma_channel_config_t dma_channel_config =
{
.descriptor = &dma_descr,
.preemptable = false,
.priority = DMA_CHANNEL_PRIORITY,
.enable = false,
.bufferable = false,
};
static const cyhal_resource_inst_t DW_obj =
{
.type = CYHAL_RSC_DW,
.block_num = ((uint32_t)RX_DMA_INSTANCE - DW0_BASE)/sizeof(DW_Type),
.channel_num = RX_DMA_CHANNEL_NUM
};
static cy_rslt_t _init_dma(void);
static cy_rslt_t _deinit_dma(void);
static void _rx_dma_irq_handler(void);
static cy_en_smif_status_t _read_next_chunk(void);
static void _value_to_byte_array(uint32_t value, uint8_t* byte_array, uint32_t start_pos,
uint32_t size);
#endif /* #ifndef DMA_UNSUPPORTED */
static inline cy_rslt_t _mutex_acquire(void);
static inline cy_rslt_t _mutex_release(void);
//--------------------------------------------------------------------------------------------------
// cy_serial_flash_qspi_init
//
// The driver supports only one memory. When multiple memory configurations are generated by the
// SMIF configurator tool, provide only the configuration for memory that need to be supported by
// the driver. Memory configuration can be changed by deinit followed by init with new
// configuration
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_serial_flash_qspi_init(
const cy_stc_smif_mem_config_t* mem_config,
cyhal_gpio_t io0,
cyhal_gpio_t io1,
cyhal_gpio_t io2,
cyhal_gpio_t io3,
cyhal_gpio_t io4,
cyhal_gpio_t io5,
cyhal_gpio_t io6,
cyhal_gpio_t io7,
cyhal_gpio_t sclk,
cyhal_gpio_t ssel,
uint32_t hz)
{
cy_en_smif_status_t smif_status = CY_SMIF_SUCCESS;
cy_rslt_t result = cyhal_qspi_init(&qspi_obj, io0, io1, io2, io3, io4, io5, io6, io7,
sclk, ssel, hz, 0);
qspi_mem_config[MEM_SLOT] = (cy_stc_smif_mem_config_t*)mem_config;
if (CY_RSLT_SUCCESS == result)
{
SET_FLAG(FLAG_QSPI_HAL_INIT_DONE);
// Perform SFDP detection and XIP register configuration depending on the memory
// configuration.
smif_status = Cy_SMIF_MemInit(qspi_obj.base, &qspi_block_config, &qspi_obj.context);
if (CY_SMIF_SUCCESS == smif_status)
{
// Enable Quad mode (1-1-4 or 1-4-4 modes) to use all the four I/Os during
// communication.
if ((qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->readCmd->dataWidth ==
CY_SMIF_WIDTH_QUAD) ||
(qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->programCmd->dataWidth ==
CY_SMIF_WIDTH_QUAD))
{
bool isQuadEnabled = false;
smif_status =
Cy_SMIF_MemIsQuadEnabled(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT],
&isQuadEnabled, &qspi_obj.context);
if ((CY_SMIF_SUCCESS == smif_status) && !isQuadEnabled)
{
smif_status =
Cy_SMIF_MemEnableQuadMode(qspi_obj.base,
qspi_block_config.memConfig[MEM_SLOT],
CY_SERIAL_FLASH_QUAD_ENABLE_TIMEOUT_US,
&qspi_obj.context);
}
if (CY_SMIF_SUCCESS == smif_status)
{
#ifndef DMA_UNSUPPORTED
result = _init_dma();
if (CY_RSLT_SUCCESS == result)
{
SET_FLAG(FLAG_DMA_INIT_DONE);
#endif /* #ifndef DMA_UNSUPPORTED */
#if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE)
/* Initialize the mutex */
result = cy_rtos_init_mutex(&serial_flash_mutex);
#endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */
#ifndef DMA_UNSUPPORTED
}
#endif /* #ifndef DMA_UNSUPPORTED */
}
}
}
}
if ((CY_RSLT_SUCCESS != result) || (CY_SMIF_SUCCESS != smif_status))
{
cy_serial_flash_qspi_deinit();
if (CY_SMIF_SUCCESS != smif_status)
{
result = (cy_rslt_t)smif_status;
}
}
return result;
}
//--------------------------------------------------------------------------------------------------
// cy_serial_flash_qspi_deinit
//--------------------------------------------------------------------------------------------------
void cy_serial_flash_qspi_deinit(void)
{
cy_rslt_t result;
if (IS_FLAG_SET(FLAG_QSPI_HAL_INIT_DONE))
{
if (qspi_obj.base != NULL)
{
/* There is no harm in calling this even if Cy_SMIF_MemInit() did
* not succeed since anyway we own the QSPI object.
*/
Cy_SMIF_MemDeInit(qspi_obj.base);
}
cyhal_qspi_free(&qspi_obj);
CLEAR_FLAG(FLAG_QSPI_HAL_INIT_DONE);
#ifndef DMA_UNSUPPORTED
if (IS_FLAG_SET(FLAG_DMA_INIT_DONE))
{
result = _deinit_dma();
CY_ASSERT(CY_RSLT_SUCCESS == result);
CLEAR_FLAG(FLAG_DMA_INIT_DONE);
#endif /* #ifndef DMA_UNSUPPORTED */
#if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE)
result = cy_rtos_deinit_mutex(&serial_flash_mutex);
CY_ASSERT(CY_RSLT_SUCCESS == result);
#endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */
#ifndef DMA_UNSUPPORTED
}
#endif /* #ifndef DMA_UNSUPPORTED */
}
CY_UNUSED_PARAMETER(result); /* To avoid compiler warning in Release mode. */
}
//--------------------------------------------------------------------------------------------------
// cy_serial_flash_qspi_get_size
//--------------------------------------------------------------------------------------------------
size_t cy_serial_flash_qspi_get_size(void)
{
return (size_t)qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->memSize;
}
//--------------------------------------------------------------------------------------------------
// cy_serial_flash_qspi_get_erase_size
//--------------------------------------------------------------------------------------------------
size_t cy_serial_flash_qspi_get_erase_size(uint32_t addr)
{
size_t erase_sector_size;
cy_stc_smif_hybrid_region_info_t* hybrid_info = NULL;
cy_en_smif_status_t smif_status =
Cy_SMIF_MemLocateHybridRegion(qspi_block_config.memConfig[MEM_SLOT], &hybrid_info, addr);
if (CY_SMIF_SUCCESS != smif_status)
{
erase_sector_size = (size_t)qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->eraseSize;
}
else
{
erase_sector_size = (size_t)hybrid_info->eraseSize;
}
return erase_sector_size;
}
//--------------------------------------------------------------------------------------------------
// cy_serial_flash_qspi_get_prog_size
//--------------------------------------------------------------------------------------------------
size_t cy_serial_flash_qspi_get_prog_size(uint32_t addr)
{
CY_UNUSED_PARAMETER(addr);
return (size_t)qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->programSize;
}
//--------------------------------------------------------------------------------------------------
// cy_serial_flash_qspi_read
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_serial_flash_qspi_read(uint32_t addr, size_t length, uint8_t* buf)
{
cy_rslt_t result_mutex_rel = CY_RSLT_SUCCESS;
cy_rslt_t result = _mutex_acquire();
if (CY_RSLT_SUCCESS == result)
{
// Cy_SMIF_MemRead() returns error if (addr + length) > total flash size.
result = (cy_rslt_t)Cy_SMIF_MemRead(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT],
addr,
buf, length, &qspi_obj.context);
result_mutex_rel = _mutex_release();
}
/* Give priority to the status of SMIF operation when both SMIF operation
* and mutex release fail.
*/
return ((CY_RSLT_SUCCESS == result) ? result_mutex_rel : result);
}
//--------------------------------------------------------------------------------------------------
// cy_serial_flash_qspi_abort_read
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_serial_flash_qspi_abort_read(void)
{
#ifndef DMA_UNSUPPORTED
cy_rslt_t result;
/* Wait until SMIF finishes any pending transfer. */
for (uint32_t loop = 0; loop < SMIF_BUSY_CHECK_LOOP_COUNT; loop++)
{
if (!Cy_SMIF_BusyCheck(qspi_obj.base))
{
break;
}
cyhal_system_delay_ms(SMIF_BUSY_CHECK_TIMEOUT_MS);
}
if (Cy_SMIF_BusyCheck(qspi_obj.base))
{
SET_FLAG(FLAG_READ_IN_PROGRESS);
result = CY_RSLT_SERIAL_FLASH_ERR_QSPI_BUSY;
}
else
{
Cy_DMA_Channel_Disable(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM);
result = CY_RSLT_SUCCESS;
CLEAR_FLAG(FLAG_READ_IN_PROGRESS);
}
return result;
#else // ifndef DMA_UNSUPPORTED
return CY_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED;
#endif /* #ifndef DMA_UNSUPPORTED */
}
//--------------------------------------------------------------------------------------------------
// cy_serial_flash_qspi_read_async
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_serial_flash_qspi_read_async(uint32_t addr, size_t length, uint8_t* buf,
cy_serial_flash_qspi_read_complete_callback_t callback,
void* callback_arg)
{
#ifndef DMA_UNSUPPORTED
cy_rslt_t result = CY_RSLT_SERIAL_FLASH_ERR_BAD_PARAM;
cy_rslt_t result_mutex_rel = CY_RSLT_SUCCESS;
CY_ASSERT(NULL != buf);
if (IS_FLAG_SET(FLAG_READ_IN_PROGRESS))
{
result = CY_RSLT_SERIAL_FLASH_ERR_READ_BUSY; /* Previous read request is not yet complete.
*/
}
else if ((addr + length) <= cy_serial_flash_qspi_get_size())
{
result = _mutex_acquire();
if (CY_RSLT_SUCCESS == result)
{
read_txfr_info.addr = addr;
read_txfr_info.length = length;
read_txfr_info.buf = buf;
read_txfr_info.callback = callback;
read_txfr_info.callback_arg = callback_arg;
/* Enable the DMA channel */
Cy_DMA_Channel_Enable(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM);
SET_FLAG(FLAG_READ_IN_PROGRESS);
result = (cy_rslt_t)_read_next_chunk(); /* Start the read transfer */
if (CY_RSLT_SUCCESS != result)
{
CLEAR_FLAG(FLAG_READ_IN_PROGRESS);
}
result_mutex_rel = _mutex_release();
}
}
/* Give priority to the status of SMIF operation when both SMIF operation
* and mutex release fail.
*/
return ((CY_RSLT_SUCCESS == result) ? result_mutex_rel : result);
#else // ifndef DMA_UNSUPPORTED
CY_UNUSED_PARAMETER(addr);
CY_UNUSED_PARAMETER(length);
CY_UNUSED_PARAMETER(buf);
CY_UNUSED_PARAMETER(callback);
CY_UNUSED_PARAMETER(callback_arg);
return CY_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED;
#endif /* #ifndef DMA_UNSUPPORTED */
}
//--------------------------------------------------------------------------------------------------
// cy_serial_flash_qspi_write
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_serial_flash_qspi_write(uint32_t addr, size_t length, const uint8_t* buf)
{
cy_rslt_t result_mutex_rel = CY_RSLT_SUCCESS;
cy_rslt_t result = _mutex_acquire();
if (CY_RSLT_SUCCESS == result)
{
// Cy_SMIF_MemWrite() returns error if (addr + length) > total flash size.
result = (cy_rslt_t)Cy_SMIF_MemWrite(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT],
addr,
(uint8_t*)buf, length, &qspi_obj.context);
result_mutex_rel = _mutex_release();
}
/* Give priority to the status of SMIF operation when both SMIF operation
* and mutex release fail.
*/
return ((CY_RSLT_SUCCESS == result) ? result_mutex_rel : result);
}
//--------------------------------------------------------------------------------------------------
// cy_serial_flash_qspi_erase
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_serial_flash_qspi_erase(uint32_t addr, size_t length)
{
cy_rslt_t result_mutex_rel = CY_RSLT_SUCCESS;
cy_rslt_t result = _mutex_acquire();
if (CY_RSLT_SUCCESS == result)
{
// If the erase is for the entire chip, use chip erase command
if ((addr == 0u) && (length == cy_serial_flash_qspi_get_size()))
{
result =
(cy_rslt_t)Cy_SMIF_MemEraseChip(qspi_obj.base,
qspi_block_config.memConfig[MEM_SLOT],
&qspi_obj.context);
}
else
{
// Cy_SMIF_MemEraseSector() returns error if (addr + length) > total flash size or if
// addr is not aligned to erase sector size or if (addr + length) is not aligned to
// erase sector size.
result =
(cy_rslt_t)Cy_SMIF_MemEraseSector(qspi_obj.base,
qspi_block_config.memConfig[MEM_SLOT],
addr, length, &qspi_obj.context);
}
result_mutex_rel = _mutex_release();
}
/* Give priority to the status of SMIF operation when both SMIF operation
* and mutex release fail.
*/
return ((CY_RSLT_SUCCESS == result) ? result_mutex_rel : result);
}
//--------------------------------------------------------------------------------------------------
// cy_serial_flash_qspi_enable_xip
//
// This function enables or disables XIP on the MCU, does not send any command
// to the serial flash. XIP register configuration is already done as part of
// cy_serial_flash_qspi_init() if MMIO mode is enabled in the QSPI
// Configurator.
//--------------------------------------------------------------------------------------------------
cy_rslt_t cy_serial_flash_qspi_enable_xip(bool enable)
{
if (enable)
{
Cy_SMIF_SetMode(qspi_obj.base, CY_SMIF_MEMORY);
}
else
{
Cy_SMIF_SetMode(qspi_obj.base, CY_SMIF_NORMAL);
}
return CY_RSLT_SUCCESS;
}
//--------------------------------------------------------------------------------------------------
// cy_serial_flash_qspi_set_interrupt_priority
//--------------------------------------------------------------------------------------------------
void cy_serial_flash_qspi_set_interrupt_priority(uint8_t priority)
{
NVIC_SetPriority(smif_interrupt_IRQn, priority);
}
//--------------------------------------------------------------------------------------------------
// cy_serial_flash_qspi_set_interrupt_priority
//--------------------------------------------------------------------------------------------------
void cy_serial_flash_qspi_set_dma_interrupt_priority(uint8_t priority)
{
#ifndef DMA_UNSUPPORTED
NVIC_SetPriority((IRQn_Type)(RX_DMA_CH0_IRQn + RX_DMA_CHANNEL_NUM), priority);
#else
CY_UNUSED_PARAMETER(priority);
#endif /* #ifndef DMA_UNSUPPORTED */
}
#ifndef DMA_UNSUPPORTED
//--------------------------------------------------------------------------------------------------
// _read_next_chunk
//--------------------------------------------------------------------------------------------------
static cy_en_smif_status_t _read_next_chunk(void)
{
cy_en_smif_status_t smif_status = CY_SMIF_SUCCESS;
uint32_t chunk;
uint8_t addr_array[CY_SMIF_FOUR_BYTES_ADDR] = { 0U };
if (read_txfr_info.length > 0UL)
{
/* SMIF can read only up to 65536 bytes in one go. Split the larger read into multiple
chunks */
chunk =
(read_txfr_info.length >
SMIF_MAX_RX_COUNT) ? (SMIF_MAX_RX_COUNT) : read_txfr_info.length;
/* In 2D transfer, (X_count x Y_count) should be a multiple of CY_DMA_LOOP_COUNT_MAX (256).
*/
if (chunk > CY_DMA_LOOP_COUNT_MAX)
{
/* Make chunk divisible by CY_DMA_LOOP_COUNT_MAX (256) by masking out the LS bits */
chunk &= ~(CY_DMA_LOOP_COUNT_MAX - 1);
dma_descr_config.yCount = chunk/CY_DMA_LOOP_COUNT_MAX;
dma_descr_config.xCount = CY_DMA_LOOP_COUNT_MAX;
}
else
{
dma_descr_config.yCount = DMA_YCOUNT_ONE_LOOP;
dma_descr_config.xCount = chunk;
}
dma_descr_config.dstAddress = (void*)read_txfr_info.buf;
Cy_DMA_Descriptor_Init(&dma_descr, &dma_descr_config);
/* Pass NULL for buffer (and callback) so that the function does not
* set up FIFO interrupt. We don't need FIFO interrupt to be setup
* since we will be using DMA.
*/
_value_to_byte_array(read_txfr_info.addr, &addr_array[0], 0UL,
qspi_block_config.memConfig[MEM_SLOT]->deviceCfg->numOfAddrBytes);
smif_status = Cy_SMIF_MemCmdRead(qspi_obj.base, qspi_block_config.memConfig[MEM_SLOT],
addr_array, NULL, chunk, NULL, &qspi_obj.context);
if (CY_SMIF_SUCCESS == smif_status)
{
/* Recalculate the next rxBuffer offset */
read_txfr_info.length -= chunk;
read_txfr_info.addr += chunk;
read_txfr_info.buf += chunk;
}
}
return smif_status;
}
//--------------------------------------------------------------------------------------------------
// _init_dma
//--------------------------------------------------------------------------------------------------
static cy_rslt_t _init_dma(void)
{
cy_rslt_t result;
/* Set the source address of the descriptor */
dma_descr_config.srcAddress = (void*)&SMIF_RX_DATA_FIFO_RD1(qspi_obj.base);
/* Configure the RX DMA */
result =
(cy_rslt_t)Cy_DMA_Channel_Init(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM, &dma_channel_config);
if (CY_RSLT_SUCCESS == result)
{
Cy_DMA_Channel_SetInterruptMask(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM, CY_DMA_INTR_MASK);
Cy_DMA_Enable(RX_DMA_INSTANCE);
/* Configure interrupt for RX DMA */
cy_stc_sysint_t dma_intr_config =
{ .intrSrc = (IRQn_Type)(RX_DMA_CH0_IRQn + RX_DMA_CHANNEL_NUM),
.intrPriority = DMA_INTR_PRIORITY };
result = (cy_rslt_t)Cy_SysInt_Init(&dma_intr_config, _rx_dma_irq_handler);
if (CY_RSLT_SUCCESS == result)
{
NVIC_EnableIRQ(dma_intr_config.intrSrc);
/* Configure the trigger mux */
#if defined(DEVICE_GROUP_1TO1_TRIGGER)
result = (cy_rslt_t)Cy_TrigMux_Select(TRIG_OUT_1TO1_3_SMIF_RX_TO_PDMA1_TR_IN23, false,
TRIGGER_TYPE_LEVEL);
#else
result = (cy_rslt_t)Cy_TrigMux_Connect(TRIG13_IN_SMIF_TR_RX_REQ,
TRIG13_OUT_TR_GROUP0_INPUT42, false,
TRIGGER_TYPE_LEVEL);
if (CY_RSLT_SUCCESS == result)
{
result = (cy_rslt_t)Cy_TrigMux_Connect(TRIG1_IN_TR_GROUP13_OUTPUT15,
TRIG1_OUT_CPUSS_DW1_TR_IN15, false,
TRIGGER_TYPE_LEVEL);
}
#endif /* #if defined(DEVICE_GROUP_1TO1_TRIGGER) */
}
}
if (CY_RSLT_SUCCESS == result)
{
/* Reserve the DW instance so that HAL will not be able to use it later. */
result = cyhal_hwmgr_reserve(&DW_obj);
}
return result;
}
//--------------------------------------------------------------------------------------------------
// _deinit_dma
//--------------------------------------------------------------------------------------------------
static cy_rslt_t _deinit_dma(void)
{
cy_rslt_t result = CY_RSLT_SUCCESS;
NVIC_DisableIRQ((IRQn_Type)(RX_DMA_CH0_IRQn + RX_DMA_CHANNEL_NUM));
/* Disable only the channel, not the DW instance as it may be used by other
* part of the application.
*/
Cy_DMA_Channel_Disable(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM);
/* Free the DMA resource so that HAL can use it now */
cyhal_hwmgr_free(&DW_obj);
#if defined(DEVICE_GROUP_1TO1_TRIGGER)
result = (cy_rslt_t)Cy_TrigMux_Deselect(TRIG_OUT_1TO1_3_SMIF_RX_TO_PDMA1_TR_IN23);
#else
/* No PDL function is available for handling deinit for non-1to1 trigger muxes. */
#endif /* #if defined(DEVICE_GROUP_1TO1_TRIGGER) */
return result;
}
//--------------------------------------------------------------------------------------------------
// _rx_dma_irq_handler
//--------------------------------------------------------------------------------------------------
static void _rx_dma_irq_handler(void)
{
cy_en_smif_status_t smif_status = CY_SMIF_SUCCESS;
bool terminate_read_txfr = true;
cy_en_dma_intr_cause_t cause = Cy_DMA_Channel_GetStatus(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM);
Cy_DMA_Channel_ClearInterrupt(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM);
if (CY_DMA_INTR_CAUSE_COMPLETION == cause)
{
if (read_txfr_info.length > 0UL)
{
smif_status = _read_next_chunk();
if (CY_SMIF_SUCCESS == smif_status)
{
terminate_read_txfr = false;
}
}
}
else
{
smif_status = (cy_en_smif_status_t)CY_RSLT_SERIAL_FLASH_ERR_DMA;
}
if (terminate_read_txfr)
{
Cy_DMA_Channel_Disable(RX_DMA_INSTANCE, RX_DMA_CHANNEL_NUM);
CLEAR_FLAG(FLAG_READ_IN_PROGRESS);
/* Execute the callback */
if (NULL != read_txfr_info.callback)
{
read_txfr_info.callback((cy_rslt_t)smif_status, read_txfr_info.callback_arg);
}
}
}
/*******************************************************************************
* Function Name: _value_to_byte_array
****************************************************************************//**
*
* Unpacks the specified number of bytes from a 32-bit value into the given byte
* array.
*
* \param value
* The 32-bit (4-byte) value to unpack.
*
* \param byte_array
* The byte array to fill.
*
* \param start_pos
* The start position of the byte array to begin filling from.
*
* \param size
* The number of bytes to unpack.
*
*******************************************************************************/
static void _value_to_byte_array(uint32_t value, uint8_t* byte_array, uint32_t start_pos,
uint32_t size)
{
CY_ASSERT((0lu < size) && (CY_SMIF_FOUR_BYTES_ADDR >= size));
CY_ASSERT(NULL != byte_array);
do
{
size--;
byte_array[size + start_pos] = (uint8_t)(value & LSB_MASK);
value >>= MSB_SHIFT_EIGHT; /* Shift to get the next byte */
} while (size > 0U);
}
#endif /* #ifndef DMA_UNSUPPORTED */
//--------------------------------------------------------------------------------------------------
// _mutex_acquire
//--------------------------------------------------------------------------------------------------
static inline cy_rslt_t _mutex_acquire(void)
{
#if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE)
return cy_rtos_get_mutex(&serial_flash_mutex, CY_RTOS_NEVER_TIMEOUT);
#else
return CY_RSLT_SUCCESS;
#endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */
}
//--------------------------------------------------------------------------------------------------
// _mutex_release
//--------------------------------------------------------------------------------------------------
static inline cy_rslt_t _mutex_release(void)
{
#if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE)
return cy_rtos_set_mutex(&serial_flash_mutex);
#else
return CY_RSLT_SUCCESS;
#endif /* #if defined(CY_SERIAL_FLASH_QSPI_THREAD_SAFE) */
}
#if defined(__cplusplus)
}
#endif
#endif // CY_IP_MXSMIF

View File

@ -1,33 +1,45 @@
/***************************************************************************//**
* \file cy_serial_flash_qspi.h
*
* \brief
* Provides APIs for interacting with an external flash connected to the SPI or
* QSPI interface. Flash operations read, write, and erase are implemented as
* blocking functions.
*
********************************************************************************
* \copyright
* Copyright 2018-2020 Cypress Semiconductor Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
/***********************************************************************************************//**
* \file cy_serial_flash_qspi.h
*
* \brief
* Provides APIs for interacting with an external flash connected to the SPI or
* QSPI interface. Read is implemented as both blocking and non-blocking whereas
* write, and erase are implemented as blocking functions.
*
***************************************************************************************************
* \copyright
* Copyright 2018-2021 Cypress Semiconductor Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**************************************************************************************************/
/**
* \addtogroup group_board_libs Serial Flash
* \{
*/
* \addtogroup group_board_libs Serial Flash
* \ingroup group_lib
* \{
*
* \section section_resource_usage DMA Resource Usage
* This library uses fixed DMA (Datawire or DW) resources and supports DMA only
* for the following devices. DMA is not supported for other devices and the
* functions \ref cy_serial_flash_qspi_read_async() and
* \ref cy_serial_flash_qspi_abort_read() will return
* \ref CY_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED error and
* \ref cy_serial_flash_qspi_set_dma_interrupt_priority() will simply return
* doing nothing.
* * CY8C6xx4, CY8C6xx5, CY8C6xx8, CY8C6xxA, CYB06xx5, CYB06xxA, CYS06xxA: <b>DW1, Channel 23</b>
* * CY8C6xx6, CY8C6xx7, CYB06xx7: <b>DW1, Channel 15</b>
*/
#pragma once
@ -43,7 +55,37 @@ extern "C" {
#endif
/** The function or operation is not supported on the target or the memory */
#define CY_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH, 1))
#define CY_RSLT_SERIAL_FLASH_ERR_UNSUPPORTED \
(CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH, 1))
/** Parameters passed to a function are invalid */
#define CY_RSLT_SERIAL_FLASH_ERR_BAD_PARAM \
(CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH, 2))
/** A previously initiated read operation is not yet complete */
#define CY_RSLT_SERIAL_FLASH_ERR_READ_BUSY \
(CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH, 3))
/** A DMA error occurred during read transfer */
#define CY_RSLT_SERIAL_FLASH_ERR_DMA \
(CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH, 4))
/** Read abort failed. QSPI block is busy. */
#define CY_RSLT_SERIAL_FLASH_ERR_QSPI_BUSY \
(CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_SERIAL_FLASH, 5))
#ifdef DOXYGEN
/** Enables thread-safety for use with multi-threaded RTOS environment. */
#define CY_SERIAL_FLASH_QSPI_THREAD_SAFE
#endif /* #ifdef DOXYGEN */
/**
* Callback pointer to use with \ref cy_serial_flash_qspi_read_async().
* \param peration_status Status of the read operation
* \param callback_arg Pointer to be passed back to the callback function
*/
typedef void (* cy_serial_flash_qspi_read_complete_callback_t)(cy_rslt_t operation_status,
void* callback_arg);
/**
* \brief Initializes the serial flash memory. This function accepts up to 8
@ -84,6 +126,10 @@ cy_rslt_t cy_serial_flash_qspi_init(
/**
* \brief De-initializes the serial flash memory.
* Before calling this function, ensure that an ongoing asynchronous read
* operation is either completed or successfully aborted.
* Async read is started by calling \ref cy_serial_flash_qspi_read_async() and
* aborted by calling \ref cy_serial_flash_qspi_abort_read().
*/
void cy_serial_flash_qspi_deinit(void);
@ -120,6 +166,7 @@ __STATIC_INLINE uint32_t cy_serial_flash_get_sector_start_address(uint32_t addr)
return (addr & ~(cy_serial_flash_qspi_get_erase_size(addr) - 1));
}
/**
* \brief Reads data from the serial flash memory. This is a blocking
* function. Returns error if (addr + length) exceeds the flash size.
@ -128,7 +175,34 @@ __STATIC_INLINE uint32_t cy_serial_flash_get_sector_start_address(uint32_t addr)
* \param buf Pointer to the buffer to store the data read from the memory
* \returns CY_RSLT_SUCCESS if the read was successful, an error code otherwise.
*/
cy_rslt_t cy_serial_flash_qspi_read(uint32_t addr, size_t length, uint8_t *buf);
cy_rslt_t cy_serial_flash_qspi_read(uint32_t addr, size_t length, uint8_t* buf);
/**
* \brief Reads data from the serial flash memory. This is a non-blocking
* function. Returns error if (addr + length) exceeds the flash size.
* Uses fixed DMA (DW) instance and channel for transferring the data from
* QSPI RX FIFO to the user-provided buffer.
* \param addr Starting address to read from
* \param length Number of data bytes to read
* \param buf Pointer to the buffer to store the data read from the memory
* \param callback Pointer to the callback function to be called after the read
* operation is complete. Callback is invoked from the DMA ISR.
* \param callback_arg Pointer to the argument to be passed to the callback
* function
* \returns CY_RSLT_SUCCESS if the read was successful, an error code otherwise.
*/
cy_rslt_t cy_serial_flash_qspi_read_async(uint32_t addr, size_t length, uint8_t* buf,
cy_serial_flash_qspi_read_complete_callback_t callback,
void* callback_arg);
/**
* \brief Aborts an ongoing asynchronous read initiated by calling
* \ref cy_serial_flash_qspi_read_async().
*
* \returns CY_RSLT_SUCCESS if the abort was successful, an error code
* if the QSPI block is still busy after a timeout.
*/
cy_rslt_t cy_serial_flash_qspi_abort_read(void);
/**
* \brief Writes the data to the serial flash memory. The program area
@ -141,13 +215,16 @@ cy_rslt_t cy_serial_flash_qspi_read(uint32_t addr, size_t length, uint8_t *buf);
* \returns CY_RSLT_SUCCESS if the write was successful, an error code
* otherwise.
*/
cy_rslt_t cy_serial_flash_qspi_write(uint32_t addr, size_t length, const uint8_t *buf);
cy_rslt_t cy_serial_flash_qspi_write(uint32_t addr, size_t length, const uint8_t* buf);
/**
* \brief Erases the serial flash memory, uses chip erase command when
* addr = 0 and length = flash_size otherwise uses sector erase command. This is
* a blocking function. Returns error if addr or (addr + length) is not aligned
* to the sector size or if (addr + length) exceeds the flash size.
* For memories with hybrid sectors, returns error if the end address
* (=addr + length) is not aligned to the size of the sector in which the end
* address is located.
* Call \ref cy_serial_flash_qspi_get_size() to get the flash size and
* call \ref cy_serial_flash_qspi_get_erase_size() to get the size of an erase
* sector.
@ -177,10 +254,17 @@ cy_rslt_t cy_serial_flash_qspi_enable_xip(bool enable);
*/
void cy_serial_flash_qspi_set_interrupt_priority(uint8_t priority);
/**
* \brief Changes the DMA interrupt priority
* \param priority interrupt priority to be set
*/
void cy_serial_flash_qspi_set_dma_interrupt_priority(uint8_t priority);
#if defined(__cplusplus)
}
#endif
#endif /* CY_IP_MXSMIF */
#endif // CY_IP_MXSMIF
/** \} group_board_libs */

View File

@ -0,0 +1 @@
<version>1.1.0.20805</version>

View File

@ -1 +0,0 @@
<version>.19214</version>