MSP430G2553 I2C (MPU6050)

Başlatan baran123, 17 Şubat 2016, 22:48:18

baran123

Aşağıdaki kodlar ile MPU6050 okumaya çalışıyorum AD0 VCC bağlı fakat kod Receive fonksiyonun daki şu satırda takılıyor.
while((IFG2 & UCB0TXIFG) == 0);


Nerede hata yapıyorum tam olarak anlamadım.SDA, SCL 10k ile pull-up yaptım.
/*
 * main.c
*/
#include <msp430.h> 

#define RXD	(BIT1)
#define TXD (BIT2)

#define MPU6050_I2C_ADDR	(0x69)
#define MPU6050_WHO_AM_I	(0x75)

#define LED_PDIR	P1DIR
#define LED_POUT	P1OUT
#define LED_BIT		BIT0
#define LED_PIN		0
#define LED_1		(LED_POUT |= 1 << LED_PIN)
#define LED_0		(LED_POUT &= ~(1 << LED_PIN))

typedef unsigned char uint8_t;

void FREQ_Init(void);
void GPIO_Init(void);
void I2C_Init(void);
void UART_Init(void);
void UART_SendData(uint8_t data);

int I2C_NotReady(void);
char I2C_Receive(char registerAddr);
void I2C_Transmit(char registerAddr, char data);

void main(void)
{
	FREQ_Init();
	GPIO_Init();
	UART_Init();
	I2C_Init();

	unsigned char who_am_i = 0x00;

	while (I2C_NotReady());

	who_am_i = I2C_Receive(MPU6050_WHO_AM_I);

	LED_1;

	for(;;)
	{
		UART_SendData(who_am_i);
		__delay_cycles(500000);
	}
}

void FREQ_Init(void)
{
	// Stop watchdog timer
	WDTCTL = WDTPW | WDTHOLD;

	//
	BCSCTL1 = CALBC1_1MHZ;

	//
	DCOCTL = CALDCO_1MHZ;
}

void GPIO_Init(void)
{
	// Set P1.0 as an Output pin
	LED_PDIR |= LED_BIT;

	// Set P1.0 LOW (turn LED off)
	LED_POUT &= ~LED_BIT;
}

void I2C_Init(void)
{
	P1SEL |= BIT6 + BIT7;
	P1SEL2 |= BIT6 + BIT7;

	UCB0CTL1 |= UCSWRST;                      	// Enable SW reset
	UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;     	// I2C Master, synchronous mode
	UCB0CTL1 = UCSSEL_2 + UCSWRST;            	// Use SMCLK, keep SW reset
	UCB0BR0 = 10;                             	// fSCL = SMCLK/12 = ~100kHz
	UCB0BR1 = 0;
	UCB0I2CSA = MPU6050_I2C_ADDR;         		// Slave Address is 069h
	UCB0CTL1 &= ~UCSWRST;                     	// Clear SW reset, resume operation
	IE2 |= UCB0RXIE + UCB0TXIE;
}

void UART_Init(void)
{
	//
	P1SEL = RXD + TXD;

	//
	P1SEL2 = RXD + TXD;

	/* SMCLK SECILDI */
	UCA0CTL1 = UCSSEL_2;

	/* 1MHZ –>> 9600 BAUD ve N = fclk/ Baud Rate */
	UCA0BR0 = 104;

	/* BAUD 9600 */
	UCA0BR1 = 0;

	/* MODULASYON UCBRSX = 1 */
	UCA0MCTL = UCBRS1;

	/* UCSWRST DE AKTIF EDILIYOR RESETTE KALMAMASI ICIN */
	UCA0CTL1 &= ~UCSWRST;
}

void UART_SendData(uint8_t data)
{
	/* */
	while(!(IFG2 & UCA0TXIFG));

	/* */
	UCA0TXBUF = data;
}

int I2C_NotReady(void)
{
	if(UCB0STAT & UCBBUSY)
		return 1;
	else
		return 0;
}

char I2C_Receive(char registerAddr)
{
	uint8_t receivedByte;
	while (UCB0CTL1 & UCTXSTP); 		// Ensure stop condition got sent
	UCB0CTL1 |= UCTR + UCTXSTT; 		// I2C start condition with UCTR flag for transmit
	while((IFG2 & UCB0TXIFG) == 0); 	// UCB0TXIFG is set immidiately
	UCB0TXBUF = registerAddr;		 	// write registerAddr in TX buffer
	while((IFG2 & UCB0TXIFG) == 0); 	// wait until TX buffer is empty and transmitted
	UCB0CTL1 &= ~UCTR ; 				// Clear I2C TX flag for receive
	UCB0CTL1 |= UCTXSTT + UCTXNACK; 	// I2C start condition with NACK for single byte reading
	//while (UCB0CTL1 & UCTXSTT); 		// Start condition sent? RXBuffer full?
	while(UCB0RXIFG != (IFG2 & UCB0RXIFG));
	receivedByte = UCB0RXBUF;
	UCB0CTL1 |= UCTXSTP; 				// I2C stop condition
	return receivedByte;
}

void I2C_Transmit(char registerAddr, char data)
{
    while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
    UCB0CTL1 |= UCTR + UCTXSTT;             // I2C start condition with UCTR flag for transmit
    while((IFG2 & UCB0TXIFG) == 0);         // UCB0TXIFG is set immidiately
    UCB0TXBUF = registerAddr;               // write registerAddr in TX buffer
    while((IFG2 & UCB0TXIFG) == 0);         // wait until TX buffer is empty and transmitted
    UCB0TXBUF = data;                       // Write data in register
    while((IFG2 & UCB0TXIFG) == 0);         // wait until TX buffer is empty and transmitted
    UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
    IFG2 &= ~UCB0TXIFG;                     // Clear TX interrupt flag
}

Cemre.

Baran öncelikle MPU6050 Adresini bir bit sola kaydırman gerekiyor. (mpu6050adres <<1) şeklinde olabilir.

Bir de modülü uyandırma meselesi var. PWR_MGMT_1 isimli register'ın 7.biti önce 1 sonra 0 yapılırsa modül iletişime hazır oluyor. Bunu her enerji kesip verdiğinde yapmalısın, yani init kodu gibi bir şey olacak senin için

Daha yarım saat önce blog'umda bir yazı yayınladım STM için ama eminim anlarsın.

Kolay gelsin, iyi akşamlar.

Çizgi Tagem

Tam olarak hangi noktada while((IFG2 & UCB0TXIFG) == 0); döngüsü içinden çıkmıyor? Çünkü bu kod parçası bir çok yerde kullanılıyor. Eğer ilk karşılaştığı andan itibaren döngüden çıkmıyorsa yazılımdan ziyade sensör yada donanıma yoğunlaşmak gerekir.

baran123

Fonksiyonun içindeki 3.While da takılıyor.
@cemre inceliyorum teşekkürler.

Çizgi Tagem

Hangi fonksiyon? Receive yada transmit? Bahsettiğin kod parçası programda 7 kez kullanılıyor.

baran123

Hala aynı noktada problem yaşıyorum.Sensörü 3.3V ile besliyorum.AD0 pini VCC bağlı.
@cemre dediğin gibi kaydırma işlemini yaptım fakat durum aynı.

#define MPU6050_ADDRESS 0x69 		// Address MPU6050

uint8_t I2C_NotReady(void)
{
	if(UCB0STAT & UCBBUSY)
		return 1;
	else
		return 0;
}

uint8_t I2C_ReadData(uint8_t registerAddr)
{
	//
	while (UCB0CTL1 & UCTXSTP);

	//
	UCB0CTL1 |= UCTR + UCTXSTT;

	//
	while (!(IFG2 & UCB0TXIFG));

	//
	UCB0TXBUF = registerAddr;

	//
	while (!(IFG2 & UCB0TXIFG));

	//
	UCB0CTL1 &= ~UCTR;

	 //
	UCB0CTL1 |= UCTXSTT;

	//
	IFG2 &= ~UCB0TXIFG;

	//
	while (UCB0CTL1 & UCTXSTT);

	//
	UCB0CTL1 |= UCTXSTP;

	//
	return (UCB0RXBUF);
}

void I2C_Init(uint8_t I2C_Addr)
{
	P1SEL |= BIT6 + BIT7;
	P1SEL2 |= BIT6 + BIT7;

	UCB0CTL1 |= UCSWRST;                      	// Enable SW reset
	UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;     	// I2C Master, synchronous mode
	UCB0CTL1 = UCSSEL_2 + UCSWRST;            	// Use SMCLK, keep SW reset
	UCB0BR0 = 10;                             	// fSCL = SMCLK / 10 = ~100kHz
	UCB0BR1 = 0;								//
	UCB0I2CSA = (I2C_Addr << 1);         		// Slave Address is 069h
	UCB0CTL1 &= ~UCSWRST;                     	// Clear SW reset, resume operation
	IE2 |= UCB0RXIE + UCB0TXIE;
}

uint8_t MPU6050_Init(void)
{
	static uint8_t I_AM = 0x00;

	I2C_Init(MPU6050_ADDRESS);

	while (I2C_NotReady());

	I_AM = I2C_ReadData(MPU6050_RA_WHO_AM_I);

	if(MPU6050_RA_WHO_AM_I == I_AM)
		return (MPU6050_Ok);
	else
		return(MPU6050_Error);
}


Kullanım ise şu şekilde
MPU6050_Ready = (MPU6050_Init()) ? 1 : 0;


I2C_Init içindeki 3.while da takılı kalıyor.Sanırım veriyi yollayamıyor.Arduino ile test ettim sensör çalışıyor.

Çizgi Tagem

#6
Adresleme ile ilgili bir sıkıntı olabilir gibi tam olarak anlamadım init kodu içinde while bloğu göremedim.

After beginning communications with the START condition (S), the master sends a 7-bit slave address
followed by an 8th bit, the read/write bit. Ayrıca datasheet üzerinde şöyle bir ibare var. Yani ilk 7 bit adres ama 8. biti sürekli olarak okuma yada yazma yapacağın zaman değiştirmen lazım. Yani start sinyalini göndermeden önce okuma yada yazma durumuna göre slave adres değişkeninin 8. bitini güncellemen lazım. Çünkü USCI birimini start sinyalini gönderdikten sonra otomatik olarak slave adresini de gönderiyor. Birde bunu dene düzelebilir.

// Yazma için
UCB0I2CSA = Slave_Adr & ~BIT7; 
UCB0CTL1 |= UCTR + UCTXSTT;

// Okuma için
UCB0I2CSA = Slave_Adr + BIT7; 
UCB0CTL1 |= UCTR + UCTXSTT;

baran123

Affedersiniz I2C_Write fonksiyonu içindeki 3. while da takılıyor.Biraz düzenleme yaptım.Kodun son hali şu şekilde.

void I2C_Init(uint8_t I2C_Addr)
{
	P1SEL |= BIT6 + BIT7;
	
	P1SEL2 |= BIT6 + BIT7;

	// Enable SW reset
	UCB0CTL1 |= UCSWRST;    
	
	// I2C Master, synchronous mode
	UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;  
	
	// Use SMCLK, keep SW reset
	UCB0CTL1 = UCSSEL_2 + UCSWRST;     
	
	// fSCL = SMCLK / 10 = ~100kHz
	UCB0BR0 = 40; 
	
	//
	UCB0BR1 = 0;	
	
	// Slave Address is 068h
	UCB0I2CSA = I2C_Addr  & ~BIT7;    
	
	// Clear SW reset, resume operation
	UCB0CTL1 &= ~UCSWRST;                     	
}

void I2C_Write(uint8_t registerAddr, uint8_t data)
{
	// Ensure stop condition got sent
    while (UCB0CTL1 & UCTXSTP);

    // I2C start condition with UCTR flag for transmit
    UCB0CTL1 |= UCTR + UCTXSTT;

    // UCB0TXIFG is set immidiately
    while((IFG2 & UCB0TXIFG) == 0);

    // write registerAddr in TX buffer
    UCB0TXBUF = registerAddr;

    // wait until TX buffer is empty and transmitted
    while((IFG2 & UCB0TXIFG) == 0);

    // Write data in register
    UCB0TXBUF = data;

    // wait until TX buffer is empty and transmitted
    while((IFG2 & UCB0TXIFG) == 0);

    // I2C stop condition
    UCB0CTL1 |= UCTXSTP;

    // Clear TX interrupt flag
    IFG2 &= ~UCB0TXIFG;
}

Kullanım ise ;
I2C_Write(MPU6050_RA_PWR_MGMT_1, 0x80); //Önce 1 
I2C_Write(MPU6050_RA_PWR_MGMT_1, 0x00); //Sonra 0 yapılarak modül uyandırılır.

Tabi daha ilk write da takılıyor..

Cemre.

Baran buradaki hatanın modül ile ilgili olduğunu sanmıyorum. Sen read fonksiyonunda takılmıyorsun ki? Sen write fonksiyonunda takılıyorsun. Yani sen daha hatta veri basamıyorsun. Buraya bir odaklan, çalıştığından emin olduğun bir I2C Write rutini bulamaz mısın? Ben MSP ile çalışmadığım için yanlış birşey söylemek istemiyorum ama buradaki hatanın modül ile ilgisi yok sanıyorum.

baran123

Hocam zaten write ta sorun var gönderme işlemi yapamıyor.
İnternette denemedik fonksiyon bırakmadım hepsinde aynı problem var. :/
Çok ufak bir hata yapıyorum sanırım.

baran123

Sorun çözüldü artık while da takılmıyor.Bilin bakalım neden ? O I2C pinlerinin 6 nolu olanında LED Jumperı varmış. :) Çıkarmam ile çalışması bir oldu.
Bende bu led niye yanıyor diyorum.
Evet beni forumdan atabilirsiniz. :D

Erhan YILMAZ

Çizgi Tagem'e teşekkürler :D