pretty print EEPROM
[cortex-from-scratch] / drivers / at24c.c
1 /* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL
2  * 
3  * $LOG$
4  * 2019/8/11 - ROBIN KRENS      
5  * Initial version 
6  * 
7  * $DESCRIPTION$
8  * Driver for AT24C256 EEPROM for STM32 based boards. Communication protocol is I2C
9  * Maximum write in limited to 64 bytes. Reading bytes is unlimited, but memory should
10  * be allocated accordingly. 
11  *
12  * I2C protocol : (W)rite or (R)ead 
13  * MCU is in master mode: either as transmitter or receiver
14  * | P | DEVICEADDR + R/W bit | ACK | ADDR_PART1 | ACK | ADDR_PART2 | (d+a*n) | (N)ACK | S
15  * Sending data: wait for ACK from EEPROM
16  * Receiving data: send (n)ACK to EEPROM after receiving data
17  *
18  * STM32F1 microcontrollers do not provide the ability to pull-up SDA and SCL lines. Their
19  * GPIOs must be configured as open-drain. So, you have to add two additional resistors to
20  * pull-up I2C lines. Something between 4K and 10K is a proven value. 
21  *
22  * */
23
24 #include <stdbool.h>
25 #include <stddef.h>
26 #include <stdint.h>
27
28 #include <sys/mmap.h>
29 #include <sys/robsys.h>
30
31 #include <lib/regfunc.h>
32 #include <lib/string.h>
33 #include <lib/tinyprintf.h>
34
35 #include <drivers/at24c.h>
36
37 #define TIMEOUT 5000
38 #define READ_CMD        0xA1
39 #define WRITE_CMD       0xA0
40 #define PAGE 64         /* Bytes that can be written continiously */
41 #define BUFFER 64       /* Reading buffer */
42
43
44 static char eeprombuf[BUFFER];
45
46 void eeprom_at24c_init() {
47
48  /* Program the peripheral input clock generate correct timings. 
49   * Configure the clock control registers CCR
50   * Configure the rise time register TRIS
51   * Program the I2C_CR1 register to enable the peripheral 
52   * Enable GPIOB6 and B7*/
53
54  rsetbit(RCC_APB1ENR, 21); // enable GPIOB
55  rsetbit(RCC_APB2ENR, 3); // enable I2C
56  rwrite(GPIOB_CRL, 0xEE444444); // open-drain
57  rsetbitsfrom(I2C_CR2, 0, 0x2); // 2 MHz 
58  rwrite(I2C_TRISE, 0x3); // MAX = 1000ns, TPCLK1 = 500ns (+1)
59  rwrite(I2C_CCR, 0x000A); // standard mode
60  rsetbit(I2C_CR2, 10); // buffer interrupt
61  rsetbit(I2C_CR1, 0); // enable
62
63
64 }
65
66 /* Writes data to the EEPROM starting at address addr. Size can not
67  * be more than one PAGE (64 bytes)  */
68 int eeprom_write(uint16_t addr, char * data, size_t size) {
69         
70         if(size > PAGE) {
71                 printf("Error: Maximum writable page size: %d\n", PAGE);
72                 return -1;
73         }
74
75         uint8_t hi_lo[] = { (uint8_t)(addr >> 8), (uint8_t)addr }; 
76         
77         start_condition();
78         rwrite(I2C_DR, WRITE_CMD);
79         if(!ack_recv()) 
80                 return -1;
81         
82
83         rwrite(I2C_DR, hi_lo[0]); // higher part of address
84         if(!buf_empty()) 
85                 return -1;
86         
87         rwrite(I2C_DR,hi_lo[1]); // lower part of address
88         if(!buf_empty()) 
89                 return -1;
90         
91
92         for (int i = 0; i < size; i++) {
93                 rwrite(I2C_DR, *data++);
94                 if(!buf_empty()) 
95                         return -1;
96                         
97         }
98
99         stop_condition();
100         delay(); // wait for write action to finish     
101         return 0;
102 }
103
104 /* Erase (write all 0xFF) data on EEPROM
105  * Maximum hardware allowed sequential writes of 64 bytes */
106 int eeprom_erase() {
107         
108         uint16_t cur_addr = 0x0000;
109
110         for (int i = 0; i < 512; i++) {
111                 
112                 printf("Writing at address: %#x (64 bytes) ", cur_addr);
113                 uint8_t hi_lo[] = { (uint8_t)(cur_addr >> 8), (uint8_t)cur_addr }; 
114         
115                 start_condition();
116                 rwrite(I2C_DR, WRITE_CMD);
117                 if(!ack_recv()) 
118                         return -1;
119         
120
121                 rwrite(I2C_DR, hi_lo[0]); // higher part of address
122                 if(!buf_empty()) 
123                         return -1;
124         
125                 rwrite(I2C_DR,hi_lo[1]); // lower part of address
126                 if(!buf_empty()) 
127                         return -1;
128         
129
130                 for (int i = 0; i < PAGE; i++) {
131                 rwrite(I2C_DR, 0xFF); // write all ones
132                 if(!buf_empty()) 
133                         return -1;
134                         
135                 }
136                 stop_condition();
137                 printf("[COMPLETE]\n");
138                 cur_addr += 0x40; // 64 bytes; next PAGE
139                 delay(); // wait for write to finish
140         }
141         
142         return 0;
143 }
144
145 /* Random access read of num bytes
146  * Initialize dummy write first to set correct address location
147  * The read function differentiate between num = 1 num = 2 and num > 3
148  * Data is saved to rvalues */
149 int eeprom_read(uint16_t addr, int num, char * rvalues) {
150
151         uint8_t hi_lo[] = { (uint8_t)(addr >> 8), (uint8_t)addr }; 
152
153         /* Dummy write to set address */        
154         start_condition();
155         rwrite(I2C_DR, WRITE_CMD);
156         if(!ack_recv())
157                 return -1;
158
159         rwrite(I2C_DR, hi_lo[0]); // higher part of address
160         if(!buf_empty())
161                 return -1;
162
163         rwrite(I2C_DR,hi_lo[1]); // lower part of address
164         if(!buf_empty()) 
165                 return -1;
166         
167         stop_condition();
168         
169         delay(); // wait form EEPROM
170
171         switch(num) {
172                 case 1:
173                         start_condition(); // restart condition
174                         rwrite(I2C_DR, READ_CMD); // read? to address CMD
175                         if(!ack_recv())
176                                 return -1;
177                         stop_condition();
178         
179                         if(!data_recv())
180                                 return -1;
181
182                         rvalues[0] = (char) *I2C_DR;
183                         rvalues[1] = '\0';
184                         break;
185                 case 2:
186
187                         rsetbit(I2C_CR1, 10); // set ACK
188                         rsetbit(I2C_CR1, 11); // set POS
189                         start_condition(); // restart condition
190                         rwrite(I2C_DR, READ_CMD); // read to address CMD
191                         if(!ack_recv()) 
192                                 return -1;      
193                         rclrbit(I2C_CR1, 10); // clear ACK
194                         if(!late_recv()) 
195                                 return -1;
196                 
197                         stop_condition();
198                         
199                         rvalues[0] = (char) *I2C_DR;
200                         rvalues[1] = (char) *I2C_DR;
201                         rvalues[2] = '\0';
202                         break;
203
204                 default:
205                         rsetbit(I2C_CR1, 10); // set ACK
206                         start_condition(); // restart condition
207                         rwrite(I2C_DR, READ_CMD); // read to address CMD
208                         if(!ack_recv()) 
209                                 return -1;
210         
211                         for(int i = 0; i < num-3; i++) {
212                                 if(!data_recv()) 
213                                         return -1;
214                                 rvalues[i] = (char) *I2C_DR;
215                         }
216
217                         if(!late_recv()) 
218                                 return -1;
219                 
220                         rclrbit(I2C_CR1, 10);
221                         rvalues[num-3] = *I2C_DR;
222                         stop_condition();
223                         rvalues[num-2] = *I2C_DR;
224                         if(!data_recv()) 
225                                 return -1;
226                 
227                         rvalues[num-1] = *I2C_DR;
228                         rvalues[num] = '\0';
229         }
230
231         return 0;
232
233 }
234
235 /* Dump all data on EEPROM to std out */
236 int eeprom_dump() {
237
238         uint16_t curr_addr = 0x0000;
239
240         for (int i = 0; i < 512; i++) {
241
242                 if(eeprom_read(curr_addr, 64, eeprombuf) == -1) {
243                         printf("Error: Can't (continue) dump");
244                         return -1;
245                 }
246                 printf("%#x:\n", curr_addr);
247                 for (int i = 0; i < strlen(eeprombuf); i++) {
248                         printf("%x ", eeprombuf[i]);
249                         if (((i % 16) == 0) && (i != 0))
250                                 printf("\n");
251                 }
252                 printf("\n");
253                 curr_addr += 0x40; // 64 bytes
254         }
255         return 0;
256
257 }
258
259 /* HELPER SUBROUTINES */
260
261 static void start_condition() {
262         rsetbit(I2C_CR1, 8); //start bit
263 }
264
265 static void stop_condition() {
266         rsetbit(I2C_CR1, 9); //stop bit
267 }
268
269 /* Initial ACK received after address lookup 
270  * read registers clear ADDR bit */
271 static int ack_recv() {
272         int cnt = 0;
273         while(!(*I2C_SR1 & 0x2)) {
274                 cnt++;
275                 if (cnt > TIMEOUT) {
276                         printf("Error: Can't reach device\n");
277                         return 0;
278                 }
279         }
280         int a = *I2C_SR2;
281         return 1;
282 }
283
284 /* Check send buffer
285  * Note: BLOCKING function */
286 static int buf_empty() {
287         int cnt = 0;
288         while(!(*I2C_SR1 & 0x80)) {
289                 cnt++;
290                 if (cnt > TIMEOUT) {
291                         printf("Error: Can't send data\n");
292                         return 0;
293                 }
294         }
295         return 1;
296 }
297
298 /* Check data receive buffer
299  * Note: BLOCKING function */
300 static int data_recv() {
301         int cnt = 0;
302         while(!(*I2C_SR1 & 0x40)) {
303                 cnt++;
304                 if (cnt > TIMEOUT) {
305                         printf("Error: Timeout receiving data\n");
306                         return 0;
307                 }
308         }
309         return 1;
310 }
311
312 /* Similar as above, waits for two packages to be received
313  * one in DR and one in the shadow register */
314 static int late_recv() {
315         int cnt = 0;
316         while(!(*I2C_SR1 & 0x4)) {
317                 cnt++;
318                 if (cnt > TIMEOUT) {
319                         printf("Error: Timeout receiving data\n");
320                         return 0;
321                 }
322         }
323         return 1;
324
325 }
326
327 /* Write delay form EEPROM chip */
328 static int delay() {
329         int a = 0;
330         for (int i = 0; i < 0xFFFF; i++)
331                 a++;
332 }
333
334
335 int eeprom_test() {
336         char * gd = "Testing the EEPROM chip AT24C256 write and read function";
337         eeprom_write(0x1000, gd, strlen(gd));
338         
339         uint16_t curr_addr = 0x1000;
340
341         for (int i = 0; i < 4; i++) {
342
343                 if(eeprom_read(curr_addr, 16, eeprombuf) == -1) {
344                         printf("Can't (continue) dump");
345                         return -1;
346                 }
347                 printf("%#x: ", curr_addr);
348                 for (int i = 0; i < strlen(eeprombuf); i++) {
349                         printf("%x ", eeprombuf[i]);
350                 }
351                 printf("\n");
352                 curr_addr += 0x10; // 16 bytes
353         }
354 }
355