Forum: Mikrocontroller und Digitale Elektronik SPI emulieren


von Tanja H. (hoefme)


Lesenswert?

Hallo zusammen,

Kann ich eigentlich eifach 4 normale Pin von einem Atmega128 als SPI 
emulieren. Respektive hat das jemand schonmal gemacht oder wie müsste 
ich da vorgehen? Oder ist dies schlichtweg unmöglich?

gruss

von nutzer (Gast)


Lesenswert?

Wenn es nicht so schnell sein muß, und der AVR Master ist, mag es gehen, 
das in Software zu emulieren. Aber warum willst Du das tun, der hat doch 
ne echte SPI? Hausaufgabe?

von Tanja H. (hoefme)


Lesenswert?

Besten dank für deine konstruktive Antwort. Problem ist das meine SPI 
schon für einen anderen Chip vergeben ist und diese somit blockiert. Das 
heisst müsste einen Timer initalisieren welcher den Clock darstellt und 
zusätzliche Ports wie MOSI und MISO welche die Daten synchron ausgeben 
oder?

von Micha (Gast)


Lesenswert?

Ja, so in der Richtung. Schau mal in die Sourcen von der FAT-Lub von 
Ulrich Radig. Dort kann man auch SW-SPI einstellen, mit anderen Worten 
es gibt eine Software-SPI Implementation, die Du als Vorlage benutzen 
kannst.

http://www.ulrichradig.de/home/index.php/avr/mmc-sd

von Matthias Kölling (Gast)


Lesenswert?

Du kannst problemlos mehrere Slaves an die SPI hängen. Ausgewählt werden 
die Geräte über den Chip Select Pin. Das kann ein beliebiger Controller 
Pin sein.

Gruß Matthias

von nutzer (Gast)


Lesenswert?

Also man kann oft mehrere SPI-Geräte an einen SPI-Anschluß anschließen, 
wenn man die Geräte einzeln per SS (Slave select) aktiviert.

Timer brauchst Du nicht, denn die Clock muß kein bestimmtes Zeitschema 
einhalten. Allgemein (Master):


MOSI setzen
Clock auf HIGH
MISO einlesen
Clock auf low

Das Ganze 8x für ein Byte. Wenn nur ein Gerät dranhängt, braucht man 
keine SS.

Vorher die Doku vom Slave lesen, welche Clockpolarität, max. 
Geschwindigkeit etc. Einfach ausprobieren, sollte gehen.

von Bruno (Gast)


Lesenswert?

Ich habe das auch schon gemacht. Das ist kein Problem. Nur habe ich 
damals eine etwas unregelmäßige Clock gehabt. War aber kein Problem. Wie 
oben geschrieben sollte es aber der Master sein.

von Tanja H. (hoefme)


Lesenswert?

Okay versuche es einmal so .... Problem ist das das Board keinen SS 
verwendet und somit der genutzte Chip die Leitungen MOSI und MISO immer 
auf High behält.

von Peter D. (peda)


Lesenswert?

SPI-Master ist überhaupt kein Problem:
1
#include <avr\io.h>
2
#include <inttypes.h>
3
4
5
struct bits {
6
  uint8_t b0:1;
7
  uint8_t b1:1;
8
  uint8_t b2:1;
9
  uint8_t b3:1;
10
  uint8_t b4:1;
11
  uint8_t b5:1;
12
  uint8_t b6:1;
13
  uint8_t b7:1;
14
} __attribute__((__packed__));
15
16
#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)
17
18
19
#define SPI_CLK         SBIT( PORTB, 0 )        // clock
20
#define SPI_CLK_DDR     SBIT( DDRB,  0 )
21
#define SPI_MOSI        SBIT( PORTB, 1 )        // data out
22
#define SPI_MOSI_DDR    SBIT( DDRB,  1 )
23
#define SPI_MISO_PIN    SBIT( PINB,  2 )
24
25
26
uint8_t shift_in_out( uint8_t b )  // send byte
27
{
28
  uint8_t i;
29
30
  SPI_CLK_DDR = 1;
31
  SPI_MOSI_DDR = 1;
32
33
  for( i = 8; i; i-- ){         // 8 bits
34
    SPI_MOSI = 0;
35
    if( b & 0x80 )              // high bit first
36
      SPI_MOSI = 1;
37
    b <<= 1;
38
    SPI_CLK = 1;
39
    if( SPI_MISO_PIN )
40
      b++;
41
    SPI_CLK = 0;
42
  }
43
  return b;
44
}

Peter

von Tanja H. (hoefme)


Lesenswert?

Kann eigentlich eine SPI im 100Hz bereich laufen lassen ..... sofern ich 
als Master das so bestimme?

von dreg (Gast)


Lesenswert?

Hallo,
ich hab in noch keinem Datenblatt eine Mindestfrequenz gesehen.

Gruss
dreg

von Nico E. (masta79)


Lesenswert?

Tanja Hofmann wrote:
> Kann eigentlich eine SPI im 100Hz bereich laufen lassen ..... sofern ich
> als Master das so bestimme?

In Software und mit einem Timer ist das kein Problem, mit der 
Hardware-SPI geht maximal CLK/128.

Problematisch kann es nur sein wenn einer der Slaves seine "normale" 
Arbeit stoppt während SlaveSelect aktiv ist.

von Tim R. (vref)


Lesenswert?

langsamerer datentransfer geht immer. der slave syncronisiert sich immer 
auf die clock.

ich würde nochmal über ein sauberes konzept mit CS leitungen nachdenken 
und das vorhandene SPI interface nutzen. das ist vermutlich wesentlich 
performanter.

alle SPI slaves an einen SPI bus hängen und jedem chip seine CS leitung 
an einen I/O legen.
oder die CS leitungen hinter ein SER-IN-PAR-OUT schieberegister (z.B. 
74HC595) legen um I/O's zu sparen.
wenn ein slave kein CS hat, helfen tri-stateable latches oder and-gatter 
zwischen cpu und slave.

von Tanja H. (hoefme)


Lesenswert?

Konnte also eine SPI ( SS, SCK, MOSI ) implementieren und dies über 
einen Pin ausgeben. Nun weiss ich nicht recht wie ich die MISO am 
einfachsten implementiere. Weiss jemand wie ich das am besten machen 
könnte?

Besten dank.

von Nico E. (masta79)


Lesenswert?

Tanja Hofmann wrote:
> Konnte also eine SPI ( SS, SCK, MOSI ) implementieren und dies über
> einen Pin ausgeben. Nun weiss ich nicht recht wie ich die MISO am
> einfachsten implementiere. Weiss jemand wie ich das am besten machen
> könnte?

Ganz normal, du toggelst die clock und liest den port und shiftest dir 
das in dein byte rein.

von Tanja H. (hoefme)


Lesenswert?

Wie Initalisiere ich den einen Pin als Interrupt. Irgendwie muss ich ja 
erkennen wenn die daten kommen oder?

von Nico E. (masta79)


Lesenswert?

Wenn dein Chip der Master ist setzt du die clock und damit steht fest 
wann die Daten zu kommen haben.

von Tanja H. (hoefme)


Lesenswert?

Ah ja genau so mach ich das. Aber um zu wissen wann ich die Daten holen 
will muss ich ein interrupt auf einen pin initalisieren.

Unter Folgendenem File finde ich die Interruptvektoren:

http://www.propox.com/download/edunet_doc/all/html/iom128_8h-source.html

00361 #define SIG_INTERRUPT0          _VECTOR(1)
00362 #define SIG_INTERRUPT1          _VECTOR(2)
00363 #define SIG_INTERRUPT2          _VECTOR(3)
00364 #define SIG_INTERRUPT3          _VECTOR(4)
00365 #define SIG_INTERRUPT4          _VECTOR(5)
00366 #define SIG_INTERRUPT5          _VECTOR(6)
00367 #define SIG_INTERRUPT6          _VECTOR(7)
00368 #define SIG_INTERRUPT7          _VECTOR(8)
00369 #define SIG_OUTPUT_COMPARE2     _VECTOR(9)
00370 #define SIG_OVERFLOW2           _VECTOR(10)
00371 #define SIG_INPUT_CAPTURE1      _VECTOR(11)
00372 #define SIG_OUTPUT_COMPARE1A    _VECTOR(12)
00373 #define SIG_OUTPUT_COMPARE1B    _VECTOR(13)
........

Wie weiss ich nun welcher Pin als Interrupt zu gebrauchen ist?

von Nico E. (masta79)


Lesenswert?

Tanja Hofmann wrote:
> Ah ja genau so mach ich das. Aber um zu wissen wann ich die Daten holen
> will muss ich ein interrupt auf einen pin initalisieren.

Du meinst das der Slave erstmal signalisiert wenn er Daten hat, und du 
ihn dann abfrägst? Ja, dafür kannst du einen interrupt nehmen.

> Wie weiss ich nun welcher Pin als Interrupt zu gebrauchen ist?

Steht im Datenblatt.

von Tanja H. (hoefme)


Lesenswert?

Habe das im Datenblatt nachgeschaut ..... auf welche Ports sind dann 
diese Interrupts gelegt?

2 $0002 INT0 External Interrupt Request 0
3 $0004 INT1 External Interrupt Request 1
4 $0006 INT2 External Interrupt Request 2
5 $0008 INT3 External Interrupt Request 3
6 $000A INT4 External Interrupt Request 4
7 $000C INT5 External Interrupt Request 5
8 $000E INT6 External Interrupt Request 6
9 $0010 INT7 External Interrupt Request 7

von Nico E. (masta79)


Lesenswert?

.... steht im Datenblatt ....
Du findest das beim Pinout oder auch bei den Alternate Port Functions.

PD0-3 und PE4-7

von Tanja H. (hoefme)


Lesenswert?

Wie initalisiere ich den ein Pin PD1 als Interrupt. Muss ich ihn einfach 
als Input definieren und ist der dann auf positive flanke oder negative 
flanke getriggert? Ein Beispiel würde ansonsten sehr weiterhelfen.

von Andreas W. (andreasw) Benutzerseite


Lesenswert?

RTFM "External Interrupts"
oder
http://www.gidf.de/AVR+External+Interrupts

von Tanja H. (hoefme)


Lesenswert?

Habe noch ein Problem mit der SPI. Die Emulation Funktioniert 
hervorragend wenn ich dies die Pin alleine am KO messe .... jedenfalls 
wenn ich die emulierte SPI an meinen IC hänge der die Wert sendet, habe 
ich auf allen vier Datenleitungen ein komisches rauschen drauf (SS, SCK, 
MOSI, MISO). Muss ich die Ausgäne evt über einen Widerstand auf Masse 
hängen?

Hoffe es kann mir jemand helfen.

von Michael Wilhelm (Gast)


Lesenswert?

Ein Pull Up oder -down ist bei SPI eigentlich nicht nötig. Hast du die 
Massen verbunden?

MW

von Tanja H. (hoefme)


Lesenswert?

Ja war ein Masse Problem. Das senden über die SPI funktioniert jetzt 
tipp top jedoch ist das konzept es empfangens noch nicht implementiert.

Das Problem ist das ich den Bitstom schon einlesen kann jedoch möchte 
ich eigentlech das ganze als Hexzahl und nicht ein array mit 8 Bits 
füllen. Wie stelle ich das am besten an? Oder wie konvertiere ich ein 
array in eine Hexzahl?

von max (Gast)


Lesenswert?

bit array? hexzahl? haeh?
also einlesen geht so

speicherbyte |= inputpin   (falls inputpin ein register ist muss man 
halt noch &1 machen, also:  speicherbyte |= (inputpin&1) )
speicherbyte links shiften

den ganzen prozess in jedem clock zyklus einmal (also 8* fuer ein ganzes 
byte)

So empfaengst du ein byte ueber deine SPI. Das landet dann richtig in 
einem Register/Speicherstelle. (Programmierst du in C?)

von Tanja H. (hoefme)


Lesenswert?

Ja wenn ich über meine Emulierte SPI den MISO eingang einlese setzt in 
einem Array 1 oder 0. Schlussendlich habe ich dann folgendes:

einArray = { 1,0,1,0,0,1,0,1 }

Wie mache jetzt aus diesem Array die ensprechende Hexzahl?

 0011 = A
 0101 = 5

Das ich den Wert einer variable mit A5 laden kann.

von lucem (Gast)


Lesenswert?

Die "Hexzahl" A5 ist nur eine mögliche Repräsentation eines Byte.
Das einfachste, um aus dem Ausgangsarray ein Byte im Sinne des 
C-Datentyps char zu machen, wäre nacheinander das jeweils höherwertige 
Bit aus dem Array (also index von 0 bis 7 laufen lassen) zu einem auf 0 
vorinitialisierten char dazu zu addieren und achließend das ganze nach 
links zu schieben.
1
char byte = 0; // Da steht am Ende das Byte drin
2
char array[8] = {0,1,0,1,0,0,1,0}; // Beispielwert
3
4
for(int i = 0; i <= 7; ++i)
5
{
6
  byte += array[i];
7
  byte <<= 1;
8
}

Menschen mit Vorliebe für unlesbaren Code können natürlich auch alles in 
einem Schritt erledigen.
1
char byte = 0; // Da steht am Ende das Byte drin
2
char array[8] = {0,1,0,1,0,0,1,0}; // Beispielwert
3
4
byte = (array[7] << 7) + (array[6] << 6) + (array[5] << 5) + (array[4] << 4) + [array[3] << 3) + (array[2] << 2) + (array[1] << 1) + array[0];

Stilistisch wäre die erste Variante zu bevorzugen.

von Tanja H. (hoefme)


Lesenswert?

Folgender Befehl geht nicht wirklich .... was mache ich da falsch um das 
Array in Hex umzwandeln?


int readarray8[] = {1,0,1,0,0,0,1,1};
char test;

for(int i=0;i<16;i++){
   test |= readarray[i] << i;
}

von lucem (Gast)


Lesenswert?

1
int readarray8[] = {1,0,1,0,0,0,1,1};
2
char test;
3
4
for(int i=0;i<16;i++){
5
   test |= readarray[i] << i;
6
}

so ziemlich alles...

zum einen: das Array muss auch dimensioniert sein.
also :
readarray[8] statt readarray8[]

der Index über das Array darf nur so groß sein wie das Array selbst, 
sonst fliegt's dir um die Ohren

also:
for(int i=0;i<8;i++) statt for(int i=0;i<16;i++)

Die Varaible test ist zu Beginn uninitialisiert, also kann da alles 
mögliche an Blödsinn drinstehen.
daher:
char test = 0; statt char test;

von Tanja H. (hoefme)


Lesenswert?

Ja stimmt habe jetzt gerade ein paar flüchtigkeitsfehler gemacht, weil 
ich sonst noch ein paar versuche gmeacht habe.


müsst natürlich so sein:

int readarray[8] = {1,0,1,0,0,0,1,1};
char test=0x00;

for(int i=0;i<8;i++){
   test |= readarray[i] << i;
}

jedoch funktioniert es nicht ......

von lucem (Gast)


Lesenswert?

Die gerade aufgeführten Probleme sollte aber jemand mit 
C-Minimalverständnis sofort entdecken.

Kann es sein, dass deine C-Künste noch etwa zu wünschen übrig lassen?
In dem Fall wäre es besser, sich eingehend mit der Sprache zu 
beschäftigen und nicht nur Code zu kopieren.

von lucem (Gast)


Lesenswert?

Für das Array Integers zu nehmen ist auch ein wenig Overkill...
char sollte reichen (je nach Compiler ist int auch auf einem 8bit-System 
16bit breit und verschwendet daher dann viel Platz auf dem Stack).

Wenn es nicht funktioniert versuch es mal mit unsigned Typen.

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.