Statistics
| Branch: | Tag: | Revision:

amiro-os / components / eeprom / at24.cpp @ 753ccd04

History | View | Annotate | Download (5.809 KB)

1 58fe0e0b Thomas Schöpping
#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 */