- 12V Akku mit 280 Ah bauen         
Ergebnis 1 bis 10 von 49

Thema: HaikuVM A Java VM for ARDUINO and other micros using the leJOS runtime.

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Hi,
    ich versuche, den Nibobee mit Java zu programmieren. Einfache Dinge wie zum Beispiel die Ansteuerung der LED's gelingen mir auch ganz gut, Probleme machen mir - wie eigentlich zu erwarten - die Hardware-Interrupts.
    Java ist ja nun nicht für die direkte Kommunikation mit der Hardware gedacht. Also war mein Gedanke, die Interrupt-Routinen in C zu schreiben, und diese dann per JNI in meine Java-Anwendung einzubinden. In C (und ASM) hab ich mit dem Asuro auch schon einige Erfahrungen sammeln können, auch die Bearbeitung von Interrupts. Mit Java und insbesondere mit dem JNI habe ich aber keine Erfahrungen.

    Hat jemand einen Lösungsansatz für mich?

    Versucht habe ich, die Interrupts irgendwie ohne JNI einzubinden, indem ich einfach per setMemory8 GICR, MCUCR und SREG konfiguriert und dann eine ISR (wie ich naiv glaubte) namens SIGNAL_SIG_INTERRUPT1 zu schreiben. IRGENDWAS tut der Robot auch bei dem Interrupt, ich bin mir allerdings ziemlich sicher, dass unmittelbar ein RESET folgt.

    Übrigens: Ich nutze außer haiku.vm.MemoryAccess keine vorbereiteten Pakete, auch nicht die Asuro-Lib (weil zum Beispiel Sleep oder Msleep nicht funktioniert, der Asuro ist ja ganz anders konfiguriert).

  2. #2
    kaijoe
    Gast
    Danke Haikuvm,

    das mit der Umleitung werde ich ausprobieren.
    Ich wusste nicht, dass das auch in Windows geht.

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    25.01.2013
    Beiträge
    12
    Hallo haikuvm,

    Ich hab jetzt avr-gcc 4.5.1 und es funktioniert!
    vielen Dank, nun kann ich mich zu eigenen Projekten vor wagen.

  4. #4
    Neuer Benutzer Öfters hier
    Registriert seit
    28.10.2012
    Beiträge
    26
    Hallo mlade,

    ja, gerne helfe ich. Deutlich besser gelingt die Hilfe wenn ich viel Feedback kriege.

    1) So habe ich in Post #6 schon mal was zum NIBObee geschrieben. Aber leider noch kein Feedback bekommen. Tut's das so, wie dort beschrieben, für dich?

    2) Ja, wenn du nichts vom ASURO übernehmen willst, nimm einen noch einfacheren MicroKernel und trag das Folgende in Datei 'HaikuVM.properties' ein:
    Code:
    # NIBObee
    nibobee.Extends = AVR
    nibobee.Target = atmega16
    nibobee.MemorySize = 700
    nibobee.Clock = 15000000
    nibobee.MicroKernel = haiku.avr.lib.simple010.HaikuMicroKernel
    3) Fang mit dem Programm 'avr/tutorial/BlinkSimple.java' an und steigere dich dann zu 'avr/tutorial/Blink.java'. Wahrscheinlich mußt du den Port änderen. Hin zu dem Port auf dem der NIBObee seine LEDs hat. (Deine Änderung würde mich als Feedback interessieren.) Mich würde auch interessieren wie du in 'avr/tutorial/Blink.java' den Wert für TCCR0B setzt, damit Thread.sleep(..), Thread.wait(..), System.currentTimeMillis() und der interne Thread Scheduler von HaikuVM den richtigen Millisekunden Takt bei 15Mhz bekommen?!

    4) Interrupts ja! Aber wie du schon aus 3) erahnen kannst, bitte nicht 'TIMER0_OVF_vect' verwenden (findet sich in Datei './haikuVM/simpleOS.c'), denn den braucht HaikuVM selbst.

    5) Ich werde auf der HaikuVM Page demnächst eine Serie kleiner Tutorials bringen. Eines davon wird Interrupts behandeln. Wir können ja hier - mit deiner Hilfe - damit beginnen :
    Zu diesem Tutorial wird es die Datei './haikuVM/myCProject/tutorials/interrupt.c' geben. Ich bin aber noch nicht so weit und habe nur eine Skizze und erste Idee. Vielleicht kannst du mir beim vervollständigen helfen? Der einfache Plan (für Anfänger) lautet so: Es soll (in C) einen Interrupthandler für den TIMER2 geben der nichts weiter macht als die Interrupts zählen. Mit der HaikuVM-JNI Funktion 'native_avr_tutorial_Interrupt1_getTimer2_J(..)' wird der Zähler ausgelesen. Man braucht dann nur noch 'Java_avr_tutorial_Interrupt1_getTimer2( JNIEnv *env, jobject obj)' selbst zu schreiben.

    Die Datei './haikuVM/myCProject/tutorials/interrupt.c' wird deshalb ca. so aussehen:
    Code:
    #include "haikuJ2C.h"
    #include <avr/interrupt.h>
    
    volatile static jlong timer2_interrupts = 0;
    
    SIGNAL (SIG_OVERFLOW2)
    {
          timer2_interrupts ++;
    }
    
    jlong Java_avr_tutorial_Interrupt1_getTimer2( JNIEnv *env, jobject obj) {
        jlong value;
        uint8_t oldSREG = SREG;
        cli();
        value= timer2_interrupts;
        SREG = oldSREG;
        return value;
    }
    
    /**
     * Automatic generated (see ./myCProject/haikuC/haikuJNI.c)
     * getTimer2()J
     */
    void native_avr_tutorial_Interrupt1_getTimer2_J(void) {
        pushTop();    // Save variable top onto stack.
        {
            jobject    obj = NULL;
            JNIEnv *env = NULL;
            top.j = Java_avr_tutorial_Interrupt1_getTimer2(env, obj);
        }
        // Variable top holds the return value. But we have to push the lower half.
        pushTop0();
    }
    Im JAVA Programm des Tutorials 'avr/tutorial/Interrupt1.java' (sieht ähnlich aus wie 'avr/tutorial/Blink.java') wird die native Funktion getTimer2() deklariert:
    Code:
    public static native long getTimer2();
    In der JAVA main(..) Methode von 'avr/tutorial/Interrupt1.java' wird zu Beginn der TIMER2 und sein Interrupt gesetzt ca.:
    Code:
    TCCR2 = _BV(WGM20) | _BV(WGM21) | _BV(COM20) | _BV(COM21) | _BV(CS20);
    TIMSK |= _BV(TOIE2);
    und dann in einer (Endlos-) Schleife getTime2() aufgerufen um den Wert (timer2_interrupts) auszulesen.

    6) Vielleicht, mit deiner Hilfe würde ich auch gerne ein Interrupt Tutorial für den ADC machen.
    Geändert von haikuvm (20.02.2013 um 23:27 Uhr)

  5. #5
    Hi,
    danke für die schnelle und vor allem umfangreiche Antwort.
    Zu 1:
    Ja, nach der Anleitung in diesem Post habe ich begonnen. Allerdings habe ich noch nie avrdude benutzt, und da das Hochladen so nicht auf Anhieb funktioniert hat, habe ich weiterhin den nibobee-programmer benutzt, indem ich die entstehende .hex-Datei aus dem Verzeichnis target\cross hochgeladen hab.
    Ich bin jedoch schon bald darüber gestolpert, dass die in der Asurolib definierten Methoden Sleep() und Msleep() nicht funktionieren. Ich hab mir das bis jetzt noch nicht näher angesehen, sondern einfach eine Schleife benutzt, um Zeit zu verschlafen, denn ich wollte ja erst mal einfach nur mit einer LED blinken. Ich gehe mal davon aus, das die Konfiguration des Timers, so wie sie für den Asuro benutzt wird, nicht für den nibobee funktioniert.
    Zu 2:
    Ok, werd ich machen.
    Zu 3:
    Meine Umsetzung von "Blinksimple" besteht aus 2 Klassen. Led.java definiert die Klassenkonstanten PORTB und DDRB, welche die Adressen der gleichnamigen Register enthalten. Außerdem gibt es 3 Klassenmethoden, weche die Initialisierung der Hardware übernehmen, die 4 LED's ein- oder ausschalten oder von einer zur nächsten weiterschalten.
    Led.java:
    Code:
    import static haiku.vm.MemoryAccess.*;
    
    public class Led {
    	public static final int DDRB=(((0x17) + 0x20));
    	public static final int PORTB=(((0x18) + 0x20));
    
    	public static void LedInit() {
    		setMemory8(DDRB,(getMemory8(DDRB)| 0b00001111));
    		setMemory8(PORTB, 0b00000001);
    	}
    	
    	public static void LedSwitch(){
    		int portb;
    		portb=getMemory8(PORTB);
    		if (portb < 0b00001111){
    			setMemory8(PORTB, (portb << 1));
    		}
    		else {
    			setMemory8(PORTB, 0b00000001);
    		}
    	}
    	
    	public static void LedSet(int leds){
    		if (leds > 0b00001111){
    			leds=0b00001111;
    		}
    		setMemory8(PORTB,leds);
    	}
    }
    Die Klasse TestLed.java enthält eine Klassenmethode, welche die Schleife für die Wartezeit durchläuft (als simpler Ersatz für Sleep(), wird später natürlich über den Timer geregelt, da gehe ich als nächstes dran). Außerdem enthält sie main(), in welcher einfach nur eine Art Lauflicht gebaut wird, indem nach der Initialisierung Led nach der anderen an- und ausgeschaltet wird (ich hätte auch statt LedSet mit zaehler einfach LedSwitch ohne Argumente verwenden können):
    TestLed.java:
    Code:
    public class TestLed {
    
    	private static void Sleep (int msec) {
    		int j;
    		for (int i=0; i<(msec*7); i++) {
    			j=i;
    		}
    	}
    	
    	public static void main (String args[]){
    		int zaehler=0;
    		Led.LedInit();	// 1. Led an
    		while (true){
    			while (zaehler < 4){
    				Led.LedSet((0b00000001 << zaehler)); 
    				zaehler++;
    				Sleep(1000);
    			}
    			zaehler=0;
    		}	
    	}
    }
    Zu 4-6: Ok, das ist doch mal ein Lösungsansatz, DANKE! Ich werde damit mal rumspielen. Sobald was funktionierendes dabei rum kommt, poste ich selbstverständlich hier. Ich hab auch schon gleich die erste Frage: Was enthält top, die du mit pushTop() auf dem Stack ablegst (also bevor ...getTimer2() aufgerufen wird?
    ADC ist der nächste Schritt, das ist klar. Sobald ich geradeaus fahren kann, steht natürlich Linienverfolgung auf dem "Grundschul"plan eines Roboterprogrammierers.

    Vielen Dank nochmal für die Hilfe, bis demnächst!
    Geändert von mlade (22.02.2013 um 06:20 Uhr) Grund: Code-Blöcke eingefügt

  6. #6
    Neuer Benutzer Öfters hier
    Registriert seit
    28.10.2012
    Beiträge
    26
    Hallo mlade,

    zu 1)
    a) Die ASURO Methoden Sleep() und Msleep() - so wie sie in HaikuVM implementiert sind - funktionieren nur mit einem Atmega8.
    b) Ich hatte die Hoffnung, dass der "nibobee-programmer" eine EXE Datei ist die auch Commandline Optionen versteht. Dann nämlich kann ich ihn in der nächsten Version als
    Code:
    nibobee.Upload = nibobee-programmer.exe option1 option2 ... $(HAIKU_OUTPUT)
    in 'HaikuVM.properties' einbauen.

    zu 3) Leider ist dein Code unleserlich. Editier doch bitte deine Post noch einmal und schließ ihn in einen CODE-Block ein. Würde mich freuen.

    7) "nächste Frage" pushTop(): Zunächst einmal sollte an diesen automatisch generierten Funktionen 'native_*' wirklich nichts verändert werden, sonst kommt die HaikuVM durcheinander.
    Die JAVA VM ist im Wesentlichen eine Stackmaschine (also auch HaikuVM). Alle Operationen geschehen auf dem Stack. Das ist ein ewiges auf und ab (push und pop). Beispiel 3 + 4:
    Code:
    push(3);
    push(4);
    push(pop() + pop());
    Jetzt steht das Resultat 7 auf dem Stacktop und man hat dazu 5 push&pop gebraucht.

    Besonders heiß geht es am Stacktop zu. Wenn man das weiß kann man push&pop sparen indem man den Stacktop gerade nicht auf dem Stack hält, sondern in einer Variablen (hier top):
    Code:
    push(top); top=3;
    push(top); top=4;
    top=(top + pop());
    Jetzt steht das Resultat 7 in top und man hat nur 3 push&pop gebraucht. (Da ich push(top) oft brauche gibt es die Abkürzung pushTop().)
    Jetzt zu deiner Frage:
    Irgendwas ist immer in top. Da aber getTimer2() keinen Parameter braucht kann der Inhalt von top nicht für getTimer2() bestimmt sein. Deshalb muß ich top sichern ( und zwar auf den Stack mittels pushTop() ) bevor top von 'Java_avr_tutorial_Interrupt1_getTimer2(env, obj)' überschrieben wird.

    8 ) Und ... ich muß dir widersprechen: HaikuVM ist unbedingt auch für die direkte Kommunikation mit der Hardware gedacht. Das was man in C sonst in Interrupt Routinen macht sollte man in HaikuVM mit parallelen Threads lösen. (Ähnlich wie die Propellerchips sehr gut ohne Interrupts aus kommen.)

  7. #7
    So,
    blinken mit Threads funktioniert jetzt.
    Etwas verwirrt hat mich deine Frage nach der Einstellung von TCCR0B. Der nibobee ist standardmäßig mit einem atmega16 ausgestattet, der für den Timer0 nur ein TCCR hat. Ich war mir daher nicht sicher, ober der Timer0 überhaupt der richtige Timer für die Zeitmessung ist, wenn der atmega16 benutzt wird. Aber dein Hinweis auf SimpleOS.c hat da weiter geholfen.
    Ich habe TCCR0 auf 3 gesetzt, also die beiden Clock-Select-Bits aktiviert und so den Prescaler clock/64 gewählt. Das bedeutet allerdings, dass meine Millisekunden in Wirklichkeit ca. 1,12 Millisekunden dauern. Soweit ich sehe, müsste ich für einen korrekten Wert SimpleOS.c anpassen. Genügt es, wenn ich dies in der Kopie in myProject\haikuvM mache, oder muss ich sonst noch etwas beachten?

    Der Nibobee-Programmer nimmt, soweit ich erkennen kann, keine Commandline-Optionen an. Dahingehende Versuche hat er ignoriert.

    Hier folgen noch meine Anpassungen an deiner avr\tutorial\BlinkAsync.java:
    Code:
    ...
    import haiku.vm.NativeCVariable8;
    ...
    @NativeCVariable8
    public static volatile int SREG;
    ...
    // In main():
    SREG |= (1 << 7); // Interrupts ein		
    // Timer-Konfiguration: Prescaler auf 1/64
    TCCR0 |= (1 << CS01);
    TCCR0 |= (1 << CS00);
    TIMSK |= (1 << TOIE0); // Timer-Overflow-Interrupt-Enable Timer0
    ...
    Ich werde als nächstes versuchen, für die beiden externen Interrupts INT0 und INT1 Routinen zu schreiben analog zu deiner Idee für den Timer2.

    Vielen Dank für deine Hilfe, ohne wäre ich nicht weiter gekommen.
    Geändert von mlade (22.02.2013 um 20:46 Uhr) Grund: Code-Blöcke eingefügt

  8. #8
    Neuer Benutzer Öfters hier
    Registriert seit
    28.10.2012
    Beiträge
    26
    Hallo mlade,

    1) Naja, ich kenne nicht jeden Microcontroller so genau und wußte nicht, dass der ATmega16 das Register TCCR0B nicht kennt. Sorry für das Stiften von Verwirrung.
    In 'SimpleOS.c' findest du in der Funktion millis() die Zeile:
    Code:
        return m * 128 / 125;
    Hier solltest du auf ((m * 128 / 125) * 1.12) ändern. (Also, ich habe rein rechnerisch den Faktor 1.066667!) Probiere deshalb doch mal:
    Code:
        return m * 71 / 65;
    oder noch genauer
    Code:
        return m * 225 / 206;
    oder noch genauer
    Code:
        return m * 2048 / 1875;
    In der nächsten Version werde ich das dann via 'HaikuVM.properties' konfigurierbar machen. Aber berichte erst mal ob der Gedanke in der Praxis taugt.

    2) Besser ist für dich wenn du die Änderung in 'haikuVM\SimpleOS.c' machst und dann (nur) 'myCProject\haikuVM\' löschst. Nur dann profitierst du auch bei deinem nächsten NIBOBEE Projekt ( vielleicht in 'myCProject2\' ) von dieser Änderung.

    3) Wie heißt denn der Nibobee-Programmer genau. Dann kann ich ihn wenigstens bei der nächsten Version (eben ganz ohne Commandline-Option) eintragen. In der Hoffnung, dass es für NIBOBEEisten dann noch etwas bequemer wird.

    4) Aah, und wie ich sehe bist du von get-/setMemory(..) zu direct memory access übergegangen. (Ist doch bequemer so, oder?)

    5) (Ist als Info gedacht: ) Ach ja, noch was, allgemein sind die Interrupts bei HaikuVM schon enabled.
    Code:
    ...
    // In main():
    SREG |= (1 << 7); // Interrupts ein       
    ...
    Schadet nicht, ist aber Doppeltgemoppelt. (SREG habe ich jetzt trotzdem in AVRConstants.java aufgenommen. Danke für den versteckten Tipp.)

  9. #9
    Der Programmer heißt NIBObeeProgrammer.exe und wird standardmäßig in "C:\Program Files (x86)\NIBObeeLib" installiert.

    Ich habe ein Problem beim Versuch, c einzubinden. So wie es aussieht, kennt der Compiler JNIEnv nicht. Die Fehlermeldungen lauten:
    Code:
    ../../int0.c:11: error: expected ')' before '*' token
    ../../int0.c: In function 'native_IntTest_getCount0_J':
    ../../int0.c:30: error: 'JNIEnv' undeclared (first use in this function)
    ../../int0.c:30: error: (Each undeclared identifier is reported only once
    ../../int0.c:30: error: for each function it appears in.)
    ../../int0.c:30: error: 'env' undeclared (first use in this function)
    ../../int0.c:31: warning: implicit declaration of function 'Java_IntTest_getCount0'
    int0.c:
    Code:
    #include "haikuJ2C.h"				// Header-Datei statt jni.h?
    #include <avr/interrupt.h>
    
    volatile static jlong jl_intcount0 = 0;
    
    SIGNAL (SIG_INTERRUPT0)				//INT0_vect
    {
          jl_intcount0 ++;
    }
    
    jlong Java_IntTest_getCount0( JNIEnv *env, jobject obj) {
        jlong value;
        uint8_t oldSREG = SREG;
        cli();
        value= jl_intcount0;
        SREG = oldSREG;
        return value;
    }
    
    
    /**
     * Automatic generated (see ./myCProject/haikuC/haikuJNI.c)
     * getTimer2()J
     */
    
     void native_IntTest_getCount0_J(void) {
        pushTop();    // Save variable top onto stack.
        {
            jobject    obj = NULL;
            JNIEnv *env = NULL;
            top.j = Java_IntTest_getCount0(env, obj);
        }
        // Variable top holds the return value. But we have to push the lower half.
        pushTop0();
    }
    Ich vermute mal, dass alles ab Zeile 20 raus muss, aber allein daran liegt es nicht. Ich vermisse auch das Einbinden von jni.h. Irgendwie scheint ein Schritt zu fehlen...

Ähnliche Themen

  1. [ERLEDIGT] [ARDUINO] 2 Motoren + Servo mit dem Arduino Uno steuern
    Von Torrentula im Forum C - Programmierung (GCC u.a.)
    Antworten: 0
    Letzter Beitrag: 31.08.2011, 16:31
  2. ARDUINO ARDUINO l293D + MegaservoLib
    Von m1ch15inner im Forum Microcontroller allgemeine Fragen/Andere Microcontroller
    Antworten: 2
    Letzter Beitrag: 11.07.2011, 11:50
  3. Runtime Error! in AVR Studio
    Von NemesisoD im Forum C - Programmierung (GCC u.a.)
    Antworten: 6
    Letzter Beitrag: 05.01.2007, 19:30
  4. (LEGO MINDSTORMS) lejos Klassen Facharbeit
    Von George Dorn im Forum Allgemeines zum Thema Roboter / Modellbau
    Antworten: 0
    Letzter Beitrag: 01.03.2006, 16:29
  5. lego, lejos, logitech ;)
    Von maze2k im Forum Allgemeines zum Thema Roboter / Modellbau
    Antworten: 7
    Letzter Beitrag: 21.05.2005, 22:21

Stichworte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

fchao-Sinus-Wechselrichter AliExpress