Frage zu SPI Programmierung

uwe-ftechnik

Mitglied
31. Jan. 2009
71
1
8
Bekum
Sprachen
Kann mir jemand sagen ob es bei einem ATMega oder ATXMega die möglichkeit gibt 16Bit SPI Worte mit HARDWARE-SPI zu bearbeiten ???
Habe schon einige Datenblätter durchgesehen, entweder bin ich zu DOOF oder es ist nicht Dockumentiert (nicht möglich).
Möcht versuchen ein Baustein anzusprechen der ein 16Bit SPI-Wort benötigt.

z.B. NCV 7708, TLE 5208, TLE 6208

Komme zur zeit hier nicht weiter !!
 
Hallo :)

Also soweit ich informiert bin ist SPI ein 8 Bit Bus. Was aber nichts ausmacht, denn es gibt keine "zerstörerischen" Start / Stopp Zustände wie bei I²C / TWI, außer du setzt die SS Leitung, was aber nicht automatisch geschieht.
Von daher sende einfach erst das High- und dann das Low Byte (oder war es anders herum? Ich vertu mich immer wieder mit dieser Endianness). Ein Wort ist ja nix anderes als 2 Bytes.

Ich weiß ja nun nicht in welcher Sprache du programmierst. Wäre hilfreich zu wissen um Code Beispiele zu posten die dir auch was nützen ;)
 
Hallo Uwe,

Tommy hat es ja schon soweit erklärt. Mit dem SPI-Modul vom AVR und Xmega überträgst du byteweise. Du kannst also einfach zwei mal ein Byte übertragen, um 16 Bit zu erhalten. Die Datenübertragung musst du synchronisieren, das machst du mit einem SS\ Signal (Bei MasterSPI kannst du hierfür irgendeinen freien IO-pin verwenden), dadurch wird auch der Slave angesprochen. Die Reihenfolge der Bytes, welche du überträgst, gibst du in deiner Software vor. Wichtig wäre noch bei der Konfiguration, die richtige Phasenlage einzustellen (SPI Mode) und zu wählen, ob MSB oder LSB (Bit, nicht Byte !) zuerst übertragen wird.

Man kann auch SPI einfach softwaretechnisch realisieren, ohne ein Hardwaremodul. Nachteil: man ist i.d.R. nicht ganz so schnell wie mit Hardware. Vorteil: Man kann jeden freinen IO-Pin verwenden.

Falls du in C programmierst, schaue dir vielleicht auch mal ein Projekt von mir an
Atmel Studio 6 Library für Displaymodul-Familien XV-TFT2428T, XV-TFT50D und XV-TFT60D
Am Ende des Blogbeitrages das Projekt downloaden und dann speziell Display_Interface_AVR8.h bzw. Display_Interface_XMEGA.h anschauen, dort habe ich für AVR und Xmega SoftwareSPI und HardwareSPI realisiert.


Dirk :ciao:
 
Danke für die GUTEN Antworten !! :meeting:

Währe erstmal die Frage der Programier-Sprache!
Im moment befasse ich mich ein wenig mit BASCOM, würde mich hierfür aber auch mit Assembler oder C befassen,
beispiele in Assembler währen also auch willkommen !!

Bei zwei 8Bit übertragungen währe noch zu klären wie der Empfänger daruf reagiert, da ich ja auch nach 8Bit das
Datenregister (SPDR) beachten muss. Ich müsste sehen wie z.B. der NCV 7708 daruf reagiert wenn ich die /SS leitung nicht verändere und hier gg. erstmal Daten schieben muss bevor ich die nächsten 8Bit rüberschieben lassen kann.
Ich möchte den NCV 7708 nehmen wiel der bis zu 5 Mhz SPI Tackt verarbeiten kann und ich hier auf die Geschwiendi-
gkeit grossen Werte lege, die TLE Bausteine sind viel langsammer haben zwischen 1 bis 2 Mhz SPI Tackt !!!!
Der Geschwindigkeit wegen möchte ich ja auch mit Hardware-SPI Arbeiten.
Kleines Beispiel für die übertragung beim NVC 7708(500mA 6fach High u. LOW-Side Treiber):

Anhang anzeigen SPI-Daten.TIF

Datenblatt : http://www.alldatasheet.com/datasheet-pdf/pdf/166604/ONSEMI/NCV7708.html

Habe für erste Versuche ATMEGA 328, ATMEGA 168, ATMEGA 8, ATMEGA 32, ATMEGA 164 und ATTINY2313-20 hier liegen, leider noch keinen ATXMEGA.

:wink:
 
Der Controller soll der Master sein?
Wenn der einmal als Master eingestellt ist, mußt Du Dich selbst um die Slave-Aktivierung kümmern (CS beim Slave runterziehen). Danach wird das zu sendende Byte nach SPDR geschrieben, woraufhin die Hardware mit dem senden beginnt. Dein Programm wird derweil fortgesetzt. Ist das senden abgeschlossen, wird das SPI Interrupt Flag gesetzt, an welches auch ein Interrupt gekoppelt werden könnte. Oder das man für weitere Synchronisation mit dem Programm pollen kann.

So, da das ganze über eine Clock-Leitung synchronisiert wird, sollten Abweichungen weniger das Problem sein. Aber wenn Du Wert auf Tempo legst, bist Du (in ASM) mit polling des SPIF meiner Meinung nach schneller, als mit Interrupts
in etwa so:
-Initialisierung der Hardware
-erstes zu sendendes Byte in ein Rechenregister
-CS runterziehen
-Byte aus Rechenregister nach SPDR schreiben (Byte wird durch die Hardware gesendet)
-zweites Byte in Rechenregister laden
-SPIF abfragen (*), wenn nicht gesetzt auf diese Abfrage zurückspringen
-(sonst) zweites zu sendendes Byte aus dem Rechenregister nach SPDR schreiben (Byte wird gesendet)
-Inhalt von SPDR in Rechenregister lesen (das ist der Recieve-Buffer) - dadurch wird SPIF gelöscht
-SPIF pollen(*)
-wenn gesetzt, CS wieder hochsetzen, das 2te empfangene Byte aus dem SPDR lesen (SPIF löschen)

(*) zum Pollen von SPIF:
befindet sich dieses Bit in einem I/O-Register, welches "Bit accessible" ist, kann man entsprechen direkt darauf zugreifen/dieses abfragen. Also in etwa so:
Code:
Einsprunglabel:
  SBIS Registername, SPIF 'wenn SPIF gesetzt, überspringe die folgende Instruktion
  RJMP Einsprunglabel 'zurück zum Label
HierGehtsWeiter:
andernfalls müßte man:
Code:
-das I/O-Register in ein Rechenregister laden
-dieses mit einer Maske verANDen (Bitposition von SPIF ist 1)
-bei gesetztem Zero-Flag zurück zum laden Springen (BREQ)
-sonst gehts weiter
kommt also auch auf den Controller an.
ganz Hardcore könnte man den Controller zwischen den Bytes natürlich auch exakt solange mit anderen (mehr oder weniger sinnigen) Instruktionen beschäftigen, bis das erste Byte rausgepumpt ist...
 
So, mal zum verwenden des SPI-Interrupts - folgenden Code hab ich geschrieben:
Code:
.include "m8def.inc"	;Atmega8
.org 0x0000
	rjmp reset
.org SPIaddr	
	rjmp SPI_ISR

reset:
SBI PORTD, PORTD0		;D0 ist low-aktiver Taster (interner Pullup)

;** SPI-Hardware**
;	B3 - MOSI
;	B4 - MISO
;	B5 - SCK
;	B0 - CS

SBI PORTB, PORTB0		;CS ist High (Pullup)

LDI R16, (1<<DDB3)|(1<<DDB5)|(1<<DDB0)
OUT DDRB, R16			;MOSI, SCK und CS sind Ausgänge

LDI R16, (1<<SPE)|(1<<MSTR)|(1<<SPIE)
OUT SPCR, R16			;SPI mit IRQ enabled, Master
						;DORD=0=MSB first
						;CPOL=0
						;CPHA=0
SBI SPSR, SPI2X			;F(sck)=F(osc)/2
SEI

warten:
	SBIC PIND, PIND0
	rjmp warten			;auf Taste warten

LDI R16, 4 				;erstes zu sendendes Byte
	CBI PORTB, PORTB0	;Slave aktivieren
	OUT SPDR, R16 		;erstes Byte senden
	LDI R16, 2			;zweites byte bereitgestellt
ende:
	rjmp ende

SPI_ISR:
	out SPDR, R16
	ret
Verwendet habe ich einen Mega8, der grad im STK500 steckte; interner Oscillator @ 8MHz. SCK-Takt ist mit halben Systemtakt auf Maximum.
Schneller kann man im Interrupt meiner Meinung nach nicht mit dem Senden des 2ten Bytes beginnen (wobei diese Tricks sicher nicht routinetauglich sind.)
Die Pause zwischen den beiden Bytes (1.2083µs) beträgt in etwa 9 Takte. Klar, der gerade aktuelle Befehl wird beendet, der Eintritt in die ISR kostet 7 Takte oder so.
screenshot.png

Eigenartigerweise geht die CS-Leitung ca. 469µs nach dem Trigger wieder hoch, bei 470µs beginnt ein Byte 0xD0, welches sich alle 0,4677ms wiederholt...
screenshot1.png
Ich habe überhaupt keine Ahnung, wo das herkommen soll...
Die ISR verlasse ich ja ohne Interrupts global wieder freizugeben; der Controller sollte sich bereits in der Endlosschleife befinden...
Vom STK500?
hmm... der CS des Mega selbst ist tristate und unbeschaltet...
 
...Eigenartigerweise geht die CS-Leitung ...blablabla... Ich habe überhaupt keine Ahnung, wo das herkommen soll...

nicht lachen!
Beim Mega8 muß natürlich der Stackpointer für die Verwendung von Interrupts und RCALLs initialisiert werden...
(Da krieg ich jetzt bestimmt 'n Bumerang)

So...
klassisches Polling des SPI-Flags sollte in etwa so aussehen:
Code:
.include "m8def.inc"	;Atmega8

LDI R16, high(ramend)
OUT SPH, R16
LDI R16, low(ramend)
OUT SPL, R16			;Stack initialisiert

SBI PORTD, PORTD0		;D0 ist low-aktiver Taster (interner Pullup)
;** SPI-Hardware**
;	B3 - MOSI
;	B4 - MISO
;	B5 - SCK
;	B0 - CS

SBI PORTB, PORTB0		;CS ist High (Pullup)

LDI R16, (1<<DDB3)|(1<<DDB5)|(1<<DDB0)
OUT DDRB, R16			;MOSI, SCK und CS sind Ausgänge

LDI R16, (1<<SPE)|(1<<MSTR)
OUT SPCR, R16			;SPI enabled, Master
						;DORD=0=MSB first
						;CPOL=0
						;CPHA=0
SBI SPSR, SPI2X			;F(sck)=F(osc)/2

;SPI ist bereit

warten:
	SBIC PIND, PIND0
	rjmp warten			;auf Taste warten

	LDI R16, 0x35 		;erstes zu sendendes Byte
	LDI R17, 0x89		;zweites
	RCALL Word_senden

endlos:
	rjmp endlos

Word_senden:
	CBI PORTB, PORTB0			;CS aktiviert
	OUT SPDR, R16				;erstes Byte senden
SPI_high_byte_warten:	
	SBIS SPSR, SPIF
	RJMP SPI_high_byte_warten	;warten bis fertig
	OUT SPDR, R17				;zweites Byte senden
	IN R16, SPDR				;empfangenes Byte laden, SPIF löschen
SPI_low_word_warten:
	SBIS SPSR, SPIF				
	RJMP SPI_low_word_warten	;warten bis fertig	
	IN R17, SPDR				;empfangenes Byte laden, SPIF löschen
	SBI PORTB, PORTB0			;CS deaktiviert
	RET
Der LA sagt dazu:
screenshot2.png
Ok, den CS-Pin könnte man auch vor auslesen des SPDR auf High zurücksetzen. Die Pause zwischen den Bytes ist etwas kürzer.
Es sollte natürlich auch möglich sein, den Controller die 16 Takte anderweitig zu beschäftigen, und dann ohne Polling das 2te Byte ins SPDR zu jagen... morgen vielleicht...
 
Vielen vielen DANK LotadaC :flowers::adore::adore::adore::date:

Ich muss jetzt erstmal sehen das ich mit Assembler überhaupt mal zurechtkomme, ich sagte ja schon das ich bis jetzt
nur mit BASCOM etwas gearbeitet habe.
Bis ich jetzt mal einen Einstig in Assembler gefunden habe dauert ja auch noch etwas Zeit. Deine bemühungen sind echt
SUPER, BITTE BITTE sei mir nicht böse wenn es bei mir etwas dauert bis zu deinen Informationen ein Feedbeck von mir
kommt. Habe diese und auch nächste Woche nicht viel Zeit dann kommt am ende des Monats noch ein Krankenhaus-
aufenhalt hienzu wo ich noch abwarten muss wie lange das dauert. Ich werde auf jedenfall auf deine Informationen
zurückgreifen nur es dauert halt ein wenig länger. Wenn Du noch weitere Informationen für mich hast sage ich bestiemt nicht NEIN! :eek:
So ein LS möcht ich auch noch haben währe das richtige Spielzeug nur leider für mich nicht Bezahlbar !!

Code:
.include "m8def.inc"	;Atmega8

LDI R16, high(ramend)
OUT SPH, R16
LDI R16, low(ramend)
OUT SPL, R16			;Stack initialisiert

SBI PORTD, PORTD0		;D0 ist low-aktiver Taster (interner Pullup)     Soweit verstanden !
;** SPI-Hardware**
;	B3 - MOSI
;	B4 - MISO
;	B5 - SCK
;	B0 - CS

SBI PORTB, PORTB0		;CS ist High (Pullup)                             auch OK!

LDI R16, (1<<DDB3)|(1<<DDB5)|(1<<DDB0)                                          auch OK!
OUT DDRB, R16			;MOSI, SCK und CS sind Ausgänge

LDI R16, (1<<SPE)|(1<<MSTR)
OUT SPCR, R16			;SPI enabled, Master                           auch OK!    
						;DORD=0=MSB first                     auch OK!
						;CPOL=0                                auch OK!
						;CPHA=0                               warum hier CPHA=0
SBI SPSR, SPI2X			;F(sck)=F(osc)/2                      Osc/2 OK vorgehensweise ??

;SPI ist bereit

warten:
	SBIC PIND, PIND0                                                               
	rjmp warten			;auf Taste warten                              auch OK! 

	LDI R16, 0x35 		;erstes zu sendendes Byte
	LDI R17, 0x89		;zweites
	RCALL Word_senden                                                          bis hier auch OK! 

endlos:
	rjmp endlos                                                                   muss es hier nicht [rjmp warten] stehen?? 

Word_senden:
	CBI PORTB, PORTB0			;CS aktiviert                     auch OK! 
	OUT SPDR, R16				;erstes Byte senden
SPI_high_byte_warten:	
	SBIS SPSR, SPIF                                                                         ]   
	RJMP SPI_high_byte_warten	;warten bis fertig                                   ]    
	OUT SPDR, R17				;zweites Byte senden                       ]      
	IN R16, SPDR				;empfangenes Byte laden, SPIF löschen   ]     hier muss ich noch
SPI_low_word_warten:                                                                            ]     schauen was da so 
	SBIS SPSR, SPIF				                                                   ]      abgeht, muss leider 
	RJMP SPI_low_word_warten	;warten bis fertig	                                       ]      jeden Befehl auch erstmal
	IN R17, SPDR				;empfangenes Byte laden, SPIF löschen  ]      aus einem Buch heraus-
	SBI PORTB, PORTB0			;CS deaktiviert                                   ]      suchen
	RET


Habe hier mal Versucht aufzuzeigen wie weit ich das noch nachvolziehen kann, ist im momment noch nicht das aller
meiste, möcht auch zeigen dass ich mich damit beschäftige. Habe leider noch Null Ahnung von Assembler, werde es aber bestmöglichst versuchen damit klarzukommen!! :confused::confused:

Muss jetzt auch erstmal auf die 2Meter !!!
 
Hi Uwe
ich hoffe, dein Programmkonstrukt ist nur ein abgespeckter Auszug. Von
Code:
Endlos:
RJmp Endlos
und der Programmarbeit in ISR halte ich gar nichts. Im Prinzip sollen ISR klein sein. Lies mal meinen Beitrag zu "Startproblem mit AtTiny45". Vielleicht hilft dir auch "keine Angst vor Assembler" in FAQ. Trenne Interrupt sauber vom Programm und schaffe Schnittstellen. Dann blickst du auch nach Wochen noch durch dein Programm.
Gruß oldmax
 
@oldmax:
Und wie hältst Du einen Microcontroller an, wenn das komplette Programm beendet ist? Das ist nichts anderes als 'ne leere Hauptprogrammschleife. Ob ich das Label da Main, Hauptprogramm oder schnurzdidudel nenne, ist doch vollkommen egal.
Und wo ist Dir die ISR der ersten Version zu lang? Es steht ein einziger Befehl drin (nebenbei gesagt ein ein-Takt-Befehl).
Das Trennen ist es ja, was ihm zuviel Zeit kostet - deswegen sucht er ja 'ne alternative zum üblichen Weg in Bascom. Er will ja (warum auch immer) keine Pause zwischen den beiden Bytes haben. Deswegen habe ich eben kurz skizziert, wie man das SPI zum versenden von words verwenden könnte (es geht als gar nicht um das ganze Programm,
sondern nur um das Senden der beiden Bytes). Als erstes die Version mit verwendung des SPI-Interruptes. Diese hat nämlich die längste Reaktionszeit
(Byte fertig=IRQ Befehl beenden->Programmadresse auf den Stack und Sprung in die IVT->Sprung zur ISR ->Arbeitscode). Bei einem Controller mit 2-word-IVT hätte man hier(!) das OUT und das RET sogar in die IVT schreiben können, aber selbst dann wäre die Pause noch da.
In der 2ten Version wird das SPI-fertig-Flag gepollt. hier ist die Pause etwas kleiner, aber natürlich immer noch vorhanden. Logisch, der Controller wartet ja nicht wirklich auf das Flag, sondern hopst mehr oder weniger auf der Stelle. Somit verbraucht er also zwischen dem letzten Bit von Byte1 (wo das Flag gesetzt wird) und dem beginn des 2ten Bytes noch Zeit für ein SBIS. Wenn das Flag gerade beim RJMP kommt, kommt der auch noch dazu.
Da die Taktanzahl, die das Senden eines Bytes dauert konstant ist, könnte man auch ausrechnen, wo das Flag in der Schleife fällt (wenns auf das Tempo ankommt, dürfen eh im Hintergrund keine Interrupts dazwischenfunken) - ich hab mir die Mühe gespart.
Und damit steht auch die dritte Version fest. Die SPI-Hardware sendet byteweise, also 8 bits. Da wir diese "was haste-was kannste" laufen lassen, also der SPI mit halber Systemtaktfrequenz läuft, benötigt das versenden eines Bytes im Hintergrund 16 Takte. Zwischendurch muß eventuell noch das zweite Byte aus dem SRAM geladen werden (falls das letztendlich in Bascom eingebunden werden soll). Die restlichen Takte würde oldmax jetzt vielleicht noch mit sinnigem code füllen wollen (+ dem dazu nötigen Verwaltungsoverhead) - zum testen reichen NOPs. damit sollte sich die Pause eigentlich eliminieren lassen. Natürlich muß das ganze Senden dann atomar erfolgen (zumindest bis zum Start des 2ten Bytes, wobei man sich dann irgendwann um das SPIF kümmern müßte (spätestens vor dem Senden des nächsten Words)).

@Uwe:
Du kannst ja auch bei BASCOM bleiben, und den (dann) entscheidenden Teil in Assembler in Bascom einsetzen. Ob sich die hier konkret angewendete Initialisierung des SPI in Bascom mit einem irgendwie gearteten Config-Befehl bewirken läßt, hab ich noch nicht nachgesehen... im Zweifelsfall geht das aber auch wie hier direkt über die Register...

Zu Deinen Anmerkungen:
Code:
LDI R16, (1<<SPE)|(1<<MSTR)
OUT SPCR, R16
hier wird das Byte 0b01010000 in das SPI-Kontrollregister geschrieben [SPIE|SPE|DORD|MSTR|CPOL|CPHA|SPR1|SPR0]
SPI-Interrupt aus
SPI enabled
MSB first
Master-Mode
CPOL=0
CPHA=0->hab ich willkürlich so gewählt - CPOL, CPHA und DORD müssen natürlich auf den konkreten Empfänger angepaßt werden. Die Reihenfolge der Bytes ebenso
SPR1..0=00(binär) -> SPI-Prescaler=4
Code:
SBI SPSR, SPI2X			;F(sck)=F(osc)/2                      Osc/2 OK vorgehensweise ??
Hier wird direkt (SPSR erlaubt das) das "Double SPI Speed Bit" (SPI2X in SPSR) gesetzt, welches (oh welch Überraschung) den SPI-Takt verdoppelt. oder eben den Teiler halbiert.
Code:
endlos:
	rjmp endlos                                                                   muss es hier nicht [rjmp warten] stehen??
Nein - hier ist schon alles vorbei - hier hopst er nur noch auf der Stelle, damit er nicht Flashtechnisch ins Nirvana rennt.
Der letzte Block ist das eigentliche Senden.
-am Anfang wird CS runtergesetzt, am Ende wieder rauf. sollte klar sein
-die beiden zu senden den Bytes hatten wir vorher in R16 und R17 geparkt.
-als erstes wird (OUT SPDR, R16) das erste Byte ins SPI-Datenregister geschrieben. Dieser Schreibzugriff löst in der HArdware den Transfer aus (siehe Datenblatt zu SPDR.
-Danach wird mit dem label, dem SBIS (skip if bit in IO-register is set) und dem RJMP (relative jump) eine Warteschleife aufgebaut (RJMP läßt immer wieder zurück zum label springen, erst wenn des SPIF im SPI-Statusregister gesetzt ist, wird der RJMP übersprungen, wodurch die Schleife verlassen wird)
-jetzt wird analog das 2te byte aus R17 ins SPDR geschrieben (und damit das Senden gestartet) - wir behalten aber im Kopf, daß das SPIF weiterhin gesetzt ist/bleibt - darum kümmern wir uns jetzt
-liest man das SPDR, wird der Inhalt des Recieve-Puffers ausgelesen - wir schreiben diesen nach R16. (siehe SPDR im Datenblatt). Wie man der Erklärung zum SPIF (in SPSR) aus dem Datenblatt weiterhin entnehmen kann, wird dadurch außerdem das SPIF gelöscht (SPSR bei gesetzem SPIF lesen ist ja quasi die Abbruchbedingung unserer Schleife da oben gewesen)
-somit können wir also wie beim ersten mal das SPIF pollen (Schleife mit label, SBIS und RJMP), danach wollen wir kein weiteres Byte senden (also hier kein OUT nach SPDR), wir lesen aber noch das empfangene 2te Byte nach R17 (IN), wodurch auch hier das SPIF gelöscht wird.

-das hochsetzen von CS hatte ich ja oben angesprochen
-RET sollte klar sein (return - das ganze wird ja mit rcall als subroutine/Prozedur aufgerufen - die muß natürlich irgendwann beendet werden bzw die Rückkehr ins Hauptprogramm auslösen)
 
Und hier die Version mit "no operations":
Code:
.include "m8def.inc"	;Atmega8
LDI R16, high(ramend)
OUT SPH, R16
LDI R16, low(ramend)
OUT SPL, R16			;Stack initialisiert
SBI PORTD, PORTD0		;D0 ist low-aktiver Taster (interner Pullup)
;** SPI-Hardware**
;	B3 - MOSI
;	B4 - MISO
;	B5 - SCK
;	B0 - CS
SBI PORTB, PORTB0		;CS ist High (Pullup)
LDI R16, (1<<DDB3)|(1<<DDB5)|(1<<DDB0)
OUT DDRB, R16			;MOSI, SCK und CS sind Ausgänge
LDI R16, (1<<SPE)|(1<<MSTR)
OUT SPCR, R16			;SPI enabled, Master
						;DORD=0=MSB first
						;CPOL=0
						;CPHA=0
SBI SPSR, SPI2X			;F(sck)=F(osc)/2
;******SPI ist bereit******

;wir benötigen 2 Bytes, hier als Variable im SRAM angelegt
.dseg
.org SRAM_START
data_addr: .byte 2
.cseg
	.equ data=0xF6A7 ;Inhalt
	LDI R16, high(data)
	STS data_addr, R16
	LDI R16, low(data)
	STS data_addr+1, R16	;irgendwelche Daten rein
warten:
	SBIC PIND, PIND0
	rjmp warten			;auf Taste warten
	
	RCALL FastSpiWord	;subroutine aufrufen

endlos:
	rjmp endlos			;Ende

FastSpiWord:
	PUSH R16					;R16 sichern
	LDS R16, data_addr			;erstes Byte aus SRAM laden
	CLI							;Interrupts aus
	CBI PORTB, PORTB0			;CS aktiviert
	OUT SPDR, R16				;erstes Byte senden
	NOP							;	1
	NOP							;	2
	LDS R16, data_addr+1		;Byte2 Laden	3 und 4
	NOP							;	5
	NOP							;	6
	NOP							;	7
	NOP							;	8
	NOP							;	9
	NOP							;	10
	NOP							;	11
	NOP							;	12
	NOP							;	13
	NOP							;	14
	NOP							;	15
	NOP							;	16
	NOP							;	17
	OUT SPDR, R16				;zweites Byte senden
	IN R16, SPSR				;SPSR bei gesetztem SPIF lesen
	IN R16, SPDR				;empfangenes Byte laden, SPIF löschen
	SEI							;Interrupts wieder frei
	STS data_addr, R16			;Byte ins SRAM
warte_auf_SPIF:
	SBIS SPSR, SPIF				
	RJMP warte_auf_SPIF			;warten bis fertig
	SBI PORTB, PORTB0			;CS deaktiviert	
	IN R16, SPDR				;empfangenes Byte laden, SPIF löschen
	STS data_addr+1, R16		;Byte ins SRAM
	POP R16						;R16 wiederhergestellt
	RET							;zurück zum Hauptprogramm
Resultat:screenshot3.png
Die Pause nochmal halbiert... (bei einem NOP weniger, kommt das 2te Byte nicht mehr raus, das Clock-Signal aber schon. 'Ne Write-Collision?)
Mehr fällt mir dazu nicht ein...
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)