1 #ifndef _MX25LXX_H_
2 #define _MX25LXX_H_
3
4 #include "main.h"
5
6 void mx25_spi_interface_init(void);
7 uint8_t mx25_write_read_byte(uint8_t *in_buf, uint32_t in_len, uint8_t *out_buf, uint32_t out_len);
8 /***************************************************************************/
9
10 #define DUMMY_BYTE (0xA5)
11
12 /*
13 Block64 (64k Bytes)
14 Block32 (32k Bytes)
15 Sector (4k Bytes)
16 Page (256 Bytes)
17
18 so: 1*Sector = 16*Page;
19 */
20 #define SECTOR_SIZE (4096)
21 #define PAGE_SIZE (256)
22
23 #define Manufacturer_ID (0xC2)
24
25
26 /***************************************************************************/
27
28 /*chip command*/
29 #define MX25_WREN (0x06) /*Write Enable*/
30 #define MX25_WRDI (0x04) /*Write Disable*/
31 #define MX25_FMEN (0x41) /*Factory Mode Enable*/
32 #define MX25_RDID (0x9F) /*Read Identification*/
33 #define MX25_RDP (0xAB) /*Realease from Deep Power-down*/
34 #define MX25_REMS (0x90) /*Read Electronic Manufacturer ID & Device ID*/
35 #define MX25_RDSR (0x05) /*Read Status Register*/
36 #define MX25_RDCR (0x15) /*Read Configuration Register*/
37 #define MX25_WRSR (0x01) /*Write Status Register*/
38 #define MX25_READ (0x03) /*Read Data Bytes (READ)*/
39 #define MX25_FAST_READ (0x0B) /*Read Data Bytes at Higher Speed (FAST_READ)*/
40 #define MX25_DREAD (0x3B) /*Dual Output Read Mode (DREAD)*/
41 #define MX25_2READ (0xBB) /*2 x I/O Read Mode (2READ)*/
42 #define MX25_QREAD (0x6B) /*Quad Read Mode (QREAD)*/
43 #define MX25_4READ (0xEB) /*4 x I/O Read Mode (4READ)*/
44 #define MX25_BurstRead (0xC0) /*Burst Read*/
45 #define MX25_SE (0x20) /*Sector Erase (SE)*/
46 #define MX25_BE32K (0x52) /*Block Erase (BE32K)*/
47 #define MX25_BE64K (0xD8) /*Block Erase (BE64K)*/
48 #define MX25_CE (0xC7) /*Chip Erase (CE)*/
49 #define MX25_PP (0x02) /*Page Program (PP)*/
50 #define MX25_4PP (0x38) /*4 x I/O Page Program (4PP)*/
51
52
53 /*...below is rarely used command...*/
54 #if 1
55 #define MX25_DP (0xB9) /*Deep Power-down (DP)*/
56 #define MX25_ENSO (0xB1) /*Enter Secured OTP (ENSO)*/
57 #define MX25_EXSO (0xC1) /*Exit Secured OTP (EXSO)*/
58 #define MX25_RDSCUR (0x2B) /*Read Security Register (RDSCUR)*/
59 #define MX25_WRSCUR (0x2F) /*Write Security Register (WRSCUR)*/
60 #define MX25_WPSEL (0x68) /*Write Protection Selection (WPSEL)*/
61 //#define MX25_XX (0xXX) /*Advanced Sector Protection*/
62 #define MX25_RDLR (0x2D) /*Read Lock Register (RDLR)*/
63 #define MX25_WRLR (0x2C) /*Write Lock Register (WRLR)*/
64 #define MX25_RDSPB (0xE2) /*Read SPB Status (RDSPB)*/
65 #define MX25_ESSPB (0xE4) /*SPB Erase (ESSPB)*/
66 #define MX25_WRSPB (0xE3) /*SPB Program (WRSPB)*/
67 #define MX25_RDDPB (0xE0) /*Read DPB Register (RDDPB)*/
68 #define MX25_WRDPB (0xE1) /*Write DPB Register (WRDPB)*/
69 #define MX25_GBLK (0x7E) /*Gang Block Lock (GBLK)*/
70 #define MX25_GBULK (0x98) /*Gang Block Unlock (GBULK)*/
71 //#define MX25_Suspend (0xXX) /*Program/Erase Suspend*/
72 //#define MX25_Resume (0xXX) /*Program/Erase Resume*/
73 #define MX25_NOP (0x00) /*No Operation*/
74 #endif
75
76 /***************************************************************************/
77 typedef union
78 {
79 struct
80 {
81 u8 WIP: 1;
82 u8 WEL: 1;
83 u8 BP0: 1;
84 u8 BP1: 1;
85
86 u8 BP2: 1;
87 u8 BP3: 1;
88 u8 QE: 1;
89 u8 SRWD: 1;
90 } bits;
91 u8 byte;
92 } MX25_StatusRegister_u;
93 typedef union
94 {
95 struct
96 {
97 u8 OTP: 1;
98 u8 LDSO: 1;
99 u8 PSB: 1;
100 u8 ESB: 1;
101
102 u8 RES: 1;
103 u8 P_FAIL: 1;
104 u8 E_FAIL: 1;
105 u8 WPSEL: 1;
106 } bits;
107 u8 byte;
108 } MX25_SecurityRegister_u;
109
110
111 void mx25_WriteEn(void);
112 void mx25_WriteDis(void);
113 void mx25_ReadID(u8* ManufacturerId, u16* DeviceId);
114 void mx25_REMS(u8* ManufacturerId, u8* DeviceId);
115 u8 mx25_ReadStatusRegister(void);
116 void mx25_ReadBytes(u32 address, u8* out_buf, u32 out_len);
117 u8 mx25_Erase(u32 address, u8 cmd);
118 u8 mx25_PageProgram(u32 address, u8* buf, u16 len);
119 u8 mx25_WriteBytes(u32 address, u8* buf, u32 len);
120
121 #endif
1 /*
2 file:mx25lxx.c
3 auth:ycp
4 date:2023.12.05
5 */
6
7 #include "mx25lxx.h"
8 #include "user_spi.h"
9
10 void mx25_delay_1ms(u32 n)
11 {
12 rt_thread_mdelay(n);
13 }
14
15 void mx25_spi_interface_init(void)
16 {
17 user_spi_init();
18 }
19 uint8_t mx25_write_read_byte(uint8_t *in_buf, uint32_t in_len, uint8_t *out_buf, uint32_t out_len)
20 {
21 if(in_buf == NULL)return 1;
22 return spi_bytes_write_read( in_buf, in_len, out_buf, out_len);
23 }
24 /***************************************************************************/
25
26 void mx25_WriteEn(void)
27 {
28 u8 in_buf[10];
29 in_buf[0] = MX25_WREN;
30 mx25_write_read_byte(in_buf, 1, 0, 0);
31 return;
32 }
33 void mx25_WriteDis(void)
34 {
35 u8 in_buf[10];
36 in_buf[0] = MX25_WRDI;
37 mx25_write_read_byte(in_buf, 1, 0, 0);
38 return;
39 }
40
41 void mx25_ReadID(u8* ManufacturerId, u16* DeviceId)
42 {
43 u8 out_buf[10];
44 u8 in_buf[10];
45 in_buf[0] = MX25_RDID;
46 in_buf[1] = DUMMY_BYTE;
47 in_buf[2] = DUMMY_BYTE;
48 in_buf[3] = DUMMY_BYTE;
49 mx25_write_read_byte(in_buf, 4, out_buf, 4);
50 *ManufacturerId = out_buf[1];
51 *DeviceId = out_buf[2] << 8 | out_buf[3] << 0;
52 //SYSTEM_DEBUG("ManufacturerId=%02X,DeviceId=%04X\n",*ManufacturerId,*DeviceId);
53 return;
54 }
55
56 void mx25_REMS(u8* ManufacturerId, u8* DeviceId)
57 {
58 u8 out_buf[10];
59 u8 in_buf[10];
60 in_buf[0] = MX25_REMS;
61 in_buf[1] = DUMMY_BYTE;
62 in_buf[2] = DUMMY_BYTE;
63 in_buf[3] = 0x00;
64 in_buf[4] = DUMMY_BYTE;
65 in_buf[5] = DUMMY_BYTE;
66 mx25_write_read_byte(in_buf, 6, out_buf, 6);
67 *ManufacturerId = out_buf[4];
68 *DeviceId = out_buf[5];
69 SYSTEM_DEBUG("ManufacturerId=%02X,DeviceId=%02X\n", *ManufacturerId, *DeviceId);
70 return;
71 }
72
73 u8 mx25_ReadStatusRegister(void)
74 {
75 u8 out_buf[10];
76 u8 in_buf[10];
77 in_buf[0] = MX25_RDSR;
78 in_buf[1] = DUMMY_BYTE;
79 in_buf[2] = DUMMY_BYTE;
80 mx25_write_read_byte(in_buf, 2, out_buf, 2);
81 //SYSTEM_DEBUG("out[1]=%02X,out[2]=%02X\n", out_buf[1], out_buf[2]);
82 return out_buf[1];
83 }
84
85 u8 mx25_ReadSecurityRegRegister(void)
86 {
87 u8 out_buf[10];
88 u8 in_buf[10];
89 in_buf[0] = MX25_RDSCUR;
90 in_buf[1] = DUMMY_BYTE;
91 in_buf[2] = DUMMY_BYTE;
92 mx25_write_read_byte(in_buf, 2, out_buf, 2);
93 //SYSTEM_DEBUG("out[1]=%02X,out[2]=%02X\n", out_buf[1], out_buf[2]);
94 return out_buf[1];
95 }
96
97 /*
98 address:
99 any positoin.
100 */
101 void mx25_ReadBytes(u32 address, u8* out_buf, u32 out_len)
102 {
103 u8 remain_4byte[16];
104 u8 in_buf[10];
105 in_buf[0] = MX25_READ;
106 in_buf[1] = address >> 16;
107 in_buf[2] = address >> 8;
108 in_buf[3] = address >> 0;
109 if(out_len > 4)
110 {
111 mx25_write_read_byte(in_buf, 4, out_buf, out_len);
112 memmove(&out_buf[0], &out_buf[4], out_len - 4);
113
114 //get the remain bytes.
115 address += (out_len - 4);
116 in_buf[0] = MX25_READ;
117 in_buf[1] = address >> 16;
118 in_buf[2] = address >> 8;
119 in_buf[3] = address >> 0;
120 mx25_write_read_byte(in_buf, 4, remain_4byte, 8);
121 memcpy(&out_buf[out_len - 4], &remain_4byte[4], 4);
122 }
123 else
124 {
125 mx25_write_read_byte(in_buf, 4, remain_4byte, 4 + out_len);
126 memcpy(out_buf, &remain_4byte[4], out_len);
127
128 }
129 //print_hex(__FUNCTION__, out_buf, out_len);
130 return ;
131 }
132
133 /*
134 address:
135 Should 4kbytes align
136
137 cmd:
138 0:Sector Erase(4k)
139 1:Block Erase(32k)
140 2:Block Erase(64k)
141 3:Chip Erase
142 */
143 u8 mx25_Erase(u32 address, u8 cmd)
144 {
145 cmd &= 0x03;
146 u32 timeout_ms[4] = {4000, 4000 * 8, 4000 * 16, 4000 * 100};
147 u8 command[4] = {MX25_SE, MX25_BE32K, MX25_BE64K, MX25_CE};
148 u8 in_buf[10];
149 MX25_StatusRegister_u SR;
150 MX25_SecurityRegister_u SecurityReg;
151 u32 ms = 0;
152
153 mx25_WriteEn();
154 SR.byte = mx25_ReadStatusRegister();
155
156 if(SR.bits.WEL == 0)return 1;
157 address &= 0xFFF000;
158 in_buf[0] = command[cmd];
159 in_buf[1] = address >> 16;
160 in_buf[2] = address >> 8;
161 in_buf[3] = address >> 0;
162 if(cmd == 3)
163 {
164 mx25_write_read_byte(in_buf, 1, 0, 0);
165 }
166 else
167 {
168 mx25_write_read_byte(in_buf, 4, 0, 0);
169 }
170
171 ms = timeout_ms[cmd];
172 while(ms)
173 {
174 SR.byte = mx25_ReadStatusRegister();
175 if(SR.bits.WIP == 0)break;
176 mx25_delay_1ms(1);
177 if(ms)ms--;
178 }
179 SR.byte = mx25_ReadStatusRegister();
180 //SYSTEM_DEBUG("ms=%d,timeout_ms=%d,WEL=%d\n", ms, timeout_ms[cmd] - ms, SR.bits.WEL);
181 if((ms == 0) && (SR.bits.WEL))return 2;
182 SecurityReg.byte = mx25_ReadSecurityRegRegister();
183 if(SecurityReg.bits.E_FAIL)return 3;
184 SYSTEM_DEBUG("address=%08X Erase ok\n", address);
185
186 return 0;
187 }
188
189 /*1Page=256Bytes*/
190 u8 mx25_PageProgram(u32 address, u8* buf, u16 len)
191 {
192 u8 in_buf[300];
193 MX25_StatusRegister_u SR;
194 MX25_SecurityRegister_u SecurityReg;
195 u32 ms = 0;
196 mx25_WriteEn();
197 SR.byte = mx25_ReadStatusRegister();
198 if(SR.bits.WEL == 0)return 1;
199 address &= 0xFFFF00;
200
201 memset(in_buf, 0xFF, sizeof(in_buf));
202 in_buf[0] = MX25_PP;
203 in_buf[1] = address >> 16;
204 in_buf[2] = address >> 8;
205 in_buf[3] = address >> 0;
206 memcpy(&in_buf[4], buf, len);
207
208 mx25_write_read_byte(in_buf, 4 + 256, 0, 0);
209
210 ms = 2000;
211 while(ms)
212 {
213 SR.byte = mx25_ReadStatusRegister();
214 if(SR.bits.WIP == 0)break;
215 mx25_delay_1ms(1);
216 if(ms)ms--;
217 }
218 SR.byte = mx25_ReadStatusRegister();
219 //SYSTEM_DEBUG("ms=%d,timeout_ms=%d,WEL=%d\n", ms, 2000 - ms, SR.bits.WEL);
220 if((ms == 0) && (SR.bits.WEL))return 2;
221 SecurityReg.byte = mx25_ReadSecurityRegRegister();
222 if(SecurityReg.bits.P_FAIL)return 3;
223 //SYSTEM_DEBUG("address=%08X len=%d PP ok\n", address, len);
224
225 return 0;
226 }
227 /*
228 address:
229 Should 4kbytes align
230
231 */
232 u8 mx25_WriteBytes(u32 address, u8* buf, u32 len)
233 {
234 u16 w_len = 0;
235 u8 i = 0;
236 address &= 0xFFF000;
237 //print_hex("-->",buf,len);
238 SYSTEM_DEBUG("address=%08X len=%d\n", address, len);
239
240 while(len)
241 {
242 if(mx25_Erase(address, 0))return 1;
243 for(i = 0; i < (SECTOR_SIZE / PAGE_SIZE); i++)
244 {
245 w_len = (len >= PAGE_SIZE) ? PAGE_SIZE : len;
246 if(w_len == 0)break;
247 if(mx25_PageProgram(address + i * PAGE_SIZE, buf + i * PAGE_SIZE, w_len))return 2;
248 if(len >= PAGE_SIZE)
249 {
250 len -= PAGE_SIZE;
251 if(len == 0)break;
252 }
253 else
254 {
255 len = 0;
256 break;
257 }
258 }
259 if(len == 0)break;
260 address += SECTOR_SIZE;
261 }
262
263 SYSTEM_DEBUG("WR ok\n");
264 return 0;
265 }