Results 1 to 6 of 6

Thread: MEL Trainer Chap 9 Example code questions

  1. #1
    Member
    Join Date
    Mar 2013
    Location
    Sheboygan, Wisconsin, USA
    Posts
    60

    MEL Trainer Chap 9 Example code questions

    I have the ME Labs Trainer and am working with the Chapter 9 code "Timer-Driven Assembly Language Interrupt" My goal is to understand the code well enough to port the code over to my PIC of choice and eventually develop interrupt code on my own.

    In the code relating to the actual interrupt there are comments in the lines of code but no explanation in the tutorial as to what is being done. I would like to know the purpose and how these particular Hex values were arrived at. I understand the assembly commands generally but not why the code is used. The lines in question are as follows:

    movlw 0xA7 ; Load W with 0xA7
    addwf TMR1L, F ; Add preset value to TMR1 LSB
    btfsc STATUS, 2 ; If no byte overflow, skip next instruction
    incf TMR1H, F ; If byte overflow, increment MSB of TMR1
    movlw 0x3C ; Load W with 0x3C
    addwf TMR1H, F ; Add preset value to TMR1 MSB

    Are these values used like in the previous chapter examples to adjust the time duration? If so how were they computed? I don't follow the manipulation of TMR1H byte. Why add 0xA7? Also what does incrementing the MSB do? What does adding 0x3C do? The narrative in the .pdf manual does not give any explanation what is going on with these lines.

  2. #2
    Senior Member
    Join Date
    Sep 2011
    Location
    australia
    Posts
    251
    Quote Originally Posted by abecker View Post
    what is going on with these lines.
    put simply timer1 = timer1 + 15527

    its a bog standard 16 bit addition of a 16 bit constant to a 16bit var on a 8 bit pic done in asm


    timer1 low byte = timer1 low + const low
    if result overflows (status,C) then inc timer1 high byte
    timer1 high= timer1 high + const high

  3. #3
    Member
    Join Date
    Mar 2013
    Location
    Sheboygan, Wisconsin, USA
    Posts
    60
    In Chapter 7, Paragraph 7.6 toward the end, the topic introduces the process of slowing the timer (overflow) down by introducing a constant number of counts into the timer variable to adjust the time between overflows. It bases the value on some calculations which are shown.

    Is this the purpose of the Chapter 9 assembly code that I have identified in my initial post?

  4. #4
    Member
    Join Date
    Mar 2013
    Location
    Sheboygan, Wisconsin, USA
    Posts
    60
    I believe I have determined the calculations that were used to set the tick duration:

    The value 15527 is added to TMR1 meaning that only 50,009 counts are now required for it to overflow to 65,536.

    The tutorial states that the instruction clock is used as the time base. The timer counts up at the rate of .000008 sec per count.

    With 50,000 counts per overflow * .000008 the result is that each tick = .4 sec.

    This is consistent with the way the trainer hardware behaves in that each led lights at this speed.

    Could someone confirm/dispute my conclusions?

  5. #5
    You are correct, or would be if the Trainer Tutorial was correct. The chapter is in error in that it states the system clock is 4MHz, but it is actually 16MHz in the final version of the program file. (Unless I am confused about being confused.)

    The following paragraphs are corrected to show the actual times and frequencies:

    Code:
    Bit 7-6 (Timer1 Clock Source Select bits) are set to 00, which selects the instruction clock as the clock source for
    Timer1. The instruction clock is the Oscillator Frequency divided by 4, noted in the Data Sheet as "Fosc/4". Since our
    Oscillator frequency is 16MHz (discussed above), the instruction clock is 4MHz.
    
    Bit 5-4 (Timer1 Input Clock Prescale Select bits) are set to 11, which selects the "1:8 Prescale value". This means that
    the timer will be incremented once for each 8 instruction clock cycles. Since the instruction clock runs at 4MHz, or four
    million cycles per second, the time for one clock cycle is 250 billionths of a second (250 nanoseconds, written as 250nS). If
    the timer increments on every eighth cycle, that means that the timer will increment once every 2uS. This is important
    for the sake of time calculations below.
    Your analysis is correct, except that the instruction clock is actually 4MHz and the timer counts up at a rate of one count every 2uS. I'm make sure to punish the guy who released the tutorial with that mistake in it.

    That means that an additional LED will light every 100mS.

    The Assembly code adds 15527 to the existing count in Timer1. Using addition, instead of a simple write-literal, is a technique used to compensate for those few instruction cycles that are consumed from the time the timer triggers the interrupt until the code actually stops the timer. I don't remember exactly, but I suspect that I tweaked the 15527 (hex 3CA7) value after testing and measuring with an oscilloscope.

    This is the program code (9-1_Timer1_Interrupt.pbp) I'm using for reference. I hope this is what ended up in the final release. The line 'INCLUDE "14-1_Init.pbp"' brings in the init code which sets the system clock to 16MHz.

    Code:
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ' microEngineering Labs Trainer-1 Example Program
    ' 
    ' Target microcontroller: PIC16F1937
    '
    ' Include configuration and initialization code.  The included file must exist
    ' in the folder where this program is saved.
    INCLUDE "14-1_Init.pbp"     
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    DEFINE INTHAND  ticker  ' Declare the name of the Assembly Language ISR
    
    red     VAR PORTE.0     ' name the red-dome drive pin
    OUTPUT red              ' make the red-dome drive pin an output
    tick1    VAR BYTE BANK0 ' Variable to hold the timer in 
    
    T1CON = %00110001     ' Enable Timer1 with prescale value 1:8
    PIE1 = %00000001      ' Timer1 interrupt enabled  
    INTCON = %11000000    ' global & peripheral interrupts enabled  
    
    GOTO main_loop
    
    ASM
    ticker                ; Begin the Interrupt Service Routine
        clrf    BSR         ; Point to BANK0
        bcf     T1CON, 0    ; Stop Timer1
        movlw   0xA7        ; Load W with 0xA7
        addwf   TMR1L, F    ; Add preset value to TMR1 LSB
        btfsc   STATUS, 2   ; If no byte overflow, skip next instruction
        incf    TMR1H, F    ; If byte overflow, increment MSB of TMR1
        movlw   0x3C        ; Load W with 0x3C
        addwf   TMR1H, F    ; Add preset value to TMR1 MSB
        bsf     T1CON, 0    ; Start Timer1
        bcf     PIR1, TMR1IF    ; clear Timer1 interrupt flag
        incf    _tick1, F    ; increment tick variable
        retfie  ; Return (using automatic context-restore)
    ENDASM
    
    main_loop:
        IF PORTB.0 = 1 THEN     ' If the button is not pressed...
            tick1 = 0           ' Reset the tick variable to zero
            PORTA = 0         ' Turn off the LEDs
        ELSEIF (PORTB.0 = 0) AND (tick1 <= 7) THEN  ' If the button pressed and tick1 is less than 7   
            PORTA.0[tick1] = 1    ' Turn on a single LED, position specified by tick1 variable
        ELSEIF (PORTB.0 = 0) AND (tick1 > 7) THEN   ' If button pressed and tick1 is greater than 7
            DO WHILE tick1 < 50     ' loop here until tick1 reaches 51
                red = 1             ' light the red dome
            LOOP
            red = 0             ' after exiting from the loop, shut off the dome
        ENDIF
    GOTO main_loop      ' Do it forever
    Charles Leo
    ME Labs, Inc.
    http://melabs.com

  6. #6
    Member
    Join Date
    Mar 2013
    Location
    Sheboygan, Wisconsin, USA
    Posts
    60
    Charles,

    Thanks for the explanation. When I initially studied the code I took into account the settings in the 14-1_Init.pbp which was INCLUDEd in the project code. I wondered why the 16MHz clock setting in the 14-1_Init file didn't square with the text explanation in the manual, but when I got to digesting the manual info. I had forgotten about the 16 MHz.

    In any case the 15,527 offset worked out OK when I ported the code over to my 16F72 clocked at 4MHz and I am happy to report that the lighting of the led's during the test was at such a speed that it was quite recognizable in the end.

    This exploration also introduced me to the assembly language technique of adding the "biasing" value to the 16 bit timer variable, a technique which appears to be a crucial method to make a successful interrupt when it is used as a program pacing application.

    My ultimate goal however is to take a "snapshot" of an input port to remember which pin caused the interrupt. That may or may not be something I do on a timed basis.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •