Using as many internal peripherals as possible.


+ Reply to Thread
Results 1 to 12 of 12
  1. #1

    Default Using as many internal peripherals as possible.

    Hi,

    I wonder how small the code can it be if I use as many internal peripherals as I could (and I know).
    The task is simple, alternately slowly flash LEDs on ports RA0 and RA1. If the supply
    voltage goes below 3V lit up the LED on port RA2.
    I used PIC12F1840 mcu. Used it's comparator, fixed voltage reference and Timer0.
    The code compiles used 42 words.

    Just for fun, I wonder if it is possible to program it more effectively?

    Code:
    #CONFIG
      __config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON
      __config _CONFIG2, _WRT_OFF & _PLLEN_ON & _STVREN_ON & _BORV_19 & _LVP_OFF
    #ENDCONFIG
    
    DEFINE OSC 4
    OSCCON = %01101010 
    
    
    TRISA   =    %010000   ; RA4 input, rest output
    ANSELA  =    %0000     ; ADC Disable
    OPTION_REG = %10000111 ; Disable internal pull-ups, TMR0 On, prescaller to 256
    
    FVRCON  =    %10011000 ; Internal reference to 2048V
    
    CM1CON0 =    %10100110 ; comparator uotput to C1OUT, switch on LED if voltageis beloe ref 2,048V
    CM1CON1 =    %00100001 ; C1IN1- pin is RA4, comparator voltage input, C1IN1+ positive input to FVR set to 2,048V
    
    LATA    =    %000010   ; init state of pin RA0 and RA1, LEDs connected to these port
    
    n var byte  : n=0      ; init n value to 0
    
    Main:
    
    if INTCON.2 = 1 then n=n+1 : INTCON.2 = 0 ; if TMR0 owerflow increment n by 1, then clear owerflow flag
    
    if n=10 then LATA = LATA ^ %000011 : n=0  ; if n=10 then invert bit 1,0. Pins RA0 and RA1 alternately flash the LEDs
    
    goto Main

  2. #2


    Did you find this post helpful? Yes | No

    Default Re: Using as many internal peripherals as possible.

    Even better, only 33 words.

    Code:
    #CONFIG
      __config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON
      __config _CONFIG2, _WRT_OFF & _PLLEN_ON & _STVREN_ON & _BORV_19 & _LVP_OFF
    #ENDCONFIG
     
    OSCCON =     %00110010 ; Clock 250kHz
    
    TRISA   =    %010000   ; RA4 input for battery measurement, rest output
    ANSELA  =    %0000     ; ADC Disable
    OPTION_REG = %10000111 ; Disable internal pull-ups, TMR0 On, prescaller to 256
    
    FVRCON  =    %10011000 ; Internal reference to 2048mV
    
    CM1CON0 =    %10100110 ; Comparator output to C1OUT, switch on LED if voltage is below ref. 2,048V
    CM1CON1 =    %00100001 ; C1IN1- pin is RA4, comparator voltage input, C1IN1+ positive input to FVR set to 2,048V
    
    LATA    =    %000010   ; init state of pin RA0 and RA1, LEDs connected to these port
    
    Main:
    
    if INTCON.2 = 1 then LATA = LATA ^ %000011 : INTCON.2 = 0 ; if TMR0 owerflow flip LEDs, then clear owerflow flag
    
    goto main
    I think, reached the limit of optimization.
    Last edited by louislouis; - 30th August 2023 at 14:26.

  3. #3
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,521


    Did you find this post helpful? Yes | No

    Default Re: Using as many internal peripherals as possible.

    How about this?
    Code:
    Main:
      n = n + INTCON.2
      INTCON.2 = 0
    
      IF n.3 THEN
          LATA = LATA ^ %000011
          n=0
      ENDIF
    
      goto Main
    It won't produce exactly the same frequency as your example but it's 12% smaller (37 words). I suppose there's also the odd chance/risk of the TMR0 interrupt bit being set in between checking it and clearing it. You COULD also do away with the n=0 at the start with the drawback of the FIRST iteration taking longer depending on the start value of n. AND, possibly, get rid of the GOTO Main and let the PC freerun and start over from the top.

    Adding DEFINE NO_CLRWDT 1 saves one or two words depending on which version.

    Using TMR1, which is 16 bits with its 8:1 prescaler instead of counting overflows should achieve similar results
    Code:
    T1CON = %00110001
    
    Main:
    IF PIR1.0 THEN
        PIR1.0 = 0
        LATA = LATA ^ %000011
    ENDIF
    
    Goto Main
    Combining these I got it down to 34 words but have not checked if it actually works.

    /Henrik.

  4. #4


    Did you find this post helpful? Yes | No

    Default Re: Using as many internal peripherals as possible.

    I tested your codes, both works. The second example with TMR1 I like the most because maintain 4MHz clock. And yes, it compiles only 34 words. Just one more word than mine when I manipulate the clock speed.
    Nice.

  5. #5


    Did you find this post helpful? Yes | No

    Default Re: Using as many internal peripherals as possible.

    In my minimalist mania, I tried using interrupts. On pin RA3 hooked up 10k pullup and pushbutton to ground. On pin RA5 LED. First I tried the On Interrupt statement from PBP not work at all. Then I tried DT Instant interrupts, which worked flawlessly but the code size was a little big.
    Then I came up with this. Is it ok to use interrupts like this?
    I welcome comments so that I can learn from them.
    Code:
    #CONFIG
      __config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON
      __config _CONFIG2, _WRT_OFF & _PLLEN_ON & _STVREN_ON & _BORV_19 & _LVP_OFF
    #ENDCONFIG
    
    DEFINE INTHAND INT
    DEFINE NO_CLRWDT 1
    DEFINE OSC 4
    OSCCON = %01101010
    
    TRISA   =    %011000   ; RA4 input for battery measurement, RA3 input on change, rest output
    ANSELA  =    %0000     ; ADC Disable
    OPTION_REG = %10000111 ; Disable internal pull-ups, TMR0 On, prescaller to 256
    
    FVRCON  =    %10011000 ; Internal reference to 2048mV
    
    CM1CON0 =    %10100110 ; Comparator output to C1OUT, switch on LED if voltage is below ref. 2,048V
    CM1CON1 =    %00100001 ; C1IN1- pin is RA4, comparator voltage input, C1IN1+ positive input to FVR set to 2,048V
    
    LATA    =    %000001   ; init state of pin RA0 and RA1, LEDs connected to these pins
    
    T1CON = %00110001      ; TMR1 On, prescaller 1:8, Fosc/4
    INTCON = %11001000     ; Enable GIE, PEIE, IOCIE
    PIE1.0 = 1             ; Enable TMR1IE Owerflow interrupt 
    IOCAN.3 = 1            ; Enable RA3 negative edge OnChange interrupt 
    
    ; ------------  With TMR1 and interrupt, oscilator 4MHz ---------------
    Main:
    ; pause 10000 ; some stuff here
    goto main             
    
    ; ------------  INT Handler Routine ---------------
    asm
    INT:
    endasm
    IF PIR1.0  THEN LATA = LATA ^ %000011 : PIR1.0 = 0  ; Flash the LEDs on RA0 and RA1 alternately
    if IOCAF.3 then LATA = LATA ^ %100000 : IOCAF.3 = 0 ; Toggle LED on Pin RA5 if button on RA3 is pressed
    @ RETFIE
    It compiles only 58 words, and the main section is empty, ready for some other code.
    Last edited by louislouis; - 31st August 2023 at 21:13.

  6. #6
    Join Date
    May 2013
    Location
    australia
    Posts
    2,389


    Did you find this post helpful? Yes | No

    Default Re: Using as many internal peripherals as possible.

    Is it ok to use interrupts like this?
    no , you may appear to get away with inserting pbp statements in an ASM interrupt but it is a delusion.
    pbp statements set many internal variables to enable complex statements to be evaluated , executing foreign statements from an isr will pollute this process. thats why dt-ints exists.


    use asm code in asm interrupts like this


    Code:
    #CONFIG  __config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON
      __config _CONFIG2, _WRT_OFF & _PLLEN_ON & _STVREN_ON & _BORV_19 & _LVP_OFF
    #ENDCONFIG
    
    
    DEFINE INTHAND myINT
    DEFINE NO_CLRWDT 1
    DEFINE OSC 4
    OSCCON = %01101010
    
    
    TRISA   =    %011000   ; RA4 input for battery measurement, RA3 input on change, rest output
    ANSELA  =    %0000     ; ADC Disable
    OPTION_REG = %10000111 ; Disable internal pull-ups, TMR0 On, prescaller to 256
    
    
    FVRCON  =    %10011000 ; Internal reference to 2048mV
    
    
    CM1CON0 =    %10100110 ; Comparator output to C1OUT, switch on LED if voltage is below ref. 2,048V
    CM1CON1 =    %00100001 ; C1IN1- pin is RA4, comparator voltage input, C1IN1+ positive input to FVR set to 2,048V
    
    
    LATA    =    %000001   ; init state of pin RA0 and RA1, LEDs connected to these pins
    
    
    T1CON = %00110001      ; TMR1 On, prescaller 1:8, Fosc/4
    INTCON = %11001000     ; Enable GIE, PEIE, IOCIE
    PIE1.0 = 1             ; Enable TMR1IE Owerflow interrupt 
    IOCAN.3 = 1            ; Enable RA3 negative edge OnChange interrupt 
    
    
    ; ------------  With TMR1 and interrupt, oscilator 4MHz ---------------
    Main:
    ; pause 10000 ; some stuff here
    goto main             
    
    
    ; ------------  INT Handler Routine ---------------
    asm
    myINT
     movlw 0
     banksel PIR1
     btfsc PIR1,0
     movlw 3
     bcf PIR1,0
     banksel IOCAF
     btfsc IOCAF,3
     iorlw 32
     bcf IOCAF,3
     banksel LATA
     xorwf LATA,f
     RETFIE
    endasm
    Warning I'm not a teacher

  7. #7


    Did you find this post helpful? Yes | No

    Default Re: Using as many internal peripherals as possible.

    Thanks Richard for the answer. I understand. In more complex cases, this could cause problems.
    In my case, it works, but it is not correct to combine it like this.
    So in PBP use only On Interrupt statement or DT Interrupts. Or only ASM interrupts.
    Alternatively, a system variable can be set up, e.g.:
    Code:
    Test VAR BIT SYSTEM
    and use it from PBP and ASM?

    If I want to set the Test in PBP
    Code:
    Test = 1
    or 
    @ bsf Test
    If I want to set the Test in ASM
    Code:
    bsf Test
    and use the variable from both PBP and ASM. Or it's not possible that way either.
    Last edited by louislouis; - 1st September 2023 at 11:43.

  8. #8
    Join Date
    May 2013
    Location
    australia
    Posts
    2,389


    Did you find this post helpful? Yes | No

    Default Re: Using as many internal peripherals as possible.

    Test VAR BIT SYSTEM

    Will create a var in this case called PB01
    and then define test as bit 0 in that var
    #define Test PB01, 000h


    @ bsf Test

    translates to

    @ BSF PB01 , 0 ;set test to a logic 1



    bit vars and declaring them to be system located in no way makes their use asm interrupt safe if used with pbp statements in said isr
    its the pbp statements not the vars where the issue lies
    Warning I'm not a teacher

  9. #9


    Did you find this post helpful? Yes | No

    Default Re: Using as many internal peripherals as possible.

    What I trying. Omit PBP code from ASM interrupt routine.
    But this try not work, of course.
    Where is the problem?
    Code:
    #CONFIG
      __config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON
      __config _CONFIG2, _WRT_OFF & _PLLEN_ON & _STVREN_ON & _BORV_19 & _LVP_OFF
    #ENDCONFIG
    
    DEFINE INTHAND INT
    DEFINE NO_CLRWDT 1
    DEFINE OSC 4
    OSCCON = %01101010
    
    TRISA   =    %011000   ; RA4 input for battery measurement, RA3 input on change, rest output
    ANSELA  =    %0000     ; ADC Disable
    OPTION_REG = %10000111 ; Disable internal pull-ups, TMR0 On, prescaller to 256
    
    FVRCON  =    %10011000 ; Internal reference to 2048mV
    
    CM1CON0 =    %10100110 ; Comparator output to C1OUT, switch on LED if voltage is below ref. 2,048V
    CM1CON1 =    %00100001 ; C1IN1- pin is RA4, comparator voltage input, C1IN1+ positive input to FVR set to 2,048V
    
    LATA    =    %000001   ; init state of pin RA0 and RA1, LEDs connected to these pins
    
    T1CON = %00110001      ; TMR1 On, prescaller 1:8, Fosc/4
    INTCON = %11001000     ; Enable GIE, PEIE, IOCIE
    PIE1.0 = 1             ; Enable TMR1IE Owerflow interrupt 
    IOCAN.3 = 1            ; Enable RA3 negative edge OnChange interrupt
    
    Switch var bit SYSTEM : switch = 0 
    
    
    ; ------------  With TMR1 and interrupt, oscilator 4MHz ---------------
    Main:
    if porta.3=0 and switch=1 then
    LATA = LATA ^ %100000
    pressed:
    pause 20
    if porta.3=0 then pressed   ; if the button is still pressed loop and wait for release
    Switch=0
    endif
    goto main 
    
     asm
    INT
     banksel IOCAF
     btfsc IOCAF,3
     bsf Switch                       ; set bit in Switch to 1
     bcf IOCAF,3
     RETFIE
    endasm
    Last edited by louislouis; - 1st September 2023 at 13:42.

  10. #10
    Join Date
    Aug 2011
    Posts
    412


    Did you find this post helpful? Yes | No

    Default Re: Using as many internal peripherals as possible.

    Code:
    bsf Switch                       ; set bit in Switch to 1
    Among other things...
    - that's not the form of an asm 'bsf' instruction
    - you may have issues with the proper bank being selected... you are specifying 'banksel IOCAF', but where is 'Switch' located?

    When writing asm it will do exactly what you specify... correct or not.

  11. #11
    Join Date
    May 2013
    Location
    australia
    Posts
    2,389


    Did you find this post helpful? Yes | No

    Default Re: Using as many internal peripherals as possible.

    Where is the problem?

    Good luck trying to get pbp to set a bit var where you need it be
    use a byte and place it in access space if you have to

    enabling the timer1 interrupt and not servicing it will not work well


    Code:
    #CONFIG  __config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON
      __config _CONFIG2, _WRT_OFF & _PLLEN_ON & _STVREN_ON & _BORV_19 & _LVP_OFF
    #ENDCONFIG
    
    
    DEFINE INTHAND INT
    DEFINE NO_CLRWDT 1
    DEFINE OSC 4
    OSCCON = %01101010
    
    
    TRISA   =    %011000   ; RA4 input for battery measurement, RA3 input on change, rest output
    ANSELA  =    0     ; ADC Disable
    OPTION_REG = %10000111 ; Disable internal pull-ups, TMR0 On, prescaller to 256
    
    
    FVRCON  =    %10011000 ; Internal reference to 2048mV
    
    
    CM1CON0 =    %10100110 ; Comparator output to C1OUT, switch on LED if voltage is below ref. 2,048V
    CM1CON1 =    %00100001 ; C1IN1- pin is RA4, comparator voltage input, C1IN1+ positive input to FVR set to 2,048V
    
    
    LATA    =    %000001   ; init state of pin RA0 and RA1, LEDs connected to these pins
    
    
    T1CON = %00110001      ; TMR1 On, prescaller 1:8, Fosc/4
    INTCON = %11001000     ; Enable GIE, PEIE, IOCIE
    PIE1.0 = 0             ; DISable TMR1IE OVerflow interrupt 
    IOCAN.3 = 1            ; Enable RA3 negative edge OnChange interrupt
    
    
    Switch var BYTE  $7f  SYSTEM 
     Switch = 0 
    
    
    
    
    ; ------------  With TMR1 and interrupt, oscilator 4MHz ---------------
    Main:
    if porta.3=0  and switch=1 then         
    LATA = LATA ^ %100000
    pressed:
    pause 20
    if porta.3=0 then pressed   ; if the button is still pressed loop and wait for release
    Switch=0
    endif
    goto main 
    
    
     asm
    INT
     banksel IOCAF
     btfsc IOCAF,3
     bsf Switch,0                      ; set bit0 in Switch to 1
     bcf IOCAF,3
     RETFIE
    endasm
    Warning I'm not a teacher

  12. #12


    Did you find this post helpful? Yes | No

    Default Re: Using as many internal peripherals as possible.

    Thank you, Richard, for the explanation.
    Now I have a clearer understanding of how to work with variables and share them in ASM and PBP.

    Active TMR1, yes. I just forgot to comment on this line.

    Whenever I have the time, I try to learn something new about programming in PBP.
    Right now, I'm experimenting with interrupts.
    Advice like this is helpful in my efforts.

    Louis
    Last edited by louislouis; - 2nd September 2023 at 12:31.

Similar Threads

  1. New cool PIC peripherals
    By HenrikOlsson in forum General
    Replies: 1
    Last Post: - 21st September 2016, 20:50
  2. Replies: 8
    Last Post: - 21st March 2015, 17:21
  3. Replies: 4
    Last Post: - 11th June 2014, 22:53
  4. Replies: 0
    Last Post: - 7th August 2008, 09:02
  5. Internal Oscillator
    By jhorsburgh in forum General
    Replies: 2
    Last Post: - 10th December 2007, 02:13

Members who have read this thread : 15

You do not have permission to view the list of names.

Posting Permissions

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