www.mikrocontroller.net

Forum: Compiler & IDEs USI Probleme am ATtiny2313


Autor: Karl W. (karlw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich bekomme die USI im 3-wire-mode bei einem ATtiny2313 einfach nicht zu 
laufen. Auf Interrupts möchte ich hierbei verzichten, da sie eventuell 
in andere Programmteile "reinhauen" könnten, daher habe ich folgende 
einfache Implementierung zum Testen gewählt (nach ASM-Beispiel aus 
Datasheet):
#include <avr/io.h>

#define USI_DDR       DDRB
#define USI_PORT      PORTB
#define USI_PIN        PINB
#define USI_SS        4
#define USI_DO        5
#define USI_DI        6
#define USI_SCK        7

void wait (void);

int main (void)
{
  unsigned int i;

  //Initialization
  USI_DDR |= ((1<<USI_DO)|(1<<USI_SCK)|(1<<USI_SS));
  USI_DDR &= ~(1<<USI_DI);
  USI_PORT |= (1<<USI_SS);

  while(1)
  {
    USI_PORT &= ~(1<<USI_SS);  //start frame by pulling SS low

    USIDR = 170;

    for(i=0;i<=7;i++)
    {
      USICR = (1<<USIWM0)|(1<<USICS0)|(1<<USITC);
      wait();
      USICR = (1<<USIWM0)|(1<<USICS0)|(1<<USICLK)|(1<<USITC);
      wait();
    }

    USI_PORT |= (1<<USI_SS);  //end frame by pulling CS high
    wait();
  }
  
  return(0);
}
void wait (void)
{
  volatile unsigned long l = 50000;

  while(l>0) l--;
}


Der Taktpin toggelt und das CS-Signal wird auch ordentlich generiert. 
Leider bleibt der Datenpin konstant "low"?! Was ist los, habe ich 
Tomaten auf den Augen?!

Gruß Karl

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

Bewertung
0 lesenswert
nicht lesenswert
Hmm, ich blicke gerade mit den einzelnen Optionen nicht ganz durch.
Nur schnell: hier ein Code, der zumindest auf dem ATtiny84
funktioniert:
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;
}
Was auffällt ist, dass ich USICS1 benutze, du USICS0.  Deine Variante
dürfte irgendwas sein, wo Timer/Counter 0 den Takt treibt, oder?

Autor: Karl W. (karlw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank Jörg,

Dein Code funktioniert aber leider auch nicht. Die USI-Optionen 
irritieren mich auch, ich habe schon folgendes probiert:

1) USICS1 und USICS0 sind gelöscht / USICLK und USITC generieren Takt

Meiner Meinung nach ist das die software clock strobe Variante. Das 
gleiche Problem, Daten bleiben konstant low!

2) USICS0 oder USICS1 gesetzt / USICLK und USITC generieren Takt

Ich habe mehrere Codebeispiele (Datenblatt+Forum) gefunden, in denen 
unterschiedlich USICS0 oder USICS1 gesetzt werden. Das gleiche Problem, 
Daten bleiben konstant low!

3) USICS0 oder USICS1 gesetzt / USICLK oder USITC generieren Takt

Egal ob ich USICLK oder USITC setze, die Daten bleiben low?!

Wie Du also siehst, habe ich schon alle möglichen Kombinationen 
ausprobiert und KEINE hat funktioniert?!

Viele Grüße
Karl

PS: Zwischenzeitlich habe ich den DO-Pin mal ohne USI per PORT auf 
HIGH/LOW gezogen. Diese Funktionialität ist nicht kaputt... ;-)

Autor: Karl W. (karlw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

in der Zwischenzeit habe ich mir eine komplette Software-SPI 
geschrieben, dann bin ich auch flexibler mit den Pins und es 
funktioniert wenigstens... ;-)
void SPI_Init (void)
{
  //Initialization
  SPI_DDR |= ((1<<SPI_DO)|(1<<SPI_SCK)|(1<<SPI_SS));
  SPI_DDR &= ~(1<<SPI_DI);
  SPI_PORT |= (1<<SPI_SS);
}

unsigned int SPI_Transfer (unsigned int data)
{
    unsigned int i;
    
    SPI_PORT &= ~(1<<SPI_SS);  //start frame by pulling SS low

    for(i=0;i<=7;i++)      //transfer 8 bits = 1 byte
    {
      //enable output data
      if((data & (1<<i)) == (1<<i)) SPI_PORT |= (1<<SPI_DO);
        else SPI_PORT &= ~(1<<SPI_DO);

      //clock rising edge
      SPI_PORT |= (1<<SPI_SCK);

      //sample input data
      if( (SPI_PIN & (1<<SPI_DI)) == (1<<SPI_DI)) data |= (1<<i);
        else data &= ~ (1<<i);

      //clock falling edge
      SPI_PORT &= ~(1<<SPI_SCK);
    }

    SPI_PORT |= (1<<SPI_SS);  //end frame by pulling CS high
    return(data);
}

Trotzdem ist es unbefriedigend, warum die USI nicht läuft. Würde mich 
freuen, wenn wir doch noch eine Lösung finden würden.

Grüße Karl

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn Du mal in das Assemblerlisting schaust, wirst Du sehen, daß da ganz 
schön viel Code erzeugt wird.

(1<<i) mag der Compiler nicht, da es dafür keinen Opcode gibt.

Auch macht es keinen Sinn, 16Bit Variablen zu verwenden, wenn man nur 
8Bit braucht.

Wesentlich kürzer und schneller wirds daher so:
#include <avr\io.h>


struct bits {
  uint8_t b0:1;
  uint8_t b1:1;
  uint8_t b2:1;
  uint8_t b3:1;
  uint8_t b4:1;
  uint8_t b5:1;
  uint8_t b6:1;
  uint8_t b7:1;
} __attribute__((__packed__));

#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)


#define SPI_CLK         SBIT( PORTB, 0 )        // clock
#define SPI_CLK_DDR     SBIT( DDRB,  0 )
#define SPI_MOSI        SBIT( PORTB, 1 )        // data out
#define SPI_MOSI_DDR    SBIT( DDRB,  1 )
#define SPI_MISO_PIN    SBIT( PINB,  2 )


uint8_t shift_io( uint8_t b )  // send / receive byte
{
  uint8_t i;

  SPI_CLK_DDR = 1;
  SPI_MOSI_DDR = 1;

  for( i = 8; i; i-- ){         // 8 bits
    SPI_MOSI = 0;
    if( b & 0x80 )              // high bit first
      SPI_MOSI = 1;
    b <<= 1;
    SPI_CLK = 1;
    if( SPI_MISO_PIN )
      b++;
    SPI_CLK = 0;
  }
  return b;
}


Peter

Autor: Karl W. (karlw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Peter,

danke für Deine Korrekturen.
Stimmt, mein Fehler "unsigned int" auf dem Atmel zu verwenden, da kommt 
davon wenn man immer zwischen Controllern hin- und her schalten muss... 
;-)

Peter Dannegger wrote:
> Wenn Du mal in das Assemblerlisting schaust, wirst Du sehen, daß da ganz
> schön viel Code erzeugt wird.
>
> (1<<i) mag der Compiler nicht, da es dafür keinen Opcode gibt.
>
> Auch macht es keinen Sinn, 16Bit Variablen zu verwenden, wenn man nur
> 8Bit braucht.
>

Für das Schieben (1<<i) gibt es keinen Opcode? Ich hatte mir extra der 
Übersichtlichkeit wegen die Schreibweise: PORT |= (1<<BIT); angewöhnt?!

Oder kann dies der Compiler optimieren, da ja BIT eine Konstante ist?

Gruß Karl

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

Bewertung
0 lesenswert
nicht lesenswert
Karl W. wrote:

> Oder kann dies der Compiler optimieren, da ja BIT eine Konstante ist?

Richtig, das muss nicht der Prozessor machen, anders als 1 << i.

Autor: sb (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich spiele grade schon eine Weile mit einem Attiny 45 und habe ein 
ähnliches USI-Problem. Jörgs Code funktionierte bei mir auf Anhieb. Nun 
kann ich damit auch ohen Probleme einen 74HC595 zum Ausgeben zwingen. 
Mein Problem besteht darin, dass ich nicht weiss, wie ich die Clockphase 
für einen 74HC165 ändere? Ich hab aus dem Datenblatt mal die Tabelle 
rausgesucht, die denke ich die notwendigen Register beinhaltet und die 
Funktion folgendermaßen implementiert:
static uint8_t spi165(void)
{
  USISR = _BV(USIOIF);
  do {
    USICR = _BV(USIWM0) |                 /* USIWM0=1, USIWM1=0 -> Three Wire Mode */
        _BV(USICS1) | _BV(USICS0) | _BV(USICLK) |  /* all 3 set -> Configure external clock, negative edge */
        _BV(USITC);                 /* writing to the USITC strobe bit will directly clock the 4-bit counter */
  } while ((USISR & _BV(USIOIF)) == 0);
    return USIDR;
}

Nun toggle ich den Latchpin und lasse die Funktion durchlaufen. Die 
Daten werden nun auf dem 74HC595 geschrieben. Komischerweise bekomme ich 
aber jedesmal 0xFF dort angezeigt -> Es scheint also nicht zu 
funktionieren. Kann mir bitte jemand sagen warum nicht und was ich 
anders machen sollte?

MfG sb

Autor: sb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich hab die Sache gelöst. Damit die Daten von den Eingängen in die 
internen Register übernommen werden, musste der SCK-Pin auch High sein. 
Es lag also am schalten des Latches...

LG sb

Autor: thomasH (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich weiß, ich graber hier einen alten Artikel aus, aber ich hatte gerade 
das selbe Problem.

@ Karl W.
bei dir sind DI und DO vertauscht, darum bekommst du auch keinen Output. 
Leider wird bei der USI immer MOSI mit DI und MISO mit DO geshared, da 
sind Verwechslungen ja schon fast vorprogrammiert, wenn man von den 
größeren AVRs mit richtiger SPI Schnittstelle kommt ;-)

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.