Üben Sie in der Arbeit mit Custom-Reifen des Redd-Komplexes

Im letzten Artikel haben wir uns mit der Theorie des Managements von tausend kleinen Dingen im Redd-Komplex befasst, aber um das Volumen nicht zu vergrößern, haben wir die Übung beim nächsten Mal verschoben. Es ist an der Zeit, praktische Experimente durchzuführen. Diejenigen, die den Redd-Komplex nicht verwenden, werden in diesem Artikel auch nützliche Informationen finden, nämlich die Methodik zum Senden von Vendor-Befehlen an USB-Laufwerke von Linux, da der STM32-Controller im Komplex, wie bereits erwähnt, die Funktion eines SD-Lesegeräts übernimmt, d. H. fahren.




Laufwerksklassifizierung nach Befehlssystemen


Bei der Arbeit mit Laufwerken sollten Sie zwischen einer physischen Schnittstelle und einem Befehlssystem unterscheiden. Insbesondere CD / DVD / BD-Laufwerke und andere Optiken. Traditionell werden sie an ein SATA-Kabel (früher IDE) angeschlossen. Aber speziell auf dieser Leitung laufen im laufenden Betrieb nur PACKET-Befehle, in deren Datenblock nach einem völlig anderen Prinzip codierte Befehle abgelegt sind (von welchem ​​werden wir gleich erfahren). Deshalb werden wir jetzt nicht so sehr über Drähte sprechen, sondern über die Teams, die in ihnen laufen. Ich kenne drei gängige Befehlssysteme für die Arbeit mit Antrieben.

  • MMC Es wird von SD-Karten verstanden. Ehrlich gesagt ist dies für mich das mysteriöseste Befehlssystem. Wie man sie einreicht, scheint klar, aber wie man das Laufwerk verwaltet, ohne das Dokument sorgfältig zu lesen, das viele Übergangsdiagramme enthält - ich bin immer verwirrt. Zum Glück stört uns das heute nicht mehr, denn obwohl wir mit einer SD-Karte arbeiten, arbeitet der STM32-Controller im „Black-Box“ -Modus damit.
  • ATA Diese Befehle wurden zunächst auf dem IDE-Bus und dann auf SATA ausgeführt. Ein wunderbares Befehlssystem, aber wir erwähnen heute auch nur, dass es existiert.
  • SCSI Dieses Befehlssystem wird auf einer Vielzahl von Geräten verwendet. Betrachten Sie die Verwendung in Laufwerken. Dort laufen heute SCSI-Teams zunächst über die Leitungen des SAS-Busses (übrigens sind mittlerweile auch SSDs mit SAS-Schnittstelle in Mode). Seltsamerweise funktionieren optische Laufwerke, die physisch an den SATA-Bus angeschlossen sind, auch über SCSI-Befehle. Auf dem USB-Bus werden die Befehle auch im SCSI-Format abgelegt, wenn nach dem Massenspeichergerätestandard gearbeitet wird. Der STM32-Mikrocontroller ist über den USB-Bus mit dem Redd-Komplex verbunden. In unserem Fall folgen die Befehle dem folgenden Pfad:



Vom PC zum Controller über USB liegen die Befehle im SCSI-Format vor. Der Controller codiert die Befehle gemäß der MMC-Regel und sendet sie über den SDIO-Bus. Wir müssen aber ein Programm für den PC schreiben, damit die Teams uns im SCSI-Format lassen. Sie werden vom Massenspeichergerät-Gerätetreiber vorbereitet, mit dem wir über den Dateisystemtreiber kommunizieren. Ist es möglich, Anforderungen mit anderen Geräten für diese Anforderungen zu mischen? Lass es uns richtig machen.

Details zum SCSI-Befehlssystem


Wenn Sie sich der Sache formal nähern, finden Sie die Beschreibung des SCSI-Standards auf t10.org, aber wir sind realistisch. Niemand wird es freiwillig lesen. Genauer gesagt, nicht seine, sondern ihre: Es gibt einen ganzen Stapel offener Dokumente und einen Berg geschlossener Dokumente. Nur ein extremer Bedarf lässt Sie in die komplexe Sprache eintauchen, in der der Standard geschrieben ist (dies gilt übrigens für den ATA-Standard auf t13.org). Es ist viel einfacher, die Dokumentation für echte Laufwerke zu lesen. Es ist in einer lebendigeren Sprache geschrieben, und hypothetische, aber nicht wirklich verwendete Teile werden daraus herausgeschnitten. Während der Vorbereitung des Artikels stieß ich auf ein ziemlich neues Dokument (2016) aus dem SCSI Commands Reference Manual von Seagate (direkter Link www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf), aber wie immer Ich weiß nicht, wie lange sie leben wird. Ich denke, wenn jemand dieses Befehlssystem beherrschen möchte, sollte er mit diesem Dokument beginnen. Wir erinnern uns nur, dass SD-Lesegeräte eine noch kleinere Teilmenge der Befehle aus dieser Beschreibung implementieren.

Kurz gesagt, eine Befehlseinheit mit einer Länge von 6 bis 16 Bytes wird an das Laufwerk gesendet. Ein Datenblock kann entweder vom PC zum Laufwerk oder vom Laufwerk zum PC an den Befehlsblock angehängt werden (der SCSI-Standard ermöglicht auch den bidirektionalen Austausch, für das Massenspeichergerät über USB ist jedoch nur ein Block zulässig, was bedeutet, dass die Richtung nur einer ist). Im Anweisungsblock ist das erste Byte immer der Befehlscode. Die verbleibenden Bytes sind die Argumente. Die Regeln zum Ausfüllen der Argumente werden ausschließlich durch die Details der Implementierung des Befehls beschrieben.



Zuerst habe ich viele Beispiele in den Artikel eingefügt, aber dann habe ich festgestellt, dass sie das Lesen erschweren. Daher empfehle ich jedem, die Felder des Befehls READ CAPACITY (10) aus Tabelle 119 des Seigate-Dokuments und die Felder des Befehls READ (10) aus Tabelle 97 desselben Dokuments zu vergleichen (siehe Link oben). Wer keine Verbindung gefunden hat - sei nicht beunruhigt. Das wollte ich zeigen. Neben dem Feld „Befehl“ im Null-Byte hängt der Zweck aller Felder ausschließlich von den Besonderheiten eines bestimmten Befehls ab. Sie müssen das Dokument immer öffnen und den Zweck der verbleibenden Felder darin untersuchen.

Also:

  • Um mit dem Antrieb zu kommunizieren, sollten Sie einen Befehlsblock mit einer Länge von 6 bis 16 Bytes bilden (abhängig vom Format des Befehls ist die genaue Anzahl in der Dokumentation dazu angegeben).
  • Das wichtigste ist das Null-Byte des Blocks: Er legt den Befehlscode fest.
  • Die verbleibenden Blockbytes haben keinen eindeutigen Zweck. Um zu verstehen, wie diese ausgefüllt werden, sollten Sie die Dokumentation für ein bestimmtes Team öffnen.
  • Ein Datenblock, der zu oder von einem Laufwerk übertragen werden kann, kann an einen Befehl angehängt werden.

Eigentlich ist das alles. Wir haben die Regeln für die Ausgabe von SCSI-Befehlen kennengelernt. Jetzt können wir sie einreichen, es würde eine Dokumentation darüber geben. Aber wie geht das auf Betriebssystemebene?

Linux SCSI-Befehle


Suchen Sie nach dem Zielgerät


Öffnen Sie zum Ausgeben von Befehlen das Festplattengerät. Lass uns seinen Namen finden. Dazu gehen wir genauso vor wie im Artikel über serielle Schnittstellen . Sehen wir uns die Liste der „Dateien“ im Verzeichnis / dev an (denken Sie daran, dass auf Linux-Geräten auch Dateien angezeigt werden und ihre Liste mit demselben ls-Befehl angezeigt wird).

Heute widmen wir uns dem virtuellen Verzeichnislaufwerk:



Wir schauen uns den Inhalt an:



Ein vertrauter Satz verschachtelter Verzeichnisse! Wir versuchen, das Verzeichnis by-id mit der Option –l des Befehls ls zu betrachten , die uns bereits aus dem Artikel über serielle Schnittstellen bekannt ist:



Hervorgehobene Wörter sprechen für sich. Dies ist ein Laufwerk, das die interne SD-Karte des Redd-Komplexes enthält. Großartig! Jetzt wissen wir, dass das Gerät MIR_Redd_Internal_SD dem Gerät / dev / sdb und / dev / sdb1 entspricht . Die, die ohne die Nummer das Laufwerk selbst ist, werden wir damit arbeiten, und mit der Nummer ist es das Dateisystem, das sich auf dem eingelegten Datenträger befindet. Wenn Sie mit einer SD-Karte arbeiten, ist / dev / sdb das Lesegerät und / dev / sdb1 das Dateisystem der eingelegten Karte.

Funktion des Betriebssystems zum Ausgeben von Befehlen


In der Regel werden in jedem Betriebssystem alle nicht standardmäßigen Vorgänge mit Geräten durch direkte Anforderungen an den Treiber ausgeführt. Unter Linux steht die Funktion ioctl () zum Senden solcher Anforderungen zur Verfügung. Unser Fall ist keine Ausnahme. Als Argument übergeben wir die in der Header-Datei sg.h beschriebene SG_IO-Anforderung. Dort ist auch die Struktur sg_io_hdr_t beschrieben , die die Anforderungsparameter enthält. Ich werde nicht die vollständige Struktur angeben, da nicht alle Felder ausgefüllt werden müssen. Ich werde nur das Wichtigste von ihnen geben:

typedef struct sg_io_hdr { int interface_id; /* [i] 'S' for SCSI generic (required) */ int dxfer_direction; /* [i] data transfer direction */ unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ unsigned char mx_sb_len; /* [i] max length to write to sbp */ unsigned short int iovec_count; /* [i] 0 implies no scatter gather */ unsigned int dxfer_len; /* [i] byte count of data transfer */ void * dxferp; /* [i], [*io] points to data transfer memory or scatter gather list */ unsigned char * cmdp; /* [i], [*i] points to command to perform */ unsigned char * sbp; /* [i], [*o] points to sense_buffer memory */ unsigned int timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */ 

Es macht keinen Sinn, Felder zu beschreiben, die in Kommentaren gut dokumentiert sind ( interface_id, dxfer_direction, timeout ). Der Artikel wächst bereits.

Das Feld cmd_len enthält die Anzahl der Bytes im Befehlsblock, und cmdp enthält einen Zeiger auf diesen Block. Sie können nicht auf einen Befehl verzichten, daher darf die Anzahl der Bytes nicht Null sein (von 6 bis 16).

Daten sind optional. Wenn dies der Fall ist, wird die Länge des ausgewählten Puffers im Feld dxfer_len und ein Zeiger darauf im Feld dxferp angegeben. Ein Laufwerk kann physisch weniger Daten als die angegebene Puffergröße übertragen. Die Übertragungsrichtung wird im Feld dxfer_direction angegeben. Gültige Werte für USB-Massenspeichergeräte sind: SG_DXFER_NONE, SG_DXFER_TO_DEV, SG_DXFER_FROM_DEV . In der Header-Datei gibt es noch etwas, aber der Massenspeichergeräte-Standard erlaubt keine physische Implementierung.

Sie können auch die Rückgabe eines erweiterten Fehlercodes ( SENSE ) anfordern . Was es ist, ist im Abschnitt 2.4 des Segate-Dokuments zu finden. Die Länge des zugewiesenen Puffers wird im Feld mx_sb_len angegeben , und der Zeiger auf den Puffer selbst wird im Feld sbp angegeben .

Wie Sie sehen können, ist alles, worüber ich oben gesprochen habe, in dieser Struktur enthalten (und Sie können erweiterte Informationen über den Fehler erhalten). Weitere Informationen zum Arbeiten mit SG_IO- Anfragen finden Sie hier: sg.danny.cz/sg/sg_io.html

Wir senden einen Standardbefehl an das Laufwerk


Nun, wir haben das Format des Befehls herausgefunden, wir haben herausgefunden, an welches Gerät es gesendet werden soll, wir haben herausgefunden, welche Funktion aufzurufen ist. Versuchen wir, einen Standardbefehl an unser Gerät zu senden. Sei dies der Befehl, um den Laufwerksnamen zu erhalten. So wird es im Sigeyt-Dokument beschrieben:



Bitte beachten Sie, dass gemäß der SCSI-Ideologie alle Felder in Standardbefehlen in der Big-Endian-Notation ausgefüllt sind, d. H. Dem höchsten Byte vorwärts. Deshalb füllen wir das Feld mit der Pufferlänge nicht im Format "0x80, 0x00", sondern im Gegenteil - "0x00, 0x80". Dies ist aber in Standardbefehlen. In Sonderfällen ist alles möglich, konsultieren Sie immer die Beschreibung. Eigentlich müssen nur der Befehlscode ( 12h ) und die Länge ausgefüllt werden. Wir fordern eine Seite Null an, und die übrigen Felder sind entweder reserviert oder veraltet oder standardmäßig auf Null gesetzt. Also füllen Sie sie alle mit Nullen.

Wir machen ein Programm, das diesen Befehl gibt:
 #include <cstdio> #include <stdint.h> #include <string.h> #include <fcntl.h> // open #include <unistd.h> // close #include <sys/ioctl.h> #include <scsi/scsi.h> #include <scsi/sg.h> int main() { printf("hello from SdAccessTest!\n"); int s_fd = open("/dev/sdb", O_NONBLOCK | O_RDWR); if (s_fd < 0) { printf("Cannot open file\n"); return -1; } sg_io_hdr_t header; memset(&header;, 0, sizeof(header)); uint8_t cmd12h[] = { 0x12,0x00,0x00,0x00,0x80,0x00}; uint8_t data[0x80]; uint8_t sense[0x80]; header.interface_id = 'S'; //  'S' //  header.cmd_len = sizeof(cmd12h); header.cmdp = cmd12h; //  header.dxfer_len = sizeof(data); header.dxferp = data; header.dxfer_direction = SG_DXFER_TO_FROM_DEV; //     header.mx_sb_len = sizeof(sense); header.sbp = sense; // header.timeout = 100; // 100  int res = ioctl(s_fd, SG_IO, &header;); close(s_fd); return 0; } 



Wie man solche Programme auf einem entfernten Redd-Gerät ausführt, haben wir bereits in einem der vorhergehenden Artikel besprochen. Richtig, ich habe beim ersten Start sofort einen Fehler beim Aufrufen der Funktion open () erhalten . Es stellte sich heraus, dass der Benutzer standardmäßig nicht über ausreichende Rechte zum Öffnen von Plattengeräten verfügt. Welcher von mir ein Linux-Spezialist ist, habe ich oft geschrieben, aber im Netzwerk konnte ich feststellen, dass Sie zur Behebung dieses Problems die Zugriffsrechte auf das Gerät ändern können, indem Sie den folgenden Befehl eingeben:

sudo chmod 666 / dev / sdb

Mein Chef (und er ist ein großartiger Spezialist für dieses Betriebssystem) stellte später jedoch fest, dass die Lösung gültig ist, bis das Betriebssystem neu gestartet wird. Um die Rechte sicher zu erhalten, müssen Sie den Benutzer der Datenträgergruppe hinzufügen.

Welchen dieser beiden Pfade wir auch gehen, setzen Sie, nachdem alles funktioniert hat, einen Haltepunkt auf die Zeile close (s_fd); und überprüfen Sie die Ergebnisse zu dem Zeitpunkt, zu dem sie in der Entwicklungsumgebung erzielt werden (da das Programm nicht einmal eintägig ist, haben wir keine Zeit und Mühe, Mapper einzufügen, wenn die Entwicklungsumgebung uns alles zeigen kann). Der Wert von res ist Null. Das Team hat also fehlerfrei gearbeitet.



Was ist in den Puffer gekommen? Als ich das Wort data in die Adresse für den Speicherauszug eingab, wurde mir mitgeteilt, dass der Wert nicht berechnet werden konnte. Ich musste & data eingeben . . Es ist seltsam, denn Daten sind ein Zeiger. Wenn Sie unter Windows debuggen, funktioniert alles, aber ich stelle nur fest, dass dies folgendermaßen funktioniert: Sehen Sie sich das so erhaltene Ergebnis an:



Richtig, sie haben uns den Namen und die Revision des Laufwerks zurückgegeben. Weitere Informationen zum Format der resultierenden Struktur finden Sie im Segate-Dokument (Abschnitt 3.6.2, Tabelle 59). Der Lesepuffer wurde nicht gefüllt, aber die IOCTL-Beschreibung der Anforderung besagt, dass er nur gefüllt wird, wenn ein Fehler auftritt, der etwas in diesem Puffer zurückgibt. Wörtlich: Sense-Daten (werden nur verwendet, wenn 'status' CHECK CONDITION ist oder (driver_status & DRIVER_SENSE) true ist) .

Benutzerdefiniertes Befehlsformat für Redd Internal SD Drive


Nachdem wir nicht nur die trockene Beschreibung der Norm studiert haben, sondern auch alles in der Praxis ausprobiert haben und fühlen, was ein Befehlsblock ist, können wir bereits das Befehlsformat anzeigen, mit dem Sie nicht standardmäßige Funktionen aufrufen können, die der STM32-Steuerung auf der Platine des Komplexes "geflasht" werden. Ich habe den Befehlscode am Anfang des herstellerspezifischen Befehlsbereichs ausgewählt. Es ist gleich 0xC0. In den Beschreibungen der SCSI-Befehle wird traditionell C0h geschrieben . Die Länge des Befehls beträgt immer 10 Bytes. Das Format des Teams ist einheitlich und in der folgenden Tabelle dargestellt.

ByteTermin
0Befehlscode C0h
1Unterbefehlscode
2Argument arg1. In Little Endian-Notation setzen (Low-Byte-Forward)
3
4
5
6Argument arg2. In Little Endian-Notation setzen (Low-Byte-Forward)
7
8
9

Wie Sie sehen, werden die Argumente in der Little-Endian-Notation angegeben. Auf diese Weise können Sie den Befehl in Form einer Struktur beschreiben und direkt auf seine Felder zugreifen, ohne auf die Byte-Permutationsfunktion zurückgreifen zu müssen. Ausrichtungsprobleme (Doppelwörter in der Struktur haben Offsets, die nicht ein Vielfaches von vier sind) auf x86- und x64-Architekturen sind es nicht wert.

Unterbefehlscodes werden durch die folgende Aufzählung beschrieben:
 enum vendorSubCommands { subCmdSdEnable = 0, // 00 Switch SD card to PC or Outside subCmdSdPower, // 01 Switch Power of SD card On/Off subCmdSdReinit, // 02 Reinitialize SD card (for example, after Power Cycle) subCmdSpiFlashEnable, // 03 Switch SPI Flash to PC or Outside subCmdSpiFlashWritePage, // 04 Write Page to SPI Flash subCmdSpiFlashReadPage, // 05 Read Page from SPI Flash subCmdSpiFlashErasePage,// 06 Erase Pages on SPI Flash (4K block) subCmdRelaysOn, // 07 Switch relays On by mask subCmdRelaysOff, // 08 Switch relays off by mask subCmdRelaysSet, // 09 Set state of all relays by data subCmdFT4222_1_Reset, // 0A Activate Reset State or switch chip to normal mode subCmdFT4222_2_Reset, // 0B Activate Reset State or switch chip to normal mode subCmdFT4222_3_Reset, // 0C Activate Reset State or switch chip to normal mode subCmdFT4232_Reset, // 0D Activate Reset State or switch chip to normal mode subCmdFT2232_Reset, // 0E Activate Reset State or switch chip to normal mode subCmdMAX3421_Reset, // 0F Activate Reset State or switch chip to normal mode subCmdFT4222_1_Cfg, // 10 Write to CFG pins of FT4222_1 subCmdFT4222_2_Cfg, // 11 Write to CFG pins of FT4222_2 subCmdFT4222_3_Cfg, // 12 Write to CFG pins of FT4222_3 }; 

Sie können in Gruppen eingeteilt werden.

Geräte in internen und externen Modus schalten


Die Befehle subCmdSdEnable und subCmdSpiFlashEnable schalten die SD-Karte bzw. den SPI-Flash um. Der Parameter arg1 übergibt einen der folgenden Werte:

 enum enableMode { enableModeToPC = 0, enableModeOutside }; 

Standardmäßig sind beide Geräte an einen PC angeschlossen.

Netzschalter


Das SDIO-Protokoll erfordert während der Initialisierung einige Manipulationen. Manchmal ist es nützlich, die SD-Karte in den Ausgangszustand zurückzusetzen (z. B. wenn die Leitungen zu einem externen Anschluss umgeschaltet werden). Schalten Sie dazu das Gerät aus und wieder ein. Dies kann mit dem Befehl subCmdSdPower erfolgen . Im Argument arg1 wird einer der folgenden Werte übergeben: 0 - Ausschalten, 1 - Einschalten. Denken Sie daran, Zeit zu geben, um die Kondensatoren auf der Stromleitung zu entladen.

Nach dem Einschalten sollte die Karte, sofern sie mit dem PC verbunden ist, neu initialisiert werden. Verwenden Sie dazu den Befehl subCmdSdReinit (er hat keine Argumente).

Arbeiten Sie mit dem SPI-Flash-Laufwerk


Wenn die SD-Karte als volles Laufwerk an das System angeschlossen ist, ist der Zugriffschip in der aktuellen Version sehr begrenzt. Sie können jeweils nur auf die einzelnen Seiten (256 Byte) zugreifen. Die Speicherkapazität des Mikrokreislaufs ist so bemessen, dass der Vorgang selbst bei der Arbeit an der Seite nicht viel Zeit in Anspruch nimmt. Dieser Ansatz vereinfacht jedoch die „Firmware“ des Mikrocontrollers erheblich.

Der Befehl subCmdSpiFlashReadPage liest die Seite. Die Adresse wird im Parameter arg1 angegeben, die Anzahl der zu sendenden Seiten im Parameter arg2. In der aktuellen Version sollte die Anzahl der Seiten jedoch gleich eins sein. Der Befehl gibt 256 Datenbytes zurück.

Für sie ist der Befehl subCmdSpiFlashWritePage gespiegelt. Argumente für sie werden nach dem gleichen Prinzip ausgefüllt. Die Richtung der Datenübertragung ist zum Gerät.

Die Besonderheit des Flash-Speichers besteht darin, dass während der Aufzeichnung nur einzelne Bits durch Null-Bits ersetzt werden können. Um sie auf einen einzelnen Wert zurückzusetzen, sollten die Seiten gelöscht werden. Hierfür gibt es einen Befehl subCmdSpiFlashErasePage . Aufgrund der Eigenschaften der verwendeten Mikroschaltung wird zwar keine einzelne Seite, die im Parameter arg1 festgelegt ist, gelöscht, sondern ein 4-Kilobyte-Block, der diese Seite enthält.

Solid State Relay Management


Der Komplex verfügt über sechs Halbleiterrelais. Es gibt drei Teams, die sie verwalten.

subCmdRelaysSet - legt den Wert aller sechs Relais gleichzeitig fest. Im Parameter arg1 wird ein Wert übergeben, von dem jedes Bit seinem eigenen Relais entspricht (Nullbit - Relais mit Index 0, erstes Bit mit Index 1 usw.). Ein einziger Bitwert schließt das Relais, ein Nullwert öffnet es.

Diese Arbeitsweise ist gut, wenn alle Relais als eine Gruppe arbeiten. Wenn sie unabhängig voneinander arbeiten, müssen Sie bei diesem Ansatz eine Puffervariable starten, die den Statuswert aller Relais speichert. Wenn verschiedene Relais von verschiedenen Programmen gesteuert werden, wird das Problem des Speicherns des Gesamtwerts extrem akut. In diesem Fall können Sie zwei weitere Befehle verwenden:

subCmdRelaysOn - Aktiviert ausgewählte Relais nach Maske. Die Relais, die den Einheitenbits im Argument arg1 entsprechen, werden aktiviert. Die Relais, die Nullen in der Maske entsprechen, behalten ihren aktuellen Status bei.

Der Befehl subCmdRelaysOff, der es spiegelt, schaltet die ausgewählten Relais über die Maske aus. Die Relais, die den einzelnen Bits im Argument arg1 entsprechen , werden ausgeschaltet. Die Relais, die Nullen in der Maske entsprechen, behalten ihren aktuellen Status bei.

Setzen Sie die FTDI- und Maxim-Controller zurück


Um Rücksetzsignale an FTDI- und Maxim-Mikroschaltungen zu senden, wird die Befehlsgruppe subCmdFT4222_1_Reset , subCmdFT4222_2_Reset , subCmdFT4222_3_Reset , subCmdFT4232_Reset , subCmdFT2232_Reset und subCmdMAX3421_ verwendet . An ihren Namen können Sie erkennen, welche Chips sie durch Rücksetzsignale steuern. Die FT4222-Brücken sind, wie bereits erwähnt, zwei in der Schaltung (ihre Indizes sind 1 und 2). Eine weitere FT4222-Brücke überträgt Daten an den MAX3421-Chip, auf die wir im nächsten Artikel eingehen werden.

Der Parameter arg1 übergibt einen der folgenden Werte:

 enum ResetState { resetStateActive =0, resetStateNormalOperation }; 

Standardmäßig sind alle Brücken in einem normalen Betriebszustand. Wie bereits in einem vorherigen Artikel erwähnt , sind wir uns nicht sicher, ob diese Funktionalität benötigt wird. Wenn jedoch kein direkter Zugriff auf das Gerät besteht, ist es besser, alles und jedes remote zurücksetzen zu können.

Konfigurationszeilen von FT4222-Chips wechseln


FT4222-Chips haben vier Modi. Es ist unwahrscheinlich, dass jemand einen anderen Modus als "00" benötigt. Wenn Sie ihn jedoch plötzlich benötigen, können Sie die Befehle subCmdFT4222_1_Cfg , subCmdFT4222_2_Cfg und subCmdFT4222_3_Cfg zum Umschalten für den ersten, zweiten und dritten Chip verwenden . Der Wert der Zeilen CFG0 und CFG1 wird in den unteren beiden Bits des Parameters arg1 eingestellt .

Praktische Erfahrung in der Ausgabe von Befehlen an die STM32-Steuerung


Um das theoretische Material in der Praxis zu testen, werden wir versuchen, die SD-Karte auszutauschen. Setzen Sie dazu den Befehl subCmdSdEnable mit dem Code 0x00 und dem Argument enableModeOutside mit dem Code 0x01 ab. Großartig. Wir haben das Programm wie folgt umgeschrieben.

Umgeschriebenes Programm:
 #include <cstdio> #include <stdint.h> #include <string.h> #include <fcntl.h> // open #include <unistd.h> // close #include <sys/ioctl.h> #include <scsi/scsi.h> #include <scsi/sg.h> int main() { printf("hello from SdAccessTest!\n"); int s_fd = open("/dev/sdb", O_NONBLOCK | O_RDWR); if (s_fd < 0) { printf("Cannot open file\n"); return -1; } sg_io_hdr_t header; memset(&header;, 0, sizeof(header)); uint8_t cmdSdToOutside[] = { 0xC0,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; uint8_t cmdSdToPC[] = { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; uint8_t sense[32]; memset(sense, 0, sizeof(sense)); header.interface_id = 'S'; //  'S' //  header.cmd_len = sizeof(cmdSdToOutside); header.cmdp = cmdSdToOutside; //  ( ) header.dxfer_len = 0; header.dxferp = 0; header.dxfer_direction = SG_DXFER_NONE; //     header.mx_sb_len = sizeof(sense); header.sbp = sense; // header.timeout = 100; // 100  int res = ioctl(s_fd, SG_IO, &header;); //   header.cmdp = cmdSdToPC; res = ioctl(s_fd, SG_IO, &header;); close(s_fd); return 0; } 


Wir haben die Befehlslänge auf zehn Bytes geändert und den Datenblock entfernt. Nun, sie haben den Befehlscode nach Bedarf mit Argumenten aufgeschrieben. Ansonsten bleibt alles beim Alten. Wir fangen an ... und ... nichts funktioniert. Die Funktion ioctl () gibt einen Fehler zurück. Der Grund ist im SG_IO- Befehlsdokument beschrieben. Tatsache ist, dass wir den herstellerspezifischen Befehl C0h geben und Folgendes wörtlich über sie gesagt wird:
Jeder andere SCSI-Befehl (Opcode), der nicht für den SG-Treiber angegeben wurde, benötigt O_RDWR. Jeder andere SCSI-Befehl (Opcode), der nicht für die Blockschicht SG_IO ioctl erwähnt wird, benötigt einen Benutzer mit der Fähigkeit CAP_SYS_RAWIO.

Wie der Chef mir erklärte (ich erzähle nur seine Worte), werden die Werte der Fähigkeiten einer ausführbaren Datei zugewiesen. Aus diesem Grund musste ich mich von der Entwicklungsumgebung aus als root anmelden . Nicht die beste Lösung, aber zumindest etwas. Unter Windows sind für die Anforderung IOCTL_SCSI_PASS_THROUGH_DIRECT Administratorrechte erforderlich. Vielleicht gibt jemand in den Kommentaren Ratschläge, wie man das Tracing-Problem ohne solch drastische Schritte löst, aber Sie können das bereits geschriebene Programm ohne root ausführen, wenn Sie die richtigen Fähigkeiten dafür registrieren. Ändern Sie in der Zwischenzeit den Benutzernamen in der Entwicklungsumgebung und setzen Sie einen Haltepunkt in der Zeile:

 int res = ioctl(s_fd, SG_IO, &header;); 

Bevor wir die Funktion ioctl () aufrufen, sehen wir uns die Liste der Speichergeräte an:



Rufen Sie ioctl () auf und sehen Sie sich die Liste noch einmal an:



Das Gerät / dev / sdb ist geblieben (grob gesagt, das ist der SD-Kartenleser selbst), und / dev / sdb1 ist verschwunden. Dieses Gerät entspricht dem Dateisystem auf dem Datenträger. Der Träger wurde vom Computer getrennt - er war nicht mehr sichtbar. Wir verfolgen weiter. Nach dem Aufruf der zweiten ioctl () -Funktion sehen wir uns noch einmal die Liste der Geräte an:



Die SD-Karte wird erneut mit dem System verbunden, sodass / dev / sdb1 wieder in Position ist. Tatsächlich haben wir gelernt, wie man herstellerspezifische Befehle ausgibt und ein Gerät verwaltet, das auf dem STM32-Mikrocontroller im Redd-Komplex basiert. Andere Befehle werden den Lesern zum unabhängigen Studium überlassen. Sie können den Betrieb einiger von ihnen auf ähnliche Weise steuern. Wenn ein ftdi- Chip in einen Reset-Zustand wechselt, wird das entsprechende Gerät aus dem System entfernt. Der Betrieb des Relais und die Steuerung der Beine der Konfiguration müssen durch Messinstrumente gesteuert werden. Sie können die Arbeit mit einem Flash-Laufwerk überprüfen, indem Sie Seiten mit anschließender Lesesteuerung schreiben.

Fazit


Wir haben zwei große Themen untersucht, die nicht mit FPGAs im Redd-Komplex zusammenhängen. Der dritte blieb bestehen - er arbeitete mit dem MAX3421-Chip, mit dem USB 2.0 FS-Geräte implementiert werden können. In der Tat gibt es auch Hosts, aber es gibt viele Hosts und das Motherboard. Die Funktionalität des Geräts ermöglicht es dem Komplex, sich als USB-Flash-Laufwerk (zum Senden von Firmware-Updates), USB-Tastatur (zum Steuern externer Geräte) usw. auszugeben. Wir werden dieses Thema im nächsten Artikel betrachten.

Source: https://habr.com/ru/post/de484706/


All Articles