Skip to content

VELOOS Example 2

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 { 
  byte    msg_id;
  word    millisec; }
 struct VTMR_cMsgTimer1s {
   byte    msg_id;
   word    seconds; }

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

Download sources

Running the application

This application was loaded to PIC16F690 on "Low Pin Count Demo Board" supplied with PICkit™ 2. Activity of 1s driven object can be visually monitored with a led. Activities of other objects (1ms and self-triggering) can be monitored aurally, for example by connecting a headset, or with a scope. Signals from RC2 and RC3 were captured with Simplescope and their traces are shown on Figure 1 and Figure 2. As results show, in the first run 1 ms period was actually shorter  – 970 us instead of 1000. Therefore, for the next run internal oscillator has been tuned with -4 value. Traces indicate that 1 ms period varies 1000-1080 ms – this is an expected effect of message queuing.

  Timing of sampled signals
Figure 1
  Timing of sampled signals (adjusted)
Figure 2

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

Your email is never published nor shared. Required fields are marked *
*
*

*