Effizientes Dekodieren von nicht standardmäßigen seriellen Signalen

11

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:

  1. 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.

  2. 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.

Keegan Jay
quelle
Ich muss sagen, es kommt selten vor, dass ich sehe, dass viele Vorschläge, die ich mag, so schnell beantwortet werden, gut zu Ihrer Frage sprechen. Mich würde interessieren, mehr über die Datenburts zu erfahren. Sind sie platzen, plötzlich mit voller Geschwindigkeit und dann Perioden mit geringen Datenmengen, oder ist es plausibel, dass Sie einen längeren Zeitraum mit kontinuierlichen Daten verbringen würden?
Kortuk
Solange der ASIC mit Strom versorgt wird, sendet er einen kontinuierlichen Datenstrom. Überhaupt nicht platzen. Es ist eine medizinische Echtzeit-Sensoranwendung mit einer Computeranzeige. Schon mal ein EKG gesehen?
Keegan Jay
So viele tolle Antworten hier. Ich sah eine klare Trennung zwischen Lösungen mit Änderungen an den Interrupts und Lösungen mit dedizierter Hardware / digitaler Logik. Dinge wie FPGAs und Verilog sind mir vertraut, aber noch nicht bekannt. Dies bedeutet, dass sie langfristig gespeichert werden müssen. Kurzfristig ist eine weniger Interrupt-schwere Methode von @rocketmagnets in Ordnung. Ich mag die Eleganz, einfache Aufgaben der digitalen Logik zu widmen und den ARM für echte Berechnungen zu speichern. In Zukunft wird die Leistung des ARM zur Analyse und Filterung der drahtlosen seriellen Daten verwendet.
Keegan Jay
Ist das Signal synchron oder asynchron?
Markrages
Asynchron. 4 Startbits, 10 Datenbits, 2 Stoppbits. Aufgrund der Art des ASIC, der sendet, variieren die HI- und LO-Zeiten stark von Chip zu Chip. Ich habe bereits einen Algorithmus geschrieben, um die Baudrate abzuleiten.
Keegan Jay

Antworten:

5

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.

loop
{
    if (serial_bit_ready)
    {
        // shift serial bit into a byte
    }

    if (serial_byte_ready)
    {
        // decode serial data
    }

    if (enough_serial_bytes_available)
    {
        // more decoding
    }        

    if (usb_queue_not_empty)
    {
        // handle USB data
    }        
}

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.

loop
{
    if (serial_bit_ready)
    {
        // shift serial bit into a byte
    }

    if (serial_byte_ready)
    {
        // decode serial data
    }

    if (serial_bit_ready)
    {
        // shift serial bit into a byte
    }

    if (enough_serial_bytes_available)
    {
        // more decoding
    }        

    if (serial_bit_ready)
    {
        // shift serial bit into a byte
    }

    if (usb_queue_not_empty)
    {
        // handle USB data
    }        
}

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.

Raketenmagnet
quelle
Ich mag deine Antwort mehr als die Antwort anderer Rocketmagnet-Personen. Anstelle von mehr Hadrware, schnellerer Hardware, mehr von etwas anderem, schlagen Sie Rocketmagnet vor: Machen Sie weniger, besser, einfacher.
Okay, ich habe viele Fälle gesehen, in denen Interrupts eine Lösung viel besser machen. Sie machen großartige Dinge, ermöglichen gut strukturierten Code, geringe Latenz und viele andere Vorteile, aber ich muss Ihnen hier zustimmen. Es sieht so aus, als ob der Prozess so intensiv ist. 1 Controller muss möglicherweise jedes bisschen seiner Aufmerksamkeit der Handhabung des seriellen Streams widmen. Das digitale Frontend klingt für mich ideal, aber wenn Sie ein Schulprojekt haben, haben Sie oft ein paar Mikros und kein FPGA. Ich würde wahrscheinlich zuerst ein Mikro für die Handhabung verwenden und später versuchen, es in ein FPGA einzubauen, um es zu ersetzen Kosten.
Kortuk
Dies ist wahrscheinlich die Lösung, mit der ich kurzfristig gehen werde. Ich hatte gehofft, dies zu vermeiden, da einige der vorhandenen seriellen Treiber neu geschrieben werden müssen, aber es ist eine elegante Lösung, die innerhalb eines kurzen Zeitraums innerhalb meiner Fähigkeiten liegt.
Keegan Jay
1
@ JayKeegan - Ja, es ist wahrscheinlich der schnellste Weg zu einer Lösung. PSoC und FPGA könnten der Ansatz für das nächste Projekt sein.
Raketenmagnet
6

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 ).

vicatcu
quelle
Dies könnte auf lange Sicht eine hervorragende Lösung sein. Ich hatte gehofft, dass ich neben Softwarelösungen auch viele digitale Logik- / Hardwarelösungen erhalten habe, denn jetzt habe ich eine Ausrede, um etwas über diese Dinge zu lernen! Ich habe leider noch keine Erfahrung mit FPGAs.
Keegan Jay
6

Einfach: Verwenden Sie einen PSoC5-Mikrocontroller .

PSoC

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.

Raketenmagnet
quelle
Auf der Übersichtsseite sind keine Taktfrequenzen aufgeführt, was meinen Verdacht geweckt hat. Datenblatt sagt 40MHz (ich habe auch 6mA bei 6MHz notiert). Das ist die Hälfte dessen, was OP jetzt hat. "Die MCU muss auch viele andere Aufgaben erledigen", daher kann es davon abhängen, ob dies eine gute Idee ist oder nicht.
Stevenvh
Sie gehen bis zu 67MHz. Es ist also fast so schnell wie der aktuelle Prozessor des OP, außer dass der größte Teil der Arbeit in Hardware erledigt wird und die CPU viel mehr Freizeit hat.
Raketenmagnet
1
Ich habe mir nicht alle Datenblätter angesehen. Der erste, den ich ausgewählt habe, sagte 40 MHz.
Stevenvh
@stevenvh - Sie haben unterschiedliche Geschwindigkeitsstufen. Die dritte Zahl in der PN ist die Geschwindigkeitsstufe. (4 = 48 MHz, 6 = 67 MHz).
Raketenmagnet
1
Dies ist auch auf lange Sicht eine fantastische Lösung, ähnlich wie die FPGA-Idee. Ich habe noch nie von dieser Art von Chip gehört, aber es bringt einen Großteil der Funktionalität auf dem Rest meines Boards in einen Chip. In Zukunft könnte dies bedeuten, dass der gesamte Empfänger auf etwas von der Größe eines USB-Sticks passt, was die Vision meines Projektleiters ist. Ich werde Verilog im nächsten Semeseter lernen.
Keegan Jay
4

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.

Akohlsmith
quelle
Diese Lösung ergänzt den Softwareansatz von Rocketman durch die Reduzierung der Anzahl von Interrupt-basierten Treibern. Ich kann den von mir erwähnten seriellen Haupttreiber als Interrupt-basiert behalten. Außerdem werde ich versuchen, mich zu drehen, bis der gesamte Frame gelesen ist, wie Sie bereits erwähnt haben.
Keegan Jay
3

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.

Jon L.
quelle
Dies ist eigentlich der Plan, den ich mir vorgestellt hatte, als ich das gepostet habe. Wenn ich die Software nicht rationalisieren kann, indem ich die Abhängigkeit von Interrupts (ausgewählte Antwort) reduziere, werde ich dies mit Sicherheit tun. Aber ja, es wird einen weiteren Board-Run erfordern, wahrscheinlich zwei, weil ich es nicht mag, meine Designs gleich beim ersten Mal richtig zu machen.
Keegan Jay
@ JayKeegan, haha, willkommen im Club!
Jon L
2

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.

Superkatze
quelle
Dies alles ist sehr wertvoll, wenn die digitale Logik für die Decodierung entworfen wird. Ich werde in der Tat als SPI ausgeben. Im Moment mache ich nur die Dekodierung mit einer eigenständigen MCU (Zeitbeschränkungen). Vielen Dank!
Keegan Jay