ATTiny2313 - USI - USISR lässt sich nicht setzten

OP #2498876
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
#2498939
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
#2499014
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
OP #2499540
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
#2501506
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
OP #2501766
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
#2501822
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
OP #2502968
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
#2502989
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
OP #2503031
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?
OP #2503149
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;
}
#2503191
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren