UNO R4 Minima and UNO Rev4 Wifi werden unterstützt
stepper.read() kann die aktuelle Winkelposition auch in Bruchteilen zurückgeben ( z.B. 1/10° )
Hallo,
ich habe dies auch schon im internationalen Teil gepostet. Ich hoffe trotzdem, dass das hier nicht als Cross-Posting gebannt wird , da es sich eher speziell an die deutschen Anwender der Lib wendet, und nicht alle aus dem deutschen Forum auch im englischen Teil aktiv sind.
Ich habe ein paar Erweiterungen gemacht, und auch neue Cores werden unterstützt. Falls jemand Lust hat, die Beta etwas zu testen, würde ich mich freuen. Und wenn es nur darum geht zu prüfen, ob vorhandene Projekte noch mit der neuen Version laufen - auch das hilft schon.
Folgendes ist neu:
Der ATmega 4809 ( Nano Every, UNO WiFi Rev2 ) wird nun unterstützt.
Der ESP32 Core V2.x konnte nicht verwendet werden, da es zu Kompilierfehlern kam. Das sollte beseitigt sein.
Beim Stepper darf nun auch die Geschwindigkeit auf 0 gesetzt werden ( .setSpeedSteps(0); ). Der Stepper fährt mit Rampe bis zum Stillstand. Wenn entsprechend konfiguriert, wird er auch abgeschaltet. Die derzeit aktive Zielposition geht aber nicht verloren. Wird die Geschwindigkeit wieder heraufgesetzt, wird die Fahrt dorthin fortgesetzt. Das Ziel darf auch während des Stillstands geändert werden.
Beim Lesen der aktuellen Steprate ( .getSpeedSteps(); ) wird über ein Vorzeichen auch die Drehrichtung übermittelt. Bisher war das Ergebnis vorzeichenlos.
Auch unipolare Stepper (4-Pins) können nun per attachEnable im Stillstand abgeschaltet werden. Ein eigener EnablePin ist nicht erforderlich, es werden einfach alle 4 Ausgänge abgeschaltet (LOW). Das funktioniert auch, wenn die Stepper über SPI/Schieberegister angesteuert werden.
Bei den Servos gibt es eine neue Methode um die Geschwindigkeit festzulegen. Mit .setSpeedTime( time ); wird die Zeit (in ms) vorgegeben, die das Servo benötigt, um sich von 0° auf 180° zu bewegen.
Die Doku ist entsprechend aktualisiert. Das Zip-file kann hier heruntergeladen werden.
F:\arduino\libraries\MobaTools-Development2.5.0\src\utilities\MoToSoftledESP.cpp: In function 'void ISR_Softled(void*)':
F:\arduino\libraries\MobaTools-Development2.5.0\src\utilities\MoToSoftledESP.cpp:30:21: warning: this statement may fall through [-Wimplicit-fallthrough=]
changePulse = LINEAR;
F:\arduino\libraries\MobaTools-Development2.5.0\src\utilities\MoToSoftledESP.cpp:31:7: note: here
case INCBULB: // no difference in first version
^~~~
F:\arduino\libraries\MobaTools-Development2.5.0\src\utilities\MoToSoftledESP.cpp:55:21: warning: this statement may fall through [-Wimplicit-fallthrough=]
changePulse = LINEAR;
F:\arduino\libraries\MobaTools-Development2.5.0\src\utilities\MoToSoftledESP.cpp:56:7: note: here
case DECBULB:
^~~~
F:\arduino\libraries\MobaTools-Development2.5.0\src\utilities\MoToStepper.cpp: In member function 'void MoToStepper::detach()':
F:\arduino\libraries\MobaTools-Development2.5.0\src\utilities\MoToStepper.cpp:273:19: warning: this statement may fall through [-Wimplicit-fallthrough=]
pinMode( _stepperData.pins[2], INPUT );
~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
F:\arduino\libraries\MobaTools-Development2.5.0\src\utilities\MoToStepper.cpp:275:7: note: here
case A4988_PINS: // only pins 0/1
^~~~
Der Sketch verwendet 798325 Bytes (60%) des Programmspeicherplatzes. Das Maximum sind 1310720 Bytes.
Globale Variablen verwenden 48712 Bytes (14%) des dynamischen Speichers, 278968 Bytes für lokale Variablen verbleiben. Das Maximum sind 327680 Bytes.
Hallo,
danke für's Testen. das 'Durchfallen' ist da Absicht, allerdings fehlte noch der entsprechende Hinweis an den Compiler. Sollte jetzt behoben sein ( zip auf GitHub ist aktualisiert ).
Aufgrund des Testergebnis von @Doc_Arduino habe ich jetzt noch einen gemeinen Fehler beim 4809 gefunden - speziell wenn Servos und Stepper parallel betrieben werden. Beim update der 16-Bit timer-Register ist der scheinbar noch etwas kritischer als die alten ATMegas. Hab's vorsichtshalber aber auch da korrigiert. Hatte zwar nicht direkt mit dem warning zu tun, aber wenn man erstmal an einem Zipfelchen zieht ...
Die compare-Register sind ja 16 Bit-Register, der Prozessor aber nur 8 Bit. Also braucht es 2 Schritte so ein Register zu ändern. Die ersten 8 Bit werden in einen Zwischenspeicher geschrieben, mit dem 2. Schreibbefehl werden dann die gesamten 16 Bit ins Compare-Register geschrieben. Das hat erstmal nichts damit zu tun, ob ich das Comparregister sofort verändern will, oder die gepufferte Variante verwende. Da es 2 Schritte sind, sollte da nichts ( IRQ) dazwischenfunken. Das war an einer Stelle nicht gegeben. Beim 328P hat es offensichtlich nichts ausgemacht, wenn das Schreiben der beiden comparregister nicht abgesichert war - dieses 8-Bit Zwischenregister ist wohl für jedes Compare-Register getrennt. Der 4809 scheint nur 1 Zwischenregister für alle 16-Bit Register zu haben. Wenn also das Schreiben in ein Register von einem IRQ unterbrochen wird, der ins andere Register schreibt, rauchts. ( Servo und Stepper ) .
Ich habe das Datenblatt aber noch nicht genau nach diesem Problem gelesen. Es scheint aber bei 4809 anders zu sein als beim 328P - das zeigen die Versuche eindeutig. Jetzt ist es aber überall abgesichert und die (hoffentlich letzte) Lücke in dieser Hinsicht geschlossen.
prinzipiell erstmal formal richtig, aber wenn man konsequent die Bufferregister verwendet, dann funktioniert das automatisch richtig. Die Timer haben noch ein Valid Bit was das Update erst freigibt wenn der neue Wert komplett im Buffer steht, erst dann wird es übernommen. Meine Bitte. Verwende konsequent die Bufferregister.
Ob man die Bufferregister verwendet, oder die Compareregister direkt verändert, hängt sehr von der Anwendung ab. Es hat seinen Grund, weshalb es beide Möglichkeiten gibt. Bei den MobaTools kann ich die Bufferregister - die ja erst bei bestimmten Ereignissen, z.B. Timerüberlauf ins Compareregister geschrieben werden - nicht gebrauchen. Die Synchronisation von zwei 8-Bit Zugriffen mit Zwischenspeichern des ersten Bytes und dann aktualisieren des 16-Bit Registers in einem Takt ist ja immer gegeben. Das hat auch nichts mit puffern oder nicht zu tun. Wenn diese Synchronisation schief geht, steht auch ein falscher Wert im Bufferregister.
Immer. Anders ginge das auch gar nicht, wenn man so viele zeitgesteuerte Signale ( bis 6 Stepper, bis 16 Servos und die Softleds) mit einem Timer erzeugen will. Der Timer läuft immer mit festem TOP durch, und über das Verschieben der CMP-Register werden zum passenden Zeitpunkt die Irq's für das Steuern der Ausgänge und die Berechnung des nächsten CMP Wertes erzeugt.
Ich habe jetzt nochmal die Datenblätter studiert. Von daher sollte es eigentlich keinen Unterschied zwischen 386P und 4809 geben. Beide benutzen ein temporäres 8-Bit Zwischenregister für den 16-Bit Zugriff, und beide haben auch nur ein solches Zwischenregister für alle 16-Bit Register eines Timers. Der einzige Unterschied ist, dass man beim 4809 dieses Zwischenregister auch direkt schreiben/lesen kann ( was ich nicht tue ).
Der Zugriff muss also bei beiden atomar mit gesperrten Interrupts erfolgen. Bis auf die eine Stelle, wo ich es vergessen hatte, war das auch überall so. Warum sich das an der Stelle bisher beim 386P nicht bemerkbar gemacht hat und beim 4809 ziemlich schnell zur Blockade führt, entzieht sich meiner Kenntnis.
Aber jetzt ist ja auch dieses Loch gestopft .
Es wird erst das High Byte und dann das Low Byte geschrieben. Das ist normal. Dazu kommt der Automatismus des Valid Flags für die endgültige Übernahme.
Ein kleiner Unterschied zwischen alten und neuen µC Gen. ist, dass man bei den Neuen die Buffer-Register immer zur Verfügung hat und man wählen kann ob man diese nutzt oder nicht. Bei den alten Controllern ist das "Vorhandensein" der Buffer-Register abhängig vom Timermode und sie sind auch nicht wählbar. Im entsprechenden Timermode werden sie "intern" ohne zu tun des Anwenders einfach verwendet.
Wegen der Art der Pulserzeugung. Bspw. Servo. Du erzeugst innerhalb einer Periode alle Servopulse hintereinander. Richtig? Die Berechnung und das Update für den nächsten Comparewert machst du in einer Timer ISR. Richtig? Das müßte die Datei MoToMegaAVR.cpp sein Zeile 22 ISR ( TCA0_CMP1_vect). Richtig?
Hier hast du die Interruptsperren eingefügt?
Ich habe die alte 2.5 Version nicht mehr zum vergleichen.
Wegen den unterschiedlichen Verhalten hätte ich vielleicht eine Antwort. Die alten ATmegas haben keine unterbrechenbaren Interrupts. Die neue Gen. haben unterbrechenbare Interrupts. So lese ich Kapitel 13.3.2.4. im Manual Version DS40002173C. Wenn der neue Interrupt eine höhere Prio hat wird der Aktuelle unterbrochen. Allerdings habe alle Interrupts Standardmäßig "normaly priority" Level 0. Da müßte jemand einen Interrupt auf Level 1 gesetzt haben damit ein laufender ISR unterbrochen wird. Allerdings sind alle 4 CPUINT Register 0 wenn ich diese auslese. Das heißt normalerweise müßte in deiner TCA0_CMP1 ISR nichts extra abgeschalten werden. Habe da aktuell keinen Ansatz bzw. Erklärung für das Verhalten.
Dann fiel mir noch was auf. Ich verwende öfters das MegaCoreX Package. Wenn ich damit bspw. das Bsp. Servo_01 kompiliere erhalte ich
In file included from C:\Arduino IDE Portable\megaAVR0\arduino-1.8.19\portable\sketchbook\libraries\MobaTools\src/utilities/MoToBase.h:11:0,
from C:\Arduino IDE Portable\megaAVR0\arduino-1.8.19\portable\sketchbook\libraries\MobaTools\src/MobaTools.h:196,
from C:\Arduino IDE Portable\megaAVR0\arduino-1.8.19\portable\sketchbook\libraries\MobaTools\src\utilities\MoToStepper.cpp:13:
C:\Arduino IDE Portable\megaAVR0\arduino-1.8.19\portable\sketchbook\libraries\MobaTools\src/megaAVR/MoToMegaAVR.h: In function 'void initSpiAS()':
C:\Arduino IDE Portable\megaAVR0\arduino-1.8.19\portable\sketchbook\libraries\MobaTools\src/megaAVR/MoToMegaAVR.h:76:41: error: 'MoToSS' was not declared in this scope
portSS = digitalPinToPortStruct(MoToSS);
^
C:\Arduino IDE Portable\megaAVR0\arduino-1.8.19\portable\packages\MegaCoreX\hardware\megaavr\1.1.2\cores\coreX-corefiles/Arduino.h:114:40: note: in definition of macro 'digitalPinToPortStruct'
#define digitalPinToPortStruct(pin) ( (pin < NUM_TOTAL_PINS) ? ((PORT_t *)&PORTA + digitalPinToPort(pin)) : NULL)
^~~
C:\Arduino IDE Portable\megaAVR0\arduino-1.8.19\portable\sketchbook\libraries\MobaTools\src/megaAVR/MoToMegaAVR.h:76:41: note: suggested alternative: 'portSS'
portSS = digitalPinToPortStruct(MoToSS);
^
C:\Arduino IDE Portable\megaAVR0\arduino-1.8.19\portable\packages\MegaCoreX\hardware\megaavr\1.1.2\cores\coreX-corefiles/Arduino.h:114:40: note: in definition of macro 'digitalPinToPortStruct'
#define digitalPinToPortStruct(pin) ( (pin < NUM_TOTAL_PINS) ? ((PORT_t *)&PORTA + digitalPinToPort(pin)) : NULL)
^~~
Wo wird MoToSS definiert? Vorallen warum kompiliert das ohne MegaCoreX?
Zwei Semikolons könnten in der MoToMegaAVR.h entfernt werden. Zeile 56 und 63. oldSREG könnte man const machen.
Beeindruckend finde ich auch etwas ganz anderes, nämlich das du einen 386P mit der Arduino IDE programmierst. Hut ab.
falsch, das ist der Interrupt für Stepper und Softleds. Die Servos hängen am CMP0.
richtig
Doch, da in der Stepper ISR die Interrupts wieder eingeschaltet werden. Das muss sein, da dieser IRQ rel. lange laufen kann ( bis zu knapp 200µs, je nach Auslastung mit Steppern und Softleds). Deshalb wird nach den zeitkritischen Dingen und während der zeitaufwändigen Berechnungen für Beschleunigen und Bremsen der Interrupt wieder freigegeben.
Die Servo ISR ist da unkritischer, deshalb gibt es da keine Interruptfreigabe. Die Servo-ISR kann die Stepper-ISR unterbrechen, aber nicht umgekehrt. Das ist auch der kritische Punkt, da die Servo ISR auch ihr CMP0-Register setzt, und damit den Zwischenspeicher verändert.
Das liegt daran, dass die MegaCoreX nicht compatibel zum Arduino megaAVR ist. Es werden andere nicht alle Compiler-Defines gesetzt und ich kann dann z.B. nicht zwischen Nano Every und UNO Wifi Rev 2 unterscheiden. Die MegaCoreX müsste extra unterstützt werden. Sie hätte auch Vorteile, weil da millis() nicht den TCA0 Prescaler belegt. Meines Wissens unterstützt sie aber nicht den Standard-Bootloader des Nano Every.
Das dürfte nicht funktionieren. Da steht kein konstanter Wert drin. ( Die 2 überflüssigen Semikola habe ich gelöscht - stammt vom vielen hin- und her editieren bei der Fehlersuche )
Das passiert mir öfters. Irgendwie mögen meine Finger das '328P' nicht so richtig - warum auch immer
Nochwas wegen Every Bootloader. Der hat in dem Sinne wie man das kennt keinen Bootloader. Da sitzt ein extra Controller drauf der das alles übernimmt. Deswegen sollte das bezüglich des Core Packages keinen Unterschied machen.
Erst ein nackter Controller, Eigenbauboard etc. benötigt einen Bootloader. Kann aber auch gut sein das MegaCoreX auch hierfür irgendwelche #defines verwendet zur eigenen Unterschied. Vielleicht meinst du das sogar vielleicht.
Das andere wegen den #defines wird natürlich so ein. Da ist einiges anders und genau wie du sagst hätte man den TCA0 frei.
Wegen Sicherung oldSREG nochmal. Schreib mal const davor und probiere es aus. Es wird funktionieren. Danach weißt du sicherlich warum.
Egal ob das Laden auf dem Board von einem Bootloader auf dem 4809 oder von einem eigenen Controller übernommen wird - die PC-Seite muss mit dem Protokoll klarkommen. Bisher habe ich das mit dem MegaCoreX noch nicht geschafft - egal welchen Bootloader man da auswählt ( ist ja immer Optiboot ).
Vielleicht kannst Du mir da ja einen Tip geben?
Zum const - Du hast natürlich recht, da das oldSREG an der Stelle immer neu angelegt, initiiert und danach nicht mehr verändert wird, funktioniert das. Ist aber ein sehr überschaubarer Gültigkeitsbereich, da ist die Gefahr einer versehentlichen Änderung gering . Hab's übernommen - schaden tut's ja nicht