SPI Kommunikation zwischen AT90CAN und ATmega16 (AVR)

#7750080
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
}
Angehängte Dateien:
#7750123
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?

Beitrag #7750250 wurde von einem Moderator gelöscht.
#7750277
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).

#7750754
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

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