Forum: Mikrocontroller und Digitale Elektronik ATTiny2313 - USI - USISR lässt sich nicht setzten


von Anthony S. (anthony_02)


Lesenswert?

Hi,

ich habe einen ATTiny2313 und versuche dort über USI ein Signal an 
meinen Rechner zu schicken.

ich hatte im Internet Beispiele zu Ähnlichen µC's gefunden und habe so 
folgendes Programm geschrieben.

Hab dort aber bereits in der Simulation das Problem, das ich das 
USISR-Register nicht setzten kann. (Dieses benötige ich um den 
Überlauffläg zu löschen.


Hier das von mir geschriebene Programm:


#include <avr/io.h>
#include <stdlib.h>
#include <util/delay.h>

void SPI_init(void)
{

  //Eigene Initialisierung WatchDog
  MCUSR =0;

  MCUCR = 0x80;    //JTAG abschalten
  MCUCR = 0x80;

  DDRA |= (1<<PB7)|(1<<PB6); //Output: PB7=USCK, PB6=DO
  DDRA &= ~(1<<PB5); //Input: PB5=DI
  DDRA |= (1<<PD5); //LED auf Ausgang
  USICR = (1<<USIWM0) | (1<<USICLK)|(1<<USITC)| (1<<USICS1);
  // USIWM0 = 1: SPI-Betrieb mit DO, DI und USCK
  // USICLK = 1, USITC = 1, USICS1 = 1: generiert den Taktimpuls für das 
Schieberegister und
  // den 4bit Timer. Der Takt wird am USCK-Pin (PA4) ausgegeben.

}

void SPI_transfer(int data)
{
  USIDR = data; //Daten in Data Register laden
  USISR = (1<<USIOIF); //Überlaufflag löschen
  while (!(USISR & (1<<USIOIF))) //solange kein Timerüberlauf...

  {
    USICR |= (1<<USITC); //Toggle clk (2x)
    USICR |= (1<<USITC);
  }

}

int main (void)
{
  SPI_init();
  while(1)
  {
    SPI_transfer(0x41); // Daten (A) senden
    PORTA |= (1<<PD5); // Led on
    _delay_ms(100);
    PORTA &= !(1<<PD5); // Led off
    _delay_ms(100);
  }
}




Hat jemand eine Idee wo der Fehler sein könnte?

Gruß
Anthony

von Alex S. (thor368)


Lesenswert?

Tach Anthony,

> SICR |= (1<<USITC);

du willst hier ein xor haben:

> SICR ^= (1<<USITC);

Thor

von Anthony S. (anthony_02)


Lesenswert?

Die Zeile

>  USICR |= (1<<USITC);

funktioniert als XOR.


Das Problem das ich habe, ist das er in der Zeile

>  USISR = (1<<USIOIF); //Überlaufflag löschen

den Wert für USIOIF nicht setzt. Das USISR Register bleibt komplett 
leer.


Gibts es dafür eine Erklärung

von Alex S. (thor368)


Lesenswert?

> den Wert für USIOIF nicht setzt. Das USISR Register bleibt komplett
> leer.

Das ist richtig so.
Das sind flags. Die werden von der Hardware gesetzt und müssen durch 
schreiben einer 1 zurück gesetzt werden. Wenn du da eine 1 reinschreibst 
wird das bit also zurück gesetzt!

Thor

von Anthony S. (anthony_02)


Lesenswert?

OK, verständlich.

Aber dann würde die while-schleife nie beendet werden.
(Was bei mir auch der Fall ist)

Zudem habe ich diese Whileschleife mit genau den befehlen öfters im 
Internet gesehen. Ist der Code dann so Falsch? Und wenn ja wie würde es 
Richtig gehören?

Schonmal Danke
Anthony

von Alex S. (thor368)


Lesenswert?

Mhh, ich sehe grade, dass USITC auch eine flag ist. Das bedeutet, dass 
das bit ebenfalls selbstständig zu 0 zurück kehrt. Das |= wirkt also 
nicht als xor sondern schreibt einfach nur eine 1 in USITC, während es 
sich selbst zurücksetzt.

Ich muss da nochmal drüber nachdenken. Ist schon zu spät um das jetzt 
noch zu lösen. Bis morgen.

Thor

von Anthony S. (anthony_02)


Lesenswert?

Hi,

hat den vieleicht noch jemand anders der auch schonmal mit USI 
gearbeitet hat eine Idee wo hier der Fehler sein könnte?

Gruß
Anthony

von Anthony S. (anthony_02)


Lesenswert?

Hab schonmal einen großen Fehler gefunden.

Bei der Initialisierung sowie an ein paar anderen stellen, habe ich beim 
übernehmen des Codes nicht alle
> PORTA in PORTB etc.
umgeändert.

Jedoch hat sich in der Simulation nichts geändert:
-> weiterhin das Problem, das er dort nicht aus der Whileschleife wieder 
rauskommt.

Programmiere ich allerdings den µC mit dem Code:
-> die LED blinkt -> er scheint doch aus der Whileschleife raus zu 
kommen.

Ich kann allerdings weder am Oszi noch am Rechner (verbunden über USB 
TTL Serial Kabel) ein Signal erkennen. Lediglich ein Rauschen um den 
Nullpunkt herrum.

Vieleich noch einen Idee?

Gruß
Anthony

von Alex S. (thor368)


Lesenswert?

> (1<<USICS1)
Bedeutet, trigger auf external positiv edge. Das ist richtig. Du 
solltest aber auch noch USICLK setzen. UU wird sonst der counter nicht 
imkrementiert.

Thor

von Anthony S. (anthony_02)


Lesenswert?

Soll ich USICLK noch an irgend einer anderen stelle setzten?
Denn in der Initialisierung habe ich doch bereits gesetzt.

Anthony

von Alex S. (thor368)


Lesenswert?

Nein außer beim init brauchst du das nicht zu setzen. Aber warum 
toggelst du eigentlich schon beim init USITC?

Äham, wo ich mir deine post grade noch mal so duch lese: Du hast 
gemerkt, dass du einige PortA statt PortB stehen hast aber hast du auch 
gemerkt, dass das auch für die DDRs gilt?

Thor

von Anthony S. (anthony_02)


Lesenswert?

Ja das hatte ich auch gemerkt. Das hab ich alles ausgebessert.

Habs jetzt dazu gebracht, das ich das Signal am Oszi sehe, allerdings 
kommt an meinem zweiten Mikrocontroller noch nichts an.

Ich glaube das der Fehler irgendwas damit zu tun hat das ich beide µCs 
als Master programmiert habe.

Weißt du was ich genau Einstellen muss um einen als Slave zu 
programmieren?

Reicht es wenn ich folgende Implementierung mache?:

>  DDRA |= (1<<PB7)|(1<<PB6); //Output: PB7=USCK, PB6=DO
>  DDRA &= ~(1<<PB5); //Input: PB5=DI
>  DDRA |= (1<<PD5); //LED auf Ausgang
>  USICR = (1<<USIWM0)|(1<<USICS1);


Nochmal vielen Dank für die bisherige Hilfe

Gruß
Anthony

von Alex S. (thor368)


Lesenswert?

Du hast immer noch DDRA da stehen. Das macht mich etwas nervös.

Ansonsten musst du um beide µC zu verketten an deinem setup kaum etwas 
verändern. Die DDRs von DO und DI bleiben gleich. Du musst aber 
bedenken, dass DO und DI gekreuzt werden müssen. Auch das setting von 
USICR bleibt gleich: external clock source. Nur das DDR von USCK muss 
aus, weil nur der master die clock treibt.

Thor

von Anthony S. (anthony_02)



Lesenswert?

OK, da war jetzt der Fehler ich hatte "USCK" noch als output 
eingestellt.

>Hab jetzt aber ein Problem mit meinem Probeprogramm.

Ich hatte dieses so Programmiert das:
-der eine µC_1 "UART" Signale erhält und diese über "USI" wieder ausgibt
-der anderen µC_2 die ausgegebenen "USI" Signale erhält und diese über 
"UART" wiederum ausgibt

Die beiden UART Schnittstellen sind am Rechner angeschlossen, sodass ich 
von dort die Signale Senden und Empfangen kann.

>Jetzt habe ich folgendes Problem:
-Endet das zu Sendene Signal auf 0 ("B" ; 0x42 ; 0100 0010) kommt es 
einwandfrei an
-Endet das zu Sendene SIgnal auf 1 ("A" ; 0x41 ; 0100 0001) kommt 
irgendwas an

>FRAGE1:
Eine Idee woran das liegen könnte?
(Ich hatte dazu feststellen können, das der µC_2 ZWEI Byte rauschickt 
obwohl er eigendlich nur EINEN Byte erhalten haben sollte)

>FRAGE2:
Da ich ja jetzt beim µC_2 die Clock (USCK) auf input gestellt habe 
stellt sich mir dort jetzt die Frage:
-Wie kann der µC_2 der die Clock als Input hat Signale rauschicken ohne 
selber die Clock zu erzeugen?

Gruß
Anthony

von Alex S. (thor368)


Lesenswert?

> Eine Idee woran das liegen könnte?
> (Ich hatte dazu feststellen können, das der µC_2 ZWEI Byte
> rauschickt obwohl er eigendlich nur EINEN Byte erhalten haben
> sollte)
Uff, das war jetzt etwas kurz. Mit "irgendwas" meist du reproduzierbar 
"irgendwas"?

> Da ich ja jetzt beim µC_2 die Clock (USCK) auf input gestellt
> habe stellt sich mir dort jetzt die Frage:
> -Wie kann der µC_2 der die Clock als Input hat Signale rauschicken
> ohne selber die Clock zu erzeugen?
Du meinst SPI seitig. Das clocking des USI läuft bei master und slave 
genau gleich. Beide holen sich die clock vom USCK pin rein. Nur muss 
klar sein wer die clock erzeugt und das ist halt der master. Deshalb hat 
der master das DDR auf und der slave zu.

Thor

von Anthony S. (anthony_02)


Lesenswert?

>Uff, das war jetzt etwas kurz. Mit "irgendwas" meist du reproduzierbar
>"irgendwas"?

Habs mir gerade nochmal genauer angeschaut:
Er scheint das Ganze Signal um EINE Stelle zu Verschieben und ein High 
ans Ende zu hängen.
--> Aus  ("A" ; 0x41 ; 0100 0001)
    Wird ("ƒ" ; 0x83 ; X100 0001 1)

--> Aus  ("C" ; 0x43 ; 0100 0011)
    Wird ("‡" ; 0x87 ; X100 0011 1)

Eine Idee?

von Alex S. (thor368)


Lesenswert?

Das ist doch schon mal ein Anfang. Zeig mal wie du den UART 
initialisierst.

Thor

von Anthony S. (anthony_02)


Lesenswert?

>DAS wär jetzt das Komplette Programm von beiden µCs


>Receive_UART_Transmit_USI
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

/* Prototypes */
void InitUART (unsigned char baudrate);
void InitUSI (void);
unsigned char ReceiveUART (void);
void TransmitUSI (uint8_t data);

// Main - simple program that Transmit Data
main (void)
{
    InitUART(12);               /* Set the baudrate to 4.8k bps using a 
1MHz crystal */
    InitUSI();
    while (1)
    {
      TransmitUSI(ReceiveUART());
    }
}

/* Initialize UART */
void InitUART (unsigned char baudrate)
{
  //Eigene Initialisierung WatchDog
  MCUSR =0;

  //JTAG abschalten
  MCUCR = 0x80;
  MCUCR = 0x80;

  /* Set the baud rate */
  UBRRL = baudrate;

  /* Enable UART receiver and transmitter */
  UCSRB = (1 << RXEN) | (1 << TXEN);

   /* 8 data bits, 1 stop bit */
   UCSRC = (1 << UCSZ1) | (1 << UCSZ0);
}

void InitUSI(void)
{
  //Eigene Initialisierung WatchDog
  MCUSR =0;

  //JTAG abschalten
  MCUCR = 0x80;
  MCUCR = 0x80;

  //Eigene Initialisierung (Outputs)
  DDRD |= (1<<PD5);

  //Output: PB7=USCK, PB6=DO
  DDRB |= (1<<PB7)|(1<<PB6);

  //Input: PB5=DI
  DDRB &= ~(1<<PB5);

  // USIWM0 = 1: SPI-Betrieb mit DO, DI und USCK
  // USICLK = 1, USITC = 1, USICS1 = 1: generiert den Taktimpuls für das 
Schieberegister und
  // den 4bit Timer. Der Takt wird am USCK-Pin (PB7) ausgegeben.
  USICR = (1<<USIWM0) | (1<<USICLK) | (1<<USITC) | (1<<USICS1);
}

void TransmitUSI (uint8_t data)
{
  //Daten in Data Register laden
  USIDR = data;

  //Überlaufflag löschen
  USISR = (1<<USIOIF);

  //solange kein Timerüberlauf...
  while (!(USISR & (1<<USIOIF)))

  {
    //Toggle clk (2x)
    USICR |= (1<<USITC);
    USICR |= (1<<USITC);
  }

    PORTD |= (1<<PD5); // Led on
    _delay_ms(1000);

    PORTD &= !(1<<PD5); // Led off
    _delay_ms(1000);
}

unsigned char ReceiveUART(void)
{
    /* Wait for incomming data */
    while (!(UCSRA & (1 << RXC)));
  return UDR;
}




>Receive_USI_Transmit_UART
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

/* Prototypes */
void InitUART (unsigned char baudrate);
void InitUSI (void);
unsigned char ReceiveUSI (void);
void TransmitUART (unsigned char data);

// Main - simple program that Transmit Data
main (void)
{
    InitUART(12);               /* Set the baudrate to 4.8k bps using a 
1MHz crystal */
    InitUSI();
    while (1)
    {
      TransmitUART(ReceiveUSI());
    }
}

/* Initialize UART */
void InitUART (unsigned char baudrate)
{
  //Eigene Initialisierung WatchDog
  MCUSR =0;

  //JTAG abschalten
  MCUCR = 0x80;
  MCUCR = 0x80;

  //Eigene Initialisierung (Outputs)
  DDRD |= (1<<PD5);

  /* Set the baud rate */
  UBRRL = baudrate;

  /* Enable UART receiver and transmitter */
  UCSRB = (1 << RXEN) | (1 << TXEN);

   /* 8 data bits, 1 stop bit */
   UCSRC = (1 << UCSZ1) | (1 << UCSZ0);
}

void InitUSI(void)
{
  //Eigene Initialisierung WatchDog
  MCUSR =0;

  //JTAG abschalten
  MCUCR = 0x80;
  MCUCR = 0x80;

  //Output: PB6=DO
  DDRB |= (1<<PB6);

  //Input: PB5=DI
  DDRB &= ~(1<<PB5);

  //Input: PB7=USCK
  DDRB &= ~(1<<PB7);

  // USIWM0 = 1: SPI-Betrieb mit DO, DI und USCK
  // USICLK = 1, USITC = 1, USICS1 = 1: generiert den Taktimpuls für das 
Schieberegister und
  // den 4bit Timer. Der Takt wird am USCK-Pin (PB7) ausgegeben.
  USICR = (1<<USIWM0)|(1<<USICS1);
}

void TransmitUART (unsigned char data)
{
  /* Wait for empty transmit buffer */
  while (!(UCSRA & (1 << UDRE)));

  /* Start transmittion */
  UDR = data;

    PORTD |= (1<<PD5); // Led on

    _delay_ms(1000);

    PORTD &= !(1<<PD5); // Led off

    _delay_ms(1000);
}


unsigned char ReceiveUSI(void)
{
  //Wait for incomming data
  while(USIDR == 0x00);

  //Pass Data to returnData
  unsigned char returnData = USIDR;

  //Delete Data in USIDR
  USIDR = 0x00;

  //Return the data
  return returnData;
}

von Alex S. (thor368)


Lesenswert?

Also erstmal könntest du das setzen der DDRs beim µC2 noch zusammen 
fassen. Die DDRs von PB5 und PB7 sind immerhin im selben Register.

Dein Problem könnte sein, dass du die Beendigung des Empfangs beim µC2 
durch das bloße Prüfen auf Verschiedenheit von null beurteils. Leider 
ist USIDR aber nicht gepuffert und es kann daher dazu kommen, dass deine 
Warteschleife zu früh abbricht. Trigger am besten auf den counter 
overflow. Der sagt dir zuverlässig, wann der shfit fertig ist.

Thor

von Anthony S. (anthony_02)


Lesenswert?

Das wars, jetzt funktioniert es.

Vielen Dank für deine Hilfe, hast mir echt gut weiter geholfen.

Gruß
Anthony

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.