www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik SPI emulieren


Autor: Tanja Hofmann (hoefme)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: nutzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Tanja Hofmann (hoefme)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Micha (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Matthias Kölling (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: nutzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Bruno (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Tanja Hofmann (hoefme)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
SPI-Master ist überhaupt kein Problem:

#include <avr\io.h>
#include <inttypes.h>


struct bits {
  uint8_t b0:1;
  uint8_t b1:1;
  uint8_t b2:1;
  uint8_t b3:1;
  uint8_t b4:1;
  uint8_t b5:1;
  uint8_t b6:1;
  uint8_t b7:1;
} __attribute__((__packed__));

#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)


#define SPI_CLK         SBIT( PORTB, 0 )        // clock
#define SPI_CLK_DDR     SBIT( DDRB,  0 )
#define SPI_MOSI        SBIT( PORTB, 1 )        // data out
#define SPI_MOSI_DDR    SBIT( DDRB,  1 )
#define SPI_MISO_PIN    SBIT( PINB,  2 )


uint8_t shift_in_out( uint8_t b )  // send byte
{
  uint8_t i;

  SPI_CLK_DDR = 1;
  SPI_MOSI_DDR = 1;

  for( i = 8; i; i-- ){         // 8 bits
    SPI_MOSI = 0;
    if( b & 0x80 )              // high bit first
      SPI_MOSI = 1;
    b <<= 1;
    SPI_CLK = 1;
    if( SPI_MISO_PIN )
      b++;
    SPI_CLK = 0;
  }
  return b;
}


Peter

Autor: Tanja Hofmann (hoefme)
Datum:

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

Autor: dreg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich hab in noch keinem Datenblatt eine Mindestfrequenz gesehen.

Gruss
dreg

Autor: Nico Erfurth (masta79)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Tim R. (vref)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Tanja Hofmann (hoefme)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Nico Erfurth (masta79)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Tanja Hofmann (hoefme)
Datum:

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

Autor: Nico Erfurth (masta79)
Datum:

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

Autor: Tanja Hofmann (hoefme)
Datum:

Bewertung
0 lesenswert
nicht 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...

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?

Autor: Nico Erfurth (masta79)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Tanja Hofmann (hoefme)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Nico Erfurth (masta79)
Datum:

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

PD0-3 und PE4-7

Autor: Tanja Hofmann (hoefme)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andreas Watterott (andreasw) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
RTFM "External Interrupts"
oder
http://www.gidf.de/AVR+External+Interrupts

Autor: Tanja Hofmann (hoefme)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Michael Wilhelm (Gast)
Datum:

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

MW

Autor: Tanja Hofmann (hoefme)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: max (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?)

Autor: Tanja Hofmann (hoefme)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: lucem (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

char byte = 0; // Da steht am Ende das Byte drin
char array[8] = {0,1,0,1,0,0,1,0}; // Beispielwert

for(int i = 0; i <= 7; ++i)
{
  byte += array[i];
  byte <<= 1;
}


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

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.

Autor: Tanja Hofmann (hoefme)
Datum:

Bewertung
0 lesenswert
nicht 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;
}

Autor: lucem (Gast)
Datum:

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

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

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;

Autor: Tanja Hofmann (hoefme)
Datum:

Bewertung
0 lesenswert
nicht 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 ......

Autor: lucem (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: lucem (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

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.