📄 spi_flash.c
字号:
/*! * \file spi_flash.c * \brief Driver for a generic SPI Flash device * \version $Revision: 1.1 $ * \author Michael Norman */ #include "common.h"#include "spi_flash.h"#include "dspi.h"/********************************************************************//*! SPI Flash Device ID data */SPI_FLASH_DEVICE_ID dev_id;/*! SPI Flash Device Info */SPI_DEVICE spi_flash = { .baud = 20000000, .mode = SPI_MODE_0, .fbit = SPI_FBIT_MSB, .cs = 1, .cs_is = 1, .cs_muxed = 0, .frame_size = 8, .delay_csclk = 10, .delay_clkcs = 10, .delay_cscs = 10,};/********************************************************************//*! * Initialize the SPI Flash device * \return Zero for success; non-zero otherwise */intspi_flash_init (void){ spi_master_init(); spi_master_device_init(&spi_flash); spi_flash_read_id(); return 0;}/********************************************************************//*! * Write Enable * \return Zero for success; non-zero otherwise */static intspi_flash_write_enable (void){ uint8 data; data = SPIFLASH_WREN; spi_master_write(&spi_flash, &data, sizeof(data)); data = spi_flash_read_sr(); return !(data & SPIFLASH_SR_WEL);} /********************************************************************//*! * Write Disable * \return Zero for success; non-zero otherwise */static intspi_flash_write_disable (void){ uint8 data; data = SPIFLASH_WRDI; spi_master_write(&spi_flash, &data, sizeof(data)); data = spi_flash_read_sr(); return (data & SPIFLASH_SR_WEL);}/********************************************************************//*! * Read ID * \return Pointer to updated device ID */SPI_FLASH_DEVICE_ID*spi_flash_read_id (void){ int i; uint8 data[4]; data[0] = SPIFLASH_RDID; spi_master_write_read(&spi_flash, data, data, sizeof(data)); dev_id.manuf_id = data[1]; dev_id.mem_type = data[2]; dev_id.mem_cap = data[3]; return &dev_id;}/********************************************************************//*! * Read Status Register * \return status register contents */uint8spi_flash_read_sr (void){ uint8 data[2]; data[0] = SPIFLASH_RDSR; spi_master_write_read(&spi_flash, data, data, sizeof(data)); return data[1];}/********************************************************************//*! * Write Status Register * \param sr Data to be written to status register * \return Zero for success; non-zero otherwise */intspi_flash_write_sr (uint8 sr){ uint8 data[2]; data[0] = SPIFLASH_WRSR; data[1] = sr; return spi_master_write(&spi_flash, data, sizeof(data));}/********************************************************************//*! * Read Data Bytes * \param address Address from which to begin reading * \param length Number of bytes to read * \param buffer Buffer where received data will be stored * \return Zero for success; non-zero otherwise */intspi_flash_read (ADDRESS address, int length, uint8 *buffer){ uint8 data[4]; SPI_MSG_CHAIN chain; SPI_MSG_LINK link0, link1; data[0] = SPIFLASH_READ; data[1] = (address & 0x00FF0000) >> 16; data[2] = (address & 0x0000FF00) >> 8; data[3] = (address & 0x000000FF); /* Build a message chain */ memset(&chain, 0, sizeof(SPI_MSG_CHAIN)); chain.device = &spi_flash; chain.link = &link0; memset(&link0, 0, sizeof(SPI_MSG_LINK)); link0.tx_buf = data; link0.rx_buf = NULL; link0.length = sizeof(data); link0.next = &link1; memset(&link1, 0, sizeof(SPI_MSG_LINK)); link1.tx_buf = NULL; link1.rx_buf = buffer; link1.length = length; link1.next = NULL; return spi_master_transfer(&chain, TRUE);}/********************************************************************//*! * Read Data Bytes (at higher speed) * \param address Address from which to begin reading * \param length Number of bytes to read * \param buffer Buffer where received data will be stored * \return Zero for success; non-zero otherwise */intspi_flash_fast_read (ADDRESS address, int length, uint8 *buffer){ uint8 data[5]; SPI_MSG_CHAIN chain; SPI_MSG_LINK link0, link1; data[0] = SPIFLASH_FAST_READ; data[1] = (address & 0x00FF0000) >> 16; data[2] = (address & 0x0000FF00) >> 8; data[3] = (address & 0x000000FF); data[4] = 0; /* Dummy Byte */ /* Build a message chain */ memset(&chain, 0, sizeof(SPI_MSG_CHAIN)); chain.device = &spi_flash; chain.link = &link0; memset(&link0, 0, sizeof(SPI_MSG_LINK)); link0.tx_buf = data; link0.rx_buf = NULL; link0.length = sizeof(data); link0.next = &link1; memset(&link1, 0, sizeof(SPI_MSG_LINK)); link1.tx_buf = NULL; link1.rx_buf = buffer; link1.length = length; link1.next = NULL; return spi_master_transfer(&chain, TRUE);}/********************************************************************//*! * Page Program * \param address Address at which to begin programming * \param length Number of bytes to program (<= 256) * \param buffer Pointer to data to be programmed * \return Zero for success; non-zero otherwise */intspi_flash_page_program (ADDRESS address, int length, uint8 *buffer){ int i; uint8 data[4]; SPI_MSG_CHAIN chain; SPI_MSG_LINK link0, link1; data[0] = SPIFLASH_PP; data[1] = (address & 0x00FF0000) >> 16; data[2] = (address & 0x0000FF00) >> 8; data[3] = (address & 0x000000FF); /* Build a message chain */ memset(&chain, 0, sizeof(SPI_MSG_CHAIN)); chain.device = &spi_flash; chain.link = &link0; memset(&link0, 0, sizeof(SPI_MSG_LINK)); link0.tx_buf = data; link0.rx_buf = NULL; link0.length = sizeof(data); link0.next = &link1; memset(&link1, 0, sizeof(SPI_MSG_LINK)); link1.tx_buf = buffer; link1.rx_buf = NULL; link1.length = length; link1.next = NULL; if (spi_master_transfer(&chain, TRUE)) return -1; for (i = 10000000; i > 0; i--) { data[0] = spi_flash_read_sr(); if (!(data[0] & SPIFLASH_SR_WIP)) break; } return !i;}/********************************************************************//*! * Sector Erase * \param address Address at which to begin programming * \return Zero for success; non-zero otherwise */intspi_flash_sector_erase (ADDRESS address){ int i; uint8 data[4]; data[0] = SPIFLASH_SE; data[1] = (address & 0x00FF0000) >> 16; data[2] = (address & 0x0000FF00) >> 8; data[3] = (address & 0x000000FF); if (spi_master_write(&spi_flash, data, sizeof(data))) return -1; for (i = 10000000; i > 0; i--) { data[0] = spi_flash_read_sr(); if (!(data[0] & SPIFLASH_SR_WIP)) break; } return !i;}/********************************************************************//*! * Bulk Erase * \return Zero for success; non-zero otherwise */intspi_flash_bulk_erase (void){ uint8 data[1]; data[0] = SPIFLASH_BE; return spi_master_write(&spi_flash, data, sizeof(data));}/********************************************************************//*! * Enter Deep Power-Down * \return Zero for success; non-zero otherwise */intspi_flash_power_down (void){ uint8 data[1]; data[0] = SPIFLASH_DP; return spi_master_write(&spi_flash, data, sizeof(data));}/********************************************************************//*! * Wake up from Deep Power-Down * \return Zero for success; non-zero otherwise */intspi_flash_wake_up (void){ uint8 data[1]; data[0] = SPIFLASH_RES; return spi_master_write(&spi_flash, data, sizeof(data));}/********************************************************************//*! * Erase some flash * \param start Start address * \param bytes Bytes to erase * \param print Print progress? * \return Zero for success; non-zero otherwise */intspi_flash_erase(ADDRESS start, int bytes, int print){ int i, ebytes = 0; if (bytes == 0) return 0; for (i = 0; i < SPIFLASH_SECTORS; i++) { if (start >= (ADDRESS)SOFFSET(i) && start <= (ADDRESS)(SOFFSET(i) + (SSIZE(i) - 1))) break; } ASSERT(i != SPIFLASH_SECTORS); while (ebytes < bytes) { if (print) out_char('.'); if (spi_flash_write_enable()) return -1; if (spi_flash_sector_erase(SOFFSET(i))) return -1; ebytes += SSIZE(i); i++; } if (print) { out_char(0x0D); out_char(0x0A); } return 0;} /********************************************************************//*! * Program some flash * \param dest Start address in SPI flash * \param source Pointer to data to be programmed * \param bytes Bytes to program * \param erase Erase first? * \param print Print progress? * \return Zero for success; non-zero otherwise */intspi_flash_program(ADDRESS dest, ADDRESS source, int bytes, int erase, int print){ int i, b, first, hashi=1; uint8 *src, *dst; char hash[5]; hash[0]=8; /* Backspace */ hash[1]=124;/* "|" */ hash[2]=47; /* "/" */ hash[3]=45; /* "-" */ hash[4]=92; /* "\" */ src = (uint8 *)source; dst = (uint8 *)dest; /* Erase device if necessary */ if (erase) if (spi_flash_erase(dest, bytes, print)) return -1; for (i = 0; i < SPIFLASH_PAGES; i++) { if (dest >= (ADDRESS)POFFSET(i) && dest <= (ADDRESS)(POFFSET(i) + (PSIZE(i) - 1))) break; } ASSERT(i != SPIFLASH_PAGES); /* Handle case where start address isn't start of page */ if (dest & (PSIZE(i) - 1)) { b = PSIZE(i) - (dest & (PSIZE(i) - 1)); if (spi_flash_write_enable()) return -1; if (spi_flash_page_program((ADDRESS)dst, b, src)) return -1; bytes -= b; dst += b; src += b; i++; } while (bytes > 0) { if (bytes < PSIZE(i)) b = bytes; else b = PSIZE(i); if (spi_flash_write_enable()) return -1; if (spi_flash_page_program((ADDRESS)dst, b, src)) return -1; bytes -= b; dst += b; src += b; i++; if (print) { out_char(hash[0]); out_char(hash[hashi]); hashi++; if (hashi == 5) hashi=1; } } return 0;}/********************************************************************//*! * Dump the contents of the SPI Flash * \param addr Start address * \param bytes Bytes to dump */voidspi_flash_dump (ADDRESS addr, int bytes){ int i; uint8 *data; ADDRESS cur, end; data = (uint8 *)malloc(bytes); ASSERT(data); spi_flash_read(addr, bytes, data); printf("SPI Flash data:"); cur = addr; for (i = 0; i < bytes; i++) { if (!(i % 16)) printf("\n%06X: ",cur); printf("%02X ", data[i]); cur++; } printf("\n"); free(data);}/********************************************************************//*! * Dump the contents of the Device ID structure */voidspi_flash_dump_id (void){ int i; printf("SPI Flash ID data\n------------------\n"); printf(" Manuf ID: %02X\n", dev_id.manuf_id); printf(" Mem Type: %02X\n", dev_id.mem_type); printf(" Capacity: %02X\n", dev_id.mem_cap); printf("\n");}/********************************************************************//*! * Test for correct SPI functionality */voidspi_flash_test (void){ int i; uint8 data; uint8 *buffer; #if 0 printf("\nSPI Flash Test\n"); spi_flash_init(); data = spi_flash_read_sr(); printf("SR = %02X\n", data); spi_flash_dump_id(); /* Save off data from first sector */ buffer = (uint8 *)malloc(256); ASSERT(buffer); spi_flash_read(0x00000000, 256, buffer); /* Print the contents of the first sector */ spi_flash_dump(0x00000000, 256); /* Erase the sector */ printf("Erasing first sector..."); spi_flash_sector_erase(0); printf("done\n"); /* Print the contents of the first sector */ spi_flash_dump(0x00000000, 256); /* Write the original data back */ spi_flash_program(0x00000000, (ADDRESS)buffer, 256, FALSE, FALSE); /* Print the contents of the first sector */ spi_flash_dump(0x00000000, 256);#else printf("\nSPI Flash Test\n"); spi_flash_init(); /* Print the device ID info */ spi_flash_dump_id(); /* Print the contents of the first sector */ spi_flash_dump(0x00000000, 256); /* Erase the sector */ printf("Erasing first sector"); if (spi_flash_erase(0x00000000, 256, TRUE)) printf("failed\n"); else printf("done\n"); /* Print the contents of the first sector */ spi_flash_dump(0x00000000, 256); buffer = (uint8 *)malloc(256); ASSERT(buffer); /* Write some data to the flash */ for (i = 0; i < 256; i++) buffer[i] = i; if (spi_flash_program(0x00000000, (ADDRESS)buffer, 256, FALSE, FALSE)) printf("Program failed\n"); free(buffer); /* Print the SR */ data = spi_flash_read_sr(); printf("SR = %02X\n", data); /* Print the contents of the first sector */ spi_flash_dump(0x00000000, 256);#endif return;}/********************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -