04ef3007bc25733d8c95f55bca3f402d1aa5058d
[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_PROTEXT = 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 static void wait_for_ready() {
66 BYTE reg_status = 0xFF;
67
68 CS_LOW();
69 xmit_spi(OP_STATUS_READ);
70 do {
71 rcvr_spi_m((uint8_t *) &reg_status);
72 } while (reg_status & STATUS_BSY);
73 CS_HIGH();
74 }
75
76 static void dataflash_powerdown() {
77 CS_LOW();
78 xmit_spi(OP_POWERDOWN);
79 CS_HIGH();
80 }
81
82 static void dataflash_resume() {
83 CS_LOW();
84 xmit_spi(OP_RESUME);
85 CS_HIGH();
86 }
87
88 DSTATUS dataflash_initialize() {
89 sspInit(0, sspClockPolarity_Low, sspClockPhase_RisingEdge);
90
91 gpioSetDir(RB_SPI_CS_DF, gpioDirection_Output);
92 dataflash_resume();
93 status &= ~STA_NOINIT;
94
95 return status;
96 }
97
98 DSTATUS dataflash_status() {
99 return status;
100 }
101
102 DRESULT dataflash_random_read(BYTE *buff, DWORD offset, DWORD length) {
103 if (!length) return RES_PARERR;
104 if (status & STA_NOINIT) return RES_NOTRDY;
105 if (offset + length > PAGE_MAX * PAGE_SIZE) return RES_PARERR;
106
107 wait_for_ready();
108 CS_LOW();
109 xmit_spi(OP_READARRAY);
110 xmit_spi((BYTE)(offset >> 16));
111 xmit_spi((BYTE)(offset >> 8));
112 xmit_spi((BYTE)offset);
113 xmit_spi(0x00); // follow up with don't care byte
114
115 do {
116 rcvr_spi_m(buff++);
117 } while (--length);
118 CS_HIGH();
119
120 return RES_OK;
121 }
122
123 DRESULT dataflash_read(BYTE *buff, DWORD sector, BYTE count) {
124 return dataflash_random_read(buff, sector * SECTOR_SIZE_FATFS, count * SECTOR_SIZE_FATFS);
125 }
126
127 #if _READONLY == 0
128 DRESULT dataflash_random_write(const BYTE *buff, DWORD offset, DWORD length) {
129 if (!length) return RES_PARERR;
130 if (status & STA_NOINIT) return RES_NOTRDY;
131 if (offset + length > PAGE_MAX * PAGE_SIZE) return RES_PARERR;
132
133 do {
134 wait_for_ready();
135
136 DWORD pageaddr = (offset / PAGE_SIZE) * PAGE_SIZE;
137 DWORD remaining = PAGE_SIZE - offset % PAGE_SIZE;
138
139 if (remaining > length) {
140 remaining = length;
141 }
142
143 length -= remaining;
144 offset += remaining;
145
146 CS_LOW();
147 xmit_spi(OP_WRITE_ENABLE);
148 CS_HIGH();
149
150 // read page into the internal buffer
151 CS_LOW();
152 xmit_spi(OP_PROGRAM_PAGE);
153 xmit_spi((BYTE)(pageaddr >> 16));
154 xmit_spi((BYTE)(pageaddr >> 8));
155 xmit_spi((BYTE) pageaddr );
156
157 do {
158 xmit_spi(*buff++);
159 } while (--remaining);
160
161 CS_HIGH();
162 } while (length);
163
164 return RES_OK;
165 }
166
167 DRESULT dataflash_write(const BYTE *buff, DWORD sector, BYTE count) {
168 return dataflash_random_write(buff, sector * SECTOR_SIZE_FATFS, count * SECTOR_SIZE_FATFS);
169 }
170 #endif /* _READONLY */
171
172 #if _USE_IOCTL != 0
173 DRESULT dataflash_ioctl(BYTE ctrl, void *buff) {
174 DRESULT res;
175 BYTE *ptr = buff;
176
177 res = RES_ERROR;
178
179 if (ctrl == CTRL_POWER) {
180 switch (*ptr) {
181 case 0: /* Sub control code == 0 (POWER_OFF) */
182 dataflash_powerdown();
183 res = RES_OK;
184 break;
185 case 1: /* Sub control code == 1 (POWER_ON) */
186 dataflash_resume();
187 res = RES_OK;
188 break;
189 case 2: /* Sub control code == 2 (POWER_GET) */
190 // TODO: figure out a way to retrieve the powerstate
191 *(ptr+1) = (BYTE)1;
192 res = RES_OK;
193 break;
194 default :
195 res = RES_PARERR;
196 }
197 } else {
198 if (status & STA_NOINIT) return RES_NOTRDY;
199
200 switch (ctrl) {
201 case CTRL_SYNC:
202 wait_for_ready();
203 res = RES_OK;
204 break;
205 case GET_SECTOR_COUNT:
206 // TODO: read from device ID register
207 *(WORD*)buff = PAGE_MAX * PAGE_SIZE / SECTOR_SIZE_FATFS;
208 res = RES_OK;
209 break;
210 case GET_SECTOR_SIZE:
211 *(WORD*)buff = SECTOR_SIZE_FATFS;
212 res = RES_OK;
213 break;
214 case GET_BLOCK_SIZE:
215 *(WORD*)buff = 1;
216 res = RES_OK;
217 break;
218 default:
219 res = RES_PARERR;
220 }
221 }
222
223 return res;
224 }
225 #endif /* _USE_IOCTL != 0 */
226
227 DWORD get_fattime () {
228 return 0;
229 /*
230 struct tm* tm=mygmtime(getSeconds());
231 DWORD t= (((tm->tm_year-80)<<9)|
232 ((tm->tm_mon+1)<<5)|
233 (tm->tm_mday))<<16 |
234 ((tm->tm_hour<<11)|
235 (tm->tm_min<<5)|
236 (tm->tm_sec>>1));
237 return t;
238 */
239 }
This page took 0.057149 seconds and 3 git commands to generate.