Learning to program the PIC16LF1823

MaxHeadRoom

Joined Jul 18, 2013
28,688
Ok, this chip has two timers: Timer0 and Timer2 (what happened to Timer1? :confused:).
My theory is that two timers were made available for this chip, and Picmicro appear to try and keep thing standard across different versions as much as possible, and a PWM module is present so the usual PR2/TMR2 was included because of this.
TMR1 lost the cut.
Max.
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
This is the closest approximation for an interrupt period for Timer2 that I could find:

;PR2 = 8D <- Timer2 compare and interrupt trigger value
;T2CKPS = 64D <- prescaling factor, 1:1 to 1:64
;TOUTPS = 15D <- postscaling factor, 1:1 to 1:16

That would result in: 8 * 64 * 15 / (31,000/4) = 0.99097 seconds ... which is perfectly alright, because the service routine itself will eat up more cycles, plus the 1/10 of a second that the LED will flash before completing the routine.... I'll just work with these parameters for now, and refine them later.

Question, I get that the normal syntax for hex numbers is 0x050 (or 50H if I'm not mistaken), for instance. and for binary is b'00000000' ... what would be the most common convention for the different formats? Can I write decimal 12 as 12D, instead of d'12' or .12 ?
 

jpanhalt

Joined Jan 18, 2008
11,087
I used zero for PR2 just to see how it worked in a recent project. It worked and gave a very short period limited by the steps it took to recognize it as zero. It is not like, say, decfsz , which if you start at zero, counts all the way around back to zero.
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
HELP! ... I'm trying to figure out how to complement a bit in a register in the PIC architecture ... but I'm trapped by my 8051 mentality and can't get out! ...

Mainly, I'd like to toggle the RA1 pin on and off
 

jpanhalt

Joined Jan 18, 2008
11,087
Try xor'ing it. That is , 0x01 xor 0x01 = 0, xor w/ 0x01 = 1 ...

Very often used to flash LED's or switch anything alternating with a delay in between.

You will use xorlw or xorwf depending on your code.

Of course xor w/ 0x01 only affects bit zero.

John
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
Try xor'ing it. That is , 0x01 xor 0x01 = 0, xor w/ 0x01 = 1 ...

Very often used to flash LED's or switch anything alternating with a delay in between.

You will use xorlw or worwf depending on your code.

Of course xor w/ 0x01 only affects bit zero.

John
I know what an XOR does ... but would you mind being more specific? I'm suffering from complete mental block right now ...
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
Ok... would this work?

Code:
               movf LATA, 0      ;load the contents of LATA into W
               xorlw b'00000010' ;perform an exclusive or on the contents of W, filtering 
                                 ;bit1 (LATA1)
               movwf LATA        ;load the contents of W into LATA
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
Here's the complete code for my first attempt. It already went through the compiler, reporting no errors.

Code:
;*****************************************************************************************
;                                  11 JUL 2018, 12:39:15 PM: 
;                           Generator controller for the PIC10LF322
;     The following program flashes a LED connected at RA1 for 0.1s once per second using 
;    the Timer interrupt feature. Internal oscillator is set at 31 KHz
;     
;*****************************************************************************************

       list          p=PIC10LF322                ;list directive to define processor
       #include      p10lf322.inc                ;processor specific variable definitions
       radix         dec

       ; - Flash memory self-write protection off     (default state)
       ; - Brown-out reset low trip point is selected (default state)
       ; - Low-power Brown-out Reset is enabled       (default state)
       ; - High Voltage on MCLR pin must be used for programming
       ; - Program memory code protection disabled    (default state)
       ; - MCLR pin set as digital input
       ; - Power-up Timer disabled                    (default state)
       ; - Watchdog timer disabled
       ; - Brown-out reset is enabled                 (default state)
       ; - Internal oscillator is activated
       
       __CONFIG _LVP_OFF & _MCLRE_OFF & _WDTE_OFF & _FOSC_INTOSC


; in this architecture, general purpose registers are located in addresses 40H through 7FH
TEMPVAR EQU 40H                    ;TEMPVAR creates a direct reference to memory location 40H

;*****************************************************************************************
;                       Reset and Interrupt program memory locations
;*****************************************************************************************
RESET_VECTOR: ORG    0x000                       ;processor reset vector
              goto Init                          ;go to beginning of program

INT_VECTOR:   ORG    0x004                       ;interrupt vector location
               ;clear the Timer2 to PR2 match interrupt flag
               bcf PIR1, TMR2IF
               
               ;complement RA1's state, effectively turning on the LED for 1 second
               ;and off for another second
               movlw b'00000010' ;load W with a filter
               xorwf LATA, 1     ;perform an exclusive or on the contents of W, filtering 
                                 ;bit1 (LATA1) ... if LATA1 was zero, it will be set as
                                 ;one, if LATA1 was one, it will be set as zero ... all of
                                 ;the other bits will remain unafected
               
       retfie ;return from interrupt

;*****************************************************************************************
;                                   Main program start
;*****************************************************************************************
Init:

       ;the reference Clock output bit CLKROE is disabled by default, we'll leave it that way
       ;set the internal oscillator frequency to 31 KHz (the lowest possible), this is done
       ;by clearing the IRCF bits, which belong in bit locations 4, 5 and 6, respecively

       movlw b'10001111'  ;the W register has been loaded with the IRCF bits as zeroes
       andwf OSCCON, f    ;AND the W register with OSCCON, storing the result in OSCCON

       clrf   INTCON      ;make sure that all interrupts are disabled for now

;************************************* I/O definitions ***********************************
       CLRF ANSELA       ;clear the analog select register, which for some stupid reason
                         ;is enabled by default ... otherwise the digital i/o function
                         ;won't work
                         
       
       ;BANKSEL PORTA  ;this instruction is not necessary with the 10LF322, since it only
       ;has one bank of SFRs 

       ;set all pin outputs as zeroes (low), to prevent the LED from starting up already
       ;lit before enabling the timer interrupt function
       movlw b'00000000'
       movwf LATA

       ; - set RA1 as an output, active high ... leave RA0 and RA2 as inputs ... RA3 can 
       ;   ONLY be an input
       ;10 JUL 2018, 5:57:17 PM: By the advice of JohnInTx a complete movwf to TRISA should
       ;be used, instead of writing to the individual TRISAX bits
       movlw b'00001101'
       movwf TRISA
       
       ;Interrupt period is given by: PR2 * T2CKPS * TOUTPS / (Fosc/4)
       ;to get a period of one second, the following values make for the best approximation:
       ;Remember that the clock input for the timers is Fosc/4, in this case 31 KHz/4 = 7.75 KHz
       ;PR2    =  8D <- Timer2 compare and interrupt trigger value
       ;T2CKPS = 64D <- prescaling factor, 1:1 to 1:64
       ;TOUTPS = 15D <- postscaling factor, 1:1 to 1:16

       movlw d'8'
       movwf PR2
       
       ;check the structure of T2CON to understand the following instruction
       movlw b'01110011'
       movwf T2CON
       
       ;enable Timer2 to match PR2 interrupt
       bsf PIE1, TMR2IE
       
       ;enable all active peripheral interrupts 
       bsf INTCON, PEIE

       ;enable all active interrupts
       bsf INTCON, GIE
       
       ;turn Timer2 On
       bsf T2CON, TMR2ON

ProgramLoop:
       goto $

 END
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
:eek: IT WORKS!!!! ... and on my very first attempt! :) ...

... that felt kind of weird ... :confused: ... guess I'm too used to banging my head against the wall whenever I try to make something work for the first time ... :(
 

jpanhalt

Joined Jan 18, 2008
11,087
Because the bit being affected is defined by 0x01. You need the destination as there are two possibilities, W and F (see below). I used to use 1 and 0 for my destinations of F and W, respectively, but learned from the excellent examples here not to do that. I still have the bad habit of using lower case f and w, but I am trying to fix that. It is just so easy to avoid the upper case.

upload_2018-7-11_18-9-47.png

Edit: Nothing feels better than getting code that works! Good for you.

John
 

Attachments

JohnInTX

Joined Jun 26, 2012
4,787
Nice!
Now, its time to do the proper context save in the interrupt routine.

Agree with @japhnalt on the destination specifier. Use F or W always, (I like upper case) and never just accept the default destination (F). If you do, you'll get a warning that you'll be tempted to ignore or suppress - then when you make a REAL destination mistake, it will be a lot harder to find e.g. 'Many of these use the default destination of F. One is wrong. Your job-find it' Better to be explicit and let MPASM warn you when you goof.
 

JohnInTX

Joined Jun 26, 2012
4,787
Typical midrange context save code:
Code:
      ; Saves W common area or replicated banked RAM as necessary
      ; Saves status and PCLATH in banked context save RAM
          ; Polls sources and goes to routine
          ; IRQ routines come back to IRQreturn

          movwf   IRQsaveW      ; save W reg, in common area if available
                ; iff not available, replicate IRQsaveW in each bank
                ; for banked systems

          swapf   STATUS,W      ; get status reg without changing flags

          banksel IRQsaveS      ; save it in context bank
          movwf   IRQsaveS

; Saving PCLATH is necessary only when multiple ROM banks are used
      movf      PCLATH,W    ; save upper address as req'd
      movwf   IRQsavePCLATH
; set PCLATH to point to service routines
      pagesel svcTMR2 ; better way to do it


          ;******************************************************
          ; Check flags and exit iff none set, else, do em again
          ;  without running foreground (just burns overhead)

          btfss   PIE1,TMR2IE   ; Timer 2 irq enabled?
          goto    chkNext       ; nope (can omit iff you never turn TMR2 off)

          btfsc   PIR1,TMR2IF   ; Timer 2 needs service?
          goto    svcTMR2       ; Jump instead of call to save stack space

          ;************************
          ; Check other IRQ sources as required
chkNext:

      ;*********************************
          ; Service routines jump back here
IRQreturn:
          banksel IRQsaveS        ; locate saved context

          movf    IRQ_PCLATH,W    ; restore upper address (iff used)
          movwf   PCLATH  ; NO more calls or gotos after this..

          swapf   IRQsaveS,W      ; get saved status
          movwf   STATUS          ; now.. we are in the original banks

          swapf   IRQsaveW,F      ; get saved W without changing flags
          swapf   IRQsaveW,W
         retfie                   ; return and reenable
EDIT: used pagesel directive for PCLATH
 
Last edited:

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
Typical midrange context save code:
Code:
      ; Saves W common area or replicated banked RAM as necessary
      ; Saves status and PCLATH in banked context save RAM
          ; Polls sources and goes to routine
          ; IRQ routines come back to IRQreturn

          movwf   IRQsaveW      ; save W reg, in common area if available
                ; iff not available, replicate IRQsaveW in each bank
                ; for banked systems

          swapf   STATUS,W      ; get status reg without changing flags

          banksel IRQsaveS      ; save it in context bank
          movwf   IRQsaveS

; Saving PCLATH is necessary only when multiple ROM banks are used
      movf      PCLATH,W    ; save upper address as req'd
      movwf   IRQsavePCLATH
; set PCLATH to point to service routines
      pagesel svcTMR2 ; better way to do it


          ;******************************************************
          ; Check flags and exit iff none set, else, do em again
          ;  without running foreground (just burns overhead)

          btfss   PIE1,TMR2IE   ; Timer 2 irq enabled?
          goto    chkNext       ; nope (can omit iff you never turn TMR2 off)

          btfsc   PIR1,TMR2IF   ; Timer 2 needs service?
          goto    svcTMR2       ; Jump instead of call to save stack space

          ;************************
          ; Check other IRQ sources as required
chkNext:

      ;*********************************
          ; Service routines jump back here
IRQreturn:
          banksel IRQsaveS        ; locate saved context

          movf    IRQ_PCLATH,W    ; restore upper address (iff used)
          movwf   PCLATH  ; NO more calls or gotos after this..

          swapf   IRQsaveS,W      ; get saved status
          movwf   STATUS          ; now.. we are in the original banks

          swapf   IRQsaveW,F      ; get saved W without changing flags
          swapf   IRQsaveW,W
         retfie                   ; return and reenable
EDIT: used pagesel directive for PCLATH
I guess I'm too spoiled by the PUSH and POP instructions available in the 8051 ... how is IRQsaveS supposed to be declared?
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,253
Also, the PIC10 architecture has less instructions than other more advanced chips:

For instance, there's no pagesel instruction .... nor banksel

upload_2018-7-11_18-27-36.png
 
Top