Arduino assembly instructies in vector table

Ik ben bezig met een project om een Sega Mega Drive controller te simuleren met een AVR/arduino. Hiervoor gebruik ik een 'external intterupt' maar dit geeft nog te veel vertraging.

Nu heb ik op deze site een paar goed tips gelezen maar de beste truc die lukt me nog niet. Het komt erop neer dat hij code plaatst in de plek waar normaal de vector tabel staat om 3 clock-pulsen te besparen, wat toch weer 187ns minder is.

Het verschil is dat hij een "kale" avr gebruikt en ik de arduino IDE omdat het makkelijker is om de code in de chip te krijgen. Ik hoopte dat iemand misschien een tip had om dit toch via de arduino IDE voor elkaar te krijgen.

Alvast bedankt.

Als je net bezig bent met je project moet je je echt geen zorgen gaan
maken om 3 clock cycles bij een interrupt.

Wat onder andere veel meer uitmaakt is als je het kristal op 20MHz zet. Die 3 clocks heb je na 16 clocks al terugverdiend.

Maar het belangrijkste is dat je de boel zo inricht dat het enigszins efficient kan werken. Je bent echt extreem bezig als het op die drie clocks aankomt.

Arduino is bedoeld om het je makkelijk te maken. Dingen als "vector table" wordt voor je geregeld dat daar mooie standaard dingen in staan. Geen fratsen als direct daar code plempen. Daar is het JUIST niet voor.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Arduino is meer dan 1 ding.

het is een print ontwerp (waar jij mischien geen gebruik van maakt)
het is een ontwikkelomgeving, maar daar zijn er meer van
het is een vaste bootloader, die een STK500 emuleert (wel handig)
het zijn een aantal macro's die het programmeren sneller maken.

die macro's zijn niet optimaal, het schrijven van een paar pinnen is trager als de hele port in een keer schrijven. toch werkt het wel erg snel als je iets wilt opzetten.

kun je voorbeelden geven die te traag zijn?

je kan veel dingen ook googlen, bijvoorbeeld voor de millis() functie wordt standaard een timer interupt gebruikt, hier zijn problemen bij bekend.

GMT+1

Ik ben al een tijdje bezig met dit project, om al mijn retro consoles te voorzien van een draadloze controller. Heb de SNES controller al helemaal draadloos maar moet nog aan de SNES ontvanger beginnen, heb nu alleen een USB ontvanger die het prima doet.

Natuurlijk is de Arduino bedoeld om te leren omgaan met microcontrollers en elektronica eromheen en wordt er zeer veel voor je geregeld zodat het 'gewoon werkt'. Maar ik begin me toch aan veel te storen en loop nu tegen de grenzen aan.
Ik ben nu ongeveer een week of twee bezig met de ontvanger aan de mega drive zelf, en het hele probleem zit hem in het feit dat de chip in de orginele controller binnen 5ns reageerd. En mijn arduino simulatie doet er bijna 650ns over. En sommige spellen die uit gaan van de echte chip lezen direct de controller uit, maar dan ben ik dus net te laat. En dus moet het inderdaad "extreem" door die drie clocks te besparen.

@Progger: Je hebt gelijk dat Arduino meer is dan 1 ding. In dit geval gaat het om de ontwikkelomgeving, maar ik gebruik alles van het lijstje op dit moment. Een Arduino Nano kloon de Arduino IDE de bootloader maar de van de standaard library gebruik ik zo min mogelijk, omdat die inderdaad niet zo snel zijn.

De code is best groot maar met wat knip en plak werk komt het hier op neer:

c code:


register byte next_state  asm("r3");
register byte state_0     asm("r4");
register byte state_1     asm("r5");

ISR(INT0_vect, ISR_NAKED)
{
  //PORTC = next_state;
  asm( "out %0, r3\n" : : "I" _SFR_IO_ADDR(PORTC) );

  if(PIND & 0x04)
  {
    next_state = state_1;
  } else {
    next_state = state_0;
  }

  reti();
}

void setup()
{
  DDRC  = 0b11111111;
  PORTC = 0b11111111;

  //disable the timer0 intterupt
  TIMSK0 &= ~_BV(TOIE0); // disable timer0 overflow interrupt

  //enable pin intterupt
  EICRA |= (1 << ISC00);
  EIMSK |= (1 << INT0);

  sei();
}

void loop()
{

  while(1)
  {
    if(radio.avalable())
    {
      //set state_0
      //set state_1
    }
  }
}

En het stukje assembly wat ik wil invoegen:

avr asm code:


.ORG 0x04
    out _SFR_IO_ADDR(PORTC), r3
    rjmp __vector_1

Ik heb bewust delen weg gelaten om het kort te houden. Maar wat ik dus wil bereiken is dat het korte stukje assembly over de vector table geschreven wordt en de regel met inline assembly in de ISR vervalt. Maar tot nu toe wordt de assembly of helemaal niet toegevoegd of heeeeleeemaal achteraan. Dit kan ik zien met het avr-objdump commando.

bprosman

Golden Member

Waarom dan de Arduino omgeving niet loslaten en gewoon assembly programmeren op een losse ATMega328 of zo, en het Arduino bordje als luxe STK500 / programmer gebruiken.

De jongere generatie loopt veel te vaak zijn PIC achterna.
Arco

Special Member

Als het een kwestie van nS is, dan kun je beter een andere oplossing zoeken, zoals een veel snellere controller of progammeerbare logica...
Interrupts kun je in ieder geval beter achterwege laten, het iedere keer interrupt in/uit geeft heel veel vertraging (beter pollen)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com

Op 4 april 2016 20:01:39 schreef bprosman:
Waarom dan de Arduino omgeving niet loslaten en gewoon assembly programmeren op een losse ATMega328 of zo, en het Arduino bordje als luxe STK500 / programmer gebruiken.

Ik ben er wel over aan het denken om in dit geval de Arduino omgeving te verlaten, maar naar 100% assembly zal ik niet gaan denk ik. Ik heb dat eens gebrood met een PIC maar ook daar ben ik toen toch naar C gegaan. Ik gebruik arduino omdat het makkelijk is en de kloon boorden zeer goedkoop te krijgen zijn. Maar het is wel een idee om alleen de bootloader te blijven gebruiken.

Op 4 april 2016 20:16:35 schreef Arco:
Als het een kwestie van nS is, dan kun je beter een andere oplossing zoeken, zoals een veel snellere controller of progammeerbare logica...
Interrupts kun je in ieder geval beter achterwege laten, het iedere keer interrupt in/uit geeft heel veel vertraging (beter pollen)

Ik heb nog ongebruikte Guzunties liggen, dus ik heb al een CPLD in huis. Ik heb er alleen nooit iets mee gedaan en heb totaal geen ervaring met CPLD. Ik heb we l al wat onderzoek gedaan en denk dat ik een poging ga doen Verilog te gebruiken in Linux. Heb wel windows als het echt moet maar liever niet.

Pollen heb ik geprobeerd en werkte min of meer wel maar niet goed genoeg. Misschien de moeite om daar nog eens naar te kijken inderdaad. Toen had ik nog wel timer0 aanstaan.

Heeft de compiler niet de mogelijkheid een stukje assembly in het programma bij te plaatsen?
Bijvoorbeeld bij Microchip kun je in je C-programma tussen de directives "asm" en "endasm" een stukje asm invoegen.

Oh mijn god, weer dat geknoei met inline assembly. Daar heb ik toch zo'n hekel aan die totaal ondoorzichtige syntax van gcc hoe dat gedaan is.

Gewoon een asm file maken en daar je functie in maken (extensie .S).
Die link je aan de rest van je C-code en klaar is kees.
De code is dan goed leesbaar. Even mee rekening houden dat je de juiste registers saved en restored, afhankelijk wat je gebruikt, alles perfect in eigen hand.

Een voorbeeld skelet voor de functie;

code:


        .section .text

        .global TIMER1_OVF1_vect
TIMER1_OVF1_vect:
; Save working registers, part 1
        push    r0
        in      r0, __SREG__    ; Save status register

        push    r# >>> alle registers die je nog meer nodig hebt saven

>>> hier komt je code


        pop    r# <<< alles wat je extra gesaved hebt weer restoren in omgekeerde volgorde

; Restore working registers, part 1
        out     __SREG__, r0
        pop     r0
        reti

Uiteraard de juiste vector definitie gebruiken. Bovenstaande werkt netjes in avr studio 4.

1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.

Op 4 april 2016 22:29:25 schreef henri62:
Oh mijn god, weer dat geknoei met inline assembly. Daar heb ik toch zo'n hekel aan die totaal ondoorzichtige syntax van gcc hoe dat gedaan is.

Gewoon een asm file maken en daar je functie in maken (extensie .S).
Die link je aan de rest van je C-code en klaar is kees.
De code is dan goed leesbaar. Even mee rekening houden dat je de juiste registers saved en restored, afhankelijk wat je gebruikt, alles perfect in eigen hand.

Ik ben het met je eens dat het er niet mooi en erg onduidelijk uitziet. Ik had het stukje assembly ook al in een .s bestand staan maar die werd niet mee gecompileerd.Toen zag ik in jouw reactie .S staan, en ja hoor toen werd ie wel meegenomen.

Helaas wordt het of overschreven of weg(bezuinigd) want ik zie mijn assembly niet terug in de bytecode.

Dit is de dissasembly van mijn interrupt functie:

code:


ISR(INT0_vect, ISR_NAKED)
{
  //PORTC = next_state;
  asm( "out %0, r3\n" : : "I" _SFR_IO_ADDR(PORTC) );
 1be:	38 b8       	out	0x08, r3	; 8

  if(PIND & 0x04)
 1c0:	4a 9b       	sbis	0x09, 2	; 9
 1c2:	02 c0       	rjmp	.+4      	; 0x1c8 <__vector_1+0xa>
  {
    next_state = state_1;
 1c4:	35 2c       	mov	r3, r5
 1c6:	01 c0       	rjmp	.+2      	; 0x1ca <__vector_1+0xc>
  } else {
    next_state = state_0;
 1c8:	34 2c       	mov	r3, r4
  }

  reti();
 1ca:	18 95       	reti

000001cc <loop>:
}

En van de vector table:

code:


Disassembly of section .text:

00000000 <__vectors>:
.section .text
;.ORG 0x4000
    ;//out   _SFR_IO_ADDR(PORTC), r3
    rjmp  __vector_1
   0:	0c 94 67 00 	jmp	0xce	; 0xce <__ctors_end>
    nop
    nop
   4:	0c 94 df 00 	jmp	0x1be	; 0x1be <__vector_1>
    nop
    nop
   8:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
   c:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  10:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  14:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  18:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  1c:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  20:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  24:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  28:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  2c:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  30:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  34:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  38:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  3c:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  40:	0c 94 95 04 	jmp	0x92a	; 0x92a <__vector_16>
  44:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  48:	0c 94 1a 06 	jmp	0xc34	; 0xc34 <__vector_18>
  4c:	0c 94 4c 06 	jmp	0xc98	; 0xc98 <__vector_19>
  50:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  54:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  58:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  5c:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  60:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>
  64:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>

Het je de juiste naam van de ISR gebruikt?
Dat is (wat ik weet) binnen AVR studio niet consistent benoemd wat betreft CPU typen.

Het beste is in de header files kijken hoe ze exact heten.
Anders zou het wel kunnen dat ze weg optimized worden omdat er geen referentie naar is.

P.S. Ik weet dat AVR studio zelf een (R)JMP PC+.... in de vector table zet naar het entrypoint van je zelf gedefinieerde ISR toe.
Als je zelf geen ISR maakt (met precies de juiste naam) gaat volgens mij via een "weak" binding het entrypoint naar een dummy locatie.

Heeft me ook eens een uur gekost voordat ik erachter was dat de timer overflow vector tussen twee verschillende devices net iets anders qua naam was.

1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.

Datgene wat je in asm (".... "); wordt gewoon letterlijk aan de assembler doorgegeven. Dus als jij daar...

Op 4 april 2016 19:57:54 schreef Archer:
En het stukje assembly wat ik wil invoegen:

avr asm code:


.ORG 0x04
    out _SFR_IO_ADDR(PORTC), r3
    rjmp __vector_1

...in zet, dan gaat dat gewoon naar de assembler. Hoe je na de .org 0x04 weer terugfloept naar de normale positie in je output weet ik niet.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Op 5 april 2016 22:31:05 schreef rew:
Datgene wat je in asm (".... "); wordt gewoon letterlijk aan de assembler doorgegeven. Dus als jij daar...

Dat is niet helemaal waar, de notatie %0 %1 etc. wordt gebruikt als placeholder voor tijdelijke registers. Ik moet elke keer in het Gcc manual gaan zoeken hoe dat ook alweer in elkaar zit.

Ook het save/restoren van registers met inline code kan op sommige processoren nog wel wat verassingen opleveren (of extra code opleveren die je niet verwacht).

Terug ga je met een 'reti' instructie.

@Archer: Bij het stukje code wat door rew gequote is als voorbeeld is natuurlijk r3 compleet undefined dus dat is niet af natuurlijk voor het geval iemand dat nog niet begrepen had.

(het stuk onder: Dit is de dissasembly van mijn interrupt functie:)
Die code zal ook onherroepelijk crashen ook omdat het status register bijvoorbeeld niet gesaved wordt.

1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.

Op 5 april 2016 23:44:26 schreef henri62:
[...] Dat is niet helemaal waar, de notatie %0 %1 etc. wordt gebruikt als placeholder voor tijdelijke registers. Ik moet elke keer in het Gcc manual gaan zoeken hoe dat ook alweer in elkaar zit.

Ook het save/restoren van registers met inline code kan op sommige processoren nog wel wat verassingen opleveren (of extra code opleveren die je niet verwacht).

Ja, je hebt gelijk. Maar als je geen %1 dingen gebruikt gaat het gewoon letterlijk naar de assembler.

Terug ga je met een 'reti' instructie.

Nee, zo bedoel ik het niet. De assembler is vrolijk jou "main.c" aan het assembleren, terwijl jij eeneens "org 4" roept. Dan moet de uitvoor ineens naar absolute locatie 4, en na de OUT en de jump wil je dat de assembler weer gewoon output maakt voor wat "normaal" in main thuishoort.

@Archer: Bij het stukje code wat door rew gequote is als voorbeeld is natuurlijk r3 compleet undefined dus dat is niet af natuurlijk voor het geval iemand dat nog niet begrepen had.

Volgens mij is het de bedoeling om bepaalde variabelen ALTIJD in registers te houden.

Ik betwijfel of je dat voldoende duidelijk hebt gemaakt naar de compiler.

Een hint dat dit niet het geval is, heb je uit het feit dat er ergens een library staat die vorig jaar gecompileerd is en vrolijk R3 kan gaan gebruiken. Die code kan niet weten dat r3 nu speciaal voor de interrupt gereserveerd is.

Normaliter schrijf je code gewoon in C. Als je dan zo nu en dan wat assembly nodig hebt, gebruik je zo'n "asm" statement.

Als je zo ver wilt gaan als hier, dan ben je eigenlijk in assembly aan het schrijven, en voor het gemak schrijf je kleine stukken toch maar in C. Als een hogere-taal-tool dan in de weg gaat zitten doe je hem weg.

Het zou mij inderdaad niet verbazen als het niet werkt niet omdat de timing een paar ns fout is maar omdat de boel nog niet goed in mekaar zit. Dus dat de register waardes/reserveringen niet goed zijn.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Misschien heb ik mijn vraag niet duidelijk genoeg uitgelegd. Het stuk C code uit mijn eerdere post functioneert prima (zie hier mijn thread op sega-16). Zeker met de uitgeschakelde timer0 die allerlei zaken voor de arduino omgeving regelt, die ik in dit project niet eens nodig heb, werkt de simulatie goed genoeg om de meeste spellen die ik heb draadloos te spelen. Nou, draadloos gaat het worden. Zender en ontvanger zitten beide nog op breadboards. :D

@henri62: De variable 'next_state' uit het C programma heb ik als 'suggestie' aan de compiler gevraagd die in r3 te bewaren. Zover ik heb begrepen is dat de manier en zoals is te zien in de disassembly van mijn ISR functie heeft de compiler dat ook netjes gedaan. Maar wordt dit weer met de vector table van arduino overschreven.

Zoals ik al aangaf is deze truuk eerder uitgehaald door Raphael Assenat van raphnet in zijn snes2md project. Hij heeft een heel artikel geschreven over het optimaliseren van een AVR intterupt voor het emuleren van een genesis/mega drive controller. Een paar van zijn tips heb ik al toegepast en ben daardoor van 1,5us naar 625ns gekomen. Hierdoor waren eerdere 'glitches' in games opgelost en werden de games speelbaar. Er is nog maar 1 spel dat echt een merkbaar issue heeft en dat is Lion King. Hierin kun je een aanloop nemen en springen waardoor simba dus verder kan springen. Dit is wat nog niet goed werkt met de huidige simulatie.

Met de hulp van henri62, nog bedankt hiervoor, zag ik dat de assembly file een .S extensie moest hebben en ik had er .s van gemaakt. Ik heb linux dus ja die kleine s deed het niet. Toen ik dat had aangepast werkte het compileren we en zag ik ook dat de file in de linker werd meegenomen. In de disassembly is ook te zien dat mijn assembly code als source wordt weergegeven. Ik denk alleen dat mijn code op 0x04 wordt geplaatst en daarna door de arduino interrupt vector verzameling, of hoe dat ook heten mag, wordt overschreven. Ik zoek denk ik naar een mogelijkheid om mijn assembly file een soort van prio te geven zodat het niet overschreven kan worden door de arduino omgeving.

Maar ik denk dat ik inderdaad moet gaan kijken of ik dit buiten de IDE wel voor elkaar krijg. Ik denk dat ik eens naar de externe Makefile utilities ga kijken die buiten de arduino IDE de source kunnen compileren en in de chip kunnen programmeren. Ik ben de IDE sowieso al een beetje zat omdat ie zo kaal is en geen variabelen lijst kan weergeven enzo wat een beetje goede editor tegenwoordig standaard wel heeft.

Een andere optie die ik nog had bedacht is de .hex file handmatig aanpassen en daar mijn assembly code in stoppen, maar het berekeken van die RJMP offset wordt een ramp denk ik. Ik heb ook nog gedacht om achter de OUT, die het tijd kritische deel van de hele functie is, een NOP te zetten en dan mijn ISR als INT1_vect in te stellen. Ik wil dit meer doen als test om te zien of de code sowieso gaat werken. En of het sneller is en het probleem wat ik heb met de Lion King oplost. Ben wel benieuwd of dit gaat werken.

Dan krijg je dus deze vector table:

code:


00000000 <__vectors>:
   0:	0c 94 67 00 	jmp	0xce	; 0xce <__ctors_end>
   4:	xx xx xx xx 	out     PORTC, r3 ; Ik weet de byte codes nu
                        nop               ; even niet, maar het gaat
                                          ; om het idee.
   8:	0c 94 8f 00 	jmp	0x1be	; 0x1be <__vector_2>
   c:	0c 94 8f 00 	jmp	0x11e	; 0x11e <__bad_interrupt>

Is een extra jump echt een probleem? Kost 3 bytes fetchen + een paar cycles. Ik kan het me niet voorstellen.

Op 6 april 2016 08:39:48 schreef rew:
Normaliter schrijf je code gewoon in C. Als je dan zo nu en dan wat assembly nodig hebt, gebruik je zo'n "asm" statement.

Ben ik het niet (geheel) mee eens (behalve natuurlijk dat je normaliter in C-schrijft). Een in-line asm is bijvoorbeeld bruikbaar als je heel kort even een interrupt wilt disablen of als je bijvoorbeeld speciale instructies nodig hebt (wdt reset bijvoorbeeld).
MAAR NU KOMT HET: Die dingen zitten over het algemeen in de AVR libraries meestal als macro geimplementeerd en zie je als gebruiker dus eigenlijk niet in je code staan (het lijken gewoon C-functies).

Dus is er eigenlijk geen enkele reden om een "paar" asm instructies inline te zetten in je eigen code.

Wel een zeer goede reden is om een hele interrupt functie als assembly te maken. En dan ga je juist NIET zitten klooien met inline assembly wat dat is een zooitje, waarom? Hierom:
Het allergrootste bezwaar met in-linen van assembly is dat je geen idee hebt wat de compiler zelf precies gebruikt heeft, welke temporary registers er precies op het moment in-use zijn. Ook wat bevat het status register, misschien wilde de compiler wel iets later een jump doen ahv de Z-flag, met "jouw" inlining kan dat om zeep geholpen zijn etc. etc. Dus wil je op safe spelen moet je alles saven, code uitvoeren, restoren. Dan is meteen het nut van de in-lining te ziele.

@Archer: Verder die hint van r3 naar de compiler om die voor een specifieke variable te gebruiken: Vergeet dit echt maar, dat werkt alleen in de context van een functie niet daarbuiten.
In jouw ISR is r3 die kompleet random.

In een interrupt service routine MOET je alles save en restoren wat je gebruikt. Hier wordt GEEN status register gesaved, dus per crashed je main code als er een interrupt langs komt op een ongelukkige plaats. Als je echt maar een enkele instructies gebruikt waar geen enkele status flag (Zero/overflow en dat spul dus) "affected" is (zie datasheet van de instructies) dat kun je de save/restore weglaten, maar dat is erg zeldzaam.
(De voorbeeldcode die ik in een paar posts geleden gaf is een correcte manier hoe je dat doet).

Verder nog wat: Alle variablen die je in de ISR gebruikt en ook in je C-code, declareer je in je C-code als volatile zodat de compiler weet dat die de variable altijd gelezen moet worden en dat er geen optimalisatie mag zijn.

1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.

Henri, als je niet voldoende gelezen hebt is het misschien handig om niet te reageren.

Ik begon op dezelfde manier van: Weet je zeker dat je dat wel nodig hebt en de TS heeft het ondertussen duidelijk gemaakt. Of die drie clocks uit gaan maken, betwijfel ik nog steeds, maar goed, het prepareren van de "output" en die ONMIDDELIJK in de interrupt uitvoeren is een bekende truuk. Gebruik ik ook om servo signalen te maken. Prima repeteerbaarheid: ongeveer 1 clock jitter, omdat sommige instructies in main 2 clocks duren en niet interrumpeerbaar zijn.

@TS: Zoals ik al zei: arduino is bedoeld om eea voor jou makkelijk te maken. Dingen als "stmcube" is bedoeld om het onderste uit de kan te kunenn krijgen wbt de processors waar het voor gemaakt is. Dus daar kan je alles overrulen om zoals hier die laatste paar clocks uit je interrupt routine te winnen.

Om "even" te testen is zeker het patchen van de hexfile een optie. Met avr-objdump kan je het objectfile dumpen en de binary instructies te weten komen. Na het patchen weer met objdump kijken of het een beetje gelukt is....

Hexfiles hebben een simpele checksum. Dus de laatste byte op iedere regel is een check -- letterlijk -- sum. Als je 1 bij een byte optelt, moet de checksum 1 omlaag. (dacht ik, anders omhoog... je merkt het snel genoeg).

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Op 7 april 2016 09:52:57 schreef rew:
Henri, als je niet voldoende gelezen hebt is het misschien handig om niet te reageren.

Ik heb het wel degelijk gelezen. Maar ik heb de twijfels of wat ik geschreven heb ook gelezen is.

Afijn het probleem van een stukje assembly toevoegen is dat het gewoon niet gaat om zomaar een register te reserveren voor bijvoorbeeld 'r3', dat is niet fatsoenlijk te doen met de compiler want je moet echt ALLES recompilen ook je libraries etc. Misschien dat je dan mazzel hebt dat 'r3' inderdaad NERGENS in je C-code gebruikt wordt. Of ALLES zelf in assembly schrijven, als de TS dat kan zou die zeker hier deze vraag niet gesteld hebben dus valt dat denk ik gewoon af.

Verder is er nog steeds het probleem van het corrumperen van het status register waar ik niemand over gehoord heb.

Het volgende issue is dat je de vector(en) (als je geen jump wilt hebben) achter de gebruikte vector niet meer kunt gebruiken.
(Kan dus inderdaad door met een "org" de code keihard op die plaats te leggen)

Dus wordt dat het datasheet doorpluizen en kijken wat daar zit.
In de arduino code en/of C-code kun je dus niets meer van de libraries gebruiken die dat nodig heeft. Maar zoals je zelf aangeeft betwijfel ik of die ene jump dat echt uitmaakt.
(er wordt ergens gesproken over een 5 nS delay/read oid? nou vergeet het maar dan kan het al helemaal niet werken natuurijk)

Ja ook ik heb een AVR gebruikt om 8 servo's parallel te sturen, met een resolutie van 250 nS (4096 stapjes over 1-2 mS), dat kan ik halen zonder me te "vergrijpen" aan een reservering van een register of zoiets en ik knoei ook niet direct in de vector/jump table. En de jitter is precies wat je opgeeft: maximaal de tijd van een ondeelbare instructie in je code.
Dit alles met de main code gewoon in C-geschreven.

Je moet dus ook NERGENS een interrupt disablen in de main code, dat is meestal waar je latency je de nek breekt en de rootcause van de problemen.
Ook al gebruik je zelf geen cli()/sti() dan kan het ook in een van de libs zitten, dan ben je ook de klos!

1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.