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


von M.B. (Gast)


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:
1
// aus der USI_TWI_Master.h:
2
3
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny24A__)|| defined(__AVR_ATtiny44__)|| defined(__AVR_ATtiny44A__)|| defined(__AVR_ATtiny84__)
4
    #define DDR_USI             DDRA
5
    #define PORT_USI            PORTA
6
    #define PIN_USI             PINA
7
    #define PORT_USI_SDA        PORTA6
8
    #define PORT_USI_SCL        PORTA4
9
    #define PIN_USI_SDA         PINA6
10
    #define PIN_USI_SCL         PINA4
11
#endif
1
// aus der USI_TWI_Master.c:
2
3
/*---------------------------------------------------------------
4
 USI TWI single master initialization function
5
---------------------------------------------------------------*/
6
void USI_TWI_Master_Initialise( void )
7
{
8
  PORT_USI |= (1<<PIN_USI_SDA);           // Enable pullup on SDA, to set high as released state.
9
  PORT_USI |= (1<<PIN_USI_SCL);           // Enable pullup on SCL, to set high as released state.
10
/* Achtung: ATTiny24 & Co haben im TworWire Mode die internen Pull-ups deaktiviert und müssen */
11
/*          extern im Schaltplan und Layout vorgesehen werden!!!                              */ 
12
  
13
  DDR_USI  |= (1<<PIN_USI_SCL);           // Enable SCL as output.
14
  DDR_USI  |= (1<<PIN_USI_SDA);           // Enable SDA as output.
15
  
16
  USIDR    =  0xFF;                       // Preload dataregister with "released level" data.
17
  USICR    =  (0<<USISIE)|(0<<USIOIE)|                            // Disable Interrupts.
18
              (1<<USIWM1)|(0<<USIWM0)|                            // Set USI in Two-wire mode.
19
              (1<<USICS1)|(1<<USICS0)|(1<<USICLK)|                // Software stobe as counter clock source
20
              (0<<USITC);
21
  USISR   =   (1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|      // Clear flags,
22
              (0x0<<USICNT0);                                     // and reset counter.
23
}
24
[...]
25
unsigned char USI_TWI_Start_Transceiver_With_Data( unsigned char *msg, unsigned char msgSize)
26
{
27
  unsigned char tempUSISR_8bit = (1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|      // Prepare register value to: Clear flags, and
28
                                 (0x0<<USICNT0);                                     // set USI to shift 8 bits i.e. count 16 clock edges.
29
[...]
30
/*Write address and Read/Write data */
31
  do
32
  {
33
      /* Write a byte */
34
      USIDR     = *(msg++);                        // Setup data.
35
      USI_TWI_Master_Transfer( tempUSISR_8bit );   // Send 8 bits on bus.
36
  }while( --msgSize) ;                             // Until all data sent/received.
37
  USI_TWI_Master_Stop();                           // Send a STOP condition on the TWI bus.
38
39
/* Transmission successfully completed*/
40
  return (TRUE);
41
}
42
[...]
43
unsigned char USI_TWI_Master_Transfer( unsigned char temp )
44
{ 
45
46
  USISR = temp;                                     // Set USISR according to temp.
47
                                                    // Prepare clocking.
48
  temp  =  (0<<USISIE)|(0<<USIOIE)|                 // Interrupts disabled
49
           (1<<USIWM1)|(0<<USIWM0)|                 // Set USI in Two-wire mode.
50
           (1<<USICS1)|(1<<USICS0)|(1<<USICLK)|     // Software clock strobe as source.
51
           (1<<USITC);                              // Toggle Clock Port.
52
  do
53
  {
54
    _delay_us(4);              
55
    USICR = temp;                          // Generate negative SCL edge.
56
57
    _delay_us(6);              
58
    USICR = temp;                          // Generate positve SCL edge.
59
60
    while( !(PIN_USI & (1<<PIN_USI_SCL)) );// Wait for SCL to go high.
61
62
  }while( !(USISR & (1<<USIOIF)) );        // Check for transfer complete.
63
64
65
  return temp;                             // Return the data from the USIDR
66
}
67
[...]

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:
1
// in der USI_TWI_Master_Transfer:
2
  do
3
  {
4
    _delay_us(4);              
5
    USICR = temp;                          // Generate negative SCL edge.
6
7
    _delay_us(6);              
8
    USICR = temp;                          // Generate positve SCL edge.
9
10
    while( !(PIN_USI & (1<<PIN_USI_SCL)) );// Wait for SCL to go high. 
11
//^^^^^^^^ hier steckt er fest, weil die Clock nicht mehr "1" wird
12
// Generate positive SCL edge scheint nicht mehr zu funktionieren
13
14
  }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.

von M.B. (Gast)


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?

von spess53 (Gast)


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

von M.B. (Gast)


Lesenswert?

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

"Meine Version":
1
  do
2
  {
3
    _delay_us(4);              
4
    USICR = temp;                          // Generate negative SCL edge.
5
6
    _delay_us(6);              
7
    USICR = temp;                          // Generate positve SCL edge.
8
9
    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?

von M.B. (Gast)


Lesenswert?

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

von spess53 (Gast)


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

von M.B. (Gast)


Lesenswert?

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

von spess53 (Gast)


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

von M.B. (Gast)


Angehängte Dateien:

Lesenswert?

Anbei ein Auszug

von spess53 (Gast)


Lesenswert?

Hi

>Anbei ein Auszug

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

MfG Spess

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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

Zumal die USI das ja auch kann...

von M.B. (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Zumal die USI das ja auch kann...

So war der Plan

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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:
1
static uint8_t
2
SPITransfer(uint8_t d)
3
{
4
        USIDR = d;
5
        USISR = _BV(USIOIF);
6
        do {
7
                USICR = _BV(USIWM0) | _BV(USICS1) |
8
                        _BV(USICLK) | _BV(USITC);
9
        } while ((USISR & _BV(USIOIF)) == 0);
10
        return USIDR;
11
}

von M.B. (Gast)


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.

von spess53 (Gast)


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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Julian B. (julinho)


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ß

von Julian B. (julinho)


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ß

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.