www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik SPI und SCK Problem


Autor: Jakob M. (Firma: Student) (jakkob)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
zur Ansteuerung eines Sensors will ich das Hardware SPI des ATmega16 
benutzen.

Dies ist die Initialisierung des SPI:
DDRB = (1<<PB5) | (1<<PB7);   //Set MOSI and SCK output, all others input   
DDRB |= (1<<PB4);// configure the CS Pin as output as not to affect the SPI
      
/* initialize SPI Control Registers */
SPCR |= (1<<SPE);   //enables SPI functionality
SPCR &= ~(1<<DORD);  //Data Order, 0-->MSB first
SPCR |= (1<<MSTR);  //Master/Slave Select, 1--> ATmega is master
SPCR &= ~(1<<CPOL);// Clock Cycle :rising edge first, falling edge trailing
SPCR &= ~(1<<CPHA);//1-->sample on falling edge
  
SPCR |= (1<<SPR1);//SPI fqrequenzy= F_CPU/64
SPCR &= ~(1<<SPI2X) &~ (1<<SPR0);

Und jetzt in main()
SPDR=0x00;    //damit die ISP Clock läuft
while (!(SPSR & (1<<SPIF))) //Warten 
Ist die while Schleife drin, so bleibt das Programm hängen, ohne läuft 
es weiter???
Ich glaube das Problemn ist, dass SCK nicht wackelt. Auch mit 
SpeicherOszi sehe keine daten über die Leitung huschen. Liegt das an der 
Initialisierung, oder liegt der Hund woanders begraben.

Danke für eure Hilfe

Autor: Lötlackl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

wenn das wirklich Dein Code ist, fehlt hinter der Befehlszeile ein 
Semikolon.
SPDR=0x00;    //damit die ISP Clock läuft
while (!(SPSR & (1<<SPIF))); //Warten 

mfg

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was sagt denn dein Debugger?

Autor: Jakob M. (Firma: Student) (jakkob)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Na gut, daran sols nicht scheitern, das Semikolon spendier ich gern :-)
Aber leider ist das noch nicht der Grund....-(

Autor: Lötlackl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

na dann spendier mal dieser Zeile
SPCR |= (1<<SPR1);//SPI fqrequenzy= F_CPU/64
auch ein Semikolon. ;) (frequency ist aber sehr merkwürdig geschrieben)

mfg

Autor: Lötlackl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, ist ja eines drin! Vergiß den Müll da oben.

Autor: Jakob M. (Firma: Student) (jakkob)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mein Debugger is t leider nur der Simulator dea AVR Studios und bei dem 
wird SPIF gestzt und alles ist gut...
Also an Semikolata :-) wird es nicht liegen, denn kompiliert wird ja...

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eine untaugliche Programmstruktur und eine fehlerhafte SPI 
Initialisierung oder Abfrage können zu der Beschriebung passen. Die SPI 
Initialisierung / Abfrage habe ich nicht geprüft, weil es IMHO an deiner 
Programmstruktur hapert.

Du willst SPI in main durch Polling (sich wiederholende Abfrage aus 
dem Hauptprogramm heraus, siehe AVR-GCC-Tutorial) bedienen.

In Pseudocode sieht das so aus

main
spi initialisieren
Endlosschleife
  1. Prüfe KURZ, ob an SPI was anliegt
    es liegt was an, dann behandeln
    es liegt nichts an, dann nix machen
  2. Rest vom Programm machen
Zurück zu Endlosschleife

Im Moment machst du durch

while (!(SPSR & (1<<SPIF))); //Warten

eine ggf. LANGE Schleife, bis was an SPI anliegt und dadurch kann sich 
die Abarbeitung von

  2. Rest vom Programm machen

verzögern. Der Teil aus dem Pseudocode

  1. Prüfe KURZ, ob an SPI was anliegt
    es liegt was an, dann behandeln

könnte so z.B. aussehen (ungeprüft, nur dein Code umorganisiert)

if ( (SPSR & (1<<SPIF)) )
{
  spi();
}

In der Funktion spi() handelst du dann die SPI Kommunikation ab.

Autor: Jakob M. (Firma: Student) (jakkob)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bi jetzt mit meinem Latein ziemlich am Ende...ich habe das Programm 
aufs allernötigste Kondensiert, den AVR wieder zurück aufs STK 
strafversetzt und die Komprimierung ausgeschaltet und trotzdem hängt das 
Programm noch in der while (!(SPSR & (1<<SPIF))), und läuft ohne 
wunderbar...
Versteht das Jemand? Bitte...
#include <avr/io.h>
#include <avr/interrupt.h>

volatile unsigned int msec=0; volatile unsigned char newmsec=0; 
volatile unsigned char sec=0; volatile unsigned char newsec=0;

int main (void) 
{
 // ***PORTS***
  PORTA=0x00;
  DDRA=0xFF;
  
// ***PORTS***ENDE

//***TIMER***

  //Timer0 -- global time
  TCCR0 |= (1<<CS00) | (1<<CS01); //prescale:64
  TCCR0 |= (1<<WGM01);
  OCR0  = 0x83;
  TIMSK |= (1<<OCIE0);
  
//***TIMER*** ENDE  
  
  sei();
    
  DDRB = (1<<PB5) | (1<<PB7);     //Set MOSI and SCK output, all others input   
  DDRB |= (1<<PB4);    // configure the CS Pin as output as not to affect the SPI
    
  
  /* initialize SPI Control Registers */
  SPCR |= (1<<SPE);       //enables SPI functionality
  // SPCR &= ~(1<<DORD);      //Data Order, 0-->MSB first
  SPCR |= (1<<MSTR);      //Master/Slave Select, 1--> ATmega is master
  // SPCR &= ~(1<<CPOL);      // Clock Cycle :rising edge first, falling edge trailing
  // SPCR &= ~(1<<CPHA);      //1-->sample on falling edge
  
  SPCR |= (1<<SPR1);      //SPI fqrequenzy= F_CPU/64
  SPCR &= ~(1<<SPI2X) &~ (1<<SPR0);
  
  while (1){
  
    if (newsec==1)   {
      SPDR=0xFF;
      while (!(SPSR & (1<<SPIF)));
      PORTA ^= 0xFF;    
      newsec=0;
    }
  }  
}

ISR (SIG_OUTPUT_COMPARE0) 
{ 
  msec++;
  newmsec=1;
  
  if (msec==1000) {  
    sec++;
    newsec=1;
    msec=0;
  }  
}


Autor: Jakob M. (Firma: Student) (jakkob)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Stefan

Wenn ich es so mache, wie Du sagst, also
if ( (SPSR & (1<<SPIF)) )
{
  spi();
}
dann würde sich der weitere Ablauf meines Programms natürlich nicht 
verändern. Allerdings sehe ich dann doch auch noch weniger, warum SPI 
nicht funzt. Dann bleibt der Controller zwar nicht hängen, wird aber 
wohl auch kaum auf einmal in die if-Bedingung springen, und das ist ja 
was ich will. So sehe ich halt wenigstens genau, dass er wegen dieser 
einen Zeile hängt...
Wenn das vollständige Byte übertragen worden ist durch
SPDR=0xFF;
MUSS doch SPIF gesetzt werden, völlig unabhängig davon, ob irgendwo was 
anliegt oder nicht, richtig? Ich habe ja auf dem STK auch MOSI/MISO gar 
nicht irgendwo angeschlossen, aber das ist doch fürs Flag nicht 
relevant. Also muss doch der Fehler schon beim Ausbleiben des 
ClockSignals lieben, so das das Byte gar nicht erst übertragen 
wird...zumindest ist das mein Wissen. Ich werde aber gerne korrigiert, 
vor allem wenn danach mein Programm läuft :-)

Autor: Bruno (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
was ist denn mit SPCR Bit7? Interrupt freigeschaltet?

Autor: Jakob M. (Firma: Student) (jakkob)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nun ja, das SPCR Bit7 brauch ich ja nur wenn ich überhaupt Interrupts 
aktiviere möchte...hier läuft ja (theoretisch) alles im Polling-Betrieb, 
dafür brauchts keine IR...

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast du mal geprüft ob dir der Programmer einen Strich durch die 
Rechnung macht? der nuzt ja auch SPI...
Also ma besten mal den Programmer abstecken.

Autor: Jakob M. (Firma: Student) (jakkob)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auf meiner Platine wäre das ne Möglickeit, aber auf dem STK?? Es steht 
auch extra in der Anleitung das das SPI Kabel nicht abgenommen werden 
muss...und Abnehmen ändert leider auch nix, hab ich auch probiert :-(

Autor: Udo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Jakob,


versuch es doch mal so:


#define F_CPU 10000000  //evtl. auf deine Taktrate anpassen

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

void transmit(unsigned char, char);

void Load_Low()
{  
  PORTB &= ~(1 << PB4);
}

void Load_High()
{
  PORTB |= (1 << PB4);
}


void SPI_MasterInit(void) {

    DDRB = (1<<PB4)|(1<<PB5)|(1<<PB7);      // set PB4(SS), PB5 (MOSI) and PB7 (SCK) output, all others input

    SPCR = (1<<SPE)|(1<<MSTR);           // enable SPI, Master, set clock rate fck/4  
  
    PORTB |= (1 << PB7)|(1 << PB4);
}

void transmit(unsigned char addr, char data) {
  
  SPDR = addr;                      // Start transmission
  while(!(SPSR & (1<<SPIF)));           // Wait for transmission complete
  
  asm volatile("nop");
 
  SPDR = data;                      // Start transmission
  while(!(SPSR & (1<<SPIF)));            // Wait for transmission complete
}

void test_Init(void)
{
  Load_Low();
  for (int i = 0; i < 3; i++)
  {
  transmit(0x0C,0x01);            // normal mode  transmit(0x0C,0x01);
  }
  Load_High();
}

int main()
{
  
    SPI_MasterInit();
    _delay_us(10);
    test_Init();
  
    //tu was....

      while (1) { 

     _delay_ms(10);

      }

   return 0;

}


Gruß
Udo

Autor: Jakob M. (Firma: Student) (jakkob)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt läufts irgendwie...aber nur, wenn ich den /SS Pin als EINGANG 
konfiguriere (sprich: nicht DDRB |= (1<<PB4) setze), was IMHO dem 
Datenblatt widerspricht???
Kann mir das Jemand erklären? Ich wäre sehr dankbar!

Autor: Udo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vielleicht solltest du es so setzen:
DDRB = (1<<PB4);
PORTB |= (1 << PB4);

Autor: Jakob M. (Firma: Student) (jakkob)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der gedanke kam mir eben beim Mittagessen auch...und siehe da: es geht! 
Also Problem gelöst! Nur verstehe ich nicht, warum das so sein muss, wo 
andere Leute SPI benutzen, ohne den Poort zu setzen...naja.
Danke Euch allen!!

Autor: Jakob M. (Firma: Student) (jakkob)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ALter, Kopf schlag gegen die Wand! Nur in dem kleinen abgespeckten Prog 
hats funktioniert, in meinem echten Programm hilft das nix. kotz

Autor: Udo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann poste doch mal dein "echtes Programm"

Autor: Jakob M. (Firma: Student) (jakkob)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Udo
siehe Anfang des threads...

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>SPCR &= ~(1<<SPI2X) &~ (1<<SPR0);

SPI2X liegt nicht in SPCR ;)

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>SPCR &= ~(1<<SPI2X) &~ (1<<SPR0);

Die ganze Zeile sieht böse aus. Was wird da wann in
welcher Reihenfolge berechnet.

Wenn schon falsch dann bitte richtig:

SPCR &= ~((1<<SPI2X) | (1<<SPR0));

Autor: Jakob M. (Firma: Student) (jakkob)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@holger
Recht hast Du. Nur leider ändert das wie mans dreht und wendet nur die 
Frequenz (Bit 0 ist in SPSR und SPFR für Frequwnz zuständig).
Und das mit der Syntax finde ich eigentlich logisch! Die beiden 
Ausdrücke sind doch equivalent. Ob Du nun die Bits einzeln negierst, 
oder den Gesamtausdruck...
danke trotzdem

Autor: Jakob M. (Firma: Student) (jakkob)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ES GEHT! ES GHET!
Lösung:
erst SPCR |= (1<<MSTR);
dann SPCR |= (1<<SPE);

und schon läufts

thx to everybody!

Autor: Lötlackl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hmmm... n8

Auf die Idee, das "SPCR"-Register nacheinander zu beschreiben, wäre ich 
nicht gekommen. Mit als Bleistiel unten genannter Schreibweise hatte ich 
noch nie Probleme. (geklauter Code)
    SPCR = (0 << SPIE) | /* SPI Interrupt Enable */
           (1 << SPE)  | /* SPI Enable */
           (0 << DORD) | /* Data Order: MSB first */
           (1 << MSTR) | /* Master mode */
           (0 << CPOL) | /* Clock Polarity: SCK low when idle */
           (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */
           (1 << SPR1) | /* Clock Frequency: f_OSC / 128 */
           (1 << SPR0);
Muß ich mir merken, sowas.

mfg

Autor: die ??? (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mmmh, Mega16, was? Hatte ich auch schon das Problem.

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.