mx25lxx驱动

发布时间 2023-12-21 10:15:10作者: =天赋=
  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.E_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 }