📄 dataflash.c
字号:
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support - ROUSSET -
* ----------------------------------------------------------------------------
* Copyright (c) 2006, Atmel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaiimer below.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the disclaimer below in the documentation and/or
* other materials provided with the distribution.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
* File Name : dataflash.c
* Object : ATMEL DataFlash High level functions
* Creation : NLe Jul 12th 2006
*---------------------------------------------------------------------------
*/
#include <includes.h>
/*------------------------------------------------------------------------------*/
/* \fn df_spi_init */
/* \brief Configure SPI */
/*------------------------------------------------------------------------------*/
static int df_spi_init(unsigned int pcs, unsigned int spi_csr)
{
unsigned int ncs = 0;
/* Open PIO for SPI0 */
df_hw_init();
/* Enables the SPI0 Clock */
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI0);
/* Reset SPI0 */
AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SWRST;
/* Configure SPI0 in Master Mode with No CS selected */
AT91C_BASE_SPI0->SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCS;
switch (pcs)
{
case AT91C_SPI_PCS0_DATAFLASH: ncs = 0; break;
case AT91C_SPI_PCS1_DATAFLASH: ncs = 1; break;
case AT91C_SPI_PCS2_DATAFLASH: ncs = 2; break;
case AT91C_SPI_PCS3_DATAFLASH: ncs = 3; break;
}
/* Configure CSx */
AT91C_BASE_SPI0->SPI_CSR[ncs] = spi_csr;
/* Choose CSx */
AT91C_BASE_SPI0->SPI_MR &= ~(0x0F << 16);
AT91C_BASE_SPI0->SPI_MR |= ((pcs<<16) & AT91C_SPI_PCS);
/* SPI_Enable */
AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SPIEN;
return 0;
}
/*------------------------------------------------------------------------------*/
/* \fn df_is_busy */
/* \brief Test if SPI has received a buffer or not */
/*------------------------------------------------------------------------------*/
static AT91S_DF_SEM df_is_busy(
AT91PS_DF pDataFlash)
{
unsigned int dStatus = AT91C_BASE_SPI0->SPI_SR;
/* If End of Receive Transfer interrupt occurred */
if (( dStatus & AT91C_SPI_RXBUFF))
{
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_TXTDIS; /* PDC Disable Tx */
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_RXTDIS; /* PDC Disable Rx */
/* Release the semaphore */
pDataFlash->bSemaphore = UNLOCKED;
return UNLOCKED;
}
return pDataFlash->bSemaphore;
}
/*------------------------------------------------------------------------------*/
/* \fn df_send_command */
/* \brief Generic function to send a command to the dataflash */
/*------------------------------------------------------------------------------*/
char df_send_command (
AT91PS_DF pDataFlash,
unsigned char bCmd, /* Command value */
unsigned char bCmdSize, /* Command Size */
char *pData, /* Data to be sent */
unsigned int dDataSize, /* Data Size */
unsigned int dAddress) /* Dataflash Address */
{
unsigned int dInternalAdr;
div_t result = div(dAddress, AT91C_PAGE_SIZE(pDataFlash));
/* Try to get the dataflash semaphore */
if ((pDataFlash->bSemaphore) != UNLOCKED)
return (char) 0;
pDataFlash->bSemaphore = LOCKED;
/* Compute command pattern */
dInternalAdr = (result.quot << AT91C_PAGE_OFFSET(pDataFlash)) + result.rem;
if (AT91C_DF_NB_PAGE(pDataFlash) >= 16384)
{
pDataFlash->command[0] = (bCmd & 0x000000FF) | \
((dInternalAdr & 0x0F000000) >> 16) | \
((dInternalAdr & 0x00FF0000) >> 0) | \
((dInternalAdr & 0x0000FF00) << 16);
pDataFlash->command[1] = (dInternalAdr & 0x000000FF);
if ((bCmd != DB_CONTINUOUS_ARRAY_READ) && (bCmd != DB_PAGE_READ))
bCmdSize++;
}
else
{
pDataFlash->command[0] = (bCmd & 0x000000FF) | \
((dInternalAdr & 0x00FF0000) >> 8) | \
((dInternalAdr & 0x0000FF00) << 8) | \
((dInternalAdr & 0x000000FF) << 24);
pDataFlash->command[1] = 0;
}
/* Send Command and data through the SPI */
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_RXTDIS; /* PDC Disable Rx*/
AT91C_BASE_SPI0->SPI_RPR = (unsigned int) &(pDataFlash->command); /* PDC Set Rx */
AT91C_BASE_SPI0->SPI_RCR = bCmdSize;
AT91C_BASE_SPI0->SPI_RNPR = (unsigned int) pData; /* PDC Set Next Rx */
AT91C_BASE_SPI0->SPI_RNCR = dDataSize;
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_TXTDIS; /* PDC Disable Tx */
AT91C_BASE_SPI0->SPI_TPR = (unsigned int) &(pDataFlash->command); /* PDC Set Tx */
AT91C_BASE_SPI0->SPI_TCR = bCmdSize;
AT91C_BASE_SPI0->SPI_TNPR = (unsigned int) pData; /* PDC Set Next Tx */
AT91C_BASE_SPI0->SPI_TNCR = dDataSize;
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_RXTEN; /* PDC Enable Rx */
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_TXTEN; /* PDC Enable Tx */
while (df_is_busy(pDataFlash) == LOCKED);
return 1;
}
/*------------------------------------------------------------------------------*/
/* \fn df_wait_ready */
/* \brief wait for DataFlash to be ready */
/*------------------------------------------------------------------------------*/
static char df_wait_ready(AT91PS_DF pDataFlash)
{
unsigned int timeout = 0;
while (timeout++ < AT91C_DF_TIMEOUT)
{
if (df_get_status(pDataFlash))
{
if (df_is_ready(pDataFlash))
return 1;
}
}
return 0;
}
/*------------------------------------------------------------------------------*/
/* \fn df_read */
/* \brief Read a block in dataflash */
/*------------------------------------------------------------------------------*/
static int df_read(
AT91PS_DF pDf,
unsigned int addr,
unsigned char *buffer,
unsigned int size)
{
unsigned int SizeToRead;
while (size)
{
SizeToRead = (size < AT91C_MAX_PDC_SIZE)? size : AT91C_MAX_PDC_SIZE;
/* wait the dataflash ready status */
df_wait_ready(pDf);
df_continuous_read(pDf, (char *)buffer, SizeToRead, addr);
size -= SizeToRead;
addr += SizeToRead;
buffer += SizeToRead;
}
return 0;
}
/*----------------------------------------------------------------------*/
/* \fn df_download */
/* \brief load the content of the dataflash */
/*----------------------------------------------------------------------*/
static int df_download(AT91PS_DF pDf, unsigned int img_addr, unsigned int img_size, unsigned int img_dest)
{
/* read bytes in the dataflash */
df_read(pDf, img_addr,(unsigned char *)img_dest, img_size);
/* wait the dataflash ready status */
df_wait_ready(pDf);
return 0;
}
/*----------------------------------------------------------------------*/
/* \fn df_probe */
/* \brief Returns DataFlash ID */
/*----------------------------------------------------------------------*/
static int df_probe(AT91PS_DF pDf)
{
char *pResult = (char *)(pDf->command);
df_get_status(pDf);
return (pResult[1] & 0x3C);
}
/*----------------------------------------------------------------------*/
/* \fn df_init */
/* \brief This function tries to identify the DataFlash connected */
/*----------------------------------------------------------------------*/
static int df_init (AT91PS_DF pDf)
{
int dfcode = 0;
int status = 1;
/* Default: AT45DB321B */
pDf->dfDescription.pages_number = 8192;
pDf->dfDescription.pages_size = 528;
pDf->dfDescription.page_offset = 10;
dfcode = df_probe (pDf);
switch (dfcode)
{
/* case AT45DB011B:
pDf->dfDescription.pages_number = 512;
pDf->dfDescription.pages_size = 264;
pDf->dfDescription.page_offset = 9;
break;
case AT45DB021B:
pDf->dfDescription.pages_number = 1024;
pDf->dfDescription.pages_size = 264;
pDf->dfDescription.page_offset = 9;
break;
case AT45DB041B:
pDf->dfDescription.pages_number = 2048;
pDf->dfDescription.pages_size = 264;
pDf->dfDescription.page_offset = 9;
break;
case AT45DB081B:
pDf->dfDescription.pages_number = 4096;
pDf->dfDescription.pages_size = 264;
pDf->dfDescription.page_offset = 9;
break;
*/
case AT45DB161B:
pDf->dfDescription.pages_number = 4096;
pDf->dfDescription.pages_size = 528;
pDf->dfDescription.page_offset = 10;
break;
case AT45DB321B:
pDf->dfDescription.pages_number = 8192;
pDf->dfDescription.pages_size = 528;
pDf->dfDescription.page_offset = 10;
break;
case AT45DB642:
pDf->dfDescription.pages_number = 8192;
pDf->dfDescription.pages_size = 1056;
pDf->dfDescription.page_offset = 11;
break;
/*
case AT45DB1282:
pDf->dfDescription.pages_number = 16384;
pDf->dfDescription.pages_size = 1056;
pDf->dfDescription.page_offset = 11;
break;
case AT45DB2562:
pDf->dfDescription.pages_number = 16384;
pDf->dfDescription.pages_size = 2112;
pDf->dfDescription.page_offset = 12;
break;
case AT45DB5122:
pDf->dfDescription.pages_number = 32768;
pDf->dfDescription.pages_size = 2112;
pDf->dfDescription.page_offset = 12;
break;
*/
default:
status = 0;
break;
}
return status;
}
/*------------------------------------------------------------------------------*/
/* \fn df_is_boot_valid */
/* \brief Check that the first bytes of the buffer are valid ARM vectors */
/*------------------------------------------------------------------------------*/
static signed int df_is_boot_valid(unsigned char *buffer)
{
int i = 3;
/* Verify if the 28 first bytes of the sram correspond to ARM vectors
The sixth ARM vector contain the size of the code */
while(i < 28)
{
if (i != 23)
{
if ((buffer[i] != 0xEA) && (buffer[i] != 0xE5) )
return -1;
}
i+=4;
}
return 0;
}
/*------------------------------------------------------------------------------*/
/* \fn load_df */
/* \brief This function loads dataflash content to specified address */
/*------------------------------------------------------------------------------*/
int load_df(unsigned int pcs, unsigned int img_addr, unsigned int img_size, unsigned int img_dest)
{
AT91S_DF sDF;
AT91PS_DF pDf = (AT91PS_DF)&sDF;
unsigned int rxBuffer[128];
pDf->bSemaphore = UNLOCKED;
df_spi_init(pcs, DF_CS_SETTINGS);
if (!df_init(pDf)) {
return -1;
}
#ifdef AT91SAM9260
/* Test if a button has been pressed or not */
/* Erase Page 0 to avoid infinite loop */
df_recovery(pDf);
#endif
df_continuous_read(pDf, (char *)rxBuffer, 32, img_addr);
df_wait_ready(pDf);
if (df_is_boot_valid((unsigned char*)rxBuffer)) {
// return -2;
}
return df_download(pDf, img_addr, img_size, img_dest);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -