하드웨어
짜짠~~~
휴가 갔다가 돌아 왔습니다.
정말 비 맞은 휴가 였습니다. ㅠㅠ
아그들하고 속초 갔는데 비오는 바닷가 수영
진짜 죽입니다 크아~~~~
그외 판타지 & 무협지를 끝없이 봤습니다.
영화 마을 아저씨 무척 좋아 하시더만요...
어쨌든 재 충전 했으면 힘이 나야 하느데..
넘 일을 안했더니 모든것이 귀찮군요 ㅜㅜ
그래도 강좌는 해야 겠죠?
이전에 뭐 했는지 가물 가물 하지만 기억을 되 돌려서
시작해 봅시당... ㅋㅋ
NAND 읽기
이번 강좌는 NAND 읽기 입니다. 당근 읽기가 쓰기보다 편하지용...
(뭐 반드시 그런건 아니지만요 쩝~~~)
하지만 NOR 에 비하면 이전에 말한것과 같이 간단하지 않습니다.
어쨌든 NAND 읽기를 살펴보면 아마도 조금 더 내부동작을 이해 할 수 있을겁니다.
우리는 메모리를 읽을때 특정 위치를 지정합니다. 메모리라면 읽기 위한 주소를 지정해야 하죠...
그 주소라는 것이 실제로 두가지가 존재합니다.
하나는 시스템 메모리 전체를 기준으로 하는 주소와 그 메모리 자체적인 주소죠...
뭐 이걸 base address ( 베이스 어드레스), offset address ( 오프셋 어드레스 )
라고도 말할수 있겠네요 그쵸?
보통 NOR 플래쉬라면 이 두가지 개념을 생각해야 하지만...
NAND 플래쉬라면 오직 한가지 플래쉬 주소만 생각하면 됩니다.
이전에 핀 사양을 보시면 아시겠지만 주소 지정 핀이 없습니다.
그렇다고 각각의 어드레스를 접근하기 위한 주소나 데이터를 넣기 위한 주소를
베이스 어드레스라고 우기면 뭐 할수 없습니다만...
플래쉬 주소는 그 용량에 따라서 범위가 결정되죠..
예를 들어 64MByte 라면 유효 주소 범위는 ...
흠 잠시 계산 합시당.
64 * 1024 * 1024 = 67108864
이 범위가 되는데 저같이 이미 16진수에 익숙한 사람은 이렇게 큰 수치는 언뜻
머리에 들어 오지 않습니다.
이걸 16진수로 바꾸어 보면 다음과 같습니다.
0x4000000
즉 지정이 가능한 범위는 0x0000000 부터 0x3FFFFFF
이것도 보기 어렵죠... 워낙 길어야 말이죠...
그래서 32비트 프로세스가 등장한 이후부터는 이걸 이렇게 표시 합니다.
0000-0000 부터 03FF-FFFF
요렇게 표시 합니다.
어...쨌....든
우리는 플래쉬 메모리에서 특정 번지를 읽어 오고자 합니다.
예를 들어 013A-332F 의 데이터를 읽는 다고 합시당.
NOR 라면 당근 그냥 해당 위치의 주소를 읽어 오면 됩니다.
(물론 쓰기 모드 상태라면 읽기 모드로 변환해 주어야 하거나 좀 기달려야 하겠지만 말입니다)
NOR 플래쉬가 0 번지에 매달려 있다면 그냥 0x013A332F 번지를 읽어오면 끝입니다.
뭐 프로그램 적으로 표시하면 다음과 같이 코딩하면 됩니다.
volatile unsigned char *addr;
addr = (volatile unsigned char *) 0x013A332F;
printf( "%02X\n", *addr );
쉽죠?
근데...
NAND 에서는 이렇게 쉽게 못 읽어 옵니다.
왜냐?
이전에 말했죠?
NAND 내부 구조를 보면 PAGE 단위로 NAND 메모리 셀을 접근한다고요..
즉 NAND는 직접적으로 해당 위치의 데이터를 읽어 오지 못하고 항상
NAND PAGE 버퍼를 통해서 읽어 와야 합니당...
자 이걸 설명하려면 먼저 그림을 보면서 이해해야 합니다.
레퍼런스 매뉴얼에서 제공하는 그림을 슬쩍 봅시다...
[그림 3-10] 읽기 모드 1 타이밍
음...
우선 보아야 할 그림은 하단의 그림중 왼쪽에 있는 그림입니다.
보시면 아시겠지만 왼쪽 그림과 오른쪽 그림이 비슷합니다.
그림중 위에 있는 것이 플래쉬 메모리 셀들이라고 보시면 될것이고
그 밑에 한줄 박스가 바로 페이지 버퍼 레지스터라고 보시면 됩니다.
NAND 플래쉬 메모리에서 데이터를 읽기 위해서는 먼저 메모리 셀에서
페이지 버퍼 레지스터에 옮기는 과정이 필요합니다.
그 다음에 그냥 NAND 플래쉬에 읽기 신호를 주면 버퍼 레지스터에서 순차적으로 출력되고
그것을 프로세서는 읽어 들이는 거죠..
그래서 NAND를 읽기 위해서는
1) 읽으라는 명령을 주고
2) 읽을 위치를 지정하고
3) 읽을 동안 잠시 기다렸다가
4) 필요한 만큼 읽기를 반복
하면 되는 겁니다.
뭐 의외로 간단하죠?
자 그런데 ....
이게 좀 간단하지 않습니다. ...
왜 그럴까요?
우선 보면 아시겠지만 NAND 메모리의 페이지 버퍼는 크게
1st Half Array(256) , 2st Half Array(256), Spare Array(16)
이렇게 나뉘어져 있습니다.
각 영역을 어떤 그림에는 A,B, C 영역이라고도 합니다.
그래서 각 위치를 읽어 올때 명령이 다릅니다.
첫번째 영역에서 부터 읽어 들이려면 0x00 을 명령을 주어야 하고
두번째 영역에서 부터 읽어 들이려면 0x01 명령을 주어야 하고
세번째 영역에서 부터 읽어 들이려면 0x50 명령을 주어야 합니다.
간단한듯 한데
뭐가 복잡하냐?
위 세가지중 하나의 읽기 명령을 지정한 이후에 주소를 지정하는데
여기서 바로 A8 이 빠진 주소로 지정해야 한다는 겁니다.
그림에도 그렇게 표기 되어 있죠?
위에서도 이야기 했지만 플래쉬 메모리를 읽을때 내부 동작은
메모리에서 페이지 버퍼로 데이터가 이동하게 됩니다.
이때 이동되는 데이터 총 수는 528 바이트 입니다.
요거이가 바로 한 페이지죠
이중 16 바이트는 스페어죠..
그래서 실제로 플래쉬 메모리가 페이지 버퍼에 옮길 위치를 지정하기 위해서
사용되는 주소는 A9 부터 A25를 사용하게 됩니다.
그리고 A0 부터 A7 은 페이지 버퍼에서 읽어 오기 위한 위치 포인터로 사용됩니다.
그뒤로 위치 포인터는 읽기를 한번 수행할때마다 자동으로 증가 하게됩니다.
이 증가는 C 영역까지 계속 증가 합니다.
C 영역 끝까지 가면 어떻게 되냐?
그건 다음에 이야기 합시다. 어쨌건 할 이야기니깐...
그래서 스페어를 뺸 나머지 총 512 바이트의 위치를 지정하기 위해서는 A0 부터 A8 까지가 필요한데
이중 A8은 읽기 명령에 따라서 자동 지정되고
그 나머지 8비트 즉 A0 부터 A7은 페이지 버퍼의 각 영역의 시작 위치가 0으로 했을때의 위치가 지정되는 겁니다.
스페어 영역을 읽기 위해서는 A0 에서 부터 A3 까지만 필요하죠... 16 바이트 위치만 지정하면 되므로
A4 부터 A7까지는 별 의미가 없는 겁니다.
그래서 읽기 명령을 써 넣은 후 주소를 4 번 써넣게 되는데
읽기 명령에 읽을 위치중 페이지 버퍼의 영역중 첫번째을 영역을 읽을건지
두번째 영역을 읽을 건지 세번째 영역을 읽을 건지를 정한후 해당 명령를 결정하는 겁니다.
그 뒤에 가장 처음 버퍼의 상대 위치인 주소를 한 바이트로 표현해서 써 넣고 ( A0 ~ A7 )
그 다음 나머지를 주소를 써넣게 됩니다. 이 주소를 페이지 주소라고 합니다.
자....
정리하면 이렇습니다.
NAND 플래쉬 메모리의 주소는 크게 두가지 나누어 볼수 있는데
페이지 주소와 버퍼 위치 주소(또는 컬럼 주소)죠...
페이지 주소는 A9 부터 시작한다고 생각하시면 됩니다.
버퍼 위치 주소는 다시 명령과 주소 지정을 이용해서 지정하고
첫번째 영역과 두번째 영역의 읽기인 경우 A0 ~ A7 으로 지정 하는 것이죠
세번째 스페어 영역은 A0 ~ A7 을 모두 써 넣어야 하지만 (뭐 8비트 단위로 써 넣어야 하는데 당연하겠죠)
A4 부터 A7 은 어떤 값이 되든 상관 없다는 겁니다.
버퍼의 위치를 지정하기 위해서 사용되는 A0 ~ A7을 지정하는 것은
페이지 읽기는 한번에 수행되지만 마지막 위치를 읽기만 해야 한다면 굳이 0 부터 항상 순차적으로
읽어서 그 위치까지 읽을때 까지 읽기를 반복하는 것을 줄이기 위해서 입니다.
근데요...
현실적으로 NAND 플래쉬는 하드 디스크 처럼 사용하고 페이지를 섹터 개념으로 사용하기 땜시
실제로는 거의 0으로 지정해서 읽습니다.
즉 실제 사용할때는 별 의미가 없는데
뭐...
어떤 분들은 그렇게 사용하지 않는 분들도 있지 않겠습니까? 그쵸?
그런 분들에게는 A0 에서 A7도 의미가 있는 겁니다.
리눅스의 블록 디바이스 드라이버라면 거의 읽기 명령으로 00을 사용하고
항쌍 512 바이트를 쭈욱 읽는 방식을 사용합니다.
자 여기서 한가지 기억할 것은 NAND 플래쉬는 읽기 명령을 준후
읽을 주소를 4번 쓰면( 현재 예제로 사용하는 용량일 경우) 그 다음 자동으로
플래시 메모리 페이지에서 페이지 버퍼로 데이터를 옮기게 되는데
이때 시간이 소모 됩니다. 또 이렇게 읽고 있는 동안에는 R/nB 가 Low 로 떨어짐으로써
자기가 바쁘다고 알리는데 읽을수 있는 상태인가를 확인하려면 이 핀을 체크 하면 되겠죠..
벗!!
그러나 실제로 회로를 만들때 R/nB는 잘 사용하지 않습니다.
또 게으른 우리들 프로그래머들은 이 R/nB가 설령 연결되어 있더라도
이 핀의 상태를 체크하도록 프로그램 하지 않습니다.
왜냐...
요 시간이 기껏 해봐야 10uSec 입니다.
그냥 지연 루틴을 넉넉하게 20uSec 정도 준 후 읽어도 아무런 이상이 없기 땜시...
복잡하게 체크 루틴을 만드느니 그냥 지연을 넉넉하게 20uSec를 주는 것이 편하다는 거죠...
편하게 사는 것이 건강하게 사는 길입니다. 흠흠...
자 이렇게 읽는 것을 위에 타이밍도를 봐도 되겠지만 레퍼런스 매뉴얼에 조금 자세하게
나온것이 있는데 그 부분을 그림으로 올려 봅시당...
[그림 3-11] 읽기 모드 1 타이밍 2
보통 메뉴얼에 보면 읽기 모드 1 이라는 것은 첫번째 영역 또는 두번째 영역을 읽는 다는 것이고
이때 사용하는 명령은 0x00 또는 0x01 입니다.
읽기 모드 2 는 스페어 영역을 읽는 다는 것이고 명령은 0x50 입니다.
그리고 위 그림에서 보듯이 주소 지정은 총 4 사이클이 필요한데
가장 첫번째 사이클이 영역의 읽기 시작하는 위치를 지정하고
그 나머지 3 사이클이 페이지 어드레스를 지정하는 겁니다.
아...
오늘도 이정도에서 마무리 지어야 겠네요...
다음 강좌에서는 읽는 부분 방법중 시퀀스 하게 읽는 것을 설명하도록 하겠습니다.
그럼 바바이...