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