Ich bin ein Student in einem Forschungsteam, das an einem Projekt arbeitet, das einen HF-sendenden ASIC und dessen drahtlosen Empfänger umfasst, der letztendlich Daten an einen PC senden soll.
Der Empfänger gibt ein schnelles , kontinuierliches, asynchrones, nicht standardmäßiges serielles Signal aus (dh nicht SPI, I2C, UART usw.). Daher besteht meine Aufgabe darin, eine Mikrocontroller-Software zu schreiben, um den Empfänger mit dem Computer zu verbinden. Derzeit besteht mein Ansatz darin, flankengetriggerte Interrupts zu verwenden, um die Daten in einem Ringpuffer zu platzieren und den gesamten bitweisen Decodierungsprozess in der Hauptschleife durchzuführen. Der Mikrocontroller muss diese Daten gleichzeitig über USB (Virtual Com Port) an den Computer ausgeben.
Hier ist ein Problem, das ich habe und das ich erwarte:
Ich kann die gepufferten Daten selbst mit meinem recht leistungsstarken 72-MHz-ARM-Cortex-M3-Prozessor nicht schnell genug verarbeiten. Die Bitrate beträgt 400 Kbit / s (2,5 us / Bit). Als Referenz bleiben nur 180 Zyklen pro Bit übrig (einschließlich der Decodierung UND des ISR, der ~ 30 Zyklen Overhead-Autsch hat!). Die MCU muss auch viele andere Aufgaben erledigen, nach denen sie in der Hauptschleife fragt.
Der USB-Treiber für den virtuellen COM-Anschluss basiert ebenfalls auf Interrupts. Dies macht mich fast sicher, dass der Treiber den Prozessor irgendwann so lange unterbrechen wird, dass er das 2,5-Mikrosekunden-Fenster (180 Zyklen) verfehlt, in dem ein Bit übertragen werden kann. Ich bin mir nicht sicher, wie solche Interrupt-Konflikte / Rennen normalerweise gelöst werden.
Die Frage ist also einfach, was könnte man tun, um diese Probleme zu lösen, oder ist dies überhaupt nicht der richtige Ansatz? Ich bin bereit, auch weniger softwarezentrierte Ansätze in Betracht zu ziehen. Verwenden Sie zum Beispiel einen dedizierten USB-Chip mit einer Art Hardware-Zustandsmaschine für die Dekodierung, aber dies ist ein unbekanntes Gebiet.
Antworten:
Eine andere Antwort: Verwenden Sie keine Interrupts mehr.
Die Leute springen, um Interrupts zu leicht zu benutzen. Persönlich benutze ich sie selten, weil sie tatsächlich viel Zeit verschwenden, wie Sie entdecken.
Es ist oft möglich, eine Hauptschleife zu schreiben, die alles so schnell abfragt, dass die Latenz innerhalb der Spezifikation liegt und nur sehr wenig Zeit verschwendet wird.
Es kann einige Dinge in der Schleife geben, die weitaus häufiger vorkommen als andere. Vielleicht fügen die eingehenden Bits in diesem Fall mehr dieser Tests hinzu, so dass mehr Prozessor für diese Aufgabe reserviert ist.
Es kann Ereignisse geben, für die die Latenz dieses Ansatzes zu hoch ist. Beispielsweise benötigen Sie möglicherweise ein sehr genau zeitgesteuertes Ereignis. In diesem Fall sollten Sie dieses Ereignis unterbrechen und alles andere in der Schleife haben.
quelle
Sie könnten möglicherweise ein FPGA anstelle eines Mikrocontrollers verwenden, um den drahtlosen Datenstrom zu dekodieren und zu puffern. Verwenden Sie dann den ARM-Prozessor, um die FPGA-Puffer zu leeren (z. B. über eine SPI-Schnittstelle) und den Inhalt über den USB-Kommunikationsanschluss zu versenden. Es funktioniert, aber ein FPGA sollte problemlos mithalten können, solange Sie es häufig genug warten können, um sicherzustellen, dass seine Hardwarepuffer nicht überlaufen (oder wenn Sie mit gelöschten Daten auf einer höheren Ebene des Protokolls umgehen können ).
quelle
Einfach: Verwenden Sie einen PSoC5-Mikrocontroller .
Sie haben die Benutzerfreundlichkeit eines Mikrocontrollers und enthalten eine CPLD, sodass Sie Ihre eigenen Hardware-Peripheriegeräte in Verilog schreiben können. Schreiben Sie einfach Ihren seriellen Datendecoder in Verilog und streamen Sie ihn mit DMA auf den USB-Anschluss.
In der Zwischenzeit kann der leistungsstarke 32-Bit-ARM-Kern seine Thumb-Anweisungen verändern.
quelle
Ich denke, Sie müssen eine klassische technische Entscheidung treffen: schnell, billig, funktioniert: Wählen Sie zwei.
Die Lösung von @ vicatcu ist sicherlich eine gute, aber wenn Sie nicht mehr Hardware hinzufügen können oder wollen (und dies schließt einen schnelleren Prozessor ein), müssen Sie eine Wahl treffen. Wenn diese serielle Verbindung die wichtigste ist, sollten Sie im ISR sitzen, bis alle Bits gesammelt wurden. 180 Anweisungen pro Bit sind eigentlich gar nicht schlecht, aber versuchen Sie nicht, alles zu tun. Wenn Sie den Beginn einer Übertragung erkennen, drehen Sie, bis die Übertragung abgeschlossen ist. Füllen Sie das Ergebnis in ein FIFO und setzen Sie dann die normale Verarbeitung fort.
Sie sagen nicht, wie lang jede Übertragung ist, aber wenn sie kurz und platzt, ist dies eine praktikable Lösung. Ich bin bereit zu wetten, dass Ihre virtuelle COM-Port-Implementierung auch eine gewisse Hardware-Pufferung aufweist, sodass ein "verzögerter" Interrupt-Dienst dafür nicht zu viel Ärger bereiten sollte. Was den Rest der MCU angeht, müssen Sie einige Entwurfsentscheidungen treffen.
quelle
Zuallererst mag ich einige der Antworten hier bereits, und einige haben meine Stimme erhalten.
Aber nur um eine andere mögliche Lösung zu finden: Wäre das Hinzufügen eines zweiten Mikrocontrollers angesichts der Einschränkungen Ihres Projekts schlecht (würde dies einen weiteren Board-Lauf beinhalten)? Möglicherweise ein einfacher 8-Bit-Mikrocontroller, der über ein schnelles Peripheriegerät wie SPI mit Ihrem Cortex-M3 verbunden ist. Der 8-Bit-Controller Ihrer Wahl fragt nach Bits ab und bildet Bytes wie in der ausgewählten Antwort. Wenn er jedoch über ein Byte verfügt, kann er es zur Übertragung in das SPI-Datenregister ausgeben.
Die Cortex-M3-Seite würde bei empfangenen SPI-Daten einfach unterbrechen. Dadurch wird Ihr bisheriger durch eine externe Flanke ausgelöster Interrupt mit 400 KHz auf 50 KHz reduziert.
Die beiden Gründe, warum ich dies vorschlage, sind, dass einige der anderen Methoden (PSoC oder hinzugefügtes FPGA) etwas teuer sind (obwohl dies für ein akademisches Projekt mit geringem Volumen wahrscheinlich keine Rolle spielt) und dass Sie möglicherweise einige davon beibehalten können die Struktur Ihres aktuellen Codes.
Abgesehen davon finde ich die PSoC-Idee großartig, wenn Sie Ihr eigenes Peripheriegerät über DMA auf USB übertragen.
quelle
Wenn Ihr Datenformat dem eines UART ähnelt, jedoch mit einer unvorhersehbaren und dennoch konsistenten Baudrate, würde ich gerne eine CPLD verwenden, um jedes Wort eingehender Daten entweder in ein SPI- oder ein Standard-Async-Format zu konvertieren. Ich glaube nicht, dass es notwendig ist, den ganzen Weg in das Reich der CPLDs zu drängen. Tatsächlich könnte sogar diskrete Logik fast praktikabel sein. Wenn Sie eine Uhr erzeugen könnten, die mehr als das Fünffache Ihrer gewünschten Datenrate beträgt, könnten Sie einen Zähler zum Teilen durch fünf und zum Teilen durch 16 mit einigen Toren verwenden. Ordnen Sie den Zähler zum Teilen durch fünf so an, dass er immer dann zurückgesetzt wird, wenn der Eingang inaktiv ist und der Zähler zum Teilen durch 16 auf Null steht. Andernfalls erzeugen Sie einen SPI-Taktimpuls und stoßen den Zähler zum Teilen durch 16 jedes Mal an, wenn der Zähler zum Teilen durch fünf 2 trifft.
Angesichts des 5-fachen Takts könnte man den SPI-Takt mit einem 16V8 (dem kleinsten und billigsten derzeit verfügbaren programmierbaren Logikgerät) erzeugen. Ein zweiter 16V8 oder 22V10 könnte als Teiler der Bruchrate verwendet werden, um den 5-fachen Takt zu erzeugen, oder man könnte einen etwas größeren Chip (CPLD) verwenden und alles in einem tun.
Bearbeiten / Nachtrag
Wenn man eine CPLD verwenden möchte, kann man der Schaltung nach einigen weiteren Überlegungen leicht einige zusätzliche Verbesserungen hinzufügen. Zum Beispiel kann man ziemlich leicht Logik hinzufügen, um die Schaltung zum Stillstand zu bringen, bis sie mindestens 1,5 Bit Zeiten des Stoppbits empfängt, gefolgt von 3,5 Bit Zeiten des Startbits; Wenn es ein zu kurzes Startbit empfängt, sollte es wieder nach dem Stoppbit suchen. Wenn Sie SPI verwenden, können Sie auch das / CS-Signal verwenden, um sicherzustellen, dass das empfangende Gerät korrekt gerahmte Daten sieht. Wenn das Gerät, das die SPI-Daten empfängt, 10-Bit-Frames verarbeiten kann, kann man solche Frames direkt senden. Andernfalls könnte jeder Zehn-Bit-Rahmen als 8-Bit-Rahmen mit gesetztem LSB (7 Datenbits) und als Rahmen mit allen gelöschten LSBs (3 Datenbits) gesendet werden. Der SPI-Takt würde während der Stoppbits beschleunigt, so dass alle Daten gesendet würden.
Einige Mikrocontroller verfügen über ziemlich vielseitige PWM-Generierungsmodule, die beispielsweise die Fähigkeit beinhalten, durch ein externes Signal zurückgesetzt zu werden, und deren Timing mit der Freigabe eines solchen Signals synchronisieren. Wenn Ihr Mikrocontroller dies in Abhängigkeit von seinen genauen Merkmalen kann, kann dies die CPLD- oder Timing-Generierungsschaltung erheblich vereinfachen.
Ein anderer Ansatz, den Rocketmagnet etwas berührt hat, wäre ein kleines Mikro, dessen einziger Zweck darin besteht, die seriellen Daten zu dekodieren und in ein Format zu konvertieren, das vom Hauptmikro verwendet werden kann. Ihre 400-kHz-Datenrate ist für die Software-Dekodierung ziemlich schnell, aber so etwas wie ein PIC könnte damit umgehen, wenn er nicht gleichzeitig etwas anderes tun müsste. Je nachdem, mit welchen Geräten Sie vertraut sind, kann dies einfacher oder schwieriger sein als die Verwendung einer CPLD.
quelle