JZ2440:norflash
发布时间:2020-12-15 20:05:18 所属栏目:百科 来源:网络整理
导读:采用的器件是:29lv160dbt1-70g 1. 简介 : norflash 的特点是: NOR Flash 的特点是芯片内执行(XIP ,eXecute In Place),这样应用程序可以直接在Flash闪存内运行,不必再把代码读到系统RAM中。 NOR 的传输效率很高,在1~4MB的小容量时具有很高的成本效益
采用的器件是:29lv160dbt1-70g
1. 简介:
norflash 的特点是:
采用的器件:
2. 硬件:给的原理图还是有点瞎的:
这个原理图上型号没有跟实际硬件对应上,其中的几个引脚也是标注“错误”,当然作为批量的东西,找一个通用的元件来代替,本质是没有错误的。
板子上芯片的名字:29lv160dbt1-70g
引脚15:RY/BY# (
Ready/Busy?output
)
引脚47:BYTE# (
Selects?8-bit?or?16-bit?mode
)
? ? 高电平:16位模式,有效的输入输出引脚是 DQ15-DQ0
? ? 低电平:8位模式,有效的输入输出引脚是 DQ7-DQ0,DQ8-DQ14处于三态,DQ15(
the?DQ15?pin?is?used?as?
an?input?for?the?LSB?(A-1)?address?function.?
)
从原理图上看到,引脚47是高电平,这个开发板采用的是16位模式。
3. 编程:3.1?读:系统上电,直接能读U16 read_en29lv160ab(U32 addr) { return *((volatile U16 *)(addr)); } 3.2 软件复位:norflash不仅能硬件复位,也能软件复位,思路是向任一地址写入复位命令 0xf0:
void reset_en29lv160ab(void) { *((volatile U16 *)0x0) = 0xf0; }
norflash 的写和擦除:需要 4 到 6 个周期来完成,每一个周期都要把相应的命令写入 norflash 中的某一个寄存器:
3.3?写操作的过程:
需要知道的几点:
check_toggle函数的作用是:用于判断这次操作是否正确
? ? 它的原理是连续两次读取数据总线上的数据,判断数据总线上的第6位数值(DQ6)是否翻转,如果没有翻转则正确,否则还要判断第5位(DQ5),以确定是否是因为超时而引起的翻转。
#define flash_base 0x00000000 #define CMD_ADDR0 *((volatile U16 *)(0x555<<1+flash_base)) #define CMD_ADDR1 *((volatile U16 *)(0x2aa<<1+flash_base)) U8 en29lv160ab_program(U32 addr,U16 dat) { CMD_ADDR0 = 0xaa; CMD_ADDR1 = 0x55; CMD_ADDR0 = 0xa0; *((volatile U16 *)(addr)) = dat; return check_toggle(); } U8 check_toggle() { volatile U16 newtoggle,oldtoggle; oldtoggle = *((volatile U16 *)0x0); while(1) { newtoggle = *((volatile U16 *)0x0); if((oldtoggle & 0x40)==(newtoggle & 0x40)) break; if(newtoggle & 0x20) //DQ5 { oldtoggle = *((volatile U16 *)0x0); newtoggle = *((volatile U16 *)0x0); if((oldtoggle & 0x40)==(newtoggle & 0x40)) break; else return 0; //错误 } oldtoggle = newtoggle; } return 1; //正确 } 3.4?擦除操作的过程:
写操作只能使“1”变为“0”,而只有擦除才能使“0”变为“1”。因此在写之前一定要先擦除。
// 输入参数为擦除块的首地址 U8 en29lv160ab_sector_erase(U32 section_addr) { CMD_ADDR0 = 0xaa; CMD_ADDR1 = 0x55; CMD_ADDR0 = 0x80; CMD_ADDR0 = 0xaa; CMD_ADDR1 = 0x55; *((volatile U16 *)(section_addr)) = 0x30; return check_toggle(); } 3.5 读取芯片的 ID:
//读厂商 ID U32 get_en29lv160ab_id(void) { U32 temp=0; CMD_ADDR0 = 0xaa; CMD_ADDR1 = 0x55; CMD_ADDR0 = 0x90; temp = (*(volatile unsigned short *)(flash_base+ (0x100<<1)))<<16; temp |= *(volatile unsigned short *)(flash_base + (1<<1)); return temp; } 4. 例子:
下面的程序实现了对一块区域进行擦除,写入,并读出的操作,判断写入的数据是否与读出的数据相同:
CFI:是一个记录芯片信息的接口,可以通过特定的命令来访问这些数据
…… …… U16 buffer[1024]; char cmd; …… …… void test_en29lv160ab(void) { U32 temp; U8 sta; int i; for(i=0;i<1024;i++) buffer[i]=2*i+1; //读ID temp = get_en29lv160ab_id(); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)((temp&0xff000000)>>24); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)((temp&0x00ff0000)>>16); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)((temp&0x0000ff00)>>8); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)((temp&0x000000ff)); reset_en29lv160ab(); //这里一定要复位 delay(100); //擦除块33 sta=en29lv160ab_sector_erase(0xf0000); if(sta == 0) { while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=0xaf; //擦除出错 } else { for(i=0;i<1024;i++) { sta = en29lv160ab_program(0xf0000+(i<<1),buffer[i]); //写 if(sta == 0) //写出错 { while(!(rUTRSTAT0 & 0x2)); rUTXH0=0xbf; break; } delay(200); } if(sta == 1) { for(i=0;i<1024;i++) { if(read_en29lv160ab(0xf0000+(i<<1))!=buffer[i]) //读出错 { while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=0xcf; sta = 3; break; } } if(sta !=3) //全部操作都正确 { while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=0x66; } } } while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=0x88; //结束 } //简单测试CFI void test_en29lv160ab_CFI(void) { U16 temp; *((volatile U16 *)(0x55<<1+flash_base))=0x98; //CFI命令 temp = (*(volatile unsigned short *)(flash_base+ (0x10<<1))); //while(!(rUTRSTAT0 & 0x2)) ; //rUTXH0=(U8)((temp&0xff00)>>8); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)(temp&0x00ff); temp = (*(volatile unsigned short *)(flash_base+ (0x11<<1))); //while(!(rUTRSTAT0 & 0x2)) ; //rUTXH0=(U8)((temp&0xff00)>>8); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)(temp&0x00ff); temp = (*(volatile unsigned short *)(flash_base+ (0x12<<1))); //while(!(rUTRSTAT0 & 0x2)) ; //rUTXH0=(U8)((temp&0xff00)>>8); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)(temp&0x00ff); temp = (*(volatile unsigned short *)(flash_base+ (0x13<<1))); //while(!(rUTRSTAT0 & 0x2)) ; //rUTXH0=(U8)((temp&0xff00)>>8); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)(temp&0x00ff); temp = (*(volatile unsigned short *)(flash_base+ (0x14<<1))); //while(!(rUTRSTAT0 & 0x2)) ; //rUTXH0=(U8)((temp&0xff00)>>8); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)(temp&0x00ff); temp = (*(volatile unsigned short *)(flash_base+ (0x15<<1))); //while(!(rUTRSTAT0 & 0x2)) ; //rUTXH0=(U8)((temp&0xff00)>>8); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)(temp&0x00ff); temp = (*(volatile unsigned short *)(flash_base+ (0x16<<1))); //while(!(rUTRSTAT0 & 0x2)) ; //rUTXH0=(U8)((temp&0xff00)>>8); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)(temp&0x00ff); temp = (*(volatile unsigned short *)(flash_base+ (0x17<<1))); //while(!(rUTRSTAT0 & 0x2)) ; //rUTXH0=(U8)((temp&0xff00)>>8); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)(temp&0x00ff); temp = (*(volatile unsigned short *)(flash_base+ (0x18<<1))); //while(!(rUTRSTAT0 & 0x2)) ; //rUTXH0=(U8)((temp&0xff00)>>8); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)(temp&0x00ff); temp = (*(volatile unsigned short *)(flash_base+ (0x19<<1))); //while(!(rUTRSTAT0 & 0x2)) ; //rUTXH0=(U8)((temp&0xff00)>>8); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)(temp&0x00ff); temp = (*(volatile unsigned short *)(flash_base+ (0x1a<<1))); //while(!(rUTRSTAT0 & 0x2)) ; //rUTXH0=(U8)((temp&0xff00)>>8); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)(temp&0x00ff); } void __irq uartISR(void) { char ch; rSUBSRCPND |= 0x1; rSRCPND |= 0x1<<28; rINTPND |= 0x1<<28; ch=rURXH0; switch(ch) { case 0x11: //get ID cmd = 1; break; case 0x66: //test CFI cmd = 6; break; case 0x77: //test norflash cmd = 7; break; } while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=ch; } void Main(void) { U32 temp; int i; //uart0 port rGPHCON = 0x00faaa; rGPHUP = 0x7ff; //init uart0 rULCON0 = 0x3; rUCON0 = 0x5; rUFCON0 = 0; rUMCON0 = 0; rUBRDIV0 = 26; rSRCPND = (0x1<<19)|(0x1<<28); rSUBSRCPND = 0x1; rINTPND = (0x1<<19)|(0x1<<28); rINTSUBMSK = ~(0x1); rINTMSK = ~((0x1<<19)|(0x1<<28)); pISR_UART0 = (U32)uartISR; cmd = 0; while(1) { switch(cmd) { case 1: //读ID cmd = 0; temp = get_en29lv160ab_id(); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)((temp&0xff000000)>>24); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)((temp&0x00ff0000)>>16); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)((temp&0x0000ff00)>>8); while(!(rUTRSTAT0 & 0x2)) ; rUTXH0=(U8)((temp&0x000000ff)); reset_en29lv160ab(); break; case 0x7: cmd = 0; test_en29lv160ab(); break; case 0x6: cmd = 0; test_en29lv160ab_CFI(); reset_en29lv160ab(); break; } } } 博客参考: s3c2440对norflash的操作 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |