페이지

글목록

레이블이 AT24Cxx인 게시물을 표시합니다. 모든 게시물 표시
레이블이 AT24Cxx인 게시물을 표시합니다. 모든 게시물 표시

2015년 12월 28일 월요일

[PSOC] PSOC4 I2C I/F with AT24C04(EEPROM) - Read (3/3)

EEPROM posting 마지막인, AT24C04 READ 동작 테스트입니다.

AT24xx IC의 READ 동작 방식은 3가지가 있습니다.
1. RANDOM BYTE READ
2. SEQUENTIAL READ
3. CURRENT ADDRESS READ

이 중, 테스트 결과 미리 말씀드릴 내용이 있는데,
3. Current Address Read 의 경우 Byte Write 와 Random Byte Read 를 실행한 다음에는 Current Address 값이 읽히는 것이 아니라 Current Address 위치의 데이터 값이 읽힙니다.
제가 잘 못한 것이 있는지 모르겠으나 여러번 테스트 해 봐도, 그렇네요.
Page Write 나 Sequential Read를 수행한 후에는 Address가 제대로 읽히네요.
또 1가지, Page의 마지막 1 바이트를 Random Byte Read로 읽은 후에는 Current Address Read가 제대로 동작합니다.

정리해보면 Current Address Read 명령은 다음과 같은 경우 동작한다.
1. Page Write 이후
2. Sequential Read 이후
3. Page의 마지막 데이터를 Random Byte Read한 이후

추가로 테스트해 본 결과, 전원 리셋 이후 AT24C04를 처음에 Current Address Read를 수행하면 0xFF 가 읽히고 그 다음에 계속 읽어 보아도 0xFF만 계속 읽히는 군요. 데이터가 읽히는 건지 current Address 가 계속 0xFF 고 자동으로 증가한다던 Address 가 증가를 안하는 건지 확인이 안되네요.


[1. RANDOM BYTE READ]
RANDOM BYTE READ 함수는 다음과 같이 정의했습니다.
uint8_t EEP_24C04_Read_Byte(uint32_t slaveAddress,uint8_t wordAddress)
{
    uint8_t rtn_val;
    
    I2C_1_I2CMasterWriteBuf(slaveAddress, &wordAddress, 1, I2C_1_I2C_MODE_COMPLETE_XFER );
    for(;;)
{
if(0u != (I2C_1_I2CMasterStatus() & I2C_1_I2C_MSTAT_WR_CMPLT))
{
break;
}
}
    I2C_1_I2CMasterReadBuf(slaveAddress, &rtn_val, 1, I2C_1_I2C_MODE_COMPLETE_XFER);
for(;;)
{
        if(0u != (I2C_1_I2CMasterStatus() & I2C_1_I2C_MSTAT_RD_CMPLT))
    {
    break;
    }
}    
    
    return rtn_val;
}


데이터시트를 보면 Device Address 와 Word Address 를 Dummy Write 하라고 했는데, 이 동작에서 Dummy 라는 말이 문제가 있습니다. Dummy 는 쓰레기 또는 아무 의미 없는 동작을 말하는데 테스트 결과, Dummy로 넣은 Word Address 에 의해 Word Address 에 해당하는 데이터가 출력됩니다. 이것은 Dummy 라는 표현이 옳지 않은 것 같습니다.


어쨓든 Device Address(/Write) + Word Address 를 Write한 후에  I2C_1_I2CMasterReadBuf() 함수로 데이터를 1개 읽으면 됩니다.

동작 테스트 예로써, 다음과 같은 코드를 실행해 봤습니다.
    i=0;
    i2c_buffer[i++] = EEP_24C04_Read_Byte(0x52,0x14);

Device Address : 0x52 , Word Address : 0x14 에 해당하는 데이터를 1개 읽는 동작입니다.

오실로스코프로 측정한 결과는 다음과 같습니다.

0x04가 읽혔네요. 이건 맞습니다. 이전에 제가 Word Address 0x10~0x1F 에 데이터 0x00~0x0F를 Write 했으니, Word Address 0x14 에 해당하는 데이터는 0x04 가 맞는 거죠.

UART로 뿌려 보니 0x04가 나오는 군요.
 

[2. SEQUENTIAL READ]

SEQUENTIAL READ 동작은 RANDOM BYTE READ 에서 1 BYTE만 읽던 것에 추가로 여러바이트를 읽으면 됩니다.
Device Address(/Write) + Word Address 를 Write한 후에  I2C_1_I2CMasterReadBuf() 함수로 데이터를 여러개 읽으면 됩니다.

동작시퀀스는 다음과 같습니다.


제가 만든 함수 원형은 다음과 같습니다.

void EEP_24C04_Read_Sequential(uint32_t slaveAddress,uint8_t wordAddress,uint8_t *RdData,uint32_t cnt)
{
    I2C_1_I2CMasterWriteBuf(slaveAddress, &wordAddress, 1, I2C_1_I2C_MODE_COMPLETE_XFER );
    for(;;)
{
if(0u != (I2C_1_I2CMasterStatus() & I2C_1_I2C_MSTAT_WR_CMPLT))
{
break;
}
}
    I2C_1_I2CMasterReadBuf(slaveAddress, (uint8 *) RdData, cnt, I2C_1_I2C_MODE_COMPLETE_XFER);
for(;;)
{
        if(0u != (I2C_1_I2CMasterStatus() & I2C_1_I2C_MSTAT_RD_CMPLT))
    {
    break;
    }
}    
}

테스트 동작 코드의 예는 다음과 같습니다.
EEP_24C04_Read_Sequential(0x52,0x10,i2c_buffer,16);

Device Address : 0x52 , Word Address : 0x10부터 16개의 데이터를 순차적으로 읽는 동작입니다.

오실로 스코프로 측정한 결과는 다음과 같습니다.

안보여서 확대해 본 그림은 다음과 같습니다.

앞부분만 분석해 본 결과 제대로 송/수신이 되고 있네요. 
0x52(Device Address)+/Write+ACK , 
0x10(Word Address)+ACK, 
0x52(Device Address)+Read+ACK , 
0x00+ACK , 0x01+ACK , 0x02+ACK~..

UART로 출력한 결과 다음과 같습니다.

제대로 읽혀졌음이 확인됐습니다.


[3. Current Address Read]
현재 어드레스를 읽는 동작으로 Random Byte Read에서 Write Code(Device address+Wordaddress) 를 뺀 것 과 같습니다.

함수 정의는 다음과 같습니다.
uint8_t EEP_24C04_Read_Address(uint32_t slaveAddress)
{
    uint8_t rtn_val;
    
    I2C_1_I2CMasterReadBuf(slaveAddress, &rtn_val, 1, I2C_1_I2C_MODE_COMPLETE_XFER);
for(;;)
{
        if(0u != (I2C_1_I2CMasterStatus() & I2C_1_I2C_MSTAT_RD_CMPLT))
    {
    break;
    }
}    
    
    return rtn_val;
}

맨 처음 문제를 제기한 것 처럼, Page Write 나 Sequential Read 일 때만 제대로 동작합니다. 다른 의미로는 페이지의 마지막 데이터를 Access한 다음에만 동작한다고도 할 수 있겠네요.

동작 시퀀스는 다음과 같습니다.


오실로 스코프로 측정한 결과 입니다. 

Word Address 0x21이 읽히네요.

다음은 UART로 출력한 결과 입니다. UART에는 0x20 이 읽히는데, 위의 스코프 데이터와 관련없이 보십시요. 위의 파형은 Current Address Read만 1번 더 실행해서 측정하다 보니 Address 가 자동으로 +1 되어 0x21이 되어 버렸습니다.



자, 이것으로 I2C 기초 공부를 마치겠습니다. 혹시 Current Address Read 의 애매한 부분을 아시면 댓글 남겨 주시기 바랍니다. ^^

그리고 PSOC Creator 예제 파일추가 링크 입니다.

2015년 12월 27일 일요일

[PSOC] PSOC4 I2C I/F with AT24C04(EEPROM) - Write (2/3)

AT24C04 의 Write 테스트시,

Write 는 2가지 방식이 있습니다.
1. Byte Write
  1-Byte 단위로 특정 주소에 Write 하는 방식입니다.
2. Page Write
  Page 단위(AT24C01,02 : 8 Byte, 04,08,16 : 16 Byte)로 특정 주소에 Write 하는 방식입니다. 16-Byte를 넘어서 쓰게되면 다음의 주소에 써지는 것이 아니라 맨 처음의 주소로 돌아가서 OverWrite 되니 주의하여야 합니다.

테스트 방법은 Write를 한 후, 다시 메모리를 읽어서 UART로 Terminal에 출력해서 확인해 봤습니다. 추가로 오실로 스코프로 세부 내용을 확인해 봤습니다.


PSOC Creator 에서 C로 프로그램을 할 때, 자동으로 만들어지는 I2C Master용 함수들을 이용해서 인터럽트에 의해 동작이 이루어 집니다.
인터럽트를 자세히 알 필요는 없었습니다. 그냥 UART 하듯이 간단하게 PSOC Creator에 의해 준비가 잘 되어 있어서 다른 MCU 다루기 보다는 너무 쉽더군요.


다만, 조금 헤맨 부분은 AT24Cxx IC에 Write 명령을 보내면 Write Cycle Time 이 있어서 5ms 동안 어떤 동작도 하지 않아서 Error가 발생한다는 점입니다. 이 때는 Error를 무시하고 주기적으로 상태를 확인하는 명령을 보내고 상태를 수신하거나 5ms를 기다렸다가 다음 동작을 수행하면 됩니다. 그런데 이 때, 상태 확인하는 레지스터같은 것이 AT24Cxx에는 없어서 확인하는 방법은 읽어서 값이 제대로 써졌는지 확인하는 방법밖에 없는듯 합니다.

저는 그냥 5ms 딜레이를 주고 다음 동작을 하도록 프로그래밍 했습니다.

요새 나오는 Flash Memory인 W25Q128 같은 경우는 Write Cycle Time에도 상태 확인하는 명령은 먹었는데, AT24xx IC는 하도 오래전에 나오고 초기에 만들어진 제품이라 그런지 명령이 몇개 없고 간단했습니다.

< 1. WRITE BYTE >
먼저 PSOC 에서 Write Byte 프로그램을 해 보겠습니다.
함수를 조합해서 1개 만들었는데, 별 거 없습니다.

void EEP_24C04_Write_Byte(uint32_t slaveAddress,uint8_t wordAddress,uint8_t WrData)
{
    uint8_t i2c_Data[2];
    i2c_Data[0] = wordAddress;
    i2c_Data[1] = WrData;
    
    I2C_1_I2CMasterWriteBuf(slaveAddress, (uint8 *) i2c_Data, 2, I2C_1_I2C_MODE_COMPLETE_XFER );

    for(;;)
{
if(0u != (I2C_1_I2CMasterStatus() & I2C_1_I2C_MSTAT_WR_CMPLT))
{
                
break;
}
}
    CyDelayUs(5000);    // Write Cycle Time (5ms)
}

PSOC에서 기본으로 제공되는 함수인 I2C_1_I2CMasterWriteBuf 로 AT24C04 의 Device address 를 slaveAddress 에 넣어 주고 wordaddress 와 Write할 데이터(1-Byte)를 순서대로 I2C_data 에 넣어주고, 마지막은 mode 인데 전송시 START,STOP 파형을 결정하는 옵션입니다. 이 IC에서는 I2C_1_I2C_MODE_COMPLETE_XFER 외에는 쓸 일이 없더군요.

모드 설명은 자동으로 생성되는 (component 이름이 I2C_1 일 때) I2C_1_I2C.h 에 정의되어 있습니다.
/* "Mode" constants for MasterWriteBuf() or MasterReadBuf() function */
#define I2C_1_I2C_MODE_COMPLETE_XFER     (0x00u)    /* Full transfer with Start and Stop       */
#define I2C_1_I2C_MODE_REPEAT_START      (0x01u)    /* Begin with a ReStart instead of a Start */
#define I2C_1_I2C_MODE_NO_STOP           (0x02u)    /* Complete the transfer without a Stop    */


Device Address 를 0x52(기본 세팅은 0x50 인데, Address Select 기능 테스트를 위해 A1을 High로 하여 0x52로 바꿨음)설정하고, Word Address 0x1F 에 데이터 1 Byte 인 0x3A를 쓰는 예는 다음과 같습니다.
    EEP_24C04_Write_Byte(0x52,0x1F,0x3A);

AT24xx 데이터 시트에서 Byte Write 펄스 시퀀스는 다음과 같습니다.

오실로 스코프로 측정한 파형은 다음과 같습니다. 이런..ㅜㅜ 아래 그림은 0x10에 0xBB를 Write 한 것이네요. 바쁜 관계로 그림 편집없이 제대로 된 파형만 추가하겠습니다.

Device addr : 0x52 +/W+A, word address : 0x1F+A , Write Byte : 0x3A+A



노란색이 SCL 이고 빨강색이 SDA인데 출력 결과가 데이터 시트와 일치합니다.

아직 I2C Read 설명을 안했는데, 이미 만들어 놓은 Read 명령으로 읽어서 UART로 뿌린 결과 제대로 써졌음을 확인했습니다.


< 2. WRITE PAGE >
다음은 Page 단위(AT24C04 에서 부터는 16-Byte)로 Write 하는 방법을 알아보겠습니다.

이건 간단합니다. 위 Write Byte 에서 Word Address 이후에 1-Byte만 보내던 것을, 연속으로 16-Byte 데이터를 보내면 됩니다.

Page Write 함수도 1개 만들어 보았는데,
입력변수로 배열 변수를 받고,
몇 개 보낼 것인지 cnt를 전달해 주는 것이
Byte Write 함수와의 차이입니다.

먼저 전달할 1-Byte(uint8_t) 타입의 입력 배열 값에 쓰고자 하는 값을 넣고 이 함수에 전달해 주면 I2C 통신에 의해 Page Write 동작이 실행됩니다.

함수 정의는 다음과 같습니다.

void EEP_24C04_Write_Page(uint32_t slaveAddress,uint8_t wordAddress,uint8_t *WrData,uint32_t cnt)
{
    uint8_t i2c_Data[20];
    uint32_t i;

    i2c_Data[0] = wordAddress; // 1st data : WordAddress (8-bit : 0x00~0xFF)
    
    for (i=0;i
    {
        i2c_Data[1+i] = WrData[i];  // 2nd~17 data(16 byte data) : page write data[0]~[15]
    }
    
    I2C_1_I2CMasterWriteBuf(slaveAddress, (uint8 *) i2c_Data, (cnt+1), I2C_1_I2C_MODE_COMPLETE_XFER );
    for(;;)
{
if(0u != (I2C_1_I2CMasterStatus() & I2C_1_I2C_MSTAT_WR_CMPLT))
{
                
break;
}

}
    CyDelayUs(5000);    // Write Cycle Time (5ms)
}


실제 코드에 적용한 예는 다음과 같습니다.

    for (j=0,i=0x00;j<20 i="" j="" p="">    {
        i2c_buffer[j] = i;
    }
   
    EEP_24C04_Write_Page(0x52,0x10,i2c_buffer,16);

배열 변수인 i2c_buffer[j]에 수차적으로 0x00~0x0F 를 넣고,
device Address = 0x52, word Address = 0x10, cnt = 16 파라메터를 넣어 EEP_24C04_Write_Page() 함수를 동작 시키면 Address 0x10 부터 0x1F 에 0x00,0x01~0x0F 형태로 데이터가 써(Write)집니다.

이 때, 16개 이상 Write 하면 17번째 부터 WordAddress 0x10 에 OverWrite 되니 주의하시기 바랍니다.

아까 설명을 안한 부분이 있는데, Write시 I2C_1_I2CMasterWriteBuf() 함수가 실행되면 여기서 데이터를 다 쓰는 것이 아니라, Tx 버퍼에 넣고 인터럽트에 의해 Write가 동작하는 중이라 if(0u != (I2C_1_I2CMasterStatus() & I2C_1_I2C_MSTAT_WR_CMPLT)) 코드에 의해 송신이 완료될 때까지 기다리는 것입니다.

여기는 Master 인 PSOC4에서 데이터만 다 보낸 것이고, AT24Cxx 에서 Write cycle 타임이 있어 EEPROM에 다 써질 때 까지 기다려야 합니다. 이 때는 아무 동작을 안합니다. 메뉴얼을 보면 5ms 라고 나와 있어서 5ms 기다리고 끝냅니다.
CyDelayUs(5000);    // Write Cycle Time (5ms)


다음은 Datasheet에 있는 Page Write 동작 시퀀스 입니다.

다음은 위의 코드에 의해 동작시 I2C 통신라인을 오실로 스코프로 측정한 결과 입니다.


안보여서 좀 더 확대해 보면 다음과 같습니다.

데이터가 제대로 나가고 있네요. ^^

실제로 잘 써 졌는지 읽어서 UART로 출력해 보면 다음과 같습니다.

^^ 잘 써졌네요. 동작 검증 끝.


Psoc creator Source 파일은 마지막 [PSOC] PSOC4 I2C I/F with AT24C04(EEPROM) - Read (3/3) 에 올려 놓을 예정입니다.

[PSOC] PSOC4 I2C I/F with AT24C04(EEPROM) - 결선 (1/3)

PSOC4로 AT24C04 와 I2C 통신으로 Read/Write 테스트를 해봤습니다.

PSOC4 장치는 CY8CKIT-042 개발 키트를 사용하였고,
AT24C04 는 얼마 전에 엘레파츠에서 AT24CXX 보드를 사서 붙였습니다.

[AT24Cxx BOARD 그림]

AT24C04 는 Serial EEPROM으로, I2C 통신시 최대 400KHz 속도까지 나옵니다.
메모리는 4KBIT(512x8)이고 Page 단위는 16 Byte입니다.


AT24 시리즈는 파트넘버마다 Page 와 핀의 기능이 서로 조금씩 달라집니다.
AT24C01,02 는 Page size 가 8-Byte 이고, 04,08,16 은 16-Byte 입니다.

또한 파트마다 H/W 핀 기능 중 Device Address Select 핀인 A2,A1,A0이 달라집니다.
01,02 는 A2,A1,A0 모두 사용할 수 있지만,
04 는 A2,A1 만 사용 가능하고 남는(안쓰는) A0는 연결하지 않거나 GND에 연결합니다.
08 은 A2 만 사용 가능하고, 남는(안쓰는) A1,A0는 연결하지 않거나 GND에 연결합니다.
16은 모두 안쓰고, 남는(안쓰는) A2,A1,A0는 연결하지 않거나 GND에 연결합니다.

WP 핀은 Active High 로 High 일 때, Write Protect 됩니다.


AT24Cxx 의 주소는 2가지로 구성되어 있습니다.

1. Device Address

I2C 통신시 장치를 구분해 주는 ID와 같은 역할을 합니다. 이 주소가 틀리면 AT24Cxx IC는 응답을 안합니다.
이 주소는 H/W Address Select 핀을 반영하는데, 위의 Address Select 핀 설명에서 처럼 A2,A1,A0 을 High/Low에 연결해서 주소를 바꿀 수가 있습니다.
04 부터는 Px 가 있어서 1 Word address(0x00~0xFF)를 넘어가는 Address를 바꾸는데 사용합니다. Word Address 는 8-bit로 256개(0x00~0xFF) 밖에 내부 메모리 주소를 Access 할 수 없으므로 용량이 커지면서 Px Address가 생겨난 것으로 봅니다.

2. Word Address
이 주소는 내부 8bit(1 Byte) 데이터 단위로 순차적으로 구성되어 있습니다. 
8bit 로 되어 있고, 따라서 0~255(256개) 로 Address를 선택 할 수 있습니다.
따라서 4K(512-Byte=256x2 Byte, @24C04) 부터는 Device Address의 Px Address를 이용해서 주소를 확장할 수 있습니다.


AT24CXX IC Datasheet 링크


[개발키트와의 결선도]


PSOC4 보드와의 결선도인데, I2C 로 AT24C04와 연결하였고 Read/Write 내용을 간단하게 테스트해 보기 위해서 UART를 추가로 연결해서 터미날(Tera COM 이나 Hyper Terminal)을 이용해서 PC에서 눈으로 확인했습니다.

다음은 PSOC4에 프로그램하기 위해 PSOC Creator 설정입니다.
1. TopDesign.cysch

I2C component의 설정은 이번에 처음 다뤄서 내용을 같이 올립니다.
PSOC4에 기본으로(UDB가 아닌) 제공되는 SCB(Serial Communication Block)을 사용한 I2C 콤포넌트인데, Configuration을 I2C로 선택하고, I2C Basic TAB에서 Mode는 Master , 속도는 100Kbps 를 선택했습니다.

UART는 예전에 다뤘으니 세부 사항은 다루지 않겠습니다.

2. PSOC4 핀 결선
cwdrw 파일을 psoc Creator 에서 수정해서 핀들을 적절하게 설정하였습니다.