/*! * \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> 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> 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); }