www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik USI auf Tiny84 bricht Übertragung ab, bei negativem Flankenwechsel


Autor: M.B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

ich verzweifel gerade mit meinem µC ATtiny84.

Ich habe eine Datenübertragung zwischen dem µC und drei DA-Wandlern 
(nacheinander).
(USI Transfer, two-wire-mode, zwei Byte werden übertragen)
Habe zwei Platinen damit aufgebaut --> alles funktioniert
Diese habe ich leider nicht mehr, sodass ich mir nun zwei neue Platinen 
gelötet habe. Also Bauteile bestellt, neu gelötet, Programm drauf und 
nix geht mehr.

Nach drei tagen intensiver Fehlersuche bin ich nun auf folgendes 
gestoßen:

Die Übertragung beginnt und sobald auf der Datenleitung eine 0 auf eine 
1 folgt bricht die Datenübertragung ab, und zwar an folgender Stelle:

Ich benutze die App-Note von Atmel (AVR310 - Using the USI module as a 
TWI Master) mit dem zugehörigen Code, jedoch modifiziert, weil der Code 
für den IAR ist und ich den AVR-GCC nutze.

Hier ein paar Ausschnitte:
// aus der USI_TWI_Master.h:

#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny24A__)|| defined(__AVR_ATtiny44__)|| defined(__AVR_ATtiny44A__)|| defined(__AVR_ATtiny84__)
    #define DDR_USI             DDRA
    #define PORT_USI            PORTA
    #define PIN_USI             PINA
    #define PORT_USI_SDA        PORTA6
    #define PORT_USI_SCL        PORTA4
    #define PIN_USI_SDA         PINA6
    #define PIN_USI_SCL         PINA4
#endif
// aus der USI_TWI_Master.c:

/*---------------------------------------------------------------
 USI TWI single master initialization function
---------------------------------------------------------------*/
void USI_TWI_Master_Initialise( void )
{
  PORT_USI |= (1<<PIN_USI_SDA);           // Enable pullup on SDA, to set high as released state.
  PORT_USI |= (1<<PIN_USI_SCL);           // Enable pullup on SCL, to set high as released state.
/* Achtung: ATTiny24 & Co haben im TworWire Mode die internen Pull-ups deaktiviert und müssen */
/*          extern im Schaltplan und Layout vorgesehen werden!!!                              */ 
  
  DDR_USI  |= (1<<PIN_USI_SCL);           // Enable SCL as output.
  DDR_USI  |= (1<<PIN_USI_SDA);           // Enable SDA as output.
  
  USIDR    =  0xFF;                       // Preload dataregister with "released level" data.
  USICR    =  (0<<USISIE)|(0<<USIOIE)|                            // Disable Interrupts.
              (1<<USIWM1)|(0<<USIWM0)|                            // Set USI in Two-wire mode.
              (1<<USICS1)|(1<<USICS0)|(1<<USICLK)|                // Software stobe as counter clock source
              (0<<USITC);
  USISR   =   (1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|      // Clear flags,
              (0x0<<USICNT0);                                     // and reset counter.
}
[...]
unsigned char USI_TWI_Start_Transceiver_With_Data( unsigned char *msg, unsigned char msgSize)
{
  unsigned char tempUSISR_8bit = (1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|      // Prepare register value to: Clear flags, and
                                 (0x0<<USICNT0);                                     // set USI to shift 8 bits i.e. count 16 clock edges.
[...]
/*Write address and Read/Write data */
  do
  {
      /* Write a byte */
      USIDR     = *(msg++);                        // Setup data.
      USI_TWI_Master_Transfer( tempUSISR_8bit );   // Send 8 bits on bus.
  }while( --msgSize) ;                             // Until all data sent/received.
  USI_TWI_Master_Stop();                           // Send a STOP condition on the TWI bus.

/* Transmission successfully completed*/
  return (TRUE);
}
[...]
unsigned char USI_TWI_Master_Transfer( unsigned char temp )
{ 

  USISR = temp;                                     // Set USISR according to temp.
                                                    // Prepare clocking.
  temp  =  (0<<USISIE)|(0<<USIOIE)|                 // Interrupts disabled
           (1<<USIWM1)|(0<<USIWM0)|                 // Set USI in Two-wire mode.
           (1<<USICS1)|(1<<USICS0)|(1<<USICLK)|     // Software clock strobe as source.
           (1<<USITC);                              // Toggle Clock Port.
  do
  {
    _delay_us(4);              
    USICR = temp;                          // Generate negative SCL edge.

    _delay_us(6);              
    USICR = temp;                          // Generate positve SCL edge.

    while( !(PIN_USI & (1<<PIN_USI_SCL)) );// Wait for SCL to go high.

  }while( !(USISR & (1<<USIOIF)) );        // Check for transfer complete.


  return temp;                             // Return the data from the USIDR
}
[...]

Sobald im Datenbyte eine 0 auf eine 1 folgt wird die Clock nicht mehr 
released:

SDA: 0000 010-------Abbruch
SDA: 0001 0---------Abbruch
SDA: 0011 110-------Abbruch
Der µC steckt in folgender Schleife fest:
// in der USI_TWI_Master_Transfer:
  do
  {
    _delay_us(4);              
    USICR = temp;                          // Generate negative SCL edge.

    _delay_us(6);              
    USICR = temp;                          // Generate positve SCL edge.

    while( !(PIN_USI & (1<<PIN_USI_SCL)) );// Wait for SCL to go high. 
//^^^^^^^^ hier steckt er fest, weil die Clock nicht mehr "1" wird
// Generate positive SCL edge scheint nicht mehr zu funktionieren

  }while( !(USISR & (1<<USIOIF)) );        // Check for transfer complete.

Anmerkung:
Der gleiche Code (unverändert) funktionierte in den ersten beiden 
Platinen einwandfrei.
Die Platinen sind aus der selben Bestellung. Die Bauteile sind 
weitestgehend aus der selben Bestellung.
Der Prozessor ist aus einer anderen Bestellung aber der gleiche Typ! 
(ATtiny84)
Habe aber auch schon einen tiny24 probiert, gleicher Fehler.

Ich kann mir das nicht erklären.

Autor: M.B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schade das noch keiner geantwortet hat und Tipps für mich hat.

Hat ein Flankenwechsel bei der SDA-Leitung Einfluss auf die SCL-Leitung 
oder umgekehrt?

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Ich benutze die App-Note von Atmel (AVR310 - Using the USI module as a
>TWI Master) mit dem zugehörigen Code, jedoch modifiziert, weil der Code
>für den IAR ist und ich den AVR-GCC nutze.

Vergleiche z.b. mal den Code von

'unsigned char USI_TWI_Master_Transfer( unsigned char temp )'

mit dem Original. Fällt dir da etwas auf?

MfG Spess

Autor: M.B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich schätze du meinst diesen Teil: ???
Original:
 do
  {
    __delay_cycles( T2_TWI );              
    USICR = temp;                          // Generate positve SCL edge.
    while( !(PIN_USI & (1<<PIN_USI_SCL)) );// Wait for SCL to go high.
    __delay_cycles( T4_TWI );              
    USICR = temp;                          // Generate negative SCL edge.
  }while( !(USISR & (1<<USIOIF)) );        // Check for transfer complete.
 

"Meine Version":
  do
  {
    _delay_us(4);              
    USICR = temp;                          // Generate negative SCL edge.

    _delay_us(6);              
    USICR = temp;                          // Generate positve SCL edge.

    while( !(PIN_USI & (1<<PIN_USI_SCL)) );// Wait for SCL to go high. 

Wie schon gesagt, habe ich den Code modifiziert. U.a. auch deshalb weil 
in meinem Fall bei der Kommunikation mit dem DA-Wandler das Datenwort 
auf der negativen Flanke ausgelesen wird und auch der Released Pegel bei 
"1" liegt.

Vor allem aber, hat genau dieser Code ja schon einwandfrei funktioniert. 
Die Frage ist nur: Warum hat er schon mal funktioniert? Warum ist dieser 
Fehler auf den vorherigen Platinen (es waren die Gleichen) nicht 
aufgetreten?

Autor: M.B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Uuups, das gehört noch dazu (der Vollständigkeit halber)
  }while( !(USISR & (1<<USIOIF)) );        // Check for transfer
complete.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Wie schon gesagt, habe ich den Code modifiziert. U.a. auch deshalb weil
>in meinem Fall bei der Kommunikation mit dem DA-Wandler das Datenwort
>auf der negativen Flanke ausgelesen wird und auch der Released Pegel bei
>"1" liegt.

Für TWI (I2C) gibt es eigentlich eindeutige Festlegungen.

MfG Spess

Autor: M.B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, das schon, aber der DA-Wandler benutzt kein TWI sondern ein eigenes 
Protokoll, daher die Abwandlung.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Ja, das schon, aber der DA-Wandler benutzt kein TWI sondern ein eigenes
>Protokoll, daher die Abwandlung.

Dann würde ich es komplett in Software machen.

MfG Spess

Autor: M.B. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Anbei ein Auszug

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Anbei ein Auszug

Und warum nimmst du dann nicht SPI . Stattdessen versuchst du ein 
TWI-Modul zu vergewaltigen.

MfG Spess

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
spess53 schrieb:
> Und warum nimmst du dann nicht SPI .

Zumal die USI das ja auch kann...

Autor: M.B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch schrieb:
> Zumal die USI das ja auch kann...

So war der Plan

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
M.B. schrieb:
> So war der Plan

Warum setzt du den denn dann nicht um und ärgerst dich stattdessen
mit dem (völlig unangebrachten) two-wire-mode herum?

Hier mal eine USI, die als SPI master in meinem tiny230-Projekt
werkelt:
static uint8_t
SPITransfer(uint8_t d)
{
        USIDR = d;
        USISR = _BV(USIOIF);
        do {
                USICR = _BV(USIWM0) | _BV(USICS1) |
                        _BV(USICLK) | _BV(USITC);
        } while ((USISR & _BV(USIOIF)) == 0);
        return USIDR;
}

Autor: M.B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch schrieb:
> Warum setzt du den denn dann nicht um und ärgerst dich stattdessen
> mit dem (völlig unangebrachten) two-wire-mode herum?

Weil ich keine Daten zurück bekomme, also nur sende, und daher den 
TwoWireMode gewählt habe.

Außerdem gibt es Vorgaben, wie Datenübernahme bei "Falling Edge", Zwei 
Byte werden übertragen, zwischen den zwei byte muss die Clock positiv 
bleiben. Und nach Datenblattrecherche hielt ich dieses Vorgehen für 
angebracht. Zudem lief es ja und auf Nachfrage immer noch einwandfrei 
auf den beiden ersten Platinen.

Jetzt wo ich die selber brauche funktioniert es nicht mehr.

Da die Platinen die Selben (zumindest aus der gleichen Fertigung) sind, 
der Code der Selbe ist, versuche ich jetzt einen Fehler zu finden, der 
scheinbar, aus welchem Grund auch immer, vorher nicht aufgetreten ist. 
Ich hoffte vielleicht eine Erklärung im µC zu finden. Vielleicht durch 
eine neue Revision, Änderungen an der Schnittstelle, oder so. Aber im 
aktuellen Datenblatt kann ich nichts entdecken.

Vielleicht hatte jemand anders ähnliche Erfahrung und kann mir einen 
Tipp geben (so war meine Intention). Vielleicht der externe Push-up 
Widerstand der zu gering oder zu groß ist oder sowas in der Richtung.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Weil ich keine Daten zurück bekomme, also nur sende, und daher den
TwoWireMode gewählt habe.

Das sind aber schon elektrisch zwei völlig verschiede Busse.
Das Three-Wire-Interface funktioniert für 'nur Senden', auch mit 2 
Leitungen.

>Jetzt wo ich die selber brauche funktioniert es nicht mehr.

Ich tippe eher darauf, das es beim 1.Mal zufällig funktioniert hat. Hast 
du externe Pull-Ups?

MfG Spess

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
M.B. schrieb:
> Weil ich keine Daten zurück bekomme, also nur sende, und daher den
> TwoWireMode gewählt habe.

Auch im two-wire-mode kann man Daten zurücklesen. ;-)  Selbiger hat
halt nur einen definierten Prozess, bei dem es dem slave möglich
ist, dem master zuzurufen: "halt mal!, ich bin noch nicht so weit!".
Beim SPI (aka. three-wire-mode) gibt es dieses feature jedoch nicht,
da bestimmt immer der master das genaue timing.  (Daher ist ein
Controller auch ein miserabler SPI slave.  Brauchbare SPI slaves
kann man eigentlich nur in Hardware gießen.)

Ob du auch Daten zurücklesen willst oder nicht, spielt dabei überhaupt
keine Geige.

> Außerdem gibt es Vorgaben, wie Datenübernahme bei "Falling Edge", Zwei
> Byte werden übertragen, zwischen den zwei byte muss die Clock positiv
> bleiben.

Alles kein Thema, ist halt SPI mode 1 statt des (etwas gebräuchlicheren)
mode 0.  Die USCK-Leitung legst du bei der Programmierung der USI ja
ohnehin selbst in Software fest mit dem USICLK-Bit in USICR.

Mein Codebeispiel oben bezog sich in der Tat auf einen SPI mode 0, aber
das solltest du trotzdem einfach abändern können.

Autor: Julian Baugatz (julinho)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo M.B.,

was macht dein USI-Master?

Bin gerade selber dabei, einen MMA7455 über I2C mit einem Tiny84 
auszulesen und wäre über einen funktionierenden Code sehr dankbar.

Dein Problem hat vielleicht etwas mit Clock-Stretching zu tun, der Slave 
hält wenn er Zeitprobleme hat SCL auf Null, bis er fertig ist. Das mach 
er normalerweise aber nicht mitten in der Übertragung.

Gruß

Autor: Julian Baugatz (julinho)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

habe es mittlerweile geschafft, den MMA7455 über den I2C mit dem Tiny84 
auszulesen, wer am Code interessiert ist, einfach kurz schreiben.

Gruß

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.