Skocz do zawartości

[C] TWI (I2C) Zawiesza mikrokontroler


Mateusz

Pomocna odpowiedź

Witam.

Mam problem z układem mma7455l. A mianowicie chodzi o to, że po skomunikowaniu się z nimi wszystko działa poprawnie ale tylko przez jakiś czas, potem jak poruszam układem to jeszcze przez chwile działa a potem się zawiesza. Jak mogę to naprawić? Próbowałem WatchDoga ale układ mi świrował.

Komunikacja z mma7455l

/*
* mma7455l.c
*
* Created: 2012-03-14 15:20:33
*  Author: mati
*/ 
#include <avr/io.h>
#include "mma7455l.h"

void MMA7455L_init()
{
i2c();
}

int8_t getHeadingMMA()
{
int8_t x_mma=0;

i2c();

return x_mma;
}

Biblioteka TWI

/*************************************************************************
* Title:    I2C master library using hardware TWI interface
* Author:   Peter Fleury <pfleury@gmx.ch>  http://jump.to/fleury
* File:     $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
* Target:   any AVR device with hardware TWI 
* Usage:    API compatible with I2C Software Library i2cmaster.h
**************************************************************************/
#include <inttypes.h>
#include <compat/twi.h>

#include "i2cmaster.h"


/* define CPU frequency in Mhz here if not defined in Makefile */
#ifndef F_CPU
#define F_CPU 8000000UL
#endif

/* I2C clock in Hz */
#define SCL_CLOCK  100000L


/*************************************************************************
Initialization of the I2C bus interface. Need to be called only once
*************************************************************************/
void i2c_init(void)
{
 /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */

 TWSR = 0;                         /* no prescaler */
 TWBR = ((F_CPU/SCL_CLOCK)-16)/2;  /* must be > 10 for stable operation */

}/* i2c_init */


/*************************************************************************	
 Issues a start condition and sends address and transfer direction.
 return 0 = device accessible, 1= failed to access device
*************************************************************************/
unsigned char i2c(void)
{
   /* send stop condition */
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);

// wait until stop condition is executed and bus released
while(TWCR & (1<<TWSTO));

}/* i2c_stop */


/*************************************************************************
 Send one byte to I2C device

 Input:    byte to be transfered
 Return:   0 write successful 
           1 write failed
*************************************************************************/
unsigned char i2c_write( unsigned char data )
{	
   uint8_t   twst;

// send data to the previously addressed device
TWDR = data;
TWCR = (1<<TWINT) | (1<<TWEN);

// wait until transmission completed
while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits
twst = TW_STATUS & 0xF8;
if( twst != TW_MT_DATA_ACK) return 1;
return 0;

}/* i2c_write */


/*************************************************************************
Read one byte from the I2C device, request more data from device 

Return:  byte read from I2C device
*************************************************************************/
unsigned char i2c_readAck(void)
{
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
while(!(TWCR & (1<<TWINT)));    

   return TWDR;

}/* i2c_readAck */


/*************************************************************************
Read one byte from the I2C device, read is followed by a stop condition 

Return:  byte read from I2C device
*************************************************************************/
unsigned char i2c_readNak(void)
{
TWCR = (1<<TWINT) | (1<<TWEN);
while(!(TWCR & (1<<TWINT)));

   return TWDR;

}/* i2c_readNak */
Link do komentarza
Share on other sites

Jak poruszasz czujnikiem to w którymś momencie na chwile przewody tracą połączenie, powoduje to wygenerowania błędu na szynie I2C, którego Ty nie obsługujesz.

Masz 2 możliwości:

a) Prosta - do tych whileów czekających na odpowiedni komunikat I2C dodaj jakiś czas po którym czekanie jest porzucone i zaczynasz komunikację od początku.

Czyli coś w stylu

int a=10;
while ((...) & (a-->0))
{
delayus(10);
}

Czekasz 10 razy po 10us i jak w 100us nie przyjdzie spodziewana odpowiedz po I2C (np. ACK) to mimo wszystko idziesz dalej.

b) Możliwość trudniejsza to pełne wykorzystanie sprzętowej implementacji I2C, obsługiwanie przerwań itd.

Niestety nie jest to za proste...

Link do komentarza
Share on other sites

I jeszcze filmik jak to działa a w zasadzie to nie 🙂.

I zaraz spróbuje Twojego rozwiązania.

Odkryłem kiedy występuje błąd. Po pierwsze jest on powodowany przez akcelerometr bo jak mam tylko gyro to wszystko działa.

A jak akcelerometr wysyła wartości większe od 0 to wszystko jest ok, jednak gdy wartości wchodzą na minus coś złego się dzieje.

Np. jak wysyłałem wartości po UART do kompa to wszystko było ok a jak wartości z akcelerometru spadały poniżej 0 to wysyłane były jakieś śmieci i kamera przestawała działać.

A co do kompasu to wszystko działa jeżeli płytka stoi poziomo jednak jeżeli ją trochę obrócę względem osi x lub y to kompas trochę wariuje 9wszystko widać na filmiku poniżej. Kąt obliczam w taki sposób:

int headingDegrees = atan2(raw_y,raw_x)* 57 + 180;

Wykorzystuje tylko odczyty x i y. Może powinienem dodać jeszcze z? Albo może są jakieś inne rozwiązania?

No i po połączeniu obu ruchów. Jeszcze sporo do poprawy zostaje. Bo jak widać na końcu filmiku znowu się zawiesiło i nie mam pojęcia czemu ani w jakim miejscu. Ale zawiesza się tylko jak używany jest akcelerometr. No i nie wiem jak ten kompas opanować żeby nie reagował na ruchy góra i dół.

MirekCz

Zrobiłem tak jak pisałeś ale nic to nie zmieniło.

/*************************************************************************
* Title:    I2C master library using hardware TWI interface
* Author:   Peter Fleury <pfleury@gmx.ch>  http://jump.to/fleury
* File:     $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
* Target:   any AVR device with hardware TWI 
* Usage:    API compatible with I2C Software Library i2cmaster.h
**************************************************************************/
#define F_CPU 8000000UL
#include <inttypes.h>
#include <compat/twi.h>
#include <util/delay.h>

#include "i2cmaster.h"

/* I2C clock in Hz */
#define SCL_CLOCK  100000L


/*************************************************************************
Initialization of the I2C bus interface. Need to be called only once
*************************************************************************/
void i2c_init(void)
{
 /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */

 TWSR = 0;                         /* no prescaler */
 TWBR = ((F_CPU/SCL_CLOCK)-16)/2;  /* must be > 10 for stable operation */

}/* i2c_init */


/*************************************************************************	
 Issues a start condition and sends address and transfer direction.
 return 0 = device accessible, 1= failed to access device
*************************************************************************/
unsigned char i2c(void)
{
   /* send stop condition */
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);

// wait until stop condition is executed and bus released
int a=100;
while(TWCR & (1<<TWSTO) && a>0)
{
	_delay_us(10);
	a--;
}

}/* i2c_stop */


/*************************************************************************
 Send one byte to I2C device

 Input:    byte to be transfered
 Return:   0 write successful 
           1 write failed
*************************************************************************/
unsigned char i2c_write( unsigned char data )
{	
   uint8_t   twst;

// send data to the previously addressed device
TWDR = data;
TWCR = (1<<TWINT) | (1<<TWEN);

// wait until transmission completed
int a=100;
while(!(TWCR & (1<<TWINT)) && a>0)
{
	_delay_us(10);
	a--;
}

// check value of TWI Status Register. Mask prescaler bits
twst = TW_STATUS & 0xF8;
if( twst != TW_MT_DATA_ACK) return 1;
return 0;

}/* i2c_write */


/*************************************************************************
Read one byte from the I2C device, request more data from device 

Return:  byte read from I2C device
*************************************************************************/
unsigned char i2c_readAck(void)
{
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
int a=100;
while(!(TWCR & (1<<TWINT)) && a>0)
{
	_delay_us(10);
	a--;
} 

   return TWDR;

}/* i2c_readAck */


/*************************************************************************
Read one byte from the I2C device, read is followed by a stop condition 

Return:  byte read from I2C device
*************************************************************************/
unsigned char i2c_readNak(void)
{
TWCR = (1<<TWINT) | (1<<TWEN);
int a=100;
while(!(TWCR & (1<<TWINT)) && a>0)
{
	_delay_us(10);
	a--;
}


   return TWDR;

}/* i2c_readNak */

Obsługa czujnika:

/*
* mma7455l.c
*
* Created: 2012-03-14 15:20:33
*  Author: mati
*/ 
#include <avr/io.h>
#include "mma7455l.h"

void MMA7455L_init()
{
i2c();
}

int8_t getHeadingMMA()
{
int8_t x_mma=0;

i2c();

return x_mma;
}
Link do komentarza
Share on other sites

Mam podobny problem z AVR32. Otóż próba sprawdzenia linii I2C pod katem obecności urządzeń zawiesza mikrokontroler jeżeli żadne urządzenie nie jest podłączone. Czy znacie jakieś sposoby na ominięcie problemu?

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Próbowaliście zamiast tych bibliotek Petera Fleury i innych wzorowanych na niej działających w pętlach wypróbować biblioteki dostarczone przez Atmela w appnote AVR315: http://www.atmel.com/Images/doc2564.pdf

W linku pdf do appnota ale ze strony można też ściągnąć gotowe funkcje w C. Ja z nich korzystałem parę razy i nigdy nie miałem problemów. Szczególnie mi się przydały do systemu wielozadaniowego, gdzie na takie pętle nie mogłem sobie pozwolić. Poza tym biblioteka udostępnia gotowe bufory nadawcze i odbiorcze, informacje o błędach itp.

Link do komentarza
Share on other sites

Mam problem z układem mma7455l. A mianowicie chodzi o to, że po skomunikowaniu się z nimi wszystko działa poprawnie ale tylko przez jakiś czas, potem jak poruszam układem to jeszcze przez chwile działa a potem się zawiesza. Jak mogę to naprawić?

Pokaż schemat + PCB + zdjęcia, bo na filmie widać, że dotykasz płytki rękoma.

Link do komentarza
Share on other sites

Udało się rozwiązać mój problem 🙂 po prostu podczas odczytu z czujnika mma odczytywałem jeden bajt funkcją RaedAck a powienienm ReadNak 🙂.

A czy ktoś ma pomysł jak odczytać pozycję z kompasu 3-osiowego w taki sposób aby też gdy jest w innym położeniu niż poziomym?

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.