Ist Assembler in der IDE möglich?

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. :astonished:

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. :slight_smile: 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. :slight_smile: Ich wollte es Euch nicht vorenthalten.

Inline_Assembler.c (3.12 KB)