Release-Binaries
[hackover2013-badge-firmware.git] / dataflash / at45db041d.c
1 #include "projectconfig.h"
2 #include "diskio.h"
3 #include "iobase.h"
4 #include "core/ssp/ssp.h"
5
6 #ifdef R0KET
7 #include <r0ketports.h>
8 #else
9 #include <badge/pinconfig.h>
10 #define RB_SPI_CS_DF HOB_PORT(HOB_DATAFLASH_CS), HOB_PIN(HOB_DATAFLASH_CS)
11 #endif
12
13 /* Opcodes */
14 #define OP_POWERDOWN (0xB9)
15 #define OP_RESUME (0xAB)
16 #define OP_PAGEREAD (0xD2)
17 #define OP_BUFFER1READ (0xD1) /* Low Frequency (<=33MHz) */
18 #define OP_BUFFER2READ (0xD3) /* Low Frequency (<=33MHz) */
19 #define OP_BUFFER1WRITE (0x84)
20 #define OP_BUFFER2WRITE (0x87)
21 #define OP_BUFFER1PROG (0x83) /* with builtin erase */
22 #define OP_BUFFER2PROG (0x86) /* with builtin erase */
23 #define OP_STATUSREAD (0xD7)
24 #define OP_DEVICEID (0x9F)
25 #define OP_PAGE2BUFFER1 (0x53)
26 #define OP_PAGE2BUFFER2 (0x55)
27 #define OP_BUFFER1PAGECMP (0x60)
28 #define OP_BUFFER2PAGECMP (0x61)
29 #define OP_AUTOREWRITE1 (0x58) /* Auto Page Rewrite throught Buffer 1 */
30 #define OP_AUTOREWRITE2 (0x59) /* Auto Page Rewrite throught Buffer 2 */
31
32 #define SB_READY (1 << 7)
33 #define SB_COMP (1 << 6)
34 #define SB_PROTECT (1 << 1)
35 #define SB_PAGESIZE (1 << 0)
36
37 #define MAX_PAGE (2048)
38
39 #define CS_LOW() gpioSetValue(RB_SPI_CS_DF, 0)
40 #define CS_HIGH() gpioSetValue(RB_SPI_CS_DF, 1)
41
42 static volatile DSTATUS status = STA_NOINIT;
43
44 static void wait_for_ready() {
45 BYTE reg_status = 0xFF;
46
47 CS_LOW();
48 xmit_spi(OP_STATUSREAD);
49 do {
50 rcvr_spi_m((uint8_t *) &reg_status);
51 } while (!(reg_status & SB_READY));
52 CS_HIGH();
53 }
54
55 static void dataflash_powerdown() {
56 CS_LOW();
57 xmit_spi(OP_POWERDOWN);
58 CS_HIGH();
59 }
60
61 static void dataflash_resume() {
62 CS_LOW();
63 xmit_spi(OP_RESUME);
64 CS_HIGH();
65 }
66
67 DSTATUS dataflash_initialize() {
68 sspInit(0, sspClockPolarity_Low, sspClockPhase_RisingEdge);
69
70 gpioSetDir(RB_SPI_CS_DF, gpioDirection_Output);
71
72 dataflash_resume();
73 status &= ~STA_NOINIT;
74 return status;
75 }
76
77 DSTATUS dataflash_status() {
78 return status;
79 }
80
81 DRESULT dataflash_random_read(BYTE *buff, DWORD offset, DWORD length) {
82 if (!length) return RES_PARERR;
83 if (status & STA_NOINIT) return RES_NOTRDY;
84 if (offset+length > MAX_PAGE*256) return RES_PARERR;
85
86 do {
87 wait_for_ready();
88 DWORD pageaddr = ((offset/256) << 9) | (offset%256);
89 DWORD remaining = 256 - offset%256;
90 if (remaining > length) {
91 remaining = length;
92 }
93 length -= remaining;
94 offset += remaining;
95
96 CS_LOW();
97 xmit_spi(OP_PAGEREAD);
98 xmit_spi((BYTE)(pageaddr >> 16));
99 xmit_spi((BYTE)(pageaddr >> 8));
100 xmit_spi((BYTE)pageaddr);
101 xmit_spi(0x00); // follow up with 4 don't care bytes
102 xmit_spi(0x00);
103 xmit_spi(0x00);
104 xmit_spi(0x00);
105 do {
106 rcvr_spi_m(buff++);
107 } while (--remaining);
108 CS_HIGH();
109 } while (length);
110
111 return length ? RES_ERROR : RES_OK;
112 }
113
114 DRESULT dataflash_read(BYTE *buff, DWORD sector, BYTE count) {
115 return dataflash_random_read(buff, sector*512, count*512);
116 }
117
118 #if _READONLY == 0
119 DRESULT dataflash_random_write(const BYTE *buff, DWORD offset, DWORD length) {
120 if (!length) return RES_PARERR;
121 if (status & STA_NOINIT) return RES_NOTRDY;
122 if (offset+length > MAX_PAGE*256) return RES_PARERR;
123
124 do {
125 wait_for_ready();
126 DWORD pageaddr = (offset/256) << 9;
127 DWORD buffaddr = (offset%256);
128 DWORD remaining = 256 - offset%256;
129 if (remaining > length) {
130 remaining = length;
131 }
132 length -= remaining;
133 offset += remaining;
134
135 // read page into the internal buffer
136 CS_LOW();
137 xmit_spi(OP_PAGE2BUFFER1);
138 xmit_spi((BYTE)(pageaddr >> 16));
139 xmit_spi((BYTE)(pageaddr >> 8));
140 xmit_spi((BYTE)pageaddr);
141 CS_HIGH();
142 wait_for_ready();
143
144 // write bytes into the dataflash buffer
145 CS_LOW();
146 xmit_spi(OP_BUFFER1WRITE);
147 xmit_spi((BYTE)(buffaddr >> 16));
148 xmit_spi((BYTE)(buffaddr >> 8));
149 xmit_spi((BYTE)buffaddr);
150 do {
151 xmit_spi(*buff++);
152 } while (--remaining);
153 CS_HIGH();
154 wait_for_ready();
155
156 // compare buffer with target memory page
157 CS_LOW();
158 xmit_spi(OP_BUFFER1PAGECMP);
159 xmit_spi((BYTE)(pageaddr >> 16));
160 xmit_spi((BYTE)(pageaddr >> 8));
161 xmit_spi((BYTE)pageaddr);
162 CS_HIGH();
163 wait_for_ready();
164 CS_LOW();
165 BYTE reg_status = 0xFF;
166 xmit_spi(OP_STATUSREAD);
167 rcvr_spi_m((uint8_t *) &reg_status);
168 CS_HIGH();
169
170 // trigger program only if data changed
171 if (reg_status & SB_COMP) {
172 CS_LOW();
173 xmit_spi(OP_BUFFER1PROG);
174 xmit_spi((BYTE)(pageaddr >> 16));
175 xmit_spi((BYTE)(pageaddr >> 8));
176 xmit_spi((BYTE)pageaddr);
177 CS_HIGH();
178 }
179 } while (length);
180
181 return length ? RES_ERROR : RES_OK;
182 }
183
184 DRESULT dataflash_write(const BYTE *buff, DWORD sector, BYTE count) {
185 return dataflash_random_write(buff, sector*512, count*512);
186 }
187 #endif /* _READONLY */
188
189 #if _USE_IOCTL != 0
190 DRESULT dataflash_ioctl(BYTE ctrl, void *buff) {
191 DRESULT res;
192 BYTE *ptr = buff;
193
194 res = RES_ERROR;
195
196
197 if (ctrl == CTRL_POWER) {
198 switch (*ptr) {
199 case 0: /* Sub control code == 0 (POWER_OFF) */
200 dataflash_powerdown();
201 res = RES_OK;
202 break;
203 case 1: /* Sub control code == 1 (POWER_ON) */
204 dataflash_resume();
205 res = RES_OK;
206 break;
207 case 2: /* Sub control code == 2 (POWER_GET) */
208 // TODO: figure out a way to retrieve the powerstate
209 *(ptr+1) = (BYTE)1;
210 res = RES_OK;
211 break;
212 default :
213 res = RES_PARERR;
214 }
215 } else {
216 if (status & STA_NOINIT) return RES_NOTRDY;
217
218 switch (ctrl) {
219 case CTRL_SYNC:
220 wait_for_ready();
221 res = RES_OK;
222 break;
223 case GET_SECTOR_COUNT:
224 // TODO: read from device ID register
225 *(WORD*)buff = MAX_PAGE/2;
226 res = RES_OK;
227 break;
228 case GET_SECTOR_SIZE:
229 *(WORD*)buff = 512;
230 res = RES_OK;
231 break;
232 case GET_BLOCK_SIZE:
233 *(WORD*)buff = 1;
234 res = RES_OK;
235 break;
236 default:
237 res = RES_PARERR;
238 }
239 }
240
241 return res;
242 }
243 #endif /* _USE_IOCTL != 0 */
244
245 DWORD get_fattime () {
246 return 0;
247 /*
248 struct tm* tm=mygmtime(getSeconds());
249 DWORD t= (((tm->tm_year-80)<<9)|
250 ((tm->tm_mon+1)<<5)|
251 (tm->tm_mday))<<16 |
252 ((tm->tm_hour<<11)|
253 (tm->tm_min<<5)|
254 (tm->tm_sec>>1));
255 return t;
256 */
257 }
This page took 0.063367 seconds and 5 git commands to generate.