Go Down

Topic: [Projekt] Schnelle Digital Eingabe/Ausgabe (Read 3880 times) previous topic - next topic

DrDiettrich

Ich habs interessehalber mal ausprobiert, und bin mit einem Burst (for Schleife 8 mal innerhalb loop) auf eine Zykluszeit von ca. 0,5µs gekommen, etwa 2MHz oder 8 Takte :-)
Dabei wird der Port zweimal gelesen und geändert. Wenn man ihn vorher ausliest, und dann nur die Änderungen reinschreibt, könnte man noch um 2 Takte schneller werden.

Jedenfalls deutlich schneller als die 12µs mit digitalWrite. Wobei es zeitlich ziemlich egal ist, ob man damit den Pin in loop() einmal oder zweimal ändert, die meiste Zeit wird anscheinend nicht im Aufruf von loop() verdödelt, sondern in digitalWrite().

combie

#16
Jan 16, 2016, 10:34 am Last Edit: Jan 16, 2016, 10:37 am by combie
Quote
Dabei wird der Port zweimal gelesen und geändert. Wenn man ihn vorher ausliest, und dann nur die Änderungen reinschreibt, könnte man noch um 2 Takte schneller werden.
Da bin ich mir nicht sicher....
Die Änderungen wollen ja auch berechnet werden.....
Oder wenigstens aus dem Speicher gefischt.

Allerdings hast du recht, wenn man nicht ausliest, sondern stumpf das ganze Register beschreibt, wirds etwas schneller. In der Praxis wird das leider wenig Bedeutung erlangen...

Code: [Select]

void loop()  // 2,667 MHz symmetrischer Rechteck
{

    for(;;) PINB = 0xFF;
}
Wer seine Meinung nie zurückzieht, liebt sich selbst mehr als die Wahrheit.

Quelle: Joseph Joubert

combie

#17
Dec 17, 2017, 01:20 pm Last Edit: Dec 17, 2017, 01:33 pm by combie
Ich freue mich auf PinPlus, wo dann auch togglePinPlus(13); funktioniert.
Ein Stück des Weges, ist gegangen....


Blink.ino:
Code: [Select]

#include "PinDefinition.h"

using PinDefinition::OutputPin;

OutputPin<13> led;

void setup(void)
{
   led.init();
}

void loop(void)
{
    led.toggle();
    delay(1000);
}



Ein weiteres Beispiel: Beim Tastendruck erleuchtet die LED an Pin 13
Code: [Select]
#include "PinDefinition.h"

using namespace PinDefinition;

TasterGND<2>  taster; // Taster zwischen Pin und GND(invertierend)
OutputPin<13> led;

void setup(void)
{
  taster.initPullup();
  led.init();
}

void loop(void)
{
    led = taster;
}



Das ganze ist noch nicht ganz ausgereift, glaube ich mal...
Bisher existieren an Spezialisierungen nur der TasterGND und RelaisINV.
Den Taster haben wir schon gesehen...

Das RelaisINV dient zum schalten der typischen (inversen) China Relais.

Code: [Select]
#include "PinDefinition.h"

using namespace PinDefinition;

RelaisINV<13> relais;

void setup(void)
{
  relais.init();// ohne kurze Low Phase
}

void loop(void)
{
   relais.ein();
   delay(1000);
   relais.aus();
   delay(1000);
}


Die Klassen/Objekte beanspruchen kein Ram.
Der generiert Code beschränkt sich auf das notwendigste.
z.B. relais.aus(); wird übersetzt, wie ein: " PORTB |= 1<<PB5; "
Knapper geht es nicht.


Über Anregungen, Kritik usw. würde ich mich sehr freuen.

Wer seine Meinung nie zurückzieht, liebt sich selbst mehr als die Wahrheit.

Quelle: Joseph Joubert

Doc_Arduino

#18
Jan 17, 2018, 04:20 pm Last Edit: Jan 17, 2018, 09:27 pm by Doc_Arduino
Hallo,

habe mir das angeschaut. Schön das sich jemand dazu Gedanken gemacht hat. Dazu folgende Kritik, natürlich positive.  :)

Wäre es nicht von Vorteil das Bit setzen und löschen Lib intern mit dem klassischen sbi und cbi zu machen?
Bei den "Definitionen" noch ein 4. Array dazu um den echten Pinnamen alias PA4 zum Bsp. dann direkt ansprechen zu können. Dann muss die Lib nicht nochmal extra mit Bitmasken hantieren. Desweiteren wäre ich dafür schon zum bestehenden halbwegs kompatibel zu bleiben. Sprich Funktionsnamen statt digitalWrite() vielleicht setDigital oder digitalSet(). Dann müßte man im Sketch nur digitalWrite gegen den neuen Funktionsnamen austauschen und alles läuft schneller. So stellte ich mir das zumindestens vor, obs wirklich so einfach geht weiß ich nicht.

Arduino Mega2560
Code: [Select]

#include <CombiePinDefinition.h>

#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))   // setzt das angegebene Bit auf 1
#endif
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))  // setzt (löscht) das angegebene Bit auf 0
#endif

// Servopin Definitionen, OUT
#define P12_OUT  sbi (DDRB,6)  // PB6 Ausgang
#define P12_ON   sbi (PORTB,6) // PB6 einschalten
#define P12_OFF  cbi (PORTB,6) // PB6 ausschalten

using namespace Combie::PinDefinition;

RelaisINV<12> relais;

void setup(void)
{
  relais.init();// ohne kurze Low Phase
}

void loop(void)
{
      // 1,6MHz
      relais.ein();
      relais.aus();

      >> oder <<
      
      // 2MHz
      P12_ON;
      P12_OFF;
}
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Doc_Arduino

Hallo,

ich hatte eigentlich an sowas gedacht, scheint aber sinnlos zu sein, sind nur 125kHz drin, nicht besser wie digitalWrite.
Das hätte ich dann auf setDigital(Pin, High/Low)  umbauen wollen. Dann würde es noch langsamer.
Hat nicht sein sollen.  ;)


Code: [Select]

>> fastSwitch.h <<

#pragma once
        

#include <avr/io.h>
 
    // Der Index ist jeweils die Arduino Pinnummer
      
class fastSwitch              
{
  private:                  
    // *** Arduino Mega2560 Pinnummer 0 bis 13
    volatile uint8_t const Pin;      
    volatile uint8_t const *portList[15] = {&PORTE,&PORTE,&PORTE,&PORTE,&PORTG,&PORTE,&PORTH,&PORTH,&PORTH,&PORTH,&PORTB,&PORTB,&PORTB,&PORTB};
    volatile uint8_t const  numList[15]  = {PE0,PE1,PE4,PE5,PG5,PE3,PH3,PH4,PH5,PH6,PB4,PB5,PB6,PB7};
            
    
  public:                    
    fastSwitch (const uint8_t);
    void setDigitalON(void);
    void setDigitalOFF(void);    
};


// -------------------------------------------------------------------- //
>> fastSwitch.cpp <<

#include "fastSwitch.h"


#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))   // setzt das angegebene Bit auf 1
#endif
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))  // setzt (löscht) das angegebene Bit auf 0
#endif
      
      
fastSwitch::fastSwitch (volatile uint8_t _Pin):
  Pin(_Pin)
{ }    


void fastSwitch::setDigitalON(void)
{
  sbi(*portList[Pin], numList[Pin]);
}


void fastSwitch::setDigitalOFF(void)
{
  cbi(*portList[Pin], numList[Pin]);
}
        

// -------------------------------------------------------------------- //
>> fastSwitch.ino <<

// *** Arduino Mega2560 only *** //

#include "fastSwitch.h"

fastSwitch LED (13);

void setup() {
  pinMode(13, OUTPUT);
 
}

void loop() {
  
  // mickrige 125kHz
  LED.setDigitalON();
  LED.setDigitalOFF();
}
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

Ja, ist nicht einfach da die richtige Balance zu finden.

Deine 125k Version muss die Register/Masken zur Laufzeit zusammenstoppeln.
Das wirkt wie ein Stock in den Speichen.

Auf dem Wege habe ich auch experimentiert.
> hat nicht sollen sein!


Auch ist dazu sicherlich interessant, was deine Version mit Flash und Ram anstellt.

Wer seine Meinung nie zurückzieht, liebt sich selbst mehr als die Wahrheit.

Quelle: Joseph Joubert

Doc_Arduino

Hallo,

die obige Version verballert 94 Byte RAM und 1178 Byte Flash.   Man hats ja.  :)
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

Aua..
Das ist recht teuer...

Ja, ich stimme dir zu, meine Variante mag nicht die schönste sein. Und selber bin ich auch noch nicht fertig/glücklich damit.

Aber was solls... es ist ein Prozess...
Wer seine Meinung nie zurückzieht, liebt sich selbst mehr als die Wahrheit.

Quelle: Joseph Joubert

Doc_Arduino

Hallo,

schnell ist deine Version ja, muss man neidvoll zugeben. Scheinbar gehts auch nicht anders wenn es schnell bleiben soll.  Egal wie egal was, irgendwann kommt aus dem Hinterstübchen ein neuer Gedanke. Man darf sich nur von niemanden aufhalten lassen.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Tommy56

Ich glaube bildlich gesprochen das Produkt aus Schnelligkeit und Speicherbedarf ist weitestgehend konstant. Ich erkaufe Geschwindigkeit mit Speicherbedarf oder umgekehrt.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

Doc_Arduino

Hallo,

das dachte ich bis jetzt auch, je mehr RAM im Einsatz umso schneller. Aber combies Version benötigt nur 9 Bytes RAM und 670 Byte Flash.

Code: [Select]

#include <CombiePinDefinition.h>


using namespace Combie::PinDefinition;

RelaisINV<12> relais;

void setup(void)
{
  relais.init();    // ohne kurze Low Phase
}

void loop(void)
{
      // 1,6MHz
      relais.ein();
      relais.aus();
}
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

#26
Jan 17, 2018, 10:04 pm Last Edit: Jan 17, 2018, 10:11 pm by combie
Ja, vielleicht kommt ja noch der goldene Weg zum Vorschein.
Nur eben unwahrscheinlich...
Feilen, an der Erscheinung/Handling, da ist noch was drin.

Quote
nur 9 Bytes RAM
Die gehen für die Arduino Features drauf!
Millis, und der TimerInterrupt usw.
Welche auch den Löwenteil Flash benötigen.


Lässt man loop und setup weg, braucht es 0 Byte Ram, und funktioniert doch.
Selbst die Instanz, die Referenz darauf, wird weg optimiert.

Für das setzen, oder lesen eines Ports gehen jeweils rund 4 Byte Programmspace drauf.
Inclusive Operatorenüberladung.
Eine Inline Assembler Variante könnte bei manchen Zugriffen 2 Byte davon einsparen.
Glaube nicht, dass man in C++ OOP einen schmaleren Fußabdruck hin bekommt.
No!


Quote
Ich erkaufe Geschwindigkeit mit Speicherbedarf oder umgekehrt.
Gegen die Gleichung habe ich lange zeit angekämpft.
Glaube, dass ich damit recht erfolgreich war.

Wer seine Meinung nie zurückzieht, liebt sich selbst mehr als die Wahrheit.

Quelle: Joseph Joubert

Doc_Arduino

Hallo,

ist schon erstaunlich was mit constexpr, inline und templates so alles möglich ist.
Glückwunsch und weitermachen!   ;)

Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

#28
Jan 18, 2018, 03:33 pm Last Edit: Jan 18, 2018, 03:42 pm by combie
Danke für die Blumen!
Und, ja: Ich bleibe dran.

[ot]Da ist mir doch glatt gerade meine Festplatte abgeraucht!
Möge sie in den Plattenhimmel einziehen, und ihre Rohstoffe weiter geben.[/ot]

Testprogramm: (die aktuelle Lib im Anhang)
Code: [Select]
#include <CombiePin.h>

Combie::Pin::OutputPin<4> out;

int main()
{
  out.init();
  for(;;) out.toggle();// 2,667MHz auf einem UNO
}


Quote
Der Sketch verwendet 140 Bytes (0%) des Programmspeicherplatzes. Das Maximum sind 32256 Bytes.
Globale Variablen verwenden 0 Bytes (0%) des dynamischen Speichers, 2048 Bytes für lokale Variablen verbleiben.
--------------

Ein leeres Programm:
Code: [Select]

int main()
{
  for(;;);
}

Quote
Der Sketch verwendet 134 Bytes (0%) des Programmspeicherplatzes. Das Maximum sind 32256 Bytes.
Globale Variablen verwenden 0 Bytes (0%) des dynamischen Speichers, 2048 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.
Der Init, und das Toggeln benötigen zusammen 6 Byte Programmspeicher.
(-: Ich finde das geht :-)

Wer seine Meinung nie zurückzieht, liebt sich selbst mehr als die Wahrheit.

Quelle: Joseph Joubert

Tommy56

Das sieht echt nach einem Sieg über die "Formel" aus. Gratuliere.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

Go Up