Line data Source code
1 : /*
2 : driver for RAMTRON FRAM persistent memory devices. These are used
3 : for parameter and waypoint storage on most FMUv1, FMUv2, FMUv3 and FMUv4
4 : boards
5 : */
6 :
7 : #include "AP_RAMTRON.h"
8 : #include <AP_Math/crc.h>
9 : #include <AP_Math/AP_Math.h>
10 :
11 : extern const AP_HAL::HAL &hal;
12 :
13 : // register numbers
14 : static const uint8_t RAMTRON_RDID = 0x9f;
15 : static const uint8_t RAMTRON_READ = 0x03;
16 : static const uint8_t RAMTRON_WREN = 0x06;
17 : static const uint8_t RAMTRON_WRITE = 0x02;
18 :
19 : #define RAMTRON_RETRIES 10
20 : #define RAMTRON_DELAY_MS 10
21 :
22 : /*
23 : list of supported devices. Thanks to NuttX ramtron driver
24 : */
25 : const AP_RAMTRON::ramtron_id AP_RAMTRON::ramtron_ids[] = {
26 : { 0x21, 0x00, 16, 2, RDID_type::Cypress }, // FM25V01
27 : { 0x21, 0x08, 16, 2, RDID_type::Cypress }, // FM25V01A
28 : { 0x22, 0x00, 32, 2, RDID_type::Cypress }, // FM25V02
29 : { 0x22, 0x08, 32, 2, RDID_type::Cypress }, // FM25V02A
30 : { 0x22, 0x48, 32, 2, RDID_type::Cypress }, // FM25V02A - Extended Temperature Version
31 : { 0x22, 0x01, 32, 2, RDID_type::Cypress }, // FM25VN02
32 : { 0x23, 0x00, 64, 2, RDID_type::Cypress }, // FM25V05
33 : { 0x23, 0x01, 64, 2, RDID_type::Cypress }, // FM25VN05
34 : { 0x24, 0x00, 128, 3, RDID_type::Cypress }, // FM25V10
35 : { 0x24, 0x01, 128, 3, RDID_type::Cypress }, // FM25VN10
36 : { 0x25, 0x08, 256, 3, RDID_type::Cypress }, // FM25V20A
37 : { 0x26, 0x08, 512, 3, RDID_type::Cypress }, // CY15B104Q
38 :
39 : { 0x27, 0x03, 128, 3, RDID_type::Fujitsu }, // MB85RS1MT
40 : { 0x05, 0x09, 32, 2, RDID_type::Fujitsu }, // MB85RS256B
41 : { 0x24, 0x03, 16, 2, RDID_type::Fujitsu }, // MB85RS128TY
42 : { 0x25, 0x03, 32, 2, RDID_type::Fujitsu }, // MB85RS256TY
43 :
44 : { 0x22, 0x00, 16, 2, RDID_type::Petabytes }, // PB85RS128C
45 : { 0x24, 0x00, 256, 3, RDID_type::Petabytes }, // PB85RS2MC
46 : };
47 :
48 : // initialise the driver
49 3 : bool AP_RAMTRON::init(void)
50 : {
51 3 : dev = hal.spi->get_device_ptr("ramtron");
52 3 : if (!dev) {
53 0 : DEV_PRINTF("No RAMTRON device\n");
54 0 : return false;
55 : }
56 :
57 : struct cypress_rdid {
58 : uint8_t manufacturer[6];
59 : uint8_t memory;
60 : uint8_t id1;
61 : uint8_t id2;
62 : };
63 : struct fujitsu_rdid {
64 : uint8_t manufacturer[2];
65 : uint8_t id1;
66 : uint8_t id2;
67 : };
68 : struct petabytes_rdid {
69 : uint8_t manufacturer[2];
70 : uint8_t id1;
71 : uint8_t id2;
72 : };
73 :
74 : uint8_t rdid[sizeof(cypress_rdid)];
75 :
76 : {
77 3 : WITH_SEMAPHORE(dev->get_semaphore());
78 3 : if (!dev->read_registers(RAMTRON_RDID, rdid, sizeof(rdid))) {
79 0 : return false;
80 : }
81 3 : }
82 :
83 9 : for (uint8_t i = 0; i < ARRAY_SIZE(ramtron_ids); i++) {
84 9 : if (ramtron_ids[i].rdid_type == RDID_type::Cypress) {
85 9 : const cypress_rdid *cypress = (const cypress_rdid *)rdid;
86 9 : if (ramtron_ids[i].id1 == cypress->id1 &&
87 3 : ramtron_ids[i].id2 == cypress->id2) {
88 3 : id = i;
89 3 : break;
90 : }
91 0 : } else if (ramtron_ids[i].rdid_type == RDID_type::Fujitsu) {
92 0 : const fujitsu_rdid *fujitsu = (const fujitsu_rdid *)rdid;
93 0 : if (ramtron_ids[i].id1 == fujitsu->id1 &&
94 0 : ramtron_ids[i].id2 == fujitsu->id2) {
95 0 : id = i;
96 0 : break;
97 : }
98 0 : } else if (ramtron_ids[i].rdid_type == RDID_type::Petabytes) {
99 0 : const petabytes_rdid *petabytes = (const petabytes_rdid *)rdid;
100 0 : if (petabytes->manufacturer[0] == 0x62 &&
101 0 : petabytes->manufacturer[1] == 0x8C &&
102 0 : ramtron_ids[i].id1 == petabytes->id1 &&
103 0 : ramtron_ids[i].id2 == petabytes->id2) {
104 0 : id = i;
105 0 : break;
106 : }
107 : }
108 : }
109 :
110 3 : if (id == UINT8_MAX) {
111 0 : DEV_PRINTF("Unknown RAMTRON device\n");
112 0 : return false;
113 : }
114 :
115 3 : return true;
116 : }
117 :
118 : /*
119 : send a command and offset
120 : */
121 782 : void AP_RAMTRON::send_offset(uint8_t cmd, uint32_t offset) const
122 : {
123 782 : if (ramtron_ids[id].addrlen == 3) {
124 0 : uint8_t b[4] = { cmd, uint8_t((offset>>16)&0xFF), uint8_t((offset>>8)&0xFF), uint8_t(offset&0xFF) };
125 0 : dev->transfer(b, sizeof(b), nullptr, 0);
126 : } else /* len 2 */ {
127 782 : uint8_t b[3] = { cmd, uint8_t((offset>>8)&0xFF), uint8_t(offset&0xFF) };
128 782 : dev->transfer(b, sizeof(b), nullptr, 0);
129 : }
130 782 : }
131 :
132 : // read from device
133 384 : bool AP_RAMTRON::read(uint32_t offset, uint8_t *buf, uint32_t size)
134 : {
135 : // Don't allow reads outside of the FRAM memory.
136 : // NOTE: The FRAM devices will wrap back to address 0x0000 if they read past
137 : // the end of their internal memory, so while we'll get data back, it won't
138 : // be what we expect.
139 768 : if ((size > get_size()) ||
140 384 : (offset > (get_size() - size))) {
141 0 : return false;
142 : }
143 384 : const uint8_t maxread = 128;
144 765 : while (size > maxread) {
145 381 : if (!read(offset, buf, maxread)) {
146 0 : return false;
147 : }
148 381 : offset += maxread;
149 381 : buf += maxread;
150 381 : size -= maxread;
151 : }
152 :
153 384 : for (uint8_t r=0; r<RAMTRON_RETRIES; r++) {
154 384 : if (r != 0) {
155 0 : hal.scheduler->delay(RAMTRON_DELAY_MS);
156 : }
157 : /*
158 : transfer each block twice and compare with a crc. This is to
159 : prevent transient errors from causing parameter corruption
160 : */
161 : {
162 384 : WITH_SEMAPHORE(dev->get_semaphore());
163 384 : dev->set_chip_select(true);
164 384 : send_offset(RAMTRON_READ, offset);
165 384 : dev->transfer(nullptr, 0, buf, size);
166 384 : dev->set_chip_select(false);
167 384 : }
168 :
169 384 : uint32_t crc1 = crc_crc32(0, buf, size);
170 :
171 : {
172 384 : WITH_SEMAPHORE(dev->get_semaphore());
173 384 : dev->set_chip_select(true);
174 384 : send_offset(RAMTRON_READ, offset);
175 384 : dev->transfer(nullptr, 0, buf, size);
176 384 : dev->set_chip_select(false);
177 384 : }
178 384 : uint32_t crc2 = crc_crc32(0, buf, size);
179 :
180 384 : if (crc1 == crc2) {
181 : // all good
182 384 : return true;
183 : }
184 : }
185 :
186 0 : return false;
187 : }
188 :
189 : // write to device
190 95757 : bool AP_RAMTRON::write(uint32_t offset, const uint8_t *buf, uint32_t size)
191 : {
192 : // Don't allow writes outside of the FRAM memory.
193 : // NOTE: The FRAM devices will wrap back to address 0x0000 if they write past
194 : // the end of their internal memory, so we could accidentally overwrite the
195 : // wrong memory location.
196 95764 : if ((size > get_size()) ||
197 7 : (offset > (get_size() - size))) {
198 95750 : return false;
199 : }
200 :
201 7 : WITH_SEMAPHORE(dev->get_semaphore());
202 :
203 7 : for (uint8_t r=0; r<RAMTRON_RETRIES; r++) {
204 7 : if (r != 0) {
205 0 : hal.scheduler->delay(RAMTRON_DELAY_MS);
206 : }
207 :
208 : // we need to enable writes every time. The WREN bit is
209 : // automatically reset on completion of the write call
210 7 : dev->set_chip_select(true);
211 7 : dev->transfer(&RAMTRON_WREN, 1, nullptr, 0);
212 7 : dev->set_chip_select(false);
213 :
214 7 : dev->set_chip_select(true);
215 7 : send_offset(RAMTRON_WRITE, offset);
216 7 : dev->transfer(buf, size, nullptr, 0);
217 7 : dev->set_chip_select(false);
218 :
219 : /*
220 : verify first 32 bytes of every write using a crc
221 : */
222 7 : uint8_t rbuf[32] {};
223 7 : const uint8_t nverify = MIN(size, sizeof(rbuf));
224 7 : uint32_t crc1 = crc_crc32(0, buf, nverify);
225 :
226 7 : dev->set_chip_select(true);
227 7 : send_offset(RAMTRON_READ, offset);
228 7 : dev->transfer(nullptr, 0, rbuf, nverify);
229 7 : dev->set_chip_select(false);
230 :
231 7 : uint32_t crc2 = crc_crc32(0, rbuf, nverify);
232 :
233 7 : if (crc1 == crc2) {
234 7 : return true;
235 : }
236 : }
237 :
238 0 : return false;
239 7 : }
|