Saturday, October 18, 2014

Diabetic Foods and Cooking

A few notes on sugar free cooking.

As my doctor put it, I am not diabetic, but I should eat as if I am.

It appears that the most important dietary modification to diabetes and weight control, is to avoid any food that digests rapidly.

At first the list looks daunting: Wheat, potato, rice, alcohol, glucose, sucrose... essentially all common carbohydrates must be avoided - which makes one wonder what is left, since that is about 90% of all the junk on the supermarket shelves!

Oats and Rye

I don't mind going on a caveman diet of meat, salad and nuts, since I'm a committed carnivore already, but wheat bread is curiously addictive and getting over it is not easy.  There are many different kinds of wheat: Spelt, Durham... so be careful that you don't buy an alternative that isn't an alternative at all.

Rye bread is commonly available at bakeries, but it is a little chewy - an automatic consumption limiter.

My wife is an engineer of economics, loves cooking and did a few experiments with rye, oats and barley kernels.  She quickly figured out that it is very easy to make rye and oats flour: Simply chuck the grains into a coffee grinder and press the button - brrrrrrrrrrrrzzzzzzt - done, perfect flour!

The other surprising thing is that when oats flour is used in baking, it doesn't taste like oatmeal porridge as one would expect.  Baked oats confectionery works and tastes the same as wheat bread and cake - probably because of all the other ingredients.  So between oats and rye, we got wheat eliminated easily and she bakes bread, cake, pancakes, strudel - anything - with oats and rye flour.

Barley

Barley makes a perfect alternative to rice.  It is a little different, but sufficiently the same that we don't miss rice at all.

Sucralose, Aspartame, Xilatol and Stevea

For baking, it is important to use a sweetener that doesn't denature at high temperature.  Sucralose is available in boxes as a fluffed up powder that can be used almost 1:1 (more like 1:2, since it is extremely sweet) to replace sugar.

Be careful with diet sodas.  Many people are sensitive to phenylalanine (produced when Aspartame is broken down) and it increases muscle tension.  Too many diet sodas and you will feel creaky as if you are a 100 years old.  If you overdosed on sodas, bear in mind that phenylalanine takes about 14 days to get out of your system again, so be patient, you will eventually be able to turn your head again.  I can handle one diet soda every other day - no more.  Alcohol free beer is much better and I can chug as many of those as I want with no side effects.

Xilatol is used in 'dental' chewing gum.  It is derived from wood.  The only reason I mention this here, is because Xilatol gum will kill a dog - it makes a dog stop breathing.  Don't leave gum lying around where a puppy can get it, or you could become rather unpopular very quickly.

I don't like the taste of Stevea root much, but I cannot imagine life without chocolate...

Life in the Slow Lane

Once you made the above modifications, you will enjoy life in the slow metabolic lane.  Various nuts and little round cheeses is my way of snacking and when we go out, I drink either nealco Zlatý Bažant (Golden Pheasant) or Bavaria (yum), or Diet Cola (yech).

Swimming

The other important thing is exercise - the more the merrier.  I prefer swimming, since gym machines always hurt my hands and I need my fingers for typing.  So I swim about 3km per week - it sure helps living in a hot country, although it is rather chilly today - only 34 Celsius!

Saturday, August 9, 2014

Reversing the Telephone Table

Are you also fed-up with telemarketer calls?  Chris Blasco wrote a nice piece about social engineering a telemarketer into resetting his own phone set: https://plus.google.com/+ChrisBlasko/posts/GzCuzTyUXNq

Being somewhat incredulous after reading that, I researched it myself.  It turns out that it really is that easy to reset a Yealink phone, but resetting a Polycom may require a password and for a Cisco, you need to enter the configuration menu first, so your mileage may vary.

Here is a handy list:
http://www.3cx.com/blog/ip-phone-configuration/factory-reset-your-phone/

This may become a new sport - at least until the telemarketers wizen up.


Saturday, August 2, 2014

Canoeing in Cinque Terre

A Real Canadian always has a canoe at the ready.  We have inflatable canoes stashed with relatives in multiple countries.  These water toys are cheap, relatively light weight (about 25kg) and easy to transport in the boot of a car.  This summer, we took our European Sea Eagle to Northern Italy.

We rented a tiny little apartment in Manarola, roughly in the middle of this picture, next to the old tower, directly above the harbour.

Nowadays, I mostly use my Samsung phone camera - it has some spherical distortion, but the quality and warmth is very pleasing.



Cinque Terre is a crazy place which really should be on your bucket list.  Many of the buildings are from the 15th century, but the craziest building period was in the 19th and 20th.

Note that the best way to get there is by rail from La Spezia.  The railway runs up the coast in an infinite series of tunnels, so it is mostly invisible and doesn't spoil the park.  We went by car and dragging the canoe and luggage between the car park up on the mountain and the village down below, was really hard work.

Pirates ahoi!


We still heard the party on the pirate boat by 4 in the morning.

The view from the canoe, using my waterproof Olympus uTough camera.  The Olympus produces very sharp, but colder photos, which really need to be hue adjusted a bit, but usually I can't be bothered:


The trains only exit the tunnels at the stations.  With only one person in the Sea Eagle, it is a bit wobbly for photos so I ended up with lots of fuzzy ones, but an inflatable has a nice soft ride over the swells - it just bends a bit - same as an air mattress:


...and if you don't have a canoe and don't like trains, take a ferry:


With an inflatable, you should never leave your pump behind!

You can click the pics for a larger view.

Monday, July 21, 2014

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!

Sunday, July 6, 2014

PIC16F1708 a Dilly

I always wondered what is a dilly, why would you pick it and what could you possibly do with it in a circus, but those English are crazy - it must be something in the water.

The last time I used a Microchip PIC processor - some time before the dinosaurs in the previous century - there were only a handful of different chips.  Nowadays there are over 300.  A problem with this proliferation is that it is now much more difficult to find relevant information on the exact chip that you want to use and getting started with the infernal things can be very time consuming.

I wanted to use a PIC16F1708, which includes an ADC, DAC and even a couple of Op Amps for anti-aliasing filters, an all in one CODEC chip for an audio interface widget.

Here are a few tips on things that I discovered along the way.

No Power

When trying out the evaluation board I got with the PICkit3, I kept getting the error: 
Target device was not found. You must connect to a target device to use PICkit 3. 

The problem is that there is no power supply on the evaluation target board. The PICkit3 needs to supply the power and it is turned off somewhere, despite the power LED on the probe lighting up.

Try this:
    1. Go to Run > Set Project Configuration > Customize...
    2. In "Categories" window click once on PICkit 3.
    3. In the right side you have "Option Categories" drop down box, click on "Power".
    4. Now check the box for "Power target circuit from PICkit 3".
    5. Choose the "voltage level" from the drop down menu. (My PIC18F45K20 devkit is 3V)

And your target should now power up and be happy.

MPASM Configuration Registers

You must set the Configuration bits in the assembler code at the top of the main file. 

First configure the processor type PIC16F1708 in MPLabX then:
Change Configuration bits in MPLabX in the Configuration Bits window (Window>PIC Memory Views>Configuration Bits). 

Then you can export the settings by right clicking in the window and selecting “Generate Source Code to Output” and copy this code from the Output Window into your code.

First I would put a List command:
 LIST   P=PIC16F1708

Then copy and paste the generated code:

; PIC16F1708 Configuration Bit Settings

; ASM source line config statements

 #include "p16f1708.inc"

; CONFIG1
; __config 0xFFE0
 __CONFIG _CONFIG1, _FOSC_LP & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON
; CONFIG2
; __config 0xFFFF
 __CONFIG _CONFIG2, _WRT_OFF & _PPS1WAY_ON & _ZCDDIS_ON & _PLLEN_ON & _STVREN_ON & _BORV_LO & _LPBOR_OFF & _LVP_ON

Read the PIC data sheet for details, since each of these devices is rather different.

An interesting page layout annoyance to note is that only labels, comments and #include may start in the left-most column.  The __CONFIG macro for example, is indented by one character.

PIC18F45K20 MPASM Example

Here is a LED flasher for the PICkit3 with the PIC18F45K20 development board in MPASM.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; LED flasher
; PIC18F45K20
; Herman Oosthuysen, Copyright Reserved, General Public License (GPL) v2, 2014
; Version 1.00, 7 July 2014
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    LIST   P=PIC18F45K20

; PIC18F45K20 Configuration Bit Settings

#include "p18f45k20.inc"

; CONFIG1H
  CONFIG  FOSC = INTIO7         ; Oscillator Selection bits (Internal oscillator block, port function on RA6 and RA7)
  CONFIG  FCMEN = OFF           ; Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
  CONFIG  IESO = OFF            ; Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

; CONFIG2L
  CONFIG  PWRT = OFF            ; Power-up Timer Enable bit (PWRT disabled)
  CONFIG  BOREN = SBORDIS       ; Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
  CONFIG  BORV = 18             ; Brown Out Reset Voltage bits (VBOR set to 1.8 V nominal)

; CONFIG2H
  CONFIG  WDTEN = OFF           ; Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register)
  CONFIG  WDTPS = 32768         ; Watchdog Timer Postscale Select bits (1:32768)

; CONFIG3H
  CONFIG  CCP2MX = PORTC        ; CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
  CONFIG  PBADEN = ON           ; PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
  CONFIG  LPT1OSC = OFF         ; Low-Power Timer1 Oscillator Enable bit (Timer1 configured for higher power operation)
  CONFIG  HFOFST = ON           ; HFINTOSC Fast Start-up (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.)
  CONFIG  MCLRE = ON            ; MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)

; CONFIG4L
  CONFIG  STVREN = ON           ; Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
  CONFIG  LVP = OFF             ; Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
  CONFIG  XINST = OFF           ; Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

; CONFIG5L
  CONFIG  CP0 = OFF             ; Code Protection Block 0 (Block 0 (000800-001FFFh) not code-protected)
  CONFIG  CP1 = OFF             ; Code Protection Block 1 (Block 1 (002000-003FFFh) not code-protected)
  CONFIG  CP2 = OFF             ; Code Protection Block 2 (Block 2 (004000-005FFFh) not code-protected)
  CONFIG  CP3 = OFF             ; Code Protection Block 3 (Block 3 (006000-007FFFh) not code-protected)

; CONFIG5H
  CONFIG  CPB = OFF             ; Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
  CONFIG  CPD = OFF             ; Data EEPROM Code Protection bit (Data EEPROM not code-protected)

; CONFIG6L
  CONFIG  WRT0 = OFF            ; Write Protection Block 0 (Block 0 (000800-001FFFh) not write-protected)
  CONFIG  WRT1 = OFF            ; Write Protection Block 1 (Block 1 (002000-003FFFh) not write-protected)
  CONFIG  WRT2 = OFF            ; Write Protection Block 2 (Block 2 (004000-005FFFh) not write-protected)
  CONFIG  WRT3 = OFF            ; Write Protection Block 3 (Block 3 (006000-007FFFh) not write-protected)

; CONFIG6H
  CONFIG  WRTC = OFF            ; Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
  CONFIG  WRTB = OFF            ; Boot Block Write Protection bit (Boot Block (000000-0007FFh) not write-protected)
  CONFIG  WRTD = OFF            ; Data EEPROM Write Protection bit (Data EEPROM not write-protected)

; CONFIG7L
  CONFIG  EBTR0 = OFF           ; Table Read Protection Block 0 (Block 0 (000800-001FFFh) not protected from table reads executed in other blocks)
  CONFIG  EBTR1 = OFF           ; Table Read Protection Block 1 (Block 1 (002000-003FFFh) not protected from table reads executed in other blocks)
  CONFIG  EBTR2 = OFF           ; Table Read Protection Block 2 (Block 2 (004000-005FFFh) not protected from table reads executed in other blocks)
  CONFIG  EBTR3 = OFF           ; Table Read Protection Block 3 (Block 3 (006000-007FFFh) not protected from table reads executed in other blocks)

; CONFIG7H
  CONFIG  EBTRB = OFF           ; Boot Block Table Read Protection bit (Boot Block (000000-0007FFh) not protected from table reads executed in other blocks)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Macros
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Compare file register to constant and jump to destination
;
; if register >= constant
_BGE    MACRO reg, const, dest
        MOVLW const & 0xff
        SUBWF reg, W
        BTFSC STATUS, CARRY
        GOTO dest
        ENDM

; If register == constant
_BEQ    MACRO reg, const, dest
        MOVLW  const & 0xff
        SUBWF  reg, W
        BTFSC  STATUS, Z
        GOTO   dest
        ENDM

; If register <= constant
_BLT    MACRO reg, const, dest
        MOVLW  const & 0xff
        SUBWF  reg, W
        BTFSS  STATUS, C
        GOTO   dest
        ENDM

; If register != constant
_BNE    MACRO reg, const, dest
        MOVLW  const & 0xff
        SUBWF  reg, W
        BTFSS  STATUS, Z
        GOTO   dest
        ENDM


; Swap the accumulator and a file register
_SWAPWF MACRO  reg
        XORFW  reg,F
        XORFW  reg,W
        XORFW  reg,F
        ENDM

; Decrement the accumulator (a readability macro)
_DECW   MACRO
        ADDLW  0xFF       ; Add W to -1
        ENDM




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Variables
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        UDATA 0x0020

delay1  res 1
delay2  res 1


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Vector Table
; Code space = 4kW (0000 - 0FFF)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

START   CODE 0x0000
start
        GLOBAL start
        PAGESEL main
        GOTO main

ISR     CODE 0x0004
isr
        GLOBAL isr
        ; ISR code goes here
        RETFIE

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Main
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MAIN    CODE            ; Linker to place immediately after ISR
main
        GLOBAL    main

        CLRF PORTD
        CLRF TRISD
        CLRF delay1
        CLRF delay2

mainloop:
        BTG PORTD,RD1   ; Toggle PORT D PIN 1 (20)
delay:
        DECFSZ delay1,1 ; Roughly 1 Hz with internal clock
        GOTO delay
        DECFSZ delay2,1
        GOTO delay
        GOTO mainloop

        END
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

This should be a good starting template for assembler jobs with this processor.

PIC16F1708 MPASM Example

Annoyingly, each PIC has a somewhat different instruction set and whatever works on one processor, may not work at all on another.  So when developing something, you got to keep the data sheet open on one screen - a dual screen computer setup is pretty much required to get anything done with the least amount of pain.  A virtual desktop system as in Linux and Mac helps a lot, but two screens are better.

On a PIC, doing anything remotely useful, requires at least 2 instructions and usually more like 4 and each instruction takes at least 2 cycles.   Therefore a machine running at 20 MHz is not as fast as one would think at first glance, but even with a 1 MHz effective 'do something' rate, it is still fast enough to make my head hurt thinking about it.

We used to build frequency hopping radios with 256 kHz processors - the advantage of a low clock speed is low power consumption, which is critical on battery powered equipment.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; PIC16F1708
; Herman Oosthuysen, Copyright Reserved, 2014
; General Public License (GPL) version 2
; Version 0.01, 5 July 2014
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Power
; The PIC16F1708 uses 4 to 6V
; The PICkit3 can power the target, but 5V may not be available on a laptop PC
; Go to Run > Set Project Configuration > Customize...
; In "Categories" window click once on PICkit 3.
; In the right side you have "Option Categories" drop down box, click on "Power".
; Now check the box for "Power target circuit from PICkit 3".
; Choose the "voltage level" from the drop down menu and set it to 4.5V
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Include Files
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    LIST        P=PIC16F1708
    #include    "p16f1708.inc"

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Configuration
; First configure the processor type then do:
; Window>PIC Memory Views>Configuration Bits
; Edit then click "Generate Source Code to Output"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; CONFIG1
; __config 0x17C4
 __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _BOREN_ON & _CLKOUTEN_ON & _IESO_ON & _FCMEN_OFF
; CONFIG2
; __config 0x37FB
 __CONFIG _CONFIG2, _WRT_OFF & _PPS1WAY_OFF & _ZCDDIS_ON & _PLLEN_ON & _STVREN_ON & _BORV_LO & _LPBOR_ON & _LVP_ON


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Macros
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Initialize Clock
_INITOSC MACRO
        BANKSEL OSCCON
        MOVLW B'11111010'   ; Internal oscillator, 16 MHz
        MOVWF OSCCON
        ENDM

; Initialize PORTB
_INITB  MACRO
        BANKSEL PORTB
        CLRF PORTB
        BANKSEL LATB
        CLRF LATB
        BANKSEL ANSELB
        CLRF ANSELB         ; Analogue functions disable = 0
        BANKSEL TRISB       ; Tristate = 1 = Input
        MOVLW B'01110000'   ; Out: B7, In: B6-4
        MOVWF TRISB
        BANKSEL RB7PPS
        MOVLW B'00000'      ; Peripheral Pin Select
        MOVWF RB7PPS        ; LatchB7 = Out
        ENDM


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Variables
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        UDATA   0x20
stateb  res 1                ; LATB status
delay1  res 1                ; Delay LSB
delay2  res 1                ; Delay MSB
        

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Vector Table
; Code space = 4kW (0000 - 0FFF)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
START   CODE 0x0000             ; Reset Vector
start
        GLOBAL start
        PAGESEL main
        GOTO main

ISR     CODE 0x0004             ; Interrupt Service Routine
isr
        GLOBAL isr
        ; ISR code goes here
        RETFIE

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Main Code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
MAIN    CODE              ; Main program start vector
main
        GLOBAL    main

        _INITOSC                ; Configure the Clocks
        _INITB                  ; Configure PortB

        BANKSEL stateb          ; Zap the latch variable
        CLRF stateb
        CLRF delay1
        CLRF delay2

flashled
        BANKSEL PORTB           ; Toggle PORT B bit 7 (pin 10)
        MOVLW 0x80              ; set bit 7 in W
        XORWF stateb, 1         ; XOR W with port & store result
        MOVFW stateb            ; get the result again
        MOVWF PORTB             ; Output the latch state to the port latch

delay
        DECFSZ delay1,1         ; Roughly 4 Hz with internal 16 MHz clock
        GOTO delay
        DECFSZ delay2,1
        GOTO delay
        GOTO flashled

        END
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



La voila!

Saturday, July 5, 2014

Fletcher Checksum Calculator in Bash

Bash is quite a powerful scripting language and all UNIX machines have it.   The main problem with it is that it was initially designed to work in text mode, making it awkward to process numbers, which tend to be unexpectedly converted back to text strings.

If you need to debug a serial RS232/RS422 avionics device with control messages that end in a checksum or CRC, then it can be hard to generate the checksums.  This example calculates the Fletcher checksum of a hexadecimal message and prints the message out, so that you can copy and paste it into a serial terminal such as cutecom, minicom or screen.

Alternatively, you could print the message directly to the serial device, provided that you initialized it with stty as shown in here: http://www.aeronetworks.ca/2014/01/crcs-and-serial-ports.html

The calculator bc and the printf statement can be used to overcome these limitations.

#! /bin/bash
echo -en "Message = "

# Calculate the Hexadecimal message checksum using bc
MESSAGE="11 22 33 44 55 66"
SUM=0
FLETCHER=0
j=0

for i in $MESSAGE
do
 j=$(echo "ibase=16;$i" | bc)
 printf "%x " "$j"

 SUM=$(echo "$SUM + $j" | bc)
 SUM=$(echo "$SUM%256" | bc)

 FLETCHER=$(echo "$FLETCHER + $SUM" | bc)
 FLETCHER=$(echo "$FLETCHER%256" | bc)
done
printf "%x " "$SUM"
printf "%x\n" "$FLETCHER"


La voila!

Monday, June 30, 2014

Mouse Wiggler

Have you ever watched a movie and got annoyed when the screen saver kicked in?

Some video players interact with the screen savers and will send a dbus command every once in a while to kick the screen saver, but some don't.

The standard fix is to get a child to wiggle the mouse every once in a while.  At least that way they get some exercise!

However, a computer is supposed to automate things, so here is a mouse wiggler script using the xdotool:

# yum install xdotool -y

#! /bin/bash
STATUS=1
while [ "${STATUS:-null}" != null ]; do
  STATUS=`pgrep firefox`
  xdotool mousemove_relative 1 1
  sleep 1
  xdotool mousemove_relative -- -1 -1
  sleep 1
done


It will keep wiggling the mouse pointer a tiny little bit, while Firefox is running.

Modify at your peril...