mx25lxx驱动
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 }