[TMS320F28069M] SPI(Serial Peripheral Interface)-2(with AT45DB041, Flash Memory)

728x90
반응형

https://vuzwa.tistory.com/entry/TMS320F28069M-SPISerial-Peripheral-Interface-1?category=1034782 

 

[TMS320F28069M] SPI(Serial Peripheral Interface)-1(with AT45DB041, Flash Memory)

SCI(UART) 포스팅을 끝내지 않고 SPI로 넘어왔다. 해야 할 일이 있어서 넘어왔다. TI DSP에서 SPI를 사용할 수 있는 방법은 크게 두 가지다. 기본적으로 제공하는 SPI를 사용하는 방법과 McBSP를 사용하는

vuzwa.tistory.com

 

 

이전 포스팅에 이어 AT34DB041에 데이터를 쓰고, 데이터를 읽어오는 방법과 코드 작성에 대해 포스팅하겠다.

 

 

AT45DB041메모리 구성 먼저 살펴보자. 데이터 시트 4페이지를 모면 Memory Architecture가 보인다.

 

메모리(Flash, EEPROM 등)는 일반적으로 위 그림에서 보이는 것과 같이 SECTOR, BLCOK, PAGE로 영억을 나눈다. 우선 가장 오른쪽에 페이지 먼저 살펴보자. PAGE 0부터 시작해서 가장 아래 PAGE 2,047까지 총 2048 개의 PAGE가 보인다. 

메모리에서 1 PAGE는 256Byte의 용량을 갖는다. 즉, 1페이지에 256Byte를 저장할 수 있다는 뜻이다. 맨 아래 보면 "Page 256/264 bytes"라는 설명이 보이는데 AT45DB041은 1 PAGE에 저장할 수 있는 데이터의 양을 256 또는 264 Byte로 설정할 수 있는데 일반적으로 256Byte로 설정해 사용한다. 이유는 2의 제곱으로 딱 떨어지기 때문이다. 

 

여기서 말하는 PAGE라는 단어는 쉽게 생각하면 우리가 사용하는 노트의 1장이라고 생각하면 된다. "노트의 첫 번째 장( PAGE 0)에 쓸 수 있는 글자의 수는 256개(256Byte)다."라고 이해하면 쉬울 것 같다. 

 

가운데 BLOCK를 살펴보자. BLOCK는 0번부터 맨 아래 255까지 총 256개의 BLOCK이 있다. 한 개의 BLCOK은 8개의 PAGE로 구성된다. 즉, 8개의 PAGE를 묶어 놓은 것을 의미한다. 

 

맨 왼쪽에 SECTOR은 0번부터 7번까지 총 8개로 나눠지고 0번 SECTOR는 다시 a와 b로 나눠진다.  SECTOR는 영역마다 PAGE의 개수가 다르다. SECTOR은 BLCOK 보다 더 큰 의미로 0~31개의 BLCOK을 모아놓은 것을 의미한다. 

 

여기서 가장 중요한 것은 PAGE다. 일반적으로 데이터를 쓰고 읽을 때는 PAGE단위로 읽고 쓴다. 메모리의 종류에 따라서는 BLOCK단위로 읽고 쓰는 것도 있다.

 

 

AT45DB041은 264Byte가 PAGE의 기본 용량이다. 보통 256으로 바꿔서 사용한다. 

 

0x3D, 0x2A, 0x80, 0xA6을 보내면 1 PAGE의 용량을 256Byte로 변경할 수 있는데. 다시 264로 되돌리는 방법은 안 나와 있다. 내가 못 찾는 건지.. 아직까지 찾지 못했다. 코드로 구현해보면

void AT45DB041_set_pagesize_binary(void)
{
	// 1page = 256 byte 
	Uint8 data[4] = {AT45_BINARY_PAGE_FIRST_OPCODE, 0x2A, 0x80, 0xA6};
	
	AT45_CS_L;
	spia_xmit(data[0]);
	spia_xmit(data[1]);
	spia_xmit(data[2]);
	spia_xmit(data[3]);
	AT45_CS_H;
}

 

이렇게 설정하고 재부팅한 다음 상태 레지스터를 읽어보면 설정이 정상적으로 되었는지 확인할 수 있다.

 

 

status 레지스터의 0번 bit 값이 1이면 PAGE 당 256byte로 0이면 페이지당 264Byte로 구성된다. 

 

상태 레지스터는 코드는.

Uint8 AT45DB041_Get_Status(void)
{
	/*	bit 7, 1 : Ready, 0 : Device busy
		Busy state : 
		Main Memory Page to Buffer Transfer, 
		Main Memory Page to Buffer Compare,
		Buffer to Main Memory Page Program, 
		Main Memory Page Program through Buffer, 
		Page Erase, 
		Block Erase, 
		Sector Erase, 
		Chip Erase and Auto Page Rewrite.		*/

	/*	bit 6 : 1 : not match, 0 : match 
		The result of the most recent Main Memory Page to Buffer Compare operation is indicated using bit 6 of the status register.	*/

	/*	bit 1, 1 : sector protection enable, 0 : sector protection disable	*/
	/*	bit 0, 1 : page size 256byte, 0 : page size 264 byte*/
	AT45_CS_L;
	
	spia_xmit(0xD7); // Opcode
	gAT45DB041.Status.all = spia_xmit(0x00); // read status
		
	AT45_CS_H;

	return gAT45DB041.Status.all;
}

 

여기서 보이는 gAT45DB041.Status.all은 내가 만든 구조 체고, 주석은 레지스터에 관한 내용을 정리해 적어놓은 것이다. 

 

그럼 데이터를 써보자. 데이터는 PAGA 단위로 쓰고 읽는다. 즉 한 번에 256 또는 264Byte씩 쓰고 읽어야 된다.

왼쪽 그림은 메모리를 저장하는 순서고, 오른쪽 그림은 메모리의 Block diagram이다.

AT45DB041에는 2개의 Buffer가 있고, 데이터를 쓸 때는 Buffer를 지나 Main memory에 바로 쓰는 방법과 버퍼에 넣어두고 Main memory에 쓰는 방법 두 가지가 있다. 커맨드와 주소는 아래 데이터 시트 내용 참고,

 

 

 

 

git에 다른 코드들을 찾아보니 BUFFER WRITE -> BUFFER TO MAIN MEMORY PAGE PROGRAM 순으로 데이터를 저장해서 나도 똑같이 구현했다. 아래 코드는 메모리에 데이터를 쓰는 기능을 하는 함수다.

void AT45_WritePage(Uint8 buffer, Uint16 addr, Uint8 data[264])
{
	Uint8 cmd[4] = {0x00, };
	Uint16 i=0, size = 0;

	if(buffer == 1)	{
		cmd[0] = AT45_BUFFER_1_WRITE;
	}
	else if(buffer == 2)	{
		cmd[0] = AT45_BUFFER_2_WRITE;
	}
	cmd[1] = 0x00;
	cmd[2] = 0x00;
	cmd[3] = 0xff;

	if(gAT45DB041.Status.bit0_PageSize == 1)	{
		size = 256;
	}
	else {
		size = 264;
	}
	
	AT45_CS_L;
	spia_xmit(cmd[0]);
	spia_xmit(cmd[1]);
	spia_xmit(cmd[2]);
	spia_xmit(cmd[3]);

	for(i=0;i<size;i++)	{
		spia_xmit(*(data+i));
	}
	AT45_CS_H;

	// delay
	DELAY_US(100);

	AT45_CS_L;
	if(buffer == 1)	{
		cmd[0] = AT45_PAGE_1_WRITE;
	}
	else if(buffer == 2)	{
		cmd[0] = AT45_PAGE_2_WRITE;
	}
	cmd[1] = ((addr>>8) & 0x00ff);
	cmd[2] = addr & 0x00ff;
	cmd[3] = 0x00;

	spia_xmit(cmd[0]);
	spia_xmit(cmd[1]);
	spia_xmit(cmd[2]);
	spia_xmit(cmd[3]);
	AT45_CS_H;

	DELAY_US(100);
	AT45DB041_Get_Status();
	while((AT45DB041_Get_Status() & 0x80) == 0)	{
		
	}
}

설명은 Pass(코드 자체가 설명이다.)

 

데이터를 읽어올 때는 command를 한 번만 전송해 주면 된다. 쓰는 동작은 buffer -> main memory 순서였지만, 읽어 올 때는 이 과정을 거치지 않고 바로 읽어올 수 있다. 아래 데이터 시트 내용 참고

 

데이터를 읽어오는 함수

void AT45_ReadPage(Uint32 addr, Uint8 d[264])
{
	Uint8 cmd[8] = {0x00, };
	Uint16 i=0, size;

	cmd[0] = AT45_PAGE_READ;
	cmd[1] = ((addr>>15) & 0xff);
	cmd[2] = ((addr>>7) & 0xfe);
	cmd[3] = 0x00;
	cmd[4] = 0x00;
	cmd[5] = 0x00;	
	cmd[6] = 0x00;
	cmd[7] = 0x00;


	if(gAT45DB041.Status.bit0_PageSize == 1)	{
		size = 256;
	}
	else {
		size = 264;
	}

	AT45_CS_L;
	spia_xmit(cmd[0]);
	spia_xmit(cmd[1]);
	spia_xmit(cmd[2]);
	spia_xmit(cmd[3]);
	spia_xmit(cmd[4]);
	spia_xmit(cmd[5]);
	spia_xmit(cmd[6]);
	spia_xmit(cmd[7]);
	
	for(i=0;i<size;i++)	{
		d[i] = spia_xmit(0x00);
	}
	
	AT45_CS_H;
}

 

Write, Read 함수 모두 줄일 수 있는 부분이 있다. 우선 포스팅하고 정리된 코드는 git에 올릴 계획이다. 

 

 

마지막으로 주소에 대해 알아보자. AT45D041은 PAGE 단위로 데이터를 읽고 쓴다. 우선 버퍼에 저장하기 위해서는 버퍼에 저장할 바이트 수를 command와 함께 전송한 다음 데이터를 전송해야 한다. 

 

우선 buffer의 주소 지정에 대해 알아보자.

84h와 87h는 각각 buffer1과 buffer2에 데이터를 쓰는 커맨드다. 마지막 1byte가 버퍼에 저장할 데이터 크기다. 보통 256byte씩 저장하니까 0xff로 지정해주면 된다. 만약 264byte로 저장하려면 아래 주소 값을 참고, 관련 내용은 데이터 시트 30, 31페이지에 나와있다.

 

데이터 저장을 264byte씩 할 경우 주소 값이 1bit 더 있는 것을 확인할 수 있다.

 

마지막으로 page의 주소 지정.

page의 데이터를 쓰는 command는 83h와 86h다. 마지막 1byte는 사용하지 않고 중간에 위치한 2, 3 byte를 사용한다. 주소 지정은 0~2047번지 까지 총 2048개의 주소를 사용한다. 해당 값이 0 이면 0번 page에 데이터를 쓰겠다는 의미다. 주소 지정은 write, read 모두 동일하다.

 

아래 코드는 부팅부터 메모리에 데이터를 쓰고, 읽어오는 과정까지 확인한 코드다.

	for(for_i = 0; for_i < 264; for_i++)	{
		Data[for_i] = for_i;
	}

	AT45DB041_Read_ID();
	AT45DB041_Get_Status();
	//AT45DB041_set_pagesize_binary();
	//AT45DB041_Get_Status();


	AT45_WritePage(1, 0x0000, Data);
	memset(Data, 0x00, (sizeof Data));
	AT45_ReadPage(0x0000, Data);

for 문에서 data를 0~263으로 초기화 한다음. 메모리의 아이디와 상태값을 읽어온다. 다음으로 AT45DB041의 1번 버퍼에 데이터를 쓰고, 0번 page에 데이터를 저장한다. Data 변수를 초기화 한다음, 0번 Page의 데이터를 읽어와서 메모리의 동작을 확인한다. 

 

 

 

 

혹시 질문이나 자료가 필요하면 댓글 부탁드려요.

 

- 끝- 

 

728x90
반응형