示例#1
0
/*******************************************************************************
* 函数名称: FLASH_ErasePage
* 功能描述: 擦除一个FLASH页.
* 输入参数: FLASH_Page:需要擦除的页.
* 输出参数: 无
* 返回参数: FLASH 状态: 返回值可以是: FLASH_BUSY,
*                  FLASH_ERROR_PG, FLASH_ERROR_WRP, FLASH_COMPLETE or 
*                  FLASH_TIMEOUT.
*******************************************************************************/
FLASH_Status FLASH_ErasePage(u32 Page_Address)
{
  FLASH_Status status = FLASH_COMPLETE;

  /* Check the parameters [检查参数]*/
  assert_param(IS_FLASH_ADDRESS(Page_Address));

  /* Wait for last operation to be completed [等待最后一个操作完成]*/
  status = FLASH_WaitForLastOperation(EraseTimeout);
  
  if(status == FLASH_COMPLETE)
  { 
    /* if the previous operation is completed, proceed to erase the page [如果前一个操作已经完成,]*/
    FLASH->CR|= CR_PER_Set;
    FLASH->AR = Page_Address; 
    FLASH->CR|= CR_STRT_Set;
    
    /* Wait for last operation to be completed [等待最后一个操作完成]*/
    status = FLASH_WaitForLastOperation(EraseTimeout);

    if(status != FLASH_BUSY)
    {
      /* if the erase operation is completed, disable the PER Bit [如果擦除操作完成,禁止PER位]*/
      FLASH->CR &= CR_PER_Reset;
    }
  }
  /* Return the Erase Status [返回擦除状态]*/
  return status;
}
示例#2
0
/**
  * @brief  Programs a word at a specified address.
  * @param Address: specifies the address to be programmed.
  * @param Data: specifies the data to be programmed.
  * @retval : FLASH Status: The returned value can be: FLASH_BUSY,
  *   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;
    /* Check the parameters */
    assert_param(IS_FLASH_ADDRESS(Address));
    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(ProgramTimeout);

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

        *(__IO uint16_t*)Address = (uint16_t)Data;
        /* Wait for last operation to be completed */
        status = FLASH_WaitForLastOperation(ProgramTimeout);

        if(status == FLASH_COMPLETE) {
            /* if the previous operation is completed, proceed to program the new second
            half word */
            *(__IO uint16_t*)(Address + 2) = Data >> 16;

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

            if(status != FLASH_BUSY) {
                /* Disable the PG Bit */
                FLASH->CR &= CR_PG_Reset;
            }
        } else {
示例#3
0
/**
  * @brief  Programs a half word (16-bit) at a specified address.
  * @note   This function must be used when the device voltage range is from 2.1V to 3.6V.
  * @param  Address: specifies the address to be programmed.
  *         This parameter can be any address in Program memory zone or in OTP zone.
  * @param  Data: specifies the data to be programmed.
  * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PROGRAM,
  *                       FLASH_ERROR_WRP, FLASH_ERROR_OPERATION or FLASH_COMPLETE.
  */
FLASH_Status FLASH_ProgramHalfWord(uint32 Address, uint16 Data)
{
  FLASH_Status status = FLASH_BAD_ADDRESS;

	if (IS_FLASH_ADDRESS(Address))
	{
		/* Wait for last operation to be completed */
		status = FLASH_WaitForLastOperation(ProgramTimeout);

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

			*(__io uint16*)Address = Data;

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

			if(status != FLASH_TIMEOUT)
			{
			  /* if the program operation is completed, disable the PG Bit */
			  FLASH->CR &= (~FLASH_CR_PG);
			}
		}
	}

  /* Return the Program Status */
  return status;
}
示例#4
0
/**
  * @brief  Erases a specified FLASH page.
  * @param  Page_Address: The page address to be erased.
  * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,
  *   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_ADDRESS(Page_Address));
  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation(EraseTimeout);

  if(status == FLASH_COMPLETE)
  {
    /* if the previous operation is completed, proceed to erase the page */
    FLASH->CR|= CR_PER_Set;
    FLASH->AR = Page_Address;
    FLASH->CR|= CR_STRT_Set;

    /* Wait for last operation to be completed */
#if 0 /* testing erratum bsy - MOD_MTHOMAS_STMLIB */
#ifdef MOD_MTHOMAS_STMLIB
	for (volatile int i=0;i<1000;i++);
#endif
#endif

    status = FLASH_WaitForLastOperation(EraseTimeout);
    if(status != FLASH_TIMEOUT)
    {
      /* if the erase operation is completed, disable the PER Bit */
      FLASH->CR &= CR_PER_Reset;
    }
  }
  /* Return the Erase Status */
  return status;
}
示例#5
0
/**
  * @brief  Erases a specified FLASH page.
  * @param  Page_Address: The page address to be erased.
  * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,
  *   FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
  */
FLASH_Status FLASH_ErasePage(uint32 Page_Address)
{
	FLASH_Status status = FLASH_COMPLETE;
	/* Check the parameters */
	ASSERT(IS_FLASH_ADDRESS(Page_Address));
	/* Wait for last operation to be completed */
	status = FLASH_WaitForLastOperation(EraseTimeout);
  
	if(status == FLASH_COMPLETE)
	{
		/* if the previous operation is completed, proceed to erase the page */
		FLASH_BASE->CR |= FLASH_CR_PER;
		FLASH_BASE->AR = Page_Address;
		FLASH_BASE->CR |= FLASH_CR_STRT;

		/* Wait for last operation to be completed */
		status = FLASH_WaitForLastOperation(EraseTimeout);
		if(status != FLASH_TIMEOUT)
		{
			/* if the erase operation is completed, disable the PER Bit */
			FLASH_BASE->CR &= ~FLASH_CR_PER;
		}
		FLASH_BASE->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR);
	}
	/* Return the Erase Status */
	return status;
}
示例#6
0
/**
  * @brief  Erases a specified FLASH page.
  * @param  Page_Address: The page address to be erased.
  * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,
  *   FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
  */
FLASH_Status FLASH_ErasePage(uint32 Page_Address)
{
	FLASH_Status status = FLASH_COMPLETE;
	/* Check the parameters */
	ASSERT(IS_FLASH_ADDRESS(Page_Address));
	/* Wait for last operation to be completed */
	status = FLASH_WaitForLastOperation(EraseTimeout);
  
	if(status == FLASH_COMPLETE)
	{
		/* if the previous operation is completed, proceed to erase the page */
		__set_bits(FLASH_CR, CR_PER_Set);
		__write(FLASH_AR, Page_Address);
		__set_bits(FLASH_CR, CR_STRT_Set);

		/* Wait for last operation to be completed */
		status = FLASH_WaitForLastOperation(EraseTimeout);
		if(status != FLASH_TIMEOUT)
		{
			/* if the erase operation is completed, disable the PER Bit */
			__clear_bits(FLASH_CR, ~CR_PER_Reset);
		}
		__write(FLASH_SR, (FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR));
	}
	/* Return the Erase Status */
	return status;
}
示例#7
0
/**
  * @brief  Programs a byte (8-bit) at a specified address.
  * @note   This function can be used within all the device supply voltage ranges.               
  * @param  Address: specifies the address to be programmed.
  *         This parameter can be any address in Program memory zone or in OTP zone.  
  * @param  Data: specifies the data to be programmed.
  * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PROGRAM,
  *                       FLASH_ERROR_WRP, FLASH_ERROR_OPERATION or FLASH_COMPLETE.
  */
FLASH_Status FLASH_ProgramByte(uint32_t Address, uint8_t Data)
{
  FLASH_Status status = FLASH_COMPLETE;

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

  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation();
  
  if(status == FLASH_COMPLETE)
  {
    /* if the previous operation is completed, proceed to program the new data */
    FLASH->CR &= CR_PSIZE_MASK;
    FLASH->CR |= FLASH_PSIZE_BYTE;
    FLASH->CR |= FLASH_CR_PG;
  
    *(__IO uint8_t*)Address = Data;
        
    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation();

    /* if the program operation is completed, disable the PG Bit */
    FLASH->CR &= (~FLASH_CR_PG);
  } 

  /* Return the Program Status */
  return status;
}
示例#8
0
/**
  * @brief  Programs a half word at a specified address.
  * @param  Address: specifies the address to be programmed.
  * @param  Data: specifies the data to be programmed.
  * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
  *   FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. 
  */
FLASH_Status FLASH_ProgramHalfWord(uint32 Address, uint16 Data)
{
	FLASH_Status status = FLASH_BAD_ADDRESS;

	if (IS_FLASH_ADDRESS(Address))
	{
		/* Wait for last operation to be completed */
		status = FLASH_WaitForLastOperation(ProgramTimeout);
		if(status == FLASH_COMPLETE)
		{
			/* if the previous operation is completed, proceed to program the new data */
			__set_bits(FLASH_CR, CR_PG_Set);
			*(__io uint16*)Address = Data;
			/* Wait for last operation to be completed */
			status = FLASH_WaitForLastOperation(ProgramTimeout);
			if(status != FLASH_TIMEOUT)
			{
				/* if the program operation is completed, disable the PG Bit */
				__clear_bits(FLASH_CR, ~CR_PG_Reset);
			}
			__write(FLASH_SR, (FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR));
		}
	}
	return status;
}
示例#9
0
/**
  * @brief  Programs one byte in program or data EEPROM memory
  * @param  Address : Address where the byte will be programmed
  * @param  Data : Value to be programmed
  * @retval None
  */
void FLASH_ProgramByte(uint32_t Address, uint8_t Data)
{
  /* Check parameters */
  assert_param(IS_FLASH_ADDRESS(Address));

  *(PointerAttr uint8_t*) (uint16_t)Address = Data;
}
示例#10
0
/**
  * @brief  Erases one byte in the program or data EEPROM memory
  * @param  Address : Address of the byte to erase
  * @retval None
  */
void FLASH_EraseByte(uint32_t Address)
{
  /* Check parameter */
  assert_param(IS_FLASH_ADDRESS(Address));

  *(PointerAttr uint8_t*) (uint16_t)Address = FLASH_CLEAR_BYTE; /* Erase byte */
}
示例#11
0
/*
 * Erases a specified FLASH page.
 * @param Page_Address: The page address to be erased.
 * @retval : FLASH Status: The returned value can be: FLASH_BUSY, 
 *   FLASH_ERROR_PG, 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_ADDRESS(Page_Address));
  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation(EraseTimeout);
  
  if (status == FLASH_COMPLETE) { 
    /* if the previous operation is completed, proceed to erase the page */
    FLASH->CR|= CR_PER_Set;
    FLASH->AR = Page_Address; 
    FLASH->CR|= CR_STRT_Set;
    
    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(EraseTimeout);

    if (status != FLASH_BUSY) {
      /* if the erase operation is completed, disable the PER Bit */
      FLASH->CR &= CR_PER_Reset;
    } /* if (status != FLASH_BUSY) */

  } /* if (status == FLASH_COMPLETE) */

  /* Return the Erase Status */
  return status;
}
示例#12
0
/**
  * @brief  Programs a half word at a specified address.
  * @param  Address: specifies the address to be programmed.
  * @param  Data: specifies the data to be programmed.
  * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
  *   FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. 
  */
FLASH_Status FLASH_ProgramHalfWord(uint32 Address, uint16 Data)
{
	FLASH_Status status = FLASH_BAD_ADDRESS;

	if (IS_FLASH_ADDRESS(Address))
	{
		/* Wait for last operation to be completed */
		status = FLASH_WaitForLastOperation(ProgramTimeout);
		if(status == FLASH_COMPLETE)
		{
			/* if the previous operation is completed, proceed to program the new data */
			FLASH_BASE->CR |= FLASH_CR_PG;
			*(__io uint16*)Address = Data;
			/* Wait for last operation to be completed */
			status = FLASH_WaitForLastOperation(ProgramTimeout);
			if(status != FLASH_TIMEOUT)
			{
				/* if the program operation is completed, disable the PG Bit */
				FLASH_BASE->CR &= ~FLASH_CR_PG;
			}
			FLASH_BASE->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR);
		}
	}
	return status;
}
示例#13
0
/**
  * @brief  Reads one byte from flash memory
  * @param  Address: Address to read
  * @retval Value of the byte
  */
uint8_t FLASH_ReadByte(uint16_t Address)
{
  /* Check parameter */
  assert_param(IS_FLASH_ADDRESS(Address));
  
  /* Read byte */  
  return(*(PointerAttr uint8_t *) (uint16_t)Address);
}
示例#14
0
    void MacBase::onSend(NetEventDescriptor& ned) {

      // must be an ethernet send request

      if(ned.eventType!=NetEventDescriptor::NetEventType::ETHERNET_TRANSMIT_REQUEST)
        return;

      EthernetTransmitRequestEvent& event=static_cast<EthernetTransmitRequestEvent&>(ned);
      EthernetFrameData *efd;

      // we cannot transmit data out of flash memory because the flash banks are
      // not connected to the Ethernet DMA bus on the STM32. More's the pity.

      uint32_t ub=reinterpret_cast<uint32_t>(event.networkBuffer->getUserBuffer());

      if(ub && IS_FLASH_ADDRESS(ub)) {
        delete event.networkBuffer;
        this->setError(ErrorProvider::ERROR_PROVIDER_NET_MAC,E_NO_FLASH_DATA);
        return;
      }

      // the NetBuffer needs to get an ethernet header

      efd=reinterpret_cast<EthernetFrameData *>(event.networkBuffer->moveWritePointerBack(getDatalinkTransmitHeaderSize()));

      efd->eth_destinationAddress=event.macAddress;
      efd->eth_sourceAddress=_params.mac_address;
      efd->eth_etherType=NetUtil::htons(static_cast<uint16_t>(event.etherType));

      uint32_t now=MillisecondTimer::millis();

      while(!sendBuffer(event.networkBuffer)) {

        if(errorProvider.isLastError(ErrorProvider::ERROR_PROVIDER_NET_MAC,E_BUSY)) {

          // DMA still has our TX descriptor. If we're not running in an IRQ context then we
          // can wait to see if it frees up

          if(Nvic::isAnyIrqActive()) {
            delete event.networkBuffer;
            return;
          }

          if(MillisecondTimer::hasTimedOut(now,_params.mac_txWaitMillis)) {
            delete event.networkBuffer;
            return;
          }
        }
        else {
          delete event.networkBuffer;
          return;         // other error
        }
      }

      // it was sent and the net buffer will be deleted when the TX interrupt is processed

      event.succeeded=true;
    }
/**
  * @brief  Program byte (8-bit) at a specified address.
  * @note   This function must be used when the device voltage range is from
  *         1.8V to 3.6V.
  *
  * @note   If an erase and a program operations are requested simultaneously,    
  *         the erase operation is performed before the program one.
  *  
  * @param  Address: specifies the address to be programmed.
  * @param  Data: specifies the data to be programmed.
  * @retval None
  */
static void FLASH_Program_Byte(uint32_t Address, uint8_t Data)
{
  /* Check the parameters */
  assert_param(IS_FLASH_ADDRESS(Address));
  
  /* If the previous operation is completed, proceed to program the new data */
  CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE);
  FLASH->CR |= FLASH_PSIZE_BYTE;
  FLASH->CR |= FLASH_CR_PG;

  *(__IO uint8_t*)Address = Data;
}
示例#16
0
/**
  * @brief  Program a half-word (16-bit) at a specified address.
  * @note   This function must be used when the device voltage range is from
  *         2.7V to 3.6V.
  *
  * @note   If an erase and a program operations are requested simultaneously,    
  *         the erase operation is performed before the program one.
  *  
  * @param  Address: specifies the address to be programmed.
  * @param  Data: specifies the data to be programmed.
  * @retval None
  */
static void FLASH_Program_HalfWord(uint32_t Address, uint16_t Data)
{
  /* Check the parameters */
  assert_param(IS_FLASH_ADDRESS(Address));
  
  /* If the previous operation is completed, proceed to program the new data */
  FLASH->CR &= CR_PSIZE_MASK;
  FLASH->CR |= FLASH_PSIZE_HALF_WORD;
  FLASH->CR |= FLASH_CR_PG;

  *(__IO uint16_t*)Address = Data;
}
示例#17
0
/**
  * @brief  Program a double word (64-bit) at a specified address.
  * @note   This function must be used when the device voltage range is from
  *         2.7V to 3.6V and Vpp in the range 7V to 9V.
  *
  * @note   If an erase and a program operations are requested simultaneously,
  *         the erase operation is performed before the program one.
  *
  * @param  Address specifies the address to be programmed.
  * @param  Data specifies the data to be programmed.
  * @retval None
  */
static void FLASH_Program_DoubleWord(uint32_t Address, uint64_t Data)
{
  /* Check the parameters */
  assert_param(IS_FLASH_ADDRESS(Address));

  /* If the previous operation is completed, proceed to program the new data */
  CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE);
  FLASH->CR |= FLASH_PSIZE_DOUBLE_WORD;
  FLASH->CR |= FLASH_CR_PG;

  /* Program the double-word */
  *(__IO uint32_t*)Address = (uint32_t)Data;
  *(__IO uint32_t*)(Address+4) = (uint32_t)(Data >> 32);
}
/**
  * @brief  Program byte (8-bit) at a specified address.
  * @note   This function must be used when the device voltage range is from
  *         2.7V to 3.6V.
  *
  * @note   If an erase and a program operations are requested simultaneously,    
  *         the erase operation is performed before the program one.
  *  
  * @param  Address: specifies the address to be programmed.
  * @param  Data: specifies the data to be programmed.
  * @retval None
  */
static void FLASH_Program_Byte(uint32_t Address, uint8_t Data)
{
  /* Check the parameters */
  assert_param(IS_FLASH_ADDRESS(Address));
  
  /* If the previous operation is completed, proceed to program the new data */
  FLASH->CR &= CR_PSIZE_MASK;
  FLASH->CR |= FLASH_PSIZE_BYTE;
  FLASH->CR |= FLASH_CR_PG;

  *(__IO uint8_t*)Address = Data;

  /* Data synchronous Barrier (DSB) Just after the write operation
     This will force the CPU to respect the sequence of instruction (no optimization).*/
  __DSB();
}
示例#19
0
/**
  * @brief  Programs one word (4 bytes) in program or data EEPROM memory
  * @param  Address : The address where the data will be programmed
  * @param  Data : Value to be programmed
  * @retval None
  */
void FLASH_ProgramWord(uint32_t Address, uint32_t Data)
{
  /* Check parameters */
  assert_param(IS_FLASH_ADDRESS(Address));
  /* Enable Word Write Once */
  FLASH->CR2 |= FLASH_CR2_WPRG;

  /* Write one byte - from lowest address*/
  *((PointerAttr uint8_t*)(uint16_t)Address)       = *((uint8_t*)(&Data));   
  /* Write one byte*/
  *(((PointerAttr uint8_t*)(uint16_t)Address) + 1) = *((uint8_t*)(&Data) + 1);
  /* Write one byte*/
  *(((PointerAttr uint8_t*)(uint16_t)Address) + 2) = *((uint8_t*)(&Data) + 2); 
  /* Write one byte - from higher address*/
  *(((PointerAttr uint8_t*)(uint16_t)Address) + 3) = *((uint8_t*)(&Data) + 3); 
}
示例#20
0
/**
  * @brief  Program a double word (64-bit) at a specified address.
  * @note   This function must be used when the device voltage range is from
  *         2.7V to 3.6V and an External Vpp is present.
  *
  * @note   If an erase and a program operations are requested simultaneously,
  *         the erase operation is performed before the program one.
  *
  * @param  Address specifies the address to be programmed.
  * @param  Data specifies the data to be programmed.
  * @retval None
  */
static void FLASH_Program_DoubleWord(uint32_t Address, uint64_t Data)
{
  /* Check the parameters */
  assert_param(IS_FLASH_ADDRESS(Address));

  /* If the previous operation is completed, proceed to program the new data */
  FLASH->CR &= CR_PSIZE_MASK;
  FLASH->CR |= FLASH_PSIZE_DOUBLE_WORD;
  FLASH->CR |= FLASH_CR_PG;

  /* Program the double-word */
  *(__IO uint32_t*)Address = (uint32_t)Data;
  *(__IO uint32_t*)(Address+4) = (uint32_t)(Data >> 32);

  /* Data synchronous Barrier (DSB) Just after the write operation
     This will force the CPU to respect the sequence of instruction (no optimization).*/
  __DSB();
}
示例#21
0
/*******************************************************************************
* 函数名称: FLASH_ProgramWord
* 功能描述: 在特定地址编程一个字.
* 输入参数: (1)Address:将要编程的地址.
*           (2)Data:指定被编程的数据.
* 输出参数: 无
* 返回参数: FLASH状态:这个返回值可以是: FLASH_BUSY,
*                  FLASH_ERROR_PG, FLASH_ERROR_WRP, FLASH_COMPLETE or 
*                  FLASH_TIMEOUT. 
*******************************************************************************/
FLASH_Status FLASH_ProgramWord(u32 Address, u32 Data)
{
  FLASH_Status status = FLASH_COMPLETE;

  /* Check the parameters [检查参数]*/
  assert_param(IS_FLASH_ADDRESS(Address));

  /* Wait for last operation to be completed [等待最后一个操作完成]*/
  status = FLASH_WaitForLastOperation(ProgramTimeout);
  
  if(status == FLASH_COMPLETE)
  {
    /* if the previous operation is completed, proceed to program the new first 
    half word [如果前一个操作完成,编程新的第一个半字]*/
    FLASH->CR |= CR_PG_Set;
  
    *(vu16*)Address = (u16)Data;

    /* Wait for last operation to be completed [等待最后一个操作完成]*/
    status = FLASH_WaitForLastOperation(ProgramTimeout);
 
    if(status == FLASH_COMPLETE)
    {
      /* if the previous operation is completed, proceed to program the new second 
      half word [如果前一个操作完成,编程新的第二个半字]*/
      *(vu16*)(Address + 2) = Data >> 16;
    
      /* Wait for last operation to be completed [等待最后一个操作完成]*/
      status = FLASH_WaitForLastOperation(ProgramTimeout);
        
      if(status != FLASH_BUSY)
      {
        /* Disable the PG Bit [禁止PG位]*/
        FLASH->CR &= CR_PG_Reset;
      }
    }