CSE466 Assignment 2 Solution

In my version, I went ahead and added the code to check for the case that the fan is moving too slow. There are at least three ways that this code can fail in real operation. Identify at least two of these failure modes and make any changes or additions necessary to catch them. Note: I am not looking for bugs in my code, If I made an obvious programming error, please fix it, but it won't count against the two items!

The some possible problems with the original solution:

  1. If the fan is turning slow enough then the timer might overflow (maybe several times) before we get an external interrupt. In this case, the program might erroneously conclude that the fan is operating normally. To solve this problem, modify the T2 interrupt routine to check for the overflow flag.  In the event of overflow, just set the period to FFFF so that the main routine will notice that the fan is out of range.  This will also work if the fan is not turning at all. We don't have to set up our timer any differently because the T2 interrupt is caused by either T2_EX or TF2. 
  2. Since the timer value is a 16 bits (two bytes) there is a risk that we could get fan interrupt in the middle of the 16 bit compare, right after concluding that the high order bytes are equal. If this happens, periodL might be changed by the interrupt service routine (ISR) so that it is greater than MaxL. Say for example that the fan period is changes from 2B60H to 2A90H in the middle of the comparison. In this case the system might erroneously conclude that the fan is operating out of range. The easy fix for this is to just consider the high order byte and set the limit to 2CH! which is probably much better since each fan might operate a little differently anyway so we don't want to set our limit with no margin for error. In the event that we do care about the low order byte, it would be better to temporarily disable interrupts during the comparison as I have shown below. There is no potential for missing an interrupt in this case...we just postpone processing it. To minimize the time that interrupts are disable, I decided just to make a local copy of the period variables while interrupts are disabled.
  3. I enabled interrupts before initializing the period...oops. This could be bad because an interrupt might occur in the middle of initialization, causing a similar problem to the one above
  4. I neglected to initialize 'then'
  5. I don't deal with the case that the first fan interrupt I receive is invalid since the process will not have recorded a complete period. However, since I am only checking for periods that are too long, this particular problem would not cause any trouble since it will only make the fan look like is turning too fast.
NAME HW2

maxH equ  2BH;  maximum period at 30Hz is 11K
maxL equ  67H;

PROG SEGMENT CODE
VAR1 SEGMENT DATA
BITVAR SEGMENT BIT
STACK SEGMENT IDATA
RSEG  BITVAR     ; relocatable segment
first: DBIT  1           ; single bit variables

RSEG VAR1
periodH:  DS  1
periodL:  DS  1
thenL:     DS 1
thenH:    DS 1
localpH  DS1
localpL  DS 1

RSEG  STACK  ; relocatable segment

DS    10H  ; 16 Bytes
CSEG  AT   0 ; absolute segment        
JMP   START  ; Execution starts here on reset.

CSEG AT 2BH  ; location for EX2 interrupt
PUSH  ACC;
PUSH  PSW;
PUSH  R3;
JMP    MYT2;

RSEG  PROG
MYT2:
    MOV C,TF2          ; move the overflow flag to the carry bit
    JNC   NOOVR     ; No overflow found, so no problem
    MOV periodH #FF ; ensures that main routine will detect fan speed error
    MOV periodL #FF ;
    MOV TL2, #00;      reset everything
    MOV TH2,#00;     
    MOV thenL, #00;  
    MOV thenH, #00; 
    JMP   exit
NOOVR:

    CLR C;
    MOV  A,RCAP2L ; get low byte
    MOV  R3,A           ; save for later
    SUBB thenL        ; subtract "then" low byte
    MOV  thenL,R3  ; save now as then
    MOV  periodL,A     ; store difference in low byte  
    MOV  A,RCAP2H; get high byte
    MOV  R3,A       ; save for later    
    SUBB A, thenH   ; subtract high byte
    MOV  thenH,R3  ; save now as then
    MOV  periodH,A ; store high byte difference
    MOV  T2CON, #0D;  clear the interrupt flags
EXIT:
    POP   R3;
    POP   PSW;
    POP   ACC;
    RTI

 

RSEG  PROG      ; relocatable segment

START:
    MOV  SP,#STACK-1 ; first set Stack Pointer
    MOV  PSW,#00  ; use register bank 0
    MOV  T2CON, #0D;    setup timer 2 for internal clock, capture, external interrupt
    MOV  IE, #C0        ;     enable global interrupts and T2EX interrupt
    MOV  periodH,#00;
    MOV  periodL,#00;
LOOP:
    CLR    EA             ; disable all interrupts
    MOV  localpH,periodH ;
    MOV  localpL,periodL ;
    SET    EA             ; enable interrupts

    MOV  A,localpH;
    CLR    C;
    SUBB A,#maxH;
    JC       OKAY;   maxH is greater than periodH so no error
    JNZ    ERR;        maxH is less than periodH so error  
; maxH equals periodH so check the low byte
    MOV  A,localpL;
    CLR   C;
    SUBB A,#maxL
    JC      OKAY;   maxL is greater than periodL so okay
    JZ       OKAY;  maxL is equal to periodL so okay
ERR: SET   P1.1    ; set error bit
    JMP  LOOP;
OKAY: CLR P1.1
    JMP LOOP