So here I am, frittering away a Sunday afternoon, all because I was lured into Julien Illett’s Youtube Walk down PIC memory lane. The development board which is useful to play along with these dabblings is an EBAY special which comprises nothing more than a PIC12F675 and a few discrete components.
It looks like this…
So having connected it up to a PicKit and reverse engineered the simple circuit see previous post it seemed only right to turn it on and see what happens… After a false start due to not having the jumpers in place the board did indeed show some life by flashing LED1 and LED2 alternately (with POWer lit too).
So… let’s do some reverse engineering PIC12 style….
; Datasheet 22.214.171.124
; Calibrating the Internal Oscillator
; OSCCAL register is 0x10 in Bank 1
bsf STATUS, RP0 ;Bank 1
call OSCINFO ;Get the cal value
movwf OSCCAL ;Calibrate
bcf STATUS, RP0 ;Bank 0
main: CLRF STATUS
; Some kind of delay function?
L7: MOVWF 0x20
L6: CLRF 0x21
L5: MOVF 0x20,W
L4: MOVLW 0xC8
init: MOVLW 0xFF ; All GPIO High (although currently Inputs)
MOVLW 0x07 ; Turn Comparator Mode to OFF
BSF STATUS,RP0 ; Bank 1
CLRF ANSEL ; Use pins as Digital
MOVLW 0x3C ; GPIO0 and GPIO1 Outputs
MOVLW 0xFF ; Weak Pull-ups Enabled
MOVLW 0x3C ; GPIO0 and GPIO1 Outputs. Again???
loop: MOVLW 0xF4 ; 244?
BCF STATUS,RP0 ; Use Bank 0
BCF GPIO,0 ; Clear GPIO0 (ie LED1 ON)
BSF GPIO,1 ; Set GPIO1 (ie LED2 OFF)
BSF GPIO,0 ; Set GPIO0 (ie LED OFF)
BCF GPIO,1 ; Clear GPIO1 (i.e LED ON)
There are some interesting things in here…
Firstly, as the PIC starts at PC=0 it loads the OSCCAL value by doing a call to 0x3ff. The very last instruction is itself the OSCCAL value wrapped up in a RETLW instruction. (i.e. Return Literal). This value needs to be loaded explictly in PIC12F675 unlike for PIC12C5xx series which uses a really dirty trick to start the PC the last memory address, pick up the value and then wrap PC to 0 to start the main program. How cool is that for a hack!
Secondly, there appears to be a delay routine. This appears to be a collection of loops designed to fritter away real-time by going around in circles. Personally I don’t like such loops, it would be much better to use timers and interrupts to defer work and to get on with something more interesting in the meantime but here there isn’t anything else to do so it is a good solution. In practical terms you would probably just use an existing library routine for delays but hand crafted ones are common, in fact there is even an online generator to help produce such things PIC Delay Generator. Here is looks like you put a literal in W and CALL L7 for delay.
Thirdly, the PIC’s registers are set-up to allow I/O to LED1 and LED2 on GPIO0 and GPIO1 respectively. There appears to be a small bug? TRISO set up twice?
Finally, the main loop consists of LED1 ON (by going output low, causing the LED which is already connected to VDD via a resistor to glow) & LED2 OFF, a delay, then LED1 OFF & LED2 ON and a delay and then repeat forever.
The delay argument is 244 which is a funny number, and if the delay routine was 1ms then perhaps that was intended as 244ms!?!
Measurement of the flashing frequency seems to yield a period of around 698ms i.e. 350ms (ish) ON and OFF.
Incidentally the config bits programmed in when it arrived were 0x01B4, i.e. Internal Oscillator with No WDT and GPIO3, GPIO4 and GPIO5 useable for I/O. So that should give a clock frequency of 4MHz.
One instruction cycle consists of four oscillator periods; for an oscillator frequency of 4 MHz, this gives a normal instruction execution time of 1 µs.
It might be interesting to evaluate the instruction timing of that loop…
…maybe next time.
But before I go I converted the disassembly into MPASM for use in MPLABX…
; __config 0x1B4
__CONFIG _FOSC_INTRCIO & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _BOREN_OFF & _CP_OFF & _CPD_OFF
RES_VECT CODE 0x0000 ; processor reset vector
MAIN_PROG CODE 0x3D8 ; let linker place main program
MOVF 0x20, W
SUBWF 0x21, W
BTFSC STATUS, 0x0
INCF 0x21, F
INCF 0x22, F
SUBWF 0x22, W
BTFSC STATUS, 0x0
BCF GPIO, 0x0
BSF GPIO, 0x1
BSF GPIO, 0x0
BCF GPIO, 0x1
This produces identical code except for some extra instructions added by the linked.
These harmless RETLW 0x00 instructions (as described here http://www.microchip.com/forums/m10435.aspx) can be removed by a bit of linker script..
CODEPAGE NAME=.cinit START=0x4000 END=0x4fff PROTECTED
SECTION NAME=.cinit ROM=.cinit // Useless Initialization stuff
and now we have identical HEX to the original. Hooray!