NOR-플래시 메모리 제어 (2)

2005.07.04 20:07

단장 조회 수:961 추천:29

   플래시메모리 읽고 쓰기

     오랜만에 강의를 올립니다. 이번강의는 플래시를 직접 제어하겠습니다.

   2.2.0 스트라타 플래시 읽기


     너무 쉬어요. 그냥주소 주고 읽습니다. 메모리하고 같지요.

   2.2.1 스트라타,부트블럭 플래시 ID 읽기


     모든 플래시의 제어에 있어 ID 읽기가 기본입니다. (읽어온 값을 미리 알고 있으니까..)


     이것만 읽는다면 하드웨어의 연결이나 타이밍은 95퍼센트 완벽하다고 믿을수 있지요.



     이후는 소프트웨어에서 해결할 문제만 남아있을 뿐입니다.

     모든 플래시는 각각의 고유한 ID가 있습니다. 우선 제조사번호와 디바이스 번호(크기,타입)등이 반드시 있고요.

     스트라타 메뉴얼의 Table-4 (12-page)를 보면 Command가 나와있습니다.




     부트블럭은 Table-5 (15-page)입니다.


     그중 Read Identifier Codes 란 명령어를 해석해보면 기냥 ID읽기 입니다.

     #define BASE_ADDR
     unsigned short *fadr; // 플래시의 주소

     처음 할 일은 플래시의 상태를 특별한 상태로 변경하는 것입니다.




     명령에 따라 상태는 변경되며 명령이 끝나면 다시 정상상태(읽기)로 바꾸어 줍니다.



     다시한번 설명하면 최초의 플래시 상태는 읽기만 가능한 상태이고, 플래시이기 때문에 쓰는 동작은



     금지되어 있습니다.
    



ID읽기 커멘드는 0x90입니다



     // 명령어  

    fadr = BASE_ADDR;     // 플래시의 CS가 움직이는 영역이면 된다.
    *fadr = 0x90;              //  command Read ID

커멘드 줬으면 ID를 읽어봅시다.

    // 명령어에 따른 부가적인 행동

    fadr = BASE_ADDR+0*2;     // 제조사코드가있는 주소
    (제조사)= *fadr;

    fadr = BASE_ADDR+1*2;    // 플래시의 디바이스코드가 있는 주소
    (코드) = *fadr;                 // 코드값을 보고 크기를 분석한다.

커멘드를 끝낸다.(반드시 이동작을 해야만 합니다.)



    // 명령 끝

    fadr = BASE_ADDR;      // 플래시의 CS가 움직이는 영역이면 됩니다.
    *fadr = 0xff;                 // 읽기모드로 변경해야 합니다.







      

     너무 쉽지요 여기까지는....

     √  주의

     BASE_ADDR + offset * 2 라는 것을 주의해야 합니다.


     offset은 메뉴얼에 명시된 주소이지요. 이것에 2를 곱하는 이유는 메뉴얼에 나온 주소는 Word 단위의



     주소이기 때문입니다.

   2.2.2 스트라타 플래시 정보읽기
  

     이명령은 플래시의 쓰기버퍼크기, 지우기 시간, 쓰기(퓨징)시간, 이때 소모되는 전류와 필요한 전압등이



     기재되어 있습니다.






    //명령어

    fadr = BASE_ADDR;     // 플래시의 CS가 움직이는 영역이면 된다.
    *fadr = 0x98;              // command Read Query

    //명령어에 따른 부가적인 행동

    fadr = BASE_ADDR+0x27*2;         // 플래시의 정확한 크기가 있는 영역
    (크기) = 2^(*fadr);                     // 16MByte 일경우 2^24

    fadr = BASE_ADDR+0x2A*2;      // 쓰기버퍼의 크기가 있는 영역
    (버퍼크기) = 2^(*fadr);             // 2^5 = 32



    //명령 끝

    fadr = BASE_ADDR;        // 플래시의 CS가 움직이는 영역이면 됩니다.
    *fadr = 0xff;                   // 읽기모드로 변경해야 합니다.




     폼나는 프로그램을 작성하려면 이것을 읽어 사용해 보세요


     하지만 여기서는 사용하지 않습니다. (시간이 없어서.. ^^)


     우리는 스트라타 또는 부트블럭 플래시라는 것과 위에서 읽은 디바이스 크기만을 가지고 작성합니다.


     스트라타이면 버퍼의 크기는 32-Word 이고요.


     부트블럭이면 1-word 입니다.

   2.2.3 플래시 블럭 쓰기금지/쓰기금지해제


     플래시에 데이타를 쓴다는 것은 지워지지 않는 데이타가 필요하기 때문입니다.


     함부로 지우지 못하도록 하드웨어 핀으로 안전장치를 했으며 소프트웨어적으로는 블럭마다 락(LOCK)을



     걸수있지만 플래시를 쓰거나 지우기위해서는 이 락을 풀어야 합니다.



     물론 락이 걸려있지 않다면 풀이유는 없습니다.

     이것에 대한 사용예는 2.2.4에서 다루겠습니다.

     락을 푼이후에 데이타를 쓴후 다시 락을 걸면 데이타가 임의로 지워지는 것을 막을수 있을겁니다.



     만일 락을 걸고 MTD를 올리면 이 영역은 쓰기가 금지됩니다.


   2.2.4 플래시 블럭 지우기


     쓰기위해서 지워야 하는것은 누구나 알고있는 사실이지요.


     스트라타 플래시 블럭의 크기는 128KByte 입니다.


     숫자로 보면 0x20000 로 증가하는 주소이고요.


     부트블럭은 0x10000 증가합니다.(64KByte)

     부트블럭에서 주의할점은 처음블럭 또는 마지막블럭이 8개로 나누어져 있다는 점입니다.



     부트블럭 Bottom의 경우


     0x00000 0x02000 0x04000 0x06000 .... 0x0E000 // 8개 블럭
     0x10000 // 9번째 블럭
     0x20000 // 10번째 블럭

     #define BA // 플래시 블럭주소

     블럭에 락이 걸려있는지 확인합니다.






    //명령어

    fadr = BASE_ADDR+BA;      // 플래시의 블록주소
    *fadr = 0x70;                     // command Read Status

    //명령어에 따른 부가적인 행동
    fadr = BASE_ADDR+BA+2*2;     // 락정보가 있는 주소
    (락정보) = *fadr;                     // 락정보의 d0 비트가 1이면 락이 걸린 것이다.

     락이 걸려있으면 락을 푼다.

    //명령어
    fadr = BASE_ADDR+BA;      // 플래시의 CS가 움직이는 영역이면 된다.
    *fadr = 0x60;                     // command Set Block Lock-Bit

    //명령어에 따른 부가적인 행동
    fadr = BASE_ADDR+BA;       // 플래시의 블록주소
    *fadr = 0xd0;                      // 락을 푼다.

    //명령 수행이 끝났는지 확인
    fadr = BASE_ADDR;      // status 레지스터 첫번째 주소
    while (1)
    {
            // status 레지스터 d7 비트 확인
            if (0x0080 & *fadr) break;      // SR.7 = 0 이면 busy
     }

SR 이라는 것은 status 레지스터를 말하며 위의 코드는 status 레지스터
첫번째 바이트를 읽은 것이다. status 레지스터를 읽기 위해서는 0x70 명령을
줘야 하지만 지우기,쓰기,락 등의 명령를 준 이후에 읽기를 하면 status
레지스터를 읽을수 있다.

이제 블럭을 지운다.

    //명령어
    fadr = BASE_ADDR+BA;      // 플래시의 블록주소
    *fadr = 0x20;                     // command Block Erase

    //명령어에 따른 부가적인 행동
    fadr = BASE_ADDR+BA;    // 플래시의 블록주소
    *fadr = 0xd0;                   // command Confirm

    //명령 수행이 끝났는지 확인
    fadr = BASE_ADDR;         // status 레지스터 첫번째 주소
    while (1)
    {
           // status 레지스터 d7 비트 확인
           if (0x0080 & *fadr) break;       // SR.7 = 0 이면 busy
     }

    //상태를 읽어 성공했는지 확인
    fadr = BASE_ADDR;      // status 레지스터 첫번째 주소
    SR = *fadr;

    // SR.3 = 0 프로그램전압 OK
    // SR.1 = 0 unlock
    // SR.5 = 0 지우기성공
    if ( ( SR.3 == 0 ) && ( SR.1 == 0 ) && ( SR.5 == 0 ) )
    {
          지우기 성공
     }
     else
    {
          지우기 실패
     }

    //상태비트 클리어
    fadr = BASE_ADDR;      // 플래시의 CS가 움직이는 영역이면 된다.
    *fadr = 0x50;               // command Clear Status



    //명령 끝

    fadr = BASE_ADDR;     // 플래시의 CS가 움직이는 영역이면 됩니다.


    *fadr = 0xff;                // 읽기모드로 변경해야 합니다.






     지우기 동작은 while 문에서 최대 1초정도 대기하므로 멀티수행을 고려해 봐야 합니다.


     아울러 시간초과 루틴을 필요로 하지요.

   2.2.5 플래시에 1바이트 또는 1워드 쓰기


     쓰기버퍼가 없다면 한개의 워드씩 다음과 같이 써야합니다.


     스트라타 플래시도 한개씩 쓸수 있습니다.

     #define PA // 쓰고자 하는 주소
     #define DA // 쓰려는 데이타





   //명령어

   fadr = BASE_ADDR;      // 플래시의 CS가 움직이는 영역이면 된다.
   *fadr = 0x40;                // command Write Word/Byte

   //명령어에 따른 부가적인 행동
   fadr = BASE_ADDR+PA;     // 쓰고자 하는 주소
   *fadr = DA;

   //명령 수행이 끝났는지 확인
   fadr = BASE_ADDR;        // status 레지스터 첫번째 주소
   while (1)
   {
              // status 레지스터 d7 비트 확인
              if (0x0080 & *fadr) break;   // SR.7 = 0 이면 busy
    }
    // 위의 while 문은 최대 2msec 소요된다.

   //상태를 읽어 성공했는지 확인
   fadr = BASE_ADDR;    // status 레지스터 첫번째 주소
   SR = *fadr;

    // SR.3 = 0 프로그램전압 OK
    // SR.1 = 0 unlock
    // SR.4 = 0 프로그램 성공
    If ( ( SR.3 == 0 ) && ( SR.1 == 0 ) && ( SR.4 == 0 ) )
    {
          프로그램 성공
     }
     else
     {
          프로그램 실패
     }

    //상태비트 클리어
    fadr = BASE_ADDR;         // 플래시의 CS가 움직이는 영역이면 된다.
    *fadr = 0x50;                  // command Clear Status



    //명령 끝

   fadr = BASE_ADDR;         // 플래시의 CS가 움직이는 영역이면 됩니다.
   *fadr = 0xff;                    // 읽기모드로 변경해야 합니다.






     여러개의 테이타를 쓰기위해서는 위의 루틴을 반복합니다.




     속도가 느리겠죠...

   2.2.6 스트라타 플래시 버퍼 쓰기 명령


     스트라타만이 이 명령을 지원합니다.

     #define LEN 16 // 쓰기버퍼최대 크기
     unsigned short buff[LEN];// 데이타버퍼
     int wdcnt; // 워드데이타 카운트





   //명령어
   fadr = BASE_ADDR+BA;      // 플래시의 블록주소
   *fadr = 0xE8;                    // command Write Word/Byte

   //명령 수행이 끝났는지 확인
   fadr = BASE_ADDR;          // status 레지스터 첫번째 주소
   while (1)
   {
          // status 레지스터 d7 비트 확인
          if (0x0080 & *fadr) break;    // SR.7 = 0 이면 busy
    }




   //버퍼에 쓸 갯수를 알려준다
   fadr = BASE_ADDR+BA;         // 플래시의 블록주소
   wdcnt = 16;                          // 임의로 최대값을 넣었다.
   wdcnt --;                             // 0 이면 한개의 워드이다.
   *fadr = count;

   버퍼의 크기는 32-byte 이므로 16-word 가 된다.
   그러므로 wdcnt 는 0 ~ 15 사이의 값이 된다.

    //카운트만큼 쓴다
    fadr = PA;                 // 쓰려는 첫번째 주소
    for (idx=0; idx<wdcnt; idx++)
    {
           *fadr = buff[idx];
            fadr += 2;        // 16비트 버스이므로 2씩 증가한다.
     }

    //프로그램 명령을 준다
    fadr = BASE_ADDR+BA;     // 플래시의 블록주소
   *fadr = 0xd0;                     // command Confirm

    //명령 수행이 끝났는지 확인
    fadr = BASE_ADDR;          // status 레지스터 첫번째 주소
    while (1)
    {
          // status 레지스터 d7 비트 확인
          if (0x0080 & *fadr) break;       // SR.7 = 0 이면 busy
    }
   // 위의 while 문은 최대 2msec 소요된다.

    //상태를 읽어 성공했는지 확인
    fadr = BASE_ADDR;         // status 레지스터 첫번째 주소
    SR = *fadr;

    // SR.3 = 0 프로그램전압 OK
    // SR.1 = 0 unlock
    // SR.4 = 0 프로그램 성공
    if ( ( SR.3 == 0 ) && ( SR.1 == 0 ) && ( SR.4 == 0 ) )
    {
        프로그램 성공
    }
    else
   {
        프로그램 실패
   }

   //상태비트 클리어
   fadr = BASE_ADDR;     // 플래시의 CS가 움직이는 영역이면 된다.
   *fadr = 0x50;               // command Clear Status


   //명령 끝

   fadr = BASE_ADDR;    // 플래시의 CS가 움직이는 영역이면 됩니다.
   *fadr = 0xff;               // 읽기모드로 변경하면 됩니다.






     여러개의 테이타를 쓰기위해서는 위의 루틴을 반복하고


     다시한번 쓰기 위해서는 블럭이 지워져 있어야 합니다.

   2.2.7 기타의 명령어들


     그외에 몇개의 명령이 있지만 설명하지 않겠습니다.


     메뉴얼을 보면 나와있으니 필요하면 참고하십시오.

     이번 강의에 기술된 내용은 모두 메뉴얼에 나온것입니다.



     메뉴얼 뒷쪽에 플로워 챠트가 있으니 확인하면 됩니다.


     인텔플래시가 아닌 다른 플래시도 이와 비슷한 형식을 따릅니다.


     직접 제어해보지 않은 이상 확실한 이해는 어려울 것입니다.



     시간이 되면 직접 코딩하여 플래시에 데이타를 써보십시오.


     듣고싶은(?) 강의가 있으시면 메일이나 강의게시판에 올려주시기 바랍니다..



     아는 내용이면 이후의 강의에 포함하도록 하죠..


댓글 0

파일 첨부

여기에 파일을 끌어 놓거나 파일 첨부 버튼을 클릭하세요.

파일 크기 제한 : 0MB (허용 확장자 : *.*)

0개 첨부 됨 ( / )
 
목록
번호 제목 글쓴이 날짜 조회 수
24 아마추어 암호 설계자에게 주는 충고 by 브루스 슈나이어 단장 2005.12.22 983
23 AMD CPU 리퍼런스 테이블 단장 2005.07.11 978
22 서울 시내에서 '무료'로 주차하기 단장 2007.03.06 976
21 R6002 floating point not loaded ??? 단장 2006.05.16 973
20 VC 디버그빌드에서 들어가는 쓰레기값들의 의미 단장 2006.04.15 964
19 이펙터 단장 2006.06.14 962
» NOR-플래시 메모리 제어 (2) 단장 2005.07.04 961
17 유명 다이아몬드들 단장 2007.01.31 960
16 일어 12월명 [1] 단장 2006.03.21 933
15 귤화위지의 고사 단장 2005.10.03 924
14 No Silver Bullet 단장 2007.01.04 911
13 이해의 선물 단장 2007.03.02 909
12 부동산 매수 시 고려해야 할 38가지 단장 2006.04.19 882
11 파워맥에 들어가는 배터리 단장 2005.06.28 864
10 오자서 평전 단장 2005.09.26 855
9 플래시 메모리 쉽게 끝내기 (1) 단장 2005.07.04 855
8 해외 취업, 미국으로 가는 길 단장 2006.04.26 849
7 빠른 1/sqrt(n) 계산방법 단장 2014.03.05 549
6 마포에서 AF되는 포서드용 렌즈들 단장 2014.02.13 436
5 VC 2012이후에서 릴리즈 빌드 스택변수들 디버깅하기 file 단장 2014.03.05 401