From 482b39a98fb736be26b8ad09d9d4620871eaa235 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 30 Jul 2011 19:31:47 +0200 Subject: add basic-dataflash-example --- basic-dataflash-project/Makefile | 152 +++++++++++++ basic-dataflash-project/bin/.empty | 0 basic-dataflash-project/main.c | 434 +++++++++++++++++++++++++++++++++++++ basic-dataflash-project/obj/.empty | 0 4 files changed, 586 insertions(+) create mode 100644 basic-dataflash-project/Makefile create mode 100644 basic-dataflash-project/bin/.empty create mode 100644 basic-dataflash-project/main.c create mode 100644 basic-dataflash-project/obj/.empty diff --git a/basic-dataflash-project/Makefile b/basic-dataflash-project/Makefile new file mode 100644 index 0000000..63de4ee --- /dev/null +++ b/basic-dataflash-project/Makefile @@ -0,0 +1,152 @@ +# ---------------------------------------------------------------------------- +# ATMEL Microcontroller Software Support +# ---------------------------------------------------------------------------- +# Copyright (c) 2008, 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 disclaimer below. +# +# 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. +# ---------------------------------------------------------------------------- + +# Makefile for compiling basic-dataflash-project + +#------------------------------------------------------------------------------- +# User-modifiable options +#------------------------------------------------------------------------------- + +# Chip & board used for compilation +# (can be overriden by adding CHIP=chip and BOARD=board to the command-line) +CHIP = at91sam7s128 +BOARD = simtrace + +# Trace level used for compilation +# (can be overriden by adding TRACE_LEVEL=#number to the command-line) +# TRACE_LEVEL_DEBUG 5 +# TRACE_LEVEL_INFO 4 +# TRACE_LEVEL_WARNING 3 +# TRACE_LEVEL_ERROR 2 +# TRACE_LEVEL_FATAL 1 +# TRACE_LEVEL_NO_TRACE 0 +TRACE_LEVEL = 4 + +# Optimization level, put in comment for debugging +OPTIMIZATION = -Os + +# AT91 library directory +AT91LIB = ../at91lib + +# Output file basename +OUTPUT = basic-dataflash-project-$(BOARD)-$(CHIP) + +# Compile for all memories available on the board (this sets $(MEMORIES)) +include $(AT91LIB)/boards/$(BOARD)/board.mak + +# Output directories +BIN = bin +OBJ = obj + +#------------------------------------------------------------------------------- +# Tools +#------------------------------------------------------------------------------- + +# Tool suffix when cross-compiling +CROSS_COMPILE = arm-elf- + +# Compilation tools +CC = $(CROSS_COMPILE)gcc +SIZE = $(CROSS_COMPILE)size +STRIP = $(CROSS_COMPILE)strip +OBJCOPY = $(CROSS_COMPILE)objcopy + +# Flags +INCLUDES = -I$(AT91LIB)/boards/$(BOARD) -I$(AT91LIB)/peripherals +INCLUDES += -I$(AT91LIB)/memories -I$(AT91LIB) + +CFLAGS = -Wall -mlong-calls -ffunction-sections +CFLAGS += -g $(OPTIMIZATION) $(INCLUDES) -D$(CHIP) -DTRACE_LEVEL=$(TRACE_LEVEL) +ASFLAGS = -g $(OPTIMIZATION) $(INCLUDES) -D$(CHIP) -D__ASSEMBLY__ +LDFLAGS = -g $(OPTIMIZATION) -nostartfiles -Wl,--gc-sections + +#------------------------------------------------------------------------------- +# Files +#------------------------------------------------------------------------------- + +# Directories where source files can be found +PERIPH = $(AT91LIB)/peripherals +MEM = $(AT91LIB)/memories +BOARDS = $(AT91LIB)/boards +UTILITY = $(AT91LIB)/utility + +VPATH += $(MEM)/spi-flash +VPATH += $(UTILITY) +VPATH += $(PERIPH)/dbgu $(PERIPH)/pio $(PERIPH)/aic $(PERIPH)/pmc +VPATH += $(PERIPH)/cp15 +VPATH += $(BOARDS)/$(BOARD) $(BOARDS)/$(BOARD)/$(CHIP) + +# Objects built from C source files +C_OBJECTS = main.o +C_OBJECTS += spid.o at45.o +C_OBJECTS += string.o stdio.o +C_OBJECTS += dbgu.o pio.o aic.o pmc.o cp15.o +C_OBJECTS += board_memories.o board_lowlevel.o + +# Objects built from Assembly source files +ASM_OBJECTS = board_cstartup.o +#ASM_OBJECTS += cp15_asm_gcc.o +ASM_OBJECTS += cp15_asm.o + +# Append OBJ and BIN directories to output filename +OUTPUT := $(BIN)/$(OUTPUT) + +#------------------------------------------------------------------------------- +# Rules +#------------------------------------------------------------------------------- + +all: $(BIN) $(OBJ) $(MEMORIES) + +$(BIN) $(OBJ): + mkdir $@ + +define RULES +C_OBJECTS_$(1) = $(addprefix $(OBJ)/$(1)_, $(C_OBJECTS)) +ASM_OBJECTS_$(1) = $(addprefix $(OBJ)/$(1)_, $(ASM_OBJECTS)) + +$(1): $$(ASM_OBJECTS_$(1)) $$(C_OBJECTS_$(1)) + $(CC) $(LDFLAGS) -T"$(AT91LIB)/boards/$(BOARD)/$(CHIP)/$$@.lds" -o $(OUTPUT)-$$@.elf $$^ + $(OBJCOPY) -O binary $(OUTPUT)-$$@.elf $(OUTPUT)-$$@.bin + $(SIZE) $$^ $(OUTPUT)-$$@.elf + +$$(C_OBJECTS_$(1)): $(OBJ)/$(1)_%.o: %.c Makefile $(OBJ) $(BIN) + $(CC) $(CFLAGS) -D$(1) -c -o $$@ $$< + +$$(ASM_OBJECTS_$(1)): $(OBJ)/$(1)_%.o: %.S Makefile $(OBJ) $(BIN) + $(CC) $(ASFLAGS) -D$(1) -c -o $$@ $$< + +debug_$(1): $(1) + perl ../resources/gdb/debug.pl $(OUTPUT)-$(1).elf + +endef + +$(foreach MEMORY, $(MEMORIES), $(eval $(call RULES,$(MEMORY)))) + +clean: + -rm -f $(OBJ)/*.o $(BIN)/*.bin $(BIN)/*.elf + diff --git a/basic-dataflash-project/bin/.empty b/basic-dataflash-project/bin/.empty new file mode 100644 index 0000000..e69de29 diff --git a/basic-dataflash-project/main.c b/basic-dataflash-project/main.c new file mode 100644 index 0000000..f30f263 --- /dev/null +++ b/basic-dataflash-project/main.c @@ -0,0 +1,434 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, 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 disclaimer below. + * + * 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. + * ---------------------------------------------------------------------------- + */ +//------------------------------------------------------------------------------ +/// \dir "Basic-dataflash-project" +/// +/// !!!Purpose +/// +/// The Basic Dataflash project will help new users get familiar with SPI interface +/// on Atmel's AT91 family of microcontrollers. This project gives you an AT45 +/// Dataflash programming code so that can help develop your own SPI devices +/// applications with maximum efficiency. +/// +/// You can find following information depends on your needs: +/// - A Spi low level driver performs SPI device Initializes, data transfer and +/// receive. It can be used by upper SPI driver such as AT45 %dataflash. +/// - A Dataflash driver is based on top of the corresponding Spi driver. +/// It allow user to do operations with %dataflash in a unified way. +/// +/// !See also +/// - "spi-flash": Dataflash interface driver. +/// +/// !!!Requirements +/// +/// This package can be used with all Atmel evaluation kits that have SPI +/// interface and on-board or external Serialflash connected. The package runs at +/// SRAM or SDRAM, so SDRAM device is needed if you want to run this package in SDRAM. +/// +/// +/// !!!Description +/// +/// The demonstration program tests the dataflash present on the evaluation kit by +/// erasing and writing each one of its pages. +/// +/// !!!Usage +/// +/// -# Build the program and download it inside the evaluation board. Please +/// refer to the SAM-BA User Guide, +/// the GNU-Based Software Development +/// application note or to the IAR EWARM User Guide, +/// depending on your chosen solution. +/// -# On the computer, open and configure a terminal application +/// (e.g. HyperTerminal on Microsoft Windows) with these settings: +/// - 115200 bauds +/// - 8 bits of data +/// - No parity +/// - 1 stop bit +/// - No flow control +/// -# Start the application. +/// -# Upon startup, the application will output the following lines on the DBGU. +/// \code +/// -- Basic Dataflash Project xxx -- +/// -- AT91xxxxxx-xx +/// -- Compiled: xxx xx xxxx xx:xx:xx -- +/// -I- Initializing the SPI and AT45 drivers +/// -I- At45 enabled +/// -I- SPI interrupt enabled +/// -I- Waiting for a dataflash to be connected ... +/// \endcode +/// -# As soon as a dataflash is connected, the tests will start. Eventually, +/// the test result (pass or fail) will be output on the DBGU. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !Purpose +/// +/// This file contains all the specific code for the basic-dataflash-project. +/// It tests the dataflash present on the evaluation kit by erasing and writing +/// each one of its pages +/// +/// !Contents +/// The code can be roughly broken down as follows: +/// - AT45 Dataflash write data function. +/// - AT45 Dataflash read data function. +/// - AT45 Dataflash erase function. +/// - Other AT45 functions (such as AT45_GetStatus()) +/// - The main() function, which implements the program behavior. +/// - Initializes an AT45 instance and configures SPI chip select pin. +/// - Config SPI Interrupt Service Routine. +/// - Identifier the AT45 device connected to the evaluation kit. +/// - Test the dataflash by erasing and writing each one of its pages. +/// +/// !See also +/// - "spi-flash": Dataflash interface driver. +/// Please refer to the list of functions in the #Overview# tab of this unit +/// for more detailed information. +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include + +#include + +//------------------------------------------------------------------------------ +// Local definitions +//------------------------------------------------------------------------------ + +/// SPI clock frequency, in Hz. +#define SPCK 1000000 + +/// If there is no on-board dataflash socket, use SPI0/NPCS0. +#ifndef BOARD_AT45_A_SPI_PINS + #ifdef AT91C_BASE_SPI0 + #define BOARD_AT45_A_SPI_BASE AT91C_BASE_SPI0 + #define BOARD_AT45_A_SPI_ID AT91C_ID_SPI0 + #define BOARD_AT45_A_SPI_PINS PINS_SPI0 + #define BOARD_AT45_A_NPCS_PIN PIN_SPI0_NPCS0 + #else + #define BOARD_AT45_A_SPI_BASE AT91C_BASE_SPI + #define BOARD_AT45_A_SPI_ID AT91C_ID_SPI + #define BOARD_AT45_A_SPI_PINS PINS_SPI + #define BOARD_AT45_A_NPCS_PIN PIN_SPI_NPCS0 + #endif + #define BOARD_AT45_A_SPI 0 + #define BOARD_AT45_A_NPCS 0 +#endif + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// SPI driver instance. +static Spid spid; + +/// AT45 driver instance. +static At45 at45; + +/// Pins used by the application. +static const Pin pins[] = {BOARD_AT45_A_SPI_PINS, BOARD_AT45_A_NPCS_PIN}; + +/// Page buffer. +static unsigned char pBuffer[2112]; + +//------------------------------------------------------------------------------ +// Internal functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// SPI interrupt handler. Invokes the SPI driver handler to check for pending +/// interrupts. +//------------------------------------------------------------------------------ +static void ISR_Spi(void) +{ + SPID_Handler(&spid); +} + +//------------------------------------------------------------------------------ +/// Retrieves and returns the At45 current status, or 0 if an error +/// happened. +/// \param pAt45 Pointer to a At45 driver instance. +//------------------------------------------------------------------------------ +static unsigned char AT45_GetStatus(At45 *pAt45) +{ + unsigned char error; + unsigned char status; + + // Sanity checks + ASSERT(pAt45, "-F- AT45_GetStatus: pAt45 is null\n\r"); + + // Issue a status register read command + error = AT45_SendCommand(pAt45, AT45_STATUS_READ, 1, &status, 1, 0, 0, 0); + ASSERT(!error, "-F- AT45_GetStatus: Failed to issue command.\n\r"); + + // Wait for command to terminate + while (AT45_IsBusy(pAt45)); + + return status; +} + +//------------------------------------------------------------------------------ +/// Waits for the At45 to be ready to accept new commands. +/// \param pAt45 Pointer to a At45 driver instance. +//------------------------------------------------------------------------------ +static void AT45_WaitReady(At45 *pAt45) +{ + unsigned char ready = 0; + + // Sanity checks + ASSERT(pAt45, "-F- AT45_WaitUntilReady: pAt45 is null\n\r"); + + // Poll device until it is ready + while (!ready) { + + ready = AT45_STATUS_READY(AT45_GetStatus(pAt45)); + } +} + +//------------------------------------------------------------------------------ +/// Reads and returns the JEDEC identifier of a At45. +/// \param pAt45 Pointer to a At45 driver instance. +//------------------------------------------------------------------------------ +static unsigned int AT45_GetJedecId(At45 *pAt45) +{ + unsigned char error; + unsigned int id; + + // Sanity checks + ASSERT(pAt45, "-F- AT45_GetJedecId: pAt45 is null\n\r"); + + // Issue a manufacturer and device ID read command + error = AT45_SendCommand(pAt45, AT45_ID_READ, 1, (void *) &id, 4, 0, 0, 0); + ASSERT(!error, "-F- AT45_GetJedecId: Could not issue command.\n\r"); + + // Wait for transfer to finish + while (AT45_IsBusy(pAt45)); + + return id; +} + +//------------------------------------------------------------------------------ +/// Reads data from the At45 inside the provided buffer. Since a continuous +/// read command is used, there is no restriction on the buffer size and read +/// address. +/// \param pAt45 Pointer to a At45 driver instance. +/// \param pBuffer Data buffer. +/// \param size Number of bytes to read. +/// \param address Address at which data shall be read. +//------------------------------------------------------------------------------ +static void AT45_Read( + At45 *pAt45, + unsigned char *pBuffer, + unsigned int size, + unsigned int address) +{ + unsigned char error; + + // Sanity checks + ASSERT(pAt45, "-F- AT45_Read: pAt45 is null\n\r"); + ASSERT(pBuffer, "-F- AT45_Read: pBuffer is null\n\r"); + + // Issue a continuous read array command + error = AT45_SendCommand(pAt45, AT45_CONTINUOUS_READ_LEG, 8, pBuffer, size, address, 0, 0); + ASSERT(!error, "-F- AT45_Read: Failed to issue command\n\r"); + + // Wait for the read command to execute + while (AT45_IsBusy(pAt45)); +} + +//------------------------------------------------------------------------------ +/// Writes data on the At45 at the specified address. Only one page of +/// data is written that way; if the address is not at the beginning of the +/// page, the data is written starting from this address and wraps around to +/// the beginning of the page. +/// \param pAt45 Pointer to a At45 driver instance. +/// \param pBuffer Buffer containing the data to write. +/// \param size Number of bytes to write. +/// \param address Destination address on the At45. +//------------------------------------------------------------------------------ +static void AT45_Write( + At45 *pAt45, + unsigned char *pBuffer, + unsigned int size, + unsigned int address) +{ + unsigned char error; + + // Sanity checks + ASSERT(pAt45, "-F- AT45_Write: pAt45 is null.\n\r"); + ASSERT(pBuffer, "-F- AT45_Write: pBuffer is null.\n\r"); + ASSERT(size <= pAt45->pDesc->pageSize, "-F- AT45_Write: Size too big\n\r"); + + // Issue a page write through buffer 1 command + error = AT45_SendCommand(pAt45, AT45_PAGE_WRITE_BUF1, 4, pBuffer, size, address, 0, 0); + ASSERT(!error, "-F- AT45_Write: Could not issue command.\n\r"); + + // Wait until the command is sent + while (AT45_IsBusy(pAt45)); + + // Wait until the At45 becomes ready again + AT45_WaitReady(pAt45); +} + +//------------------------------------------------------------------------------ +/// Erases a page of data at the given address in the At45. +/// \param pAt45 Pointer to a At45 driver instance. +/// \param address Address of page to erase. +//------------------------------------------------------------------------------ +static void AT45_Erase(At45 *pAt45, unsigned int address) +{ + unsigned char error; + + // Sanity checks + ASSERT(pAt45, "-F- AT45_Erase: pAt45 is null\n\r"); + + // Issue a page erase command. + error = AT45_SendCommand(pAt45, AT45_PAGE_ERASE, 4, 0, 0, address, 0, 0); + ASSERT(!error, "-F- AT45_Erase: Could not issue command.\n\r"); + + // Wait for end of transfer + while (AT45_IsBusy(pAt45)); + + // Poll until the At45 has completed the erase operation + AT45_WaitReady(pAt45); +} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Tests the At45 connected to the board by performing several command +/// on each of its pages. +//------------------------------------------------------------------------------ +int main() +{ + unsigned int i; + unsigned int page; + unsigned char testFailed; + const At45Desc *pDesc; + + // Configure pins + PIO_Configure(pins, PIO_LISTSIZE(pins)); + + // Configure traces + TRACE_CONFIGURE(DBGU_STANDARD, 115200, BOARD_MCK); + printf("-- Basic Dataflash Project %s --\n\r", SOFTPACK_VERSION); + printf("-- %s\n\r", BOARD_NAME); + printf("-- Compiled: %s %s --\n\r", __DATE__, __TIME__); + + // SPI and At45 driver initialization + TRACE_INFO("Initializing the SPI and AT45 drivers\n\r"); + AIC_ConfigureIT(BOARD_AT45_A_SPI_ID, 0, ISR_Spi); + SPID_Configure(&spid, BOARD_AT45_A_SPI_BASE, BOARD_AT45_A_SPI_ID); + SPID_ConfigureCS(&spid, BOARD_AT45_A_NPCS, AT45_CSR(BOARD_MCK, SPCK)); + AT45_Configure(&at45, &spid, BOARD_AT45_A_NPCS); + TRACE_INFO("At45 enabled\n\r"); + AIC_EnableIT(BOARD_AT45_A_SPI_ID); + TRACE_INFO("SPI interrupt enabled\n\r"); + + // Identify the At45 device + TRACE_INFO("Waiting for a dataflash to be connected ...\n\r"); + pDesc = 0; + while (!pDesc) { + + pDesc = AT45_FindDevice(&at45, AT45_GetStatus(&at45)); + } + TRACE_INFO("%s detected\n\r", at45.pDesc->name); + + // Output JEDEC identifier of device + TRACE_INFO("Device identifier: 0x%08X\n\r", AT45_GetJedecId(&at45)); + + // Test all pages + testFailed = 0; + page = 0; + while (!testFailed && (page < AT45_PageNumber(&at45))) { + + TRACE_INFO("Test in progress on page: %6u\r", page); + + // Erase page + AT45_Erase(&at45, page * AT45_PageSize(&at45)); + + // Verify that page has been erased correctly + memset(pBuffer, 0, AT45_PageSize(&at45)); + AT45_Read(&at45, pBuffer, AT45_PageSize(&at45), page * AT45_PageSize(&at45)); + for (i=0; i < AT45_PageSize(&at45); i++) { + + if (pBuffer[i] != 0xff) { + + TRACE_ERROR("Could not erase page %u\n\r", page); + testFailed = 1; + break; + } + } + + // Write page + for (i=0; i < AT45_PageSize(&at45); i++) { + + pBuffer[i] = i & 0xFF; + } + AT45_Write(&at45, pBuffer, AT45_PageSize(&at45), page * AT45_PageSize(&at45)); + + // Check that data has been written correctly + memset(pBuffer, 0, AT45_PageSize(&at45)); + AT45_Read(&at45, pBuffer, AT45_PageSize(&at45), page * AT45_PageSize(&at45)); + for (i=0; i < AT45_PageSize(&at45); i++) { + + if (pBuffer[i] != (i & 0xFF)) { + + TRACE_ERROR("Could not write page %u\n\r", page); + testFailed = 1; + break; + } + } + + page++; + } + + // Display test result + if (testFailed) { + + TRACE_ERROR("Test failed.\n\r"); + } + else { + + TRACE_INFO("Test passed.\n\r"); + } + + return 0; +} + diff --git a/basic-dataflash-project/obj/.empty b/basic-dataflash-project/obj/.empty new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3