Nor flash 原理及硬件操作(2)
回顾:
其实Nor flash的硬件操作---->Nor flash的内存操作---->Nor flash地址和数据操作。
所以,对Nor flash手册的解读至关重要!!!《MX29LV800BT/BB(推荐)/MX29LV160D T/B》
对了,u-boot是裸机开发的集大成者,虚心学习总是没错的。
程序框架:
1 void nor_flash_test(void) 2 { 3 char c; 4 5 /*打印菜单,供我们选择测试内容*/ 6 myprintf("\n\r"); 7 myprintf("[s] Scan nor flash\n\r"); 8 myprintf("[e] Erase nor flash\n\r"); 9 myprintf("[w] Write nor flash\n\r"); 10 myprintf("[r] Read nor flash\n\r"); 11 myprintf("[q] Quit\n\r"); 12 myprintf("Enter selection:"); 13 14 c = getchar(); 15 myprintf("%c\n\r",c); 16 17 /*测试内容: 18 *1.识别nor_falsh 19 *2.擦出nor_flash某扇区 20 *3.编写某个地址 21 *4.读某个地址 22 */ 23 switch(c) 24 { 25 case 's': 26 case 'S': 27 do_scan_nor_flash(); 28 break; 29 30 case 'e': 31 case 'E': 32 do_erase_nor_flash(); 33 break; 34 35 case 'w': 36 case 'W': 37 do_write_nor_flash(); 38 break; 39 40 case 'r': 41 case 'R': 42 do_read_nor_flash(); 43 break; 44 45 case 'q': 46 case 'Q': 47 return; //return直接返回到函数起始位置重新开始执行 48 break; 49 50 default: 51 break; 52 53 } 54 }
基本框架有了,接着我们就来完善每一个选择对应的被调函数:
再回忆一下,在Nor flash 原理及硬件操作(1)中,我们是如何对Nor flash的进行读/写的:
1 md.w addr //读操作命令,参数
2 mw.w addr data //写操作命令,参数
所以,我们最好首先分别封装读/写函数,然后提供给其他的函数使用:
#define NOR_FLASH_BASE 0 //Nor flash的基地址为0
...
1 unsigned int nor_read_word(unsigned int base,unsigned int offset) 2 { 3 volatile unsigned short *p = (volatile unsigned short *)(base + (offset<<1)); 4 return *p; 5 } 6 7 unsigned int nor_dat(unsigned int offset) 8 { 9 return nor_read_word(NOR_FLASH_BASE, offset); 10 }
(1)do_scan_nor_flash函数
1 void do_scan_nor_flash(void) 2 { 3 char str[4]; 4 unsigned int size; 5 int regions,i; 6 int region_info_base; 7 int block_addr, blocks,block_size,j; 8 int cnt; 9 int vendor,device; 10 11 /*打印厂家ID*/ 12 nor_cmd(0x555,0xaa); //解锁 13 nor_cmd(0x2aa,0x55); 14 nor_cmd(0x555,0x90); 15 16 vendor = nor_dat(0); //读ID 17 device = nor_dat(1); 18 19 nor_cmd(0,0xf0); //复位,退出读ID操作 20 21 22 nor_cmd(0x55,0x98); //进入CFI模式,读取其他的信息 23 24 str[0] = nor_dat(0x10); //读QRY确认进入CFI模式 25 str[1] = nor_dat(0x11); 26 str[2] = nor_dat(0x12); 27 str[3] = '\0'; 28 myprintf("str = %s\n\r",str); 29 30 /*打印容量*/ 31 size = (1<<nor_dat(0x27)); //1个数左移n位,就等于将这个数乘以2的n次方 32 myprintf("vendor id = 0x%x,device id = 0x%x,Nor flash size = %dM\n\r",vendor,device,size/(1024*1024)); 33 34 /*打印各个扇区的起始地址*/ 35 regions = nor_dat(0x2c); 36 region_info_base = 0x2d; 37 block_addr = 0; 38 myprintf("Block/sector start Address:\n\r"); 39 cnt = 0; 40 for(i=0; i<regions; i++) 41 { 42 blocks = 1 + (nor_dat(region_info_base) + (nor_dat(region_info_base+1)<<8)); 43 block_size = 256 * (nor_dat(region_info_base+2) + (nor_dat(region_info_base+3)<<8)); 44 region_info_base += 4; 45 46 for(j=0; j<blocks; j++) 47 { 48 /*打印每个block的起始地址*/ 49 printHex(block_addr); 50 putchar(' '); 51 block_addr += block_size; 52 cnt++; 53 if(cnt % 5 == 0 ) 54 { 55 myprintf("\n\r"); 56 } 57 } 58 } 59 myprintf("\n\r"); 60 /*退出CFI模式*/ 61 nor_cmd(0,0xf0); 62 }
(bits:15-0): 2F 0x00 30 0x01 所以要将2F、30合成低16位数0x0100
((bits:15-0) + 1)=blocks
(bits:31-16): 2D 0x0f 2E 0x00 所以要将2D、2E合成高16位数0x000f
(bits:31-16)*256=block_size
(2)do_erase_nor_flash函数
1 void do_erase_nor_flash(void ) 2 { 3 unsigned int addr; 4 5 /*获得地址*/ 6 myprintf("Enter the address of sector to erase: "); 7 addr = get_uint(); //string_utils.c里面的函数,可以直接获得标准输入 8 9 myprintf("Erase ...\n\r"); 10 11 nor_cmd(0x555,0xaa); //解锁 12 nor_cmd(0x2aa,0x55); 13 nor_cmd(0x555,0x80); //擦除 14 15 nor_cmd(0x555,0xaa); //再次解锁 16 nor_cmd(0x2aa,0x55); 17
18 /*扇区地址写入0x30*/
19 nor_cmd(addr>>1,0x30); /*Nor flash 16bits*/ //一个数右移n位,就等于这个数除以2的n次方 20 wait_ready(addr); 21 myprintf("Erasing finished!"); 22 }
(3)由于读/写/擦除都需要时间,所以我们需要设置延时,但是延时又无法保证精准,可能会浪费系统时间。
我们查看手册,看是否有更好的解决办法:
于是wait_ready函数:
1 void wait_ready(unsigned int addr) 2 { 3 unsigned int val; 4 unsigned int pre; 5 6 pre = nor_dat(addr>>1); //先读一次数据 7 val = nor_dat(addr>>1); //再读一次数据 8 9 while((val & (1<<6)) != (pre & (1<<6))) //若两次读取结果不一致,说明说明数据还在变化,继续等待 10 { 11 pre = val; //继续读取 12 val = nor_dat(addr>>1); 13 } 14 }
(4)do_read_nor_flash函数:
1 void do_read_nor_flash(void ) 2 { 3 unsigned int addr; 4 volatile unsigned char *p; 5 int i,j; 6 unsigned char c; 7 unsigned char str[16]; 8 9 /*获得地址*/ 10 myprintf("Enter the address to read: "); 11 addr = get_uint(); 12 13 p = (volatile unsigned char *)addr; 14 15 myprintf("Data :\n\r"); 16 17 /*长度固定为64Bytes*/ 18 for(i=0; i<4; i++) 19 { 20 /*每行打印16个字符数据*/ 21 for(j=0; j<16;j++) 22 { 23 /*先打印数值*/ 24 c = *p++; 25 str[j] = c; 26 myprintf("%02x",c); //格式控制显示结果为2个字节,高位补零 27 myprintf(" "); 28 } 29 30 myprintf(" ;"); 31 for(j=0; j<16;j++) 32 { 33 /*后打印不可显示字符*/ 34 if(str[j] < 0x20 || str[j] > 0x7e) //ASCII码 可显示字符0x20~0x7e 35 { 36 putchar('.'); 37 } 38 else 39 { 40 putchar(str[j]); 41 } 42 } 43 myprintf("\n\r"); 44 } 45 }
(5)do_write_nor_flash函数:
1 void do_write_nor_flash(void ) 2 { 3 unsigned int addr; 4 unsigned char str[100]; 5 int i,j; 6 unsigned int val; 7 8 /*获得地址*/ 9 myprintf("Enter the address of sector to write: "); 10 addr = get_uint(); 11 12 myprintf("Enter the string to write: "); 13 gets(str); 14 15 myprintf("Writing ...\n\r"); 16 17 /*str[0],str[1]==>>16bit*/ 18 /*str[2],str[3]==>>16bit*/ 19 20 i=0; 21 j=1; 22 while(str[i] && str[j]) 23 { 24 val = str[i] + (str[j]<<8); //str[0],str[1]合并成16bit的数据,依次类推... 25 26 /*烧写*/ 27 nor_cmd(0x555,0xaa); //解锁 28 nor_cmd(0x2aa,0x55); 29 nor_cmd(0x555,0xa0); //发出烧写信号 30 nor_cmd(addr>>1,val); 31 32 /*等待烧写完成,读数据Q6无变化时表示结束*/ 33 wait_ready(addr); 34 35 i += 2; //合并str[2],str[3] 36 j += 2; 37 addr += 2; 38 } 39 40 val = str[i]; //10 50 63 00 1f ff ff 41 42 nor_cmd(0x555,0xaa); //解锁 43 nor_cmd(0x2aa,0x55); 44 nor_cmd(0x555,0xa0); //发出烧写信号 45 nor_cmd(addr>>1,val); //写完最后一个高位数据 46 /*等待烧写完成,读数据Q6无变化时表示结束*/ 47 wait_ready(addr);
48
49 myprintf("Writting finished!"); 50 50 }
代码展示:
1 #include "myprintf.h" 2 #include "string_utils.h" 3 4 #define NOR_FLASH_BASE 0 5 6 /*进入nor flash的CFI模式 7 *读取各类信息 8 */ 9 10 /*55H 98*/ 11 /*地址(0+(0x55<<1))写0x98*/ 12 void nor_write_word(unsigned int base,unsigned int offset,unsigned short val) 13 { 14 volatile unsigned short *p = (volatile unsigned short *)(base + (offset<<1)); 15 *p = val; 16 } 17 18 /*offset是基于Nor flash的角度*/ 19 void nor_cmd(unsigned int offset,unsigned int cmd) 20 { 21 nor_write_word(NOR_FLASH_BASE, offset, cmd); 22 } 23 24 unsigned int nor_read_word(unsigned int base,unsigned int offset) 25 { 26 volatile unsigned short *p = (volatile unsigned short *)(base + (offset<<1)); 27 return *p; 28 } 29 30 unsigned int nor_dat(unsigned int offset) 31 { 32 return nor_read_word(NOR_FLASH_BASE, offset); 33 } 34 35 void wait_ready(unsigned int addr) 36 { 37 unsigned int val; 38 unsigned int pre; 39 40 pre = nor_dat(addr>>1); 41 val = nor_dat(addr>>1); 42 43 while((val & (1<<6)) != (pre & (1<<6))) 44 { 45 pre = val; 46 val = nor_dat(addr>>1); 47 } 48 } 49 50 void do_scan_nor_flash(void) 51 { 52 char str[4]; 53 unsigned int size; 54 int regions,i; 55 int region_info_base; 56 int block_addr, blocks,block_size,j; 57 int cnt; 58 int vendor,device; 59 60 /*打印厂家ID*/ 61 nor_cmd(0x555,0xaa); //解锁 62 nor_cmd(0x2aa,0x55); 63 nor_cmd(0x555,0x90); 64 65 vendor = nor_dat(0); //读ID 66 device = nor_dat(1); 67 68 nor_cmd(0,0xf0); //复位 69 70 71 nor_cmd(0x55,0x98); //进入CFI模式 72 73 str[0] = nor_dat(0x10); 74 str[1] = nor_dat(0x11); 75 str[2] = nor_dat(0x12); 76 str[3] = '\0'; 77 myprintf("str = %s\n\r",str); 78 79 /*打印容量*/ 80 size = (1<<nor_dat(0x27)); 81 myprintf("vendor id = 0x%x,device id = 0x%x,Nor flash size = %dM\n\r",vendor,device,size/(1024*1024)); 82 83 /*打印各个扇区的起始地址*/ 84 regions = nor_dat(0x2c); 85 region_info_base = 0x2d; 86 block_addr = 0; 87 myprintf("Block/sector start Address:\n\r"); 88 cnt = 0; 89 for(i=0; i<regions; i++) 90 { 91 blocks = 1 + (nor_dat(region_info_base) + (nor_dat(region_info_base+1)<<8)); 92 block_size = 256 * (nor_dat(region_info_base+2) + (nor_dat(region_info_base+3)<<8)); 93 region_info_base += 4; 94 95 for(j=0; j<blocks; j++) 96 { 97 /*打印每个block的起始地址*/ 98 printHex(block_addr); 99 putchar(' '); 100 block_addr += block_size; 101 cnt++; 102 if(cnt % 5 == 0 ) 103 { 104 myprintf("\n\r"); 105 } 106 } 107 } 108 myprintf("\n\r"); 109 /*退出CFI模式*/ 110 nor_cmd(0,0xf0); 111 } 112 113 void do_erase_nor_flash(void ) 114 { 115 unsigned int addr; 116 117 /*获得地址*/ 118 myprintf("Enter the address of sector to erase: "); 119 addr = get_uint(); 120 121 myprintf("Erase ...\n\r"); 122 123 nor_cmd(0x555,0xaa); //解锁 124 nor_cmd(0x2aa,0x55); 125 nor_cmd(0x555,0x80); //擦除 126 127 nor_cmd(0x555,0xaa); //再次解锁 128 nor_cmd(0x2aa,0x55); 129 nor_cmd(addr>>1,0x30); //扇区地址写入0x30 130 wait_ready(addr); 131 132 myprintf("Erase finished!"); 133 } 134 135 void do_write_nor_flash(void ) 136 { 137 unsigned int addr; 138 unsigned char str[100]; 139 int i,j; 140 unsigned int val; 141 142 /*获得地址*/ 143 myprintf("Enter the address of sector to write: "); 144 addr = get_uint(); 145 146 myprintf("Enter the string to write: "); 147 gets(str); 148 149 myprintf("Writing ...\n\r"); 150 151 /*str[0],str[1]==>>16bit*/ 152 /*str[2],str[3]==>>16bit*/ 153 154 i=0; 155 j=1; 156 while(str[i] && str[j]) 157 { 158 val = str[i] + (str[j]<<8); 159 160 /*烧写*/ 161 nor_cmd(0x555,0xaa); //解锁 162 nor_cmd(0x2aa,0x55); 163 nor_cmd(0x555,0xa0); //发出烧写信号 164 nor_cmd(addr>>1,val); 165 166 /*等待烧写完成,读数据Q6无变化时表示结束*/ 167 wait_ready(addr); 168 169 i += 2; 170 j += 2; 171 addr += 2; 172 } 173 174 val = str[i]; 175 176 nor_cmd(0x555,0xaa); //解锁 177 nor_cmd(0x2aa,0x55); 178 nor_cmd(0x555,0xa0); //发出烧写信号 179 nor_cmd(addr>>1,val); 180 /*等待烧写完成,读数据Q6无变化时表示结束*/ 181 wait_ready(addr); 182 183 myprintf("Writing finished!"); 184 185 } 186 187 void do_read_nor_flash(void ) 188 { 189 unsigned int addr; 190 volatile unsigned char *p; 191 int i,j; 192 unsigned char c; 193 unsigned char str[16]; 194 195 /*获得地址*/ 196 myprintf("Enter the address to read: "); 197 addr = get_uint(); 198 199 p = (volatile unsigned char *)addr; 200 201 myprintf("Data :\n\r"); 202 203 /*长度固定为64Bytes*/ 204 for(i=0; i<4; i++) 205 { 206 /*每行打印16个字符数据*/ 207 for(j=0; j<16;j++) 208 { 209 /*先打印数值*/ 210 c = *p++; 211 str[j] = c; 212 myprintf("%02x",c); 213 myprintf(" "); 214 } 215 216 myprintf(" ;"); 217 for(j=0; j<16;j++) 218 { 219 /*后打印不可显示字符*/ 220 if(str[j] < 0x20 || str[j] > 0x7e) 221 { 222 putchar('.'); 223 } 224 else 225 { 226 putchar(str[j]); 227 } 228 } 229 myprintf("\n\r"); 230 } 231 } 232 233 void nor_flash_test(void) 234 { 235 char c; 236 237 /*打印菜单,供我们选择测试内容*/ 238 myprintf("\n\r"); 239 myprintf("[s] Scan nor flash\n\r"); 240 myprintf("[e] Erase nor flash\n\r"); 241 myprintf("[w] Write nor flash\n\r"); 242 myprintf("[r] Read nor flash\n\r"); 243 myprintf("[q] Quit\n\r"); 244 myprintf("Enter selection:"); 245 246 c = getchar(); 247 myprintf("%c\n\r",c); 248 249 /*测试内容: 250 *1.识别nor_falsh 251 *2.擦出nor_flash某扇区 252 *3.编写某个地址 253 *4.读某个地址 254 */ 255 switch(c) 256 { 257 case 's': 258 case 'S': 259 do_scan_nor_flash(); 260 break; 261 262 case 'e': 263 case 'E': 264 do_erase_nor_flash(); 265 break; 266 267 case 'w': 268 case 'W': 269 do_write_nor_flash(); 270 break; 271 272 case 'r': 273 case 'R': 274 do_read_nor_flash(); 275 break; 276 277 case 'q': 278 case 'Q': 279 return; 280 break; 281 282 default: 283 break; 284 285 } 286 }