eGospodarka.pl
eGospodarka.pl poleca

eGospodarka.plGrupypl.misc.elektronikaI2C/TWI - poddaję się... › I2C/TWI - poddaję się...
  • Path: news-archive.icm.edu.pl!news.icm.edu.pl!newsfeed2.atman.pl!newsfeed.atman.pl!.P
    OSTED!not-for-mail
    From: badworm <n...@p...pl>
    Newsgroups: pl.misc.elektronika
    Subject: I2C/TWI - poddaję się...
    Date: Sun, 3 Jul 2016 21:46:11 +0200
    Organization: ATMAN - ATM S.A.
    Lines: 255
    Message-ID: <b106c354jpaq$.dlg@badworm.pl>
    NNTP-Posting-Host: ip-5-172-247-238.free.aero2.net.pl
    Mime-Version: 1.0
    Content-Type: text/plain; charset="iso-8859-2"
    Content-Transfer-Encoding: 8bit
    X-Trace: node2.news.atman.pl 1467575174 12592 5.172.247.238 (3 Jul 2016 19:46:14 GMT)
    X-Complaints-To: u...@a...pl
    NNTP-Posting-Date: Sun, 3 Jul 2016 19:46:14 +0000 (UTC)
    User-Agent: 40tude_Dialog/2.0.15.1pl Hamster/2.0.0.1
    Xref: news-archive.icm.edu.pl pl.misc.elektronika:702287
    [ ukryj nagłówki ]

    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

Podziel się

Poleć ten post znajomemu poleć

Wydrukuj ten post drukuj


Następne wpisy z tego wątku

Najnowsze wątki z tej grupy


Najnowsze wątki

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: