아트메가/이론

ATMEGA128 TWI(I2C)통신 알아보기 3편

원원 2022. 9. 13. 14:55

안녕하세요. 오늘은 ATMEGA128 TWI READ를 해보겠습니다

 

READ를 알아보기전에 먼저 알아야 할게 있습니다. 어떤 모듈에게 데이터를 WRITE/READ를 하려면 먼저 그 모듈의 메모리주소에 접근해야하고 접근하려면 WRITE를 해야합니다. 그래서 WRITE를 하고 READ를 하면 데이터를 읽을 수 있습니다.

 

*READ하기

Read통신하는 순서가 있습니다.
순서를 크게보면 슬레이브 주소를 전송하고 슬레이브가 응답했으면 데이터를 Read하고 통신을 끝냅니다.


- 순서
0) WRITE과정하기(ATMEGA128 TWI(I2C)통신 알아보기 2편 참고)
1) START신호 전송
2) START신호 전송완료했나 확인
3) 슬레이브 주소 전송(7bit) +  READ전송( Write : 0, Read : 1)
4) 슬레이브가 응답했는지 확인(ACK or NACK)
5) 슬레이브에게 응답하기(ACK or NACK)
6) 데이터 수신했는지 확인
7) 데이터 변수에 저장하기 (한번당 데이터를 1byte읽고 2byte를 읽으려면 5~7과정을 두번 하면 됩니다)
8) STOP신호 전송

unsigned char twi_read2(unsigned char add, unsigned char len)
{
	int i=0;
	memset(twi_recv,'\0',sizeof(twi_recv));
	
	/* STEP1 START */
	TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
	
	/* STEP2 Start check */
	while(1)
	{
		if((TWCR & 0x80) && ((TWSR & 0xf8) == 0x08))
		break;
	}

	/* STEP3 Address send */
	TWDR = add<<1 | 0x01; // slave address, read
	TWCR = (1<<TWINT)|(1<<TWEN);
	
	/* STEP4 ACK Check */
	while(1)
	{
		if((TWCR & 0x80) && ((TWSR & 0xf8) == 0x40))
		break;
		if((TWCR & 0x80) && ((TWSR & 0xf8) == 0x48))
		return 0;
	}

	for(i=0; i<len; i++)
	{
		/* STEP5 send ACK or NACK*/
		if((i+1)!=len)
			TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA); //ACK
		else
			TWCR = (1<<TWINT)|(1<<TWEN); //NACK
		/* STEP6 Data receive Check */
		while(1)
		{
			if((TWCR & 0x80) && ((TWSR & 0xf8) == 0x50))
				break;
			if((TWCR & 0x80) && ((TWSR & 0xf8) == 0x58))
				break;
		}
        /* STEP7 Receive Data*/
		twi_recv[i] = TWDR;
	}
	
	/* STEP8 STOP */
	TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
	return 1;
}
int main(void)
{
	sei();
	usart0_init();
	twi_init();
    /* STEP 0 Write*/
	twi_write(0x48,0x02);
	_delay_us(100);
	twi_read2(0x48,2);
	USART0_char(twi_recv[0]);
	USART0_char(twi_recv[1]);
	
	while(1)
	{

	}
}

여기서 사용하는 모듈의 주소는 0x48이고 읽을 데이터는 0x02에 있고 데이터는 2바이트로 이뤄져 있습니다.

시리얼모니터와 파형모두 예상대로 나왔습니다.

 

*READ하기(RESTART)

Read할 때 Restart기능도 있습니다. Restart는 Write를 하고 STOP을 안하고 Restart를 해서 데이터를 읽으면 됩니다.
Restart의 장점은 통신을 할 때 STOP을 안 하므로 모듈이 여러 개 연결해서 사용 중일 때 제어권을 다른 모듈에게 안 뺏기게 됩니다.

 

- 순서
1) START신호 전송
2) START신호 전송완료했나 확인
3) 슬레이브 주소 전송(7bit) +  WRITE전송( Write : 0, Read : 1)
4) 슬레이브가 응답했는지 확인(ACK or NACK)
5) 데이터 전송
6) 슬레이브가 응답했는지 확인(ACK or NACK)
7) Restart신호 전송
8) Restart 신호 전송완료했나 확인
9) 슬레이브 주소 전송(7bit) +  READ전송( Write : 0, Read : 1)
10) 슬레이브가 응답했는지 확인(ACK or NACK)
11) 슬레이브에게 ack or nack 전송
12) 데이터 수신했는지 check
13) 데이터 변수에 저장
14) STOP신호 전송

unsigned char twi_read(unsigned char add, unsigned char dat1, unsigned char len)
{
	int i=0;
	memset(twi_recv,'\0',sizeof(twi_recv));
	
	/* STEP1 Start */
	TWCR = (1<<TWSTA)|(1<<TWINT)|(1<<TWEN); //start

	/* STEP2 Start check */
	while(1)
	{
		if((TWCR & 0x80) && ((TWSR & 0xf8) == 0x08))
		break;
	}

	/* STEP3 Address send */
	TWDR = add<<1 | 0; // slave address, write
	TWCR = (1<<TWINT)|(1<<TWEN);

	/* STEP4 ACK Check */
	while(1)
	{
		if((TWCR & 0x80) && ((TWSR & 0xf8) ==0x18))
			break;
		if((TWCR & 0x80) && ((TWSR & 0xf8) == 0x20))
			return 0;
	}
	/* STEP5 Data send */
	TWDR = dat1;
	TWCR = (1<<TWINT)|(1<<TWEN);

	/* STEP6 Data send check */
	while(1)
	{
		if((TWCR & 0x80) && ((TWSR & 0xf8) == 0x28))
			break;
		if((TWCR & 0x80) && ((TWSR & 0xf8) == 0x30))
			return 0;
	}

	/* STEP7 REPEAT START */
	TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
	/* STEP8 ReStart check */
	while(1)
	{
		if((TWCR & 0x80) && ((TWSR & 0xf8) == 0x10))
			break;
	}


	/* STEP9 Address send */
	TWDR = add<<1 | 0x01; // slave address, read
	TWCR = (1<<TWINT)|(1<<TWEN);
	
	/* STEP10 ACK Check */
	while(1)
	{
		if((TWCR & 0x80) && ((TWSR & 0xf8) == 0x40))
			break;
		if((TWCR & 0x80) && ((TWSR & 0xf8) == 0x48))
			return 0;
	}

	for(i=0; i<len; i++)
	{
		/* STEP11 send ACK or NACK*/
		if((i+1)!=len)
			TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA); //ACK
		else
			TWCR = (1<<TWINT)|(1<<TWEN); //NACK
		/* STEP12 Data receive Check */
		while(1)
		{
			if((TWCR & 0x80) && ((TWSR & 0xf8) == 0x50))
				break;
			if((TWCR & 0x80) && ((TWSR & 0xf8) == 0x58))
				break;
		}
		/* STEP13 Receive Data*/
		twi_recv[i] = TWDR;
	}
			
	/* STEP14 STOP */
	TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
	return 1;	
}

중간에 있는 Sr이 Restart입니다.

데이터 읽는 걸 보면 마지막 부분에는 NACK를 보내게 되어있습니다. 그 이유는 모듈에게 데이터를 그만 보내라는 의미입니다.

사용하는 모듈의 데이터시트를보면 아래의 그림이 있습니다

이러한 그림대로 파형을 만들어야 정상적으로 동작합니다.
예를들어 0x02번지는 데이터를 2개 읽을 수 있는데 1개만 읽고 STOP신호를 보내버리면 정상적으로 STOP이 안되는 증상이 있었습니다. 파형은 아래처럼 나옵니다. 아마 슬레이브는 데이터1개를 보내고 그 다음에 데이터를 또 보내려고 SDA를 LOW로 잡고있었던거같습니다.

 

감사합니다.