Hallo,
die globalen Variablen die in der ISR vorkommen muß ich auch berücksichtigen?
Hallo,
die globalen Variablen die in der ISR vorkommen muß ich auch berücksichtigen?
Inline Assembler würde ich gern bevorzugen, habs aber noch nicht hinbekommen. Vielleicht hat ja jemand eine Idee.
Ich habe eine Idee!
Das was du zeigst, ist Assembler, aber kein Inline Assembler.
Übersetze es in die Inline Syntax, dann geht das auch...
Höchst vermutlich.
Zumindest hast du dann eine weiteren Weg.
Und das bringt dich dann sicherlich wieder einen Schritt weiter.
C Variablen in inline Assembler:
http://rn-wissen.de/wiki/index.php/Inline-Assembler_in_avr-gcc#Zugriff_aufs_SRAM
Hallo,
naja, ich möcht nicht zugreifen, ich muß die definieren. Da er wieder wegen dem Punkt .def meckerte habe ich die beiden benötigten Variablen klassisch C geschrieben. Meckert er nicht an.
Allerdings kennt er den Assemblerbefehl in im ISR nicht. Testweise in Atmel Studio kompilieren lassen. Gleiches Problem. Auch will Studio den Pfad zur m2560def nicht kennen wollen. Wenn die IDE meckert kann ich das ja verstehen, aber Atmel Studio, ist doch ihre eigene Datei. Braucht man die überhaupt?
IDE Fehlermeldungen:
Timer1_Frequenzgenerator_010_asm.ino:8:24: error: m2560def.inc: No such file or directory
Timer1_Frequenzgenerator_010_asm.ino: In function 'void __vector_17()':
Timer1_Frequenzgenerator_010_asm:119: error: expected string-literal before 'in'
Timer1_Frequenzgenerator_010_asm:121: error: 'synchr' was not declared in this scope
Timer1_Frequenzgenerator_010_asm:122: error: expected `;' before 'out'
Atmel Studio Fehlermeldungen:
Compiling 'freq2' for 'Arduino Mega 2560 or Mega ADK'
freq2.ino:4:24: error: m2560def.inc: No such file or directory
freq2.ino:In function 'void __vector_17()'
freq2.ino:119: error: expected string-literal before 'in'
freq2.ino:121: error: 'synchr' was not declared in this scope
freq2.ino:122: error: expected `;' before 'out'
Error compiling
/*
08.07.2015
Arduino Mega2560
*/
#include "m2560def.inc"
#include <avr/io.h>
// globale Variablen
/*
__asm__ (
.def isr_SREG = r2
.def isr_tmp = r16
)
*/
#define isr_SREG = r2
#define isr_tmp = r16
#define INCRMNT 1 // B0000.0001 , Toggle Bit 7...0 im ISR Handler (Pin 30-37)
// legt die Bits/Pin fest die geschalten werden sollen
#define OUTPORT PORTC
// Funktionen deklarieren
void set_Timer0();
void set_Timer1(float Frequency);
void setup() {
OUTPORT = 0; // Port.C alles aus
DDRC = 0xFF; // Port.C alles Ausgänge
set_Timer0(); // schalte Timer0 aus
set_Timer1(44000); // gewünschte Taktfrequenz in Hz - bei Bedarf mit einer Kommastelle
} // Ende Setup
void loop() {
// do other things here
}
// *** Funktionen *** ----------------------------------------------
void set_Timer0()
{
cli(); //stop interrupts
// set Timer-1 Register
TCCR0A = 0; // Reset TCCR1A Register
TCCR0B = 0; // Reset TCCR1B Register, Timer gestoppt
TIMSK0 = 0; // Reset TIMSK1 Register (disable Timer Compare Interrupts)
sei(); //allow interrupts
} // end Funktion
void set_Timer1(float Frequency)
{ // berechnet den best möglichen CMR Wert und setzt den Timer 1
long CPU_Takt = 16000000;
int usedPrescaler[]={1,8,64,256,1024}; // mögliche Prescaler
int Prescaler = 0;
long maxCMR = 65535; // max. Compare Match Register Wert
long new_CMR = 0; // passender errechneter Compare Match Register Wert
if (Frequency < 0.2 || Frequency > 8000000) { // Gültigkeitskontrolle
Prescaler = 0;
new_CMR = 0;
}
else {
for ( byte i = 0; i<5; i++) {
new_CMR = (long) (CPU_Takt/(usedPrescaler[i]*Frequency*2)-1+0.5); // CMR Berechnung und runden
if (new_CMR <= maxCMR && new_CMR >= 0) {
Prescaler = usedPrescaler[i];
break;
}
}
if (new_CMR < 0 || new_CMR > maxCMR) { // Ergebnis Gültigkeitsprüfung
Prescaler = 0;
new_CMR = 0;
}
} // end else
cli(); //stop interrupts
// set Timer-1 Register
TCCR1A = 0; // Reset TCCR1A Register
TCCR1B = 0; // Reset TCCR1B Register
TIMSK1 = 0; // Reset TIMSK1 Register (disable Timer Compare Interrupts)
TCNT1 = 0; // initialize counter value to 0
OCR1A = new_CMR; // Compare Match Register <= 65535
TCCR1B |= (1 << WGM12); // turn on CTC mode
switch (Prescaler) { // set Prescaler Clock Select Bits
case 1 : TCCR1B |= (1 << CS10);
TIMSK1 |= (1 << OCIE1A); // enable Timer Compare Interrupt Bit
break;
case 8 : TCCR1B |= (1 << CS11);
TIMSK1 |= (1 << OCIE1A);
break;
case 64 : TCCR1B |= (1 << CS11) | (1 << CS10);
TIMSK1 |= (1 << OCIE1A);
break;
case 256 : TCCR1B |= (1 << CS12);
TIMSK1 |= (1 << OCIE1A);
break;
case 1024 : TCCR1B |= (1 << CS12) | (1 << CS10);
TIMSK1 |= (1 << OCIE1A);
break;
default : ; // to do nothing, sollte nicht passieren
} // Ende switch
sei(); //allow interrupts
} // end Funktion
ISR(TIMER1_COMPA_vect) { // Timer 1 Interrupt
__asm__ (
in isr_SREG,SREG
in isr_tmp,OUTPORT
subi isr_tmp,INCRMNT ; synchr. pos. Flanke
out OUTPORT,isr_tmp
out SREG,isr_SREG
);
}
Schau dir das mal genauer an. Inline Assembler wird aus irgendeinem Grund als String geschrieben.
Hallo,
die " " haben gefehlt. Jetzt meckert er aber noch wegen der nicht gefundenen m2560def.inc rum.
Kommentiere ich das aus, kommt
C:\Users\Worker\AppData\Local\Temp/cc7RpVdp.s: Assembler messages:
C:\Users\Worker\AppData\Local\Temp/cc7RpVdp.s:19: Error: unknown pseudo-op: `.def'
C:\Users\Worker\AppData\Local\Temp/cc7RpVdp.s:396: Error: constant value required
C:\Users\Worker\AppData\Local\Temp/cc7RpVdp.s:396: Error: constant value required
C:\Users\Worker\AppData\Local\Temp/cc7RpVdp.s:396: Error: garbage at end of line
Wie schreibt man das include mit Pfadangabe? Oder die Datei gleich wohin kopieren. Wohin? Wo sucht er?
/*
08.07.2015
Arduino Mega2560
*/
#include "m2560def.inc"
#include <avr/io.h>
// globale Variablen
__asm__ (
".def isr_SREG = r2"
".def isr_tmp = r16"
);
#define INCRMNT 1 // B0000.0001 , Toggle Bit 7...0 im ISR Handler (Pin 30-37)
// legt die Bits/Pin fest die geschalten werden sollen
#define OUTPORT PORTC
// Funktionen deklarieren
void set_Timer0();
void set_Timer1(float Frequency);
void setup() {
OUTPORT = 0; // Port.C alles aus
DDRC = 0xFF; // Port.C alles Ausgänge
set_Timer0(); // schalte Timer0 aus
set_Timer1(44000); // gewünschte Taktfrequenz in Hz - bei Bedarf mit einer Kommastelle
} // Ende Setup
void loop() {
// do other things here
}
// *** Funktionen *** ----------------------------------------------
void set_Timer0()
{
cli(); //stop interrupts
// set Timer-1 Register
TCCR0A = 0; // Reset TCCR1A Register
TCCR0B = 0; // Reset TCCR1B Register, Timer gestoppt
TIMSK0 = 0; // Reset TIMSK1 Register (disable Timer Compare Interrupts)
sei(); //allow interrupts
} // end Funktion
void set_Timer1(float Frequency)
{ // berechnet den best möglichen CMR Wert und setzt den Timer 1
long CPU_Takt = 16000000;
int usedPrescaler[]={1,8,64,256,1024}; // mögliche Prescaler
int Prescaler = 0;
long maxCMR = 65535; // max. Compare Match Register Wert
long new_CMR = 0; // passender errechneter Compare Match Register Wert
if (Frequency < 0.2 || Frequency > 8000000) { // Gültigkeitskontrolle
Prescaler = 0;
new_CMR = 0;
}
else {
for ( byte i = 0; i<5; i++) {
new_CMR = (long) (CPU_Takt/(usedPrescaler[i]*Frequency*2)-1+0.5); // CMR Berechnung und runden
if (new_CMR <= maxCMR && new_CMR >= 0) {
Prescaler = usedPrescaler[i];
break;
}
}
if (new_CMR < 0 || new_CMR > maxCMR) { // Ergebnis Gültigkeitsprüfung
Prescaler = 0;
new_CMR = 0;
}
} // end else
cli(); //stop interrupts
// set Timer-1 Register
TCCR1A = 0; // Reset TCCR1A Register
TCCR1B = 0; // Reset TCCR1B Register
TIMSK1 = 0; // Reset TIMSK1 Register (disable Timer Compare Interrupts)
TCNT1 = 0; // initialize counter value to 0
OCR1A = new_CMR; // Compare Match Register <= 65535
TCCR1B |= (1 << WGM12); // turn on CTC mode
switch (Prescaler) { // set Prescaler Clock Select Bits
case 1 : TCCR1B |= (1 << CS10);
TIMSK1 |= (1 << OCIE1A); // enable Timer Compare Interrupt Bit
break;
case 8 : TCCR1B |= (1 << CS11);
TIMSK1 |= (1 << OCIE1A);
break;
case 64 : TCCR1B |= (1 << CS11) | (1 << CS10);
TIMSK1 |= (1 << OCIE1A);
break;
case 256 : TCCR1B |= (1 << CS12);
TIMSK1 |= (1 << OCIE1A);
break;
case 1024 : TCCR1B |= (1 << CS12) | (1 << CS10);
TIMSK1 |= (1 << OCIE1A);
break;
default : ; // to do nothing, sollte nicht passieren
} // Ende switch
sei(); //allow interrupts
} // end Funktion
ISR(TIMER1_COMPA_vect) { // Timer 1 Interrupt
__asm__ (
"in isr_SREG,SREG"
"in isr_tmp,outPORT"
"subi isr_tmp,incrmnt" // synchr. pos. Flanke
"out outPORT,isr_tmp"
"out SREG,isr_SREG"
);
}
Wie schreibt man das include mit Pfadangabe?
Studio?
Nicht meine Baustelle...
Aber ich würde mal tippen, dass es so aussehen muss:
#define __AVR_ATmega2560__
#include <avr/io.h>
Ein #include "m2560def.inc" brauchst du wohl nicht.
Aber das schützt dich nicht vor den anderen Fehlern ...
Hast du überhaupt schonmal geschaut, ob der Aufwand irgendwas bringt?
(Vergleich mit dem disassembly einer avr-gcc ISR)
Wenn ja, wieviele nanosekunden?
Oder gehts nur um den sportlichen Ehrgeiz, assembler-Programmierung zu schaffen?
Hallo,
so liest du also meine Beiträge? Alles nur überflogen.
Ich würde mich jetzt nicht mit Assembler abgeben wenn ich es nicht müßte, wobei die Assembler Freaks da anderer Meinung sind. Das Hauptproblem ist ja nicht Assembler an sich. Sondern C und Assembler zu mixen. Ich möchte einen Frequenzgenerator bauen und da zählt jeder eingesparte Takt in der Code-Abarbeitung im ISR.
Bsp. Prescaler 1 und Compare Match 0 hat man 8MHz. Steht Compare Match auf 1 hat man nur noch 4MHz. Steht der auf 3 hat man nur noch 2MHz usw.
Den Interrupt Handler in C geschrieben benötigt der 51 Takte. Bedeutet, Compare Match Register mit kleiner 51 laden funktioniert nicht mehr, Takt kommt außer Tritt. Den in Assembler geht bis 14 runter. Damit ist mehr als der doppelte Takt drin bis ca. 500kHz. Für ein Rechtecksignal bräuchte ich das nicht, aber für ein Sinus ist das mehr als sinnvoll.
so liest du also meine Beiträge?
schäm stimmt, im Beitrag #3 hätte ich es sehen können.
Ein Rechtecksignal kriegt man ohne Software hin und kommt so in den MHz Bereich, einen Sinus anzunähern geht so wohl nicht. (Keine Ahnung)
Dafür hat so ein Controller ja die Timer und ihr konfigurierbares Verhalten, und ihre Verbindungen zu GPIOs.
Wenn 50 prozessortakte zu viel sind und eine Reduktion um insgeamt 30 Takte je Interrupt möglich (?), würde ich sagen, du sitzt auf dem falschen Pferd oder reitest mindestens in die falsche Richtung...
Aber jetzt will ich nicht mehr meckern, und (unter dem "sportlichen" Aspekt) heimlich weiter mitlesen. Viel Erfolg!
Hallo,
falsche Richtung ist so eine Sache. Ich wollte eben was programmieren und aus dem Atmel µC rausholen was eben möglich ist. Klar man könnte sich auch einen DDS von Analog Devices schnappen und den mit µC befehligen. Ich möchte es erstmal ohne versuchen. Wenn ein max. Takt im niedrigen kHz Bereich mit brauchbaren Sinus rauskommt wäre ich schon zufrieden. Mal sehen. Mitlesen darf jeder. Wenn ich was neues rausgefunden habe zum Thema werde ich es mitteilen.
Hallo,
eine Update der Geschichte. Auch wenn es das letzte sein wird zu dem Thema. Jedenfalls funktioniert der Code erstmal. Beim Inline Assembler war fremde Hilfe im Spiel. Da bin ich ehrlich, wie immer. Ich wollte es Euch nicht vorenthalten.
Inline_Assembler.c (3.12 KB)