Gömülü sistemlerde en
kullanışlı uygulama ortamlarından biri de Gerçek Zamanlı İşletim Sistemleridir.
Real Time Operating System – Kısaca RTOS). Uygun bir yaklaşımla
kullanıldığında uygulamayı daha yalın hale getirir ve bir çok görevin de
uygulama içinde daha iyi yönetilmesini ve olası hataların daha az yapılması
sağlar.
PIC mikro denetleyiciler
için bu PIC18 ailesi çıkana kadar böyle bir seçenek yoktu. PIC18 ile birlikte
bootloader yanında RTOS uygulamaları için gerekli altyapı sağlanmaktadır.
RTOS, bir çok program
görevlerini (threads) yürüten, bunlar arasındaki önceliklendirmeyi ve
ilişkileri yöneten bir uygulamadır.
Bizim projemizde ledlerin
farklı iki görevli program tarafından sıra ile kendi belirledikleri şekilde
yakılmasını görüyoruz.
RTOS Gerçekleştirilmiş Hali
Basit RTOS Devre Şeması
RTOS Assembly Programı
TaskStart macro Address, Priority, Size
bcf INTCON, GIE ; Disable
Interrupts During RTOS Request Operation
movlw 0x00F
iorwf 0x060, f, 0 ; Mark in RTOS there is a Command
movlw Size ; Save the Number of File Registers
movwf FSR1L, 0
movlw Priority << 4 ; Save the
Application's Priority
movwf FSR0L, 0
push ; Make Sure Call Address Not Taken
movlw Address & 0x0FF ; Save its Starting Address
movwf TOSL, 0
movlw (Address & 0x0FF00) >> 8
movwf TOSH, 0
movlw (Address & 0x0FF0000) >> 16
movwf TOSU, 0
movlw 0
call _RTOS
pop ; Pop the Address Passed
endm
;
; Next Task Skip Execution to the Next Task None
TaskNext macro
bcf INTCON, GIE ; Disable
Interrupts During RTOS Request Operation
call _RTOS ; Just Call the RTOS
endm
;
; Wait for Interrupt Wait for the Specified None
;
Interrupt Request. When
;
Received, Interrupt "F" and
"E" Bits are Reset
IntWait macro Interrupt
bcf INTCON, GIE ; Disable
Interrupts During RTOS Request Operation
movf 0x060, w, 0 ; Read in the Flag Register
andlw 0x030 ; Clear Everything But Priority
iorlw Interrupt ; Note the Interrupt Number
movwf 0x060, 0
call _RTOS
endm
;
; Send Message Task Number None
; 2
Byte Message in FSR0L/FSR1L
MsgSend macro TaskNumber ; Assume FSR0L/FSR1L already Set up
bcf INTCON, GIE ; Disable
Interrupts During RTOS Request Operation
movf 0x060, w, 0 ; Read in the Flag Register
andlw 0x030
iorlw 0x040
iorwf TaskNumber, w, 0 ; Note, Task Number is a
Variable
movwf 0x060, 0
call _RTOS
endm
;
; Wait Message None First 2 Byte Message
;
in FSR0L/FSR1L
MsgWait macro
bcf INTCON, GIE ; Disable
Interrupts During RTOS Request Operation
bcf 0x060, 6, 0 ; Mark Waiting
for Message
call _RTOS
endm
;
; Read Message Task Number Carry Set, no Message being
;
Sent
; Carry Reset, Message Sent and Returned in
FSR0L-FSR1L
MsgRead macro TaskNumber
bcf INTCON, GIE ; Disable
Interrupts During RTOS Request Operation
movlw 0x00F
iorwf 0x060, f, 0 ; Set the Appropriate Message Number
movlw 0x010
iorwf TaskNumber, w, 0
call _RTOS
endm
;
; Ack Message Task Number Carry Set, no Message Waiting
; Carry
Reset, Message Acked
MsgAck macro TaskNumber
bcf INTCON, GIE ; Disable
Interrupts During RTOS Request Operation
movlw 0x00F
iorwf 0x060, f, 0 ; Note to RTOS that it is a Command
movlw 0x020
iorwf TaskNumber, w, 0 ; Specify the Task Number
call _RTOS
endm
;
; Interrupt Numbers:
; # Function
Register
; 0 - TMR1 PIR1
; 1 - TMR2 PIR1
; 2 - CCP1 PIR1
; 3 - SSP PIR1
; 4 - TX
PIR1
; 5 - RC
PIR1
; 6 - AD
PIR1
; 7 - PSP PIR1
; 8 - CCP2 PIR2
; 9 - TMR3 PIR2
; 10 - LVD PIR2
; 11 - BCL PIR2
; 12 - RB INTCON
; 13 - INT0
INTCON
; 14 - TMR0
INTCON - Note "E" Flag is NOT Reset
; 15 - SPECIAL
Indicator to RTOS that WREG has the RTOS Function Number
; Task Information
Block Definition:
CBLOCK 0
TIB ; Task Information Block
_wreg, _status, _bsr ; Execution Context Registers
_pclath, _pclatu ; Jump Context Registers
_tablptrl, _tablptrh, tablat ; Table Access Context Registers
_prodl, _prodh ; Multiplication Product
_fsr0:2 ; FSR0
_fsr1:2 ; FSR1
_tos_1:3 ; First Top of Stack
_tos_2:3 ; Second Top of Stack
_tos_3:3 ; Third Top of Stack
ENDC
;
; One Task Information
Block is placed for each Task with the Task's
; File Registers
following them.
;
; The "Task Flag
Register" is Defined as:
; Bits Function
; 7-6 Execution Type
; 11 -
Active, Can Run
; 10 -
Waiting to Receive Message
; 01 -
Sending Message/Waiting for Ack
; 00 -
Waiting for Interrupt
; 5-4 Task Priority
; 11 -
Highest
; :
; 00 -
Lowest
; 3-0 Send Task Address/Interrupt Number Delay
;
;
; Hardware Notes:
; The PIC18Cxx is
Running at 4 MHz.
; Reset is tied
directly to Vcc and PWRT is Enabled.
; TMR0 is running and
Interrupts the PICMicro every 32.768 usecs
; I/O Ports and other
resources are defined by the Applications
;
;
LIST R=DEC, F=INHX32
INCLUDE
"p18f452.inc"
; Register Usage
CBLOCK 0x00C ; Start Registers at End of the Values
Dlay:2
ENDC
; Macros
PAGE
;__CONFIG _CONFIG0,
_CP_OFF_0
;__CONFIG _CONFIG1,
_OSCS_OFF_1 & _XT_OSC_1
;__CONFIG _CONFIG2,
_PWRT_ON_2 & _BOR_ON_2 & _BORV_42_2
; __CONFIG _CONFIG3, _WDT_OFF_3
; __CONFIG _CONFIG5, _CCP2MX_OFF_5
; __CONFIG _CONFIG6, _STVR_OFF_6
__CONFIG _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L
& _CP2_OFF_5L & _CP3_OFF_5L ; all protection off
__CONFIG _CONFIG1H, _OSCS_ON_1H & _XT_OSC_1H ;
External Clock on OSC1 & OSC2
__CONFIG _CONFIG2L, _BOR_ON_2L & _BORV_20_2L
& _PWRT_ON_2L ; Brown out reset on at 2.0V, no power-up timer
__CONFIG _CONFIG2H, _WDT_OFF_2H & _WDTPS_128_2H
; watchdog off, postscaler count to 128
__CONFIG _CONFIG3H, _CCP2MX_OFF_3H ; CCP2 pin Mux
enabled. What is this?
__CONFIG _CONFIG4L, _STVR_OFF_4L ;& _LVP_ON_4L
& _DEBUG_OFF_4L ; Stack under/overflow reset on, LVP on, debug off
; Note that the WatchDog Timer is OFF
; Demo Code, Loop
Forever Toggling PA0 (Flashing the LED)
org 0 ; Reset Vector
clrf TMR0L, 0 ; Reset TMR0
movlw
(1 << TMR0ON) + (1 << T08BIT) + 5
movwf T0CON ; Start T0CON executing
bra _ATSetup
org 8
_RTOS ; Treat RTOS as an address Vector
movff WREG, 0x061 ; Start Saving the Context Registers
movff STATUS, 0x062
movlw 0x062
movwf FSR2L, 0 ; Setup the Pointer to the FSR Register
clrf FSR2H, 0
movff BSR, PREINC2 ; Save the Last Context Register
movff PCLATH, PREINC2
movff PCLATU, PREINC2
movff TBLPTRL, PREINC2
movff TBLPTRH, PREINC2
movff
TABLAT, PREINC2
movff PRODL, PREINC2
movff PRODH, PREINC2
movff FSR0L, PREINC2
movff FSR0H, PREINC2
movff FSR1L, PREINC2
movff FSR1H, PREINC2
movlw 3 ; Save the top 3 Stack Elements
_RTOS_SaveStack
movff TOSL, PREINC2 ; Save the Return
Address
movff TOSH, PREINC2
movff TOSU, PREINC2
pop
decfsz WREG, f, 0
bra _RTOS_SaveStack
; Save the Registers
in Memory
movlw 0x078 ; Find the Active Task
movwf FSR0L, 0
clrf FSR0H, 0
movlw 0x080
movwf FSR1L, 0
clrf FSR1H, 0
_RTOS_SaveFind
btfsc INDF0, 7 ; Bit 7 Set for the Task?
bra _RTOS_SaveFound
movf POSTINC0, 0 ; Get the Value to Add to FSR1L for the Offset
addwf FSR1L, f, 0
btfsc STATUS, C, 0
incf FSR1H, f, 0
bra _RTOS_SaveFind
_RTOS_SaveFound ; FSR1 is Pointing to the Task Memory
movf INDF0, w, 0 ; Get the Count
movwf FSR2L, 0
movlw 0x060 ; Save the Task Information
movwf FSR0L, 0
clrf FSR0H, 0
movlw 0x018 ; Save all 0x018 Context Register Bytes
_RTOS_SaveContext
movff POSTINC0, POSTINC1 ; Move the Value Right
In
decfsz WREG, f, 0
bra _RTOS_SaveContext
movlw 0x098 ; Get the Byte Count to Save
subwf FSR2L, w, 0
btfsc STATUS, Z, 0
bra _RTOS_SaveDone
clrf FSR0L, 0 ; Start at Beginning
clrf FSR0H, 0
_RTOS_SaveRegister
movff POSTINC0, POSTINC1
decfsz WREG, f, 0
bra _RTOS_SaveRegister
_RTOS_SaveDone ; Task Information Saved
; Check the Interrupt Registers
for Requests
clrf FSR0L, 0 ; Clear the Offset Counter
movlw 8 ; Start with 8 Bits
movwf FSR0H, 0
movf PIR1, w, 0 ; Start with PIR1 (Bits 0 - 7)
movwf FSR1L, 0
btfss STATUS, Z, 0
bra _RTOS_HaveInt
movlw 8 ; PIR2 (Bits 8 - 11)
movwf FSR0L, 0
movlw 4
movwf FSR0H, 0
movf PIR2, w, 0
andlw 0x00F ; Only 4 Bits
movwf FSR1L, 0
btfss STATUS, Z, 0
bra _RTOS_HaveInt
bsf FSR0L, 2, 0 ; INTCON (Bits 12
to 14)
decf FSR0H, f, 0
movf INTCON, w, 0
andlw 0x007 ; Only 3 Bits
movwf FSR1L, 0
btfsc STATUS, Z, 0
bra _RTOS_Action
_RTOS_HaveInt ; Figure Out the Interrupt Number
incf FSR0L, f, 0 ; Increment the
rrcf FSR1L, f, 0 ; Shift Down the Bit
btfss STATUS, C, 0 ; Have the Bit?
bra _RTOS_HaveInt
decf FSR0L, f, 0 ; Correct Number In FSR0L
movff FSR0L, FSR0H ; Get the Correct Bit
movlw PIR1 & 0x0FF
movwf FSR1L, 0
movlw PIE1 & 0x0FF
movwf FSR2L, 0
btfss FSR0H, 3 ; Which Register?
bra _RTOS_ClearInt
bcf FSR0H, 3 ; Look for PIR2
movlw PIR2 & 0x0FF
movwf FSR1L, 0
movlw PIE2 & 0x0FF
movwf FSR2L, 0
btfss FSR0H, 2
bra _RTOS_ClearInt
bcf FSR0H, 2 ;
Have INTCON
movlw INTCON & 0x0FF
movwf FSR1L, 0
movwf FSR2L, 0
_RTOS_ClearInt ; Find Bit to Clear
movlw 0x00F
movwf FSR1H, 0
movwf FSR2H, 0
movlw 0x0FE
movf FSR0H, f, 0 ; Set Zero Flag if Bit Number is Zero
btfsc STATUS, Z, 0
bra $ + (2 * 4)
rlncf WREG, f, 0
decfsz FSR0H, f, 0
bra $ - (2 * 2)
movff FSR0L, FSR0H ; Save the Bit Number
andwf INDF1, f, 0 ; Clear the "F" Bit
movwf FSR0L, 0 ; Save Mask for "E" Bit
movlw 14 ;
Do we Have a TMR0?
xorwf FSR0H, w, 0
btfsc STATUS, Z, 0
bra _RTOS_ClearDone
movlw 0x00C ; Is this an INTCON Value?
andwf FSR0H, w, 0
xorlw 0x00C
btfss STATUS, Z, 0
bra _RTOS_ClearDo
rlncf FSR0L, f, 0 ; INTCON - Shift the Mask Up by 3 to Reset
rlncf FSR0L, f, 0
rlncf FSR0L, f, 0
_RTOS_ClearDo
movf FSR0L, w, 0
andwf INDF2, f, 0 ; Clear the "E" Bits
_RTOS_ClearDone ; The Interrupt Bits are Cleared
movlw 0x078 ; Interrupt Number if FSR0H
movwf FSR1L, 0
clrf FSR1H, 0
movlw 0x080 ; Look at the Flag Register
movwf FSR2L, 0
clrf FSR2H, 0
_RTOS_IntResetLoop
movf FSR0H, w, 0 ; Does the Interrupt Match the Waiting?
xorwf INDF2, w, 0
andlw 0x00F
btfss STATUS, Z, 0
bra _RTOS_IntResetSkip
movlw 0x030 ; Reset the Check Value
andwf INDF2, w, 0
iorlw 0x0C0 ; Mark that it is Active
movwf INDF2, 0
_RTOS_IntResetSkip
movf POSTINC1, w, 0 ; Get the Increment Value
andlw 0x07F ; Make Sure Top Bit is Reset
addwf FSR2L, f, 0 ; Add to the Offset
btfsc STATUS, Z, 0
incf FSR2H, f, 0
movf INDF1, f, 0
btfsc STATUS, Z
bra $ + (2 * 3) ; Zero, Gone through the List
btfss INDF0, 7, 0 ;
Value == 0x080 (Past End?)
bra _RTOS_IntResetLoop
; Now, Look through
for Action in the Operation
_RTOS_Action
movlw 0x078 ; Look for Tasks Waiting for Action
movwf FSR0L, 0
clrf FSR0H, 0
movlw 0x080 ; Keep Track of the TASK Address
movwf FSR1L, 0
clrf FSR1H, 0
_RTOS_ActionLoop
movf INDF1, w, 0
andlw 0x00F ; Do we Have an "Action"
Command?
xorlw 0x00F
btfss STATUS, Z, 0
bra _RTOS_ActionDone ; No, Skip Over
movlw 1 ; Check the "w" Register for the
Command
btfss PLUSW1, 5, 0
bra _RTOS_ActionNotAck
_RTOS_ActionAck ; Look for Task Sending to Current
movf INDF1, w, 0 ; Current Task can Execute Afterward no matter
what
andlw 0x0F0 ; Clear out the Task Number
iorlw 0x0C0 ; Indicate that it is Active
movwf INDF1, 0
movff FSR1L, TBLPTRL ; Save the contents of FSR1
movff FSR1H, TBLPTRH
movlw _wreg ; Get the Task Number
movf PLUSW1, w, 0
andlw 0x0FF ^ (1 << 5)
movwf PRODH, 0
movlw 8
subwf PRODH, w, 0 ; Do we Have a Problem?
btfsc STATUS, C
bra _RTOS_ActionAckError ; Yes, Task Number is >
7, or Other Bits Set
movlw 0x078 ; Point to the Task Table
movwf FSR1L, 0
clrf FSR1H, 0
movlw 0x080 ; Point to the First Task
movwf FSR2L, 0
clrf FSR2H, 0
movlw 0x078 ; Get the Task Number Sending
subwf FSR0L, w, 0
movwf PRODL, 0 ; Use "PRODL" as a Temporary Register
movwf TABLAT, 0 ; Use "TABLAT" as the Task Counter
_RTOS_ActionAckLoop ; Loop Here Until Task Found
movf TABLAT, f, 0 ; Is
"PRODL" equal to Zero?
btfsc STATUS, Z, 0
bra _RTOS_ActionAckLoopEnd
movf POSTINC1, w, 0 ; Add to the FSR2 Offset
btfsc STATUS, Z, 0
bra _RTOS_ActionAckError ; Error - If Zero, then
not Loaded Task
decf TABLAT, f, 0
btfsc STATUS, Z, 0
bra _RTOS_ActionAckLoopEnd
andlw 0x07F ; Clear Bit 8 if active
addwf FSR2L, f, 0
btfsc STATUS, C, 0
incf FSR2H, f, 0
bra _RTOS_ActionAckLoop
_RTOS_ActionAckLoopEnd ; Have the Task that is Finished
movlw 0x078
subwf FSR0L, w, 0
movwf PRODH
movlw _wreg
movf PLUSW2, w, 0
xorwf PRODH, w, 0
andlw 0x00F
btfss STATUS, Z, 0
bra _RTOS_ActionAckError ; Doesn't Equal, A problem
movff TBLPTRL, FSR1L ; Restore FSR1
movff TBLPTRH, FSR1H
movf INDF2, w, 0
andlw 0x030
iorlw 0x0C0
movwf INDF2, 0 ; Indicate to Sender it can Execute
movlw _status ; Indicate Operation Executed Correctly
bcf PLUSW1, C, 0
bra _RTOS_ActionDone
_RTOS_ActionAckError ; Set Carry Flag if there is a Problem
movff TBLPTRL, FSR1L ; Restore FSR1
movff TBLPTRH, FSR1H
movlw _status
bsf PLUSW1, C, 0 ; Task STATUS is two
from the Start
bra _RTOS_ActionDone
_RTOS_ActionNotAck
btfss PLUSW1, 4, 0
bra _RTOS_ActionNewTask
_RTOS_ActionRead
movf INDF1, w, 0 ; Current Task can Execute Afterward no matter
what
andlw 0x0F0 ; Clear out the Task Number
iorlw 0x0C0 ; Indicate that it is Active
movwf INDF1, 0
movff FSR1L, TBLPTRL ; Save the contents of FSR1
movff FSR1H, TBLPTRH
movlw _wreg ; Get the "WREG" Contents
movf PLUSW1, w, 0 ; Save the Task
Number
andlw 0x0FF ^ (1 << 4)
movwf PRODH, 0
movlw 8
subwf PRODH, w, 0 ; Do we Have a Problem?
btfsc STATUS, C
bra _RTOS_ActionReadError ; Yes,
Task Number is > 7, or Other Bits Set
movlw 0x078 ; Point to the Task Table
movwf FSR1L, 0
clrf FSR1H, 0
movlw 0x080 ; Point to the First Task
movwf FSR2L, 0
clrf FSR2H, 0
_RTOS_ActionReadLoop ; Find the Specified Task Number
movf PRODH, f, 0
btfsc STATUS, Z, 0
bra _RTOS_ActionReadFound
movf POSTINC1, w, 0 ; Get Offset Into Register
Memory
addwf FSR2L, f, 0
btfsc STATUS, C, 0
incf FSR2H, f, 0
decf PRODH, f, 0
bra _RTOS_ActionReadLoop
_RTOS_ActionReadFound ; At the Corect Offset
movf INDF2, w, 0 ; Is it Sending to this Task?
andlw 0x0C0
xorlw 0x040
btfss STATUS, Z, 0
bra _RTOS_ActionReadError
movlw 0x078
subwf FSR0L, w, 0
xorwf INDF2, w, 0
andlw 0x00F
btfss STATUS, Z, 0
bra _RTOS_ActionReadError
movff TBLPTRL, FSR1L ; Save the contents of FSR1
movff TBLPTRH, FSR1H
movlw _fsr0 ; Transfer FSR0L Byte
movff PLUSW2, PLUSW1
movlw _fsr1
movff PLUSW2, PLUSW1
movlw _status ; Indicate Operation Executed Correctly
bcf PLUSW1, C, 0
bra _RTOS_ActionDone
_RTOS_ActionReadError ; Set Carry Flag if there is a Problem
movff TBLPTRL, FSR1L ; Restore FSR1
movff TBLPTRH, FSR1H
movlw _status
bsf PLUSW1, C, 0 ; Task STATUS is
two from the Start
bra _RTOS_ActionDone
_RTOS_ActionNewTask
movf INDF1, w, 0 ; Current Task can Execute Afterward no matter
what
andlw 0x0F0 ; Clear out the Task Number
movwf INDF1, 0
movlw _fsr1 ; Check the Size for Validity
movff PLUSW1, PRODL
movlw 63 + 1 ; Maximum of 63 Variable Bytes
subwf PRODL, w, 0 ; Make Sure Size isnt' too large.
btfsc STATUS, C, 0
bra _RTOS_ActionNewTaskError
movlw _fsr0 ; Get the Priority and Save it
movff PLUSW1, PRODH
movff FSR1L, TBLPTRL ; Save the contents of FSR1
movff FSR1H, TBLPTRH
movlw 0x077 ; Find the New Task Space
movwf FSR1L, 0
clrf FSR1H, 0
movlw 0x080 ; Point to the First Task
movwf FSR2L, 0
clrf FSR2H, 0
_RTOS_ActionNewTaskLoop ; Loop Here Until Open Task Found
movf PREINC1, w, 0 ; Add to the FSR2
Offset
btfsc STATUS, Z
bra _RTOS_ActionNewTaskFound
andlw 0x07F ; Clear Bit 8 if active
addwf FSR2L, f, 0
btfsc STATUS, C, 0
incf FSR2H, f, 0
movlw 0x07F ; At the End and Nothing Available?
subwf FSR1L, w, 0
btfss STATUS, Z, 0
bra _RTOS_ActionNewTaskLoop
bra _RTOS_ActionNewTaskError
_RTOS_ActionNewTaskFound ; Have the Task Block that is Available
movlw 0x018
addwf PRODL, f, 0 ; Get the Task's Size and Put in Blocks
movff PRODL, INDF1
movlw 0x078
subwf FSR1L, w, 0 ; get the Task Number
movwf TABLAT, 0
movff TBLPTRL, FSR1L ; Restore FSR1
movff TBLPTRH, FSR1H
movlw _wreg ; Update "WREG" with the Created Task
Number
movff TABLAT, PLUSW1
movff FSR2L, TBLPTRL ; Save the Block Start
Address
movff FSR2H, TBLPTRH
movf PRODL, w, 0 ; Clear the Memory
clrf POSTINC2, 0
decfsz WREG, f, 0
bra $ - (2 * 2)
movff TBLPTRL, FSR2L ; Restore the Block Start
Address
movff TBLPTRH, FSR2H
movf PRODH, w, 0 ; Get the Task Priority
iorlw 0x0C0 ; Mark that it is Active
movwf INDF2, 0
movff FSR1L, PRODL ; Save the Source Address
movff FSR1H, PRODH
movlw _tos_2 ; Get the Source Address
addwf FSR1L, f, 0 ; Add the Offset to it
btfsc STATUS, C, 0
incf FSR1H, f, 0
movff POSTINC1, TBLPTRL
movff POSTINC1, TBLPTRH
movff POSTINC1, TABLAT
movff FSR2L, PCLATH ; Save FSR2 Start
for Saving PCLAT Registers
movff FSR2H, PCLATU
movlw _tos_1 ; Putin Execution Address
addwf FSR2L, f, 0 ; Add the Offset to it
btfsc STATUS, C, 0
incf FSR2H, f, 0
movff TBLPTRL, POSTINC2
movff TBLPTRH, POSTINC2
movff TABLAT, POSTINC2
movff
PCLATH, FSR2L ; Setup Pointer to Start
movff PCLATU, FSR2H
movlw _pclath ; Put in the PCLATH Values
addwf FSR2L, f, 0
btfsc STATUS, C, 0
incf FSR2H, f, 0
movff TBLPTRH, POSTINC2
movff TABLAT, POSTINC2
movff PRODL, FSR1L ; Save the Source Address
movff PRODH, FSR1H
movlw _status ; Indicate Operation Executed Correctly
bcf PLUSW1, C, 0
bra _RTOS_ActionDone
_RTOS_ActionNewTaskError ; Set Carry Flag if there is a Problem
movff TBLPTRL, FSR1L ; Restore FSR1
movff TBLPTRH, FSR1H
movlw _status
bsf PLUSW1, C, 0 ; Task STATUS is
two from the Start
bra _RTOS_ActionDone
_RTOS_ActionDone ; Finished Executing Request
movf POSTINC0, w, 0 ; Get the Offset to the Next
andlw 0x07F ; Make Sure Bit 7 Not Set
addwf FSR1L, f, 0
btfsc STATUS, C, 0
incf FSR1H, f, 0
movf INDF0, f, 0
btfsc STATUS, Z, 0
bra _RTOS_ActionEnd ; Next Value == 0, Finished
with List
btfss FSR0L, 7, 0 ; Are we at 0x080?
bra _RTOS_ActionLoop
_RTOS_ActionEnd
movlw 0x078 ; Look for Tasks that are waiting for messages
movwf FSR0L, 0
clrf FSR0H, 0
movlw 0x080 ; FSR1 Points to the Offsets
movwf FSR1L, 0
clrf FSR1H, 0
_RTOS_WaitLoop
movf INDF0, f, 0 ; At End of Task List?
btfsc STATUS, Z, 0
bra _RTOS_WaitDone
movf INDF1, w, 0 ; Waiting for a Message?
andlw 0x0C0
xorlw 0x080
btfss STATUS, Z, 0
bra _RTOS_WaitNext ; No - Jump to the Next
Task
movff FSR1L, PRODL ; Save FSR1 and Look for Matches
movff FSR1H, PRODH
movlw 0x078
movwf FSR1L, 0
clrf FSR1H, 0
movlw 0x080 ; Get the Offsets
movwf FSR2L, 0
clrf FSR2H, 0
_RTOS_WaitSubLoop ; Loop Here for a Match
movf INDF1, f, 0 ; At the End of the List?
btfsc STATUS, Z, 0
bra _RTOS_WaitRestoreNext ; Yes,
No March
movf INDF2, w, 0 ; Check for sending a Value
andlw 0x0C0
xorlw 0x040
btfss STATUS, Z, 0
bra _RTOS_WaitSubNext ; No, Check the Next
movf INDF2, w, 0 ; Get the Task Number
andlw 0x00F
addlw 0x078
xorwf FSR0L, w, 0 ; Does it Match the "Get" Task?
btfss STATUS, Z, 0
bra _RTOS_WaitSubNext ; No, Skip Over
movf FSR1L, w, 0
movff PRODL, FSR1L ; Restore to Look at the Original (for
Resetting)
movwf PRODL, 0 ; Save the Offset for Setting up the
Destination
movff PRODH, FSR1H
movlw 0x0C0 ; Mark that the Task Can Execute
iorwf INDF1, f, 0
movlw _fsr0 ; Move the Data Over
movff PLUSW2, PLUSW1
movlw _fsr1
movff PLUSW2, PLUSW1
movlw 0x078 ; Return the Task Number
subwf PRODL, f, 0
movlw _wreg
movff PRODL, PLUSW1
bra _RTOS_WaitNext
_RTOS_WaitSubNext ; No Match, Loop Around and Try Again
movf POSTINC1, w, 0
andlw 0x07F
addwf FSR2L, f, 0
btfsc STATUS, C, 0
incf FSR2H, f, 0
btfss FSR1L, 7, 0 ; At Address 0x080?
bra _RTOS_WaitSubLoop
_RTOS_WaitRestoreNext
movff PRODL, FSR1L
movff PRODH, FSR1H
_RTOS_WaitNext
movf POSTINC0, w, 0 ; Point to the Next Task
andlw 0x07F
addwf FSR1L, f, 0
btfsc STATUS, C, 0
incf FSR1H, f, 0
btfss FSR0L, 7, 0 ; At the End of the Tasks?
bra _RTOS_WaitLoop
_RTOS_WaitDone
movlw 0x078 ; Find the Next Task to Execute (From Current)
movwf FSR0L, 0
clrf FSR0H, 0
movlw 0x080
movwf FSR1L, 0
clrf FSR1H, 0
_RTOS_ExecuteFind
btfsc INDF0, 7, 0 ; Is the Execution flag Set?
bra _RTOS_ExecuteFound
movf POSTINC0, w, 0
addwf FSR1L, f, 0
btfsc STATUS, C, 0
incf FSR1H, f, 0
bra _RTOS_ExecuteFind
_RTOS_ExecuteFound ; Have Found Current Task
movff FSR0L, PRODL ; Record the Start Position
clrf PRODH, 0 ; Record the Next to Execute's
clrf FSR2L, 0 ; Record the Next to Execute's Priority
clrf FSR2H, 0
bcf INDF0, 7, 0 ; Clear the
Execution Flag
_RTOS_ExecuteLoop
movf POSTINC0, w, 0 ; Jump to the Next Value
movf INDF0, f, 0 ; At the End of the List?
btfss STATUS, Z, 0
btfsc FSR0L, 7, 0 ; Either Next is Zero or Current is == 0x80
bra _RTOS_ExecuteWrap ; Yes, Wrap Around
addwf FSR1L, f, 0 ; Add it to the Execution List
btfsc STATUS, C, 0
incf FSR1H, f, 0
bra _RTOS_ExecuteCheck
_RTOS_ExecuteWrap ; Wrap Execution back to the Start
movlw 0x078
movwf FSR0L, 0
clrf FSR0H, 0
movlw 0x080
movwf FSR1L, 0
clrf FSR1H, 0
_RTOS_ExecuteCheck ; Check to See if Current is Better than Last
movf INDF1, w, 0 ; Check to See if it can Execute
andlw 0x0C0
xorlw 0x0C0
btfss STATUS, Z
bra _RTOS_ExecuteEndCheck ;
Can't Execute, Check to See if at End
movf PRODH, f, 0 ; Anything Entered Yet?
btfsc STATUS, Z, 0
bra _RTOS_ExecuteAdd ; No - Start with This one
movf INDF1, w, 0 ; Check to See if Current is Higher Priority
subwf INDF2, w, 0 ; than Saved
btfsc STATUS, C, 0
bra _RTOS_ExecuteEndCheck ; It's
not
_RTOS_ExecuteAdd
movff FSR0L, PRODH ; Save the Offset
movff FSR1L, FSR2L
movff FSR1H, FSR2H
_RTOS_ExecuteEndCheck ; At the End?
movf PRODL, w, 0
xorwf FSR0L, w, 0
btfss STATUS, Z
bra _RTOS_ExecuteLoop ; No, Look at another
one
movff PRODH, FSR0L ; Point to the Current Value
clrf FSR0H, 0
bsf INDF0, 7, 0 ; Mark that it is
Executing
movlw 0x060 ; Copy in the TIB Information
movwf FSR1L, 0
clrf FSR1H, 0
movlw 0x018
_RTOS_TIBRestore
movff POSTINC2, POSTINC1
decfsz WREG, f, 0
bra _RTOS_TIBRestore
movf INDF0, w, 0
andlw 0x07F ; Clear the Execution Flag
movwf PRODL, 0
movlw 0x018
subwf PRODL, w, 0 ; Copy in the Registers
btfsc STATUS, Z, 0
bra _RTOS_Restore
clrf FSR1L, 0
clrf FSR1H, 0
_RTOS_RegRestore
movff POSTINC2, POSTINC1
decfsz WREG, f, 0
bra _RTOS_RegRestore
_RTOS_Restore ; Ready to Resume Execution
movlw 0x077 ; Restore the Registers
movwf FSR2L, 0
clrf FSR2H, 0
movlw 3 ; Restore the Stack
movwf FSR0L, 0
_RTOS_RestoreStack
push
movf POSTDEC2, w, 0 ; Restore the Pushed
Addresses
movwf TOSU
movf POSTDEC2, w, 0
movwf TOSH
movf POSTDEC2, w, 0
movwf TOSL
decfsz FSR0L, f, 0
bra _RTOS_RestoreStack
movff POSTDEC2, FSR1H ; Restore the Task Context
Registers
movff POSTDEC2, FSR1L
movff POSTDEC2, FSR0H
movff POSTDEC2, FSR0L
movff POSTDEC2, PRODH
movff POSTDEC2, PRODL
movff POSTDEC2, TABLAT
movff POSTDEC2, TBLPTRH
movff POSTDEC2, TBLPTRL
movff POSTDEC2, PCLATU
movff POSTDEC2, PCLATH
movff POSTDEC2, BSR ; Restore the
Context Registers
movff POSTDEC2, STATUS
movff POSTDEC2, WREG
retfie
_ATSetup ; Setup the "AllTask" Value
movlw (1 << GIE) + (1 << PEIE) + (1
<< TMR0IE)
movwf INTCON
movlw 0x098 ; Setup the "AllTask" OS Value
movwf 0x078, 0 ; Note that it is Active As well
movlw 7
movwf 0x060, 0 ; Clear the Other Task Size Registers
movlw 0x079
movwf FSR0L, 0
clrf FSR0H, 0
clrf POSTINC0, 0 ; Clear the Register FSR0 is Pointing to and
Increment
decfsz 0x060, f, 0 ; Repeat 7x
bra $ - (2 * 2)
push ; Make Sure Stack is Loaded and No UNDERFLOW
push
push
movlw 0x0C0 ; Mark that "AllTask" is Executing
movwf 0x060, 0
_AllTask ; Always Return Here
TaskStart Task1, 1, 63 ;
Start Application Code
_AllTask_Loop
TaskNext ; Jump to Next Active Task
bra _AllTask_Loop
Task1
CBLOCK 0x000 ;
Put the Variables Starting at 0x000
LEDTask ;
Counter ; Number of Times Executing
LEDValue
ENDC
clrf Counter, 0 ; Clear the Variables
movlw 0x0FF
movwf LEDValue
TaskStart
LEDTaskStart, 1, 2 ; Put in the LED Executing Task
movwf LEDTask ; Save the Task Number of LEDTask
movff LEDValue, FSR0L ; Save the LED Task Value
MsgSend LEDTask
nop
Task1Loop ; Loop Here Until 64x Past
IntWait 14 ; Wait for the Timer0 Interrupt
incf Counter, f, 0
movlw 64 ; Done 64x?
xorwf Counter, w, 0
btfss STATUS, Z, 0
bra Task1Loop ; If Not, Loop Around Again
movwf Counter, 0
decf LEDValue, f, 0 ; Increment the LEDs
movff LEDValue, FSR0L
MsgSend LEDTask
bra Task1Loop
LEDTaskStart ; Make PORTB Output and Wait for Messages
CBLOCK 0x000 ;
Variables
LEDTaskNumber
ENDC
clrf TRISB, 0
LEDTaskLoop ; Loop Here for Each Character
MsgWait
movwf LEDTaskNumber, 0 ; Save the Task Number
MsgRead LEDTaskNumber
movff FSR0L, PORTB ; Update the LED Value
MsgAck LEDTaskNumber ;
Acknowledge the Message
bra LEDTaskLoop
end
No comments:
Post a Comment