This post continues series of examples and describes how VELOOS can be used for implementing time-triggered applications.
Example2 – Heartbeat Driven PDO
Design idea: | Enhance previous example with a timer and two PDOs processing timer messages. Use EEPROM to keep instance-specific data. |
Value: | Gives a simple example of implementing (1) time-triggered PDOs, (2) reenterable classes. Implements a class which may be used for debug purposes to watch system "heartbeat". |
Design Description
This sample application implements two PDO each triggering port pin with a certain period: first PDO is on 1 sec period, second – on 1 ms. Since behavioral pattern of these PDO are the same, they were implemented as instances of the same class.
Deploying VELOOS Timer Driver
Timer Driver is a non-reenterable encapsulated PDO with an interrupt handler and internal counters for millisecond and seconds. To deploy a timer driver to VELOOS application, the project should include file vtm0.asm (Timer0 based) or vtm2.asm (Timer2 based). Timer constants are calculated automatically based on _osc_clock
. Timer driver configures hardware timer for 1 ms interrupts. When a timer interrupts occurs, Interrupt Handler sends a broadcast message. Timer PDO counts 1ms messages and on every 1000-th broadcasts a 1s message. Both 1 ms and 1 s messages include current time value.
In a pseudo language messages can be declared as the following (acceptor field is not shown):
struct VTMR_cMsgTimer1ms { |
struct VTMR_cMsgTimer1s { |
Handling Timer Messages
Timer messages are regular VELOOS messages. To handle a timer message, PDO should first recognize the message and then, if necessary, examine time delivered with the message and take appropriate action:
MyHandler ; FSR points to message ID field
movlw VTMR_cMsgIDTimer1ms
xorwf INDF, W ; if message.msg_id <> VTMR_cMsgIDTimer1ms
skpz
return ; return
incf FSR, F ; make FSR pointing to LSB of message data
movf INDF, W
andlw 0F0h
xorlw 007h ; on 7-th msec of every 16 msec
skpnz
return
; do something
Targeting Reenterability
To make a class reenterable, it should not be build-time-bound to any resource. This sample class achieves reenterability by using This as a pointer to EEPROM data with configuration (message ID, port mask) assigned to a particular class instance. In run-time PDO reads data from EEPROM on per need basis (e.g. does not cache in in registers). Since message ID is also stored in EEPROM, message handler first reads message ID from EEPROM and then message is processed:
TmrHandler
movf This, W
call EE_read ; W = EEPROM[This]; //(== msgid)
xorwf INDF, W
skpz
return
With this design, class should be properly instantiated, e.g. object data should point to the configuration location in EEPROM. This can be achieved with use of a label, placed in EEPROM section:
DEEPROM code
On1mSecData ; Configuration name
de VTMR_cMsgIDTimer1ms, .1 ; Configuration data
VOS_Objects ; Object registry begins
On1mSec ; Object name (not necessary for this example)
VOS_mPersistentObject MyTimer, On1mSecData ; Instance on MyTimer constructed with
;object data pointing to configuration
Building the project
All classes and objects for this example (except Timer) are declared, implemented and instantiated in one file: main.asm. Although this is not a recommended practice, this example, for simplicity, gives it this way. Moduling aspects will be discussed in a subsequent example.
A package with sources for this example can be downloaded on this link. It includes the following files:
Example2.mcp |
MP LAB project file |
main.asm |
Example2 application sources |
pic.inc |
Processor-specific primitives, macros and includes |
pic16.inc |
PIC16/PIC12 specific primitives |
vos.asm |
VELOOS kernel |
vos.inc |
VELOOS public interface |
vos_cfg.inc |
VELOOS configuration file |
vtm2.inc |
Timer public interface |
vtm2_m.inc |
Timer auxiliary macros |
vtm2.asm |
Timer implementation |
16f690.lkr |
VELOOS specific linker script |
Application Source
; License: Licensed to public under the Open Software License
; http://www.opensource.org/licenses/osl-3.0.php
include "pic.inc"
include "vos.inc"
;------------------------------------------------------------------------------
__CONFIG _WDT_ON & _INTRC_OSC_NOCLKOUT & _CP_OFF & _PWRTE_ON & _MCLRE_ON & _FCMEN_OFF & _BOR_OFF & _IESO_OFF
;------------------------------------------------------------------------------
constant mask = 02h ; mask to be used for driving port (RA1)
constant msgid = 040h ; message ID
constant mask1ms = 04h ; mask to be used for driving port on 1 msec event (RC2)
constant mask1s = 08h ; mask to be used for driving led (RC3)
VOS_Classes ; Class definitions begin
MyClass VOS_mClass MyHandler, MyInit ; MyClass implementes MyHandler and MyInit methods
MyTimer VOS_mClass TmrHandler, TmrInit ; MyTimer implementes TmrHandler, TmrInit
; Class definitions end with beginning of the next code section
VOS_Objects ; Object registry begins
MyObject
VOS_mPersistentObject MyClass, mask ; Instance of MyClass constructed with object data == mask
On1mSec
VOS_mPersistentObject MyTimer,On1mSecData; Instance on MyTimer constructed with object data pointing
; to EERPOM location
On1Sec
VOS_mPersistentObject MyTimer,On1SecData ; Another instance on MyTimer
; Object registry ends with beginning of the code next section
;------------------------------------------------------------------------------
DEEPROM code
On1mSecData
de VTMR_cMsgIDTimer1ms, mask1ms
On1SecData
de VTMR_cMsgIDTimer1s, mask1s
;------------------------------------------------------------------------------
code
MyInit ; This was loaded with object data
comf This, W ; W := ~mask
banksel TRISA
movwf TRISA ; Prepare port for output
VOS_mPostMessage MyObject, msgid ; post message to itself
return
;------------------------------------------------------------------------------
MyHandler ; FSR points to message ID field, This is loaded with object data
movlw msgid
xorwf INDF, W ; if message.msg_id <> msgid
skpz
return ; return
movf This, W
banksel PORTA
xorwf PORTA, F ; Toggle port
VOS_mPostMessage MyObject, msgid ; post message to itself
return
;------------------------------------------------------------------------------
EE_read
banksel EEADR
movwf EEADR ; EEADDR = This
banksel EECON1
bsf EECON1, RD ; EE Read
banksel EEDATA
movfw EEDATA
return
;------------------------------------------------------------------------------
TmrHandler
movf This, W
call EE_read ; W = EEPROM[This] == msgid
xorwf INDF, W
skpz
return
incf This, W
call EE_read ; W = EEPROM[This+1] == mask
banksel PORTC
xorwf PORTC, F ; Toggle PORT
return
;------------------------------------------------------------------------------
TmrInit
incf This, W
call EE_read ; W = EEPROM[This+1] == mask
xorlw 0FFh ; W = ~mask
banksel TRISC
andwf TRISC, F ; Prepare port for output according to mask
return
;------------------------------------------------------------------------------
VOS_BootHandlers code ; starts a section for the application boot handler
banksel ANSEL
clrf ANSEL ; Turn all pints to digital
clrf ANSELH
banksel OSCCON ; Set Fosc = 8Mhz
movlw (.7 << IRCF0)
movwf OSCCON
banksel OSCTUNE
movlw -.4
movwf OSCTUNE
; !!! NO RETURN ALLOWED !!!
;------------------------------------------------------------------------------
end
Post a Comment