Hallo zusammen!
Ich verwende gerade ein Embedded System (Zybo) und habe ein Problem bei
der Prozessorprogrammierung!
Ich will in das gemappted Register (vom XADC) einen Wert schreiben
(verwende Petalinux), dieser wird aber nicht reingeschrieben.
Ich verwende folgenden Befehl (mit Überprüfung):
Tja, dann musst du wohl tiefer reinsteigen. Ich fürchte, dass es nicht
so viele Leute gibt, die sich mit dieser Plattform auskennen.
Gibt's vielleicht irgendwelche Kernelmeldungen in den Logs? Kann es
sein, dass dein Register irgendeine Form von Schreibschutz besitzt?
Btw., du solltest natürlich unbedingt den Rückkehrwert von mmap()
testen, bevor du auf die Region zugreifst. Ist allerdings vermutlich
nicht dein Problem hier.
Vielen Dank für die schnelle Antwort!
Den Rückgabewert von mmap() habe ich schon getestet und das läuft
soweit.
Ich hab natürlich auch schon eine Recherche gemacht, aber nichts
gefunden.
Einen Fehler beim Schreiben erhalte ich auch nicht.
Finde ich sehr komisch....
Prinzipiell ist die Vorgehensweise schon korrekt so, wenn man mit
memory mapping auf sowas zugreifen muss. Allerdings habe ich selbst
solche Aktionen das letzte Mal vor mehr als 20 Jahren gemacht, als
die PCs noch deutlich einfacher strukturiert waren (ISA-Adressraum).
mmap() sieht natürlich normalerweise nur virtuelle Adressen, wie diese
auf physische Adressen umgesetzt werden, entscheidet das OS darunter.
Dieser Teil scheint jedoch beim TE zu funktionieren, sein Problem ist
ja nur, dass sich in der Hardware dabei nichts ändert, er also seinen
geschriebenen Wert nicht rücklesen kann.
Ich hab jetzt gerade mal geschaut, was in dem Register passiert und die
Werte variieren. Bedeutet, den Wert den ich in das Register schreibe,
ist sofort wieder weg.
derFragende schrieb:> Bedeutet, den Wert den ich in das Register schreibe, ist sofort wieder> weg.
Naja, für memory-mapped IO ist das ja erstmal nicht völlig ungewöhnlich:
ist halt kein Speicher, sondern ein IO-Register eines Peripherals.
Da wirst du dich wohl durch die Details selbst durchbeißen müssen.
Schau dir mal einen größeren Bereich an Adressen an und versuche, ob
du da irgendeinen Zusammenhang zur Registeranordnung gemäß Dokumentation
herstellen kannst.
Ich meinte damit auch nicht die Vorgehensweise ändern. Vielleicht gibt's
ja schon einen Treiber für eine andere Hardwarekomponente, die das so
macht.
Dort könnte man dann Schritt für Schritt vergleichen und ggf. abschauen.
Als nicht-user-mode Programm könnte man das mit Pointern auf die
Adressen lösen.
Bsp:
1
volatilechar*dst=(volatilechar*)0xADD;
Je nach gewünschter Datenbreite int, short, ... verwenden, bzw uint8_t,
uint16_t, ...
Jörg W. schrieb:> Vielleicht, weil man auf einer ungeraden Adresse nicht mit einem> 16bittigen Zugriff arbeiten kann?
Ich sehe da keinen ungraden Offset. Die 0x49 wird zu einem uint16_t*
addiert - dabei multipliziert der Compiler automagisch mit 2.
Eventuell könnte das auch ein Problem sein (falscher Offset)? Ich finde
jedenfalls auf die Schnelle kein Datenblatt von dem ADC.
Andererseits sind ADCs von SOCs gerne mal so komplex (DMA & Co), dass
man die mit einem Kernel Modul ansteuern will.
Safari schrieb:> Als nicht-user-mode Programm könnte man das mit Pointern auf die> Adressen lösen.
Im Kontext eines VM-Betriebssystems wäre das dann allerdings kein
"Programm" mehr, sondern ein "Treiber", den man dafür schreiben
müsste.
MMIO über mmap() hat den Vorteil, dass man erstmal flexibler ist,
da man im Userland herumopern kann. Wenn das Mapping auf das Gerät
prinzipiell funktioniert, dann ist nicht davon auszugehen, dass durch
die Verlagerung des Codes in den Kernel irgendwas anders oder besser
wird. Es lässt sich dann nur schwieriger debuggen.
Jörg W. schrieb:> Wenn das Mapping auf das Gerät> prinzipiell funktioniert, dann ist nicht davon auszugehen, dass durch> die Verlagerung des Codes in den Kernel irgendwas anders oder besser> wird. Es lässt sich dann nur schwieriger debuggen.
Wo zieht man die Grenze zwischen Programm und Treiber? Also was wird
Programm und was sollte besser ein Treiber werden?
Bei PCs ist das, denke ich, noch einfacher als bei Einzelanfertigungen,
geringen Stückzahlen und Bastelei.
Aber im Sinne von "universal" würde ich ein /dev/adc doch besser finden,
als wenn jedes mögliche Programm direkt im Speicher hantiert.
<nicht ernst nehmen> Wir könnten ja CPM-like Sprungtabellen zu den
Helferroutinen anlegen... </...>
@debugging: Als ich angefangen habe, mir anzusehen, wie Kernel-Module
geschrieben werden und selbst herumprobiert habe, stellte ich schnell
fest, dass mein PC eine Reset-Taste braucht.
Also mir fehlt der Schreibzugriff zu den Config-Registern.
Der Wert davor ist 0, ich schreibe
1
xadc_addr[0x40|=0x8200;
anschließend steht weiterhin der Wert 0 im Register.
Gibts da eine Möglichkeit Schreibzugriff zu erhalten.
Hier wäre das Datenblatt (aufgrund einer Nachfrage)
https://www.xilinx.com/support/documentation/user_guides/ug480_7Series_XADC.pdf
Bzgl. des ändernden Werte, ich habe gerade das Statusregister mit einem
internen Werteregister verwechselt.
derFragende schrieb:> Nur blöd, dass ich den Schreibzugriff im mmap() aktiviert habe.
Trotzdem muss der zugrunde liegende mem-Treiber den ja auch und vor
allem für den von dir gewünschten Adressbereich implementieren.
Da musst du wohl mal in dessen Treiberquellcode reingucken.
Jörg W. schrieb:> Da musst du wohl mal in dessen Treiberquellcode reingucken.
Ich glaube, dafür könnte man Strace nehmen, verfolgen was aufgerufen
wird und dann die jewiligen Funktionen im Quellcode betrachten, oder
liege ich da falsch?
Da liegst du falsch. Der einzige Syscall ist ja das mmap(), danach
gehen alle Zugriffe über die auf diese Weise gemappte Region.
Da muss man schon den Sourcecode von /dev/mem ansehen.
also ich hab jetzt mal bei mmap den offset auf 0 gesetzt und geschaut.
Jetzt hält es die Werte, die ich reinschreibe in die Register.
Aber ich brauch den offset....
derFragende schrieb:> also ich hab jetzt mal bei mmap den offset auf 0 gesetzt und geschaut.> Jetzt hält es die Werte, die ich reinschreibe in die Register.> Aber ich brauch den offset....
Dann rechne ihn beim zugriff drauf. mmap() und Konsorten arbeiten über
Page mapping und können daher nur Offsets in Blöcken der Pagegröße
deines Systems (typischer Wert: 4k) verarbeiten.
Wenn die ADC-Adresse nicht an einer Pagegrenze liegt, geht das durchaus
mal schief.
danke!
Ich hab schon beim Schreiben der Register den offset reingerechnet. Dann
gibts aber eine exception.
Hat jemand eine Ahnung wie man das ggf. erweitern könnte?
derFragende schrieb:> Dann> gibts aber eine exception.
Ich weiß nicht genau, was du mit "Exception" meinst.
Schmiert das Programm ab?
Kannst du den ganzen Code posten bzw. die relevanten Teile mit der
Information, welche Werte die Defines für die Adressen haben?