Skip to main content

PIC16F1708 Macros

So Easy, a Caveman can PIC it

The PIC processors have a small and primitive instruction set.  This makes it easy to learn, but doing anything remotely useful usually requires four or more instructions, liberally sprinkled with BANKSEL instructions, which all make the resulting code hard to read and error prone.

Your Own Development Kit



As you can see above, it is very easy to make a little development kit of your own, using Vero board and a DIP size PIC.  Once things are working, then you can use Eagle schematic and PCB designer to make a tiny surface mount board, or you can just spray the Vero model with conformal coating and stick it into a soap box with a blob of RVT...

Your Own High Level Language

The solution is to make your own high level language of sorts with macros.  The upshot of macros is that if you find a bug in one, then you can fix that bug in many places all at once.  The downside is that debugging complex macros can be hard, since the PICKit3 debugger has a very limited ability to step into a macro.  The best method is to write the code and debug it in a little test program, before turning it into a macro.

Goto in Macros

All high level languages have Goto statements.  Even Ada has it.  The PIC assembly language makes heavy use of Gotos in conditional branch instructions.

One of the annoying things with a macro language is that you cannot use a label inside a macro, since the second time you use the macro, the assembler will complain about a double defined label.  This makes it hard to do loops in a macro, but not impossible.  The trick is to use the goto $ operator:

;loop
        MOVIW FSR0++                ; Copy buffers from bottom upwards
        MOVWI FSR1++
        DECFSZ varlength, F
        GOTO $-3                    ; loop till zero


BASIC Macros

Possibly the most useful statements in BASIC were the PEEK and POKE instructions.  A typical embedded program is full of them.  So if you feel nostalgic, then Macros are an ideal way to get your revenge on Kernighan, Ritchie and Stroustrup.

Here are a few useful macros to get you going:

; Peek and Poke
_PEEK MACRO #register
        BANKSEL #register
        MOVF #register, W
        ENDM

_POKE MACRO #register, #literal
        BANKSEL #register
        MOVLW #literal
        MOVWF #register
        ENDM
       
_SAVE MACRO #register
BANKSEL #register
MOVWF #register
ENDM

_COPY MACRO #regfrom, #regto
        BANKSEL #regfrom
        MOVF #regfrom, W
        BANKSEL #regto
        MOVWF #regto
        ENDM

_ZAP MACRO #register
        BANKSEL #register
        CLRF #register
        ENDM
        
_INC MACRO #register
BANKSEL #register
INCF #register, F
ENDM

_DEC MACRO #register
BANKSEL #register
DECF #register, F
ENDM

; Turn one or more port pins on
_PORTON MACRO   #port, #state, #mask1
        BANKSEL #state
        MOVLW #mask1         ; get the mask
        IORWF #state, W      ; Set bit(s): OR with 1 mask
        MOVWF #state         ; save the state
        BANKSEL #port
        MOVWF #port          ; set the port
        ENDM

; Turn one or more port pins off
_PORTOFF MACRO   #port, #state, #mask0
        BANKSEL #state
        MOVLW #mask0         ; get state
        ANDWF #state, W      ; Clear bit(s): AND with 0 mask
        MOVWF #state         ; save state
        BANKSEL #port
        MOVWF #port          ; set the port
        ENDM

; Toggle one or more port pins
_PORTTOGGLE MACRO    #port, #state, #mask1
        BANKSEL #state
        MOVLW #mask1         ; get 1 mask
        XORWF #state, W      ; toggle bit(s): XOR with 1 mask
        MOVWF #state         ; Save state
        BANKSEL #port
        MOVWF #port          ; Set the port
        ENDM


; Parameter Call Stack
_PUSHALL MACRO #param1, #param2, #param3
        _POKE varstack1, #param1
        _POKE varstack2, #param2
        _POKE varstack3, #param3
        ENDM

_PUSH1 MACRO #param1
        _POKE varstack1, #param1
        ENDM

_PUSH2 MACRO #param2
        _POKE varstack2, #param2
        ENDM

_PUSH3 MACRO #param3
        _POKE varstack3, #param3
        ENDM

_POP1 MACRO
        _PEEK varstack1
        ENDM

_POP2 MACRO
        _PEEK varstack2
        ENDM

_POP3 MACRO
        _PEEK varstack3
        ENDM


; Function Call
_CALL   MACRO #name, #param1, #param2, #param3
        _PUSHALL #param1, #param2, #param3
        PAGESEL #name
        call #name
        ENDM

; Conditional Branches
; Branch if not equal
; Note: Negative statements are harder to understand
_BNEWR  MACRO   #register, #destination
        BANKSEL #register
        SUBWF #register, W
        BTFSS STATUS, Z     ; Test and skip if Z flag is set
        GOTO #destination
        ENDM

_BNERR  MACRO   #register1, #register2, #destination
        BANKSEL #register1
        MOVF #register1, W
        SUBWF #register2, W
        BTFSS STATUS, Z     ; Test and skip if Z flag is set
        GOTO #destination
        ENDM

_BNEWL  MACRO   #literal, #destination
        BANKSEL #destination
        SUBLW #literal
        BTFSS STATUS, Z     ; Test and skip if Z flag is set
        GOTO #destination

        ENDM

_BNERL  MACRO   #register, #literal, #destination
        BANKSEL #register
        MOVLW #literal
        SUBWF #register, W
        BTFSS STATUS, Z     ; Test and skip if Z flag is set
        GOTO #destination
        ENDM

; Branch if equal
; Note: Positive statements are easier to understand
_BEQWR  MACRO   #register, #destination
        BANKSEL #register
        SUBWF #register, W
        BTFSC STATUS, Z     ; Test and skip if Z flag is clear
        GOTO #destination
        ENDM

_BEQRR  MACRO   #register1, #register2, #destination
        BANKSEL #register1
        MOVF #register1, W
        SUBWF #register2, W
        BTFSC STATUS, Z     ; Test and skip if Z flag is clear
        GOTO #destination
        ENDM

_BEQWL  MACRO   #literal, #destination
        BANKSEL #destination
        SUBLW #literal
        BTFSC STATUS, Z     ; Test and skip if Z flag is clear
        GOTO #destination
        ENDM

_BEQRL  MACRO   #register, #literal, #destination
        BANKSEL #register
        MOVLW #literal
        SUBWF #register, W
        BTFSC STATUS, Z     ; Test and skip if Z flag is clear
        GOTO #destination
        ENDM

; Branch if Bit equal
_BBEQRL MACRO #register, #literal, #label
        BANKSEL #register       ; select bank 0
        BTFSC #register, #literal     ; test RCIF receive interrupt
        GOTO #label
        ENDM

; Function call parameter 'stack'
; Obviously this only works one call deep!
group1      UDATA 0x0020
varstack1   res 1               
varstack2   res 1
varstack3   res 1

La Voila!

Comments

Popular posts from this blog

Parasitic Quadrifilar Helical Antenna

This article was reprinted in OSCAR News, March 2018:  http://www.amsat-uk.org If you want to receive Satellite Weather Pictures , then you need a decent antenna, otherwise you will receive more noise than picture. For polar orbit satellites, one needs an antenna with a mushroom shaped radiation pattern .  It needs to have strong gain towards the horizon where the satellites are distant, less gain upwards where they are close and as little as possible downwards, which would be wasted and a source of noise.  Most satellites are spin stabilized and therefore the antenna also needs circular polarization, otherwise the received signal will flutter as the antennas rotate through nulls. The helical antenna, first proposed by Kraus in 1948, is the natural solution to circular polarized satellite communications.  It is a simple twisted wire - there seems to be nothing to it.  Various papers have been published on helix antennas, so the operation is pretty well ...

To C or not to C, That is the Question

As most would know, the Kernighan and Ritchie C Programming Language is an improved version of B, which is a simplified version of BCPL, which is derived from ALGOL, which is the Ur computer language that started the whole madness, when Adam needed an operating system for his Abacus, to count Eve's apples in the garden of Eden in Iraq.  The result is that C is my favourite, most hated computer language , which I use for everything. At university, I learned FORTRAN with punch cards on a Sperry-Univac, in order to run SPICE, to simulate an operational amplifier.  Computers rapidly lost their glamour after that era! Nobody taught me C.  I bought the book and figured it out myself. Over time, I wrote a couple of assemblers, a linker-locator, various low level debuggers and schedulers and I even fixed a bug in a C compiler - not because I wanted to, but because I had to, to get the job done!   Much of my software work was down in the weeds with DSP and radio modems...

Unlock CRA PDF Forms

Unlock Canada Revenue Agency PDF Forms It appears that there is a relatively new PDF feature to prevent casual copying and saving of a file and that some programs save PDF files with these foolish features active by default.  Many forms from the Canada Revenue Agency are locked in this way, which makes it difficult to do one's taxes, since one can fill the form, but cannot save it.  One can only print the form.  It should be possible to print to a file or export it to a new PDF file, but it is far better to reset the annoying anti-taxpayer flags, since the 'printed' form cannot be edited easily any more and I always manage to make a mistake or three that need to be corrected after review. If there is a Linux (virtual) machine handy, install qpdf and use it to reset the silly flags: $ su - password # dnf update # dnf install qpdf # exit $ qpdf --decrypt lockedfile.pdf unlockedfile.pdf One doesn't need a password to unlock these flags, so the fix is instant. La voila! He...