PDA

View Full Version : Using as many internal peripherals as possible.



louislouis
- 29th August 2023, 17:58
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?



#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

louislouis
- 30th August 2023, 14:22
Even better, only 33 words.



#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.

HenrikOlsson
- 30th August 2023, 14:25
How about this?


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


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.

louislouis
- 30th August 2023, 14:49
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.

louislouis
- 31st August 2023, 20:48
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.


#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.

richard
- 31st August 2023, 23:54
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




#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

louislouis
- 1st September 2023, 11:40
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.:


Test VAR BIT SYSTEM

and use it from PBP and ASM?

If I want to set the Test in PBP


Test = 1
or
@ bsf Test

If I want to set the Test in ASM


bsf Test


and use the variable from both PBP and ASM. Or it's not possible that way either.

richard
- 1st September 2023, 12:30
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

louislouis
- 1st September 2023, 13:17
What I trying. Omit PBP code from ASM interrupt routine.
But this try not work, of course.
Where is the problem?


#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

tumbleweed
- 1st September 2023, 15:19
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.

richard
- 2nd September 2023, 00:35
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



#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

louislouis
- 2nd September 2023, 12:27
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