📄 dflashhw.c
字号:
/******************************************************************************/
/* This file is part of the ARM Toolchain package */
/* Copyright KEIL ELEKTRONIK GmbH 2005 - 2007 */
/******************************************************************************/
/* */
/* FlashHW.C: Hardware Layer of External DataFlash Programming Functions */
/* adapted for the Atmel AT91SAM926x Devices */
/* */
/******************************************************************************/
#include <AT91SAM9260.H> // AT91SAM9260 definitions
#include <lib_AT91SAM9260.h> // Library function definitions
#include "Error.h" // Error definitions
#define SYS_CLOCK 18432000 // System Clock (in Hz)
#define SPI_CLOCK 1000000 // Expected SPI clock speed (in Hz)
#define DLYBS 300 // Delay Before SPCK (in ns)
#define DLYBCT 500 // Delay Between Consecutive Transfers (in ns)
#define SPI_PCS0_DF 0x0E // Chip Select 0 : NPCS0 %1110
#define SPI_PCS1_DF 0x0D // Chip Select 1 : NPCS1 %1101
#define SPI_PCS2_DF 0x0B // Chip Select 2 : NPCS2 %1011
#define SPI_PCS3_DF 0x07 // Chip Select 3 : NPCS3 %0111
// Constants depending on Chip used
// ----------------- Page Size 528, CS0 used ----------------------------------
#ifdef P528_CS0
#define PAGE_SIZE 528 // Size of page
#define ADDR_BITS 10 // Bits for addressing inside page
#define CHIP_SIZE 0x420000 // Chip size (in bytes)
#define SPI_PCS_DF SPI_PCS0_DF
#define CS_INDEX 0
#endif
// ----------------- Page Size 1056, CS1 used ----------------------------------
#ifdef P1056_CS1
#define PAGE_SIZE 1056 // Size of page
#define ADDR_BITS 11 // Bits for addressing inside page
#define CHIP_SIZE 0x840000 // Chip size (in bytes) = 8MB
#define SPI_PCS_DF SPI_PCS1_DF
#define CS_INDEX 1
#endif
#define BLOCK_SIZE 8*PAGE_SIZE // Block size (used for erase)
// READ COMMANDS
#define DB_CONTINUOUS_ARRAY_READ 0xE8 // Continuous array read
#define DB_BURST_ARRAY_READ 0xE8 // Burst array read
#define DB_PAGE_READ 0xD2 // Main memory page read
#define DB_BUF1_READ 0xD4 // Buffer 1 read
#define DB_BUF2_READ 0xD6 // Buffer 2 read
#define DB_STATUS 0xD7 // Status Register
// PROGRAM and ERASE COMMANDS
#define DB_BUF1_WRITE 0x84 // Buffer 1 write
#define DB_BUF2_WRITE 0x87 // Buffer 2 write
#define DB_BUF1_PAGE_ERS_PGM 0x83 // Buf 1 to main mem page prg w built-In erase
#define DB_BUF1_PAGE_ERS_FASTPGM 0x93 // Buf 1 to main mem page prg w built-In erase, Fast program
#define DB_BUF2_PAGE_ERS_PGM 0x86 // Buf 2 to main mem page prg w built-In erase
#define DB_BUF2_PAGE_ERS_FASTPGM 0x96 // Buf 2 to main mem page prg w built-In erase, Fast program
#define DB_BUF1_PAGE_PGM 0x88 // Buf 1 to main mem page prg wo built-In erase
#define DB_BUF1_PAGE_FASTPGM 0x98 // Buf 1 to main mem page prg wo built-In erase, Fast program
#define DB_BUF2_PAGE_PGM 0x89 // Buf 2 to main mem page prg wo built-In erase
#define DB_BUF2_PAGE_FASTPGM 0x99 // Buf 2 to main mem page prg wo built-In erase, Fast program
#define DB_PAGE_ERASE 0x81 // Page Erase
#define DB_BLOCK_ERASE 0x50 // Block Erase
#define DB_PAGE_PGM_BUF1 0x82 // Main mem page thru buf 1
#define DB_PAGE_FASTPGM_BUF1 0x92 // Main mem page thru buf 1, Fast
#define DB_PAGE_PGM_BUF2 0x85 // Main mem page thru buf 2
#define DB_PAGE_FastPGM_BUF2 0x95 // Main mem page thru buf 2, Fast
// ADDITIONAL COMMANDS
#define DB_PAGE_2_BUF1_TRF 0x53 // Main mem page to buf 1 transfer
#define DB_PAGE_2_BUF2_TRF 0x55 // Main mem page to buf 2 transfer
#define DB_PAGE_2_BUF1_CMP 0x60 // Main mem page to buf 1 compare
#define DB_PAGE_2_BUF2_CMP 0x61 // Main mem page to buf 2 compare
#define DB_AUTO_PAGE_PGM_BUF1 0x58 // Auto page rewrite thru buf 1
#define DB_AUTO_PAGE_PGM_BUF2 0x59 // Auto page rewrite thru buf 2
static unsigned int command[2]; // Command for DataFlash
// Module's local functions prototypes
static unsigned long SwapU32 (unsigned long to_swap);
static int SendCommandDF (unsigned char cmd, unsigned char cmd_sz, unsigned long adr, unsigned char *buf, unsigned long sz);
/************************* Module Exported Functions ***************************/
/*- InitFlashController_HW (...) -----------------------------------------------
*
* Initialize Flash Controller
* Parameter: bus_width: Bus Width (8, 16 bit)
* adr_cycles: Addressing Cycles (3, 4, 5)
* page_type: Page Type (0 -Small Page, 1 - Large Page)
* clk: Clock Frequency (Hz)
* Return Value: ERROR code
*/
int InitFlashController_HW (unsigned char bus_width, unsigned char adr_cycles, unsigned char page_type, unsigned long clk) {
/* 1. Initialize pins for SPI functionality */
/* Enable clocks */
*AT91C_PMC_PCER |= (1 << AT91C_ID_PIOA);
*AT91C_PMC_PCER |= (1 << AT91C_ID_PIOC);
*AT91C_PMC_PCER |= (1 << AT91C_ID_SPI0);
/* MISO pin: int disable, not pull-up, alt func A select, enable alt func */
*AT91C_PIOA_IDR = AT91C_PA0_SPI0_MISO;
*AT91C_PIOA_PPUDR = AT91C_PA0_SPI0_MISO;
*AT91C_PIOA_ASR = AT91C_PA0_SPI0_MISO;
*AT91C_PIOA_PDR = AT91C_PA0_SPI0_MISO;
/* MOSI pin: int disable, not pull-up, alt func A select, enable alt func */
*AT91C_PIOA_IDR = AT91C_PA1_SPI0_MOSI;
*AT91C_PIOA_PPUDR = AT91C_PA1_SPI0_MOSI;
*AT91C_PIOA_ASR = AT91C_PA1_SPI0_MOSI;
*AT91C_PIOA_PDR = AT91C_PA1_SPI0_MOSI;
/* SPCK pin: int disable, not pull-up, alt func A select, enable alt func */
*AT91C_PIOA_IDR = AT91C_PA2_SPI0_SPCK;
*AT91C_PIOA_PPUDR = AT91C_PA2_SPI0_SPCK;
*AT91C_PIOA_ASR = AT91C_PA2_SPI0_SPCK;
*AT91C_PIOA_PDR = AT91C_PA2_SPI0_SPCK;
/* NPCS0 pin: int disable, not pull-up, alt func A select, enable alt func */
*AT91C_PIOA_IDR = AT91C_PA3_SPI0_NPCS0;
*AT91C_PIOA_PPUDR = AT91C_PA3_SPI0_NPCS0;
*AT91C_PIOA_ASR = AT91C_PA3_SPI0_NPCS0;
*AT91C_PIOA_PDR = AT91C_PA3_SPI0_NPCS0;
/* NPCS1 pin: int disable, not pull-up, alt func B select, enable alt func */
*AT91C_PIOC_IDR = AT91C_PC11_SPI0_NPCS1;
*AT91C_PIOC_PPUDR = AT91C_PC11_SPI0_NPCS1;
*AT91C_PIOC_BSR = AT91C_PC11_SPI0_NPCS1;
*AT91C_PIOC_PDR = AT91C_PC11_SPI0_NPCS1;
/* 2. Initialize SPI0 controller */
AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SWRST;
AT91C_BASE_SPI0->SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCS;
AT91C_BASE_SPI0->SPI_CSR[CS_INDEX] = AT91C_SPI_NCPHA |
(AT91C_SPI_DLYBS & ((SYS_CLOCK/1000000*DLYBS/1000) << 16)) |
(AT91C_SPI_DLYBCT & (((SYS_CLOCK/1000000*DLYBCT/1000)/32) << 24)) |
((SYS_CLOCK/SPI_CLOCK) << 8);
AT91C_BASE_SPI0->SPI_MR &= ~AT91C_SPI_PCS;
AT91C_BASE_SPI0->SPI_MR |= ((SPI_PCS_DF << 16) & AT91C_SPI_PCS);
AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SPIEN;
// Wait for DataFlash to become ready
do { SendCommandDF(DB_STATUS, 2, 0, 0, 0); } while (!(command[0] & 0x8000));
return (OK);
}
/*- GetPageSize_HW (...) -------------------------------------------------------
*
* Get Size of Page
* Parameter:
* Return Value: page size in bytes
*/
int GetPageSize_HW (void) {
return (PAGE_SIZE);
}
/*- ErasePage_HW (...) ---------------------------------------------------------
*
* Erase a Page
* Parameter: adr: Page Start Address
* Return Value: ERROR code
*/
int ErasePage_HW (unsigned long adr) {
if (SendCommandDF(DB_PAGE_ERASE, 4, adr, 0, 0) != OK)
return (ERROR_ERASE);
// Wait for operation to finish
do { SendCommandDF(DB_STATUS, 2, 0, 0, 0); } while (!(command[0] & 0x8000));
return (OK);
}
/*- EraseBlock_HW (...) ---------------------------------------------------------
*
* Erase a Block
* Parameter: adr: Block Start Address
* Return Value: ERROR code
*/
int EraseBlock_HW (unsigned long adr) {
if (SendCommandDF(DB_BLOCK_ERASE, 4, adr, 0, 0) != OK)
return (ERROR_ERASE);
// Wait for operation to finish
do { SendCommandDF(DB_STATUS, 2, 0, 0, 0); } while (!(command[0] & 0x8000));
return (OK);
}
/*- EraseChip_HW (...) ---------------------------------------------------------
*
* Erase Full Flash Memory
* Parameter:
* Return Value: ERROR code
*/
int EraseChip_HW (void) {
unsigned long i;
// Because Chip Erase Command (0xC7) in documentation is said not to
// be reliable on some chips, chip is erased with multiply Block Erase
// Commands (0x50)
for (i = 0; i < CHIP_SIZE; i += BLOCK_SIZE) {
if (SendCommandDF(DB_BLOCK_ERASE, 4, i, 0, 0) != OK)
return (ERROR_ERASE);
// Wait for operation to finish
do { SendCommandDF(DB_STATUS, 2, 0, 0, 0); } while (!(command[0] & 0x8000));
}
return (OK);
}
/*- ReadPage_HW (...) ----------------------------------------------------------
*
* Initialize Flash Programming Functions
* Parameter: adr: Page Start Address
* sz: Page Size
* buf: Page Data
* Return Value: ERROR code
*/
int ReadPage_HW (unsigned long adr, unsigned long sz, unsigned char *buf) {
if (SendCommandDF(DB_CONTINUOUS_ARRAY_READ, 8, adr, buf, sz) != OK)
return (ERROR_READ);
// Wait for operation to finish
do { SendCommandDF(DB_STATUS, 2, 0, 0, 0); } while (!(command[0] & 0x8000));
return (OK);
}
/*- ProgramPage_HW (...) -------------------------------------------------------
*
* Initialize Flash Programming Functions
* Parameter: adr: Page Start Address
* sz: Page Size
* buf: Page Data
* Return Value: ERROR code
*/
int ProgramPage_HW (unsigned long adr, unsigned long sz, unsigned char *buf) {
unsigned int i;
// Clear (0xFF) rest of a page if not full page is requested for program
// because always a whole page must be programmed
if (sz < PAGE_SIZE)
for (i = sz; i < PAGE_SIZE; i++)
buf[i] = 0xFF;
// Write Data to Buf1
if (SendCommandDF(DB_BUF1_WRITE, 4, adr, buf, PAGE_SIZE) != OK)
return (ERROR_WRITE);
// Wait for operation to finish
do { SendCommandDF(DB_STATUS, 2, 0, 0, 0); } while (!(command[0] & 0x8000));
// Write Buf1 to DataFlash
if (SendCommandDF(DB_BUF1_PAGE_PGM, 4, adr, buf, PAGE_SIZE) != OK)
return (ERROR_WRITE);
// Wait for operation to finish
do { SendCommandDF(DB_STATUS, 2, 0, 0, 0); } while (!(command[0] & 0x8000));
return (OK);
}
/*- CheckBlock_HW (...) --------------------------------------------------------
*
* Check if block at requested address is valid
* Parameter: adr: Block Start Address
* Return Value: ERROR code
*/
int CheckBlock_HW (unsigned long adr) {
return (ERROR_NOT_IMPLEMENTED);
}
/*- MarkBlockBad_HW (...) ------------------------------------------------------
*
* Mark the block as being bad
* Parameter: adr: Block Start Address
* Return Value: ERROR code
*/
int MarkBlockBad_HW (unsigned long adr) {
return (ERROR_NOT_IMPLEMENTED);
}
/**************************** Auxiliary Functions ******************************/
/*- SwapU32 (...) --------------------------------------------------------------
*
* Swap big <-> little-endian for 32 bit value
* Parameter:
* Return Value: swapped value
*/
static unsigned long SwapU32(unsigned long to_swap)
{
const unsigned long mask = 0x00FF00FF;
unsigned long temp;
__asm {
AND temp, mask, to_swap
AND to_swap, mask, to_swap, ROR #24
ORR to_swap, to_swap, temp, ROR #8
}
return (to_swap);
}
/*- SendCommandDF (...) --------------------------------------------------------
*
* Send command to DataFlash
* Parameter: cmd: Command to be Sent
* cmd_sz: Command Size (in bytes)
* adr: Address in DataFlash
* buf: Data to be Sent (or Received)
* sz: Size of Data
* Return Value: ERROR code
*/
static int SendCommandDF (unsigned char cmd, unsigned char cmd_sz, unsigned long adr, unsigned char *buf, unsigned long sz) {
unsigned long mul, rem;
// Divide adr by PAGE_SIZE
// Instead of using multiplication and division
// because it needs library which takes too much
// memory
mul = 0;
rem = adr;
while (rem >= PAGE_SIZE) {
rem -= PAGE_SIZE;
mul++;
}
// Calculate address
adr = (mul << ADDR_BITS) + (rem);
command[0] = (SwapU32(adr) & 0xFFFFFF00) | cmd;
command[1] = 0;
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_RXTDIS;
AT91C_BASE_SPI0->SPI_RPR = (unsigned int) &command[0];
AT91C_BASE_SPI0->SPI_RCR = cmd_sz;
AT91C_BASE_SPI0->SPI_RNPR = (unsigned int) &buf[0];
AT91C_BASE_SPI0->SPI_RNCR = sz;
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_TXTDIS;
AT91C_BASE_SPI0->SPI_TPR = (unsigned int) &command[0];
AT91C_BASE_SPI0->SPI_TCR = cmd_sz;
AT91C_BASE_SPI0->SPI_TNPR = (unsigned int) &buf[0];
AT91C_BASE_SPI0->SPI_TNCR = sz;
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_RXTEN;
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_TXTEN;
while (!(AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_RXBUFF));
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_RXTDIS;
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_TXTDIS;
return (OK);
}
/*******************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -