Statistics
| Branch: | Tag: | Revision:

amiro-os / components / eeprom / at24.cpp @ 309980f0

History | View | Annotate | Download (5.809 KB)

1
#include <ch.hpp>
2
#include <hal.h>
3

    
4
#include <type_traits>
5

    
6
#include <amiro/bus/i2c/I2CDriver.hpp>
7
#include <amiro/bus/i2c/I2CParams.hpp>
8

    
9
#include <amiro/eeprom/at24.hpp>
10

    
11
#define AT24_GET_PAGE_OFFSET(_ADDRESS_, _PAGE_SIZE_) (_ADDRESS_ & (_PAGE_SIZE_ - 1u))
12

    
13
namespace amiro {
14

    
15
const struct BaseFileStreamVMT eeprom_at24_base_file_stream_methods = {
16

    
17
    /* .write       */ AT24::write,
18
    /* .read        */ AT24::read,
19
    /* .put         */ 0,
20
    /* .get         */ 0,
21
    /* .close       */ AT24::close,
22
    /* .geterror    */ EEPROM::geterror,
23
    /* .getsize     */ EEPROM::getsize,
24
    /* .getposition */ EEPROM::getposition,
25
    /* .lseek       */ EEPROM::lseek,
26

    
27
};
28

    
29
AT24::
30
AT24(size_t size, uint8_t page_size, uint16_t max_t_wr, I2CDriver* i2c_driver) :
31
  EEPROM(&eeprom_at24_base_file_stream_methods, size, page_size, max_t_wr, AT24_SLA, i2c_driver) {
32

    
33
}
34

    
35
AT24::
36
~AT24() {
37

    
38
}
39

    
40
msg_t
41
AT24::
42
poll_ack(void* instance) {
43

    
44
  EEPROM* bfs = (EEPROM*) instance;
45

    
46
  register I2CDriver* bfs_i2c_driver = bfs->i2c_driver;
47
  register msg_t ret_val = RDY_OK;
48
  register i2cflags_t i2c_err_flags;
49

    
50
  uint8_t dummy_buf[2];
51

    
52
  I2CRxParams i2c_rxparams;
53
  i2c_rxparams.addr = bfs->i2c_txparams.addr;
54
  i2c_rxparams.rxbuf = dummy_buf;
55
  i2c_rxparams.rxbytes = sizeof(dummy_buf);
56

    
57
  for (register uint16_t wr_time = 0x0000u; wr_time < bfs->max_t_wr; wr_time++) {
58

    
59
    bfs_i2c_driver->acquireBus();
60

    
61
    ret_val = bfs_i2c_driver->masterReceive(&i2c_rxparams);
62

    
63
    i2c_err_flags = bfs->i2c_driver->getErrors();
64

    
65
    bfs_i2c_driver->releaseBus();
66

    
67
    // Wait cycle over
68
    if (ret_val == RDY_OK)
69
      break;
70

    
71
    // Check for errors, ignoring only I2CD_ACK_FAILURE
72
    if (i2c_err_flags & ~I2CD_ACK_FAILURE) {
73
      break;
74
    }
75

    
76
    chThdSleepMicroseconds(10);
77

    
78
  }
79

    
80
  // This can only be the case when
81
  // * timeout reached
82
  // * i2cError other than I2CD_ACK_FAILURE within time limit
83
  if (ret_val != RDY_OK)
84
    bfs->error = i2c_err_flags;
85

    
86
  return ret_val;
87

    
88
}
89

    
90

    
91
size_t
92
AT24::
93
write(void* instance, const uint8_t* bp, size_t n) {
94

    
95
  EEPROM* bfs = (EEPROM*) instance;
96

    
97
  i2cflags_t i2c_err_flags;
98
  uint8_t i;
99
  uint8_t j;
100
  uint8_t scratchpad[2 + AT24_MAX_PAGE_SIZE];
101
  msg_t ret_val = RDY_OK;
102
  fileoffset_t cur_pos = bfs->position;
103

    
104
  register size_t tx_bytes;
105
  register const uint8_t* ptr = bp;
106
  register size_t num_bytes;
107
  register uint8_t page_size = bfs->page_size;
108
  register I2CTxParams* bfs_i2c_txparams = &bfs->i2c_txparams;
109

    
110
  // If no bytes are to be written, shortcut stop
111
  if (!n)
112
    return 0;
113

    
114
  // Clear error
115
  bfs->error = EEPROM_ERROR_NONE;
116

    
117
#if HAL_USE_I2C
118

    
119
  // number of bytes remaining in page starting at cur_pos
120
  // b/c of address rollover withing current page
121
  tx_bytes = AT24_GET_PAGE_OFFSET(cur_pos, page_size);
122
  // adjust for AT24_MAX_PAGE_SIZE < page_size
123
  tx_bytes = AT24_MAX_PAGE_SIZE - AT24_GET_PAGE_OFFSET(tx_bytes, AT24_MAX_PAGE_SIZE);
124

    
125
  for (num_bytes = n; num_bytes > 0;) {
126

    
127
    // write address
128
    i = 0;
129
    // Support for 16bit-addressable devices
130
    if (bfs->size > 0x0080u)
131
      scratchpad[i++] = (cur_pos >> 8) & 0xFFu;
132

    
133
    scratchpad[i++] = cur_pos & 0xFFu;
134

    
135
    // adjust number of bytes to transfer if end of buffer
136
    if (num_bytes < tx_bytes)
137
      tx_bytes = num_bytes;
138

    
139
    // copy data
140
    for (j = 0; j < tx_bytes; j++) {
141
      scratchpad[i++] = *ptr++;
142
    }
143

    
144
    // acknowledge polling
145

    
146
    // acknowledge polling and
147
    // address device
148
    for (register uint16_t wr_time = 0x0000u; wr_time < bfs->max_t_wr; wr_time++) {
149

    
150
      bfs->i2c_driver->acquireBus();
151

    
152
      bfs_i2c_txparams->txbuf = scratchpad;
153
      bfs_i2c_txparams->txbytes = i;
154
      bfs_i2c_txparams->rxbytes = 0;
155

    
156
      ret_val = bfs->i2c_driver->masterTransmit(bfs_i2c_txparams);
157

    
158
      i2c_err_flags = bfs->i2c_driver->getErrors();
159

    
160
      bfs->i2c_driver->releaseBus();
161

    
162
      // Write cycle over
163
      if (ret_val == RDY_OK)
164
        break;
165

    
166
      // Check for errors, ignoring only I2CD_ACK_FAILURE
167
      if (i2c_err_flags & ~I2CD_ACK_FAILURE) {
168
        break;
169
      }
170

    
171
      chThdSleepMicroseconds(10);
172

    
173
    }
174

    
175
    // This can only be the case when
176
    // * timeout reached
177
    // * i2cError other than I2CD_ACK_FAILURE within time limit
178
    if (ret_val != RDY_OK)
179
      break;
180

    
181
    cur_pos += tx_bytes;
182
    num_bytes -= tx_bytes;
183
    tx_bytes = AT24_MAX_PAGE_SIZE;
184

    
185
  }
186

    
187
  if (ret_val != RDY_OK)
188
    bfs->error = i2c_err_flags;
189

    
190
#endif
191

    
192
  bfs->position = cur_pos;
193

    
194
  // number of bytes to transfer - number of bytes not transferred
195
  return n - num_bytes;
196

    
197
}
198

    
199
size_t
200
AT24::
201
read(void* instance, uint8_t* bp, size_t n) {
202

    
203
  EEPROM* bfs = (EEPROM*) instance;
204

    
205
  uint8_t i;
206
  uint8_t scratchpad[2];
207
  msg_t ret_val;
208
  register I2CTxParams* bfs_i2c_txparams = &bfs->i2c_txparams;
209

    
210
  // If no bytes are to be read, shortcut stop
211
  if (!n)
212
    return 0;
213

    
214
  // Clear error
215
  bfs->error = EEPROM_ERROR_NONE;
216

    
217
#if HAL_USE_I2C
218

    
219
  // Fill address buffer
220
  i = 0;
221
  // Support for 16bit-addressable devices
222
  if (bfs->size > 0x0080u)
223
    scratchpad[i++] = (bfs->position >> 8) & 0xFFu;
224

    
225
  scratchpad[i++] = bfs->position & 0xFFu;
226

    
227
  // if device does not answer within timeout, don't read anything
228
  if (poll_ack(bfs) != RDY_OK)
229
    return 0;
230

    
231
  bfs->i2c_driver->acquireBus();
232

    
233
  bfs_i2c_txparams->txbuf = scratchpad;
234
  bfs_i2c_txparams->txbytes = i;
235
  bfs_i2c_txparams->rxbuf = bp;
236
  bfs_i2c_txparams->rxbytes = n;
237

    
238
  // address device
239
  // and read data
240
  ret_val = bfs->i2c_driver->masterTransmit(bfs_i2c_txparams);
241

    
242
  if (ret_val != RDY_OK)
243
    bfs->error = bfs->i2c_driver->getErrors();
244

    
245
  bfs->i2c_driver->releaseBus();
246

    
247
  // We cannot tell where I²C transfer went wrong
248
  // therefore report 0 bytes read
249
  if (ret_val != RDY_OK)
250
    return 0;
251

    
252
#endif
253

    
254
  return n;
255

    
256
}
257

    
258
/**
259
 * Close EEPROM device.
260
 * \note EEPROMs do not support close semantics.
261
 * \return FILE_OK Closing an EEPROM device will never fail.
262
 */
263
uint32_t
264
AT24::
265
close(void* instance) {
266

    
267
  (void) instance;
268
  return FILE_OK;
269

    
270
}
271

    
272
} /* amiro */