2023-01-11 23:45:54 +08:00

543 lines
20 KiB
C

/* -----------------------------------------------------------------------------
* Copyright (c) 2014 - 2019 ARM Ltd.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software. Permission is granted to anyone to use this
* software for any purpose, including commercial applications, and to alter
* it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
*
* $Date: 2021-7-1
* $Revision: V1.0.0
*
* Project: Flash Programming Functions for Puya PY32F0xx Flash
* --------------------------------------------------------------------------- */
/* History:
* Version 1.0.0
* Initial release
*/
#include "FlashOS.h" // FlashOS Structures
typedef volatile unsigned char vu8;
typedef unsigned char u8;
typedef volatile unsigned short vu16;
typedef unsigned short u16;
typedef volatile unsigned long vu32;
typedef unsigned long u32;
#define M8(adr) (*((vu8 *) (adr)))
#define M16(adr) (*((vu16 *) (adr)))
#define M32(adr) (*((vu32 *) (adr)))
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT))
#define READ_BIT(REG, BIT) ((REG) & (BIT))
#define CLEAR_REG(REG) ((REG) = (0x0))
#define WRITE_REG(REG, VAL) ((REG) = (VAL))
#define READ_REG(REG) ((REG))
#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))
// Peripheral Memory Map
#define RCC_BASE 0x40021000
#define IWDG_BASE 0x40003000
#define FLASH_BASE 0x40022000
#define RCC ((RCC_TypeDef*) RCC_BASE)
#define IWDG ((IWDG_TypeDef *) IWDG_BASE)
#define FLASH ((FLASH_TypeDef*) FLASH_BASE)
typedef struct
{
vu32 CR; /*!< RCC Clock Sources Control Register, Address offset: 0x00 */
vu32 ICSCR; /*!< RCC Internal Clock Sources Calibration Register, Address offset: 0x04 */
} RCC_TypeDef;
// Independent WATCHDOG
typedef struct {
vu32 KR; /*!< IWDG Key register, Address offset: 0x00 */
vu32 PR; /*!< IWDG Prescaler register, Address offset: 0x04 */
vu32 RLR; /*!< IWDG Reload register, Address offset: 0x08 */
vu32 SR; /*!< IWDG Status register, Address offset: 0x0C */
} IWDG_TypeDef;
// Flash Registers
typedef struct {
vu32 ACR; /*!< FLASH Access Control register, Address offset: 0x00 */
vu32 RESERVED1; /*!< Reserved1, Address offset: 0x04 */
vu32 KEYR; /*!< FLASH Key register, Address offset: 0x08 */
vu32 OPTKEYR; /*!< FLASH Option Key register, Address offset: 0x0C */
vu32 SR; /*!< FLASH Status register, Address offset: 0x10 */
vu32 CR; /*!< FLASH Control register, Address offset: 0x14 */
vu32 RESERVED2[2]; /*!< Reserved2, Address offset: 0x18-0x1C */
vu32 OPTR; /*!< FLASH Option register, Address offset: 0x20 */
vu32 SDKR; /*!< FLASH SDK address register, Address offset: 0x24 */
vu32 RESERVED3; /*!< Reserved2, Address offset: 0x28 */
vu32 WRPR; /*!< FLASH WRP address register, Address offset: 0x2C */
vu32 RESERVED4[(0x90 - 0x2C) / 4 - 1];
vu32 STCR; /*!< FLASH sleep time config register, Address offset: 0x90 */
vu32 RESERVED5[(0x100 - 0x90) / 4 - 1];
vu32 TS0; /*!< FLASH TS0 register, Address offset: 0x100 */
vu32 TS1; /*!< FLASH TS1 register, Address offset: 0x104 */
vu32 TS2P; /*!< FLASH TS2P register, Address offset: 0x108 */
vu32 TPS3; /*!< FLASH TPS3 register, Address offset: 0x10C */
vu32 TS3; /*!< FLASH TS3 register, Address offset: 0x110 */
vu32 PERTPE; /*!< FLASH PERTPE register, Address offset: 0x114 */
vu32 SMERTPE; /*!< FLASH SMERTPE register, Address offset: 0x118 */
vu32 PRGTPE; /*!< FLASH PRGTPE register, Address offset: 0x11C */
vu32 PRETPE; /*!< FLASH PRETPE register, Address offset: 0x120 */
} FLASH_TypeDef;
// Flash Keys
#define FLASH_KEY1 ((unsigned int)0x45670123)
#define FLASH_KEY2 ((unsigned int)0xCDEF89AB)
#define FLASH_OPTKEY1 ((unsigned int)0x08192A3B)
#define FLASH_OPTKEY2 ((unsigned int)0x4C5D6E7F)
// Flash Control Register definitions
#define FLASH_CR_PG_Pos (0U)
#define FLASH_CR_PG_Msk (0x1UL << FLASH_CR_PG_Pos) /*!< 0x00000001 */
#define FLASH_CR_PG FLASH_CR_PG_Msk
#define FLASH_CR_PER_Pos (1U)
#define FLASH_CR_PER_Msk (0x1UL << FLASH_CR_PER_Pos) /*!< 0x00000002 */
#define FLASH_CR_PER FLASH_CR_PER_Msk
#define FLASH_CR_MER_Pos (2U)
#define FLASH_CR_MER_Msk (0x1UL << FLASH_CR_MER_Pos) /*!< 0x00000004 */
#define FLASH_CR_MER FLASH_CR_MER_Msk
#define FLASH_CR_SER_Pos (11U)
#define FLASH_CR_SER_Msk (0x1UL << FLASH_CR_SER_Pos) /*!< 0x00000800 */
#define FLASH_CR_SER FLASH_CR_SER_Msk
#define FLASH_CR_OPTSTRT_Pos (17U)
#define FLASH_CR_OPTSTRT_Msk (0x1UL << FLASH_CR_OPTSTRT_Pos) /*!< 0x00020000 */
#define FLASH_CR_OPTSTRT FLASH_CR_OPTSTRT_Msk
#define FLASH_CR_PGSTRT_Pos (19U)
#define FLASH_CR_PGSTRT_Msk (0x1UL << FLASH_CR_PGSTRT_Pos) /*!< 0x00080000 */
#define FLASH_CR_PGSTRT FLASH_CR_PGSTRT_Msk
#define FLASH_CR_EOPIE_Pos (24U)
#define FLASH_CR_EOPIE_Msk (0x1UL << FLASH_CR_EOPIE_Pos) /*!< 0x01000000 */
#define FLASH_CR_EOPIE FLASH_CR_EOPIE_Msk
#define FLASH_CR_ERRIE_Pos (25U)
#define FLASH_CR_ERRIE_Msk (0x1UL << FLASH_CR_ERRIE_Pos) /*!< 0x02000000 */
#define FLASH_CR_ERRIE FLASH_CR_ERRIE_Msk
#define FLASH_CR_OBL_LAUNCH_Pos (27U)
#define FLASH_CR_OBL_LAUNCH_Msk (0x1UL << FLASH_CR_OBL_LAUNCH_Pos) /*!< 0x08000000 */
#define FLASH_CR_OBL_LAUNCH FLASH_CR_OBL_LAUNCH_Msk
#define FLASH_CR_OPTLOCK_Pos (30U)
#define FLASH_CR_OPTLOCK_Msk (0x1UL << FLASH_CR_OPTLOCK_Pos) /*!< 0x40000000 */
#define FLASH_CR_OPTLOCK FLASH_CR_OPTLOCK_Msk
#define FLASH_CR_LOCK_Pos (31U)
#define FLASH_CR_LOCK_Msk (0x1UL << FLASH_CR_LOCK_Pos) /*!< 0x80000000 */
#define FLASH_CR_LOCK FLASH_CR_LOCK_Msk
// Flash Status Register definitions
#define FLASH_SR_EOP_Pos (0U)
#define FLASH_SR_EOP_Msk (0x1UL << FLASH_SR_EOP_Pos) /*!< 0x00000001 */
#define FLASH_SR_EOP FLASH_SR_EOP_Msk
#define FLASH_SR_WRPERR_Pos (4U)
#define FLASH_SR_WRPERR_Msk (0x1UL << FLASH_SR_WRPERR_Pos) /*!< 0x00000010 */
#define FLASH_SR_WRPERR FLASH_SR_WRPERR_Msk
#define FLASH_SR_OPTVERR_Pos (15U)
#define FLASH_SR_OPTVERR_Msk (0x1UL << FLASH_SR_OPTVERR_Pos) /*!< 0x00008000 */
#define FLASH_SR_OPTVERR FLASH_SR_OPTVERR_Msk
#define FLASH_SR_BSY_Pos (16U)
#define FLASH_SR_BSY_Msk (0x1UL << FLASH_SR_BSY_Pos) /*!< 0x00010000 */
#define FLASH_SR_BSY FLASH_SR_BSY_Msk
#define FLASH_OPTR_IWDG_SW_Pos (12U)
#define FLASH_OPTR_IWDG_SW_Msk (0x1UL << FLASH_OPTR_IWDG_SW_Pos) /*!< 0x00010000 */
#define FLASH_OPTR_IWDG_SW FLASH_OPTR_IWDG_SW_Msk
#define FLASH_OPTR_WWDG_SW_Pos (13U)
#define FLASH_OPTR_WWDG_SW_Msk (0x1UL << FLASH_OPTR_WWDG_SW_Pos) /*!< 0x00080000 */
#define FLASH_OPTR_WWDG_SW FLASH_OPTR_WWDG_SW_Msk
u32 RCC_ICSCR_HSI_FS_RESTORE;
void InitRccAndFlashParam(void);
void UnInitRccAndFlashParam(void);
/*
* Initialize Flash Programming Functions
* Parameter: adr: Device Base Address
* clk: Clock Frequency (Hz)
* fnc: Function Code (1 - Erase, 2 - Program, 3 - Verify)
* Return Value: 0 - OK, 1 - Failed
*/
#ifdef FLASH_MEM
int Init(unsigned long adr, unsigned long clk, unsigned long fnc)
{
FLASH->KEYR = FLASH_KEY1; // Unlock Flash
FLASH->KEYR = FLASH_KEY2;
InitRccAndFlashParam();
FLASH->ACR = 0x00000000; // Zero Wait State, no Prefetch
FLASH->SR |= FLASH_SR_EOP; // Reset FLASH_EOP
if ((FLASH->OPTR & FLASH_OPTR_IWDG_SW) == 0x00) // Test if IWDG is running (IWDG in HW mode)
{
// Set IWDG time out to ~32.768 second
IWDG->KR = 0x5555; // Enable write access to IWDG_PR and IWDG_RLR
IWDG->PR = 0x06; // Set prescaler to 256
IWDG->RLR = 0xFFF; // Set reload value to 4095
}
return (0);
}
#endif
#ifdef FLASH_OPT
int Init(unsigned long adr, unsigned long clk, unsigned long fnc)
{
FLASH->KEYR = FLASH_KEY1; // Unlock Flash
FLASH->KEYR = FLASH_KEY2;
InitRccAndFlashParam();
FLASH->OPTKEYR = FLASH_OPTKEY1; // Unlock Option Bytes
FLASH->OPTKEYR = FLASH_OPTKEY2;
FLASH->ACR = 0x00000000; // Zero Wait State, no Prefetch
FLASH->SR |= FLASH_SR_EOP; // Reset FLASH_EOP
if ((FLASH->OPTR & 0x1000) == 0x00) // Test if IWDG is running (IWDG in HW mode)
{
// Set IWDG time out to ~32.768 second
IWDG->KR = 0x5555; // Enable write access to IWDG_PR and IWDG_RLR
IWDG->PR = 0x06; // Set prescaler to 256
IWDG->RLR = 0xFFF; // Set reload value to 4095
}
return (0);
}
#endif
/*
* De-Initialize Flash Programming Functions
* Parameter: fnc: Function Code (1 - Erase, 2 - Program, 3 - Verify)
* Return Value: 0 - OK, 1 - Failed
*/
#ifdef FLASH_MEM
int UnInit(unsigned long fnc)
{
UnInitRccAndFlashParam();
FLASH->CR |= FLASH_CR_LOCK; // Lock Flash
return (0);
}
#endif
#ifdef FLASH_OPT
int UnInit(unsigned long fnc)
{
UnInitRccAndFlashParam();
FLASH->CR |= FLASH_CR_LOCK; // Lock Flash
FLASH->CR |= FLASH_CR_OPTLOCK; // Lock Option Bytes
return (0);
}
#endif
/*
* Erase complete Flash Memory
* Return Value: 0 - OK, 1 - Failed
*/
#ifdef FLASH_MEM
int EraseChip(void)
{
FLASH->SR |= FLASH_SR_EOP; // Reset FLASH_EOP
FLASH->CR |= FLASH_CR_MER; // Mass Erase Enabled
FLASH->CR |= FLASH_CR_EOPIE;
M32(0x08000000) = 0xFF;
__asm("DSB");
while (FLASH->SR & FLASH_SR_BSY)
{
IWDG->KR = 0xAAAA; // Reload IWDG
}
FLASH->CR &= ~FLASH_CR_MER; // Mass Erase Disabled
FLASH->CR &= ~FLASH_CR_EOPIE; // Reset FLASH_EOPIE
if (FLASH_SR_EOP != (FLASH->SR & FLASH_SR_EOP)) // Check for FLASH_SR_EOP
{
FLASH->SR |= FLASH_SR_EOP;
return (1); // Failed
}
return (0); // Done
}
#endif
#ifdef FLASH_OPT
int EraseChip(void)
{
/* erase chip is not needed for
- Flash Option bytes
- Flash One Time Programmable bytes
*/
return (0); // Done
}
#endif
/*
* Erase Sector in Flash Memory
* Parameter: adr: Sector Address
* Return Value: 0 - OK, 1 - Failed
*/
#ifdef FLASH_MEM
int EraseSector(unsigned long adr)
{
FLASH->SR |= FLASH_SR_EOP; // Reset FLASH_EOP
FLASH->CR |= FLASH_CR_SER; // Sector Erase Enabled
FLASH->CR |= FLASH_CR_EOPIE;
M32(adr) = 0xFF; // Sector Address
__asm("DSB");
while (FLASH->SR & FLASH_SR_BSY)
{
IWDG->KR = 0xAAAA; // Reload IWDG
}
FLASH->CR &= ~FLASH_CR_SER; // Sector Erase Disabled
FLASH->CR &= ~FLASH_CR_EOPIE; // Reset FLASH_EOPIE
// if (FLASH_EOP != (FLASH->SR & FLASH_EOP)) { // Check for FLASH_SR_EOP
// FLASH->SR |= FLASH_EOP;
// return (1); // Failed
// }
return (0); // Done
}
#endif
#ifdef FLASH_OPT
int EraseSector(unsigned long adr)
{
/* erase sector is not needed for
- Flash Option bytes
- Flash One Time Programmable bytes
*/
return (0); // Done
}
#endif
/*
* Blank Check Checks if Memory is Blank
* Parameter: adr: Block Start Address
* sz: Block Size (in bytes)
* pat: Block Pattern
* Return Value: 0 - OK, 1 - Failed
*/
int BlankCheck(unsigned long adr, unsigned long sz, unsigned char pat)
{
return (1); // Always Force Erase
}
/*
* Program Page in Flash Memory
* Parameter: adr: Page Start Address
* sz: Page Size
* buf: Page Data
* Return Value: 0 - OK, 1 - Failed
*/
#ifdef FLASH_MEM
int ProgramPage(unsigned long adr, unsigned long sz, unsigned char *buf)
{
sz = (sz + 127) & ~127; // Adjust size for 32 Words
FLASH->SR |= FLASH_SR_EOP; // Reset FLASH_EOP
while (sz)
{
FLASH->CR |= FLASH_CR_PG; // Programming Enabled
FLASH->CR |= FLASH_CR_EOPIE;
for (u8 i = 0; i < 32; i++)
{
M32(adr + i * 4) = *((u32 *)(buf + i * 4)); // Program the first word of the Double Word
if (i == 30)
{
FLASH->CR |= FLASH_CR_PGSTRT;
}
}
__asm("DSB");
while (FLASH->SR & FLASH_SR_BSY)
{
IWDG->KR = 0xAAAA; // Reload IWDG
}
FLASH->CR &= ~FLASH_CR_PG; // Programming Disabled
FLASH->CR &= ~FLASH_CR_EOPIE; // Reset FLASH_EOPIE
// if (FLASH_EOP != (FLASH->SR & FLASH_EOP)) { // Check for FLASH_SR_EOP
// FLASH->SR |= FLASH_EOP;
// return (1); // Failed
// }
adr += 128; // Go to next Page
buf += 128;
sz -= 128;
}
return (0); // Done
}
#endif // FLASH_MEM
#ifdef FLASH_OPT
int ProgramPage(unsigned long adr, unsigned long sz, unsigned char *buf)
{
u32 optr;
u32 sdkr;
u32 wrpr;
optr = *((u32 *)(buf + 0x00));
sdkr = *((u32 *)(buf + 0x04));
wrpr = *((u32 *)(buf + 0x0C));
FLASH->SR |= FLASH_SR_EOP; // Reset FLASH_EOP
FLASH->OPTR = (optr & 0x0000FFFF); // Write OPTR values
FLASH->SDKR = (sdkr & 0x0000FFFF); // Write SDKR values
FLASH->WRPR = (wrpr & 0x0000FFFF); // Write WRPR values
FLASH->CR |= FLASH_CR_OPTSTRT;
FLASH->CR |= FLASH_CR_EOPIE;
M32(0x40022080) = 0xFF;
__asm("DSB");
FLASH->CR &= ~FLASH_CR_OPTSTRT; // Programming Disabled
FLASH->CR &= ~FLASH_CR_EOPIE; // Reset FLASH_EOPIE
//FLASH->CR |= FLASH_CR_OBL_LAUNCH;
return (0); // Done
}
#endif // FLASH_OPT
/*
* Verify Flash Contents
* Parameter: adr: Start Address
* sz: Size (in bytes)
* buf: Data
* Return Value: (adr+sz) - OK, Failed Address
*/
#ifdef FLASH_OPT
unsigned long Verify(unsigned long adr, unsigned long sz, unsigned char *buf)
{
u32 optr;
u32 sdkr;
u32 wrpr;
optr = *((u32 *)(buf + 0x00));
sdkr = *((u32 *)(buf + 0x04));
wrpr = *((u32 *)(buf + 0x0C));
if (M32(adr + 0x00) != optr)
{
return (adr + 0x00);
}
if (M32(adr + 0x04) != sdkr)
{
return (adr + 0x04);
}
if (M32(adr + 0x0C) != wrpr)
{
return (adr + 0x0C);
}
return (adr + sz);
}
#endif // FLASH_OPT
#define RCC_CR_HSIRDY_Pos (10U)
#define RCC_CR_HSIRDY_Msk (0x1UL << RCC_CR_HSIRDY_Pos) /*!< 0x00000400 */
#define RCC_CR_HSIRDY RCC_CR_HSIRDY_Msk /*!< Internal High Speed clock ready flag */
#define RCC_ICSCR_HSI_TRIM_Pos (0U)
#define RCC_ICSCR_HSI_TRIM_Msk (0x1FFFUL << RCC_ICSCR_HSI_TRIM_Pos) /*!< 0x00001FFF */
#define RCC_ICSCR_HSI_TRIM RCC_ICSCR_HSI_TRIM_Msk /*!< HSITRIM[14:8] bits */
#define RCC_ICSCR_HSI_FS_Pos (13U)
#define RCC_ICSCR_HSI_FS_Msk (0x7UL << RCC_ICSCR_HSI_FS_Pos) /*!< 0x0000E000 */
#define RCC_ICSCR_HSI_FS RCC_ICSCR_HSI_FS_Msk /*!< HSIFS[15:13] bits */
#define RCC_ICSCR_HSI_FS_0 (0x01UL << RCC_ICSCR_HSI_FS_Pos) /*!< 0x00002000 */
#define RCC_ICSCR_HSI_FS_1 (0x02UL << RCC_ICSCR_HSI_FS_Pos) /*!< 0x00004000 */
#define RCC_ICSCR_HSI_FS_2 (0x04UL << RCC_ICSCR_HSI_FS_Pos) /*!< 0x00008000 */
void InitRccAndFlashParam(void)
{
RCC_ICSCR_HSI_FS_RESTORE = READ_BIT(RCC->ICSCR, RCC_ICSCR_HSI_FS);
MODIFY_REG(RCC->ICSCR, RCC_ICSCR_HSI_FS, RCC_ICSCR_HSI_FS_2);//HSI_24MHz
MODIFY_REG(RCC->ICSCR, RCC_ICSCR_HSI_TRIM, M32(0x1FFF0F10)&RCC_ICSCR_HSI_TRIM);
while (RCC_CR_HSIRDY != READ_BIT(RCC->CR, RCC_CR_HSIRDY));
FLASH->TS0 = ((M32(0x1FFF0F1C + 4 * 0x14) >> 0) & 0x000000FF);
FLASH->TS3 = ((M32(0x1FFF0F1C + 4 * 0x14) >> 8) & 0x000000FF);
FLASH->TS1 = ((M32(0x1FFF0F1C + 4 * 0x14) >> 16) & 0x000001FF);
FLASH->TS2P = ((M32(0x1FFF0F20 + 4 * 0x14) >> 0) & 0x000000FF);
FLASH->TPS3 = ((M32(0x1FFF0F20 + 4 * 0x14) >> 16) & 0x000007FF);
FLASH->PERTPE = ((M32(0x1FFF0F24 + 4 * 0x14) >> 0) & 0x0001FFFF);
FLASH->SMERTPE = ((M32(0x1FFF0F28 + 4 * 0x14) >> 0) & 0x0001FFFF);
FLASH->PRGTPE = ((M32(0x1FFF0F2C + 4 * 0x14) >> 0) & 0x0000FFFF);
FLASH->PRETPE = ((M32(0x1FFF0F2C + 4 * 0x14) >> 16) & 0x0000FFFF);
}
void UnInitRccAndFlashParam(void)
{
MODIFY_REG(RCC->ICSCR, RCC_ICSCR_HSI_FS, RCC_ICSCR_HSI_FS_RESTORE);
switch (RCC_ICSCR_HSI_FS_RESTORE)
{
case RCC_ICSCR_HSI_FS_2://24MHz
MODIFY_REG(RCC->ICSCR, RCC_ICSCR_HSI_TRIM, M32(0x1FFF0F10)&RCC_ICSCR_HSI_TRIM);
break;
case (RCC_ICSCR_HSI_FS_1|RCC_ICSCR_HSI_FS_0)://22.12MHz
MODIFY_REG(RCC->ICSCR, RCC_ICSCR_HSI_TRIM, M32(0x1FFF0F0C)&RCC_ICSCR_HSI_TRIM);
break;
case RCC_ICSCR_HSI_FS_1://16MHz
MODIFY_REG(RCC->ICSCR, RCC_ICSCR_HSI_TRIM, M32(0x1FFF0F08)&RCC_ICSCR_HSI_TRIM);
break;
case RCC_ICSCR_HSI_FS_0://8MHz
MODIFY_REG(RCC->ICSCR, RCC_ICSCR_HSI_TRIM, M32(0x1FFF0F04)&RCC_ICSCR_HSI_TRIM);
break;
default://4MHz
MODIFY_REG(RCC->ICSCR, RCC_ICSCR_HSI_TRIM, M32(0x1FFF0F00)&RCC_ICSCR_HSI_TRIM);
break;
}
while (RCC_CR_HSIRDY != READ_BIT(RCC->CR, RCC_CR_HSIRDY));
}