페이지

글목록

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

2016년 10월 10일 월요일

[터치 키 IC] CY8CMBR31xx 소개(PSOC5 소스 포함)

안녕하세요. 계획에 없던 IC 소개 글을 쓰게 됐네요.

편집을 하다 보니 글이 꽤 깁니다. 값싸고 성능이 좋은 IC 라고 생각 되며, PSOC5 와 같이 테스트를 했습니다.
STM32 계열이나 다른 CPU와도 연결해서 써도 괜찮겠는데, 나중에 STM에 연결하게 되면 또 올리겠습니다.

편집하다 보니 시간이 너무 많이 들어가서 그림 위주로 올리겠습니다.

[참고한 자료 #1] - 링크

[참고한 자료 #2] - 링크






















이렇게 추가를 하면, host API 폴더에 있는 MBR31xx IC를 콘트롤 할 수 있는 함수들을 사용할 수 있는데, I2C 콤포넌트 이름이 틀리다고 에러가 날 것 입니다.

이 API 함수가 PSOC4와 연동해서  동작하도록 되어 있는데, PSOC5 와 이름만 틀리고 완전히 동일하게 쓰이니까, I2C 함수 이름만 맞게 바꿔 주면 에러가 없어집니다.

컴파일해서 프로그램을 넣으면, 동작이 안되네요.

디버그로 추적해서 보니까, 원인은 예제 프로젝트가 MBR3116 IC 로 되어있고,
제가 사용한 IC는 MBR3108 이어서 ID 비교 시에 오류가 나서 동작이 안됐습니다.

Host_API 폴더안의 CY8CMBR3xxx_Device.h 파일에서 다음과 같이 디바이스 이름을 수정해 주면 정상 동작합니다.


제가 첨부한 PSOC5 프로그램은 예제와는 약간 다릅니다.
인터럽트 방식을 사용하지 않았고, Proximity 센싱 대신에 버튼을 3개 센싱하는 프로그램 입니다.

LED 3개를 host에서 I2C로 제어 합니다. 

아쉬운 것이, Proximity Sense 와 Guard Sense 를 테스트 못해봤는데..
PSOC 과는 다르게 버튼을 공통으로 Proximity Sense 와 사용할 수 없었던 점을 미리 알지 못했네요. 
Proximity Sense 와 Guard Sense 는 핀이 정해져 있는 것이 좀 다르네요.

또 한가지 아쉬운 점은, 16원짜리 PWM회로 없는 부저를 1개 달았으면 터치키가 눌릴 때 마다 소리가 나서 눌렸다는 정보를 전달해 줄 수 있었는데, 뭐 하는 기능인지 최초 설계시에 잘 몰랐습니다. ㅜㅜ


이 칩을 사용하기 전에 PSOC5 나 PSOC4 에서 CAPSENSE 기능을 사용해 봤었는데,
PSOC에서 CAPSENSE 기능을 사용시에는 너무 반응속도가 늦었습니다. 버튼이 많아질 수록 반응 속도가 더 늦어 져서 거의 사용하기 싫을 정도(?) 였었는데.. 이유는 CAPSENSE 읽는 함수를 여러 번 실행해야 응답이 1번 오는데, 버튼이 더 많아질 수록 더 많이 CAPSENSE 읽는 함수를 실행해야 해서 그렇게 느려졌습니다.

제가 혹시 잘 못 사용하는 것은 아닌지, PSOC에서 CAPSENSE 읽는 속도를 개선하는 방법을 알고 계시는 분이 계시면 좀 알려 주십시요.

결론은, 이 칩(MBR31xxx)를 사용하면 그냥 I2C로 일반 택트 스위치 읽듯이 주기적으로 값을 읽으면 됩니다. 그리고 읽은 정보를 보고 LED 상태를 바꾸고 싶으면 I2C로 LED 상태 변경 명령을 보내면 됩니다. 속도도 전혀 느려지지 않습니다.

정말로, 앞으로 터치 센서를 사용할 경우에는 이 칩만 쓰고 싶습니다. ^^

아~~, 또 한가지 .. PSOC4,5 에서 CAPSENSE 를 연결할 경우 PSOC과 CAPSENSE PCB PAD 와는 거리가 짧아야 하고 센싱 입력 ADC 선을 메쉬 쉴드와 쿠퍼로 감싸줘야 합니다.
그래서 CPU 와 터치 센서와의 위치에 대해서 엄청난 고민을 해서 아트웍과 위치 선정에 어려움이 많았고, 거리도 멀게 배치할 수도 없었는데 이 칩(MBR31xx)가 모든 고민을 해결해 줬습니다.

거리가 멀어도 됩니다. I2C 통신 거리가 보통 1m 정도는 나오니까, PCB 어디에도 터치를 연결할 수 있겠습니다.

또 한가지 장점이 있네요. PSOC에서 CAPSENSE를 사용하려면 IDAC 가 1개 들어갑니다. 만약에 DAC를 사용해야 할 때, CAPSENSE 때문에 DAC가 부족하면 PSOC 중에서 DAC가 1개 더 많은 종류를 선택해야 하는데, 이 경우에 MBR31xx 보다 가격이 더 올라갑니다.
이런 경우 당해 보셨나요? 저는 당해 봤습니다. ^^

아.. 이번에도 참 좋은 IC를 알게 되고 사용해 봤습니다. 앞으로도 많이 사용하게 될 것 같습니다. 이 칩 간만에 본 명품입니다. ^^

가격은, 단돈 $0.76 @ 1k.







[테스트 동영상]


2016년 8월 8일 월요일

[STM32F4xx] Nucleo 보드 테스트 #6(I2C 2/2 인터럽트:KEIL)

I2C 통신으로 간단하게 EEPROM(AT24C04) 를 읽기/쓰기 테스트 해 봤습니다.

예전에 PSOC4로 해 놓은 자료가 있으니까, 자세한 설명은 빼고 동작 테스트만 해 보겠습니다.

먼저 I2C 인터럽트를 사용하여 데이터를 보내고 받는 함수들은 다음과 같습니다. 
1. HAL_I2C_Master_Transmit_IT()
   : I2C 인터럽트를 사용하여 데이터를 보내는(Write) 함수
2. HAL_I2C_MasterTxCpltCallback()
   : I2C 인터럽트를 사용하여 데이터를 보내고 다 보내면 인터럽트에 의해 호출되는 함수
3. HAL_I2C_Master_Receive_IT()
   : I2C 인터럽트를 사용하여 데이터를 받는(Receive) 함수
4. HAL_I2C_MasterRxCpltCallback()
   : I2C 인터럽트를 사용하여 정해진 개수의 데이터를 다 받으면 인터럽트에 의해 호출되는 함수

위의 함수들은 stm32f4xx_hal_i2c.c 파일에 정의되어 있습니다. 
HAL_I2C_MasterTxCpltCallback(), HAL_I2C_MasterRxCpltCallback() 과 같은 콜백함수는 __weak 키워드를 없애고
main.c 파일에 복사해서 내부 내용을 바꿔서 쓰면 인터럽트가 걸릴때 마다 콜벡함수를 호출하게 됩니다.

이 파일의 위치는 다음과 같습니다.



친구 돌잔치를 가봐야 해서 main.c 에서 EEPROM 읽고 쓰는 부분을 그림으로 올려 놓겠습니다.


[16 Byte Write 오실로 스코프 파형]

[Word Address Write 오실로 스코프 파형]

[16 Byte Read 오실로 스코프 파형]

소스 파일 첨부.

2016년 8월 4일 목요일

[STM32F4xx] Nucleo 보드 테스트 #5(I2C 1/2 :KEIL)

이제 I2C 통신 테스트를 해 보려고 합니다.

먼저 Cube 툴에서 I2C1 을 선택했더니, PB6(I2C1_SDA) , PB7(I2C_SCL) 로 핀아웃이 배정되는군요.

Nucleo 보드의 핀위치는 다음과 같습니다.

현재 제가 갖고 있는 I2C 테스트하기 가장 좋은 놈이 하나 있군요. 예전에 PSOC4로 I2C를 테스트하려고 산 EEPROM 모듈(AT24C04)가 있어서 Nucleo 보드와 위의 핀에 연결해 봤습니다.

I2C 테스트 코드를 IRQ 용으로 작성을 했는데, 아직은 IRQ 처럼 사용하지는 않았습니다.
그저 Write 테스트를 해 보려했습니다.

I2C Write 방식은 
'시작 + 7비트 DEVICE ADDRESS + R/W + ACK(EEPROM 에서 응답) + 끝' 이 기본이고,

여기서 추가로 데이터를 몇개 더 보낼 때는,
'시작 + 7비트 DEVICE ADDRESS + R/W + ACK(EEPROM 에서 응답) + 8비트 데이터#1 + ACK(EEPROM 에서 응답)
 + 8비트 데이터#2 + ACK(EEPROM 에서 응답) + ....+ 8비트 데이터#n + ACK(EEPROM 에서 응답) + 끝' 과 같이 하면 됩니다.

I2C 디바이스는 각각 고유의 DEVICE ADDRESS가 있는데, 위의 AT24C04 모듈의 DEV ADDR 은 0x50 입니다.
따라서 main.c 에 어드레스를 다음과 같이 정의했습니다.
#define I2C_ADDRESS        0x50

그리고 main() 함수에 다음을 추가해서 오실로 스코프로 찍어볼 준비를 했구요.
(I2C 설정은 Cube 툴에서 해주니 설정에 관한 설명은 생략합니다)

   i2c_tx_buf[0] = 0x01;
   i2c_tx_buf[1] = 0x02;
   i2c_tx_buf[2] = 0x03;
    if(HAL_I2C_Master_Transmit_IT(&hi2c1, (uint16_t)I2C_ADDRESS, i2c_tx_buf, 3)!= HAL_OK)
    {
      /* Error_Handler() function is called in case of error. */
      Error_Handler();
    }

그런데 스코프로 찍어 보니, 7비트 어드레스만 우측으로 1비트 밀려서 나가고 더이상 데이터가 나오지 않아서
자세히 보니, 어드레스를 좌측으로 1비트 밀어야 ACK가 응답으로 오면서 후속 데이터가 제대로 나가겠구나 .. 라는 생각이 드네요.

그래서 DEVICE Address 를 다음과 같이 수정했고,
#define I2C_ADDRESS        (0x50 << 1)

오실로 스코프의 파형도 정상으로 나왔습니다.

오늘은 WRITE 출력 파형이 프로그램으로 잘 출력 되는지 정도만 확인했고,
내일은 EEPROM을 제대로 읽고 쓰는 테스트를 진행해 보겠습니다.

테스트한 파일 첨부합니다.

2016년 6월 9일 목요일

[PSOC] PSOC5 조도센서 I2C I/F 테스트

조도센서 ISL29023 (Intersil 사)를 테스트 해 봤습니다.

이 센서는 간략히 말하면, I2C I/F 방식으로 ALS(조도) 와 IR(적외선)을 continuous/once 로 측정할 수 있습니다.

일단 테스트로 ALS 를 continuous 로 측정해서, PSOC5 의 USB_UART 로 출력하도록 했습니다.

PSOC5 의 연결은 다음과 같습니다. (I2C, USB)



command 레지스터는 전원 ON시, 모두 0 으로 되므로 읽어도 아무 값도 안나옵니다. 파워 다운 모드로 되어 있어서 그런 것 같네요.

그래서 command-I 레지스터에 조도센서를 continuous 하게 샘플링하도록 설정했습니다.


USB-to-UART 로 출력하도록 해 놓고, 터미널로 본 내용은 다음과 같습니다.
밝은 상태에서 손을 데면 어두워지면서 값이 낮은 값으로 변합니다.



소스코드 링크 : psoc5_code

2016년 2월 12일 금요일

[dialog] DA14580 외부 FLASH 메모리에 쓰기

안녕하세요,

DA-14580 BLE CPU는 OTP 메모리와 RAM으로 구성되어 있어서,
1번 잘못 쓰면 프로그램을 수정할 수가 없습니다.

그래서 Keil debug를 통해서 RAM에 프로그램을 올려서 테스트용으로 프로그램을 실행하던가,
아니면 외부에 SPI/I2C Flash Memory를 붙여서 JTAG를 통해서 Dialog S/W tool인 
SmartSnippets을 사용해서 프로그램을 Flash Memory에 쓸 수 있습니다.

동작 방식은 전원을 켜면 SPI/I2C Flash 메모리에서 프로그램을 읽어와서 
SRAM에 copy 해서 SRAM에서 프로그램이 돌아가는 형태입니다.

저는 SPI FLASH를 사용했는데,
DA14580에서 약간의 I/O를 사용하는데, 가뜩이나 작은 칩을 사용해서 I/O가 충분히 많지 않기 때문에
SPI를 사용할 경우 특정 핀(SPI FLASH 연결 핀들)을 피해서 사용해야 합니다.

프로그램은 Debug에서 돌리던 프로그램을 그대로 올리면 되고,
대신에 전원 리셋시, SPI FLSH에서 S-RAM으로 프로그램을 Copy하는 시간 때문인지 약간의 딜레이가 생깁니다.


위의 표를 보면 secondary bootloader 를 사용해 보진 않아서 모르겠지만,
OTP에 프로그램을 굽는 것 보다 외부 플래쉬에 프로그램을 쓰는 것이 시간과 에너지 소비가 훨 씬 많네요.

2016년 1월 20일 수요일

[PSOC] I2C 통신시에 FIFO 초기화 문제(PSOC4)

안녕하세요, 오랜만입니다.

이번 이슈는 PSOC4 에서 I2C 통신을 하다가, I2CMasterWriteBuf() 함수를 사용할 경우 잘못된 SUB ADDRESS에 데이터를 송신하면 송신한 데이터들이 내부 FIFO 버퍼에 쌓여있다가 정상적인 SUB ADDRESS에 다시 데이터를 쓸 경우 이전에 쌓여있는 데이터가 출력되는 것을 발견했습니다.

이 문제의 발생빈도는 on-chip program 시에는 50% 정도이지만, 디버그 모드에서는 80%이상이었습니다. 즉 항상 발생하는 것은 아니라는 것이지만, 문제가 되기에는 충분합니다.

현재 Cypress에 기술 문의를 요청한 상태이고 빨리 해결되었으면 좋겠네요.

항상 제대로된 어드레스에 데이터를 전송하는 것은 아니라, 이런 경우도 있다는 점을 업체에서 인지하지 못했던 것 같습니다.

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