ENTS-tock
Environmental NeTworked Sensor firmware on Tock OS
Loading...
Searching...
No Matches
mb85rc1mt.c
Go to the documentation of this file.
1
20#include "mb85rc1mt.h"
21
22#include <libtock/peripherals/i2c_master.h>
23#include <string.h>
24
25#include "fram.h"
26
28static const uint8_t g_base_addr = 0b10100000;
29
31static const int mb85rc1mt_pages = 1;
32
34static const int mb85rc1mt_seg_size = 1 << 17;
35
39typedef struct {
41 uint8_t dev;
43 uint16_t mem;
45
51
58
69static mb85rc1mt_address convert_address(fram_addr addr) {
70 mb85rc1mt_address i2c_addr;
71
72 // Upper address bits go into device address.
73 // Shift right by 15 to get bit 16 into position, mask to keep only
74 // relevant bits, OR with base address.
75 i2c_addr.dev = g_base_addr | ((addr >> 15) & 0x0E);
76 i2c_addr.mem = addr & 0xFFFF;
77
78 return i2c_addr;
79}
80
81fram_status mb85rc1mt_write(fram_addr addr, const uint8_t* data, size_t len) {
82 fram_status status = FRAM_OK;
83
84 while (len > 0) {
85 // convert fram address to i2c address
86 mb85rc1mt_address i2c_addr = convert_address(addr);
87
88 // wakeup device
89 status = mb85rc1mt_wakeup(i2c_addr);
90 if (status != FRAM_OK) {
91 return status;
92 }
93
94 // number of bytes that can be written without changing address
95 size_t write_len = 0;
96 if ((size_t)addr + len > mb85rc1mt_seg_size) {
97 write_len = mb85rc1mt_seg_size - addr;
98 } else {
99 write_len = len;
100 }
101
102 // transmit data
103 int tock_status = RETURNCODE_SUCCESS;
104
105 // NOTE: There is an internal 32 bytes buffer on I2C communication
106 // See below in read for additional details.
107
108 size_t written = 0;
109 while (written < write_len) {
110 // Add address header to chunk
111 uint8_t buffer[32] = {};
112 buffer[0] = (uint8_t)(i2c_addr.mem >> 8);
113 buffer[1] = (uint8_t)(i2c_addr.mem & 0xFF);
114
115 // Calculate remaining bytes
116 size_t remaining = write_len - written;
117 size_t chunk_size = 0;
118 if (remaining > 30) {
119 chunk_size = 30;
120 } else {
121 chunk_size = remaining;
122 }
123
124 // copy chunk into buffer
125 memcpy(buffer + 2, data + written, chunk_size);
126 // write chunk
127 tock_status = i2c_master_write_sync(i2c_addr.dev, buffer, chunk_size + 2);
128 if (tock_status < 0) {
129 return FRAM_ERROR;
130 }
131
132 // update written with total number of bytes
133 written += chunk_size;
134 // get the address for the next chunk
135 i2c_addr = convert_address(addr + written);
136 }
137
138 // Old Implementation
139
140 // uint8_t buffer[write_len + 2] = {};
141 // buffer[0] = (uint8_t)(i2c_addr.mem >> 8);
142 // buffer[1] = (uint8_t)(i2c_addr.mem & 0xFF);
143 // memcpy(buffer+2, data, write_len);
144 // tock_status = i2c_master_write_sync(i2c_addr.dev, buffer, write_len + 2);
145
146 // if (tock_status < 0) {
147 // return FRAM_ERROR;
148 // }
149
150 // update address and length
151 addr += write_len;
152 len -= write_len;
153 data += write_len;
154
155 // sleep device
156 status = mb85rc1mt_sleep(i2c_addr);
157 if (status != FRAM_OK) {
158 return status;
159 }
160 }
161
162 return status;
163}
164
165fram_status mb85rc1mt_read(fram_addr addr, size_t len, uint8_t* data) {
166 fram_status status = FRAM_OK;
167
168 while (len > 0) {
169 // convert fram address to i2c address
170 mb85rc1mt_address i2c_addr = convert_address(addr);
171
172 // wakeup device
173 status = mb85rc1mt_wakeup(i2c_addr);
174 if (status != FRAM_OK) {
175 return status;
176 }
177
178 size_t read_len = 0;
179 if ((size_t)addr + len > mb85rc1mt_seg_size) {
180 read_len = mb85rc1mt_seg_size - addr;
181 } else {
182 read_len = len;
183 }
184
185 // transmit data
186 int tock_status = RETURNCODE_SUCCESS;
187
188 uint8_t mem_addr[2] = {};
189 mem_addr[0] = (uint8_t)(i2c_addr.mem >> 8);
190 mem_addr[1] = (uint8_t)(i2c_addr.mem & 0xFF);
191
192 // set read address
193 tock_status = i2c_master_write_sync(i2c_addr.dev, mem_addr, 2);
194 if (tock_status < 0) {
195 return FRAM_ERROR;
196 }
197
198 // NOTE: This is a temporary workaround for reading more than the 32 byte
199 // interal buffer. We write a single byte at at time.
200 // In the kernal see, `capsules/core/i2c_master.rs`.
201
202 for (size_t i = 0; i < read_len; i++) {
203 tock_status = i2c_master_read_sync(i2c_addr.dev, data + i, 1);
204 if (tock_status < 0) {
205 return FRAM_ERROR;
206 }
207 }
208
209 // read from memory
210 // tock_status = i2c_master_read_sync(i2c_addr.dev, data, read_len);
211 // if (tock_status < 0) {
212 // return FRAM_ERROR;
213 //}
214
215 // update read params
216 addr += read_len;
217 len -= read_len;
218 data += read_len;
219
220 // sleep device
221 status = mb85rc1mt_sleep(i2c_addr);
222 if (status != FRAM_OK) {
223 return status;
224 }
225 }
226
227 // return status
228 return status;
229}
230
232 // TODO: Implement wakeup
233
234 (void)addr;
235
236 return FRAM_OK;
237}
238
240 // TODO: Implement sleep
241
242 (void)addr;
243
244 return FRAM_OK;
245}
246
247fram_addr mb85rc1mt_size(void) { return mb85rc1mt_pages * mb85rc1mt_seg_size; }
const char data[]
uint8_t buffer[32]
uint8_t i
Storage interface for onboard FRAM chips.
fram_status
Definition fram.h:32
uint32_t fram_addr
Definition fram.h:41
@ FRAM_ERROR
Definition fram.h:34
@ FRAM_OK
Definition fram.h:33
fram_status mb85rc1mt_write(fram_addr addr, const uint8_t *data, size_t len)
Write bytes to FRAM at the given address.
Definition mb85rc1mt.c:81
fram_status mb85rc1mt_read(fram_addr addr, size_t len, uint8_t *data)
Read bytes from FRAM at the given address.
Definition mb85rc1mt.c:165
fram_addr mb85rc1mt_size(void)
Get the total size of FRAM in bytes.
Definition mb85rc1mt.c:247
fram_status mb85rc1mt_wakeup(mb85rc1mt_address addr)
Put the chip into sleep mode.
Definition mb85rc1mt.c:231
fram_status mb85rc1mt_sleep(mb85rc1mt_address addr)
Wake up device from sleep.
Definition mb85rc1mt.c:239
Driver for mb87rc1mt FRAM chip.
Internal representation of the MB85RC1MT I2C address.
Definition mb85rc1mt.c:39