/* ********************************************************************************************************* * IAR Development Kits * on the * * M451 * * Filename : spi_flash.c * Version : V1.00 * Programmer(s) : Qian Xianghong ********************************************************************************************************* */ #include "includes.h" // 片选 #define SFLASH_CS_LOW() LL_GPIO_ResetOutputPin(GPIOE, LL_GPIO_PIN_12) #define SFLASH_CS_HIGH() LL_GPIO_SetOutputPin(GPIOE, LL_GPIO_PIN_12) // Flash操作命令码 #define SFLASH_OP_WREN 0x06 // Write Enable #define SFLASH_OP_WRDI 0x04 // Write Disable #define SFLASH_OP_RDSR 0x05 // Read Status Register #define SFLASH_OP_WRSR 0x01 // Write Status Register #define SFLASH_OP_READ 0x03 // Read Memory #define SFLASH_OP_FSTRD 0x0B // Read Memory at Higher Speed #define SFLASH_OP_PP 0x02 // Page Program #define SFLASH_OP_DPD 0xB9 // Deep Power-down Mode #define SFLASH_OP_RDID 0x9F // JEDEC-ID Read #define SFLASH_OP_PE 0x81 // Erase 256 Bytes of Memory Array #define SFLASH_OP_SE 0x20 // Erase 4 KBytes of Memory Array #define SFLASH_OP_CE 0xC7 // Erase Full Array #define SFLASH_OP_ULBPR 0x98 // Global Block Protection Unlock // Flash状态寄存器(SR)写允许(WEL)标志位 #define SFLASH_WEL_Pos 1 #define SFLASH_WEL_Msk (0x01 << SFLASH_WEL_Pos) // Flash状态寄存器(SR)Busy标志位 #define SFLASH_BUSY_Pos 0 #define SFLASH_BUSY_Msk (0x01 << SFLASH_BUSY_Pos) // 写Flash缓冲 uint8_t SFlash_wtBuf[SFLASH_ERASE_SIZE]; //uint8_t *SFlash_wtBuf; // 放在扩展内存 // 读Flash全局缓冲 uint8_t SFlash_rdBuf[SFLASH_ERASE_SIZE]; //uint8_t *SFlash_rdBuf; // 放在扩展内存 void SFlash_Init() { LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOE); /**SPI1 GPIO Configuration PE13 ------> SPI1_SCK PE14 ------> SPI1_MISO PE15 ------> SPI1_MOSI */ GPIO_InitStruct.Pin = LL_GPIO_PIN_13|LL_GPIO_PIN_14|LL_GPIO_PIN_15; GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM; GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; GPIO_InitStruct.Alternate = LL_GPIO_AF_5; LL_GPIO_Init(GPIOE, &GPIO_InitStruct); /**/ LL_GPIO_SetOutputPin(GPIOE, LL_GPIO_PIN_12); /**/ GPIO_InitStruct.Pin = LL_GPIO_PIN_12; GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT; GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; LL_GPIO_Init(GPIOE, &GPIO_InitStruct); } void SFlash_Open() { LL_SPI_InitTypeDef SPI_InitStruct = {0}; // 分配扩展内存 // SFlash_rdBuf = SRAM_Alloc(SFLASH_ERASE_SIZE); // SFlash_wtBuf = SRAM_Alloc(SFLASH_ERASE_SIZE); /* Peripheral clock enable */ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1); /* SPI1 parameter configuration*/ SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX; SPI_InitStruct.Mode = LL_SPI_MODE_MASTER; SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT; SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW; SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE; SPI_InitStruct.NSS = LL_SPI_NSS_SOFT; SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2; SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST; SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE; SPI_InitStruct.CRCPoly = 7; LL_SPI_Init(SPI1, &SPI_InitStruct); LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA); LL_SPI_DisableNSSPulseMgt(SPI1); LL_SPI_SetRxFIFOThreshold(SPI1, LL_SPI_RX_FIFO_TH_QUARTER); LL_SPI_Enable(SPI1); // 读出ID:测试通信是否正常 SFlash_ReadID(); } void SFlash_ReadID() { uint8_t i; __disable_irq(); SFLASH_CS_LOW(); *(__IO uint8_t *)&SPI1->DR = SFLASH_OP_RDID; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; PRINTF("\r\nFlash ID is: "); for(i = 0; i < 3; i++) { *(__IO uint8_t *)&SPI1->DR = 0; // 提供CLK while(!(SPI1->SR & SPI_SR_RXNE)); PRINTF("%02X ", *(__IO uint8_t *)&SPI1->DR); } PRINTF("\r\n"); SFLASH_CS_HIGH(); __enable_irq(); } uint8_t SFlash_UnlockBPR() { __disable_irq(); SFlash_WriteEN(); SFLASH_CS_LOW(); // Write Enabled *(__IO uint8_t *)&SPI1->DR = SFLASH_OP_ULBPR; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; SFLASH_CS_HIGH(); __enable_irq(); return 1; } uint8_t SFlash_WriteEN() { uint8_t SR = 0x00; SFLASH_CS_LOW(); // Write Enabled *(__IO uint8_t *)&SPI1->DR = SFLASH_OP_WREN; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; SFLASH_CS_HIGH(); // Read SR SFLASH_CS_LOW(); *(__IO uint8_t *)&SPI1->DR = SFLASH_OP_RDSR; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; *(__IO uint8_t *)&SPI1->DR = 0; // 提供CLK while(!(SPI1->SR & SPI_SR_RXNE)); SR = *(__IO uint8_t *)&SPI1->DR; SFLASH_CS_HIGH(); // Check WEL if(SR & SFLASH_WEL_Msk) return 1; PRINTF("\r\nWrite enable failed\r\n"); return 0; } uint8_t SFlash_WriteDI() { uint8_t SR = 0xFF; SFLASH_CS_LOW(); // Write Enabled *(__IO uint8_t *)&SPI1->DR = SFLASH_OP_WRDI; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; SFLASH_CS_HIGH(); // Read SR SFLASH_CS_LOW(); *(__IO uint8_t *)&SPI1->DR = SFLASH_OP_RDSR; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; *(__IO uint8_t *)&SPI1->DR = 0; // 提供CLK while(!(SPI1->SR & SPI_SR_RXNE)); SR = *(__IO uint8_t *)&SPI1->DR; SFLASH_CS_HIGH(); // Check WEL if(SR & SFLASH_WEL_Msk) { PRINTF("\r\nWrite disable failed\r\n"); return 0; } return 1; } uint32_t SFlash_BufferRead(uint32_t Addr, uint8_t *buf, uint32_t nbytes) { uint32_t i; __disable_irq(); SFLASH_CS_LOW(); // Read *(__IO uint8_t *)&SPI1->DR = SFLASH_OP_READ; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; // address highest byte *(__IO uint8_t *)&SPI1->DR = (Addr >> 16) & 0xFF; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; // address high byte *(__IO uint8_t *)&SPI1->DR = (Addr >> 8) & 0xFF; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; // address low byte *(__IO uint8_t *)&SPI1->DR = Addr & 0xFF; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; // data for(i = 0; i < nbytes && Addr + i < SFLASH_SIZE; i++) { *(__IO uint8_t *)&SPI1->DR = 0; // 提供CLK while(!(SPI1->SR & SPI_SR_RXNE)); buf[i] = *(__IO uint8_t *)&SPI1->DR; } SFLASH_CS_HIGH(); __enable_irq(); return i; } void SFlash_PageErase(uint32_t Addr) { uint8_t SR = 0xFF; SFLASH_CS_LOW(); // Sector erase *(__IO uint8_t *)&SPI1->DR = SFLASH_OP_PE; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; // address highest byte *(__IO uint8_t *)&SPI1->DR = (Addr >> 16) & 0xFF; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; // address high byte *(__IO uint8_t *)&SPI1->DR = (Addr >> 8) & 0xFF; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; // address low byte *(__IO uint8_t *)&SPI1->DR = Addr & 0xFF; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; SFLASH_CS_HIGH(); // Read SR do { SFLASH_CS_LOW(); *(__IO uint8_t *)&SPI1->DR = SFLASH_OP_RDSR; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; *(__IO uint8_t *)&SPI1->DR = 0; // 提供CLK while(!(SPI1->SR & SPI_SR_RXNE)); SR = *(__IO uint8_t *)&SPI1->DR; SFLASH_CS_HIGH(); } while(SR & SFLASH_BUSY_Msk); } void SFlash_SectorErase(uint32_t Addr) { uint8_t SR = 0xFF; SFLASH_CS_LOW(); // Sector erase *(__IO uint8_t *)&SPI1->DR = SFLASH_OP_SE; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; // address highest byte *(__IO uint8_t *)&SPI1->DR = (Addr >> 16) & 0xFF; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; // address high byte *(__IO uint8_t *)&SPI1->DR = (Addr >> 8) & 0xFF; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; // address low byte *(__IO uint8_t *)&SPI1->DR = Addr & 0xFF; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; SFLASH_CS_HIGH(); // Read SR do { SFLASH_CS_LOW(); *(__IO uint8_t *)&SPI1->DR = SFLASH_OP_RDSR; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; *(__IO uint8_t *)&SPI1->DR = 0; // 提供CLK while(!(SPI1->SR & SPI_SR_RXNE)); SR = *(__IO uint8_t *)&SPI1->DR; SFLASH_CS_HIGH(); } while(SR & SFLASH_BUSY_Msk); } void SFlash_ChipErase() { uint8_t SR = 0xFF; SFLASH_CS_LOW(); // Chip erase *(__IO uint8_t *)&SPI1->DR = SFLASH_OP_CE; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; SFLASH_CS_HIGH(); // Read SR do { SFLASH_CS_LOW(); *(__IO uint8_t *)&SPI1->DR = SFLASH_OP_RDSR; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; *(__IO uint8_t *)&SPI1->DR = 0; // 提供CLK while(!(SPI1->SR & SPI_SR_RXNE)); SR = *(__IO uint8_t *)&SPI1->DR; SFLASH_CS_HIGH(); } while(SR & SFLASH_BUSY_Msk); } uint16_t SFlash_PageProgram(uint32_t Addr, uint8_t *buf) { uint8_t SR = 0xFF; uint16_t i; SFLASH_CS_LOW(); // Page grogram *(__IO uint8_t *)&SPI1->DR = SFLASH_OP_PP; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; // address highest byte *(__IO uint8_t *)&SPI1->DR = (Addr >> 16) & 0xFF; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; // address high byte *(__IO uint8_t *)&SPI1->DR = (Addr >> 8) & 0xFF; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; // address low byte *(__IO uint8_t *)&SPI1->DR = Addr & 0xFF; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; // data for(i = 0; i < SFLASH_PAGE_SIZE && Addr + i < SFLASH_SIZE; i++) { *(__IO uint8_t *)&SPI1->DR = buf[i]; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; } SFLASH_CS_HIGH(); // Read SR do { SFLASH_CS_LOW(); *(__IO uint8_t *)&SPI1->DR = SFLASH_OP_RDSR; while(!(SPI1->SR & SPI_SR_RXNE)); *(__IO uint8_t *)&SPI1->DR; *(__IO uint8_t *)&SPI1->DR = 0; // 提供CLK while(!(SPI1->SR & SPI_SR_RXNE)); SR = *(__IO uint8_t *)&SPI1->DR; SFLASH_CS_HIGH(); } while(SR & SFLASH_BUSY_Msk); return i; } uint16_t SFlash_SectorProgram(uint32_t Addr, uint8_t *buf) { uint16_t i = 0; uint16_t j; for(j = 0; j < SFLASH_ERASE_SIZE; j += SFLASH_PAGE_SIZE) { __disable_irq(); SFlash_WriteEN(); i += SFlash_PageProgram(Addr + j, buf + j); __enable_irq(); } return i; } uint32_t SFlash_BufferWrite(uint32_t Addr, uint8_t *buf, uint32_t nbytes) { uint32_t count, offset; while(nbytes > 0) { // 计算页内偏移(只有第一页有可能非0) offset = Addr % SFLASH_ERASE_SIZE; // 计算一页内写入字节数 count = SFLASH_ERASE_SIZE - offset; if(count > nbytes) count = nbytes; // 页对齐 Addr -= offset; // 读本页内数据 SFlash_BufferRead(Addr, SFlash_wtBuf, SFLASH_ERASE_SIZE); // 如果数据一致,不用写 if(memcmp(SFlash_wtBuf + offset, buf, count) != 0) { // 擦除本页 __disable_irq(); SFlash_WriteEN(); SFlash_PageErase(Addr); __enable_irq(); // 修改数据 memcpy(SFlash_wtBuf + offset, buf, count); // 写入本页数据 __disable_irq(); SFlash_WriteEN(); SFlash_PageProgram(Addr, SFlash_wtBuf); __enable_irq(); } // 计算下一页 Addr += SFLASH_ERASE_SIZE; buf += count; nbytes -= count; } return TRUE; } uint32_t SFlash_BufferVerify(uint32_t Addr, uint8_t *buf, uint32_t nbytes) { uint32_t data_len; while(nbytes > 0) { if(nbytes > SFLASH_ERASE_SIZE) data_len = SFLASH_ERASE_SIZE; else data_len = nbytes; SFlash_BufferRead(Addr, SFlash_wtBuf, data_len); if(memcmp(SFlash_wtBuf, buf, data_len) != 0) return FALSE; // 计算下一页 Addr += data_len; buf += data_len; nbytes -= data_len; } return TRUE; } uint16_t do_sflash_crc(unsigned long base_addr, long len) { unsigned short crc = 0; unsigned short data_len; while(len > 0) { if(len > SFLASH_ERASE_SIZE) data_len = SFLASH_ERASE_SIZE; else data_len = len; SFlash_BufferRead(base_addr, SFlash_rdBuf, data_len); crc = do_crc_16(crc, SFlash_rdBuf, data_len); base_addr += data_len; len -= data_len; } return crc; }