mirror of
https://github.com/oopuuu/zTC1.git
synced 2025-12-17 15:38:14 +08:00
1201 lines
40 KiB
C
1201 lines
40 KiB
C
/**
|
|
******************************************************************************
|
|
* @file platform_flash.c
|
|
* @author William Xu
|
|
* @version V1.0.0
|
|
* @date 05-May-2014
|
|
* @brief This file provides flash operation functions.
|
|
******************************************************************************
|
|
* UNPUBLISHED PROPRIETARY SOURCE CODE
|
|
* Copyright (c) 2016 MXCHIP Inc.
|
|
*
|
|
* The contents of this file may not be disclosed to third parties, copied or
|
|
* duplicated in any form, in whole or in part, without the prior written
|
|
* permission of MXCHIP Corporation.
|
|
******************************************************************************
|
|
*/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "platform_logging.h"
|
|
#include "platform_peripheral.h"
|
|
#include "platform.h"
|
|
#include "platform_config.h"
|
|
#include "stdio.h"
|
|
|
|
#ifdef USE_MICO_SPI_FLASH
|
|
#include "spi_flash.h"
|
|
#endif
|
|
|
|
#ifdef USE_QUAD_SPI_FLASH
|
|
#include "spi_flash.h"
|
|
#include "spi_flash_internal.h"
|
|
#endif
|
|
|
|
/* Private constants --------------------------------------------------------*/
|
|
#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Base @ of Sector 0, 16 Kbyte */
|
|
#define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000) /* Base @ of Sector 1, 16 Kbyte */
|
|
#define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000) /* Base @ of Sector 2, 16 Kbyte */
|
|
#define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000) /* Base @ of Sector 3, 16 Kbyte */
|
|
#define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08010000) /* Base @ of Sector 4, 64 Kbyte */
|
|
#define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000) /* Base @ of Sector 5, 128 Kbyte */
|
|
#define ADDR_FLASH_SECTOR_6 ((uint32_t)0x08040000) /* Base @ of Sector 6, 128 Kbyte */
|
|
#define ADDR_FLASH_SECTOR_7 ((uint32_t)0x08060000) /* Base @ of Sector 7, 128 Kbyte */
|
|
#define ADDR_FLASH_SECTOR_8 ((uint32_t)0x08080000) /* Base @ of Sector 8, 128 Kbyte */
|
|
#define ADDR_FLASH_SECTOR_9 ((uint32_t)0x080A0000) /* Base @ of Sector 9, 128 Kbyte */
|
|
#define ADDR_FLASH_SECTOR_10 ((uint32_t)0x080C0000) /* Base @ of Sector 10, 128 Kbyte */
|
|
#define ADDR_FLASH_SECTOR_11 ((uint32_t)0x080E0000) /* Base @ of Sector 11, 128 Kbyte */
|
|
|
|
/* End of the Flash address */
|
|
#define FLASH_START_ADDRESS (uint32_t)0x08000000
|
|
#define FLASH_END_ADDRESS (uint32_t)0x080FFFFF
|
|
#define FLASH_SIZE (FLASH_END_ADDRESS - FLASH_START_ADDRESS + 1)
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
/* Private define ------------------------------------------------------------*/
|
|
/* Private macro -------------------------------------------------------------*/
|
|
/* Private variables ---------------------------------------------------------*/
|
|
#ifdef USE_MICO_SPI_FLASH
|
|
static sflash_handle_t sflash_handle = {0x0, 0x0, SFLASH_WRITE_NOT_ALLOWED};
|
|
#endif
|
|
#ifdef USE_QUAD_SPI_FLASH
|
|
#define sFLASH_SPI_PAGESIZE 0x100
|
|
static sflash_handle_t sflash_handle = {0x0, 0x0, SFLASH_WRITE_NOT_ALLOWED};
|
|
extern const platform_qspi_t platform_qspi_peripherals[];
|
|
__IO uint8_t *qspiaddr = (__IO uint8_t *)(0x90000000);
|
|
QSPI_ComConfig_InitTypeDef QSPI_ComConfig_InitStructure;
|
|
#ifdef USE_QUAD_SPI_DMA
|
|
DMA_InitTypeDef DMA_InitStructure;
|
|
#endif
|
|
#endif
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
static uint32_t _GetSector( uint32_t Address );
|
|
static OSStatus _GetAddress(uint32_t sector, uint32_t *startAddress, uint32_t *endAddress);
|
|
static OSStatus internalFlashInitialize( void );
|
|
static OSStatus internalFlashErase(uint32_t StartAddress, uint32_t EndAddress);
|
|
static OSStatus internalFlashWrite(volatile uint32_t* FlashAddress, uint32_t* Data ,uint32_t DataLength);
|
|
static OSStatus internalFlashByteWrite( volatile uint32_t* FlashAddress, uint8_t* Data ,uint32_t DataLength );
|
|
#ifdef MCU_EBANLE_FLASH_PROTECT
|
|
static uint32_t _GetWRPSector(uint32_t Address);
|
|
static OSStatus internalFlashProtect(uint32_t StartAddress, uint32_t EndAddress, bool enable);
|
|
#endif
|
|
#ifdef USE_MICO_SPI_FLASH
|
|
static OSStatus spiFlashErase(uint32_t StartAddress, uint32_t EndAddress);
|
|
#endif
|
|
#ifdef USE_QUAD_SPI_FLASH
|
|
static OSStatus qspiFlashErase( uint32_t StartAddress, uint32_t EndAddress );
|
|
static void QSPI_AutoPollingMemReady(void);
|
|
static void QSPI_WriteEnable(void);
|
|
static void QSPI_QEEnable(void);
|
|
static void QSPI_GPIO_Config(/*@out@*/ const platform_qspi_t* peripheral);
|
|
int init_qsflash( /*@out@*/ const platform_qspi_t* peripheral, uint32_t flash_length, /*@out@*/ sflash_handle_t* const handle, sflash_write_allowed_t write_allowed_in );
|
|
int qsflash_read_ID( sflash_handle_t* const handle, void* const data_addr );
|
|
int qsflash_write( const sflash_handle_t* const handle, unsigned long device_address, const void* const data_addr, unsigned int size );
|
|
int qsflash_read( const sflash_handle_t* const handle, unsigned long device_address, void* const data_addr, unsigned int size );
|
|
int qsflash_sector_erase ( unsigned long device_address );
|
|
int qsflash_write_page( const sflash_handle_t* const handle, unsigned long device_address, const void* const data_addr, unsigned int size );
|
|
int get_power(uint32_t number);
|
|
#endif
|
|
|
|
|
|
OSStatus platform_flash_init( const platform_flash_t *peripheral )
|
|
{
|
|
OSStatus err = kNoErr;
|
|
|
|
require_action_quiet( peripheral != NULL, exit, err = kParamErr);
|
|
|
|
if( peripheral->flash_type == FLASH_TYPE_EMBEDDED ){
|
|
err = internalFlashInitialize();
|
|
require_noerr(err, exit);
|
|
}
|
|
#ifdef USE_MICO_SPI_FLASH
|
|
else if( peripheral->flash_type == FLASH_TYPE_SPI ){
|
|
err = init_sflash( &sflash_handle, 0, SFLASH_WRITE_ALLOWED );
|
|
require_noerr(err, exit);
|
|
}
|
|
#else
|
|
#ifdef USE_QUAD_SPI_FLASH
|
|
else if( peripheral->flash_type == FLASH_TYPE_QSPI ){
|
|
err = init_qsflash( &platform_qspi_peripherals[MICO_QSPI_1], peripheral->flash_length, &sflash_handle, SFLASH_WRITE_ALLOWED );
|
|
require_noerr(err, exit);
|
|
}
|
|
#endif
|
|
#endif
|
|
else{
|
|
err = kTypeErr;
|
|
goto exit;
|
|
}
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
OSStatus platform_flash_erase( const platform_flash_t *peripheral, uint32_t start_address, uint32_t end_address )
|
|
{
|
|
OSStatus err = kNoErr;
|
|
|
|
require_action_quiet( peripheral != NULL, exit, err = kParamErr);
|
|
require_action( start_address >= peripheral->flash_start_addr
|
|
&& end_address <= peripheral->flash_start_addr + peripheral->flash_length - 1, exit, err = kParamErr);
|
|
|
|
if( peripheral->flash_type == FLASH_TYPE_EMBEDDED ){
|
|
err = internalFlashErase( start_address, end_address );
|
|
require_noerr(err, exit);
|
|
}
|
|
#ifdef USE_MICO_SPI_FLASH
|
|
else if( peripheral->flash_type == FLASH_TYPE_SPI ){
|
|
err = spiFlashErase( start_address, end_address );
|
|
require_noerr(err, exit);
|
|
}
|
|
#else
|
|
#ifdef USE_QUAD_SPI_FLASH
|
|
else if( peripheral->flash_type == FLASH_TYPE_QSPI ){
|
|
err = qspiFlashErase( start_address, end_address );
|
|
require_noerr(err, exit);
|
|
}
|
|
#endif
|
|
#endif
|
|
else{
|
|
err = kTypeErr;
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
OSStatus platform_flash_write( const platform_flash_t *peripheral, volatile uint32_t* start_address, uint8_t* data ,uint32_t length )
|
|
{
|
|
OSStatus err = kNoErr;
|
|
|
|
require_action_quiet( peripheral != NULL, exit, err = kParamErr);
|
|
require_action( *start_address >= peripheral->flash_start_addr
|
|
&& *start_address + length <= peripheral->flash_start_addr + peripheral->flash_length, exit, err = kParamErr);
|
|
|
|
if( peripheral->flash_type == FLASH_TYPE_EMBEDDED ){
|
|
err = internalFlashWrite( start_address, (uint32_t *)data, length);
|
|
require_noerr(err, exit);
|
|
}
|
|
#ifdef USE_MICO_SPI_FLASH
|
|
else if( peripheral->flash_type == FLASH_TYPE_SPI ){
|
|
err = sflash_write( &sflash_handle, *start_address, data, length );
|
|
require_noerr(err, exit);
|
|
*start_address += length;
|
|
}
|
|
#else
|
|
#ifdef USE_QUAD_SPI_FLASH
|
|
else if( peripheral->flash_type == FLASH_TYPE_QSPI ){
|
|
err = qsflash_write( &sflash_handle, *start_address, data, length );
|
|
require_noerr(err, exit);
|
|
*start_address += length;
|
|
}
|
|
#endif
|
|
#endif
|
|
else{
|
|
err = kTypeErr;
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
OSStatus platform_flash_read( const platform_flash_t *peripheral, volatile uint32_t* start_address, uint8_t* data ,uint32_t length )
|
|
{
|
|
OSStatus err = kNoErr;
|
|
|
|
require_action_quiet( peripheral != NULL, exit, err = kParamErr);
|
|
require_action( (*start_address >= peripheral->flash_start_addr)
|
|
&& (*start_address + length) <= ( peripheral->flash_start_addr + peripheral->flash_length), exit, err = kParamErr);
|
|
|
|
if( peripheral->flash_type == FLASH_TYPE_EMBEDDED ){
|
|
memcpy(data, (void *)(*start_address), length);
|
|
*start_address += length;
|
|
}
|
|
#ifdef USE_MICO_SPI_FLASH
|
|
else if( peripheral->flash_type == FLASH_TYPE_SPI ){
|
|
err = sflash_read( &sflash_handle, *start_address, data, length );
|
|
require_noerr(err, exit);
|
|
*start_address += length;
|
|
}
|
|
#else
|
|
#ifdef USE_QUAD_SPI_FLASH
|
|
else if( peripheral->flash_type == FLASH_TYPE_QSPI ){
|
|
err = qsflash_read( &sflash_handle, *start_address, data, length );
|
|
require_noerr(err, exit);
|
|
*start_address += length;
|
|
}
|
|
#endif
|
|
#endif
|
|
else{
|
|
err = kTypeErr;
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
OSStatus platform_flash_enable_protect( const platform_flash_t *peripheral, uint32_t start_address, uint32_t end_address )
|
|
{
|
|
OSStatus err = kNoErr;
|
|
|
|
require_action_quiet( peripheral != NULL, exit, err = kParamErr);
|
|
require_action( start_address >= peripheral->flash_start_addr
|
|
&& end_address <= peripheral->flash_start_addr + peripheral->flash_length - 1, exit, err = kParamErr);
|
|
|
|
if( peripheral->flash_type == FLASH_TYPE_EMBEDDED ){
|
|
#ifdef MCU_EBANLE_FLASH_PROTECT
|
|
err = internalFlashProtect( start_address, end_address, true );
|
|
#endif
|
|
require_noerr(err, exit);
|
|
}
|
|
#ifdef USE_MICO_SPI_FLASH
|
|
else if( peripheral->flash_type == FLASH_TYPE_SPI ){
|
|
err = kNoErr;
|
|
goto exit;
|
|
}
|
|
#else
|
|
#ifdef USE_QUAD_SPI_FLASH
|
|
else if( peripheral->flash_type == FLASH_TYPE_QSPI ){
|
|
err = kNoErr;
|
|
goto exit;
|
|
}
|
|
#endif
|
|
#endif
|
|
else{
|
|
err = kTypeErr;
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
OSStatus platform_flash_disable_protect( const platform_flash_t *peripheral, uint32_t start_address, uint32_t end_address )
|
|
{
|
|
OSStatus err = kNoErr;
|
|
|
|
require_action_quiet( peripheral != NULL, exit, err = kParamErr);
|
|
require_action( start_address >= peripheral->flash_start_addr
|
|
&& end_address <= peripheral->flash_start_addr + peripheral->flash_length - 1, exit, err = kParamErr);
|
|
|
|
if( peripheral->flash_type == FLASH_TYPE_EMBEDDED ){
|
|
#ifdef MCU_EBANLE_FLASH_PROTECT
|
|
err = internalFlashProtect( start_address, end_address, false );
|
|
#endif
|
|
require_noerr(err, exit);
|
|
}
|
|
#ifdef USE_MICO_SPI_FLASH
|
|
else if( peripheral->flash_type == FLASH_TYPE_SPI ){
|
|
err = kNoErr;
|
|
goto exit;
|
|
}
|
|
#else
|
|
#ifdef USE_QUAD_SPI_FLASH
|
|
else if( peripheral->flash_type == FLASH_TYPE_QSPI ){
|
|
err = kNoErr;
|
|
goto exit;
|
|
}
|
|
#endif
|
|
#endif
|
|
else{
|
|
err = kTypeErr;
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
OSStatus internalFlashInitialize( void )
|
|
{
|
|
platform_log_trace();
|
|
FLASH_Unlock();
|
|
/* Clear pending flags (if any) */
|
|
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
|
|
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
|
|
return kNoErr;
|
|
}
|
|
|
|
OSStatus internalFlashErase(uint32_t StartAddress, uint32_t EndAddress)
|
|
{
|
|
platform_log_trace();
|
|
OSStatus err = kNoErr;
|
|
uint32_t StartSector, EndSector, i = 0, j = 0;
|
|
|
|
/* Get the sector where start the user flash area */
|
|
StartSector = _GetSector(StartAddress);
|
|
EndSector = _GetSector(EndAddress);
|
|
|
|
for(i = StartSector; i <= EndSector; i += 8)
|
|
{
|
|
/* Device voltage range supposed to be [2.7V to 3.6V], the operation will
|
|
be done by word */
|
|
_GetAddress(i, &StartAddress, &EndAddress);
|
|
for(j=StartAddress; j<=EndAddress; j+=4){
|
|
if( (*(uint32_t *)(j))!=0xFFFFFFFF )
|
|
break;
|
|
}
|
|
if( j>EndAddress )
|
|
continue;
|
|
require_action(FLASH_EraseSector(i, VoltageRange_3) == FLASH_COMPLETE, exit, err = kWriteErr);
|
|
}
|
|
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
#ifdef MCU_EBANLE_FLASH_PROTECT
|
|
OSStatus internalFlashProtect(uint32_t StartAddress, uint32_t EndAddress, bool enable)
|
|
{
|
|
OSStatus err = kNoErr;
|
|
uint16_t WRP = 0x0;
|
|
uint32_t StartSector, EndSector, i = 0;
|
|
bool needupdate = false;
|
|
|
|
/* Get the sector where start the user flash area */
|
|
StartSector = _GetWRPSector(StartAddress);
|
|
EndSector = _GetWRPSector(EndAddress);
|
|
|
|
for(i = StartSector; i <= EndSector; i=i<<1)
|
|
{
|
|
WRP = FLASH_OB_GetWRP();
|
|
|
|
if( ( enable == true && (WRP & i) == 0x0 ) ||
|
|
( enable == false && (WRP & i) ) ) {
|
|
continue;
|
|
}
|
|
if( needupdate == false){
|
|
FLASH_OB_Unlock( );
|
|
needupdate = true;
|
|
}
|
|
if( enable == true )
|
|
FLASH_OB_WRPConfig( i, ENABLE );
|
|
else
|
|
FLASH_OB_WRPConfig( i, DISABLE );
|
|
}
|
|
|
|
if( needupdate == true){
|
|
FLASH_OB_Launch( );
|
|
FLASH_OB_Lock( );
|
|
}
|
|
|
|
return err;
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_MICO_SPI_FLASH
|
|
OSStatus spiFlashErase(uint32_t StartAddress, uint32_t EndAddress)
|
|
{
|
|
platform_log_trace();
|
|
OSStatus err = kNoErr;
|
|
uint32_t StartSector, EndSector, i = 0;
|
|
|
|
/* Get the sector where start the user flash area */
|
|
StartSector = StartAddress>>12;
|
|
EndSector = EndAddress>>12;
|
|
|
|
for(i = StartSector; i <= EndSector; i += 1)
|
|
{
|
|
/* Device voltage range supposed to be [2.7V to 3.6V], the operation will
|
|
be done by word */
|
|
require_action(sflash_sector_erase(&sflash_handle, i<<12) == kNoErr, exit, err = kWriteErr);
|
|
}
|
|
|
|
exit:
|
|
return err;
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_QUAD_SPI_FLASH
|
|
static OSStatus qspiFlashErase( uint32_t StartAddress, uint32_t EndAddress )
|
|
{
|
|
platform_log_trace();
|
|
OSStatus err = kNoErr;
|
|
uint32_t StartSector, EndSector, i = 0;
|
|
|
|
/* Get the sector where start the user flash area */
|
|
StartSector = StartAddress>>12;
|
|
EndSector = EndAddress>>12;
|
|
|
|
for(i = StartSector; i <= EndSector; i += 1)
|
|
{
|
|
require_action(qsflash_sector_erase(i<<12) == kNoErr, exit, err = kWriteErr);
|
|
}
|
|
|
|
exit:
|
|
return err;
|
|
}
|
|
#endif
|
|
|
|
|
|
OSStatus internalFlashWrite(volatile uint32_t* FlashAddress, uint32_t* Data ,uint32_t DataLength)
|
|
{
|
|
platform_log_trace();
|
|
OSStatus err = kNoErr;
|
|
uint32_t i = 0;
|
|
uint32_t dataInRam;
|
|
uint8_t startNumber;
|
|
uint32_t DataLength32 = DataLength;
|
|
|
|
/*First bytes that are not 32bit align*/
|
|
if(*FlashAddress%4){
|
|
startNumber = 4-(*FlashAddress)%4;
|
|
err = internalFlashByteWrite(FlashAddress, (uint8_t *)Data, startNumber);
|
|
require_noerr(err, exit);
|
|
DataLength32 = DataLength - startNumber;
|
|
Data = (uint32_t *)((uint32_t)Data + startNumber);
|
|
}
|
|
|
|
/*Program flash by words*/
|
|
for (i = 0; (i < DataLength32/4) && (*FlashAddress <= (FLASH_END_ADDRESS-3)); i++)
|
|
{
|
|
/* Device voltage range supposed to be [2.7V to 3.6V], the operation will
|
|
be done by word */
|
|
dataInRam = *(Data+i);
|
|
require_action(FLASH_ProgramWord(*FlashAddress, dataInRam) == FLASH_COMPLETE, exit, err = kWriteErr);
|
|
require_action(*(uint32_t*)*FlashAddress == dataInRam, exit, err = kChecksumErr);
|
|
/* Increment FLASH destination address */
|
|
*FlashAddress += 4;
|
|
}
|
|
|
|
/*Last bytes that cannot be write by a 32 bit word*/
|
|
err = internalFlashByteWrite(FlashAddress, (uint8_t *)Data + i*4, DataLength32-i*4);
|
|
require_noerr(err, exit);
|
|
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
OSStatus internalFlashByteWrite(__IO uint32_t* FlashAddress, uint8_t* Data ,uint32_t DataLength)
|
|
{
|
|
uint32_t i = 0;
|
|
uint32_t dataInRam;
|
|
OSStatus err = kNoErr;
|
|
|
|
for (i = 0; (i < DataLength) && (*FlashAddress <= (FLASH_END_ADDRESS)); i++)
|
|
{
|
|
/* Device voltage range supposed to be [2.7V to 3.6V], the operation will
|
|
be done by word */
|
|
dataInRam = *(uint8_t*)(Data+i);
|
|
|
|
require_action(FLASH_ProgramByte(*FlashAddress, dataInRam) == FLASH_COMPLETE, exit, err = kWriteErr);
|
|
require_action(*(uint8_t*)*FlashAddress == dataInRam, exit, err = kChecksumErr);
|
|
*FlashAddress +=1;
|
|
}
|
|
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the sector of a given address
|
|
* @param Address: Flash address
|
|
* @retval The sector of a given address
|
|
*/
|
|
static uint32_t _GetSector(uint32_t Address)
|
|
{
|
|
uint32_t sector = 0;
|
|
|
|
if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0))
|
|
{
|
|
sector = FLASH_Sector_0;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1))
|
|
{
|
|
sector = FLASH_Sector_1;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2))
|
|
{
|
|
sector = FLASH_Sector_2;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3))
|
|
{
|
|
sector = FLASH_Sector_3;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4))
|
|
{
|
|
sector = FLASH_Sector_4;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5))
|
|
{
|
|
sector = FLASH_Sector_5;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6))
|
|
{
|
|
sector = FLASH_Sector_6;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_8) && (Address >= ADDR_FLASH_SECTOR_7))
|
|
{
|
|
sector = FLASH_Sector_7;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_9) && (Address >= ADDR_FLASH_SECTOR_8))
|
|
{
|
|
sector = FLASH_Sector_8;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_10) && (Address >= ADDR_FLASH_SECTOR_9))
|
|
{
|
|
sector = FLASH_Sector_9;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_11) && (Address >= ADDR_FLASH_SECTOR_10))
|
|
{
|
|
sector = FLASH_Sector_10;
|
|
}
|
|
else/*(Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_11))*/
|
|
{
|
|
sector = FLASH_Sector_11;
|
|
}
|
|
return sector;
|
|
}
|
|
|
|
|
|
#ifdef MCU_EBANLE_FLASH_PROTECT
|
|
/**
|
|
* @brief Gets the sector of a given address
|
|
* @param Address: Flash address
|
|
* @retval The sector of a given address
|
|
*/
|
|
static uint32_t _GetWRPSector(uint32_t Address)
|
|
{
|
|
uint32_t sector = 0;
|
|
|
|
if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0))
|
|
{
|
|
sector = OB_WRP_Sector_0;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1))
|
|
{
|
|
sector = OB_WRP_Sector_1;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2))
|
|
{
|
|
sector = OB_WRP_Sector_2;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3))
|
|
{
|
|
sector = OB_WRP_Sector_3;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4))
|
|
{
|
|
sector = OB_WRP_Sector_4;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5))
|
|
{
|
|
sector = OB_WRP_Sector_5;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6))
|
|
{
|
|
sector = OB_WRP_Sector_6;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_8) && (Address >= ADDR_FLASH_SECTOR_7))
|
|
{
|
|
sector = OB_WRP_Sector_7;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_9) && (Address >= ADDR_FLASH_SECTOR_8))
|
|
{
|
|
sector = OB_WRP_Sector_8;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_10) && (Address >= ADDR_FLASH_SECTOR_9))
|
|
{
|
|
sector = OB_WRP_Sector_9;
|
|
}
|
|
else if((Address < ADDR_FLASH_SECTOR_11) && (Address >= ADDR_FLASH_SECTOR_10))
|
|
{
|
|
sector = OB_WRP_Sector_10;
|
|
}
|
|
else/*(Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_11))*/
|
|
{
|
|
sector = OB_WRP_Sector_11;
|
|
}
|
|
return sector;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @brief Gets the address of a given sector
|
|
* @param Sector: The sector of a given address
|
|
* @retval Flash address if the sector start
|
|
*/
|
|
static OSStatus _GetAddress(uint32_t sector, uint32_t *startAddress, uint32_t *endAddress)
|
|
{
|
|
OSStatus err = kNoErr;
|
|
if(sector == FLASH_Sector_0)
|
|
{
|
|
*startAddress = ADDR_FLASH_SECTOR_0;
|
|
*endAddress = ADDR_FLASH_SECTOR_1 - 1;
|
|
}
|
|
else if(sector == FLASH_Sector_1)
|
|
{
|
|
*startAddress = ADDR_FLASH_SECTOR_1;
|
|
*endAddress = ADDR_FLASH_SECTOR_2 - 1;
|
|
}
|
|
else if(sector == FLASH_Sector_2)
|
|
{
|
|
*startAddress = ADDR_FLASH_SECTOR_2;
|
|
*endAddress = ADDR_FLASH_SECTOR_3 - 1;
|
|
}
|
|
else if(sector == FLASH_Sector_3)
|
|
{
|
|
*startAddress = ADDR_FLASH_SECTOR_3;
|
|
*endAddress = ADDR_FLASH_SECTOR_4 - 1;
|
|
}
|
|
else if(sector == FLASH_Sector_4)
|
|
{
|
|
*startAddress = ADDR_FLASH_SECTOR_4;
|
|
*endAddress = ADDR_FLASH_SECTOR_5 - 1;
|
|
}
|
|
else if(sector == FLASH_Sector_5)
|
|
{
|
|
*startAddress = ADDR_FLASH_SECTOR_5;
|
|
*endAddress = ADDR_FLASH_SECTOR_6 - 1;
|
|
}
|
|
else if(sector == FLASH_Sector_6)
|
|
{
|
|
*startAddress = ADDR_FLASH_SECTOR_6;
|
|
*endAddress = ADDR_FLASH_SECTOR_7 - 1;
|
|
}
|
|
else if(sector == FLASH_Sector_7)
|
|
{
|
|
*startAddress = ADDR_FLASH_SECTOR_7;
|
|
*endAddress = ADDR_FLASH_SECTOR_8 - 1;
|
|
}
|
|
else if(sector == FLASH_Sector_8)
|
|
{
|
|
*startAddress = ADDR_FLASH_SECTOR_8;
|
|
*endAddress = ADDR_FLASH_SECTOR_9 - 1;
|
|
}
|
|
else if(sector == FLASH_Sector_9)
|
|
{
|
|
*startAddress = ADDR_FLASH_SECTOR_9;
|
|
*endAddress = ADDR_FLASH_SECTOR_10 - 1;
|
|
}
|
|
else if(sector == FLASH_Sector_10)
|
|
{
|
|
*startAddress = ADDR_FLASH_SECTOR_10;
|
|
*endAddress = ADDR_FLASH_SECTOR_11 - 1;
|
|
}
|
|
else if(sector == FLASH_Sector_11)
|
|
{
|
|
*startAddress = ADDR_FLASH_SECTOR_11;
|
|
*endAddress = FLASH_END_ADDRESS - 1;
|
|
}
|
|
else
|
|
err = kNotFoundErr;
|
|
|
|
return err;
|
|
}
|
|
|
|
#ifdef USE_QUAD_SPI_FLASH
|
|
/**
|
|
* @brief Init qspi flash
|
|
* @param None
|
|
* @retval result
|
|
*/
|
|
int init_qsflash( /*@out@*/ const platform_qspi_t* peripheral, uint32_t flash_length, /*@out@*/ sflash_handle_t* const handle, sflash_write_allowed_t write_allowed_in )
|
|
{
|
|
int status;
|
|
device_id_t tmp_device_id;
|
|
QSPI_InitTypeDef QSPI_InitStructure;
|
|
|
|
/* Configure QSPI GPIO */
|
|
QSPI_GPIO_Config( peripheral );
|
|
|
|
/* Initialize QuadSPI ------------------------------------------------------*/
|
|
QSPI_StructInit(&QSPI_InitStructure);
|
|
QSPI_InitStructure.QSPI_SShift = QSPI_SShift_HalfCycleShift;
|
|
QSPI_InitStructure.QSPI_Prescaler = 0x01; /* 90 MHZ */
|
|
QSPI_InitStructure.QSPI_CKMode = QSPI_CKMode_Mode0;
|
|
QSPI_InitStructure.QSPI_CSHTime = QSPI_CSHTime_2Cycle;
|
|
QSPI_InitStructure.QSPI_FSize = get_power(flash_length)-1; /* 2M Byte 0x14*/
|
|
QSPI_InitStructure.QSPI_FSelect = peripheral->FSelect;/* CHOOSE FLASH 2 */
|
|
QSPI_InitStructure.QSPI_DFlash = QSPI_DFlash_Disable;
|
|
QSPI_Init(&QSPI_InitStructure);
|
|
|
|
#ifdef USE_QUAD_SPI_DMA
|
|
/* Initialize DMA ----------------------------------------------------------*/
|
|
DMA_StructInit( &DMA_InitStructure );
|
|
DMA_DeInit( peripheral->dma.stream );
|
|
|
|
/*DMA configuration*/
|
|
DMA_InitStructure.DMA_BufferSize = 0;
|
|
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
|
|
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
|
|
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(peripheral->port->DR) ;
|
|
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
|
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
|
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
|
|
DMA_InitStructure.DMA_Channel = peripheral->dma.channel;
|
|
DMA_InitStructure.DMA_Memory0BaseAddr = 0;
|
|
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
|
|
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
|
|
DMA_Init( peripheral->dma.stream, &DMA_InitStructure );
|
|
#endif
|
|
|
|
/* Initialize Command Config -----------------------------------------------*/
|
|
QSPI_ComConfig_StructInit(&QSPI_ComConfig_InitStructure);
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADSize = QSPI_ComConfig_ADSize_24bit;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_IMode = QSPI_ComConfig_IMode_1Line;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ABMode = QSPI_ComConfig_ABMode_NoAlternateByte;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_DDRMode = QSPI_ComConfig_DDRMode_Disable;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_SIOOMode = QSPI_ComConfig_SIOOMode_Disable;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_DHHC = QSPI_ComConfig_DHHC_Enable;
|
|
QSPI_ComConfig_StructInit(&QSPI_ComConfig_InitStructure);
|
|
QSPI_Cmd(ENABLE);
|
|
|
|
if ( write_allowed_in == SFLASH_WRITE_ALLOWED )
|
|
{
|
|
/* Enable write operations ---------------------------------------------*/
|
|
QSPI_WriteEnable();
|
|
QSPI_QEEnable();
|
|
}
|
|
|
|
/*Delay wait to QE Mode*/
|
|
|
|
handle->write_allowed = write_allowed_in;
|
|
/* Read Flash ID */
|
|
status = qsflash_read_ID( handle, &tmp_device_id );
|
|
|
|
if( status != 0 )
|
|
{
|
|
return status;
|
|
}
|
|
|
|
handle->device_id = ( ((uint32_t) tmp_device_id.id[0]) << 16 ) +
|
|
( ((uint32_t) tmp_device_id.id[1]) << 8 ) +
|
|
( ((uint32_t) tmp_device_id.id[2]) << 0 );
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief read block of data to the FLASH.
|
|
*
|
|
* @param data_addr: pointer to the buffer containing the data to be written
|
|
* to the FLASH.
|
|
* @param device_address: FLASH's internal address to write to.
|
|
* @param size: number of bytes to write to the FLASH.
|
|
* @retval None
|
|
*/
|
|
int qsflash_read( const sflash_handle_t* const handle, unsigned long device_address, void* const data_addr, unsigned int size )
|
|
{
|
|
uint8_t* pAddr;
|
|
|
|
/* Reading Sequence ----------------------------------------------------*/
|
|
QSPI_Cmd(ENABLE);
|
|
QSPI_TimeoutCounterCmd(DISABLE);
|
|
QSPI_MemoryMappedMode_SetTimeout(0);
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADSize = QSPI_ComConfig_ADSize_24bit;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_FMode = QSPI_ComConfig_FMode_Memory_Mapped;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADMode = QSPI_ComConfig_ADMode_4Line;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_IMode = QSPI_ComConfig_IMode_1Line;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_DMode = QSPI_ComConfig_DMode_4Line;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_Ins = SFLASH_QUAD_READ;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD;
|
|
QSPI_ComConfig_Init(&QSPI_ComConfig_InitStructure);
|
|
|
|
pAddr = (uint8_t*) qspiaddr + device_address;
|
|
memcpy(data_addr, (void *)(pAddr), size);
|
|
|
|
QSPI_AbortRequest();
|
|
QSPI_Cmd(DISABLE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Writes block of data to the FLASH. In this function, the number of
|
|
* WRITE cycles are reduced, using Page WRITE sequence.
|
|
* @param data_addr: pointer to the buffer containing the data to be written
|
|
* to the FLASH.
|
|
* @param device_address: FLASH's internal address to write to.
|
|
* @param size: number of bytes to write to the FLASH.
|
|
* @retval None
|
|
*/
|
|
int qsflash_write( const sflash_handle_t* const handle, unsigned long device_address, const void* const data_addr, unsigned int size )
|
|
{
|
|
int status = 0;
|
|
uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
|
|
unsigned char* data_addr_ptr = (unsigned char*) data_addr;
|
|
|
|
Addr = device_address % sFLASH_SPI_PAGESIZE;
|
|
count = sFLASH_SPI_PAGESIZE - Addr;
|
|
NumOfPage = size / sFLASH_SPI_PAGESIZE;
|
|
NumOfSingle = size % sFLASH_SPI_PAGESIZE;
|
|
|
|
if (Addr == 0) /*!< WriteAddr is sFLASH_PAGESIZE aligned */
|
|
{
|
|
if (NumOfPage == 0) /*!< NumByteToWrite < sFLASH_PAGESIZE */
|
|
{
|
|
status = qsflash_write_page( handle, device_address, data_addr_ptr, size );
|
|
//sFLASH_WritePage(pBuffer, WriteAddr, NumByteToWrite);
|
|
}
|
|
else /*!< NumByteToWrite > sFLASH_PAGESIZE */
|
|
{
|
|
while (NumOfPage--)
|
|
{
|
|
status = qsflash_write_page( handle, device_address, data_addr_ptr, sFLASH_SPI_PAGESIZE );
|
|
//sFLASH_WritePage(pBuffer, WriteAddr, sFLASH_SPI_PAGESIZE);
|
|
device_address += sFLASH_SPI_PAGESIZE;
|
|
data_addr_ptr += sFLASH_SPI_PAGESIZE;
|
|
}
|
|
if( NumOfSingle != 0 )
|
|
{
|
|
status = qsflash_write_page( handle, device_address, data_addr_ptr, NumOfSingle);
|
|
}
|
|
}
|
|
}
|
|
else /*!< WriteAddr is not sFLASH_PAGESIZE aligned */
|
|
{
|
|
if (NumOfPage == 0) /*!< NumByteToWrite < sFLASH_PAGESIZE */
|
|
{
|
|
if (NumOfSingle > count) /*!< (NumByteToWrite + WriteAddr) > sFLASH_PAGESIZE */
|
|
{
|
|
temp = NumOfSingle - count;
|
|
|
|
status = qsflash_write_page( handle, device_address, data_addr_ptr, count );
|
|
//sFLASH_WritePage(pBuffer, WriteAddr, count);
|
|
device_address += count;
|
|
data_addr_ptr += count;
|
|
|
|
status = qsflash_write_page( handle, device_address, data_addr_ptr, temp);
|
|
}
|
|
else
|
|
{
|
|
status = qsflash_write_page(handle, device_address, data_addr_ptr, size);
|
|
}
|
|
}
|
|
else /*!< NumByteToWrite > sFLASH_PAGESIZE */
|
|
{
|
|
size -= count;
|
|
NumOfPage = size / sFLASH_SPI_PAGESIZE;
|
|
NumOfSingle = size % sFLASH_SPI_PAGESIZE;
|
|
|
|
status = qsflash_write_page( handle, device_address, data_addr_ptr, count );
|
|
//sFLASH_WritePage(pBuffer, WriteAddr, count);
|
|
device_address += count;
|
|
data_addr_ptr += count;
|
|
|
|
while (NumOfPage--)
|
|
{
|
|
status = qsflash_write_page( handle, device_address, data_addr_ptr, sFLASH_SPI_PAGESIZE );
|
|
//sFLASH_WritePage(pBuffer, WriteAddr, sFLASH_SPI_PAGESIZE);
|
|
device_address += sFLASH_SPI_PAGESIZE;
|
|
data_addr_ptr += sFLASH_SPI_PAGESIZE;
|
|
}
|
|
|
|
if (NumOfSingle != 0)
|
|
{
|
|
status = qsflash_write_page( handle, device_address, data_addr_ptr, NumOfSingle );
|
|
//sFLASH_WritePage(pBuffer, WriteAddr, NumOfSingle);
|
|
}
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief Writes block of data to the FLASH. In this function, the number of
|
|
* WRITE cycles are reduced, using Page WRITE sequence.
|
|
* @param data_addr: pointer to the buffer containing the data to be written
|
|
* to the FLASH.
|
|
* @param device_address: FLASH's internal address to write to.
|
|
* @param size: number of bytes to write to the FLASH.
|
|
* @retval None
|
|
*/
|
|
int qsflash_write_page( const sflash_handle_t* const handle, unsigned long device_address, const void* const data_addr, unsigned int size )
|
|
{
|
|
|
|
#ifdef USE_QUAD_SPI_DMA
|
|
const platform_qspi_t* peripheral = &platform_qspi_peripherals[MICO_QSPI_1];
|
|
#else
|
|
uint8_t* buffer = NULL;
|
|
#endif
|
|
if ( handle->write_allowed == SFLASH_WRITE_ALLOWED )
|
|
{
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
/* Enable write operations ---------------------------------------------*/
|
|
QSPI_Cmd(ENABLE);
|
|
QSPI_WriteEnable();
|
|
#ifdef USE_QUAD_SPI_DMA
|
|
QSPI_DMACmd(ENABLE);
|
|
#endif
|
|
|
|
/* Writing Sequence ----------------------------------------------------*/
|
|
QSPI_SetDataLength(size-1);
|
|
|
|
QSPI_ComConfig_StructInit(&QSPI_ComConfig_InitStructure);
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_IMode = QSPI_ComConfig_IMode_1Line;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADMode = QSPI_ComConfig_ADMode_4Line;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_DMode = QSPI_ComConfig_DMode_4Line;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_FMode = QSPI_ComConfig_FMode_Indirect_Write;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADSize = QSPI_ComConfig_ADSize_24bit;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_Ins = SFLASH_QUAD_WRITE;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_DummyCycles = 0;
|
|
QSPI_ComConfig_Init(&QSPI_ComConfig_InitStructure);
|
|
QSPI_SetAddress(device_address);
|
|
|
|
#ifdef USE_QUAD_SPI_DMA
|
|
/*DMA configuration*/
|
|
peripheral->dma.stream->M0AR = (uint32_t)data_addr;
|
|
peripheral->dma.stream->NDTR = size;
|
|
DMA_Cmd( peripheral->dma.stream, ENABLE );
|
|
|
|
/* Wait for the end of Transfer */
|
|
|
|
while(DMA_GetFlagStatus(peripheral->dma.stream, peripheral->dma.complete_flags) == RESET)
|
|
{}
|
|
DMA_ClearFlag(peripheral->dma.stream, peripheral->dma.complete_flags);
|
|
|
|
DMA_Cmd(peripheral->dma.stream, DISABLE);
|
|
|
|
QSPI_DMACmd(DISABLE);
|
|
#else
|
|
/* Send data */
|
|
buffer = (uint8_t *)data_addr;
|
|
while(size--)
|
|
{
|
|
if(QSPI_GetFlagStatus(QSPI_FLAG_FT))
|
|
QSPI_SendData8(*buffer++);
|
|
}
|
|
#endif
|
|
|
|
/* Configure automatic polling mode to wait for end of program ---------*/
|
|
QSPI_AutoPollingMemReady();
|
|
QSPI_Cmd(DISABLE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Erase the selected sector through device_address.
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
int qsflash_sector_erase ( unsigned long device_address )
|
|
{
|
|
/* Enable write operations ---------------------------------------------*/
|
|
QSPI_Cmd(ENABLE);
|
|
QSPI_WriteEnable();
|
|
|
|
/* Erasing Sequence ----------------------------------------------------*/
|
|
QSPI_ComConfig_StructInit(&QSPI_ComConfig_InitStructure);
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADSize = QSPI_ComConfig_ADSize_24bit;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_IMode = QSPI_ComConfig_IMode_1Line;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADMode = QSPI_ComConfig_ADMode_1Line;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_DMode = QSPI_ComConfig_DMode_NoData;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_FMode = QSPI_ComConfig_FMode_Indirect_Write;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_Ins = SFLASH_SECTOR_ERASE;
|
|
QSPI_ComConfig_Init(&QSPI_ComConfig_InitStructure);
|
|
|
|
/* Set sector address to erase */
|
|
QSPI_SetAddress(device_address);
|
|
|
|
while(QSPI_GetFlagStatus(QSPI_FLAG_TC) == RESET)
|
|
{}
|
|
|
|
/* Configure automatic polling mode to wait for end of erase -----------*/
|
|
QSPI_AutoPollingMemReady();
|
|
QSPI_Cmd(DISABLE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Read qspi flash ID
|
|
* @param None
|
|
* @retval result
|
|
*/
|
|
int qsflash_read_ID( sflash_handle_t* const handle, void* const data_addr )
|
|
{
|
|
uint8_t* pAddr;
|
|
/* Reading Sequence ----------------------------------------------------*/
|
|
QSPI_TimeoutCounterCmd(DISABLE);
|
|
QSPI_MemoryMappedMode_SetTimeout(0);
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADSize = QSPI_ComConfig_ADSize_24bit;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_FMode = QSPI_ComConfig_FMode_Memory_Mapped;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADMode = QSPI_ComConfig_ADMode_NoAddress;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_IMode = QSPI_ComConfig_IMode_1Line;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_DMode = QSPI_ComConfig_DMode_1Line;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_Ins = SFLASH_READ_JEDEC_ID;
|
|
QSPI_ComConfig_Init(&QSPI_ComConfig_InitStructure);
|
|
|
|
pAddr = (uint8_t*) qspiaddr;
|
|
for( int i=0; i<3; i++ )
|
|
{
|
|
((uint8_t*)data_addr)[i] = *pAddr++;
|
|
}
|
|
QSPI_AbortRequest();
|
|
QSPI_Cmd(DISABLE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Configures the QSPI GPIO Pins.
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
static void QSPI_GPIO_Config(/*@out@*/ const platform_qspi_t* peripheral)
|
|
{
|
|
|
|
/* Peripheral Clock Enable -------------------------------------------------*/
|
|
/* Enable the QSPI clock */
|
|
(peripheral->peripheral_clock_func)( peripheral->peripheral_clock_reg, ENABLE );
|
|
|
|
/* Enable DMA1/2 AHB1 clock */
|
|
#ifdef USE_QUAD_SPI_DMA
|
|
if( peripheral->dma.controller == DMA1 )
|
|
{
|
|
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
|
|
}
|
|
else
|
|
{
|
|
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
|
|
}
|
|
#endif
|
|
|
|
/* QSPI GPIO Configuration -------------------------------------------------*/
|
|
platform_gpio_set_alternate_function( peripheral->pin_clock->port, peripheral->pin_clock->pin_number, GPIO_OType_PP, GPIO_PuPd_NOPULL, peripheral->gpio_af_clk );
|
|
platform_gpio_set_alternate_function( peripheral->pin_d0->port, peripheral->pin_d0->pin_number, GPIO_OType_PP, GPIO_PuPd_NOPULL, peripheral->gpio_af_d0 );
|
|
platform_gpio_set_alternate_function( peripheral->pin_d1->port, peripheral->pin_d1->pin_number, GPIO_OType_PP, GPIO_PuPd_NOPULL, peripheral->gpio_af_d1 );
|
|
platform_gpio_set_alternate_function( peripheral->pin_d2->port, peripheral->pin_d2->pin_number, GPIO_OType_PP, GPIO_PuPd_NOPULL, peripheral->gpio_af_d2 );
|
|
platform_gpio_set_alternate_function( peripheral->pin_d3->port, peripheral->pin_d3->pin_number, GPIO_OType_PP, GPIO_PuPd_NOPULL, peripheral->gpio_af_d3 );
|
|
platform_gpio_set_alternate_function( peripheral->pin_cs->port, peripheral->pin_cs->pin_number, GPIO_OType_PP, GPIO_PuPd_UP, peripheral->gpio_af_cs );
|
|
|
|
/* QSPI CS pin set high */
|
|
platform_gpio_output_high( peripheral->pin_cs );
|
|
}
|
|
|
|
/**
|
|
* @brief This function read the SR of the memory and wait the end of Command.
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
static void QSPI_AutoPollingMemReady(void)
|
|
{
|
|
/* Wait for end of Cmd */
|
|
while(QSPI_GetFlagStatus(QSPI_FLAG_BUSY) != RESET)
|
|
{}
|
|
QSPI_SetDataLength(0x00);
|
|
QSPI_AutoPollingMode_Config(0x0000, 0x0101, QSPI_PMM_AND);
|
|
QSPI_AutoPollingModeStopCmd(ENABLE);
|
|
QSPI_SetDataLength(0);
|
|
|
|
/* Reconfigure QSPI to automatic polling mode to wait for end of Command*/
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_FMode = QSPI_ComConfig_FMode_Auto_Polling;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADMode = QSPI_ComConfig_ADMode_NoAddress;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_DMode = QSPI_ComConfig_DMode_1Line;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_Ins = SFLASH_READ_STATUS_REGISTER;
|
|
QSPI_ComConfig_Init(&QSPI_ComConfig_InitStructure);
|
|
|
|
while(QSPI_GetFlagStatus(QSPI_FLAG_SM) == RESET)
|
|
{}
|
|
|
|
QSPI_ClearFlag(QSPI_FLAG_SM);
|
|
QSPI_ClearFlag(QSPI_FLAG_TC);
|
|
}
|
|
|
|
/**
|
|
* @brief This function send a Write Enable and wait it is effective.
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
static void QSPI_WriteEnable(void)
|
|
{
|
|
/* Command Config for Write Enable Operation*/
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_DHHC = QSPI_ComConfig_DHHC_Disable;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_DDRMode = QSPI_ComConfig_DDRMode_Disable;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_SIOOMode = QSPI_ComConfig_SIOOMode_Disable;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ABSize = QSPI_ComConfig_ABSize_8bit;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADSize = QSPI_ComConfig_ADSize_24bit;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_DMode = QSPI_ComConfig_DMode_NoData;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADMode = QSPI_ComConfig_ADMode_NoAddress;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ABMode = QSPI_ComConfig_ABMode_NoAlternateByte;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_IMode = QSPI_ComConfig_IMode_1Line;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_FMode = QSPI_ComConfig_FMode_Indirect_Write;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_Ins = SFLASH_WRITE_ENABLE ;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_DummyCycles = 0;
|
|
QSPI_ComConfig_Init(&QSPI_ComConfig_InitStructure);
|
|
|
|
/* Switch to Autopolling mode for the end of the Command */
|
|
while(QSPI_GetFlagStatus(QSPI_FLAG_BUSY) != RESET)
|
|
{}
|
|
QSPI_AutoPollingMode_SetInterval(0x10);
|
|
QSPI_AutoPollingMode_Config(0x02, 0x02, QSPI_PMM_AND);
|
|
QSPI_AutoPollingModeStopCmd(ENABLE);
|
|
QSPI_SetDataLength(0x00);
|
|
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_FMode = QSPI_ComConfig_FMode_Auto_Polling;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADMode = QSPI_ComConfig_ADMode_NoAddress;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_DMode = QSPI_ComConfig_DMode_1Line;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_Ins = SFLASH_READ_STATUS_REGISTER;
|
|
QSPI_ComConfig_Init(&QSPI_ComConfig_InitStructure);
|
|
|
|
while(QSPI_GetFlagStatus(QSPI_FLAG_SM) == RESET)
|
|
{}
|
|
QSPI_ClearFlag(QSPI_FLAG_SM);
|
|
QSPI_ClearFlag(QSPI_FLAG_TC);
|
|
while(QSPI_GetFlagStatus(QSPI_FLAG_BUSY) != RESET)
|
|
{}
|
|
}
|
|
|
|
/**
|
|
* @brief This function send a Quad Enable and wait it is effective.
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
static void QSPI_QEEnable(void)
|
|
{
|
|
uint8_t status_register = 0x40; //Quad Enable bit 6
|
|
/* Command Config for Write Status Register Operation*/
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADMode = QSPI_ComConfig_ADMode_NoAddress;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ABMode = QSPI_ComConfig_ABMode_NoAlternateByte;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_DMode = QSPI_ComConfig_DMode_1Line;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_IMode = QSPI_ComConfig_IMode_1Line;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_FMode = QSPI_ComConfig_FMode_Indirect_Write;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_Ins = SFLASH_WRITE_STATUS_REGISTER;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_DummyCycles = 0;
|
|
QSPI_ComConfig_Init(&QSPI_ComConfig_InitStructure);
|
|
|
|
QUADSPI->DR = status_register;
|
|
|
|
/* Switch to Autopolling mode for the end of the Command */
|
|
while(QSPI_GetFlagStatus(QSPI_FLAG_BUSY) != RESET)
|
|
{}
|
|
QSPI_AutoPollingMode_SetInterval(0x10);
|
|
QSPI_AutoPollingMode_Config(0x40, 0x40, QSPI_PMM_AND);
|
|
QSPI_AutoPollingModeStopCmd(ENABLE);
|
|
QSPI_SetDataLength(0x00);
|
|
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_FMode = QSPI_ComConfig_FMode_Auto_Polling;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_ADMode = QSPI_ComConfig_ADMode_NoAddress;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_DMode = QSPI_ComConfig_DMode_1Line;
|
|
QSPI_ComConfig_InitStructure.QSPI_ComConfig_Ins = SFLASH_READ_STATUS_REGISTER;
|
|
QSPI_ComConfig_Init(&QSPI_ComConfig_InitStructure);
|
|
|
|
while(QSPI_GetFlagStatus(QSPI_FLAG_SM) == RESET)
|
|
{}
|
|
QSPI_ClearFlag(QSPI_FLAG_SM);
|
|
QSPI_ClearFlag(QSPI_FLAG_TC);
|
|
while(QSPI_GetFlagStatus(QSPI_FLAG_BUSY) != RESET)
|
|
{}
|
|
}
|
|
|
|
|
|
int get_power(uint32_t number)
|
|
{
|
|
int count = 0;
|
|
while(1)
|
|
{
|
|
if(number>>=1) count++;
|
|
else break;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
|
|
#endif
|