PWM mit Timer erzeugen ?

Hier dürfen auch unregistrierte Besucher posten.
wobo
DOS-Guru
Beiträge: 614
Registriert: So 17. Okt 2010, 14:40

Re: PWM mit Timer erzeugen ?

Beitrag von wobo »

Nightflyer hat geschrieben:Super vielen Dank für das Beispiel, genau sowas habe ich gesucht.

Habe auch gleich einige Versuche damit gemacht. In der neuen ISR habe ich die Berechnung der Frequenz und das setzten des Output Bits am LPT eingefügt, und funktioniert auch einwandfrei. Ausserhalb der ISR kann ich nun eine Frequenz festlegen, und diese wird dann am LPT ausgegeben. Genau so soll es sein ! :-) :-)

Nun habe ich trotzdem noch ein paar Fragen:
Ausserhalb der ISR hab ich einer variable FREQUENZ als SHARED deklariert, damit ich in der ISR darauf zugreifen kann. In der ISR selber wurde jedoch per ASM einen lokalen STACK angelegt. Können irgendwelche Probleme entstehen, mit dem lokalen Stack und der SHARED Variable von Powerbasic ? Bis jetzt funktionierts, frage aber trotzdem...
Halte ich für ausgeschlossen, dass das Probleme gibt, jedenfalls nicht bei einer Handvoll Variablen - ich habe aber nur sehr, sehr wenig Erfahrung mit PowerBasic! Vielleicht kann da einer der Basic-Profis was sagen...
Nightflyer hat geschrieben: Durch die neue Frequenz, läuft natürlich auch die Systemuhr schneller.. ;-) Wie genau muss ich dies zurecht biegen, damit die Uhr trotzdem stimmt ?
Du mußt innerhalb Deiner ISR die alte ISR aufrufen, und zwar so, dass sie wieder mit ca. 18.2 Mal die Sekunde aufgerufen wird.

Wahrscheinlich sicherst Du die alte ISR so:

Code: Alles auswählen

  GetInterruptVector &H08, OldAddr
  SetInterruptVector &H08, CODEPTR32(ClockISR)
Wenn Du jetzt die alte ISR auch aufrufen willst, dann solltest Du das am Besten als Int tun, da die alte ISR ja als Interrupthandler konzipiert ist. Die Systemliteratur sagt, dass z.B. die Int ab $68 bis $6F zur Benutzung in Anwendungsprogrammen frei sind. Du kannst also die alte ISR z.B. noch auf den Int $68 legen und dann als Int aufrufen. Außerdem weisst Du ja die Frequenz, mit der Deine neue ISR aufgerufen wird. Wenn diese z.B. 1000Hz, dann musst Du hier immer 1000/18.2 Aufrufe verstreichen lassen, bis es soweit ist, dass die ursprüngliche ISR wieder aufgerufen werden soll.
z.B. so:

Code: Alles auswählen

DIM OldIntCounterBase AS SHARED DWORD
DIM OldIntCounter AS SHARED DWORD
DIM ISRFrequenz AS SHARED WORD

  GetInterruptVector &H08, OldAddr
  SetInterruptVector &H08, CODEPTR32(ClockISR)
  SetInterruptVector &H68, OldAddr
  
  OldIntCounterBase = 1193180 / ISRFrequenz
  OldIntCounter = OldIntCounterBase

Im Basic-Teil Deiner ISR musst Du jetzt halt dafür sorgen, dass die alte ISR ca 18.2 / Sekunde aufgerufen wird, also in etwa so:

Code: Alles auswählen

** Your Basic code goes here **
  
  IF OldIntCounter = 0 THEN
    OldIntCounter = OldIntCounterBase
    ! int &H68
  END IF
  DECR OldIntCounter

Die Systemuhr wird aber dennoch leicht ungenau gehen, weil Du sie in der Regel nicht exakt mit 18.2 Hz aufrufen kannst. Die hier vorgestellte Vorgehensweise ist nur eine ungefähre Annäherung, die mir aber bislang immer genügt hat.

Aber vielleicht postest Du einfach Deine ISR mal hier im Forum. Dann können sich das auch mal echte Basic-Profis anguggen. Ich kann nämlich gar kein Basic mehr :-)

Edit: Viele Nächtliche Fehler ausgebessert... ..und nochmal Fehler....
Nightflyer

Re: PWM mit Timer erzeugen ?

Beitrag von Nightflyer »

Ok, hab ich mir auch so ähnlich überlegt...

Nur frag ich mich, wie genau die Uhr überhaupt hochgezählt wird ? Geschieht dies Hardwaremässig bei jedem Interrupt automatisch, oder eben per Software in der ISR ? Würde dies per Software geschehen, so müsste mit der neuen ISR die Uhr gar nicht mehr hochgezählt werden, weil in dieser werden nur Register gesichert, einen Stack angelegt, LPT Output gesetzt, usw... Da wird also nirgends etwas in ein Register oder so geschrieben.
Sollte dies nun per Hardware geschehen, muss ich denn irgend wo einen Arbeitsmode umstellen, damit in meiner ISR die Uhr nicht hochgezählt wird ?

Hier mein Code:
Ist eigentlich das gleiche wie in dem Beispiel: https://www.powerbasic.com/support/pbfo ... hp?t=22856

[code]

ClockOn
DIM Frequenz AS Shared word
Frequenz = 1000
'OUT (&H43), &b11110110

sleep

ClockOff

SUB ClockOn()

DIM OldAddr AS SHARED DWORD

! mov Word Ptr CS: SaveDS, DS ;store PowerBASIC Data segment

GetInterruptVector &H1C, OldAddr
SetInterruptVector &H1C, CODEPTR32(ClockISR)

END SUB

SUB ClockOff()

DIM OldAddr AS SHARED DWORD

SetInterruptVector &H1C, OldAddr

END SUB

SUB SetInterruptVector(BYVAL Intr?, BYVAL NewAddr???) LOCAL
! push ds ; save DS
! mov ah, &H25 ; set AH to 25h (function number)
! mov al, Intr? ; set AL to interrupt vector being redirected
! lds DX, NewAddr???
! int &H21 ; call DOS services
! pop ds ; restore DS
END SUB

SUB GetInterruptVector(BYVAL Intr?, VAddr???) LOCAL PUBLIC
! push ds ; save DS
! push si ; save SI
! mov ah, &H35 ; set AH to 35h (function number)
! mov al, Intr? ; set AL to interrupt vector
! int &H21 ; call DOS services (ES:BX now holds address)
! lds si, VAddr??? ; get a pointer to VSeg??
! mov ds:[si+2], es ; copy ES (segment address) into VSeg??
! mov ds:[si], bx ; copy BX (offset address) into VOff??
! pop si ; restore SI
! pop ds ; restore DS
END SUB

SUB ISR () PRIVATE

DIM IsrStack AS STATIC STRING * 1024 '1k stack (probably too much)
DIM Counter AS STATIC INTEGER

DIM zaehler AS STATIC word
DIM L AS STATIC byte
DIM H AS STATIC byte

SaveDS:
! dw 0
SaveSS:
! dw 0
SaveSP:
! dw 0

ClockISR:
! push ax ; save the general registers
! push bx
! push cx
! push dx
! push si
! push di
! push bp
! push ds
! push es
! push bp
! pushf ; save the flags register
! cli ; suspend all maskable interrupts

! mov Word Ptr CS:SaveSS, SS ; save current stack segment
! mov Word Ptr CS:SaveSP, SP ; save current stack pointer
! mov DS, Word Ptr CS:SaveDS ; restore PowerBASIC data segment

' Create a local stack frame
! mov SS, Word Ptr CS:SaveDS ; SS must equal DS for PowerBASIC runtime
! lea BX, IsrStack ; get address of the local stack frame
! add BX, 1024 ; point to the end of the fixed-length string
! mov SP, BX ; set the stack pointer

' ** Your Basic code goes here **

zaehler = 1193180 / Frequenz
L = zaehler
shift right zaehler, 8
H = zaehler
'OUT (&H43), &b00110110
OUT (&H40), L
OUT (&H40), H

l = inp(888)
bit toggle l, 1
OUT (888), l

IF Counter = 0 THEN
LOCATE 1, 72, 0
COLOR 14,0
PRINT TIME$;
Counter = 18 '18 ticks per second
END IF
DECR Counter

' ** End of Basic code

! mov SP, Word Ptr CS:SaveSP ; restore the original stack segment
! mov SS, Word Ptr CS:SaveSS ; and stack pointer before restoring the registers

! popf ; restore the flags register
! pop bp ; restore the general registers
! pop es
! pop ds
! pop bp
! pop di
! pop si
! pop dx
! pop cx
! pop bx
! pop ax
! sti ; re-enable maskable interrupt processing
! iret ; return from our interrupt handler

END SUB

[/code]
wobo
DOS-Guru
Beiträge: 614
Registriert: So 17. Okt 2010, 14:40

Re: PWM mit Timer erzeugen ?

Beitrag von wobo »

Nightflyer hat geschrieben:Ok, hab ich mir auch so ähnlich überlegt...

Nur frag ich mich, wie genau die Uhr überhaupt hochgezählt wird ? Geschieht dies Hardwaremässig bei jedem Interrupt automatisch, oder eben per Software in der ISR ? Würde dies per Software geschehen, so müsste mit der neuen ISR die Uhr gar nicht mehr hochgezählt werden, weil in dieser werden nur Register gesichert, einen Stack angelegt, LPT Output gesetzt, usw... Da wird also nirgends etwas in ein Register oder so geschrieben.
Sollte dies nun per Hardware geschehen, muss ich denn irgend wo einen Arbeitsmode umstellen, damit in meiner ISR die Uhr nicht hochgezählt wird ?
Das hat mich auch schon gewundert. Wenn Du nämlich die alte ISR nicht aufrufst kann auch nichts hochgezählt werden.
Aber im Listing verwendest du Int $1C und nicht Int$08. Dann is' klar, dass die Uhr rennt.
Und wieso setzt Du _innerhalb_ Deiner ISR den Timer neu? Du solltest Du eigentlich nicht, weil das nicht so gesund für den Timer-Chip sein dürfte, wenn er ca. 1000/sec neu gesetzt wird (IMHO).

Und warum hast die Belegung des Auswahlregisters auskommentiert?

So hätte ich es jetzt versucht (ungetestet, da ich kein PowerBasic habe!):

Code: Alles auswählen


DIM Frequenz AS Shared word
DIM OldAddr AS SHARED DWORD
DIM ISRCounterBase AS SHARED word
DIM ISRCounter AS SHARED word

Frequenz = 1000
ClockOn

sleep

ClockOff


SUB ClockOn()

DIM zaehler AS STATIC word
DIM L AS STATIC byte
DIM H AS STATIC byte

! mov Word Ptr CS: SaveDS, DS ;store PowerBASIC Data segment

zaehler = 1193180 / Frequenz

ISRCounterBase = zaehler
ISRCounter = ISRCounterBase

L = zaehler
shift right zaehler, 8
H = zaehler
OUT (&H43), &b00110110
OUT (&H40), L
OUT (&H40), H

GetInterruptVector &H08, OldAddr
SetInterruptVector &H08, CODEPTR32(ClockISR)
SetInterruptVector &H68, OldAddr

END SUB


SUB ClockOff()

OUT (&H43), &b00110110
OUT (&H40), 0
OUT (&H40), 0
SetInterruptVector &H08, OldAddr

END SUB

SUB SetInterruptVector(BYVAL Intr?, BYVAL NewAddr???) LOCAL
! push ds ; save DS
! mov ah, &H25 ; set AH to 25h (function number)
! mov al, Intr? ; set AL to interrupt vector being redirected
! lds DX, NewAddr???
! int &H21 ; call DOS services
! pop ds ; restore DS
END SUB

SUB GetInterruptVector(BYVAL Intr?, VAddr???) LOCAL PUBLIC
! push ds ; save DS
! push si ; save SI
! mov ah, &H35 ; set AH to 35h (function number)
! mov al, Intr? ; set AL to interrupt vector
! int &H21 ; call DOS services (ES:BX now holds address)
! lds si, VAddr??? ; get a pointer to VSeg??
! mov ds:[si+2], es ; copy ES (segment address) into VSeg??
! mov ds:[si], bx ; copy BX (offset address) into VOff??
! pop si ; restore SI
! pop ds ; restore DS
END SUB


SUB ISR () PRIVATE

DIM IsrStack AS STATIC STRING * 1024 '1k stack (probably too much)
DIM Counter AS STATIC INTEGER

SaveDS:
! dw 0
SaveSS:
! dw 0
SaveSP:
! dw 0

ClockISR:
! push ax ; save the general registers
! push bx
! push cx
! push dx
! push si
! push di
! push bp
! push ds
! push es
! push bp
! pushf ; save the flags register
! cli ; suspend all maskable interrupts

! mov Word Ptr CS:SaveSS, SS ; save current stack segment
! mov Word Ptr CS:SaveSP, SP ; save current stack pointer
! mov DS, Word Ptr CS:SaveDS ; restore PowerBASIC data segment

' Create a local stack frame
! mov SS, Word Ptr CS:SaveDS ; SS must equal DS for PowerBASIC runtime
! lea BX, IsrStack ; get address of the local stack frame
! add BX, 1024 ; point to the end of the fixed-length string
! mov SP, BX ; set the stack pointer

' ** Your Basic code goes here **

l = inp(888)
bit toggle l, 1
OUT (888), l

IF Counter = 0 THEN
LOCATE 1, 72, 0
COLOR 14,0
PRINT TIME$;
Counter = 18 '18 ticks per second
END IF
DECR Counter

  IF ISRCounter = 0 THEN
   ISRCounter = ISRCounterBase
    ! int &H68
  ELSE
    OUT (&H20), &H20
  END IF
  DECR ISRCounter


' ** End of Basic code

! mov SP, Word Ptr CS:SaveSP ; restore the original stack segment
! mov SS, Word Ptr CS:SaveSS ; and stack pointer before restoring the registers

! popf ; restore the flags register
! pop bp ; restore the general registers
! pop es
! pop ds
! pop bp
! pop di
! pop si
! pop dx
! pop cx
! pop bx
! pop ax
! sti ; re-enable maskable interrupt processing
! iret ; return from our interrupt handler

END SUB

Nightflyer

Re: PWM mit Timer erzeugen ?

Beitrag von Nightflyer »

Aha alles klar. Gibt es irgendwo eine Tabelle/Beschreibung von den ganzen Interrupts ? Ich hab nähmlich nur so eine Portlist: http://bochs.sourceforge.net/techspec/PORTS.LST

Den Timer muss ich in der ISR neu setzten. Sonst passiert folgendes: Timer an Port H40 mit Wert 1193 laden, der Wert wird nun herunter gezählt 1192, 1191, 1190... 3, 2, 1, 0 -> ISR wird aufgerufen, danach wird der Wert weiter runtergezählt, ist er jedoch bereits bei 0, überläuft der Timer und beginnt wieder bei 65535.... Deshalb muss ich den Timer immer wieder neu setzten.

Durch leichte Anpassung deines Code, funktioniert dieser einwandfrei. Frequenz wird am LPT ausgegeben, und die Uhr stimmt ebenfalls.

Code:

DIM Frequenz AS Shared word
DIM OldAddr AS SHARED DWORD

Frequenz = 2000
ClockOn

sleep

ClockOff


SUB ClockOn()
! mov Word Ptr CS: SaveDS, DS ;store PowerBASIC Data segment
GetInterruptVector &H08, OldAddr
SetInterruptVector &H08, CODEPTR32(ClockISR)
SetInterruptVector &H68, OldAddr
END SUB


SUB ClockOff()
SetInterruptVector &H08, OldAddr
END SUB

SUB SetInterruptVector(BYVAL Intr?, BYVAL NewAddr???) LOCAL
! push ds ; save DS
! mov ah, &H25 ; set AH to 25h (function number)
! mov al, Intr? ; set AL to interrupt vector being redirected
! lds DX, NewAddr???
! int &H21 ; call DOS services
! pop ds ; restore DS
END SUB

SUB GetInterruptVector(BYVAL Intr?, VAddr???) LOCAL PUBLIC
! push ds ; save DS
! push si ; save SI
! mov ah, &H35 ; set AH to 35h (function number)
! mov al, Intr? ; set AL to interrupt vector
! int &H21 ; call DOS services (ES:BX now holds address)
! lds si, VAddr??? ; get a pointer to VSeg??
! mov ds:[si+2], es ; copy ES (segment address) into VSeg??
! mov ds:[si], bx ; copy BX (offset address) into VOff??
! pop si ; restore SI
! pop ds ; restore DS
END SUB


SUB ISR () PRIVATE

DIM IsrStack AS STATIC STRING * 1024 '1k stack (probably too much)
DIM Counter AS STATIC INTEGER

DIM zaehler AS STATIC word
DIM L AS STATIC byte
DIM H AS STATIC byte

DIM ISRCounter AS STATIC word

SaveDS:
! dw 0
SaveSS:
! dw 0
SaveSP:
! dw 0

ClockISR:
! push ax ; save the general registers
! push bx
! push cx
! push dx
! push si
! push di
! push bp
! push ds
! push es
! push bp
! pushf ; save the flags register
! cli ; suspend all maskable interrupts

! mov Word Ptr CS:SaveSS, SS ; save current stack segment
! mov Word Ptr CS:SaveSP, SP ; save current stack pointer
! mov DS, Word Ptr CS:SaveDS ; restore PowerBASIC data segment

' Create a local stack frame
! mov SS, Word Ptr CS:SaveDS ; SS must equal DS for PowerBASIC runtime
! lea BX, IsrStack ; get address of the local stack frame
! add BX, 1024 ; point to the end of the fixed-length string
! mov SP, BX ; set the stack pointer

' ** Your Basic code goes here **

zaehler = 1193180 / Frequenz

L = zaehler
shift right zaehler, 8
H = zaehler
OUT (&H43), &b00110110
OUT (&H40), L
OUT (&H40), H

l = inp(888)
bit toggle l, 1
OUT (888), l

IF Counter = 0 THEN
LOCATE 1, 72, 0
COLOR 14,0
PRINT TIME$;
Counter = 18 '18 ticks per second
END IF
DECR Counter

IF ISRCounter = 0 THEN
! int &H68
ISRCounter = Frequenz / 18.2
ELSE
OUT (&H20), &H20
END IF
DECR ISRCounter


' ** End of Basic code

! mov SP, Word Ptr CS:SaveSP ; restore the original stack segment
! mov SS, Word Ptr CS:SaveSS ; and stack pointer before restoring the registers

! popf ; restore the flags register
! pop bp ; restore the general registers
! pop es
! pop ds
! pop bp
! pop di
! pop si
! pop dx
! pop cx
! pop bx
! pop ax
! sti ; re-enable maskable interrupt processing
! iret ; return from our interrupt handler

END SUB
wobo
DOS-Guru
Beiträge: 614
Registriert: So 17. Okt 2010, 14:40

Re: PWM mit Timer erzeugen ?

Beitrag von wobo »

Nightflyer hat geschrieben:Aha alles klar. Gibt es irgendwo eine Tabelle/Beschreibung von den ganzen Interrupts ? Ich hab nähmlich nur so eine Portlist: http://bochs.sourceforge.net/techspec/PORTS.LST
Wenn es nur um einen schnellen Überblick geht, hier:
http://www.tu-chemnitz.de/informatik/RA ... belle.html

Ansonsten sehr umfangreich und detaillierter: google nach Ralph Brown's Interrupt list
Nightflyer hat geschrieben: Den Timer muss ich in der ISR neu setzten. Sonst passiert folgendes: Timer an Port H40 mit Wert 1193 laden, der Wert wird nun herunter gezählt 1192, 1191, 1190... 3, 2, 1, 0 -> ISR wird aufgerufen, danach wird der Wert weiter runtergezählt, ist er jedoch bereits bei 0, überläuft der Timer und beginnt wieder bei 65535.... Deshalb muss ich den Timer immer wieder neu setzten.
Kann ich nicht nachvollziehen, da bei mir der Zähler, wie es die Systemliteratur auch sagt, immer beim eingestellten Zähler wieder anfängt. Aber, wenn es jetzt bei Dir funktioniert, ist gut.


Nightflyer hat geschrieben: Durch leichte Anpassung deines Code, funktioniert dieser einwandfrei. Frequenz wird am LPT ausgegeben, und die Uhr stimmt ebenfalls.
Danke für die Rückmeldung. Freut mich, dass Du es noch hinbekommen hast. Weil, jetzt kann ich es ja zugeben: ich hatte noch nie was mit PowerBasic gemacht und meine letzte Berührung mit Basic war vor 1990 mit GW-Basic. Ich hatte aber anlässlich dieses Threads nach PowerBasic gegoogelt und war und bin schon mächtig beeindruckt, was man damit machen kann und wie strukturiert man damit programmieren kann. Deswegen meine Meinung: PowerBasic ist das beste Basic :-)

Was ich noch nicht ganz verstanden habe, ist das Variablenanlegen: Wenn Du eine Variable mit DIM anlegst, ist die dann lokal, d.h. nur in der jeweiligen SUB nutzbar, oder im gesamten Programm? Ich dachte bisher immer DIM MyVar AS SHARED ist quasi eine globale Variable und DIM MyVar AS STATIC eine lokale - das scheint aber nicht zu stimmen?

Aber egal, Hauptsache es läuft solide :-)

Edit: globale Variablen kann man mit GLOBAL anlegen..
Hier doch noch ein Versuch, bei dem das Setzen des Timers aus der ISR herausgenommen wird. (Aber Hauptsache es läuft bei Dir!)

Code: Alles auswählen


DIM Frequenz AS Shared word
DIM OldAddr AS SHARED DWORD

GLOBAL ISRCounter AS WORD

Frequenz = 2000
ClockOn

sleep

ClockOff


SUB ClockOn()

DIM zaehler AS STATIC word
DIM L AS STATIC byte
DIM H AS STATIC byte

  ! mov Word Ptr CS: SaveDS, DS ;store PowerBASIC Data segment
  GetInterruptVector &H08, OldAddr
  SetInterruptVector &H08, CODEPTR32(ClockISR)
  SetInterruptVector &H68, OldAddr

  zaehler = 1193180 / Frequenz
  L = zaehler
  shift right zaehler, 8  
  H = zaehler

  OUT (&H43), &b00110110
  OUT (&H40), L
  OUT (&H40), H
  ISRCounter = Frequenz / 18.2

END SUB


SUB ClockOff()
  SetInterruptVector &H08, OldAddr
  OUT (&H43), &b00110110
  OUT (&H40), 0
  OUT (&H40), 0
END SUB

SUB SetInterruptVector(BYVAL Intr?, BYVAL NewAddr???) LOCAL
  ! push ds ; save DS
  ! mov ah, &H25 ; set AH to 25h (function number)
  ! mov al, Intr? ; set AL to interrupt vector being redirected
  ! lds DX, NewAddr???
  ! int &H21 ; call DOS services
  ! pop ds ; restore DS
END SUB

SUB GetInterruptVector(BYVAL Intr?, VAddr???) LOCAL PUBLIC
  ! push ds ; save DS
  ! push si ; save SI
  ! mov ah, &H35 ; set AH to 35h (function number)
  ! mov al, Intr? ; set AL to interrupt vector
  ! int &H21 ; call DOS services (ES:BX now holds address)
  ! lds si, VAddr??? ; get a pointer to VSeg??
  ! mov ds:[si+2], es ; copy ES (segment address) into VSeg??
  ! mov ds:[si], bx ; copy BX (offset address) into VOff??
  ! pop si ; restore SI
  ! pop ds ; restore DS
END SUB


SUB ISR () PRIVATE

DIM IsrStack AS STATIC STRING * 1024 '1k stack (probably too much)
DIM Counter AS STATIC INTEGER

DIM l AS STATIC word


SaveDS:
! dw 0
SaveSS:
! dw 0
SaveSP:
! dw 0

ClockISR:
! push ax ; save the general registers
! push bx
! push cx
! push dx
! push si
! push di
! push bp
! push ds
! push es
! push bp
! pushf ; save the flags register
! cli ; suspend all maskable interrupts

! mov Word Ptr CS:SaveSS, SS ; save current stack segment
! mov Word Ptr CS:SaveSP, SP ; save current stack pointer
! mov DS, Word Ptr CS:SaveDS ; restore PowerBASIC data segment

' Create a local stack frame
! mov SS, Word Ptr CS:SaveDS ; SS must equal DS for PowerBASIC runtime
! lea BX, IsrStack ; get address of the local stack frame
! add BX, 1024 ; point to the end of the fixed-length string
! mov SP, BX ; set the stack pointer

' ** Your Basic code goes here **
l = inp(888)
bit toggle l, 1
OUT (888), l

IF Counter = 0 THEN
LOCATE 1, 72, 0
COLOR 14,0
PRINT TIME$;
Counter = 18 '18 ticks per second
END IF
DECR Counter

DECR ISRCounter
IF ISRCounter = 0 THEN
  ! sti
  ! int &H68
  ISRCounter = Frequenz / 18.2
ELSE
  OUT (&H20), &H20
END IF


' ** End of Basic code

! mov SP, Word Ptr CS:SaveSP ; restore the original stack segment
! mov SS, Word Ptr CS:SaveSS ; and stack pointer before restoring the registers

! popf ; restore the flags register
! pop bp ; restore the general registers
! pop es
! pop ds
! pop bp
! pop di
! pop si
! pop dx
! pop cx
! pop bx
! pop ax
! sti ; re-enable maskable interrupt processing
! iret ; return from our interrupt handler

END SUB
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: PWM mit Timer erzeugen ?

Beitrag von freecrac »

Es ist auf jeden Fall schon ungewöhnlich den Timer innerhalb der ISR zu verändern.
Sonst bin ich schon beeindruckt davon wie man mit PowerBASIC und Assembler zusammen arbeiten kann.

...

Bei diesen beiden Befehlen können wir das Segment override Prefix herausnehmen, weil defaultmäßig schon DS verwendet wird.
! mov ds:[si+2], es ; copy ES (segment address) into VSeg??
! mov ds:[si], bx ; copy BX (offset address) into VOff??

So ist es je ein Byte weniger
! mov [si+2], es ; copy ES (segment address) into VSeg??
! mov [si], bx ; copy BX (offset address) into VOff??

Nur wenn wir z.B. BP als Adressregister verwenden würden müssten wir DS: angeben.

Defaultmäßige Zuordnung
Adressregister Segmentregister
BX, DI, SI = DS
BP, SP = SS

Dirk
Nightflyer

Re: PWM mit Timer erzeugen ?

Beitrag von Nightflyer »

Hallo Zusammen

Ich greife das Thema nochmals auf.

Der Code läuft so wie oben beschrieben einwandfrei. Nun wollte ich den Code in meiner Anwendung integrieren, und jetzt fangen die Probleme an. Ab und zu stürzt die Software ab, und es erscheint DOS ERROR 5 (Zugriff verweigert). Der Fehler tritt nicht in der ISR auf, sondern immer an einer unterschiedlichen Stelle im Hauptprogramm. Mir ist aufgefallen, dass einige Variablen im Hauptprogramm durcheinander gebracht werden, und dadurch entsteht natürlich der Fehler. Ich muss jedoch noch anfügen, dass ich nicht jede Variable mit DIM definiert habe.

Könnte dies das Problem sein, oder ist ein STACK zu klein ? Was hat es mit dem ISR STACK auf sich ?
Antworten