ls1x-master-v0.4/public/ls1x_flash.c

316 lines
8.6 KiB
C
Raw Permalink Normal View History

2024-11-27 15:39:05 +08:00
#include "ls1x.h"
#include "ls1x_flash.h"
#include "ls1x_clock.h"
#include "ls1x_latimer.h"
#include "Config.h"
/**
* @brief Erases a specified FLASH page.
* @param Page_Address: The page address to be erased.
* @retval None
*/
uint8_t Flash_pe;
void FLASH_ErasePage(uint32_t Page_Address) //erase a flash page, FLASH_PAGE_SIZE
{
uint8_t err_code;
//////////////// ///////////////
assert_param(IS_FLASH_ADDRESS(Page_Address));
// FLASH->PET = 0x10; // erase time, 2.5ms
FLASH->CMD = FLASH_ERASE_CMD | (Page_Address & FLASH_ADDR_MASK);
err_code=FLASH_WaitForPeEnd(EraseTimeout);
// FLASH_ClearIT();
}
/**
* @brief Erases all User FLASH pages.
* @param Page_Address: The page address to be erased.
* @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
* FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
*/
void FLASH_EraseUserFlash(uint32_t Page_Address)
{
uint32_t i=0;
Page_Address |= LS1D_FLASH_ADDR;
assert_param(IS_FLASH_ADDRESS(Page_Address));
uint32_t start_addr = Page_Address; //LS1D_FLASH_ADDR片上Flash的起始地址
uint32_t page = (0xbf01ffff - start_addr)/FLASH_PAGE_SIZE; //0xbf01ffff片上Flash的上线计算多少页
for(i=0; i<page; i++)
{
FLASH_ErasePage(start_addr+i*FLASH_PAGE_SIZE);
delay_us(10);
}
}
/**
* @brief Read FLASH data.
* @param Page_Address: The page address to be erased.
* @param *data: The data pointer to the readed data.
* @param num: The number of the readed data.
* @retval The number of the readed data.
*/
uint32_t FLASH_ReadPage(uint32_t Page_Address, uint8_t *data, uint32_t num)
{
int i = 0;
uint8_t *ptr;
if (Page_Address + num > LS1D_FLASH_TOTAL) //LS1D_FLASH_TOTAL:flash大小
return -1;
Page_Address |= LS1D_FLASH_ADDR;
assert_param(IS_FLASH_ADDRESS(Page_Address));
ptr = (uint8_t *)Page_Address;
for(i = 0; i < num; i++)
{
*data++ = *ptr++;
}
return num;
}
/**
* @brief Write words at a specified address.
* @param Page_Address: specifies the address to be programmed.
* @param *data: specifies the data to be programmed.
* @param num: specifies the number of data to be programmed.
* @retval FLASH Status: The returned value can be: verif_correct,
* verif_end, pe_end,FLASH_TIMEOUTor no_permission.
*/
uint8_t FLASH_WitePage(uint32_t Page_Address, uint8_t *data, uint32_t num)
{
uint32_t temp_flash_buf;
uint8_t status;
uint8_t *temp_data = data;
Page_Address |= LS1D_FLASH_ADDR; //addr加上LS1D_FLASH_ADDR0xbf000000基地址
assert_param(IS_FLASH_ADDRESS(Page_Address));
FLASH->CMD = FLASH_PAGE_LATCH_CLEAR; //FLASH_CMD_REG=0x40000000
uint32_t flash_block_mask = FLASH_PAGE_SIZE - 1; //flash_block_mask=1270x0000007F
uint32_t *page_data = (uint32_t *)(Page_Address & ~flash_block_mask) ; //*page_data指针指向addr地址的页地址
uint32_t *old_data = (uint32_t *)(Page_Address & ~flash_block_mask) ; //*old_data指针指向addr地址的页地址
uint32_t i, j, k, offset;
j = 0;
uint32_t count = num;
uint32_t num_left = 0;
uint32_t num_right = 0;
uint32_t addr_left_align = 0xffffffff;
uint32_t addr_right_align = 0xffffffff;
uint32_t word_mask = WORD_WIDTH - 1; //word_mask=3
num = 0;
num_left = Page_Address & word_mask; //addr=124928(0x1E800),word_mask=3(0x00003),addr& word_mask=0
if (num_left) //假如num_left=3
{
num_left = WORD_WIDTH - num_left; //num_left=1
num++; //num=1
addr_left_align = (Page_Address & flash_block_mask) >> 2; //addr_left_align更改为操作地址低8位区0右移2位
}
j = count - num_left; //j=操作起始地址
num_right = (j & word_mask);
if (num_right)
{
num++;
addr_right_align = Page_Address + count - num_right;
addr_right_align = (addr_right_align & flash_block_mask) >> 2;
}
j = count - num_left - num_right;
j = j >> 2;
num += j;
offset = ((Page_Address & flash_block_mask)>>2);
for(j=0, i=0; i<(FLASH_PAGE_SIZE/4); i++)
{
if( (offset <= i) && (j < num) )
{
if (i == addr_left_align)
{
int m = 0;
temp_flash_buf = old_data[i];
k = 1 << ((WORD_WIDTH - num_left) * 8);
temp_flash_buf &= (k - 1);
for (m = 0; m < num_left; m++)
{
temp_flash_buf |= temp_data[m] << (WORD_WIDTH - num_left + m)*8;
}
temp_data = temp_data + num_left; //address change to be logic 0 again.
page_data[i] = temp_flash_buf;
num--; //because j don't add 1, num has to sub 1.
}
else if (i == addr_right_align)
{
temp_flash_buf = old_data[i];
k = 1 << (num_right * 8);
temp_flash_buf &= ~(k - 1);
for (k = 0; k < num_right; k++)
{
temp_flash_buf |= temp_data[j*4+k] << k*8;
}
j++;
page_data[i] = temp_flash_buf;
}
else
{
temp_flash_buf = 0;
for (k = 0; k < WORD_WIDTH; k++)
{
temp_flash_buf |= temp_data[j*4+k] << k*8;
}
j++;
page_data[i] = temp_flash_buf;
}
}
else
page_data[i] = old_data[i];
}
Flash_pe=0;
FLASH_ErasePage(Page_Address); //erase a flash page, FLASH_PAGE_SIZE
FLASH->CMD = FLASH_WRITE_CMD | (Page_Address & FLASH_ADDR_MASK) ;
status=FLASH_WaitForPeEnd(ProgramTimeout);
return status;
}
/**
* @brief Waits for a Flash operation to complete or a TIMEOUT to occur.
* @param Timeout: FLASH programming Timeout
* @retval FLASH Status: The returned value can be: verif_correct,
* verif_end, pe_end,FLASH_TIMEOUTor no_permission.
*/
uint8_t FLASH_WaitForPeEnd(uint32_t Timeout)
{
uint8_t status;
/* Check for the Flash Status */
/* Wait for a Flash operation to complete or a TIMEOUT to occur */
status = FLASH_GetStatus();
while((Timeout != 0x00)&& ((status & 0x04)==0x00))
{
// (status != pe_end) && status = FLASH_GetStatus();
status = FLASH_GetStatus();
delay_ms(1);
Timeout--;
}
if(Timeout == 0x00 )
{
status = FLASH_TIMEOUT;
}
/* Return the operation status */
return status;
}
/**
* @brief Checks whether the specified FLASH flag is set or not.
* @retval The new state of FLASH_FLAG (SET or RESET).
*/
uint8_t FLASH_GetStatus(void)
{
uint8_t status;
status=(FLASH->STS & 0x0F);
return status;
}
/**
* @brief Checks whether the specified FLASH flag is set or not.
* @param FLASH_FLAG: specifies the FLASH flag to check.
* This parameter can be one of the following values:
* @arg FLASH_FLAG_VERIFCORRECT: Verify Correct flag
* @arg FLASH_FLAG_VERIFEND: Verify End flag
* @arg FLASH_FLAG_PEEND: Pe End flag
* @arg FLASH_FLAG_NOPERMISSION: No Permission flag
* @retval The new state of FLASH_FLAG (SET or RESET).
*/
FlagStatus FLASH_GetFlagStatus(uint32_t FLASH_FLAG)
{
ITStatus bitstatus = RESET;
assert_param(IS_FLASH_GET_FLAG(FLASH_FLAG)) ;
if((FLASH->STS & FLASH_FLAG) != (uint32_t)RESET)
{
bitstatus = SET;
}
else
{
bitstatus = RESET;
}
return bitstatus;
}
/**
* @brief Enables or disables the specified FLASH interrupts.
* @param NewState: new state of the specified Flash interrupts.
* This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void FLASH_ITConfig(uint32_t FLASH_IT, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_FLASH_CONFIG_IT(FLASH_IT));
assert_param(IS_FUNCTIONAL_STATE(NewState));
(NewState != DISABLE)? (SET_BIT(FLASH->PET,FLASH_IT)) : (CLEAR_BIT(FLASH->PET,FLASH_IT));
}
/**
* @brief Enables or disables the FLASH interrupts.
* @param NewState: new state of the specified Flash interrupts.
* This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void FLASH_ITCmd(FunctionalState NewState)
{
assert_param(IS_FUNCTIONAL_STATE(NewState));
(NewState != DISABLE)? (SET_BIT(INT->INTC_EN,IRQ_FLASH)) : (CLEAR_BIT(INT->INTC_EN,IRQ_FLASH)); //清除中断标记位
}
/**
* @brief Clears the FLASH's interrupt flag.
* @retval None
*/
void FLASH_ClearIT(void)
{
/* clear data reg*/
SET_BIT(FLASH->CMD , FLASH_INT_CLEAR);
#if !defined (LS1C103)
SET_BIT(INT->INTC_CLR,IRQ_FLASH); //清除中断标记位
#endif
}
/**
*@brief Example of FLASH Write.
*retval None
*/
void FLASH_WiteTest(uint32_t Page_Address,uint8_t Page_data)
{
uint8_t temp[128]={0};
uint32_t USER_BEGIN = Page_Address;
FLASH_Status status;
int i;
for(i=0;i<128;i++)
temp[i] = Page_data;
Flash_pe=0;
status=FLASH_WitePage(USER_BEGIN, temp, FLASH_PAGE_SIZE);
}
/**
*@brief Example of FLASH Read.
*retval None
*/
void FLASH_ReadTest(uint32_t Page_Address)
{
uint8_t temp[128]={0};
uint32_t USER_BEGIN = Page_Address;
int i;
FLASH_ReadPage(USER_BEGIN,temp,FLASH_PAGE_SIZE);
for(i=0;i<128;i++)
{
if(i%9 == 0)
printf("\r\n");
printf("%02x ",temp[i]); //十六进制输出
}
}