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
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?
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?
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
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
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.
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.
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.
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
Kann eigentlich eine SPI im 100Hz bereich laufen lassen ..... sofern ich als Master das so bestimme?
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.
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.
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.
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.
Wie Initalisiere ich den einen Pin als Interrupt. Irgendwie muss ich ja erkennen wenn die daten kommen oder?
Wenn dein Chip der Master ist setzt du die clock und damit steht fest wann die Daten zu kommen haben.
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?
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.
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
.... steht im Datenblatt .... Du findest das beim Pinout oder auch bei den Alternate Port Functions. PD0-3 und PE4-7
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.
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.
Ein Pull Up oder -down ist bei SPI eigentlich nicht nötig. Hast du die Massen verbunden? MW
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?
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?)
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.
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.
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; }
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;
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 ......
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.