TWI (I2C) interfejs Atmega328

Wątek przeniesiony 2018-11-08 11:16 z C/C++ przez Marooned.

0

Potrzebuję pomocy. Zaprogramowałem Atmege328 z myślą o testach interfejsu TWI (I2C). Hardware'owo linie interfejsu (SCL, SDA) mam przez rezystory podciągnięte do +5V i cały procek tymże napięciem zasilam.
Pytanie brzmi dlaczego PB0 nie clear'uje się, innymi słowy : dlaczego procesor ani razu nie wchodzi w procedurę obsługi przerwania od TWI jeśli przecież ma moduł włączony, poprawnie zainicjalizowany a przerwanie od tego jest załączone.
Efekt powinien moim zdaniem być taki że po kliknięciu przycisku podpiętego do PB5 transmisja powinna się rozpocząć a prędzej czy później przerwanie powinno być odpalone.


#include <avr/io.h>
#include <avr/interrupt.h>

/* define slave (MPU6050) address as 0x68 because AD0 is low */
#define SLAVE_ADDRESS (0x68)
#define WHO_AM_I (0x75)

volatile enum state
{
    IDLE,
    START_BIT_TRANSMIT,
    SLAVE_ADDRESS_TRANSMIT,
    DATA_TRANSMIT
} sm;

void TimerInit()
{
    /* overflow interrupt enable and start timer on frequency 8MHz / 1024 */
    TIMSK0 |= (1 << TOIE0);
    TCCR0B |= (1 << CS00) | (1 << CS02);
}

void TwiInit()
{
    /* 100 kHz frequency of TWI and enable TWI module and interrupt from them */
    TWBR = 8;
    TWCR = (1 << TWEN) | (1 << TWIE);
}

/* TWI interrupt service routine */
ISR(TWI_vect)
{
    PORTB &= ~(1 << PB0);

    switch (sm)
    {
        case IDLE:
        {
            break;
        }

        case START_BIT_TRANSMIT:
        {
            /* clear start bit manually and prepare slave address SLA+W */
            TWCR &= ~(1 << TWSTA);
            TWDR = (SLAVE_ADDRESS << 1);
            TWCR |= (1 << TWINT);

            if ((TWSR == 0x08) || (TWSR == 0x10))
            {
                sm = SLAVE_ADDRESS_TRANSMIT;
            }
            break;
        }

        case SLAVE_ADDRESS_TRANSMIT:
        {
            /* prepare data */
            TWDR = WHO_AM_I;
            TWCR |= (1 << TWINT);

            if ((TWSR == 0x18) || (TWSR == 0x20))
            {
                sm = DATA_TRANSMIT;
            }
            break;
        }

        case DATA_TRANSMIT:
        {
            /* prepare stop bit */
            TWCR |= (1 << TWINT) | (1 << TWSTO);

            if ((TWSR == 0x28) || (TWSR == 0x30))
            {
                sm = IDLE;
            }
            break;
        }

        default:
        {
            break;
        }
    }
}

/* timer overflow interrupt service routine */
ISR(TIMER0_OVF_vect)
{
    PORTD ^= (1 << PD7);
}

int main(void)
{
    /* diodes output */
    DDRB |= (1 << PB0);
    DDRD |= (1 << PD7);

    /* diodes turn off */
    PORTB |= (1 << PB0);
    PORTD |= (1 << PD7);

    /* pull up resistor on PD5 input switch */
    PORTD |= (1 << PD5);

    TimerInit();
    TwiInit();

    sei();

    while (1)
    {
        if (!((PIND >> PD5) & 1))
        {
            if (sm == IDLE)
            {
                sm = START_BIT_TRANSMIT;
                TWCR |= (1 << TWSTA) | (1 << TWINT);
            }
        }
    }
}

0

Mikroklocki mogła robić przerwania tylko na określonych portach i chyba nie są to za wysokie tak na moje oko.

0

Ciekawe co prawisz... Mógłbyś rozwinąć swoją wypowiedź i napisać ją pełnym zdaniem bo przyznać muszę że nic z niej nie rozumiem a bardzo chciałbym. :)

0

Hmm, kiedyś robiłem coś na mikrokontrolerze i tam max 2 porty przerwania obsługiwały i w specyfikacji mirokontrolera było napisane, które to obsługują.

W ogóle u ciebie po wykonaniu przerwania jest xorowane coś.
Taki xor zmienia wartość, ale takie coś powoduje, że co drugie wywołanie jest takie same przy pętli.
switch może być cały czas zależny od pb0.

0

Wszystko testuję również oscyloskopem i jestem pewien że to przerwanie nie odpala się.
Co masz na myśli pisząc: "i tam max 2 porty przerwania obsługiwały...", albo ja polskiego nie znam albo to nie jest po polsku w ogóle...
Zmieniłem XORa w przerwaniu od TWI na clearowanie:

PORTB &= ~(1 << PB0);

Niestety dioda podłączona katodą do mikroklocka nie zapaliła się wcale a to świadczy o tym że to przerwanie się nie odpaliło (a powinno!).

0

A nie możesz zamiast tego TWI_vect podać INT0 INT1 tak jak się normalnie podaje, na którym porcie przerwanie ma wystąpić w ISR.

Chodź może oznacza to to samo, ale lepiej te proste nazewnictwo wykorzystać.

0

Przerwanie od TWI to całkiem inny rodzaj przerwania niż przerwanie od zmiany poziomu czy zbocza na wejściu cyfrowym mikrokontrolera.
Procesor posiada masę różnych źródeł przerwań a nie tylko przerwania od INT0 czy INT1, między innymi przerwanie od wykonania operacji przez moduł TWI który wykorzystuje linie SCL i SDA do transmisji cyfrowej po protokole I2C (nazwa Atmelowska to TWI ale standard ten sam).
Ty mi tu piszesz na temat INT0 i INT1 ale to nie na temat, mimo wszystko dzięki za chęć pomocy.
Polecam przeczytać rozdział dokumentacji o nazwie: "Interrupts", znajdziesz tam pełną listę źródeł przerwań dla danego typu procesora.

0

Dawno nie urzywałem TWI w AVR, tym bardziej z przerwaniami ;-), ale jak patrzę na twój kod vs nota katalogowa, to widzę, że w nocie przy każdym zapisie do rejestru TWCR ustawiany jest bit TWEN.

Bit 2 – TWEN: TWI Enable
The TWEN bit enables TWI operation and activates the TWI interface.

0

Bit TWEN jest ustawiony na początku w TwiInit() i nic już go nie kasuje. Jestem pewien że on jest ustawiony i że dalej już nie jest konieczne ponowne jego ustawianie bo nic go nie kasuje. Mimo to sprawdziłem jak to wszystko działa jak do każdej instrukcji z TWCR-em dodałem | (1 << TWEN).
Efekt ten sam, przerwanie nie odpala się wcale. Może ja mam procesor popsuty, czy byłby ktoś łaskaw sprawdzić to u siebie z tym kodem?
Do PB0 i PD7 podpinamy katodami diody (anody przez rezystory do plusa), do PD5 przycisk, flash'ujemy i po uruchomieniu naciskamy przycisk i sprawdzamy czy dioda podłączona do PB0 zapaliła się.

0

Wrzuciłem do Atmega168PB, (Zestaw XPlained Mini) i wygląda na to że kod działa.

0

Ciekawe co zatem stało się z moim prockiem jeśli licznik i inne przerwania w nim działają, działają porty we/wy, działają inne peryferia a procesor nie chce odpalać przerwania od TWI, być może uszkodzeniu uległo właśnie TWI w czasie testów (może coś przez przypadek zwarłem nie tam gdzie trzeba itp itd).

Czy jest możliwość aby uszkodzić procesor poprzez dotyk gołymi rękami jego nóżek (elektrostatyczne ładunki) ?

0

Tak w ogóle to w pliku utils/twi.h masz parę przydatnych funkcji i definicji do obsługi TWI. Ponadto twoja maszyna stanów nie będzie działać. Raczej powinno to wyglądać mniej więcej tak:

/* TWI interrupt service routine */
ISR(TWI_vect)
{
  switch (sm)
  {
    case IDLE:
      break;
    case START_BIT_TRANSMIT:
      /* clear start bit manually and prepare slave address SLA+W */
      if ((TWSR & 0xF8) == TW_START) {
        TWDR = (SLAVE_ADDRESS);
        TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE);
        sm = SLAVE_ADDRESS_TRANSMIT;
      } else 
        sm = ERROR;
      break;
    
    case SLAVE_ADDRESS_TRANSMIT:
      /* prepare data */
      if ((TWSR & 0xF8) == TW_MT_SLA_ACK) {
        
        TWDR = WHO_AM_I;
        TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE);
        sm = DATA_TRANSMIT;
      } else {
        sm = ERROR;
       
      }
    break;
    
    case DATA_TRANSMIT:
      /* prepare stop bit */
      if ((TWSR & 0xF8) == TW_MT_DATA_ACK) {
        TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
        sm = IDLE;
      } else {
        sm = ERROR;
      }
    break;

    case ERROR:
      while (1) {
        PORTB ^= (1 << PB5);
        _delay_ms(500);
      }
      break;
    
    default:
    {
      break;
    }
  }
}

Co ciekawe zapis do rejestru TWCR z maskowaniem poszczególnych bitów sprawiał, że u mnie transmisja kończyła się na wysłaniu adresu urządzenia slave na magistralę.

0

A jaki ma sens sprawdzenie TWSR zaraz po resecie flagi TWINT?

0

No np. taki że flaga kasuje "źródło przerwania" natomiast nie kasuje rejestru TWSR z bieżącej wartości. Nigdzie nie znalazłem informacji że należy wpierw sprawdzić status a dopiero potem skasować jedynką TWINT.
Jeśli chodzi o zapis do TWDR to już inna sprawa ale tutaj także błędu nie robię bo zanim napisze jedynkę do TWINT to ustawiam TWDR.

0

Zafleszowałem takim kodem i dalej przerwanie nie chce się odpalić ani razu! Mam już dosyć. Podejrzewam uszkodzenie procesora... pomocy...

/*
 * main.c
 *
 *  Created on: 30 wrz 2017
 *      Author: Adam
 */


#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

/* define slave (MPU6050) address as 0x68 because AD0 is low */
#define SLAVE_ADDRESS (0x68)
#define WHO_AM_I (0x75)

volatile enum state
{
    IDLE,
    START_BIT_TRANSMIT,
    SLAVE_ADDRESS_TRANSMIT,
    DATA_TRANSMIT,
    ERROR
} sm;

void TimerInit()
{
    /* overflow interrupt enable and start timer on frequency 8MHz / 1024 */
    TIMSK0 |= (1 << TOIE0);
    TCCR0B |= (1 << CS00) | (1 << CS02);
}

void TwiInit()
{
    /* 100 kHz frequency of TWI and enable TWI module and interrupt from them */
    TWBR = 32;
    TWCR = (1 << TWEN) | (1 << TWIE);
}

/* TWI interrupt service routine */
ISR(TWI_vect)
{
  switch (sm)
  {
    case IDLE:
      break;
    case START_BIT_TRANSMIT:
      /* clear start bit manually and prepare slave address SLA+W */
      if ((TWSR & 0xF8) == 0x08) {
        TWDR = (SLAVE_ADDRESS);
        TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE);
        sm = SLAVE_ADDRESS_TRANSMIT;
      } else
        sm = ERROR;
      break;

    case SLAVE_ADDRESS_TRANSMIT:
      /* prepare data */
      if ((TWSR & 0xF8) == 0x18) {

        TWDR = WHO_AM_I;
        TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE);
        sm = DATA_TRANSMIT;
      } else {
        sm = ERROR;

      }
    break;

    case DATA_TRANSMIT:
      /* prepare stop bit */
      if ((TWSR & 0xF8) == 0x28) {
        TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
        sm = IDLE;
      } else {
        sm = ERROR;
      }
    break;

    case ERROR:
      while (1) {
        PORTB ^= (1 << PB0);
        _delay_ms(500);
      }
      break;

    default:
    {
      break;
    }
  }
}


/* TWI interrupt service routine */
/*ISR(TWI_vect)
{
    PORTB &= ~(1 << PB0);

    switch (sm)
    {
        case IDLE:
        {
             clear interrupt flag
            TWCR |= (1 << TWINT);
            break;
        }

        case START_BIT_TRANSMIT:
        {
             clear start bit manually and prepare slave address SLA+W
            TWCR &= ~(1 << TWSTA);
            TWDR = (SLAVE_ADDRESS << 1);
            TWCR |= (1 << TWINT);

            if ((TWSR == 0x08) || (TWSR == 0x10))
            {
                sm = SLAVE_ADDRESS_TRANSMIT;
            }
            else
            {
                sm = IDLE;
            }
            break;
        }

        case SLAVE_ADDRESS_TRANSMIT:
        {
             prepare data
            TWDR = WHO_AM_I;
            TWCR |= (1 << TWINT);

            if ((TWSR == 0x18) || (TWSR == 0x20))
            {
                sm = DATA_TRANSMIT;
            }
            else
            {
                sm = IDLE;
            }
            break;
        }

        case DATA_TRANSMIT:
        {
             prepare stop bit
            TWCR |= (1 << TWINT) | (1 << TWSTO);

            if ((TWSR == 0x28) || (TWSR == 0x30))
            {
                sm = IDLE;
            }
            else
            {
                sm = IDLE;
            }
            break;
        }

        default:
        {
            break;
        }
    }
}*/

/* timer overflow interrupt service routine */
ISR(TIMER0_OVF_vect)
{
    //PORTD ^= (1 << PD7);
}

int main(void)
{
    /* diodes output */
    DDRB |= (1 << PB0);
    DDRD |= (1 << PD7);

    /* diodes turn off */
    PORTB |= (1 << PB0);
    PORTD |= (1 << PD7);

    /* pull up resistor on PD5 input switch */
    PORTD |= (1 << PD5);

    TimerInit();
    TwiInit();

    sei();

    while (1)
    {
        if (!((PIND >> PD5) & 1))
        {
            if (sm == IDLE)
            {
                PORTD ^= (1 << PD7);
                sm = START_BIT_TRANSMIT;
                TWCR = (1 << TWSTA) | (1 << TWINT) | (1 << TWEN) | (1 << TWIE);
            }
        }
    }
}

0

No więc wziąłem i zrobiłem próby dodatkowo na dwóch procesorach typu Atmega8. jak wiadomo cały pinout tych procków jest ten sam co dla Atmegi328, zmiany wymagały nazwy dwóch rejestrów:

  1. Zamiast TCCR0B mamy TCCR0
  2. Zamiast TIMSK0 mamy TIMSK

Efekt ten sam, przerwanie nie odpala się, maszyna stanów utyka dokładnie na stanie START_BIT_TRANSMIT który to ustawiany jest po naciśnięciu przycisku. Nie wiem co z tym dalej zrobić, bo w tym momencie jestem skłonny odrzucić pogląd o popsutym klocku.
Ktoś jest w stanie coś poradzić ?

1
  1. Jesteś w stanie zobaczyć co dzieje się na pinach SDA & SCL analizatorem logicznym?
  2. Czy możesz uruchomić komunikację TWI bez korzystania z przerwania?
  3. Jaki masz ustawiony zegar mikroprocesora?
  4. Ten czujnik na I2C to jakiś moduł? Ma podciąganie liniii SDA & SCL?
  5. Próbowałeś odpalić kod z odłączonym modułem?

Poza tym jest nota: AVR315: Using the TWI Module as I2C Master - Atmel, z którą możesz się zapoznać.

PS. Wieczorem będę miał ATmega328p, więc mogę jeszcze raz na to spojrzeć ;-)

0
  1. Na pinach SDA i SCL nie dzieje się nic - tzn. one są podciągnięte do Vcc i obserwuję to oscyloskopem ustawionym na triggerowanie tych linii - jakiekolwiek zbocze opadające wyzwala mi zatrzymanie a do takiego dochodzi tylko wówczas gdy zdejmuję zasilanie z układu :/
  2. Sprawdzę dziś i dam znać
  3. Zegar to wewnętrzny oscylator 8MHz
  4. Podciąganie linii realizuję sobie hardwareowo - dałem tam oporniki 2k7, aktualnie jest tak że czujnik nie jest podpięty pod układ więc mikroprocesor pracuje sobie jeśli chodzi o ten interfejs tylko z tymi rezystorkami
  5. Dopóki to nie ruszy nie ma sensu dawać tam tego czujnika bo on i tak nic nie odpowie a mogłoby mu ta sytuacja jeszcze zaszkodzić bo jeśli coś jest upalone to może zachować się nie po myśli protokołu
0

Zrobiłem próby związane z TWI bez wykorzystania przerwania i efekt jest mizerny, to znaczy dioda podłączona do PD7 po naciśnięciu przycisku zapaliła się i nie zgasła co świadczy o tym że program utknął na pierwszym while (!(TWCR & (1 << TWINT))); co z kolei świadczy o tym że TWI nie chce wykonać operacji startu. Potwierdzone jest to oscyloskopem - linie SCL, SDA ani drgną a ich stan jest ciągle wysoki (podciągnięte hardware'owo do Vcc). Pomocy proszę... :/

#include <avr/io.h>
#include <avr/interrupt.h>

/* define slave (MPU6050) address as 0x68 because AD0 is low */
#define SLAVE_ADDRESS (0x68)
#define WHO_AM_I (0x75)

volatile enum state
{
    IDLE,
    START_BIT_TRANSMIT,
    SLAVE_ADDRESS_TRANSMIT,
    DATA_TRANSMIT,
    ERROR
} sm;

void TimerInit()
{
    /* overflow interrupt enable and start timer on frequency 8MHz / 1024 */
    TIMSK |= (1 << TOIE0);
    TCCR0 |= (1 << CS00) | (1 << CS02);
}

void TwiInit()
{
    /* 100 kHz frequency of TWI module */
    TWBR = 32;

    /* enable TWI module without interrupt enable */
    TWCR = (1 << TWEN);
}

/* timer overflow interrupt service routine */
ISR(TIMER0_OVF_vect)
{

}

int main(void)
{
    /* diodes output */
    DDRB |= (1 << PB0);
    DDRD |= (1 << PD7);

    /* diodes turn off */
    PORTB |= (1 << PB0);
    PORTD |= (1 << PD7);

    /* pull up resistor on PD5 input switch */
    PORTD |= (1 << PD5);

    TimerInit();
    TwiInit();

    sei();

    while (1)
    {
        /* if switch pressed */
        if (!((PIND >> PD5) & 1))
        {
            if (sm == IDLE)
            {
                /* turn on the diode and request start TWI operation */
                PORTD &= ~(1 << PD7);
                sm = START_BIT_TRANSMIT;
                TWCR |= (1 << TWSTA) | (1 << TWINT);

                /* waiting for set TWINT - finish requested TWI operation */
                while (!(TWCR & (1 << TWINT)));

                PORTD |= (1 << PD7);

                /* request next TWI operation - send SLA+W */
                sm = SLAVE_ADDRESS_TRANSMIT;
                TWDR = (SLAVE_ADDRESS << 1);
                TWCR &= ~(1 << TWSTA);
                TWCR |= (1 << TWINT);

                /* waiting for set TWINT - finish requested TWI operation */
                while (!(TWCR & (1 << TWINT)));

                /* request next TWI operation - send data */
                sm = DATA_TRANSMIT;
                TWDR = WHO_AM_I;
                TWCR |= (1 << TWINT);

                /* waiting for set TWINT - finish requested TWI operation */
                while (!(TWCR & (1 << TWINT)));

                /* request next TWI operation - send stop bit */
                sm = IDLE;
                TWCR |= (1 << TWINT) | (1 << TWSTO);
            }
        }
    }
}
0

Zauważyłem teraz coś bardzo dziwnego. Po migracji na Atmege328 (poprzedni kod wykonywał się na Atmedze8) zauważyłem że po naciśnięciu przycisku, dioda się zapala i gaśnie.... uwaga - po około 3-5 sekundach... to jeszcze nic... najlepsze jest to że po około kolejnych kilku sekundach SDA idzie w dół po czym po ściśle nieokreślonym czasie wraca na high. Masakra. Chyba mam te procki upalone. Dziś jeszcze wybieram się do kolegi po zestaw arduino mega168 aby móc to wszystko jeszcze raz przetestować... A Was koledzy proszę o porady jakieś, może ktoś miał takie dziwne doświadczenia z modułem TWI...? Gorąco pozdrawiam!

0

Właśnie zrobiłem próby na Arduino Uno R3 z udziałem Atmega328 i wszystko gra. Ten sam kod działa zupełnie inaczej niż w czasie poprzednich testów, działa bez zarzutu, po kliknięciu przycisku na oscyloskopie mam ładne przebiegi potwierdzające wysyłanie po I2C.
Zamykam temat bo chyba nieświadomie uszkodziłem klocki, kurcze pieczone :/ ale ze mnie gapa, nawet nie wiem kiedy mogłem to zrobić ale widzicie - wszystko niby w nich działa ale nie działa TWI i to nie tak że w ogóle - wariuje na maxa, zachowuje się nieprzewidywalnie.
Pozdrawiam i dzięki za pomoc!

0

Tu dzieje się coś naprawdę wyjątkowego: mianowicie po zamianie procesora w podstawce w zestawie Arduino na ten niby upalony kod również działa poprawnie. Oznacza to że na płytce stykowej robiłem coś nie tak ale cholera wie co. Miałem przecież podciągnięte wszystko. Podejrzewam że filtrowanie miałem nie tak jak trzeba - zasilanie szło z przejściówki ATB USB RS232 natomiast koło procka miałem tylko 100nF i nic więcej. Nie chce mi się już tego dokładniej analizować co było przyczyną. Pozdrawiam!

1

Panowie dziękuję. Postanowiłem że tego questa tak nie zostawię jednak... i złożyłem wszystko ponownie na stykówce ale dodałem kondensator 33uF dodatkowo i o dziwo wszystko działa! Nie wiem jednak co było nie tak bo jak wyciągam tego 33uF to to tak samo - działa jak należy. Widocznie miałem jakiegoś bubla na stykówce którego nie dostrzegłem. Panowie sory. Najgorsze że nie jestem się w stanie teraz tego dowiedzieć bo poprzedni układ na stykówce został zastąpiony nowym (czyt. został zdemontowany). :) Dzięki Panowie za porady. Każdy z testowanych procków żyje i ma się dobrze! :)

0

Mój driver działa już jak należy i komunikuje się z czujnikiem MPU6050 (akcelerometr + żyroskop).
Przyspieszenia są odczytywane poprawnie ;)
Mam jedno pytanie do znawców tematyki takich czujników albo do osób które znają temat komunikacji od podstaw, jak to jest, jeśli taki czujnik załóżmy na przyspieszenie XOUT ma dwa rejestry jednobajtowe a ja je protokołem I2C muszę czytać jeden po drugim przecież to czy może wystąpić sytuacja że czytam sobie jeden rejestr a tu bach i czujnik zapisuje mi drugi inną wartością. Chodzi mi o to czy może wystąpić taka sytuacja że powiedzmy ja sobie chcę odczytać przyspieszenie x (czyli przeczytać dwa rejestry) i niech w nich będzie takie coś że w pierwszym 0x01 a w drugim 0xFF, czytam więc 0x01 a tu nagle przyspieszenie się zmieniło i to "o bardzo malutko" bo teraz wynosi załóżmy w pierwszym 0x02 i w drugim 0x00, więc odczytam drugi rejestr jako 0x00. Nietrudno się domyślić że popełniłem znaczny błąd bo około 255. Czy taka sytuacja może mieć miejsce, i co musiałbym zrobić aby jej uniknąć?

1

Bazować na mechanizmach danego czujnika. Z zasady posiadają one albo mechanizmy synchronizacyjne np. ustawianie flag zatrzaskujących pomiar, wypełnianie buforów FIFO poprawnymi danymi, rejestr-cień który zapisywany jest stale i propagowany do rejestru odczytywanego w całości.
W przypadku MPU masz....

The accelerometer measurement registers, along with the temperature measurement registers,
gyroscope measurement registers, and external sensor data registers, are composed of two sets of
registers: an internal register set and a user-facing read register set.
The data within the accelerometer sensors’ internal register set is always updated at the Sample
Rate. Meanwhile, the user-facing read register set duplicates the internal register set’s data values
whenever the serial interface is idle. This guarantees that a burst read of sensor registers will read
measurements from the same sampling instant. Note that if burst reads are not used, the user is
responsible for ensuring a set of single byte reads correspond to a single sampling instant by
checking the Data Ready interrupt.

0

Słuchajcie może to głupio brzmieć ale nie potrafię sobie tego dokładnie przetłumaczyć. Szczególnie tego:

Meanwhile, the user-facing read register set duplicates the internal register set’s data values
whenever the serial interface is idle. This guarantees that a burst read of sensor registers will read
measurements from the same sampling instant. Note that if burst reads are not used, the user is
responsible for ensuring a set of single byte reads correspond to a single sampling instant by
checking the Data Ready interrupt.

Czy ktoś mógłby pomóc mi rozszyfrować ten tekst bo z pomocą tłumaczy internetowych nie bardzo mi się to powiodło...
I czy np. gdy będę odczytywał przez I2C nie po jednym bajcie czyli tak:

START SLA+W ACK REG_ADDR ACK START SLA+R ACK DATA NACK STOP (dotyczy pierwszego bajtu)
START SLA+W ACK REG_ADDR ACK START SLA+R ACK DATA NACK STOP (dotyczy drugiego bajtu)

tylko tak:

START SLA+W ACK REG_ADDR ACK START SLA+R ACK DATA ACK DATA NACK STOP (odczyt dotyczy obydwu naraz)

to czy wówczas nie będzie ryzyka tego że nie odczyta mi się to w całości z jednej próbki (sample) , dobrze to rozumiem Panowie?
Pogrubione to to co wysyła mikrokontroler (master), niepogrubionym to co wysyła slave (czyli czujnik).

0

Wydaje mi się, że dobrze to rozumiesz ;-)

0

Ale czy to znaczy że jeśli będę czytał pojedynczo bajty czyli tak:

START SLA+W ACK REG_ADDR ACK START SLA+R ACK DATA NACK STOP (dotyczy pierwszego bajtu)
START SLA+W ACK REG_ADDR ACK START SLA+R ACK DATA NACK STOP (dotyczy drugiego bajtu)

To czy wówczas jest ryzyko że mi się pierwszy odczyta z pierwszej próbki pomiarowej, a drugi z innej ?
Będzie ktoś łaskaw przetłumaczyć dokładniej fragment:

Meanwhile, the user-facing read register set duplicates the internal register set’s data values
whenever the serial interface is idle. This guarantees that a burst read of sensor registers will read
measurements from the same sampling instant. Note that if burst reads are not used, the user is
responsible for ensuring a set of single byte reads correspond to a single sampling instant by
checking the Data Ready interrupt.

Bardzo mi zależy, proszę o pomoc.

1

Tak w tym przypadku jest takie ryzyko, o ile czas pomiędzy odczytami kolejnych bajtów będzie wystarczający, aby sensor uznał, że magistrala jest w stanie bezczynności (Idle).

Zwróć uwagę na ten fragment:

set’s data values whenever the serial interface is idle. This guarantees that a burst read of sensor registers will read measurements from the same sampling instant.

Gwarancję, że dane pochodzą z tego samego pomiaru daje tylko i wyłącznie odczyt w trybie burst.

0

Właśnie rozwiałeś moje wątpliwości kolego i za to Ci dziękuję. Musiałem zdobyć taką pewność gdyż buduję alarm motocyklowy oparty o układ mikrokontroler avr 8bit + mpu6050. Przy zazbrojeniu alarmu układ zapamięta stan przyspieszeń a ich odchyłka od tych zapamiętanych wartości o epsilon będzie alarm wyzwalała, dlatego tak istotne jest abym miał pewność że dane jednego i drugiego rejestru będą pochodzić z tej samej próbki pomiarowej.
Ciekaw jestem czy dotyczy to tylko dwóch rejestrów czy np. wszystkich sześciu (bo ja w trybie burst raczej będę odczytywał wszystkie sześć naraz czyli przyspieszenie w osi X, Y i Z). Czy ktoś może napisać jeszcze jakieś informacje?

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.