SPI und SCK Problem

(Firma: Student) #839806
Lesenswert?

Hallo,
zur Ansteuerung eines Sensors will ich das Hardware SPI des ATmega16 
benutzen.

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

Und jetzt in main()
1
SPDR=0x00;    //damit die ISP Clock läuft
2
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
Persönliche Seite #839874
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.
(Firma: Student) #839881
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...
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3

4
volatile unsigned int msec=0; volatile unsigned char newmsec=0; 
5
volatile unsigned char sec=0; volatile unsigned char newsec=0;
6

7
int main (void) 
8
{
9
 // ***PORTS***
10
  PORTA=0x00;
11
  DDRA=0xFF;
12
  
13
// ***PORTS***ENDE
14

15
//***TIMER***
16

17
  //Timer0 -- global time
18
  TCCR0 |= (1<<CS00) | (1<<CS01); //prescale:64
19
  TCCR0 |= (1<<WGM01);
20
  OCR0  = 0x83;
21
  TIMSK |= (1<<OCIE0);
22
  
23
//***TIMER*** ENDE  
24
  
25
  sei();
26
    
27
  DDRB = (1<<PB5) | (1<<PB7);     //Set MOSI and SCK output, all others input   
28
  DDRB |= (1<<PB4);    // configure the CS Pin as output as not to affect the SPI
29
    
30
  
31
  /* initialize SPI Control Registers */
32
  SPCR |= (1<<SPE);       //enables SPI functionality
33
  // SPCR &= ~(1<<DORD);      //Data Order, 0-->MSB first
34
  SPCR |= (1<<MSTR);      //Master/Slave Select, 1--> ATmega is master
35
  // SPCR &= ~(1<<CPOL);      // Clock Cycle :rising edge first, falling edge trailing
36
  // SPCR &= ~(1<<CPHA);      //1-->sample on falling edge
37
  
38
  SPCR |= (1<<SPR1);      //SPI fqrequenzy= F_CPU/64
39
  SPCR &= ~(1<<SPI2X) &~ (1<<SPR0);
40
  
41
  while (1){
42
  
43
    if (newsec==1)   {
44
      SPDR=0xFF;
45
      while (!(SPSR & (1<<SPIF)));
46
      PORTA ^= 0xFF;    
47
      newsec=0;
48
    }
49
  }  
50
}
51

52
ISR (SIG_OUTPUT_COMPARE0) 
53
{ 
54
  msec++;
55
  newmsec=1;
56
  
57
  if (msec==1000) {  
58
    sec++;
59
    newsec=1;
60
    msec=0;
61
  }  
62
}
(Firma: Student) #839890
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 :-)
Gast #840022
Lesenswert?

Hallo Jakob,


versuch es doch mal so:

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

3
#include <avr/io.h>
4
#include <util/delay.h>
5
#include <stdlib.h>
6

7
void transmit(unsigned char, char);
8

9
void Load_Low()
10
{  
11
  PORTB &= ~(1 << PB4);
12
}
13

14
void Load_High()
15
{
16
  PORTB |= (1 << PB4);
17
}
18

19

20
void SPI_MasterInit(void) {
21

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

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

29
void transmit(unsigned char addr, char data) {
30
  
31
  SPDR = addr;                      // Start transmission
32
  while(!(SPSR & (1<<SPIF)));           // Wait for transmission complete
33
  
34
  asm volatile("nop");
35
 
36
  SPDR = data;                      // Start transmission
37
  while(!(SPSR & (1<<SPIF)));            // Wait for transmission complete
38
}
39

40
void test_Init(void)
41
{
42
  Load_Low();
43
  for (int i = 0; i < 3; i++)
44
  {
45
  transmit(0x0C,0x01);            // normal mode  transmit(0x0C,0x01);
46
  }
47
  Load_High();
48
}
49

50
int main()
51
{
52
  
53
    SPI_MasterInit();
54
    _delay_us(10);
55
    test_Init();
56
  
57
    //tu was....
58

59
      while (1) { 
60

61
     _delay_ms(10);
62

63
      }
64

65
   return 0;
66

67
}


Gruß
Udo
(Firma: Student) #840220
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
Gast #840467
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)
1
    SPCR = (0 << SPIE) | /* SPI Interrupt Enable */
2
           (1 << SPE)  | /* SPI Enable */
3
           (0 << DORD) | /* Data Order: MSB first */
4
           (1 << MSTR) | /* Master mode */
5
           (0 << CPOL) | /* Clock Polarity: SCK low when idle */
6
           (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */
7
           (1 << SPR1) | /* Clock Frequency: f_OSC / 128 */
8
           (1 << SPR0);
Muß ich mir merken, sowas.

mfg

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