1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
/******************************************************************************
*
* 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_PA25_TWD | AT91C_PA26_TWCK;
pPio->PIO_PDR = AT91C_PA25_TWD | AT91C_PA26_TWCK;
pPio->PIO_MDDR = ~AT91C_PA25_TWD;
pPio->PIO_MDER = AT91C_PA25_TWD;
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
*/
void
ReadEEPROM(unsigned ee_addr, char *data_addr, unsigned size)
{
const AT91PS_TWI twiPtr = AT91C_BASE_TWI;
unsigned int status;
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_addr;
// Start transfer
twiPtr->TWI_CR = AT91C_TWI_START;
status = twiPtr->TWI_SR;
while (size-- > 1){
// Wait RHR Holding register is full
while (!(twiPtr->TWI_SR & AT91C_TWI_RXRDY))
continue;
// 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;
}
/*
* .KB_C_FN_DEFINITION_START
* void WriteEEPROM(unsigned ee_addr, char *data_addr, unsigned size)
* This global function writes data to the eeprom at ee_addr 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_addr, char *data_addr, unsigned size)
{
const AT91PS_TWI twiPtr = AT91C_BASE_TWI;
unsigned status;
char test_data;
while (size--) {
if (!(ee_addr & 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_addr++;
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_addr, &test_data, 1);
}
putchar('\r');
putchar('\n');
}
|