eGospodarka.pl
eGospodarka.pl poleca

eGospodarka.plGrupypl.misc.elektronika › I2C/TWI - poddaję się...
Ilość wypowiedzi w tym wątku: 2

  • 1. Data: 2016-07-03 21:46:11
    Temat: I2C/TWI - poddaję się...
    Od: badworm <n...@p...pl>

    Czołem!

    Wracam do tematu, który tu poruszałem na początku kwietnia, a mianowicie
    komunikacji pomiędzy AVRem (Mega 8, docelowo Mega 324) a wyświetlaczem
    OLED z kontrolerem SSD1308. O ile komunikacja po I2C zrealizowanym
    programowo działa prawidłowo, choć z niewiadomych przyczyn po
    skompilowaniu programu nowszą wersją GCC prędkość transmisji spada
    kilkunastokrotnie (częstotliwość zegara na SCL obniża się z 80kHz do
    zaledwie 5kHz), o tyle z komunikacją za pośrednictwem sprzętowego I2C
    jest jakiś grubszy problem. Kod wysyłający dane na sprzętowe I2C sam w
    sobie jest dobry. Prosty program, wysyłający dane do układu PCF8574
    (ekspander portu I2C) działa aż miło, w przebiegach praktycznie nie
    widać różnicy czy to programowe czy sprzętowe I2C. Podmiana procedur
    obsługi I2C w docelowym kodzie z obsługą OLED kończy się porażką. Sam
    program jako całość żyje, bo diodka podpięta pod PB3 i taktowana
    przerwaniem timera mruga prawidłowo. Jeśli wyświetlacz jest już
    podłączony w momencie załączania zasilania, to efekt jest taki, że coś
    idzie nie tak w programie, bo nie pojawia się stan wysoki na PB0, mający
    za zadanie potrzymywać pracę stabilizatora zasilającego cały układ.
    Muszę więc cały czas trzymać wciśnięty przycisk "power on", podczas gdy
    normalnie wystarcza naciśnięcie go na chwilę a potem jego rolę przejmuje
    właśnie PB0. Jeśli natomiast spróbuję podłączyć moduł z wyświetlaczem do
    pracującego już procesora, to z tego co pokazuje oscyloskop, momentalnie
    na pysk leci sygnał na SCL.

    Jakieś pomysły co z tym fantem zrobić? :(

    Przebieg I2C sprzętowego dla PCF8574:
    http://transport.prohost.pl/kolejowy/pliki/tek00031.
    png

    Przebieg dla I2C programowego dla PCF8574:
    http://transport.prohost.pl/kolejowy/pliki/tek00029.
    png

    Przebieg dla I2C programowego dla OLED:
    http://transport.prohost.pl/kolejowy/pliki/tek00026.
    png

    Przebieg dla I2C sprzętowego dla OLED ale bez podłączonego wyświetlacza:
    http://transport.prohost.pl/kolejowy/pliki/tek00019.
    png

    Najśmieszniejsze w tym wszystkim jest to, że to właśnie SSD1308
    oficjalnie obsługuje I2C, a Atmel tę magistralę nazywa (ze względów
    licencyjnych) TWI, więc prędzej możnaby się spodziewać odstępstw od
    wzorcowego I2C ze strony procka niż kontrolera w wyświetlaczu...

    Funkcje obsługujące I2C sprzętowe:
    //TEST I2C SPRZĘTOWEGO

    void twiinit(void)
    {
    //set SCL to 400kHz
    TWSR = 0x00;
    TWBR = 0x0C;
    //enable TWI
    TWCR = (1<<TWEN);
    }



    void twistart(void)
    {
    TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
    while ((TWCR & (1<<TWINT)) == 0);
    }


    void twistop(void)
    {
    TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
    }

    void twiwrite(uint8_t u8data)
    {
    TWDR = u8data;
    TWCR = (1<<TWINT)|(1<<TWEN);
    while ((TWCR & (1<<TWINT)) == 0);
    }

    Funkcje obsługi I2C programowego:

    // Wyliczenie czasu opóźnienia połówkowego i ćwiartkowego (cykle)
    #define I2C_nhalf (F_CPU/I2C_SPEED/2)

    // Funkcja dłuższych opóźnień
    #if I2C_nhalf < 3
    // Nic
    #elif I2C_nhalf < 8
    static void i2c_xdelay(void)
    {
    NOP();
    }
    #else
    #define I2C_delayloops (1+(I2C_nhalf-8)/3)
    #if I2C_delayloops > 255
    #error Przyspiesz - bo sie nie wyrabiam ;)
    #endif
    static void i2c_xdelay(void)
    {
    asm volatile( \
    "delayus8_loop%=: \n\t"\
    "dec %[ticks] \n\t"\
    "brne delayus8_loop%= \n\t"\
    : :[ticks]"r"(I2C_delayloops) );
    }
    #endif //I2C_nhalf >= 3

    // Opóźnienia dla I2C
    static inline void i2c_hdelay(void)
    {
    #if I2C_nhalf < 1
    return; // To jest funkcja inline, jeśli składa się tylko z "return"
    jest usuwana podczas optymalizacji
    #elif I2C_nhalf < 2
    NOP();
    #elif I2C_nhalf < 3
    asm volatile(
    "rjmp exit%=\n\t"
    "exit%=:\n\t"::);
    #else
    i2c_xdelay();
    #endif
    }

    // Ustawienie i zerowanie wyjścia
    static inline void i2c_sdaset(void)
    {
    DDR(I2C_PORT) &= ~(1<<I2C_SDA);
    PORT(I2C_PORT) |= 1<<I2C_SDA;
    }
    static inline void i2c_sdaclear(void)
    {
    PORT(I2C_PORT) &= ~(1<<I2C_SDA);
    DDR(I2C_PORT) |= 1<<I2C_SDA;
    }
    // Pobieranie danej z wyprowadzenia portu
    // Zwraca: bajt będący odpowiednikiem fizycznego stanu portu, z
    wyzerowanaymi wszystkimi bitami poza sda
    static inline uint8_t i2c_sdaget(void)
    {
    return PIN(I2C_PORT) & (1<<I2C_SDA);
    }

    // Zerowanie i ustawianie zegara
    static inline void i2c_sclset(void)
    {
    PORT(I2C_PORT) |= 1<<I2C_SCL;
    }
    static inline void i2c_sclclear(void)
    {
    PORT(I2C_PORT) &= ~(1<<I2C_SCL);
    }

    // Warunek startu
    void i2c_start(void)
    {

    // Konieczne jeśli chcę użyć start bez stop
    i2c_sdaset();
    i2c_hdelay();
    i2c_sclset();
    i2c_hdelay();
    // Normalna sekwencja startu
    i2c_sdaclear();
    i2c_hdelay();
    i2c_sclclear();


    //TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
    //while (!(TWCR & (1<<TWINT)));


    }

    // Warunek stop
    void i2c_stop(void)
    {

    i2c_sdaclear();
    i2c_hdelay();
    i2c_sclset();
    i2c_hdelay();
    i2c_sdaset();
    i2c_hdelay();


    //TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
    //while ((TWCR & (1<<TWSTO)));

    }

    // Transmisja bajtu
    // Zwraca: 0 jeśli było ack, wartość 1<<I2C_SDA jeśli nie było ACK
    uint8_t i2c_send(uint8_t data)
    {

    uint8_t n;

    for(n=8; n>0; --n)
    {
    if(data & 0x80)
    i2c_sdaset();
    else
    i2c_sdaclear();
    data <<= 1;
    i2c_hdelay();
    i2c_sclset();
    i2c_hdelay();
    i2c_sclclear();
    }
    // ack
    i2c_sdaset();
    i2c_hdelay();
    i2c_sclset();
    i2c_hdelay();
    n = i2c_sdaget();
    i2c_sclclear();

    return n;

    }

    // Pobranie bajtu
    uint8_t i2c_get(uint8_t ack)
    {

    uint8_t n, temp=0;

    i2c_sdaset();
    for(n=8; n>0; --n)
    {
    i2c_hdelay();
    i2c_sclset();
    i2c_hdelay();
    temp<<=1;
    if(i2c_sdaget())
    temp++;
    i2c_sclclear();
    }
    // ack
    if(ack == I2C_ACK)
    i2c_sdaclear();
    else
    i2c_sdaset();
    i2c_hdelay();
    i2c_sclset();
    i2c_hdelay();
    i2c_sclclear();

    return temp;



    }
    --
    Pozdrawiam Bad Worm badworm[maupa]post{kropek}pl
    GG#2400455 ICQ#320399066


  • 2. Data: 2016-07-03 22:08:07
    Temat: Re: I2C/TWI - poddaję się...
    Od: janusz_k <J...@o...pl>

    W dniu 2016-07-03 o 21:46, badworm pisze:
    > Czołem!
    >
    > Wracam do tematu, który tu poruszałem na początku kwietnia, a mianowicie
    > komunikacji pomiędzy AVRem (Mega 8, docelowo Mega 324) a wyświetlaczem
    > OLED z kontrolerem SSD1308. O ile komunikacja po I2C zrealizowanym
    > programowo działa prawidłowo, choć z niewiadomych przyczyn po
    > skompilowaniu programu nowszą wersją GCC prędkość transmisji spada
    > kilkunastokrotnie (częstotliwość zegara na SCL obniża się z 80kHz do
    > zaledwie 5kHz), o tyle z komunikacją za pośrednictwem sprzętowego I2C
    > jest jakiś grubszy problem. Kod wysyłający dane na sprzętowe I2C sam w
    > sobie jest dobry. Prosty program, wysyłający dane do układu PCF8574
    > (ekspander portu I2C) działa aż miło, w przebiegach praktycznie nie
    > widać różnicy czy to programowe czy sprzętowe I2C. Podmiana procedur
    > obsługi I2C w docelowym kodzie z obsługą OLED kończy się porażką. Sam
    > program jako całość żyje, bo diodka podpięta pod PB3 i taktowana
    > przerwaniem timera mruga prawidłowo. Jeśli wyświetlacz jest już
    > podłączony w momencie załączania zasilania, to efekt jest taki, że coś
    > idzie nie tak w programie, bo nie pojawia się stan wysoki na PB0, mający
    > za zadanie potrzymywać pracę stabilizatora zasilającego cały układ.
    > Muszę więc cały czas trzymać wciśnięty przycisk "power on", podczas gdy
    > normalnie wystarcza naciśnięcie go na chwilę a potem jego rolę przejmuje
    > właśnie PB0. Jeśli natomiast spróbuję podłączyć moduł z wyświetlaczem do
    > pracującego już procesora, to z tego co pokazuje oscyloskop, momentalnie
    > na pysk leci sygnał na SCL.
    >
    > Jakieś pomysły co z tym fantem zrobić? :(
    >
    > Przebieg I2C sprzętowego dla PCF8574:
    > http://transport.prohost.pl/kolejowy/pliki/tek00031.
    png
    >
    > Przebieg dla I2C programowego dla PCF8574:
    > http://transport.prohost.pl/kolejowy/pliki/tek00029.
    png

    Nie wiem czy zauważyłeś ale sprzętowo masz 200khz
    a programowo 83khz, sam tek ci to na dole pokazuje
    zmniejsz prędkość sprzętowego twi i powinno być dobrze.


    --
    Pozdr

    Janusz_K

strony : [ 1 ]


Szukaj w grupach

Szukaj w grupach

Eksperci egospodarka.pl

1 1 1

Wpisz nazwę miasta, dla którego chcesz znaleźć jednostkę ZUS.

Wzory dokumentów

Bezpłatne wzory dokumentów i formularzy.
Wyszukaj i pobierz za darmo: