/**
  ******************************************************************************
  * @file    lcm32f06x_flash.c
  * @author  System R&D Team
  * @version V2.0.2
  * @date    10-April-2025
  * @brief   This file provides all the FLASH firmware functions.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) Hangzhou Lingxin Microelectronics Co.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "lcm32f06x_flash.h"

/**
  * @name   FLASH_SetLatency
  * @brief  EN: Set FLASH read delay.
  *         CN: 设置FLASH 读取延迟。
  * @param  FLASH_Latency: 
  *         EN: Specify the number of read delay cycles.
  *         CN: 指定读取延时周期数。
  *             @arg FLASH_Latency_0
  *             @arg FLASH_Latency_1
  *             @arg FLASH_Latency_2
  *             @arg FLASH_Latency_3
  *             @arg FLASH_Latency_4
  * @retval None
  */
void FLASH_SetLatency(uint32_t FLASH_Latency)
{
  uint32_t tmpreg = 0;

  /* Check the parameters */
  assert_param(IS_FLASH_LATENCY(FLASH_Latency));

  /* Read the ACR register */
  tmpreg = FLASH->ACR;

  /* Sets the Latency value */
  tmpreg &= (uint32_t)(FLASH_ACR_LATENCY_Msk | FLASH_ACR_PRFTBE_Msk);
  tmpreg |= FLASH_Latency;

  /* Write the ACR register */
  FLASH->ACR = tmpreg;
}

/**
  * @name   FLASH_GetPrefetchBufferStatus
  * @brief  EN: Checks whether the FLASH Prefetch Buffer status is set or not.
  *         CN: 检查是否设置了FLASH预取缓冲区状态。
  * @param  None
  * @retval EN: FLASH Prefetch Buffer Status.
  *         CN: FLASH预取缓冲区状态。
  */
FlagStatus FLASH_GetPrefetchBufferStatus(void)
{
  FlagStatus bitstatus = RESET;

  if ((FLASH->ACR & FLASH_ACR_PRFTBS_Msk) != (uint32_t)RESET)
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  /* Return the new state of FLASH Prefetch Buffer Status (SET or RESET) */
  return bitstatus;
}

/**
  * @name   FLASH_PrefetchBufferCmd
  * @brief  EN: Enabling control of prefetching cache.
  *         CN: 预取缓存的使能控制。
  * @param  NewState: 
  *         EN: Pre drive prohibition or enable.
  *         CN: 预取禁止或使能。
  * @retval None
  */
void FLASH_PrefetchBufferCmd(FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_FUNCTIONAL_STATE(NewState));

  if (NewState != DISABLE)
  {
    FLASH->ACR |= FLASH_ACR_PRFTBE_Msk;
  }
  else
  {
    FLASH->ACR &= (uint32_t)(~FLASH_ACR_PRFTBE_Msk);
  }
}

/**
  * @name   FLASH_Unlock
  * @brief  EN: Unlocks the FLASH control register and program memory access.
  *         CN: 解锁FLASH控制寄存器和程序存储器访问。
  * @param  None
  * @retval None
  */
void FLASH_Unlock(void)
{
  if ((FLASH->CR & FLASH_CR_LOCK_Msk) != RESET)
  {
    /* Unlocking the program memory access */
    FLASH->KEYR = FLASH_FKEY1;
    FLASH->KEYR = FLASH_FKEY2;
  }
}

/**
  * @name   FLASH_UnOnlyReadMode
  * @brief  EN: Exit read-only mode.
  *         CN: 退出只读模式。
  * @param  None
  * @retval None
  */
void FLASH_UnOnlyReadMode(void)
{
  FLASH->CR &= ~(FLASH_CR_RDONLY_Msk);
}
/**
  * @name   FLASH_Lock
  * @brief  EN: Locks the Program memory access.
  *         CN: 锁定程序内存访问。
  * @param  None
  * @retval None
  */
void FLASH_Lock(void)
{
  /* Set the LOCK Bit to lock the FLASH control register and program memory access */
  FLASH->CR |= FLASH_CR_LOCK_Msk;
}

/**
  * @name   FLASH_OnlyReadMode
  * @brief  EN: Only read mode enable.
  *         CN: 只读模式使能。
  * @param  None
  * @retval None
  */
void FLASH_OnlyReadMode(void)
{
  FLASH->CR |= FLASH_CR_RDONLY_Msk;
}
/**
  * @name   FLASH_ErasePage
  * @brief  EN: Erases a specified page in program memory.
  *         CN: 擦除程序内存中的指定页面。
  * @note   To correctly run this function, the FLASH_Unlock() and FLASH_UnOnlyReadMode() function must be called before.
  * @note   Call the FLASH_Lock() to disable the flash memory access (recommended
  *         to protect the FLASH memory against possible unwanted operation)
  * @param  Page_Address
  *         EN: The page address in program memory to be erased.
  *         CN: 程序内存中要擦除的页面地址。
  * @note   A Page is erased in the Program memory only if the address to load 
  *         is the start address of a page(512bytes) .
  * @retval FLASH_Status: The returned value can be: 
  *         FLASH_ERROR_PROGRAM, FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
  */
FLASH_Status FLASH_ErasePage(uint32_t Page_Address)
{
  FLASH_Status status = FLASH_COMPLETE;

  /* Check the parameters */
  assert_param(IS_FLASH_PROGRAM_ADDRESS(Page_Address));

  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

  if (status == FLASH_COMPLETE)
  {
    /* If the previous operation is completed, proceed to erase the page */
    FLASH->CR |= FLASH_CR_PER_Msk;
    FLASH->AR = Page_Address;
    FLASH->CR |= FLASH_CR_STRT_Msk;
    while (FLASH->SR_b.EOP == 0)
    {
        status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
        break;
    }
    FLASH->SR_b.EOP = 1;
    /* Disable the PER Bit */
    FLASH->CR &= ~FLASH_CR_PER_Msk;
  }

  /* Return the Erase Status */
  return status;
}

/**
  * @name   FLASH_EraseAllPages
  * @brief  EN: Erases all FLASH pages.
  *         CN: 擦除所有FLASH页面。
  * @note   To correctly run this function, the FLASH_Unlock() and FLASH_UnOnlyReadMode() function must be called before.
  * @note   Call the FLASH_Lock() to disable the flash memory access (recommended
  *         to protect the FLASH memory against possible unwanted operation)
  * @param  None
  * @retval FLASH_Status: The returned value can be: FLASH_ERROR_PG,
  *         FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
  */
FLASH_Status FLASH_EraseAllPages(void)
{
  FLASH_Status status = FLASH_COMPLETE;

  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

  if (status == FLASH_COMPLETE)
  {
    /* if the previous operation is completed, proceed to erase all pages */
    FLASH->CR |= FLASH_CR_MER_Msk;
    FLASH->CR |= FLASH_CR_STRT_Msk;

    /* Wait for last operation to be completed */
    while (FLASH->SR_b.EOP == 0)
    {
        status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
        break;
    }
    FLASH->SR_b.EOP = 1;
    /* Disable the MER Bit */
    FLASH->CR &= ~FLASH_CR_MER_Msk;
  }

  /* Return the Erase Status */
  return status;
}

/**
  * @name   FLASH_ProgramWord
  * @brief  EN: Programs a word at a specified address.
  *         CN: 在指定地址进行字编程。
  * @note   To correctly run this function, the FLASH_Unlock() and FLASH_UnOnlyReadMode() function must be called before.
  * @note   Call the FLASH_Lock() to disable the flash memory access (recommended
  *         to protect the FLASH memory against possible unwanted operation)
  * @param  Address：
  *         EN: specifies the address to be programmed.
  *         CN: 指定要编程的地址。
  * @retval FLASH_Status: The returned value can be: FLASH_ERROR_PG,
  *         FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
  */
FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data)
{
  FLASH_Status status = FLASH_COMPLETE;
  __IO uint32_t tmp = 0;

  /* Check the parameters */
  assert_param(IS_FLASH_PROGRAM_ADDRESS(Address));

  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

  if (status == FLASH_COMPLETE)
  {
    /* If the previous operation is completed, proceed to program the new first 
    half word */
    FLASH->CR |= FLASH_CR_PG_Msk;

    *(__IO uint32_t *)Address = (uint32_t)Data;

    /* Wait for last operation to be completed */
    while (FLASH->SR_b.EOP == 0)
    {
        status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
        break;
    }
    FLASH->SR_b.EOP = 1;
    /* Disable the PG Bit */
    FLASH->CR &= ~FLASH_CR_PG_Msk;
  }

  /* Return the Program Status */
  return status;
}

/**
  * @name   FLASH_ProgramHalfWord
  * @brief  EN: Programs a half word at a specified address.
  *         CN: 在指定地址进行半字编程。
  * @note   To correctly run this function, the FLASH_Unlock() and FLASH_UnOnlyReadMode() function must be called before.
  * @note   Call the FLASH_Lock() to disable the flash memory access (recommended
  *         to protect the FLASH memory against possible unwanted operation)
  * @param  Address：
  *         EN: specifies the address to be programmed.
  *         CN: 指定要编程的地址。
  * @retval FLASH_Status: The returned value can be: FLASH_ERROR_PG,
  *         FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
  */
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{
  FLASH_Status status = FLASH_COMPLETE;

  /* Check the parameters */
  assert_param(IS_FLASH_PROGRAM_ADDRESS(Address));

  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

  if (status == FLASH_COMPLETE)
  {
    /* If the previous operation is completed, proceed to program the new data */
    FLASH->CR |= FLASH_CR_PG_Msk;

    *(__IO uint16_t *)Address = Data;

    /* Wait for last operation to be completed */
    while (FLASH->SR_b.EOP == 0)
    {
        status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
        break;
    }
    FLASH->SR_b.EOP = 1;
    /* Disable the PG Bit */
    FLASH->CR &= ~FLASH_CR_PG_Msk;
  }

  /* Return the Program Status */
  return status;
}

/**
  * @name   FLASH_OB_Unlock
  * @brief  EN: Unlocks the option bytes block access.
  *         CN: 解锁选项字节区访问。
  * @param  None
  * @retval None
  */
void FLASH_OB_Unlock(void)
{
  if ((FLASH->CR & FLASH_CR_OPTWRE_Msk) == RESET)
  {
    /* Unlocking the option bytes block access */
    FLASH->OPTKEYR = FLASH_OPTKEY1;
    FLASH->OPTKEYR = FLASH_OPTKEY2;
    FLASH->CR &= ~(FLASH_CR_RDONLY_Msk);
  }
}

/**
  * @name   FLASH_OB_Lock
  * @brief  EN: Locks the option bytes block access.
  *         CN: 上锁选项字节区访问。
  * @param  None
  * @retval None
  */
void FLASH_OB_Lock(void)
{
  /* Set the OPTWREN Bit to lock the option bytes block access */
  FLASH->CR &= ~FLASH_CR_OPTWRE_Msk;
  FLASH->CR |= FLASH_CR_RDONLY_Msk;
}

/** 
  * @name   FLASH_DM_ErasePage
  * @brief  EN: Half page erase FALSH user data area
  *         CN: 半页擦除 FALSH 用户数据区
  * @param  Page_Address
  *         EN: Address to be erased
  *         CN: 要擦除的地址
  * @retval FLASH_Status
  *         EN: Erase Status
  *         CN: 擦除状态
*/
FLASH_Status FLASH_DM_ErasePage(uint32_t Page_Address)
{
    FLASH_Status status = FLASH_COMPLETE;

    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

    if(status == FLASH_COMPLETE)
    {
      
      FLASH->CR |= FLASH_CR_OPTER_Msk;
      FLASH->AR = ((uint32_t)(Page_Address));
      FLASH->CR |= FLASH_CR_STRT_Msk;

      /* Wait for last operation to be completed */
      while (FLASH->SR_b.EOP == 0)
      {
          status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
          break;
      }
      FLASH->SR_b.EOP = 1;
      /* Disable the OPTER Bit */
      FLASH->CR &= ~FLASH_CR_OPTER_Msk;
    }
    return status;
    
}

/** 
  * @name   FLASH_DM_ProgramWord
  * @brief  EN: Word write user data
  *         CN: 字写入用户数据
  * @param  Address
  *         EN: Write address
  *         CN: 写入地址
  * @param  Data
  *         EN: Write data
  *         CN: 写入数据
  * @retval FLASH_Status
  *         EN: Write successful status
  *         CN: 写入成功状态
*/
FLASH_Status FLASH_DM_ProgramWord(uint32_t Address, uint32_t Data)
{
  FLASH_Status status = FLASH_COMPLETE;

  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

  if (status == FLASH_COMPLETE)
  {
    /* If the previous operation is completed, proceed to program the new data */
    FLASH->CR |= FLASH_CR_OPTPG_Msk;

    *(__IO uint32_t *)Address = Data;

    /* Wait for last operation to be completed */
    while (FLASH->SR_b.EOP == 0)
    {
        status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
        break;
    }
    FLASH->SR_b.EOP = 1;
    /* Disable the PG Bit */
    FLASH->CR &= ~FLASH_CR_OPTPG_Msk;
  }

  /* Return the Program Status */
  return status;
}

/** 
  * @name   FLASH_DM_ProgramHalfWord
  * @brief  EN: Half word write user data
  *         CN: 半字写入用户数据
  * @param  Address
  *         EN: Write address
  *         CN: 写入地址
  * @param  Data
  *         EN: Write data
  *         CN: 写入数据
  * @retval FLASH_Status
  *         EN: Write successful status
  *         CN: 写入成功状态
*/
FLASH_Status FLASH_DM_ProgramHalfWord(uint32_t Address, uint16_t Data)
{
  FLASH_Status status = FLASH_COMPLETE;

  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

  if (status == FLASH_COMPLETE)
  {
    /* If the previous operation is completed, proceed to program the new data */
    FLASH->CR |= FLASH_CR_OPTPG_Msk;

    *(__IO uint16_t *)Address = Data;

    /* Wait for last operation to be completed */
    while (FLASH->SR_b.EOP == 0)
    {
        status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
        break;
    }
    FLASH->SR_b.EOP = 1;
    /* Disable the PG Bit */
    FLASH->CR &= ~FLASH_CR_OPTPG_Msk;
  }

  /* Return the Program Status */
  return status;
}

/**
  * @name   FLASH_OB_Erase
  * @brief  EN: Erases the FLASH option bytes.
  *         CN: 擦除FLASH选项字节。
  * @note   To correctly run this function, the FLASH_OB_Unlock() function must be called before.
  * @note   Call the FLASH_OB_Lock() to disable the flash control register access and the option
  *         bytes (recommended to protect the FLASH memory against possible unwanted operation)
  * @param  None
  * @retval FLASH_Status: The returned value can be: FLASH_ERROR_PG,
  *         FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
  */
FLASH_Status FLASH_OB_Erase(void)
{
  uint16_t rdptmp = 0;
  uint16_t rdptmp2 = 0;
  uint16_t counter = 0;
  FLASH_Status status = FLASH_COMPLETE;
  FLASH->AR = ((uint32_t)(OB_BASE));
  /* Get the actual read protection Option Byte value */
  /*if(FLASH_OB_GetRDP() != RESET)//读取保护等级，如果保护等级不是0，则预取置为L1
  {*/
  rdptmp = 0x00;
  for (counter = 0; counter < 4; counter++)
  {
    if (OB->RDP2[counter] != 0x33CC)
    {
      rdptmp2 = 1;
      break;
    }
  }
  if (rdptmp2)
  {
    for (counter = 0; counter < 8; counter++)
    {
      if (OB->RDP[counter] != 0x55AA)
        rdptmp |= (1 << counter);
    }
    rdptmp = rdptmp;
  }

  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

  if (status == FLASH_COMPLETE)
  {
    /* If the previous operation is completed, proceed to erase the option bytes */
    FLASH->CR |= FLASH_CR_OPTER_Msk;
    FLASH->CR |= FLASH_CR_STRT_Msk;

    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

    if (status == FLASH_COMPLETE)
    {
      /* If the erase operation is completed, disable the OPTER Bit */
      FLASH->CR &= ~FLASH_CR_OPTER_Msk;

      /* Enable the Option Bytes Programming operation */
      FLASH->CR |= FLASH_CR_OPTPG_Msk;

      /* Restore the last read protection Option Byte value */
      if (rdptmp2 == 0)
      {
        OB->RDP2[0] = 0xcc;
        OB->RDP2[1] = 0xcc;
        OB->RDP2[2] = 0xcc;
        OB->RDP2[3] = 0xcc;
      }
      else
      {
        for (counter = 0; counter < 8; counter++)
        {
          if (rdptmp >> counter)
          {
            OB->RDP[counter] = 0xBB;
          }
          else
          {
            OB->RDP[counter] = 0xAA;
          }
        }
      }

      /* Wait for last operation to be completed */
      status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

      if (status != FLASH_TIMEOUT)
      {
        /* if the program operation is completed, disable the OPTPG Bit */
        FLASH->CR &= ~FLASH_CR_OPTPG_Msk;
      }
    }
    else
    {
      if (status != FLASH_TIMEOUT)
      {
        /* Disable the OPTPG Bit */
        FLASH->CR &= ~FLASH_CR_OPTPG_Msk;
      }
    }
  }
  /* Return the erase status */
  return status;
}


FLASH_Status FLASH_OB_EnableWRP(uint32_t OB_WRP)
{
  uint16_t WRP0_Data = 0xFFFF, WRP1_Data = 0xFFFF;
  uint16_t WRP2_Data = 0xFFFF, WRP3_Data = 0xFFFF;

  FLASH_Status status = FLASH_COMPLETE;

  /* Check the parameters */
  assert_param(IS_OB_WRP(OB_WRP));

  OB_WRP = (uint32_t)(~OB_WRP);
  WRP0_Data = (uint16_t)(OB_WRP & OB_WRP0_WRP0);
  WRP1_Data = (uint16_t)((OB_WRP & OB_WRP0_nWRP0) >> 8);
  OB_WRP = OB_WRP >> 16;
  WRP2_Data = (uint16_t)(OB_WRP & OB_WRP0_WRP0);
  WRP3_Data = (uint16_t)((OB_WRP & OB_WRP0_nWRP0) >> 8);
  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

  if (status == FLASH_COMPLETE)
  {
    FLASH->CR |= FLASH_CR_OPTPG_Msk;

    if (WRP0_Data != 0xFF)
    {
      OB->WRP[0] = WRP0_Data;

      /* Wait for last operation to be completed */
      status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
    }
    if ((status == FLASH_COMPLETE) && (WRP1_Data != 0xFF))
    {
      OB->WRP[1] = WRP1_Data;

      /* Wait for last operation to be completed */
      status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
    }

    if ((status == FLASH_COMPLETE) && (WRP2_Data != 0xFF))
    {
      OB->WRP[2] = WRP2_Data;

      /* Wait for last operation to be completed */
      status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
    }

    if ((status == FLASH_COMPLETE) && (WRP1_Data != 0xFF))
    {
      OB->WRP[3] = WRP3_Data;

      /* Wait for last operation to be completed */
      status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
    }

    if (status != FLASH_TIMEOUT)
    {
      /* if the program operation is completed, disable the OPTPG Bit */
      FLASH->CR &= ~FLASH_CR_OPTPG_Msk;
    }
  }
  /* Return the write protection operation Status */
  return status;
}

/**
  * @name   FLASH_OB_RDPConfig
  * @brief  EN: Enables or disables the read out protection.
  *         CN: 启用或禁用读取保护。
  * @note   To correctly run this function, the FLASH_OB_Unlock() function must be called before.
  * @note   Call the FLASH_OB_Lock() to disable the flash control register access and the option
  *         bytes (recommended to protect the FLASH memory against possible unwanted operation)
  * @param  OB_RDP:
  *         EN: specifies the read protection level. 
  *         CN: 指定读取保护级别。
  *             @arg OB_RDP_Level_0: No protection
  *             @arg OB_RDP_Level_1: Read protection of the memory
  * @retval FLASH Status: The returned value can be: 
  *         FLASH_ERROR_PROGRAM, FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
  */
FLASH_Status FLASH_OB_RDPConfig(uint8_t OB_RDP)
{
  FLASH_Status status = FLASH_COMPLETE;
  uint16_t Rsb_counter;
  /* Check the parameters */
  status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
  FLASH->AR = ((uint32_t)(OB_BASE));
  if (status == FLASH_COMPLETE)
  {
    FLASH->CR |= FLASH_CR_OPTER_Msk;
    FLASH->CR |= FLASH_CR_STRT_Msk;

    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

    if (status == FLASH_COMPLETE)
    {
      /* If the erase operation is completed, disable the OPTER Bit */
      FLASH->CR &= ~FLASH_CR_OPTER_Msk;

      /* Enable the Option Bytes Programming operation */
      FLASH->CR |= FLASH_CR_OPTPG_Msk;
      for (Rsb_counter = 0; Rsb_counter < 8; Rsb_counter++)
      {
        if (status == FLASH_COMPLETE)
        {
          if ((OB_RDP >> Rsb_counter) & 0x01)
          {
            OB->RDP[Rsb_counter] = (uint16_t)(0x33BB);
          }
          else
          {
            OB->RDP[Rsb_counter] = (uint16_t)(0x55AA);
          }
        }
        status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
      }
      /* Wait for last operation to be completed */
      status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

      if (status != FLASH_TIMEOUT)
      {
        /* if the program operation is completed, disable the OPTPG Bit */
        FLASH->CR &= ~FLASH_CR_OPTPG_Msk;
      }
    }
    else
    {
      if (status != FLASH_TIMEOUT)
      {
        /* Disable the OPTER Bit */
        FLASH->CR &= ~FLASH_CR_OPTPG_Msk;
      }
    }
  }
  /* Return the protection operation Status */
  return status;
}

/**
  * @name   FLASH_OB_USERConfig
  * @brief  EN: Programs the FLASH User Option Byte: IWDG_SW / RST_STOP / RST_STDBY.
  *         CN: 对FLASH用户选项字节进行编程：IWDG_SW/RST_STOP/RST_STDBY。
  * @note   To correctly run this function, the FLASH_OB_Unlock() function must be called before.
  * @note   Call the FLASH_OB_Lock() to disable the flash control register access and the option
  *         bytes (recommended to protect the FLASH memory against possible unwanted operation)
  * @param  IWDG_SEL:
  *         EN: IWDG sel. 
  *         CN: IWDG 设置。
  *             @arg OB_IWDG_HARD
  *             @arg OB_IWDG_SOFT
  * @param  OB_BOOT_SEL:
  *         EN: BOOT sel. 
  *         CN: BOOT 设置。
  *             @arg OB_BOOT0_HARD
  *             @arg OB_BOOT0_SOFT
  * @param  OB_BOOT1:
  *         EN: BOOT1 sel. 
  *         CN: BOOT1 设置。
  *             @arg OB_BOOT1_L
  *             @arg OB_BOOT1_H
  * @param  OB_BOOT0:
  *         EN: BOOT0 sel. 
  *         CN: BOOT0 设置。
  *             @arg OB_BOOT0_L
  *             @arg OB_BOOT0_H
  * @retval FLASH Status: The returned value can be: 
  *         FLASH_ERROR_PROGRAM, FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
  */
FLASH_Status FLASH_OB_USERConfig(uint8_t IWDG_SEL, uint8_t OB_BOOT_SEL, uint8_t OB_BOOT1, uint8_t OB_BOOT0)
{
  FLASH_Status status = FLASH_COMPLETE;
  uint16_t usertmp;

  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

  if (status == FLASH_COMPLETE)
  {
    /* Enable the Option Bytes Programming operation */
    FLASH->CR |= FLASH_CR_OPTPG_Msk;

    usertmp = (uint16_t)(IWDG_SEL & OB_BOOT_SEL & OB_BOOT1 & OB_BOOT0);
    OB->USER = usertmp;
    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

    if (status != FLASH_TIMEOUT)
    {
      /* If the program operation is completed, disable the OPTPG Bit */
      FLASH->CR &= ~FLASH_CR_OPTPG_Msk;
    }
  }
  /* Return the Option Byte program Status */
  return status;
}

/**
  * @name   FLASH_OB_ProgramData
  * @brief  EN: Programs the FLASH User Option Byte.
  *         CN: 对FLASH用户选项字节进行编程。
  * @note   To correctly run this function, the FLASH_OB_Unlock() function must be called before.
  * @note   Call the FLASH_OB_Lock() to disable the flash control register access and the option
  *         bytes (recommended to protect the FLASH memory against possible unwanted operation)
  * @param  DATAx:
  *         EN: Write data address. 
  *         CN: 写入数据地址。
  *             @arg OB_USER_DATA0
  *             @arg OB_USER_DATA1
  *             @arg OB_USER_DATA2
  * @param  OB_DATA:
  *         EN: Programming data.
  *         CN: 编程数据。
  * @retval FLASH Status: The returned value can be: 
  *         FLASH_ERROR_PROGRAM, FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
  */
FLASH_Status FLASH_OB_ProgramData(uint8_t DATAx, uint8_t OB_DATA)
{
  FLASH_Status status = FLASH_COMPLETE;
  assert_param(IS_OB_USER_DATA(DATAx));

  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

  if (status == FLASH_COMPLETE)
  {
    /* Enable the Option Bytes Programming operation */
    FLASH->CR |= FLASH_CR_OPTPG_Msk;

    OB->DATA[DATAx] = ((uint16_t)OB_DATA);

    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);

    if (status != FLASH_TIMEOUT)
    {
      /* If the program operation is completed, disable the OPTPG Bit */
      FLASH->CR &= ~FLASH_CR_OPTPG_Msk;
    }
  }
  /* Return the Option Byte program Status */
  return status;
}

/**
  * @name   FLASH_ITConfig
  * @brief  EN: Enables or disables the specified FLASH interrupts.
  *         CN: 启用或禁用指定的FLASH中断。
  * @param  FLASH_IT:
  *         EN: specifies the FLASH interrupt sources to be enabled or  disabled.
  *         CN: 指定要启用或禁用的FLASH中断源。
  *             @arg FLASH_IT_EOPIE
  *             @arg FLASH_IT_ERRIE
  *             @arg FLASH_IT_OPTWRE
  * @retval None 
  */
void FLASH_ITConfig(uint32_t FLASH_IT, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_FLASH_IT(FLASH_IT));
  assert_param(IS_FUNCTIONAL_STATE(NewState));

  if (NewState != DISABLE)
  {
    /* Enable the interrupt sources */
    FLASH->CR |= FLASH_IT;
  }
  else
  {
    /* Disable the interrupt sources */
    FLASH->CR &= ~(uint32_t)FLASH_IT;
  }
}

/**
  * @name   FLASH_GetFlagStatus
  * @brief  EN: Checks whether the specified FLASH flag is set or not.
  *         CN: 检查是否设置了指定的FLASH标志。
  * @param  FLASH_IT:
  *         EN: specifies the FLASH flag to check.
  *         CN: 指定要检查的FLASH标志。
  *             @arg FLASH_FLAG_BSY
  *             @arg FLASH_FLAG_PGERR
  *             @arg FLASH_FLAG_WRPERR
  *             @arg FLASH_FLAG_EOP
  * @retval EN: The new state of FLASH_FLAG (SET or RESET).
  *         CN: FLASH_FLAG的新状态（SET或RESET）。
  */
FlagStatus FLASH_GetFlagStatus(uint32_t FLASH_FLAG)
{
  FlagStatus bitstatus = RESET;

  /* Check the parameters */
  assert_param(IS_FLASH_GET_FLAG(FLASH_FLAG));

  if ((FLASH->SR & FLASH_FLAG) != (uint32_t)RESET)
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  /* Return the new state of FLASH_FLAG (SET or RESET) */
  return bitstatus;
}

/**
  * @name   FLASH_OB_GetUser
  * @brief  EN: Returns the FLASH User Option Bytes values.
  *         CN: 返回FLASH用户选项字节值。
  * @param  None
  * @retval EN:The FLASH User Option Bytes .
  *         CN:FLASH用户选项字节数。
  */
uint8_t FLASH_OB_GetUser(void)
{
  /* Return the User Option Byte */
  return (uint8_t)(FLASH->OBR >> 8);
}

/**
  * @name   FLASH_OB_GetWRP
  * @brief  EN: Returns the FLASH Write Protection Option Bytes value.
  *         CN: 返回FLASH写入保护选项字节值。
  * @param  None
  * @retval EN:The FLASH Write Protection Option Bytes value.
  *         CN:FLASH写入保护选项字节值。
  */
uint32_t FLASH_OB_GetWRP(void)
{
  /* Return the FLASH write protection Register value */
  return (uint32_t)(FLASH->WRPR);
}

/**
  * @name   FLASH_WaitForLastOperation
  * @brief  EN: FLASH wait for last operation.
  *         CN: FLASH等待最后一次操作。
  * @param  Timeout
  *         EN:Time out.
  *         CN:超时时间。
  * @retval FLASH_Status
  */
FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout)
{
  FLASH_Status status = FLASH_COMPLETE;

  /* Check for the FLASH Status */
  status = FLASH_GetStatus();

  /* Wait for a FLASH operation to complete or a TIMEOUT to occur */
  while ((status == FLASH_BUSY) && (Timeout != 0x00))
  {
    status = FLASH_GetStatus();
    Timeout--;
  }

  if (Timeout == 0x00)
  {
    status = FLASH_TIMEOUT;
  }
  /* Return the operation status */
  return status;
}

/**
  * @name   FLASH_GetStatus
  * @brief  EN: Get FLASH status.
  *         CN: 获取FLASH状态。
  * @param  None
  * @retval FLASH_Status
  */
FLASH_Status FLASH_GetStatus(void)
{
  FLASH_Status FLASHstatus = FLASH_COMPLETE;

  if ((FLASH->SR & FLASH_FLAG_BSY) == FLASH_FLAG_BSY)
  {
    FLASHstatus = FLASH_BUSY;
  }
  else
  {
    if ((FLASH->SR & (uint32_t)FLASH_FLAG_WRPERR) != (uint32_t)0x00)
    {
      FLASHstatus = FLASH_ERROR_WRP;
    }
    else
    {
      if ((FLASH->SR & (uint32_t)(FLASH_SR_PGERR_Msk)) != (uint32_t)0x00)
      {
        FLASHstatus = FLASH_ERROR_PROGRAM;
      }
      else
      {
        FLASHstatus = FLASH_COMPLETE;
      }
    }
  }
  /* Return the FLASH Status */
  return FLASHstatus;
}

/**
  * @name   FLASH_ClearFlag
  * @brief  EN: Clears the FLASH's pending flags.
  *         CN: 清除FLASH的挂起标志。
  * @param  FLASH_FLAG:
  *         EN: specifies the FLASH flag to clear.
  *         CN: 指定要清除的FLASH标志。
  *             @arg FLASH_FLAG_PGERR
  *             @arg FLASH_FLAG_WRPERR
  *             @arg FLASH_FLAG_EOP
  * @retval FLASH_Status
  */
void FLASH_ClearFlag(uint32_t FLASH_FLAG)
{
  /* Check the parameters */
  assert_param(IS_FLASH_CLEAR_FLAG(FLASH_FLAG));

  /* Clear the flags */
  FLASH->SR = FLASH_FLAG;
}

/**
  * @name   FLASH_ClearFlag
  * @brief  EN: Checks whether the FLASH Read out Protection Status is set or not.
  *         CN: 检查是否设置了FLASH读取保护状态。
  * @param  None:
  * @retval EN:FLASH ReadOut Protection Status(SET or RESET).
  *         CN:FLASH读出保护状态（SET或RESET）。
  */
FlagStatus FLASH_OB_GetRDP(void)
{
  FlagStatus readstatus = RESET;

  if ((uint32_t)(FLASH->RDPR & (RDPRT2 | RDPRT)) != RESET)
  {
    readstatus = SET;
  }
  else
  {
    readstatus = RESET;
  }
  return readstatus;
}

void efls_strt_per(uint32_t sec_num, uint32_t mem_type)
{
  uint32_t tmp;

  tmp = FLASH->CR;

  if (mem_type == 0)     //flash
  {
    FLASH->AR = 0x08000000 + sec_num * (1 << 10);
    tmp &= ~FLASH_CR_OPTER_Msk;
    tmp |= (1 << 1);
  }
  else if (mem_type == 1) //Calibration data
  {
    FLASH->AR = 0x1FFFF700 + sec_num * (1 << 8); // Option Calibrartion Bytes（选项 校准字节） 半页擦除 /
    tmp &= ~(1 << 1);
    tmp |= FLASH_CR_OPTER_Msk;
  }
  else if (mem_type == 2) //data memory
  {
    FLASH->AR = 0x1FFFF000 + sec_num * (1 << 8); // DATA Memory 半页擦除
    tmp &= ~(1 << 1);
    tmp |= FLASH_CR_OPTER_Msk;
  }
  else                    //opt data
  {
    FLASH->AR = 0x1FFFF600 + sec_num * (1 << 8); // Option Calibrartion Bytes（选项 校准字节） 半页擦除 /
    tmp &= ~(1 << 1);
    tmp |= FLASH_CR_OPTER_Msk;
  }
  tmp &= ~FLASH_CR_MER_Msk;
  tmp |= FLASH_CR_STRT_Msk;
  FLASH->CR = tmp;
}

void ERASE_OPT()
{
  FLASH->KEYR = FLASH_FKEY1;
  FLASH->KEYR = FLASH_FKEY2;

  FLASH->OPTKEYR = FLASH_OPTKEY1;
  FLASH->OPTKEYR = FLASH_OPTKEY2;

  FLASH->SMKEYR = FLASH_SMKEYR1;
  FLASH->SMKEYR = FLASH_SMKEYR2;

  FLASH->CR &= 0xefffffff;
  efls_strt_per(0, 3); //ERASE  0x1FFFF600 - 0x1FFFF6FF

}

void ERASE_DATA_MERMORY()
{
  FLASH->KEYR = FLASH_FKEY1;
  FLASH->KEYR = FLASH_FKEY2;

  FLASH->OPTKEYR = FLASH_OPTKEY1;
  FLASH->OPTKEYR = FLASH_OPTKEY2;

  FLASH->SMKEYR = FLASH_SMKEYR1;
  FLASH->SMKEYR = FLASH_SMKEYR2;

  FLASH->CR &= 0xefffffff;
  efls_strt_per(0, 2); //ERASE 半页擦除 0x1FFFF000 - 0x1FFFF0FF
  efls_strt_per(1, 2); //ERASE  0x1FFFF100 - 0x1FFFF1FF
  efls_strt_per(2, 2); //ERASE  0x1FFFF200 - 0x1FFFF2FF
  efls_strt_per(3, 2); //ERASE  0x1FFFF300 - 0x1FFFF3FF
  efls_strt_per(4, 2); //ERASE  0x1FFFF400 - 0x1FFFF4FF
  efls_strt_per(5, 2); //ERASE  0x1FFFF500 - 0x1FFFF5FF

}
void ERASE_Calibration_MERMORY()
{
  FLASH->KEYR = FLASH_FKEY1;
  FLASH->KEYR = FLASH_FKEY2;

  FLASH->OPTKEYR = FLASH_OPTKEY1;
  FLASH->OPTKEYR = FLASH_OPTKEY2;

  FLASH->SMKEYR = FLASH_SMKEYR1;
  FLASH->SMKEYR = FLASH_SMKEYR2;  //ULOCK

  FLASH->CR &= 0xefffffff;        //DIS READONLY
  efls_strt_per(0, 1); //ERASE 半页擦除 0x1FFFF700 - 0x1FFFF7FF

}
void efls_pg(uint32_t addr, uint32_t mem_type, uint32_t data, uint32_t word_flag)
{
  uint32_t base;
  if (mem_type == 0)
    base = 0x08000000; //MAIN FLASH ADR START
  else if (mem_type == 1)
    base = 0x1FFFF600; //OPT ADR START
  else if (mem_type == 2)                //if (mem_type == 2)
    base = 0X1FFFF700; //CALI M START
  else
    base = 0X1FFFF000; //DATAM ADR START

  if (word_flag)
  {
    WR_REG(base + addr, data);
    while(!(FLASH->SR & 0x20))
    {
        __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    };
  }
  else
    WR_REGH(base + addr, data);
}

void write_opt_flash_n(unsigned int addr, unsigned int data)
{
  addr -= 0x1ffff600;
  FLASH->KEYR = FLASH_FKEY1;
  FLASH->KEYR = FLASH_FKEY2;

  FLASH->OPTKEYR = FLASH_OPTKEY1;
  FLASH->OPTKEYR = FLASH_OPTKEY2;

  FLASH->SMKEYR = FLASH_SMKEYR1;
  FLASH->SMKEYR = FLASH_SMKEYR2;

  FLASH->CR &= ~FLASH_CR_PG_Msk;
  FLASH->CR |= FLASH_CR_OPTPG_Msk; //START OPT PG
  
  FLASH->CR &= 0xefffffff;
  efls_pg(addr, 1, data, 1);
}

void write_sm_flash_n(unsigned int addr, unsigned int data)
{
  addr -= 0x1ffff700;
  FLASH->KEYR = FLASH_FKEY1;
  FLASH->KEYR = FLASH_FKEY2;

  FLASH->OPTKEYR = FLASH_OPTKEY1;
  FLASH->OPTKEYR = FLASH_OPTKEY2;

  FLASH->SMKEYR = FLASH_SMKEYR1;
  FLASH->SMKEYR = FLASH_SMKEYR2;

  FLASH->CR &= ~FLASH_CR_OPTER_Msk;
  FLASH->CR &= ~FLASH_CR_PG_Msk;
  FLASH->CR |= FLASH_CR_OPTPG_Msk; //START OPT PG
  FLASH->CR &= 0xefffffff;
  efls_pg(addr, 2, data, 1);
}
void write_DataMemory_n(unsigned int addr, unsigned int data)
{
  addr -= 0x1ffff000;
  FLASH->KEYR = FLASH_FKEY1;
  FLASH->KEYR = FLASH_FKEY2;

  FLASH->OPTKEYR = FLASH_OPTKEY1;
  FLASH->OPTKEYR = FLASH_OPTKEY2;

  FLASH->SMKEYR = FLASH_SMKEYR1;
  FLASH->SMKEYR = FLASH_SMKEYR2;

  FLASH->CR &= ~FLASH_CR_PG_Msk;
  FLASH->CR |= FLASH_CR_OPTPG_Msk; //START OPT PG
  FLASH->CR &= 0xefffffff;
  efls_pg(addr, 3, data, 1);
}
void rcl_trim(uint32_t trim)
{
  chipctrl_access();
  CHIPCTRL->RCL_CFG = (CHIPCTRL->RCL_CFG & ~(0X7F)) |
                      (trim << 0);
  __dekey();
}
void rch_trim(uint32_t trim)
{
  chipctrl_access();
  CHIPCTRL->RCH_CFG = (CHIPCTRL->RCH_CFG & ~(0XFFF)) |
                      (trim << 0);
  __dekey();
}
void bgr_trim(uint32_t trim)
{
  chipctrl_access();
  CHIPCTRL->BGR_CFG = trim;
  __dekey();
}

void lpbgr_trim(uint32_t trim)
{
  chipctrl_access();
  CHIPCTRL->BGR_CFG = (CHIPCTRL->BGR_CFG & ~(0X3F << 16)) |
  (trim << 16);
  __dekey();
}

void adc_trim(uint32_t trim)
{
  ADC->TRIM = trim;
}

void mco_set(uint32_t sel, uint32_t div)
{
  uint32_t sysdata=0;
  sysdata=SYSCTRL->ClkEnR1;
  sysdata&=0xFFFFFF80;
  sysdata|=(sel << 3) | div;
  sysctrl_access();
  SYSCTRL->ClkEnR1 = sysdata;
  __dekey();
}



