페이지

글목록

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) 에 올려 놓을 예정입니다.

댓글 없음:

댓글 쓰기