Spikes.
[hackover2013-badge-firmware.git] / dataflash / at25df041a.c
1 #include "projectconfig.h"
2 #include "diskio.h"
3 #include "iobase.h"
4 #include "core/ssp/ssp.h"
5
6 #include <r0ketports.h>
7
8 /* Opcodes */
9 enum {
10 OP_READARRAY = 0x0b,
11 OP_READARRAY_SLOW = 0x03,
12
13 OP_ERASE_BLOCK_4K = 0x20,
14 OP_ERASE_BLOCK_32K = 0x52,
15 OP_ERASE_BLOCK_64k = 0xd8,
16 OP_ERASE_CHIP = 0x60,
17 OP_ERASE_CHIP2 = 0xc7,
18
19 OP_PROGRAM_PAGE = 0x02,
20 OP_PROGRAM_SEQ = 0xad,
21 OP_PROGRAM_SEQ2 = 0xaf,
22
23 OP_WRITE_ENABLE = 0x06,
24 OP_WRITE_DISABLE = 0x04,
25
26 OP_SECTOR_PROTECT = 0x36,
27 OP_SECTOR_UNPROTECT = 0x39,
28 OP_SECTOR_STATUS = 0x3c,
29
30 OP_STATUS_READ = 0x05,
31 OP_STATUS_WRITE = 0x01,
32
33 OP_DEVICEID_READ = 0x9f,
34
35 OP_POWERDOWN = 0xb9,
36 OP_RESUME = 0xab,
37 };
38
39 enum {
40 STATUS_SPRL = 1 << 7, // sector protection registers locked
41 STATUS_SPM = 1 << 6, // sequential program mode
42 STATUS_EPE = 1 << 5, // erase/program error
43 STATUS_WPP = 1 << 4, // write protect pin
44 STATUS_SWP = 3 << 2, // software protection
45 STATUS_WEL = 1 << 1, // write enable latch
46 STATUS_BSY = 1 << 0, // ready/busy
47
48 STATUS_SWP_NONE = 0, // no sectors are software-protected
49 STATUS_SWP_SOME = 1 << 2, // some sectors are software-protected
50 STATUS_SWP_ALL = 3 << 2 // all sectors are software-protected
51 };
52
53 enum {
54 PAGE_MAX = 2048,
55 PAGE_SIZE = 256,
56
57 SECTOR_SIZE_FATFS = 512
58 };
59
60 #define CS_LOW() gpioSetValue(RB_SPI_CS_DF, 0)
61 #define CS_HIGH() gpioSetValue(RB_SPI_CS_DF, 1)
62
63 static volatile DSTATUS status = STA_NOINIT;
64
65 BYTE dataflash_read_status_register(void) {
66 BYTE reg_status = 0xff;
67
68 CS_LOW();
69 xmit_spi(OP_STATUS_READ);
70 rcvr_spi_m(&reg_status);
71 CS_HIGH();
72
73 return reg_status;
74 }
75
76 /*
77 static void dataflash_write_status_register(BYTE status) {
78 CS_LOW();
79 xmit_spi(OP_WRITE_ENABLE);
80 CS_HIGH();
81
82 CS_LOW();
83 xmit_spi(OP_STATUS_WRITE);
84 xmit_spi(status);
85 CS_HIGH();
86 }
87 */
88 static void wait_for_ready() {
89 while(dataflash_read_status_register() & STATUS_BSY)
90 ;
91 }
92
93 static void dataflash_powerdown() {
94 CS_LOW();
95 xmit_spi(OP_POWERDOWN);
96 CS_HIGH();
97 }
98
99 static void dataflash_resume() {
100 CS_LOW();
101 xmit_spi(OP_RESUME);
102 CS_HIGH();
103 }
104
105 DSTATUS dataflash_initialize() {
106 sspInit(0, sspClockPolarity_Low, sspClockPhase_RisingEdge);
107
108 gpioSetDir(RB_SPI_CS_DF, gpioDirection_Output);
109 dataflash_resume();
110
111 // BYTE status = dataflash_read_status_register();
112 // dataflash_write_status_register((status & ~STATUS_SWP) | STATUS_SWP_NONE);
113 status &= ~STA_NOINIT;
114
115 return status;
116 }
117
118 DSTATUS dataflash_status() {
119 return status;
120 }
121
122 DRESULT dataflash_random_read(BYTE *buff, DWORD offset, DWORD length) {
123 if (!length) return RES_PARERR;
124 if (status & STA_NOINIT) return RES_NOTRDY;
125 if (offset + length > PAGE_MAX * PAGE_SIZE) return RES_PARERR;
126
127 wait_for_ready();
128
129 CS_LOW();
130 xmit_spi(OP_READARRAY);
131 xmit_spi((BYTE)(offset >> 16));
132 xmit_spi((BYTE)(offset >> 8));
133 xmit_spi((BYTE) offset );
134 xmit_spi(0x00); // follow up with don't care byte
135
136 do {
137 rcvr_spi_m(buff++);
138 } while (--length);
139 CS_HIGH();
140
141 return RES_OK;
142 }
143
144 DRESULT dataflash_read(BYTE *buff, DWORD sector, BYTE count) {
145 return dataflash_random_read(buff, sector * SECTOR_SIZE_FATFS, count * SECTOR_SIZE_FATFS);
146 }
147
148 #if _READONLY == 0
149 static void dataflash_sector_protect(DWORD addr) {
150 wait_for_ready();
151
152 addr &= ~(PAGE_SIZE - 1);
153
154 CS_LOW();
155 xmit_spi(OP_WRITE_ENABLE);
156 CS_HIGH();
157
158 CS_LOW();
159 xmit_spi(OP_SECTOR_PROTECT);
160 xmit_spi((BYTE)(addr >> 16));
161 xmit_spi((BYTE)(addr >> 8));
162 xmit_spi((BYTE) addr );
163 CS_HIGH();
164
165 wait_for_ready();
166 }
167
168 static void dataflash_sector_unprotect(DWORD addr) {
169 wait_for_ready();
170
171 addr &= ~(PAGE_SIZE - 1);
172
173 CS_LOW();
174 xmit_spi(OP_WRITE_ENABLE);
175 CS_HIGH();
176
177 CS_LOW();
178 xmit_spi(OP_SECTOR_UNPROTECT);
179 xmit_spi((BYTE)(addr >> 16));
180 xmit_spi((BYTE)(addr >> 8));
181 xmit_spi((BYTE) addr );
182 CS_HIGH();
183
184 wait_for_ready();
185 }
186
187 static DRESULT dataflash_write_4k(const BYTE *buff, DWORD addr) {
188 addr &= ~4095u;
189
190 CS_LOW();
191 xmit_spi(OP_WRITE_ENABLE);
192 CS_HIGH();
193
194 CS_LOW();
195 xmit_spi(OP_ERASE_BLOCK_4K);
196 xmit_spi((BYTE)(addr >> 16));
197 xmit_spi((BYTE)(addr >> 8));
198 xmit_spi((BYTE) addr );
199 CS_HIGH();
200
201 CS_LOW();
202 xmit_spi(OP_WRITE_ENABLE);
203 CS_HIGH();
204
205 CS_LOW();
206 xmit_spi(OP_PROGRAM_PAGE);
207 xmit_spi((BYTE)(addr >> 16));
208 xmit_spi((BYTE)(addr >> 8));
209 xmit_spi((BYTE) addr );
210 for(int i = 0; i < 4096; ++i) {
211 xmit_spi(buff[i]);
212 }
213 CS_HIGH();
214 }
215
216 DRESULT dataflash_random_write(const BYTE *buff, DWORD offset, DWORD length) {
217 if (!length) return RES_PARERR;
218 if (status & STA_NOINIT) return RES_NOTRDY;
219 if (offset + length > PAGE_MAX * PAGE_SIZE) return RES_PARERR;
220
221 do {
222 wait_for_ready();
223
224 DWORD addr = offset;
225 DWORD blockaddr = addr & ~4095u;
226 DWORD remaining = PAGE_SIZE - offset % PAGE_SIZE;
227
228 BYTE blockbuf[4096];
229 dataflash_random_read(blockbuf, blockaddr, 4096);
230
231 if (remaining > length) {
232 remaining = length;
233 }
234
235 length -= remaining;
236 offset += remaining;
237
238 dataflash_sector_unprotect(addr);
239
240 CS_LOW();
241 xmit_spi(OP_WRITE_ENABLE);
242 CS_HIGH();
243
244 CS_LOW();
245 xmit_spi(OP_PROGRAM_PAGE);
246 xmit_spi((BYTE)(addr >> 16));
247 xmit_spi((BYTE)(addr >> 8));
248 xmit_spi((BYTE) addr );
249 do {
250 xmit_spi(*buff++);
251 } while (--remaining);
252 CS_HIGH();
253
254 dataflash_sector_protect(addr);
255 } while (length);
256
257 wait_for_ready();
258
259 return RES_OK;
260 }
261
262 DRESULT dataflash_write(const BYTE *buff, DWORD sector, BYTE count) {
263 return dataflash_random_write(buff, sector * SECTOR_SIZE_FATFS, count * SECTOR_SIZE_FATFS);
264 }
265 #endif /* _READONLY */
266
267 #if _USE_IOCTL != 0
268 DRESULT dataflash_ioctl(BYTE ctrl, void *buff) {
269 DRESULT res;
270 BYTE *ptr = buff;
271
272 res = RES_ERROR;
273
274 if (ctrl == CTRL_POWER) {
275 switch (*ptr) {
276 case 0: /* Sub control code == 0 (POWER_OFF) */
277 dataflash_powerdown();
278 res = RES_OK;
279 break;
280 case 1: /* Sub control code == 1 (POWER_ON) */
281 dataflash_resume();
282 res = RES_OK;
283 break;
284 case 2: /* Sub control code == 2 (POWER_GET) */
285 // TODO: figure out a way to retrieve the powerstate
286 *(ptr+1) = (BYTE)1;
287 res = RES_OK;
288 break;
289 default :
290 res = RES_PARERR;
291 }
292 } else {
293 if (status & STA_NOINIT) return RES_NOTRDY;
294
295 switch (ctrl) {
296 case CTRL_SYNC:
297 wait_for_ready();
298 res = RES_OK;
299 break;
300 case GET_SECTOR_COUNT:
301 // TODO: read from device ID register
302 *(WORD*)buff = PAGE_MAX * PAGE_SIZE / SECTOR_SIZE_FATFS;
303 res = RES_OK;
304 break;
305 case GET_SECTOR_SIZE:
306 *(WORD*)buff = SECTOR_SIZE_FATFS;
307 res = RES_OK;
308 break;
309 case GET_BLOCK_SIZE:
310 *(WORD*)buff = 1;
311 res = RES_OK;
312 break;
313 default:
314 res = RES_PARERR;
315 }
316 }
317
318 return res;
319 }
320 #endif /* _USE_IOCTL != 0 */
321
322 DWORD get_fattime () {
323 return 0;
324 /*
325 struct tm* tm=mygmtime(getSeconds());
326 DWORD t= (((tm->tm_year-80)<<9)|
327 ((tm->tm_mon+1)<<5)|
328 (tm->tm_mday))<<16 |
329 ((tm->tm_hour<<11)|
330 (tm->tm_min<<5)|
331 (tm->tm_sec>>1));
332 return t;
333 */
334 }
This page took 0.062202 seconds and 5 git commands to generate.