- 3D-Druck Einstieg und Tipps         
Seite 3 von 4 ErsteErste 1234 LetzteLetzte
Ergebnis 21 bis 30 von 34

Thema: SRF02. Wie ohne Timer Messwert-Abfrage steuern

  1. #21
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.899
    Anzeige

    Praxistest und DIY Projekte
    Zitat Zitat von oberallgeier Beitrag anzeigen
    MUSS ich - und wenn ja, WARUM, beim I²C-Master zu Beginn einer I²C-Übertragung den Returnwert auswerten? ICH (also mein Controller) sendet. Als Master. Da hat doch niemand den Bus lahmzulegen und ich müsste die früheren Aktionen ordnungsgemäß abgeschlossen haben.
    Der Beginn einer I2C-Übertragung ist das Herstellen einer Start-Kondition. Nun ist es aber so, daß die Funktion i2c_start() wesentlich mehr macht. Sie ist schon der erste Teil der Übertragung, denn sie sie sendet auch noch das Adressbyte. Daß man das in einer Funktion zusammengefaßt ist, hat der Programmierer dieser Funktion zu verantworten. Ich würde das nicht so machen, sondern daraus zwei Funktionen bauen, auch einer der Gründe das selbst zu machen.

    Und jetzt zu dieser Funktion selbst. Als erstes setzt sie das TWISTA-Bit (sorry, wenn ich die Bitnamen mal etwas falsch schreibe, ich müßt sonst jedesmal nachschlagen). der TWI-Controler macht dann laut Datenblatt folgendes: er wartet, bis der Bus idle wird, und setzt dann Start. Da macht sogar schon die Hardware einen Check. Geht dabei etwas schief, meldet die Funktion i2c_start() einen Fehler. Dann sendet die Funktion die Adresse, wird sie nicht mit ACK quitiert, meldet die Funktion den gleichen Fehler (schlecht). Antwortet ein Slave nicht auf seine Adresse mit ACK, muß die Transaktion mit einem Stop abgebrochen werden!. Also muß der Returnwert ausgewertet werden. Dies erstmal zum Speziellen.

    Ausnahme ist Mister Murphy-Law, der schon mal, wie sein Kollege Wackel-Kontakt und andere, dreinpfuschen kann. Aber normalerweise sollte doch der I²C-Bus zu Beginn der Übertragung nicht besetzt sein - ist ja kein Multimaster
    Oder das Device ist Busy, das EEPROM schreibt gerade, ein US-Sensor misst, dein selbstgemachter Slave ist noch nicht hochgelaufen oder, oder ...

    Beim anschließenden Schreiben oder Lesen wird/kann das sinnvoll sein. Aber auch da überlege ich noch.

    Nicht dass es mir auf die paar zusätzlichen Maschinenbefehle für das "if" ankäme. Ich finde nur überflüssige Befehle sind ebenso unschönes Programmieren wie falsche.
    Es ist also eher umgekehrt, beim Verbindungsauf ist es Pflicht. Aber, wenn ich bei einer Datenübertragung nun schon eine minimale Rückmeldung bekomme, sollte man sie auch verwenden. Das ist jetzt das Inhaltliche.

    Prinzipiell gilt aber:
    Errorcodes sind dazu da, ausgewertet zu werden! Ein Code, der das nicht macht, fällt durch jedes Audit. Und ja, es führt dazu daß Fehlerbehandlung manchmal den größten Teil des Codes ausmacht. Und eigentlich sollte eine Library wie z.B. die I2C Library, die von fremden Programmieren verwendet wird, jeden Übergabeparameter auf gültige Werte überprüfe, und im Fall ungültiger Werte mit einem Fehlercode zurückkehren. Schau dir mal einige Funktionen der libc oder andere professionelle Libraries an, da ist die Beschreibung der Errorcodes häufig länger als die Funtionsbeschreibung.

    Zitat Zitat von RoboHolIC Beitrag anzeigen
    Weil dir eventuell seit dem letzten PowerUp ein EMP-Puls auf dem I2C-Bus den Slave aus dem Tritt gebracht hat und dieser Slave vielleicht keinen Reseteingang besitzt, über den du ihn programmtechnisch wieder zur Ordnung rufen könntest.
    Du kannst die Abfrage auch weglassen und stattdessen den Controller regelmässig vorbeugend eine I2C-Zauberformel sprechen lassen. Das ist irgendwas wie "mindestens 8x einen H-L-Wechsel auf der Clockleitung, während die Datenleitung H-Pegel hat".
    Das ist eher "unschlau". Dazu müßte man erstmal die I2C Hardware abschalten. Und dann dauert die Sequenz natürlich viel länger, als den Controler auf idle prüfen zu lassen, und einfach den Status auszulesen.
    Und es ist mitnichten eine "Zauberformel" sondern leicht zu erklären. Wenn der Slave mit Read adressiert worden ist, wartet er auf 8 Clocks um Datenbits zu liefern und ein neuntes mit dem ACK. Führt der Host diese Sequenz nicht vollständig durch (Absturz, Reset o.ä.), hängt der Slave (es gibt kein Timeout bei I2C). Das Toggeln von SCL führt das zuende und das High auf SDA ist ein NAK. Das bricht dann die Übertragung ab.

    Konkretes Beispiel gefällig?
    Mein aktuelles Projekt mit I2C-Bus hängt nach dem Flashen häufig.
    Ein einziger Controller als Master und ein einziger Gesprächspartner, der nur Slavemodus kann; alles ganz elementar und minimal.
    Mein eigener, ursprünglicher Ansatz, den Bus in einen geordneten Zustand zu bringen war, zu Beginn jedes Datenaustauschs das I2C-Modul des Controllers zu deaktivieren, wieder zu aktivieren und dann einen I2C-Startzustand auf den Bus zu bringen.
    Nette Idee, hilft aber leider nicht. Ein PowerUp dagegen hilft immer.
    Das passiert nicht nur beim Flashen sondern auch beim Debuggen. Single Step oder Breakpoint, Register anschauen .. noch mal von vorne, Peng!
    Und genau hier kommt die Resetsequenz ins Spiel. Wenn beim Init nach Reset der Bus nicht idle ist, schick die 8 Clocks. Ich mache das, bevor ich überhaupt die I2C Hardware anschmeiße. SDA und SCL als Input und auf High abfragen. Wenn nicht, SCL als Output und toggeln. Dann wieder Input. Wenn sie dann nicht high sind, Errorcode ausgeben und Halt (embedded Bluescreen).

    MfG Klebwax
    Strom fließt auch durch krumme Drähte !

  2. #22
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Hallo große Runde.


    Zitat Zitat von schorsch_76 Beitrag anzeigen
    Hier
    TWCR = (1<<TWSTO)|(1<<TWINT) | (1<<TWEN)|(1<<TWIE);
    TWCR = (1<<TWSTA) |(1<<TWINT) | (1<<TWEN)|(1<<TWIE);

    muss man eigentlich warten bis das STO wieder zurück esetzt wurde (siehe Tabelle in DS).

    Seite 229 Atmega328 Doku: Table 21-2. Status codes for Master Transmitter Mode
    bzw. Table 21-3 für Master Receive.

    Man kann auch STO und STA gleichzeitig setzen. Siehe die genannten Tabellen.
    Hallo schorsch_76,

    ja, die beiden Tabellen kenne ich. (Gleiches gilt auch für die Slave-Seite.)
    In den Master-Tabellen kann ich nicht erkennen, dass dort etwas dazu geschrieben wird, wie eben die Beendigung vom STOP anhand der Status-Codes aus dem TWSR-Register abzulesen ist. Ich hatte ja schon auf das 'Schaubild' "Interfacing the Application to the TWI in a Typical Transmission" hingewiesen bei dem eben auch keine Aktion nach dem STOP beschrieben ist.

    Und auch TWSTO und TWSTA gleichzeitig zu setzen ist mir bekannt um eben ein REP-START zu erzeugen.
    Das ist hier aber bewusst nicht angesprochen, da es ja um das Timing zwischen STOP und START geht.


    Aber nun kommt dein 'eigentlich' in's Spiel, denn genau um diese Spitzfindigkeit geht es mir.
    Wie kann ich erkennen, dass das TWSTO-Bit zurückgesetzt wurde? (Eher der Mut, dies zu fragen, den ich nun durch dein 'eigentlich' bekommen habe!)

    Wenn man nun zum Kapitel "TWCR - TWI Control Register" (bei mir auf Seite 235 im Kapielt 22.9.2) geht, und (nochmal, nochmal, nochmal, AHHH, endlich hab ich's nun auch gefunden) dort zum Bit TWSTO kommt, dann ist klar geschrieben was zu tun ist:

    • Bit 4 – TWSTO: TWI STOP Condition Bit
    Writing the TWSTO bit to one in Master mode will generate a STOP condition on the 2-wire Serial Bus. When the
    STOP condition is executed on the bus, the TWSTO bit is cleared automatically
    . In Slave mode, setting the
    TWSTO bit can be used to recover from an error condition. This will not generate a STOP condition, but the TWI
    returns to a well-defined unaddressed Slave mode and releases the SCL and SDA lines to a high impedance state.


    Also bleibt tatsächlich folgendes zu tun:
    TWCR = (1<<TWSTO)|(1<<TWINT) | (1<<TWEN)|(1<<TWIE);
    while (TWCR & (1<<TWSTO) /* oder while ( ! (TWCR & (1<<TWSTO)) da müsste ich jetzt echt nachdenken */
    ;
    TWCR = (1<<TWSTA) |(1<<TWINT) | (1<<TWEN)|(1<<TWIE);

    Und so ist auch das unbedingt verpönte 'Panzerband' von Klebwax endlich beseitigt und es ist kein wait()-Statement mit geratener Zeitangabe notwendig.

    Gruß an alle, ich werde das mal nächste/übernächste Woche mit "Dauerfeuer" testen. Klar, mit und ohne while().

    Gruß Sternthaler


    @Klebwax
    Tut mir Leid, wenn ich an dich nur Fragen habe.
    Womit debug'st du?
    Ich habe für meine xx4'er megas das JTAGICE3 und bin ganz zufrieden mit dem Teil. Steuernder Client ist natürlich das Atmel Studio 6.1
    Unwissenheit besteht bei mir in der Nutzung von externen simulierten Signalen. Ansonsten komme ich bis in ISR-Funktionen und kann dort auch meine Fehler suchen.

    - - - Aktualisiert - - -

    By the way.
    Ich habe gerade eine weitere Version vom 'Sammel'-Handbuch zu den ATmega48A bis ATmega328P 'entdeckt'.
    Meine letzte Version war 8271E-AVR-07/2012 mit popeligen 555 PDF-Seiten
    Es gibt mittlerweile 8271G-AVR-02/2013 aufgebläht auf 660 PDF-Seiten
    Hier zu finden: www.atmel.com/images/atmel-8271-8-bit-avr-microcontroller-atmega48a-48pa-88a-88pa-168a-168pa-328-328p_datasheet.pdf
    Geändert von Sternthaler (02.10.2014 um 22:14 Uhr) Grund: Frage zum Debugger
    Lieber Asuro programieren als arbeiten gehen.

  3. #23
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.693
    Oh Leute, da komme ich vor lauter andächtigem Lesen garnicht nach mit dem Dazulernen! Bitte macht weiter, so kann man (kann ich) das I²C-Thema mal lernen ... und noch ein bisschen C dazu.

    ... Errorcodes sind dazu da, ausgewertet zu werden! ... Fehlerbehandlung manchmal den größten Teil des Codes ausmacht ...
    Wie war das noch? Es kann nur die Anwesenheit, nicht aber die Abwesenheit von Fehlern sicher festgestellt werden. Und das schlägt auch hier mit voller Wucht zu. (Und hat seine Konsequenzen). Ansonsten muss ich sagen - können tu ich I²C noch nicht besser, aber ich lerne grad sehr viel dazu. Und in so einer tiefschürfenden Runde macht das Lernen viel mehr Spass als das Datenblatt so vor sich hinzulesen.

    Klasse macht ihrs!

    Sternthaler, danke für den Link zum 8271G; mein letztes ist das 8271E. Nun ist das Dutzend Datenblätter der 48-168-328-Familie voll.
    Geändert von oberallgeier (02.10.2014 um 23:49 Uhr) Grund: Datenblatt
    Ciao sagt der JoeamBerg

  4. #24
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.899
    Zitat Zitat von Sternthaler Beitrag anzeigen
    @Klebwax
    Tut mir Leid, wenn ich an dich nur Fragen habe.
    Womit debug'st du?
    Ich schrub (oder heißt das schriebte ), daß ich mit PICs rummache. Da gibt es den PICkit 3 und für kleineres Geld Clones. Damit kann man Programmieren und Debuggen. Fast so, wie man es auf dem PC gewöhnt ist. Je nach Chip einen oder mehrere HW-Breakpoints setzen, Variablen ansehen und ändern, Watchwindows etc. Bei den teureren Debuggern gibts wohl auch einen Trace, bin mir da aber nicht sicher. Das bedeutet zwar, daß man zwei Pins und den MRST dafür freihalten muß, das nehme ich aber in Kauf.

    "externe simulierte Signale" verstehe ich nicht. Externe Signale sind da, nicht simuliert.

    MfG Klebwax
    Strom fließt auch durch krumme Drähte !

  5. #25
    Erfahrener Benutzer Roboter-Spezialist Avatar von schorsch_76
    Registriert seit
    25.03.2012
    Ort
    Kurz vor Neuschwanstein
    Alter
    48
    Beiträge
    456
    @Sternthaler:
    Das mit dem TWI Stop hab ich so implementiert:

    Code:
    385 void
    386 i2c::wait_for_twi_stopped() const
    387 {
    388     // make sure stop was already sent
    389     while(TWCR & (1<<TWSTO));
    390 }

    Die sende/lese Routine stellt sicher, dass der Bus frei ist wenn ich was machen will.
    Code:
    449 void
    450 i2c::write_to_slave(unsigned char address, const char* data, unsigned char len)
    451 {
    452     // when the I2C is busy, we need to wait
    453     while (is_busy())  _delay_ms(1);
    454 
    455     // make sure stop was already sent
    456     wait_for_twi_stopped();
    457 
    458     // set the mode and prevent others from interfering with the registers
    459     // the irq routine will clear it again to idle
    460     m_mode = master_transmit;
    Code:
    475 void
    476 i2c::read_from_slave(unsigned char address, const char* data, unsigned char tx_len, unsigned char rx_len)
    477 {
    478     // when the I2C is busy, we need to wait
    479     while (is_busy())  _delay_ms(1);
    480 
    481     // make sure stop was already sent
    482     wait_for_twi_stopped();
    483 
    484     // set the mode and prevent others from interfering with the registers
    485     // the irq routine will clear it again to idle
    486     m_mode = master_receive;
    is_budy ist nur eine Abfrage auf meie interne I2C Statemachine
    Code:
    529 bool
    530 i2c::is_busy() const
    531 {
    532     return m_mode != idle;
    533 }
    Da das ganze in C++ und in einer Klasse implementiert ist (alle Hilfsfunktionen private), kann ich so sicherstellen, das wirklich die Reihenfolge eingehalten wird und das Interface anch aussen sehr simpel ist.

    Code:
     8 class I2C
     9 {
    10 public:
    11     enum error_code_t
    12     {
    13         no_error = 0,
    14 
    15         tx_no_answer_tw_start,
    16         tx_no_answer_tw_mt_sla_ack,
    17         tx_no_answer_tw_mt_data_ack,
    18 
    19         rx_no_answer_tw_start,
    20         rx_no_answer_sla_mt_or_sla_mr_ack,
    21         rx_no_answer_tw_mt_data_ack,
    22         rx_no_answer_tw_rep_start,
    23         rx_no_answer_tw_mr_sla_ack,
    24         rx_no_answer_tw_mr_data_ack,
    25     };
    26 
    27     i2c();
    28     void init();
    29 
    30     // handle the IRQs
    31     void handle_irq();
    32 
    33     // read/write something from/to a slave
    34     void
    35     write_to_slave(unsigned char address, const char* data, unsigned char len);
    36     void
    37     read_from_slave(unsigned char address, const char* data, unsigned char tx_len, unsigned char rx_len);
    38 
    39     // status information
    40     unsigned char rx_size() const;
    41     unsigned char tx_size() const;
    42     error_code_t is_error() const;
    43     bool is_busy() const;
    44 
    45     // get received data
    46     i2c& operator >> (char& data);
    47 private:
    Bei interesse kann ich den Code gerne ganz hochladen.

  6. #26
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.693
    Zitat Zitat von schorsch_76 Beitrag anzeigen
    ... Das mit dem TWI Stop hab ich so implementiert: ... Bei interesse kann ich den Code gerne ganz hochladen.
    Bitte hochladen! Hier ist ja ein informatives Stück I²C-Wissen aus den Tiefen der Busaktivitäten zusammengetragen, da wäre so eine Ergänzung sicher sinnvoll. Ich habe auch gerade eben den Moderator gebeten, den Titel um "I²C" zu ergänzen, damit der Thread bei allfälligen Suchen nach "I²C" nicht in den Tiefen des Servers verstaubt. Bei 25 Klicks pro Antwort sicher nicht unbegründet.
    Geändert von oberallgeier (03.10.2014 um 09:22 Uhr) Grund: 25 statt 30 Klicks. Kopfrechnen ungenügend
    Ciao sagt der JoeamBerg

  7. #27
    Erfahrener Benutzer Roboter-Spezialist Avatar von schorsch_76
    Registriert seit
    25.03.2012
    Ort
    Kurz vor Neuschwanstein
    Alter
    48
    Beiträge
    456
    fifo.h
    i2c.h
    i.c

    Seltsamerweise läst mich das Forum keine cpp Dateien hochladen. Es benennt auch meine i2c.c Datei nach i.c um...

    Die Funktion handle_irq() wird aus dem IRQ Handler aufgerufen. Ganz unten in "i.c" bzw. i2c.cpp.

    Mein Makefile sieht so aus:

    Code:
    ############################################################
    # Projekteinstellungen
    ############################################################
    
    # MCU
    MCU=atmega328p
    F_CPU=16000000
    LFUSE=0xde
    HFUSE=0xd7
    EFUSE=0x01
    
    # Die Sources
    SOURCES =   util.cpp eeprom.cpp i2c.cpp  \
                menu.cpp main.cpp  \
                            timer1.cpp scheduler.cpp \
                            rtc.cpp display.cpp adc.cpp relay.cpp storage.cpp r-to-t.cpp \
                            core.cpp
    
    # temporary deactivated                 parser.cpp rs232.cpp
    # Die Zieldateien
    ELF = heat.elf
    HEX = heat.hex
    MAP = heat.map
    
    ############################################################
    # Compiler Flags. Muss vermutlich nicht angepasst werden
    ############################################################
    CFLAGS=-g -DF_CPU=$(F_CPU) -Wall -Os --std=c++11 -mcall-prologues
    LFLAGS=-lprintf_flt
    ############################################################
    # Die Toolchain. Muss vermutlich nicht angepasst werden
    # Die AVRDUDE Zeile muss an den Programmer und
    # die Ziel CPU angepasst werden
    ############################################################
    AVRDUDE=avrdude -p m328p -c avrispmkii -P USB
    
    CC=avr-g++
    RM=rm -f
    OBJCOPY=avr-objcopy
    AVRSIZE=avr-size
    OBJDUMP=avr-objdump
    
    ############################################################
    # Ab hier muss nichts mehr angepasst werden
    ############################################################
    # OBJ = Sources mit ersetzter Dateiendung
    OBJ=$(SOURCES:%.cpp=%.o)
    
    all: hex
    
    hex: elf
            $(OBJCOPY) -R .eeprom -O ihex $(ELF) $(HEX)
    
    elf: $(OBJ)
            $(CC) -mmcu=$(MCU) $(CFLAGS) $(LFLAGS) -o $(ELF) -Wl,-Map,$(MAP) -Wl,-u,vfprintf $(OBJ)
    
    %.o: %.cpp
            $(CC) -mmcu=$(MCU) $(CFLAGS) -c $<
    
    .phony: flash
    flash: hex
            $(AVRDUDE) -e -U flash:w:$(HEX)
    
    # Ziele ohne Abhängigkeiten
    clean:
            $(RM) $(OBJ) $(ELF) $(HEX) $(MAP)
    
    readfuse:
            $(AVRDUDE) lfuse:r:-:i -v
    
    writefuse:
            $(AVRDUDE) -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
    
    size:   $(ELF)
            $(AVRSIZE) -B $(ELF)
    
    dump:
            $(OBJDUMP) -d -S --demangle $(ELF)
    
    read-eeprom:
            $(AVRDUDE) -U eeprom:r:eeprom.bin:i
    - - - Aktualisiert - - -

    Benutzen tu ich das ganze so:

    Code:
    #include "project.h"
    #include "i2c.h"
    
    extern avr::project sys;
    extern avr::i2c twi;
    
    extern bool check_twi(unsigned char& state);
    
    // -----------------------------------------------------
    // relay
    // -----------------------------------------------------
    namespace relay {
    unsigned char state = 0;
    bool
    handle()
    {
        switch (state)
        {
        case 0:
            g_buffer[0] = ~sys.relay_state;
            twi.write_to_slave(avr::relay_address, g_buffer, 1);
            state++;
            return false;
        // check that twi transmitted successful
        case 1:
            return check_twi(state);
        case 2:
            state = 0;
            return true;
        // 100: Error
        case 100:
            // reenter. try again
            state = 0;
            break;
        default:
            break;
        }
    
        return true;
    }
    }; // namespace relay
    Code:
    // -----------------------------------------------------
    // helper functions for statemachines
    // -----------------------------------------------------
    
    bool
    check_twi(unsigned char& state)
    {
        if (twi.is_busy())
            return false; // not yet done
        else if (twi.is_error() != avr::i2c::no_error)
        {
            state = 100; // we have an error
        }
        else
        {
            // everything ok
            state++;
        }
        return true;
    }
    - - - Aktualisiert - - -

    Der Scheduler ruft das ganze dann so auf:

    Code:
    // -----------------------------------------------------
    // scheduler
    // -----------------------------------------------------
    namespace scheduler {
    
    unsigned char state_i2c = 0;
    unsigned char state_spi = 0;
    unsigned char state_uart = 0;
    
    void
    i2c()
    {
        bool next_step = true;
        switch (state_i2c)
        {
        case 0:
            next_step = rtc::handle();
            break;
        case 1:
            next_step = storage::handle();
            break;
        case 2:
            next_step = menu::handle();
            break;
        case 3:
            next_step = relay::handle();
            break;
        case 4:
            next_step = display::handle();
            break;
        }
    
        if (next_step) state_i2c += 1;;
        if (state_i2c >= 5)   state_i2c = 0;
    }
    }; // namespace scheduler
    Der Scheduler selbst hängt wieder im timer1 IRQ.

    Code:
    /*
        Copyright (c) 2014 "Georg Gast <georg@schorsch-tech.de>"
    
        This file is part of thermocontrol.
    
        thermocontrol is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.
    
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
    
        You should have received a copy of the GNU General Public License
        along with this program.  If not, see <http://www.gnu.org/licenses/>.
    */
    
    #include <avr/interrupt.h>
    #include "units.h"
    #include "timer1.h"
    #include "project.h"
    #include "scheduler.h"
    
    extern avr::project sys;
    
    // we count 250 cycles until TOV1 (normal mode)
    static const int start_tcnt = 65536-250;
    
    namespace AVR {
    namespace timer1 {
    
    void
    init()
    {
        // start timer with 1 ms interval
        // normal mode
        TCCR1A  = 0;
        TCCR1B  = (1 << CS11) | (1 << CS10);                // prescale factor 64
        TIMSK1 |= (1 << TOIE1);
        TCNT1 = start_tcnt;
    }
    
    } // namespace timer1
    } // namespace AVR
    
    // -----------------------------------------------------
    // IRQ Handler are outside of our namespace
    // -----------------------------------------------------
    ISR(TIMER1_OVF_vect)
    {
        /*
        Timer 1, Normal mode, runs up and
        and then TOV1 irq when 0xffff to 0x0000
        (Timer Counter Overflow 1) irq
        */
    
        // to measure time, set let when we are in here
        TCNT1 = start_tcnt;
        sys.elapsed_time++;
    
        scheduler::i2c();
        scheduler::spi();
        scheduler::uart();
    }

  8. #28
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    02.09.2009
    Ort
    Berlin (Mariendorf)
    Beiträge
    1.023
    Zitat Zitat von Klebwax Beitrag anzeigen
    Und es ist mitnichten eine "Zauberformel" sondern leicht zu erklären. Wenn der Slave mit Read adressiert worden ist, wartet er auf 8 Clocks um Datenbits zu liefern und ein neuntes mit dem ACK. Führt der Host diese Sequenz nicht vollständig durch (Absturz, Reset o.ä.), hängt der Slave (es gibt kein Timeout bei I2C). Das Toggeln von SCL führt das zuende und das High auf SDA ist ein NAK. Das bricht dann die Übertragung ab.

    @klebwax
    Wie unterscheidet man nach dem Controller-Reset einen Bus im Idle-Zustand (SCL und SDA, beide H) vom wartenden Slave, der gerade eine "1" übertragen will ?

    Und was, wenn der Slave mit write adressiert wurde - macht das einen Unterschied?
    Was, wenn die Adressierung mit bitgebangten Einsen erst eine gültige Adressierung bewirkt?
    Was unterscheidet von Slave kommende Einsen von NAK (oder was es das ACK???) ?

    Ich sehe einfach noch nicht die geschlossenen Lösung für den Bus-Reset: Müssen jetzt acht getaktete Einsen gesendet werden, oder maximal acht und nach jedem geprüft? Ich krieg das nicht zusammen. Ich habe mich halt bisher nicht in die I2C-Diagramme hineingedacht, weil es bei mir mit einem PIC16 auf der Ebene der Steuerbits und des IRQ-Flags schönwettermäßig recht bald funktionierte. Auch der neuerliche Erhellungsversuch mit RN-Wissen und dem relevanten Teil der Contollerdoku war erfolglos.

    Kannst du das mit Fallunterscheidung mal wasserdicht darlegen - du scheinst I2C ja fundiert zu kennen. Das wäre super, auch im Sinne von oberallgeier's Anregung zum geballten I2C-Know How-Thread.

    Gruß
    RoboHolIC
    Geändert von RoboHolIC (03.10.2014 um 23:48 Uhr) Grund: Adressierung an klebwax

  9. #29
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.899
    Zitat Zitat von RoboHolIC Beitrag anzeigen
    @klebwax
    Wie unterscheidet man nach dem Controller-Reset einen Bus im Idle-Zustand (SCL und SDA, beide H) vom wartenden Slave, der gerade eine "1" übertragen will ?
    garnicht. Du bekommst dann später einen Fehler. Du müßtest das Problem dann bei der Reinitialisierung in deiner Fehlerbehandlung beseitigen. Am einfachsten ist, vor der Initialisierung generell die Clocks zu liefern.
    Und was, wenn der Slave mit write adressiert wurde - macht das einen Unterschied?
    Bei einem Write treibt nur der Master den Bus, nie der Slave. Der Slave kann also den Bus nicht blockieren.
    Was, wenn die Adressierung mit bitgebangten Einsen erst eine gültige Adressierung bewirkt?
    Der I2C Bus ist Open Collector, man kann keine 1 Senden. Und was hat "gültige Adressierung" mit "Bus ist nicht Idle" zu tun?
    Was unterscheidet von Slave kommende Einsen von NAK (oder was es das ACK???) ?
    Ein High auf dem Bus beim ersten bis achten Takt ist eine 1, beim neunten ist ein NAK.
    Ich sehe einfach noch nicht die geschlossenen Lösung für den Bus-Reset: Müssen jetzt acht getaktete Einsen gesendet werden, oder maximal acht und nach jedem geprüft?
    Wenn ich mich recht erinnere, steht "mindestens 8" in den I2C Spec. Und eigentlich kann man keine 1 Senden. Der I2C Bus ist Open Collector, man kann die Leitung nur loslassen. Wenn in der Spec 1 oder High steht, ist gemeint, daß der Master den Bus nicht treibt. Deswegen habe ich ja oben geschrieben: ich schalte vor der Initialisierung SDA auf Input (der Pin ist dann hochohmig und das ist dann equivalent zu einem nicht angesteuerten Transistor im Open Collector Triber), SCL auf Output, liefere die Clocks, schalte dann SCL auf Input und prüfe auf Bus Idle.
    Ich krieg das nicht zusammen. Ich habe mich halt bisher nicht in die I2C-Diagramme hineingedacht
    Das wäre aber zum Verständniss hilfreich. Ebenso die Lektüre der Spec, die NXP (vormals Philips) kostenfrei zur Verfügung stellt. Wenn man sich auf Single Master sowie Standard und Fast Mode beschränkt, gehört sie zu den einfachsten und kürzesten Protokollbeschreibungen, die ich kenne.
    weil es bei mir mit einem PIC16 auf der Ebene der Steuerbits und des IRQ-Flags schönwettermäßig recht bald funktionierte
    Da geht dann die Arbeit richtig los. Wie ich an anderer Stelle gesagt habe, kann der Schlechtwettercode viel länger sein.
    - du scheinst I2C ja fundiert zu kennen.
    Nun ja, in einem System mit zwei Open Colector Treiber können sich nicht viele Dinge verbergen, insbesondere wenn es so alt ist, daß die ersten Slaves mit Sicherheit reine Hardware waren, und die meisten heute noch sind.

    MfG Klebwax
    Strom fließt auch durch krumme Drähte !

  10. #30
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    02.09.2009
    Ort
    Berlin (Mariendorf)
    Beiträge
    1.023
    @ klebwax
    Zunächst vielen Dank für deine ausführliche Antwort und deine Bemühung, mir Verständnis zu verschaffen. Leider blieb das große Achsoo noch aus, da hab ich noch weiter gesucht:

    Zunächst habe ich ein Zitat aus der mir vorliegenden Philips-I2C-Spec.: ( Ver. 2.1, Jan. 2000 )
    I2C-bus compatible devices must reset their bus logic
    on receipt of a START or repeated START condition
    such that they all anticipate the sending of a slave
    address, even if these START conditions are not
    positioned according to the proper format.
    Das besagt ja, dass eine START Condition -auch zu Unzeit angewendet- eine Resetierung der Buslogik im konformen I2C-Slave bewirkt.

    Über den Busreset habe ich dort mit dem Suchbegriff "reset" nichts Einschlägiges gefunden,
    dafür aber bei Freescale folgendes:
    The sequence for a Bus Reset is as follows:
    • Disable the host MCU IIC controller
    • Create a START condition
    • Clock SCL for at least nine clocks
    • Check for SDA high
    • Create a STOP condition
    • Enable the host MCU IIC controller
    Dieser Vorschlag legt nahe, dass der Reset des Slaves auch beim STOP erfolgt.

    Zusammengenommen verstehe ich einen möglichen zielgerichteten Resetvorgang daher so:
    "Der Controller erzeugt bei nicht-getriebener (floating) SDA-Leitung wiederholt Clocksignale und prüft SDA, bis er den Zustand SDA = H vorfindet, der ihm erlaubt, ein START-Signal auf dem Bus durchzusetzen, das den Slave resettet, gefolgt von Dummy-Bit und abschliessendem STOP."
    Möglicherweise genügt (s.o.) auch die STOP Condition alleine, sobald SDA = H.
    Das Dummybit ist ggf. nötig, weil Die Abfolge START Condition - STOP Condition nicht erlaubt ist.

    Trifft diese Formulierung den Punkt?

    Ein paar Worde noch zu deiner ausführlichen Antwort:

    Zitat Zitat von Klebwax Beitrag anzeigen
    Bei einem Write treibt nur der Master den Bus, nie der Slave. Der Slave kann also den Bus nicht blockieren.
    OK, Denkfehler meinerseits.

    Zitat Zitat von Klebwax Beitrag anzeigen
    Und was hat "gültige Adressierung" mit "Bus ist nicht Idle" zu tun?
    Szenario: Controllerreset während der Chip- oder Registeradressierung. Ein Clearance-Versuch sieht SDA und SCL floating. Was tun? Busy oder nicht? Acht oder neun Clockpulse vervollständigen evtl. eine gültige Adressierung mit READ-Bit, die restlichen Clocks gehen für den Rest der Registeradresse drauf oder takten bereits die Antwort des Slave - genaues über den Zustand des Protokolls kann der Controller m.E. nicht aus SDA und SCL ablesen.
    Beliebig viele weitere Clocks sind auch nicht statthaft, das kann kollidieren mit einer reservierten Sonderadresse (1111 1111).
    Alles m.E. fragwürdig im Sinne der I2C-Spezifikation. Vielleicht liege ich auch voll daneben - das ist eben mein Rätselraten, jedenfalls nicht völlig abseits jeglicher Logik.

    Zitat Zitat von Klebwax Beitrag anzeigen
    Nun ja, in einem System mit zwei Open Colector Treiber können sich nicht viele Dinge verbergen
    Eines ist schon eines zuviel.

    Gruß
    RoboHolIC

Seite 3 von 4 ErsteErste 1234 LetzteLetzte

Ähnliche Themen

  1. [ERLEDIGT] Probleme mit IF-Abfrage / Timer
    Von sammler im Forum C - Programmierung (GCC u.a.)
    Antworten: 11
    Letzter Beitrag: 25.04.2011, 11:41
  2. SRF02 über RS232 Beispielcode ohne Funktion?
    Von TobiasBlome im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 2
    Letzter Beitrag: 10.05.2009, 14:21
  3. problem mit button-abfrage im timer (c#)
    Von Roboman93 im Forum Open Source Software Projekte
    Antworten: 4
    Letzter Beitrag: 29.12.2008, 17:40
  4. SRF02 Messwert in Millimeter ermitteln
    Von Stiffer im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 1
    Letzter Beitrag: 29.03.2008, 12:00
  5. Messwert Diagramm erstellen... aber wie?
    Von raptor_79 im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 5
    Letzter Beitrag: 15.11.2007, 08:30

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

LiFePO4 Speicher Test