From: asterix Date: Tue, 16 Oct 2007 08:17:21 +0000 (+0000) Subject: Data flash driver for AT45DBXX series. X-Git-Tag: 1.0.0~359 X-Git-Url: https://codewiz.org/gitweb?a=commitdiff_plain;h=8b2138872120fa65294769202059dd8198da8504;p=bertos.git Data flash driver for AT45DBXX series. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@882 38d2e660-2303-0410-9eaa-f027e97ec537 --- diff --git a/drv/dflash.c b/drv/dflash.c new file mode 100644 index 00000000..8aad1f54 --- /dev/null +++ b/drv/dflash.c @@ -0,0 +1,324 @@ +/** + * \file + * + * + * \brief Function library for AT45DB081D Flash memory. + * + * + * \version $Id: dflash.c 15379 2007-03-28 15:46:09Z asterix $ + * \author Daniele Basile + */ + + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "hw_spi.h" + +/** + * Send a generic command to data flash memory. + * This function send only 4 byte, for opcode, page address and + * byte address. + */ +static void send_cmd(dflashAddr_t page_addr, dflashAddr_t byte_addr, DFlashOpcode opcode) +{ + + /* + * Make sure to toggle CS signal in order, + * and reset dflash command decoder. + * \{ + */ + CS_DISABLE(); + CS_ENABLE(); + /* \} */ + + /* + * To send one command to data flash memory, we send 4 byte. + * First byte is opcode command, second and third byte are + * page address, in last byte we write a byte page address. + * (see datasheet for more detail). + * + * \note Generaly a defaul memory page size is more than 256 byte. + * In this case we need for addressing a byte in one page more than + * 8 bit, so we put in fourth byte low part of address byte, and + * hight part of address byte in third byte togheter low par of page + * address. + * + * \{ + */ + + /* + * Send opcode. + */ + spi_sendRecv(opcode); + + /* + * Send page address. + * \{ + */ + spi_sendRecv((uint8_t)(page_addr >> (16 - DFLASH_PAGE_ADDRESS_BIT))); + spi_sendRecv((uint8_t)((page_addr << (DFLASH_PAGE_ADDRESS_BIT - 8)) + (byte_addr >> 8))); + /*\}*/ + + /* + * Send byte page address. + */ + spi_sendRecv((uint8_t)byte_addr); + + /* \} */ + +} + + +//TODO: deve ritornare un bool? +/** + * Init data flash memory interface. + */ +void dflash_init(struct _KFile *fd) +{ + // Set up data flash programming functions. + fd->open = dflash_open; + fd->close = dflash_close; + fd->read = dflash_read; + fd->write = dflash_write; + fd->seek = dflash_seek; + + // Init data flash memory and micro pin. + dflash_pin_init(); +} + + +/** + * Reset dataflash memory function. + * + * This function reset data flash memory + * with one pulse reset long about 10usec. + * + */ +void dflash_reset(void) +{ + CS_ENABLE(); + RESET_ENABLE(); + timer_delayHp(us_to_hptime(RESET_PULSE_WIDTH)); + CS_DISABLE(); + RESET_DISABLE(); + timer_delayHp(us_to_hptime(RESET_PULSE_WIDTH)); +} + +/** + * dflash init function. + * This function initialize a micro pin and + * SPI driver, and test if data flash memory + * density is the same wich define in dflash.h. + */ +MOD_DEFINE(dflash); +static bool dflash_pin_init(void) +{ + uint8_t stat; + + MOD_CHECK(spi); + + RESET_DISABLE(); + WRITE_ENABLE(); //pilot wp pin. + + RESET_OUT(); + WP_OUT(); + + dflash_reset(); + + stat = dflash_stat(); + + MOD_INIT(dflash); + + /* + * 2,3,4,5 bit of 1 byte status register + * indicate a device density of dflash memory + * (see datasheet for more detail.) + */ + GET_ID_DESITY_DEVICE(stat); + + if(stat == DFLASH_ID_DEVICE_DENSITY) + return true; + else + return false; + +} + + +/** + * Read status register of dataflah memory. + * + */ +static uint8_t dflash_stat(void) +{ + uint8_t stat; + + /* + * Make sure to toggle CS signal in order, + * and reset dflash command decoder. + * \{ + */ + CS_DISABLE(); + CS_ENABLE(); + /* \} */ + + stat = spi_sendRecv(DFO_READ_STATUS); + stat = spi_sendRecv(0x00); + + return stat; +} + + +/** + * Send one command to data flash memory, and + * return status register value. + * + */ +static uint8_t dflash_cmd(dflashAddr_t page_addr, dflashAddr_t byte_addr, DFlashOpcode opcode) +{ + + send_cmd(page_addr, byte_addr, opcode); + + CS_DISABLE(); + CS_ENABLE(); + + /* + * We chech data flash memory state, and wait until busy-flag + * is hight. + */ + while(!(dflash_stat() & BUSY_BIT)); + + return (dflash_stat()); + +} + +/** + * Read one byte from main data flash memory or buffer data + * flash memory. + */ +static uint8_t dflash_read_byte(dflashAddr_t page_addr, dflashAddr_t byte_addr, DFlashOpcode opcode) +{ + uint8_t data; + + send_cmd(page_addr, byte_addr, opcode); + +#if CONFIG_DATA_FLASH == AT45DB041B + if(opcode == DFO_READ_FLASH_MEM_BYTE) + { + /* + * Send 24 don't care bit. + * \{ + */ + spi_sendRecv(0x00); + spi_sendRecv(0x00); + spi_sendRecv(0x00); + /* \} */ + + } +#endif + + spi_sendRecv(0x00); //Send 8 don't care bit. + data = spi_sendRecv(0x00); //Read byte. + CS_DISABLE(); + + return data; +} + +/** + * Read \param len bytes from main data flash memory or buffer data + * flash memory, and put it in \param *block. + */ +static void dflash_read_block(dflashAddr_t page_addr, dflashAddr_t byte_addr, DFlashOpcode opcode, uint8_t *block, dflashSize_t len) +{ + + send_cmd(page_addr, byte_addr, opcode); + + if(opcode == DFO_READ_FLASH_MEM_BYTE) + { + /* + * Send 24 don't care bit. + * \{ + */ + spi_sendRecv(0x00); + spi_sendRecv(0x00); + spi_sendRecv(0x00); + /* \} */ + } + + spi_sendRecv(0x00); //Send 8 don't care bit. + spi_read(block, len); //Read len bytes ad put in block buffer. + + + CS_DISABLE(); + +} + +/** + * Write one byte in buffer buffer data flash memory. + * + * \note Isn't possible to write byte directly in main memory data + * flash. To perform write in main memory you must before write in buffer + * data flash memory, an then send command to write page in main memory. + */ +static void dflash_write_byte(dflashAddr_t byte_addr, DFlashOpcode opcode, uint8_t data) +{ + send_cmd(0x00, byte_addr, opcode); + + spi_sendRecv(data); //Write data byte. + + CS_DISABLE(); +} + +/** + * Write \param len bytes in buffer buffer data flash memory. + * + * \note Isn't possible to write bytes directly in main memory data + * flash. To perform write in main memory you must before write in buffer + * data flash memory, an then send command to write page in main memory. + */ +static void dflash_write_block(dflashAddr_t byte_addr, DFlashOpcode opcode, uint8_t *block, dflashSize_t len) +{ + + + send_cmd(0x00, byte_addr, opcode); + + spi_write(block, len); //Write len bytes. + + CS_DISABLE(); + +} diff --git a/drv/dflash.h b/drv/dflash.h new file mode 100644 index 00000000..7d06adec --- /dev/null +++ b/drv/dflash.h @@ -0,0 +1,217 @@ +/** + * \file + * + * + * \brief Function library for AT45DB081D Flash memory. + * + * + * \version $Id: dflash.h 15402 2007-04-10 09:10:56Z asterix $ + * \author Daniele Basile + */ + + +#ifndef DFLASH_H +#define DFLASH_H + +#include + +#include +#include + +#include "hw_spi.h" + + +/** + * Type definition for dflash memory. + */ +typedef uint32_t dflashAddr_t; +typedef uint32_t dflashSize_t; + +#define RESET_PULSE_WIDTH 10 //Width of reset pulse in usec . +#define BUSY_BIT 0x80 //Select a busy bit in status register. +#define CMP_BIT 0x40 //Select a compare bit in status register. + +/** + * Select 2,3,4,5 bit of status register, that + * bit indicate a id of desity device (see datasheet for + * more detail). + */ +#define GET_ID_DESITY_DEVICE(reg_stat)\ + do {\ + reg_stat &= 0x3C;\ + reg_stat >>= 2;\ + } while (0) + +/** + * Pin definition. + * + * \note RESET and WP are asserted when logic + * level is low. + * \{ + */ +#define RESET PC0 ///Connect to RESET pin of flash memory +#define WP PC1 ///Connect to WP pin of flash memory +#define DFLASH_PORT PORTC ///Micro pin PORT register. +#define DFLASH_PIN PINC ///Micro pin PIN register. +#define DFLASH_DDR DDRC ///Micro pin DDR register. +/* \} */ + +/** + * Pin logic level. + * + * \{ + */ +#define RESET_LOW() do { DFLASH_PORT &= ~BV(RESET); } while(0) +#define RESET_HIGH() do { DFLASH_PORT |= BV(RESET); } while(0) +#define WP_LOW() do { DFLASH_PORT &= ~BV(WP); } while(0) +#define WP_HIGH() do { DFLASH_PORT |= BV(WP); } while(0) +/* \} */ + +/** + * Commands pin. + * + * \note To reset flash memory it need a pulse + * long about 10 usec, to do this we insert a + * for cicle. + * + * \{ + */ +#define RESET_OUT() do { DFLASH_DDR |= BV(RESET); } while(0) +#define WP_OUT() do { DFLASH_DDR |= BV(WP); } while(0) +#define WRITE_ENABLE() WP_HIGH() +#define WRITE_DISABLE() WP_LOW() +#define RESET_ENABLE() RESET_LOW() +#define RESET_DISABLE() RESET_HIGH() +/* \} */ + + +/** + * Memory definition. + * + * \note Below are defined valid flash memory support to + * this drive. Every time we call dflash_init() function we check + * if memory defined are right (see dflash.c form more detail). + * \{ + */ +#define AT45DB041B 1 +#define AT45DB081D 2 +#define AT45DB161D 3 + +#if CONFIG_DATA_FLASH == AT45DB161D + #define DFLASH_ID_DEVICE_DENSITY 0xb ///This indicate AT45DB161D data flah memory. + #define DFLASH_PAGE_SIZE 528 ///Number of byte in one page. + #define DFLASH_PAGE_ADDRESS_BIT 10 ///Number bit for addressing one page. + #define DFLASH_NUM_PAGE 4096 ///Number page in data flash memory. +#elif CONFIG_DATA_FLASH == AT45DB081D + #define DFLASH_ID_DEVICE_DENSITY 0x9 ///This indicate AT45DB081D data flah memory. + #define DFLASH_PAGE_SIZE 264 ///Number of byte in one page. + #define DFLASH_PAGE_ADDRESS_BIT 9 ///Number bit for addressing one page. + #define DFLASH_NUM_PAGE 4096 ///Number page in data flash memory. +#elif CONFIG_DATA_FLASH == AT45DB041B + #define DFLASH_ID_DEVICE_DENSITY 0x7 ///This indicate AT45DB041B data flah memory. + #define DFLASH_PAGE_SIZE 264 ///Number of byte in one page. + #define DFLASH_PAGE_ADDRESS_BIT 9 ///Number bit for addressing one page. + #define DFLASH_NUM_PAGE 2048 ///Number page in data flash memory. +#else + #error Nothing memory defined in CONFIG_DATA_FLASH are support. +#endif +/* \} */ + + +/** + * Data flash opcode commands. + */ +typedef enum { + /** + * Read commands data flash. + * \{ + */ + +#if CONFIG_DATA_FLASH == AT45DB081D || CONFIG_DATA_FLASH == AT45DB161D + DFO_READ_FLASH_MEM_BYTE = 0x0B, ///Continuos array read. +#elif CONFIG_DATA_FLASH == AT45DB041B + DFO_READ_FLASH_MEM_BYTE = 0xE8, ///Continuos array read. +#else + #error Nothing memory define in CONFIG_DATA_FLASH are support. +#endif + DFO_READ_FLASH_MEM = 0xD2, ///Main memory page read. + DFO_READ_BUFF1 = 0xD4, ///SRAM buffer 1 read. + DFO_READ_BUFF2 = 0xD6, ///SRAM buffer 2 read. + /* \}*/ + + /** + * Program and erase commands data flash. + * \{ + */ + DFO_WRITE_BUFF1 = 0x84, ///SRAM buffer 1 write. + DFO_WRITE_BUFF2 = 0x87, ///SRAM buffer 2 write. + DFO_WRITE_BUFF1_TO_MEM_E = 0x83, ///Buffer 1 to main memory page program with build-in erase. + DFO_WRITE_BUFF2_TO_MEM_E = 0x86, ///Buffer 2 to main memory page program with build-in erase. + DFO_WRITE_BUFF1_TO_MEM = 0x88, ///Buffer 1 to main memory page program without build-in erase. + DFO_WRITE_BUFF2_TO_MEM = 0x89, ///Buffer 2 to main memory page program without build-in erase. + DFO_ERASE_PAGE = 0x81, ///Erase page. + DFO_ERASE_BLOCK = 0x50, ///Erase block. + DFO_ERASE_SECTOR = 0x7C, ///Erase sector. + DFO_WRITE_MEM_TR_BUFF1 = 0x82, ///Write main memory page program through buffer 1. + DFO_WRITE_MEM_TR_BUFF2 = 0x85, ///Write main memory page program through buffer 2. + /* \}*/ + + /** + * Additional commands data flash. + * \{ + */ + DFO_MOV_MEM_TO_BUFF1 = 0x53, ///Main mmemory to buffer 1 transfer. + DFO_MOV_MEM_TO_BUFF2 = 0x55, ///Main mmemory to buffer 2 transfer. + DFO_CMP_MEM_TO_BUFF1 = 0x60, ///Main mmemory to buffer 1 compare. + DFO_CMP_MEM_TO_BUFF2 = 0x61, ///Main mmemory to buffer 2 compare. + DFO_ARW_MEM_TR_BUFF1 = 0x58, ///Auto page rewrite through buffer 1. + DFO_ARW_MEM_TR_BUFF2 = 0x59, ///Auto page rewrite through buffer 2 + DFO_PWR_DOWN = 0xB9, ///Deep power-down. + DFO_RESUME_PWR_DOWN = 0xAB, ///Resume from deep power-down. + DFO_READ_STATUS = 0xD7, ///Status register read. + DFO_ID_DEV = 0x9F ///Manufacturer and device ID read. + /* \}*/ +} DFlashOpcode; + +bool dflash_init(void); +void dflash_reset(void); +uint8_t dflash_stat(void); + +uint8_t dflash_cmd(dflashAddr_t page_addr, dflashAddr_t byte_addr, DFlashOpcode opcode); + +uint8_t dflash_read_byte(dflashAddr_t page_addr, dflashAddr_t byte_addr, DFlashOpcode opcode); +void dflash_read_block(dflashAddr_t page_addr, dflashAddr_t byte_addr, DFlashOpcode opcode, uint8_t *block, dflashSize_t len); + +void dflash_write_byte(dflashAddr_t byte_addr, DFlashOpcode opcode, uint8_t data); +void dflash_write_block(dflashAddr_t byte_addr, DFlashOpcode opcode, uint8_t *block, dflashSize_t len); + +#endif /* DFLASH_H */ +