summaryrefslogtreecommitdiff
path: root/m0EEPROM.cpp
blob: 306e017aa24d53cca86083343e260d7386febb19 (plain)
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
// m0EEPROM.cpp - implementation of eeprom memory library
//

#include "Arduino.h"
#include "Wire.h"
#include "RingBuffer.h" // for SERIAL_BUFFER_SIZE

#include "m0EEPROM.h"

#define PAGE_SIZE 64 // page size of the 24LC256 in bytes

// get the uint log based 2 of the number.
uint8_t log2uint(uint32_t v) {
  uint32_t z = 0;
  while (v >>=1) z++;
  return z;
}

// read a byte from the specified address in eeprom memory
uint8_t eeprom::read_byte(uint16_t address) {
  uint8_t rdata = 0xFF;
   
  Wire.beginTransmission(_device_address);
  Wire.write((int)(address >> 8));   // MSB
  Wire.write((int)(address & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(_device_address,1);
           
  if (Wire.available()) rdata = Wire.read();
             
  return rdata;

}

// write a single byte of data to the given address in eeprom memory
void eeprom::write_byte(uint16_t address, uint8_t value) {
  Wire.beginTransmission(_device_address);
    
  Wire.write((int)(address >> 8));   // MSB
  Wire.write((int)(address & 0xFF)); // LSB
        
  size_t wresult = Wire.write((int)value);
  if (wresult == 0){
//    Serial.print("wire write error = "); Serial.println(wresult);
  }

  uint8_t result = Wire.endTransmission();
  if (result){
//   Serial.print("wire endTransmission error = "); Serial.println(result);
  }
  delay(6); // at least 5ms for quiescence
}

// read a structure of arbitrary size from address.
// the size of the structure must be less than 64K-address.
// returns a byte array of memory specified.  The byte array data
// must be preallocated to the expected size.
uint8_t* eeprom::read_bytes(uint16_t address, uint8_t* data, uint16_t size) {
  unsigned char i=0;
  Wire.beginTransmission(_device_address);
  Wire.write((int)(address >> 8));   // MSB
  Wire.write((int)(address & 0xFF)); // LSB
  Wire.endTransmission();

  Wire.requestFrom(_device_address, size);

  while(Wire.available()) data[i++] = Wire.read();

  return data;
}

//  write a structure of arbitrary size to memory at address.
//  the size of the structure must be less than 64K-address - start_address.
//  The structure is passed as a byte array.
void eeprom::write_bytes(uint16_t start_address, uint8_t* data, uint16_t size) {
  // Uses Page Write for 24LC256
  // Allows for EEPROM_PAGE_SIZE byte page boundary
  // Splits string into max BUFFER_SIZE byte writes
  uint32_t  first_page_size;
  unsigned int  num_writes;
  uint8_t first_write_size=0;
  uint8_t last_write_size=0;
  uint16_t write_size=0;
                      
  // get the amount of memory to write in the first page of eeprom
  uint8_t page_bits = log2uint(PAGE_SIZE);
  first_page_size = ((start_address >> page_bits) +1) * PAGE_SIZE - start_address;
  
  // get the size of the first write based on the I2C buffer size
  uint8_t buffer_bits = log2uint(SERIAL_BUFFER_SIZE);
  if (first_page_size > SERIAL_BUFFER_SIZE){
      first_write_size = first_page_size - (first_page_size >> buffer_bits) * SERIAL_BUFFER_SIZE;
      if (first_write_size == 0) first_write_size = SERIAL_BUFFER_SIZE;
  }
  else
      first_write_size = first_page_size;

  // now get the size of the last write in the final page 
  // and the total number of pages to write.
  if (size > first_write_size){
      last_write_size = (size - first_write_size) % SERIAL_BUFFER_SIZE;
      num_writes = ((size - first_write_size) >> (buffer_bits)) + 2;
  }
  else
      num_writes = 1;

  //  Write loop
  uint16_t  address = start_address;
  uint8_t i = 0;
  for (uint32_t page = 0; page < num_writes; ++page){
      if(page==0) 
          write_size = first_write_size;
      else if (page == (num_writes-1)) 
          write_size = last_write_size;
      else write_size = SERIAL_BUFFER_SIZE;

      // I2C handshake and comms happens here 
      Wire.beginTransmission(_device_address);
      Wire.write((int)((address) >> 8));   // MSB
      Wire.write((int)((address) & 0xFF)); // LSB
      for (uint8_t counter=0; counter<write_size; ++counter,++i){
          Wire.write(data[i]);
     }
     Wire.endTransmission();
     address += write_size;

     delay(6);  // needs 5ms for page write
  }
}

eeprom Eeprom;