Files
stair56e_uart/component/ble/modules/flash/xc6xxx_fmc_spi.c
T
2026-08-05 19:07:52 +08:00

594 lines
16 KiB
C

/*!
* \file xc6xxx_fmc_spi.c
*
* \brief Target xc6xxx hal fmc spi implementation
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
*
* _ __ _ ________ _
* | |/ /(_)___ / ____/ /_ (_)___
* | // / __ \/ / / __ \/ / __ \
* / |/ / / / / /___/ / / / / /_/ /
* /_/|_/_/_/ /_/\____/_/ /_/_/ .___/
* /_/
* (C) 2022-2025 XinChip
*
* \endcode
*
* \author ( XinChip ) Alex-J
*
* \author ( XinChip )
*/
/*-----------------------------------------------------------------------------------
INCLUDE HEADE FILES
------------------------------------------------------------------------------------*/
#include "xc6xxx_fmc_spi.h"
/*------------------------------------------------------------------------------------
Functions
-------------------------------------------------------------------------------------*/
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE void *ram_memcpy_bytes(void *dst, const void *src, int size)
{
if(dst == NULL || src == NULL || size <= 0)
return NULL;
char *pdst = (char *)dst;
char *psrc = (char *)src;
if(pdst > psrc && pdst < psrc + size) {
pdst = pdst + size - 1;
psrc = psrc + size - 1;
while(size--)
*pdst-- = *psrc--;
} else {
while(size--)
*pdst++ = *psrc++;
}
return dst;
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE void FMC_Status_Wait_Idle(void)
{
uint32_t reg = 0;
do {
__READ_REG32(BLE_COMN_AGC_REG_OUT0, reg);
} while(!(reg & FMC_IDLE_Msk));
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE void FMC_SPI_WriteNByte(uint8_t* txdata, uint16_t len)
{
if(len == 0) return;
uint16_t n;
uint8_t remain = len % 4;
uint16_t cnt = len / 4;
uint32_t mid_data[64+1] = { 0 };
if(cnt != 0) {
for(n=0; n<cnt; n++) {
mid_data[n] = ((txdata[n*4] << 24) | (txdata[n*4+1] << 16) |
(txdata[n*4+2] << 8) | txdata[n*4+3]);
}
}
if(remain != 0) {
for(n=0; n<remain; n++) {
mid_data[cnt] |= (txdata[cnt*4+n] << (24-8*n));
}
}
if(cnt != 0) {
if(remain != 0)
cnt = cnt + 1;
for(n=0; n<cnt; n++)
__FMC_SPI_SendByte(mid_data[n]);
} else {
__FMC_SPI_SendByte(mid_data[0]);
}
while(!(*FMC_SSI_STS & FMC_SPI_STS_REG_FLAG_TFE) ||
(*FMC_SSI_STS & FMC_SSI_STS_BUSY));
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE void FMC_SPI_ReadNByte(uint8_t* rxdata, uint16_t len)
{
if(len == 0) return;
uint16_t n;
uint8_t remain = len % 4;
uint16_t cnt = len / 4;
uint32_t mid_data = 0;
if(cnt != 0) {
for(n=0; n<cnt; n++) {
mid_data = __FMC_SPI_RecvByte( );
// printf("0_rcv: 0x%08x\n", mid_data);
rxdata[n*4] = mid_data >> 24;
rxdata[n*4+1] = mid_data >> 16;
rxdata[n*4+2] = mid_data >> 8;
rxdata[n*4+3] = mid_data;
}
}
if(remain != 0) {
mid_data = __FMC_SPI_RecvByte( );
// printf("1_rcv: 0x%08x\n", mid_data);
for(n=0; n<remain; n++) {
rxdata[cnt*4+n] = mid_data >> 24;
rxdata[cnt*4+1+n] = mid_data >> 16;
rxdata[cnt*4+2+n] = mid_data >> 8;
rxdata[cnt*4+3+n] = mid_data;
}
}
while(*FMC_SSI_STS & FMC_SPI_STS_REG_FLAG_RFNE) {
mid_data = __FMC_SPI_RecvByte( );
}
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE void FMC_SPI_Enable(uint8_t dfs)
{
__WRITE_REG32(FMC_SSI_EN, 0);
if(dfs != 0x1f) {
uint32_t reg= *FMC_SSI_CTRL0;
__CLEAR_BIT(reg, (uint32_t)0x1f);
__SET_BIT(reg, (uint32_t)dfs);
__WRITE_REG32(FMC_SSI_CTRL0, reg);
}
__WRITE_REG32(FMC_SSI_EN, 1);
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE void FMC_SPI_Disable(void)
{
__WRITE_REG32(FMC_SSI_EN, 0);
uint32_t reg= *FMC_SSI_CTRL0;
__CLEAR_BIT(reg, (uint32_t)0x1f);
__SET_BIT(reg, (uint32_t)0x1f);
__WRITE_REG32(FMC_SSI_CTRL0, reg);
__WRITE_REG32(FMC_SSI_EN, 1);
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE void FMC_SPI_Init_Oprt(void)
{
/* BT_CLK 时钟控制寄存器 */
__WRITE_REG32(CPR_BT_CLK_CTL, ((1<<4) | ((1<<4)<<16)));
/* BT_MODEM_CLK 时钟控制寄存器 */
__WRITE_REG32(CPR_BT_MODEM_CTL, ((1<<4) | ((1<<4)<<16)));
/* 配置 BT_PCLK_EN 使能 */
__SET_BIT(*CPR_CTLAPBCLKEN_GRCTL, ((1<<10) | ((1<<10)<<16)));
__WRITE_REG32(CPR_SSI0_MCLK_CTL, ((1<<16) | ((0<<4) | ((1<<16)<<4))));
__WRITE_REG32(CPR_RSTCTL_SUBRST_SW, ((0<<2) | ((1<<2)<<16)));
__WRITE_REG32(CPR_RSTCTL_SUBRST_SW, ((1<<2) | ((1<<2)<<16)));
FMC_Status_Wait_Idle( );
__WRITE_REG32(FMC_SSI_EN, 0);
uint32_t reg= *FMC_SSI_CTRL0;
__CLEAR_BIT(reg, (uint32_t)0x1f);
__SET_BIT(reg, (uint32_t)0x1f);
__WRITE_REG32(FMC_SSI_CTRL0, reg);
*FMC_SSI_CTRL0 &= ~((uint32_t)0x01 << 14);
__WRITE_REG32(FMC_SSI_SE, 1);
__WRITE_REG32(FMC_SSI_IE, 0);
__WRITE_REG32(FMC_SSI_BAUD, 2);
__WRITE_REG32(FMC_SSI_TXFTL, 0);
__WRITE_REG32(FMC_SSI_RXFTL, 0);
__WRITE_REG32(FMC_SSI_EN, 1);
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE void FMC_SPI_Flash_PowerDown(void)
{
FMC_Status_Wait_Idle( );
uint8_t cmd[4];
cmd[0] = 0;
cmd[1] = 0;
cmd[2] = 0;
cmd[3] = CMD_PWRDWN;
FMC_SPI_Enable(0x07);
FMC_SPI_WriteNByte(cmd, sizeof(cmd));
FMC_SPI_Disable( );
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE void FMC_SPI_Flash_WakeUp(void)
{
FMC_Status_Wait_Idle( );
uint8_t cmd[4];
cmd[0] = 0;
cmd[1] = 0;
cmd[2] = 0;
cmd[3] = CMD_RELEASE_PWRDWN;
FMC_SPI_Enable(0x07);
FMC_SPI_WriteNByte(cmd, sizeof(cmd));
FMC_SPI_Disable( );
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE uint8_t FMC_SPI_Flash_Status(void)
{
FMC_Status_Wait_Idle( );
uint8_t cmd[2] = { 0 };
uint8_t sta[4] = { 0xff, 0xff, 0xff, 0xff };
cmd[0] = CMD_READ_STATUS;
cmd[1] = 0xff;
FMC_SPI_Enable(0x1f);
FMC_SPI_WriteNByte(cmd, sizeof(cmd));
FMC_SPI_ReadNByte(sta, sizeof(sta));
FMC_SPI_Disable( );
return sta[1];
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE void FMC_SPI_Flash_Wait_Busy(void)
{
while(( FMC_SPI_Flash_Status( ) & 0x01 ));
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE void FMC_SPI_Flash_Write_Enable(void)
{
FMC_Status_Wait_Idle( );
uint8_t cmd[4] = { 0 };
cmd[0] = 0;
cmd[1] = 0;
cmd[2] = 0;
cmd[3] = CMD_WRITE_ENABLE;
FMC_SPI_Enable(0x07);
FMC_SPI_WriteNByte(cmd, sizeof(cmd));
FMC_SPI_Disable( );
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE void FMC_SPI_Flash_Erase_Sector(uint32_t Dst_Addr)
{
// FMC_Status_Wait_Idle( );
FMC_SPI_Flash_Wait_Busy( );
FMC_SPI_Flash_Write_Enable( );
FMC_SPI_Flash_Wait_Busy( );
uint8_t cmd[4] = { 0 };
cmd[0] = CMD_SECTOR_ERASE;
cmd[1] = Dst_Addr>>16;
cmd[2] = Dst_Addr>>8;
cmd[3] = Dst_Addr;
FMC_SPI_Enable(0x1f);
FMC_SPI_WriteNByte(cmd, sizeof(cmd));
FMC_SPI_Disable( );
FMC_SPI_Flash_Wait_Busy( );
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE void FMC_SPI_Flash_WritePage(uint32_t WriteAddr, uint8_t *data, uint16_t size)
{
if(size > FLASH_PAGE_SIZE)
return;
uint32_t addr = WriteAddr;
uint8_t cmd[16+4] = { 0 };
for(uint8_t i=0; i<16; i++) {
FMC_SPI_Flash_Wait_Busy( );
FMC_SPI_Flash_Write_Enable( );
FMC_SPI_Flash_Wait_Busy( );
cmd[0] = CMD_PAGE_PROGRAM;
cmd[1] = addr >> 16;
cmd[2] = addr >> 8;
cmd[3] = addr;
ram_memcpy_bytes(&cmd[4], data+i*16, 16);
FMC_Status_Wait_Idle( );
FMC_SPI_Enable(0x1f);
FMC_SPI_WriteNByte(cmd, sizeof(cmd));
addr += 16;
}
FMC_SPI_Flash_Wait_Busy( );
FMC_SPI_Disable( );
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE void FMC_SPI_Flash_ReadPage(uint32_t ReadAddr, uint8_t *data, uint16_t size)
{
if(size > FLASH_PAGE_SIZE)
return;
FMC_Status_Wait_Idle( );
uint8_t cmd[16+4] = { 0 };
uint8_t mid[16+4] = { 0 };
uint16_t rx_idx = 0;
uint32_t addr = ReadAddr;
for(uint8_t i=0; i<16; i++) {
cmd[0] = CMD_READ_DATA;
cmd[1] = addr >> 16;
cmd[2] = addr >> 8;
cmd[3] = addr;
FMC_SPI_Enable(0x1f);
FMC_SPI_WriteNByte(cmd, 20); //sizeof(cmd)
FMC_SPI_ReadNByte(mid, 20); //sizeof(mid)
ram_memcpy_bytes(&data[rx_idx], mid+4, 16);
addr += 16;
rx_idx += 16;
}
FMC_SPI_Disable( );
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE uint8_t FMC_SPI_FlashWrite(uint32_t writeAddr, uint8_t *buff, uint16_t len)
{
uint32_t cur_addr = writeAddr;
uint32_t end_addr = writeAddr + len;
uint16_t wt_len = 0;
uint16_t CurPageNum = 0; //本次数据存储所占用的当前页号
uint32_t CurStartPsr = 0; //本次地址在 当前页所占的位置
uint8_t temp_buff[FLASH_PAGE_SIZE] = { 0 };
while (cur_addr != end_addr) {
/* code */
CurPageNum = CUR_PAGE_NUM(cur_addr);
CurStartPsr = CUR_START_PSR(cur_addr);
FMC_SPI_Flash_ReadPage(CurPageNum*FLASH_PAGE_SIZE, temp_buff, FLASH_PAGE_SIZE);
if(CurStartPsr) {
ram_memcpy_bytes(&temp_buff[CurStartPsr], buff+wt_len, (256-CurStartPsr)>len-wt_len? len-wt_len:(256-CurStartPsr));
wt_len += wt_len + ((256-CurStartPsr)>len-wt_len? len-wt_len:(256-CurStartPsr));
cur_addr += wt_len;
} else {
ram_memcpy_bytes(temp_buff, buff+wt_len, len-wt_len>256? 256:len-wt_len);
cur_addr += (len-wt_len>256? 256:len-wt_len);
wt_len += (len-wt_len>256? 256:len-wt_len);
}
FMC_SPI_Flash_WritePage(CurPageNum*FLASH_PAGE_SIZE, temp_buff, FLASH_PAGE_SIZE);
}
return 0;
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
* @return[out]
*
****************************************************************************************
*/
__RAM_CODE uint8_t FMC_SPI_FlashRead(uint32_t readAddr, uint8_t *buff, uint16_t len)
{
uint32_t cur_addr = readAddr;
uint32_t end_addr = readAddr + len;
uint16_t rd_len = 0;
uint16_t CurPageNum = 0; //本次数据存储所占用的当前页号
uint32_t CurStartPsr = 0; //本次地址在 当前页所占的位置
uint8_t temp_buff[FLASH_PAGE_SIZE] = { 0 };
while (cur_addr != end_addr) {
CurPageNum = CUR_PAGE_NUM(cur_addr);
CurStartPsr = CUR_START_PSR(cur_addr);
FMC_SPI_Flash_ReadPage(CurPageNum*FLASH_PAGE_SIZE, temp_buff, FLASH_PAGE_SIZE);
if(CurStartPsr) {
ram_memcpy_bytes(buff, &temp_buff[CurStartPsr], (256-CurStartPsr)>len-rd_len? len-rd_len:(256-CurStartPsr));
rd_len += rd_len + ((256-CurStartPsr)>len-rd_len? len-rd_len:(256-CurStartPsr));
cur_addr += rd_len;
} else {
ram_memcpy_bytes(buff+rd_len, temp_buff, len-rd_len>256? 256:len-rd_len);
cur_addr += (len-rd_len>256? 256:len-rd_len);
rd_len += (len-rd_len>256? 256:len-rd_len);
}
}
return 0;
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE void FMC_SPI_Flash_RUID(uint8_t *ruid)
{
FMC_Status_Wait_Idle( );
FMC_SPI_Flash_Wait_Busy( );
uint8_t cmd[21] = { 0 };
uint8_t id[21] = { 0 };
cmd[0] = CMD_RUID;
cmd[1] = 0xff;
cmd[2] = 0xff;
cmd[3] = 0xff;
cmd[4] = 0xff;
FMC_SPI_Enable(0x1f);
FMC_SPI_WriteNByte(cmd, sizeof(cmd));
FMC_SPI_ReadNByte(id, sizeof(id));
FMC_SPI_Disable( );
ram_memcpy_bytes(ruid, &id[5], 16);
}
/**
****************************************************************************************
* @brief
*
* @param[in]
* @param[in]
****************************************************************************************
*/
__RAM_CODE void FMC_SPI_Flash_RDID(uint8_t *rdid)
{
FMC_Status_Wait_Idle( );
FMC_SPI_Flash_Wait_Busy( );
uint8_t cmd[4] = { 0 };
uint8_t id[4] = { 0 };
cmd[0] = CMD_RDID;
cmd[1] = 0xff;
cmd[2] = 0xff;
cmd[3] = 0xff;
FMC_SPI_Enable(0x1f);
FMC_SPI_WriteNByte(cmd, sizeof(cmd));
FMC_SPI_ReadNByte(id, sizeof(id));
FMC_SPI_Disable( );
ram_memcpy_bytes(rdid, &id[1], 3);
}