Hallo zusammen, ich habe bereits das ganze Forum nach einer Lösung für mein Problem abgesucht, bin aber trotzdem noch nicht viel weitergekommen. Und zwar habe ich folgendes Problem: Ich bin unter Linux <> SPI ein absoluter Newbie, alles ist für mich fast völliges Neuland, deshalb Erklärungen bitte so angeben, dass sie auch ein Doofy versteht! Mein Problem ist: Ich muss unter Linux und einem i.MX6-Prozesssor(= Master) einen AD-Wandler (MAX11209 = Slave) ca. 1x pro Sekunde über die SPI-Schnittstelle auslesen (Poll-Betrieb). Softwaremäßig habe ich mich an das im Web erhältliche Beispiel gehalten (spidev_test.c). Wenn ich das Programm starte, MOSI mit MISO verbinde, CS auf Low lege funktioniert alles prima. Wenn ich allerdings den AD-Wandler abfragen will, geht alles auf 'nogo'. Die Initialisierung des Wandlers sowie die Abfrageroutine scheinen in Ordnung zu sein. Dies habe ich an Hand eines SPI-Programmes für den NXP LPC2368 überprüft. Hier funktioniert alles mit den gleichen Parametern einwandfrei. Meine Vorgehensweise ist folgende: Ich initialisiere den ADC, starte den Wandler und warte auf das Ready-Bit des Wandlers. Wenn dieses 'High' ist, frage ich den aus 3 Bytes bestehenden AD-Wert ab. Und hier beginnt mein Problem: ich erhalte vom ADC keine vernünftige Antwort. Alle Befehle und Werte werden m. E. einwandfrei und richtig über die Schnittstelle gesendet (habe ich mehrfach kontrolliert), aber das Ready-Flag bzw. Daten kommen trotzdem nicht bzw. nur sporadisch ein High-Signal mit sehr unterschiedlicher LÄnge. Der Wandler wurde bereits mehrfach getauscht und funktioniert einwandfrei. Da ich senden kann und auch auf dem Scope etwas sehe, scheint der SPI-Treiber auch richtig in Linux eingebunden zu sein. Ich vermute, dass es mit der 'ioctl'-Routine zu tun hat. Deren Funktionsweise ist mir schleierhaft, wie muss z. B. die Initialisierung sein, wenn ich 1 Byte senden, aber 3 Byte empfangen will? Habe im Web bisher noch keine vernünftige Erklärung gefunden. Die Anzahl der zu sendenden Byte kann ich an die ioctl übergeben, aber wie mache ich die Größe des Empfangsbuffers variabel? Wartet die ioctl so lange, bis Daten agekommen sind, und wie lange wartet sie (Anzahl der Bytes oder eine Zeitraum)? Sie muss doch mindestens so lange warten, bis die Wandlung fertig ist und die Daten übertragen sind? Oder muss ich(!) so lange warten, bis die Daten im Eingangsbuffer sind und diesen dann explizit abfragen? Wenn ja, wie? Wie ich auf dem Scope sehe, bedient die ioctl den CS ebenfalls. Stimmt das Default-Timing (Delay = 0) oder muss ich über das 'Delay' einen anderen Wert einstellen? (Bei einem Clock von 2 MHz geht der CS ca. 10 µs vor Sendebeginn auf Low, und ca. 15-20 µs nach dem Senden auf High. Ich habe bereits einen GPIO zur Erzeugung des CS verwendet, leider erfolglos. Die Einstellungen der SPI für den ADC (Phase, Polarität, MSB-First usw. stimmen m. E. alle). Ich daddle jetzt schon über 2 Wochen mit diesem Problem herum, komme aber nicht weiter und bin kurz vor der Verzweiflung. Am liebsten wäre mir, wenn mir jemand von Euch eine (annähernd) fertige Routine, auch gegen Kostenerstattung, zur Verfügung stellen könnte. Wenn mir also jemand helfen kann oder will und evtl. nähere Infos braucht, bitte bei mir melden. Mein Problem ist für viele von Euch wahrscheinlich ein 'Problemchen', aber für mich (noch) eine echte Herausforderung. Für Eure Hinweise und Tips schon mal im Voraus vielen Dank! Gruß Roland
Roland K. schrieb: > Ich vermute, dass es mit der 'ioctl'-Routine zu tun hat. Deren > Funktionsweise ist mir schleierhaft, wie muss z. B. die Initialisierung > sein, wenn ich 1 Byte senden, aber 3 Byte empfangen will? Du kannst nur genauso viel Bits empfangen wie du sendest! Für jedes Bit das du sendest, Empfängst du gleichzeitig ein Bit. Das ist elementares verhalten von SPI. Must du mal im Datenblatt des AD-Wandlers nachschauen, meistens ist das erste Byte was der Slave sendet ein Statusregister, denn der Slave muss ja schon was senden, noch bevor er weiß was der Master sendet, ist ja gleichzeitig!
Roland K. schrieb: > wie muss z. B. die Initialisierung > sein, wenn ich 1 Byte senden, aber 3 Byte empfangen will? Wer über SPI drei Bytes empfangen will muss drei Bytes senden. > oder muss ich über das 'Delay' einen > anderen Wert einstellen? (Bei einem Clock von 2 MHz geht der CS ca. 10 > µs vor Sendebeginn auf Low, und ca. 15-20 µs nach dem Senden auf High. Datenblatt lesen. Seite 4 und ab Seite 14 die Bilder 5 bis 7. > Am liebsten wäre mir, wenn mir jemand von Euch eine (annähernd) fertige > Routine, auch gegen Kostenerstattung, zur Verfügung stellen könnte. Ah, Hausarbeit. Na dann viel Spaß noch.
Bin nochmal den Quellcode für den NXP-Prozessor durchgegangen. Habe hier
völlig übersehen, dass ich für jedes zu empfangende Byte ein sog.
'Dummy-Byte' rauschicke.
Manchmal ist man halt völlig hirnvernagelt, besonders dann, wenn man zu
lange über ein Problem brütet.
Ich nehme mal an, dass ich das mit dem ioctl genauso machen muss,
ungefähr so:
void spi_send (char test) // test = z.B. der Lesebefehl, 1 Byte
{
int ret;
struct spi_ioc_transfer tr =
{
.tx_buf = (unsigned long)test,
.rx_buf = (unsigned long)rx,
.len = ARRAY_SIZE(tx),
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};
ret = ioctl(spi0_fd, SPI_IOC_MESSAGE(1), &tr);
spi_receive(3); // 3 Bytes abfragen
return;
}
void spi_receive(int count) // Count = Anzahl der zu empfangenden
Bytes
{
int ret;
int i;
char spi_read_data[count];
char dummy;
dummy = 0x00; // Dummy-Byte
struct spi_ioc_transfer tr =
{
.tx_buf = (unsigned long)dummy,
.rx_buf = (unsigned long)rx,
.len = ARRAY_SIZE(tx),
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};
for(i = 0; i < count;i++)
{
ret = ioctl(spi0_fd, SPI_IOC_MESSAGE(1), &tr);
spi_read_data(i) = rx;
return;
}
Liege ich so richtig?
Danke für Deine Antwort. Die Zeiten für die Steuerung des CS habe ich bestimmt schon 100x durchgelesen, aber anscheinend nicht mehr registriert. Bin schon ganz wirr im Kopf.
Christian K. schrieb: > Roland K. schrieb: >> Ich vermute, dass es mit der 'ioctl'-Routine zu tun hat. Deren >> Funktionsweise ist mir schleierhaft, wie muss z. B. die Initialisierung >> sein, wenn ich 1 Byte senden, aber 3 Byte empfangen will? > > Du kannst nur genauso viel Bits empfangen wie du sendest! > > Für jedes Bit das du sendest, Empfängst du gleichzeitig ein Bit. Das ist > elementares verhalten von SPI. > > Must du mal im Datenblatt des AD-Wandlers nachschauen, meistens ist das > erste Byte was der Slave sendet ein Statusregister, denn der Slave muss > ja schon was senden, noch bevor er weiß was der Master sendet, ist ja > gleichzeitig! Hallo Christian, hatte meinen Text flasch gepostet. Bin halt selten hier im Forum. Bin nochmal den Quellcode für den NXP-Prozessor durchgegangen. Habe hier völlig übersehen, dass ich für jedes zu empfangende Byte ein sog. 'Dummy-Byte' rauschicke. Manchmal ist man halt völlig hirnvernagelt, besonders dann, wenn man zu lange über ein Problem brütet. Ich nehme mal an, dass ich das mit dem ioctl genauso machen muss, ungefähr so: void spi_send (char test) // test = z.B. der Lesebefehl, 1 Byte { int ret; struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)test, .rx_buf = (unsigned long)rx, .len = ARRAY_SIZE(tx), .delay_usecs = delay, .speed_hz = speed, .bits_per_word = bits, }; ret = ioctl(spi0_fd, SPI_IOC_MESSAGE(1), &tr); spi_receive(3); // 3 Bytes abfragen return; } void spi_receive(int count) // Count = Anzahl der zu empfangenden Bytes { int ret; int i; char spi_read_data[count]; char dummy; dummy = 0x00; // Dummy-Byte struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)dummy, .rx_buf = (unsigned long)rx, .len = ARRAY_SIZE(tx), .delay_usecs = delay, .speed_hz = speed, .bits_per_word = bits, }; for(i = 0; i < count;i++) { ret = ioctl(spi0_fd, SPI_IOC_MESSAGE(1), &tr); spi_read_data(i) = rx; return; } Liege ich so richtig?
bezüglich "struct spi_ioc_transfer"
tx_buf und rx_buf sind pointier auf Arrays
und len gibt an wie lang die Arrays sind.
#include<stdint.h>
uint8_t tx[3] = 0;
uint8_t rx[3] = 0;
struct spi_ioc_transfer tr = {
.tx_buf = tx,
.rx_buf = rx,
.len = 3,
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = 8,
};
wenn mich nicht alles täuscht musst du die Adresse des Empfangs bzw. Sendebuffers in rx_buf und tx_buf ablegen, gecastet nach unsigned long, also: int foo, bar; tx_buf= (unsigned long)&foo; rx_buf= (unsigned long)&foo; bei arrays ist die Verwendung ohne index bereits der pointer auf das erste element, also: uint8_t foo[3]; tx_buf= (unsigned long)foo;
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.