| /****************************************************************************** |
| * |
| * Filename: eeprom.c |
| * |
| * Instantiation of eeprom routines |
| * |
| * Revision information: |
| * |
| * 28AUG2004 kb_admin initial creation - adapted from Atmel sources |
| * 12JAN2005 kb_admin fixed clock generation, write polling, init |
| * |
| * BEGIN_KBDD_BLOCK |
| * No warranty, expressed or implied, is included with this software. It is |
| * provided "AS IS" and no warranty of any kind including statutory or aspects |
| * relating to merchantability or fitness for any purpose is provided. All |
| * intellectual property rights of others is maintained with the respective |
| * owners. This software is not copyrighted and is intended for reference |
| * only. |
| * END_BLOCK |
| * |
| * $FreeBSD$ |
| *****************************************************************************/ |
| |
| #include "at91rm9200_lowlevel.h" |
| #include "at91rm9200.h" |
| #include "lib.h" |
| |
| /******************************* GLOBALS *************************************/ |
| |
| |
| /*********************** PRIVATE FUNCTIONS/DATA ******************************/ |
| |
| |
| /* Use a macro to calculate the TWI clock generator value to save code space. */ |
| #define AT91C_TWSI_CLOCK 100000 |
| #define TWSI_EEPROM_ADDRESS 0x50 |
| |
| #define TWI_CLK_BASE_DIV ((AT91C_MASTER_CLOCK/(4*AT91C_TWSI_CLOCK)) - 2) |
| #define SET_TWI_CLOCK ((0x00010000) | (TWI_CLK_BASE_DIV) | (TWI_CLK_BASE_DIV << 8)) |
| |
| |
| /*************************** GLOBAL FUNCTIONS ********************************/ |
| |
| |
| /* |
| * .KB_C_FN_DEFINITION_START |
| * void InitEEPROM(void) |
| * This global function initializes the EEPROM interface (TWI). Intended |
| * to be called a single time. |
| * .KB_C_FN_DEFINITION_END |
| */ |
| void |
| InitEEPROM(void) |
| { |
| |
| AT91PS_TWI twiPtr = (AT91PS_TWI)AT91C_BASE_TWI; |
| |
| AT91PS_PIO pPio = (AT91PS_PIO)AT91C_BASE_PIOA; |
| AT91PS_PMC pPMC = (AT91PS_PMC)AT91C_BASE_PMC; |
| |
| pPio->PIO_ASR = AT91C_PIO_PA25 | AT91C_PIO_PA26; |
| pPio->PIO_PDR = AT91C_PIO_PA25 | AT91C_PIO_PA26; |
| |
| pPio->PIO_MDDR = ~AT91C_PIO_PA25; |
| pPio->PIO_MDER = AT91C_PIO_PA25; |
| |
| pPMC->PMC_PCER = 1u << AT91C_ID_TWI; |
| |
| twiPtr->TWI_IDR = 0xffffffffu; |
| twiPtr->TWI_CR = AT91C_TWI_SWRST; |
| twiPtr->TWI_CR = AT91C_TWI_MSEN | AT91C_TWI_SVDIS; |
| |
| twiPtr->TWI_CWGR = SET_TWI_CLOCK; |
| } |
| |
| |
| /* |
| * .KB_C_FN_DEFINITION_START |
| * void ReadEEPROM(unsigned ee_addr, char *data_addr, unsigned size) |
| * This global function reads data from the eeprom at ee_addr storing data |
| * to data_addr for size bytes. Assume the TWI has been initialized. |
| * This function does not utilize the page read mode to simplify the code. |
| * .KB_C_FN_DEFINITION_END |
| */ |
| int |
| ReadEEPROM(unsigned ee_off, unsigned char *data_addr, unsigned size) |
| { |
| const AT91PS_TWI twiPtr = AT91C_BASE_TWI; |
| unsigned int status; |
| unsigned int count; |
| |
| status = twiPtr->TWI_SR; |
| status = twiPtr->TWI_RHR; |
| |
| // Set the TWI Master Mode Register |
| twiPtr->TWI_MMR = (TWSI_EEPROM_ADDRESS << 16) | |
| AT91C_TWI_IADRSZ_2_BYTE | AT91C_TWI_MREAD; |
| |
| // Set TWI Internal Address Register |
| twiPtr->TWI_IADR = ee_off; |
| |
| // Start transfer |
| twiPtr->TWI_CR = AT91C_TWI_START; |
| |
| status = twiPtr->TWI_SR; |
| |
| while (size-- > 1){ |
| // Wait RHR Holding register is full |
| count = 1000000; |
| while (!(twiPtr->TWI_SR & AT91C_TWI_RXRDY) && --count > 0) |
| continue; |
| if (count <= 0) |
| return -1; |
| |
| // Read byte |
| *(data_addr++) = twiPtr->TWI_RHR; |
| } |
| |
| twiPtr->TWI_CR = AT91C_TWI_STOP; |
| |
| status = twiPtr->TWI_SR; |
| |
| // Wait transfer is finished |
| while (!(twiPtr->TWI_SR & AT91C_TWI_TXCOMP)) |
| continue; |
| |
| // Read last byte |
| *data_addr = twiPtr->TWI_RHR; |
| return 0; |
| } |
| |
| |
| /* |
| * .KB_C_FN_DEFINITION_START |
| * void WriteEEPROM(unsigned ee_off, char *data_addr, unsigned size) |
| * This global function writes data to the eeprom at ee_off using data |
| * from data_addr for size bytes. Assume the TWI has been initialized. |
| * This function does not utilize the page write mode as the write time is |
| * much greater than the time required to access the device for byte-write |
| * functionality. This allows the function to be much simpler. |
| * .KB_C_FN_DEFINITION_END |
| */ |
| void |
| WriteEEPROM(unsigned ee_off, char *data_addr, unsigned size) |
| { |
| const AT91PS_TWI twiPtr = AT91C_BASE_TWI; |
| unsigned status; |
| unsigned char test_data; |
| |
| while (size--) { |
| if (!(ee_off & 0x3f)) |
| putchar('.'); |
| |
| // Set the TWI Master Mode Register |
| twiPtr->TWI_MMR = ((TWSI_EEPROM_ADDRESS << 16) | |
| AT91C_TWI_IADRSZ_2_BYTE) & ~AT91C_TWI_MREAD; |
| |
| // Set TWI Internal Address Register |
| twiPtr->TWI_IADR = ee_off++; |
| |
| status = twiPtr->TWI_SR; |
| |
| twiPtr->TWI_THR = *(data_addr++); |
| |
| twiPtr->TWI_CR = AT91C_TWI_START; |
| |
| // Wait transfer is finished |
| while (!(twiPtr->TWI_SR & AT91C_TWI_TXRDY)) |
| continue; |
| |
| twiPtr->TWI_CR = AT91C_TWI_STOP; |
| |
| status = twiPtr->TWI_SR; |
| |
| // Wait transfer is finished |
| while (!(twiPtr->TWI_SR & AT91C_TWI_TXCOMP)) |
| continue; |
| |
| // wait for write operation to complete |
| ReadEEPROM(ee_off, &test_data, 1); |
| } |
| |
| putchar('\r'); |
| putchar('\n'); |
| } |