Due freie Register//Rechteck-Bitmuster

Hallo Community,

anlehnend an meinen letzten Beitrag zum Leuchtturm Beispiel will ich nun einen Rechtecktakt mit bestimmtem Bitmuster generieren.

Aufgrund dessen zunächst die Frage, weiß jemand wieviel freie Register in welcher Größe ich dafür zur Verfügung hätte ?
Bei den PIO Registern sind es meiner Ansicht nach 4 â 32 Bit oder ?

Also Vorhaben habe ich unten ein Bild angehängt, was das Ziel darstellt. Ich möchte praktisch dieses Signal reproduzieren & bräuchte bei der Umsetzung ein wenig Hilfe da mir grad noch die Idee fehlt.

Besonderheiten hierbei sind:
-> Insgesamt sind es 19 Blöcke â 16 Bit wobei die letzten 16 Blöcke identisch sind
-> Codiert ist das Muster im Bild nach Flanken, soll heißen: fallende Flanke = 1 und steigende Flanke = 0
-> die ersten 2 Blöcke (2x 16Bit) sind immer gleich , ebenso wie die letzten 16 Blöcke mit je "0000"
der 3. 16Bit Block soll später Variabel gestaltet werden
-> Zwischen den einzelnen Bits beträgt der Abstand 1us -> Frequenz 1Mhz

Folgenden Code hatte ich für ein ähnliches Vorhaben geschrieben....Lässt dieser sich dafür abwandeln oder fehlen möglicherweise leere Register ?
Evtl hat ja auch jemand eine ganz neue Idee für die Umsetzung um es zu vereinfachen :slight_smile:

Danke im Voraus

#define NOP __asm__ __volatile__ ("nop\n\t");
#define PAUSE NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP
// 1 NOP Befehl entspricht 12ns (1/84MHz)
void setup() {
pinMode(5, OUTPUT); 
Serial.begin(115200);  
}
void loop() {
/*
on pin 5: 
  Signal 1: 1010 1010 1100 1100  
          Signal 2: 1110 1110 1010 1010
          Signal 3: 1010 0110 0110 1010
          Signal 4: 1101 1101 0011 0010
*/
if(Serial.available()>0){ 

byte input = Serial.read();
 
Pio *p = digitalPinToPort(7); // Port.C

uint32_t s5 = digitalPinToBitMask(5);
uint32_t c5 = digitalPinToBitMask(5);
    
switch (input){
  case '1':
  p->PIO_SODR = s5; PAUSE p->PIO_CODR = c5; PAUSE p->PIO_SODR = s5; PAUSE            
  p->PIO_CODR = c5; PAUSE 
  p->PIO_SODR = s5; PAUSE p->PIO_CODR = c5; PAUSE p->PIO_SODR = s5; PAUSE 
  p->PIO_CODR = c5; PAUSE
  p->PIO_SODR = s5; PAUSE p->PIO_SODR = s5; PAUSE p->PIO_CODR = c5; PAUSE 
  p->PIO_CODR = c5; PAUSE
  p->PIO_SODR = s5; PAUSE p->PIO_SODR = s5; PAUSE p->PIO_CODR = c5; PAUSE 
  p->PIO_CODR = c5; PAUSE
  break;
  case '2':
  p->PIO_SODR = s5; PAUSE p->PIO_SODR = s5; PAUSE p->PIO_SODR = s5; PAUSE 
  p->PIO_CODR = c5; PAUSE
  p->PIO_SODR = s5; PAUSE p->PIO_SODR = s5; PAUSE p->PIO_SODR = s5; PAUSE   
  p->PIO_CODR = c5; PAUSE
  p->PIO_SODR = s5; PAUSE p->PIO_CODR = c5; PAUSE p->PIO_SODR = s5; PAUSE 
  p->PIO_CODR = c5; PAUSE
  p->PIO_SODR = s5; PAUSE p->PIO_CODR = c5; PAUSE p->PIO_SODR = s5; PAUSE 
  p->PIO_CODR = c5; PAUSE  
  break;

  case '3':
  p->PIO_SODR = s5; PAUSE p->PIO_CODR = c5; PAUSE p->PIO_SODR = s5; PAUSE 
  p->PIO_CODR = c5; PAUSE 
  p->PIO_CODR = c5; PAUSE p->PIO_SODR = s5; PAUSE p->PIO_SODR = s5; PAUSE 
  p->PIO_CODR = c5; PAUSE 
  p->PIO_CODR = c5; PAUSE p->PIO_SODR = s5; PAUSE p->PIO_SODR = s5; PAUSE 
  p->PIO_CODR = c5; PAUSE 
  p->PIO_SODR = s5; PAUSE p->PIO_CODR = c5; PAUSE p->PIO_SODR = s5; PAUSE 
  p->PIO_CODR = c5; PAUSE 
  break;
  case '4':
  p->PIO_SODR = s5; PAUSE p->PIO_SODR = s5; PAUSE p->PIO_CODR = c5; PAUSE 
  p->PIO_SODR = s5; PAUSE
  p->PIO_SODR = s5; PAUSE p->PIO_SODR = s5; PAUSE p->PIO_CODR = c5; PAUSE 
  p->PIO_SODR = s5; PAUSE
  p->PIO_CODR = c5; PAUSE p->PIO_CODR = c5; PAUSE p->PIO_SODR = s5; PAUSE 
  p->PIO_SODR = s5; PAUSE 
  p->PIO_CODR = c5; PAUSE p->PIO_CODR = c5; PAUSE p->PIO_SODR = s5; PAUSE 
  p->PIO_CODR = c5; PAUSE 
  break; 
  } 
 }
}

Was soll das Ganze?

Wieviele Signale (digitale Ausgänge) brauchst Du tatsächlich?
Sind die Signale an den Pins synchron zueinander, oder asynchron (unabhängig)?

Ich würde die Muster aus Arrays lesen, und die Pausenzeit entsprechend korrigieren.
Ggf. Timer für exaktes Timing abfragen.

t0bsN:
Aufgrund dessen zunächst die Frage, weiß jemand wieviel freie Register in welcher Größe ich dafür zur Verfügung hätte ?

Was willst Du in diesem Zusammenhang mit Registern tun?!

Programmiere etwas, das einen String der Art "100101010010010111" bekommt, diesen Zeichen für Zeichen durchgeht und ein Pin entsprechend HIGH oder LOW setzt sowie anschließend eine passende Pause macht. Fäddich.

Gruß

Gregor

Was soll das Ganze?

Wieviele Signale (digitale Ausgänge) brauchst Du tatsächlich?
Sind die Signale an den Pins synchron zueinander, oder asynchron (unabhängig)?

Das ganze soll ein komplettes Signal werden, welches an einem Pin angenommen werden kann.

Das Signal aus dem Bild ist das Original aus einem Gerät welches ich imitieren muss für einen Prüfaufbau meinerseits.

Programmiere etwas, das einen String der Art "100101010010010111" bekommt, diesen Zeichen für Zeichen durchgeht und ein Pin entsprechend HIGH oder LOW setzt sowie anschließend eine passende Pause macht. Fäddich.

Das Problem mit dem high und low setzen (habe ich schon mal versucht) ist, dass ich so keine 1Mhz hin bekomme...ich glaub das höchste war da um die 400kHz Rechteck was man raus bekommt..

aber wenn du einen konkreten Ansatz hast, gern her damit :slight_smile:

Das allgemeine Vorhaben ist mir ja bekannt, nur die programmiertechnische Umsetzung da hapert es immer ein bisschen weil ich da nicht so wirklich Erfahrung habe außer 1 Semester c Grundlagen im Studium :smiley:

Ah, nur an einem einzigen Pin. Das habe ich vorher auch nicht verstanden, bei den vielen Erwähnungen von 32 Bit Registern.

In der Tat muss man da wohl nur in einem Register was ändern. Such mal nach "Arduino Due direct Port Manipulation". Die Werte kommen dann aus einem Array im Speicher.

Sowas wie FastIO bei mbed scheint es für den Due nicht fertig zu geben. Da muss man sich nicht selbst mit den Registern herumschlagen.

Ja war vllt etwas unverständlich ausgedrückt....der Code im Ausgangspost war wie gesagt nur ein änhliches Vorhaben, bei dem es darum ging an einem Pin 4 verschiedene 16 Bit Muster zu erzeugen....

Ich will nun aber das im Bild 8Anhang) gezeigte Signal komplett/fortlaufend aus einem Pin haben :slight_smile:

Also die Daten speicherst du in normalen C Arrays. Entweder Bitweise oder Byteweise, hängt auch davon ab, wieviel Daten und Speicher du hast. Wenn du byteweise speicherst enthält jeder Arrayeintrag acht hintereinander auszugebende Bits.

Dann hast du zwei Wege:

Entweder kriegst du einen Timer hin, der schnell genug ist und gibst in jedem Timer Ticker das nächste Bit aus. Bist du einmal durch das Muster durch, fängst du von vorne an.

Die harte Lösung wäre, der Controller macht nichts anderes, als in einer For Schleife die Bits auszugeben. Dazu müsste man wissen, wie lange er für ein Bit braucht. Um die richtige Dauer eines Bits hinzukriegen müsste man entweder warten, oder füllt die Muster entsprechend auf, dass man kontinuierlich ausgeben kann. Letzteres wird eventuell kompliziert, wenn man noch was anderes zwischendurch macht.

Weiter kann ich da zum Due nicht helfen. 8 Bit Arduino finde ich ja sehr praktisch, aber für 32 Bit bediene ich mich woanders.

okay ich versuhe mich mal rein zu denken..

meine frage ist ja: Im Grunde besteht das Signal was ich ausgeben möchte aus 19 mal 16 Bit

Ob dies überhaupt möglich ist auszugeben hintereinander auf einem Pin ?

Selbst die kleinsten Arduinos hätten Platz für 304 Bits ...

Okay, also ist die Umsetzung meines Vorhabens prinzipiell schon mal möglich :smiley:

FastLED macht ja im Grunde nicht anderes, als schnellstmöglich IO Pins zu manipulieren.

Hier die FastPin Klasse, optimiert für die gängigsten ARM und AVR Prozessoren. Der Due ist auf jeden Fall auch dabei.

Auf einem übertakteten Teensy gehen damit 24 MBit/s, ein Due sollte da zumindest nahe rankommen.

Grüße,

Helmuth

P.S. Vielleicht kann t0bsN ja mal schreiben, was für ein Signal er konkret nachbilden möchte, das erleichtert uns das Mitdenken.

Helmuth:
P.S. Vielleicht kann t0bsN ja mal schreiben, was für ein Signal er konkret nachbilden möchte, das erleichtert uns das Mitdenken.

Das Bild hängt ja oben dran. Nach der genauen Frequenz habe ich noch nicht geschaut.

Eine andere Option wäre die MOSI-Datenleitung vom SPI. Da sollte der Due eigentlich im zweistelligen Megahertz Bereich landen (42 MHz ?).

Dabei ist mir nur nicht klar, genauso wie bei einem Ansatz mit FastLED, wie man die Pause beim Neuanfang des Musters kontrolliert hinbekommt.

Für Delays bei denen das Timing wichtig ist, benutzt man Inline Assembler NOP.

For shorter delays use assembly language call 'nop' (no operation). Each 'nop' statement executes in one machine cycle (at 16 MHz) yielding a 62.5 ns (nanosecond) delay.

__asm__("nop\n\t"); 

__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t");  \\ gang them up like this

Besorge Dir auf jeden Fall einen billigen (15 €) Logic Analyzer, um Dir ansehen zu können, was wirklich passiert.

Was ist der Anwendungsfall? Pedelec Tuning? Kfz Sensorwerte Manipulation?

Helmuth

Bei der SPI-Variante wäre ja gar kein Delay wünschenswert. Wenn ein Muster raus ist, gleich wieder von vorne anfangen.

DMA ?

Serielle Ausgabe ist das richtige Stichwort. Ob SPI oder USART wäre zu prüfen, je nachdem was der Due da für Komfort anbietet. Wichtig ist, daß die Bytes ohne Unterbrechung rausgeschoben werden können (doppelt gepuffert).

Die Konkurrenz hat da mehr, man würde die Umsetzung von dem hier für den Due brauchen
BurstSPI

Der schreibt direkt in den SPI-FIFO.

Statt der for-Schleife in dem Beispiel eine Endlosschleife, die immer wieder das Array durchgeht.

Okay das sind grad viele Dinge auf einmal :smiley:

Also das "Finale-Signal" ist im ersten Post im Anhang @ Helmuth

Dieses soll wie gesagt ausgegeben werden und das halt immer wieder (Endlosschleife)

Ich hab mal versucht es nach diesem Prinzip zu versuchen

#define NOP __asm__ __volatile__ ("nop\n\t");
#define PAUSE NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP

void setup() {                  
  pinMode(12, OUTPUT);

  REG_PIOD_OWER = 0xFFFF;  
}

void loop() {
  REG_PIOD_ODSR = 0xFFFF;
  PAUSE
  REG_PIOD_ODSR = 0x0000;
  PAUSE
  REG_PIOD_ODSR = 0xFFFF;
.... usw.

}

Bei den Nop befehlen ist mir aufgefallen das sie doch recht ungenau sind irgendwie.... Für 1Mhz bräuchte ich ja rechnerisch 42 Nop aneinandereihungen.....jedoch wird die Pause mit der Zeit immer ein wenig größer als die 11,904 ns die es sein sollten....

Und gibt es evtl eine elegantere Lösung die einzelnen "highs" und "lows" zu verwenden in einem Array oder so ?! Hab leider keine Ahnung wie ich das besser umsetze dass es dann kein 200Zeilen code wird :smiley:

Aber Vielleicht noch zum allg Verständnis:

Das ganze wird dann genutzt um den Takt über Lichtwellenleiter an eine elektronische Steuereinheit zu übertragen die aus dem Signal liest, mit welcher Spannung sie arbeiten soll.... Das oben angehängte Bild ist Praktisch das Originalsignal aus dem Gesamtsystem....da ich aber nun einen Prüfstand für die eine spezielle Komponente aus dem Gesamtsystem aufbauen möchte, muss ich dieses Signal möglichst 100% Nachbilden

Das System funktioniert so: das es aller 1us die Flanke abtastet....was Zwischen diesen us-Fenstern passiert ist "praktisch egal".... nach jeder us schaut das Gerät ob eine Fallende flanke oder eine steigende Flanke anliegt....wobei das original signal so codiert ist, dass eine fallende Flanke die 1 ist und eine steigende flanke die 0...was aber nicht weiter stören soll

Ich hoffe man kann es etwas verstehen ?:smiley: Wenn nicht einfach nochmal fragen :slight_smile:

Nun, die Zwischendiskussion ging in die Richtung gar nicht selbst an dem Pin zu wackeln, sondern den SPI-Bus

zu nehmen. Da wackelt die Hardware schon selbst an den Pins. Wenn nötig sehr schnell und präzise, da vom Prozessortakt abgeleitet.

Die Frage wäre dann nur noch, wie man ihn kontinuierlich füttert, damit das Muster ohne Pause ausgegeben wird.

Hier ist schön dargestellt, welches Problem man bei Verwendung der normalen SPI-Bibliothek wohl hätte:
https://developer.mbed.org/questions/2408/16-us-gap-between-sending-SPI-data/

Und genau gegen die unerwünschten Pausen gibt es ja die weiterentwickelte SPI/USART Hardware mit integrierten Puffern oder FIFO. Gibt's die nicht z.B. beim MK1000 Board/Controller?