SPI emulieren

#921016
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?
Gast #921027
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.
#921070
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
#921121
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.
#921124
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.
#926070
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.
#926094
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?
#926141
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.
#926220
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
#926991
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.
#927721
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?
Gast #927751
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?)
#927813
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.
Gast #927896
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.
Gast #927933
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;
#927937
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 ......
Gast #927938
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.
Gast #927942
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

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