Forum: Mikrocontroller und Digitale Elektronik SPI Kommunikation zwischen AT90CAN und ATmega16 (AVR)


von Max (valborian)


Angehängte Dateien:

Lesenswert?

Moin,
liebe mikrocontroller Community.
In der Vergangenheit habe ich diese Forum schon oft genutzt um meine 
Probleme zu bewältigen.

Leider stecke ich seit 4 Tagen an einem so simplen Problem und seh den 
Wald vor lauter Bäumen nicht mehr.
Ich möchte eine simple SPI Kommunikation zum laufen bringen. Hierbei 
wird der AT90CAN128 als Master initialisiert und der ATmega16 als Slave. 
Es soll der Master den Slave ansprechen über den SS Pin (low) und der 
Atmega soll in diesem Projekt dann mit den ausgewerteten Sensordaten 
antworten. Da das alles nicht so gefunzt hat, hab ich angefangen die 
Kommunikaion Schritt für Schritt zu vereinfachen (von interrupt mode -> 
polling mode). Am Ende wollte ich jetzt Daten über Mosi rausschicken und 
diese Daten dann auf der MISO Leitung wiedersehen. Das heißt ich hab das 
SPDR register beschrieben, damit wird auch die CLK gestartet und die 
Daten werden auch einwandfrei rausgesendet (mit dem Oszi gesehen). CLK 
und SS funzt auch wunderbar. Nach der SPI Theorie bestehet die 
Kommunikation aus zwei Shift Registern, wobei diese Register 
gleichzeitig Bit für Bit austauschen. Um Bits auf die MISO Leitung zu 
senden braucht es also eigentlich nur die CLK des Masters. Ich dachte 
jetzt also das jetzt im aller ersten durchlauf da nichts brauchbares 
zurückkommen kann, aber spätestens ab dem zweiten durchlauf die MISO 
Daten gleich der MOSI Daten sein sollten. Stattdessen geht das MISO 
Signal low über die SS Zeit und verhält sich danach wie ein Kondensator 
der sich auflädt.

Das wäre echt super wenn ihr mir helfen könntet oder falls ihr die 
Datenblätter kennt mich dort auf eine Seite hinweisen die ich vielleicht 
übersehen habe.

Ich hab noch sonst zwei Ausschnitte aus dem Schaltplan mit rangehangen. 
Die hab ich nicht erstellt sondern wurden von einem Kollegen gemacht und 
ich soll die Software dafür schreiben :)

Das ist mein erster Beitrag in diesem Forum, ich hoffe ich konnte alle 
Materialien bereitstellen und die Regeln befolgen. Wenn was fehlt oder 
doof geschrieben würde ich das natürlich umgehend nachreichen.

Master Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdio.h>
4
#include <math.h>
5
#include <util/delay.h>
6
7
#define MOSI PB2
8
#define MISO PB3
9
#define SCK PB1
10
#define SS_uC PE2
11
#define SS_TK1 PE0
12
#define SS_TK2 PE1
13
14
#define SPI_Control_Reg SPCR
15
#define SPI_Status_Reg SPSR
16
#define SPI_Data_Reg SPDR
17
#define SPI_Enable SPE
18
#define SPI_Interrupt_Enable SPIE
19
#define SPI_Master MSTR
20
#define SPI_Data_Order DORD
21
#define SPI_Clock_Poarity CPOL
22
#define SPI_Clock_Phase CPHA
23
#define SPI_InterruptFlag SPIF
24
#define SPI_WriteCOLisionFlag WCOL
25
#define SPI_DoubleSpeed_Bit SPI2X
26
27
void SPI_MasterInit(void){
28
  // Set MOSI, SCK and all SS as output
29
  DDRB |= (1 << MOSI) | (1 << SCK);
30
  //Set slave selects as output
31
  DDRE |= (1<<SS_uC) | (1<<SS_TK1) | (1<<SS_TK2);
32
  // Set MISO as input
33
  DDRB &= ~(1 << MISO);
34
  // SCK-frequency = f_clkio/64
35
36
  SPI_Control_Reg = (1<<SPI_Enable) | (1<<SPI_Master) | (1<<SPR0);
37
  SPSR &= ~(1<<SPI2X); //disable double SPI speed
38
  // Set internal pull-up for MISO
39
  PORTB |= (1 << MISO);
40
  // Set all Slaveselect to pull-up
41
  PORTE |= (1<<SS_uC) | (1<<SS_TK1) | (1<<SS_TK2);
42
}
43
44
void SPI_MasterTransmit(char data) {
45
  SPDR = data;
46
  // Wait for transmission complete
47
  while(!(SPSR & (1 << SPIF)));
48
}
49
50
int main(void)
51
{
52
  uint8_t dummy_data = 0x22;
53
        SPI_MasterInit();
54
  uint8_t dummy = 0x22;
55
  //configure Fault-LED (PC0) and Heart-LED (PC2)
56
  DDRC |= (1<<PC0) | (1<<PC2);
57
58
  while(1)
59
        {
60
    PORTE &= ~(1<<SS_uC);
61
    SPI_MasterTransmit(dummy_data);
62
    PORTE |= (1<<SS_uC);
63
    PORTC ^= (1<<PC0);
64
    _delay_ms(5000);
65
        }
66
}
Slave Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdint.h>
4
#include <stdio.h>
5
#include <math.h>
6
#include <util/delay.h>
7
#include <avr/eeprom.h>
8
9
#define MOSI PB5
10
#define MISO PB6
11
#define SCK PB7
12
#define SS_uC PB4
13
14
#define SPI_Control_Reg SPCR
15
#define SPI_Status_Reg SPSR
16
#define SPI_Data_Reg SPDR
17
18
#define SPI_Enable SPE
19
#define SPI_Interrupt_Enable SPIE
20
#define SPI_Master MSTR
21
#define SPI_Data_Order DORD
22
#define SPI_Clock_Poarity CPOL
23
#define SPI_Clock_Phase CPHA
24
#define SPI_InterruptFlag SPIF
25
26
void SPI_SlaveInit(void){
27
  // Set MOSI, SCK and all SS as output
28
  DDRB &= ~(1 << MOSI) | (1 << SCK) | (1<<SS_uC);
29
  // Set MISO as input
30
  DDRB |= (1 << MISO);
31
  // SCK-frequency = f_clkio/64
32
  SPI_Control_Reg = (1<<SPI_Enable);
33
}
34
35
char SPI_SlaveReceive()
36
{
37
  // Wait for reception complete
38
  while(!(SPSR & (1 << SPIF)));
39
  // ???
40
  return(SPDR);
41
}
42
43
int main(void)
44
{
45
  uint8_t dummy_data = 0;
46
        SPI_MasterInit();
47
  DDRA |= (1<<PA4);
48
  PORTA &= ~(1<<PA4);
49
  
50
  while(1)
51
        {    
52
    if(!(PINB & (1<<SS_uC)))
53
    {
54
       dummy_data = SPI_SlaveReceive();
55
    }
56
    
57
    if(dummy_data == 0x22)
58
    {
59
      PORTA |= (1<<PA4);
60
    }
61
          
62
    }
63
}

von S. L. (sldt)


Lesenswert?

Master: soweit ich sehe, hängt PB0 laut Schaltplan und Programm 'in der 
Luft':

"If SS is configured as an input, it must be held high to ensure Master 
SPI operation ..."

Und 'SS' ist für die Hardware PB0, auch wenn hier PE2 genutzt wird. 
Erster Versuch wäre folglich, PB0 als Ausgang zu setzen.

PS:
Was hat es eigentlich mit diesem "SPI_MasterInit();" im Slave-Programm 
auf sich?

: Bearbeitet durch User
von S. L. (sldt)


Lesenswert?

Also mit korrekter Behandlung von SS im Master sowie mit 
'SPI_SlaveInit();' im Slave (und vielleicht dort auch die Kommentare in 
Ordnung bringen) sollte es funktionieren.

von Alexander M. (alexander_m366)


Lesenswert?

Fehlt da nicht eine Klammer um die Veroderung?

DDRB &= ~( (1 << MOSI) | (1 << SCK) | (1<<SS_uC) );

von S. L. (sldt)


Lesenswert?

> Fehlt da nicht eine Klammer um die Veroderung?

Denke ich auch, bin jedoch kein C-Spezialist - aber da der 'Initial 
Value' von DDRx eh 0 ist ...

von Wastl (hartundweichware)


Lesenswert?

Max schrieb:
> AT90CAN128.PNG
> ATmega16.PNG

An jedem_ VCC Pin _ein Abblock-Kondensator gegen Masse.

An jedem !

Max schrieb:
> aus dem Schaltplan mit rangehangen.

Nein!

.... aus dem Schaltplan mit angehängt.

von Wastl (hartundweichware)


Lesenswert?

Max schrieb:
> Master Code:
1
Wichtige Regeln - erst lesen, dann posten!
2
3
    Groß- und Kleinschreibung verwenden
4
    Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

"Längerer Sourcecode" ist es wenn er über eine Bildschirmseite
hinaus geht.

Beitrag #7750250 wurde vom Autor gelöscht.
von S. L. (sldt)


Lesenswert?

an Max:

Mit besagten Änderungen (das Slave-Programm wurde original doch gar 
nicht übersetzt!?) läuft es hier (mutatis mutandis), mangels AT90CAN 
zwischen zwei ATmega16.

PS:
Diese PINB-Abfrage auf SS_uC (im Slave-Programm) muss natürlich raus 
(hatte ich eben nicht mehr nachgezogen).

: Bearbeitet durch User
von Max (valborian)


Lesenswert?

Danke für die Tipps und Hinweise das hat sehr geholfen.
Der Fehler mit dem MasterInit und SlaveInit ist daraus entstanden das 
ich für diesen Beitrag den Code nochmal aufhübschen wollte und mir da 
ein Fehler bei der Benennung passiert ist. Gleiches gilt für das 
konfigurieren der Inputs, wobei die äußere Klammer gefehlt hat. Da diese 
aber eh alle mit 0 initialisiert werden hätte das jetzt keinen 
Unterschied gemacht.

Ich konnte das Problem lösen, indem ich das Master Slave Prinzip 
umgedreht habe. Dabei ist auf MISO immernoch nichts sinniges passiert. 
Als ich dann durch Zufall auf die PCB gedrückt hab, weil ich einen 
Kollegen was zeigen wollte, wurde die Bedingung für das angehen einer 
LED aufeinmal wahr. Was nur möglich wäre wenn MISO das auf MOSI 
geschickte wieder zurückgeschickt hat (hab ich noch einprogrammiert). 
Lange rede kurzer Sinn, es war am Ende eine kalte Lötstelle. Von außen 
kaum bis garnicht zu sehen. Für Menschen die das hier lesen sollten, 
vertraut dem was ihr geschrieben habt, besonders wenn alles auch so im 
Datenblatt steht. Es gibt einfach manchmal Momente wofür man nichts 
kann, was euch aber nicht demotivieren sollte die Probleme zu lösen.

Und Kommentare die Rechtschreibung in einem Technik Forum kritisieren 
haben hier nix verloren und tragen nichts zur Problemlösung bei.
Des weiteren ist ein dies meiner Meinung nach kein längerer Source Code 
gewesen, da er nur die simpelste Form einer SPI Kommunikation enthält XD

Ich danke euch und wünschen allen Technikern weiterhin viel Erfolg bei 
ihren Projekten

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.