$regfile = "m8def.dat"
$crystal = 4000000

'20060822 v00 skeleton test lcd and i2c led flash
'20060823 v01 fi1216 test single frequency, found out that floating point does not fit in at90s2313
'20060825 v02 all integer frequency calculations
'20060827 v03 test buttons on pcf8574
'20060828 v04 test eeprom usage for setup
'20060901 v05 program does not fit anymore in at90s2313, bummer!, changed to atmega8,
'xx           note that lcd pinning changed from the default!
'20060903 v06 changed lcd layout

Config Sda = Portc.5
Config Scl = Portc.4
Config I2cdelay = 10
Config Pind.2 = Input
Config Pind.6 = Output
Config Int0 = Falling
Config Lcd = 16 * 2
Config Lcdpin = Pin , Db4 = Portb.0 , Db5 = Portb.1 , Db6 = Portb.2 , Db7 = Portb.3 , E = Portb.4 , Rs = Portb.5

'I2C addresses
'pcf8574 with A2, A1, A0 tied to gnd
Const Pcf8574write = &H40
Const Pcf8574read = &H41
'fi1216 with MA1 and MA0 tied to gnd
Const Fi1216write = &HC0
Const Fi1216read = &HC1

'FI1216 vco frequency info
'A fixed step size of 50kHz is used
'Note: all frequencies are expressed in integers as a multiple
'of 50kHz
'example: 240.15MHz is expressed as (240.15)/0.05=4803
'example: 240.2 MHz is expressed as (240.2 )/0.05=4804
'The resulting number can directly be used as divisor,
'avoiding the need for floating-point calculations


'FI1216 vco band limits
'low limit of low band VCO : 48.25 MHz + 38.9 MHz IF
Const Lowband = 1743
'low limit of mid band VCO : 170 Mhz + 38.9 MHz IF
Const Midband = 4178
'low limit of high band VCO : 450 MHz + 38.9 MHz IF
Const Hilband = 9778
'high limit of high band VCO : 855.25 MHz + 38.9 IF
Const Hihband = 17883
'bit 7 plus bit 5= 128+32
Const Loband = &B10100000
'bit 7 plus bit 4= 128+16
Const Miband = &B10010000
'bit 5 plus bit 4= 32+16
Const Hiband = &B00110000

'Frequency up button is on bit0 of pcf8574
Const Frequp = &B11111110
'Frequency down button is on bit1 of pcf8574
Const Freqdn = &B11111101
'Step up button is on bit2 of pcf8574
Const Stepup = &B11111011
'Step down button is on bit3 of pcf8574
Const Stepdn = &B11110111
'Memory button is on bit4 of pcf8574
Const Mem = &B11101111
'Memory store button is on bit5 of pcf8574
Const Memstr = &B11011111
'Memory recall button is on bit6 of pcf8574
Const Memrcl = &B10111111
'number of vco frequency memories
Const Freqmemmax = 3
'number of tries to read locked pll
'this number is rather high, but necessary at a band change
Const Locktries = 250
'Maximum index of Fsteps data table
Const Fstepsnum = 7
'Default Fsteps data table index
Const Fstepsdefault = 0
'Fixed fi1216 frequency step value in kHz
Const Fstepreal = 50

Dim Tmp As Word
'pcf8574 input port value read
Dim Pcf8574port As Byte
'vco frequency
Dim Vcofreq As Word
Dim Tmpvcofreq As Long
Dim Tmpvco As Long
Dim Vcofreqstring As String * 8
Dim Tmpvcofreqstring As String * 8
'fi1216 divisor control bytes
Dim Divbyte1 As Byte
Dim Divbyte2 As Byte
'fi1216 control byte
Dim Controlbyte As Byte
'fi1216 band byte
Dim Bandbyte As Byte
'fi1216 status byte (has a.o. lock bit
Dim Statusbyte As Byte
'16-bit divisor bits
Dim Divisor As Long
Dim Tmpdivisor As Word
'counts number of pll lock tries
Dim Lockcnt As Byte
'fi1216 lock bit
Dim Lockbit As Byte
'actual frequency step value
Dim Freqstep As Word
'frequency step as displayed on lcd
Dim Freqstepdisp As String * 6
'points to the frequency step string to be used from data block
Dim Freqstepindex As Byte
'frequency step in kHz
Dim Freqstepreal As Long
'1 if there is work to do in main loop
Dim Doflag As Byte
'last memory place used
Dim Lastmemnum As Byte
'flag to display mem frequency
Dim Memdispflag As Byte

'do not use first eeprom byte, could be trashed during a reset
Dim Eedummy As Eram Byte
'last frequency saved
Dim Eelastmemnum As Eram Byte
'three frequency memories
Dim Eefrequencies(Freqmemmax) As Eram Word

'sub to handle buttons
Declare Sub Updfreqvalue
' sub to do the fi1216 programming
Declare Sub Progfi1216

'Make all Pcf8574 pins high -> input
I2cstart
I2cwbyte Pcf8574write
I2cwbyte 255
I2cstop
'pull up the int0 line
Set Portd.2
'clear lcd, cursor off
Cls
Cursor Off

'If any of the buttons is pressed at power-up, restore memory defaults
I2cstart
I2cwbyte Pcf8574read
I2crbyte Pcf8574port , Nack
I2cstop
If Pcf8574port <> 255 Then
  'Write Default Data To Eeprom
  Eelastmemnum = 1
  Eefrequencies(1) = 4000
  Eefrequencies(2) = 5000
  Eefrequencies(3) = 6000
  Lcd "mem restored"
  Wait 2
End If

On Int0 Pcfint

Enable Interrupts
'int0 is used to catch pcf8474 change of input (i.e. button pressed)
Enable Int0

Cls

Lastmemnum = Eelastmemnum
Vcofreq = Eefrequencies(lastmemnum)

Freqstepindex = Fstepsdefault
Freqstep = Lookup(freqstepindex , Fsteps)
Freqstepdisp = Lookupstr(freqstepindex , Fstepsdisp)
Freqstepreal = Freqstep * Fstepreal

Doflag = 1
Memdispflag = 0

'main loop starts here
Do
  If Doflag = 1 Then
    Doflag = 0
    Call Updfreqvalue
    'program fi1216
    Call Progfi1216
  End If
Loop

'#############################interrupt routines follow#########################
'PCF8574 interrupt routine
Pcfint:

  'debounce wait time
  Waitms 20
  'read the input pins
  I2cstart
  I2cwbyte Pcf8574read
  I2crbyte Pcf8574port , Nack
  I2cstop
   'Determine state of port bits
  If Pcf8574port <> 255 Then
    Doflag = 1
  End If
  Gifr = 64
Return

End

'#############################subroutines follow################################

Sub Updfreqvalue
  'Frequency up button
  If Pcf8574port = Frequp Then
    Tmpvcofreq = Vcofreq + Freqstep
    If Tmpvcofreq <= Hihband Then
      Vcofreq = Tmpvcofreq
    End If
  End If
  'Frequency down button
  If Pcf8574port = Freqdn Then
    Tmpvcofreq = Vcofreq - Freqstep
    If Tmpvcofreq >= Lowband Then
      Vcofreq = Tmpvcofreq
    End If
  End If
  'Frequency step up button
  If Pcf8574port = Stepup Then
    If Freqstepindex < Fstepsnum Then
      Freqstepindex = Freqstepindex + 1
      Freqstep = Lookup(freqstepindex , Fsteps)
      Freqstepdisp = Lookupstr(freqstepindex , Fstepsdisp)
    End If
  End If
  'Frequency step down button
  If Pcf8574port = Stepdn Then
    If Freqstepindex > 0 Then
      Freqstepindex = Freqstepindex - 1
      Freqstep = Lookup(freqstepindex , Fsteps)
      Freqstepdisp = Lookupstr(freqstepindex , Fstepsdisp)
    End If
  End If
  'Memory button
  If Pcf8574port = Mem Then
    If Lastmemnum = Freqmemmax Then
      Lastmemnum = 1
    Else
      Lastmemnum = Lastmemnum + 1
    End If
    Set Memdispflag
  End If
  'Store button
  If Pcf8574port = Memstr Then
    Eelastmemnum = Lastmemnum
    Eefrequencies(lastmemnum) = Vcofreq
    Cls
    Locate 1 , 1
    Lcd "Stored"
    Wait 1
  End If
  'Recall button
  If Pcf8574port = Memrcl Then
    Eelastmemnum = Lastmemnum
    Vcofreq = Eefrequencies(lastmemnum)
    Cls
    Locate 1 , 1
    Lcd "Recalled"
    Wait 1
  End If
End Sub

Sub Progfi1216
  'determine divisor bytes
  Divisor = Vcofreq
  Tmpdivisor = Divisor And &B0111111100000000               'take bits 14,13,12,11,10,9,8
  Shift Tmpdivisor , Right , 8
  Divbyte1 = Tmpdivisor                                     'and shift to the right eight places
  Tmpdivisor = Divisor And &B0000000011111111               'take bits 7,6,5,4,3,2,1,0
  Divbyte2 = Tmpdivisor                                     'and shift to the left eight places
  'determine control byte
  Controlbyte = &B10001100
  '               ||||||||
  '               |||||||OS=0 is normal operation (1 switches charge pump to high impedance state)
  '               |||||||
  '               |||||RSA & RSB: x0 = 50kHz step; 01 = 31.25kHz step (search mode); 11 = 61.25kHz step (normal search)
  '               |||||
  '               ||T2, T1, T0 is 001 for normal operation
  '               ||
  '               |CP is 1 for fast tuning, 0 for moderate speed tuning with better residual osc FM
  '               |
  '               is always 1

  'controlbyte=&B10001010 'same, except 31.25kHz step
  'determine band control byte
  If Vcofreq < Midband Then
      Bandbyte = Loband
  Else
    If Vcofreq < Hilband Then
      Bandbyte = Miband
    Else
      Bandbyte = Hiband
    End If
  End If

  'write the five control bytes to the fi1216
  I2cstart
  I2cwbyte Fi1216write
  I2cwbyte Divbyte1
  I2cwbyte Divbyte2
  I2cwbyte Controlbyte
  I2cwbyte Bandbyte
  I2cstop
  'wait some time
  Waitms 10
  ''wait for pll lock
  For Lockcnt = 1 To Locktries
    I2cstart
    I2cwbyte Fi1216read
    I2crbyte Statusbyte , Nack
    I2cstop
    Lockbit = Statusbyte And &B01000000
    If Lockbit = &B01000000 Then
      Locate 1 , 16
      Lcd "L"
      Goto Plllocked
    End If
  Next Lockcnt
  Locate 1 , 16
  Lcd "N"
  Wait 5
Plllocked:
'  If Memdispflag <> 0 Then
'    Memdispflag = 0
'    Tmp = Eefrequencies(lastmemnum)
'    Tmpvco = Tmp * Freqstepreal
'    Tmpvcofreqstring = Str(tmpvco)
'    Vcofreqstring = Format(tmpvcofreqstring , "000.000")
'    Locate 1 , 1
'    Lcd Vcofreqstring ; " MHz"
'    Locate 1 , 15
'    Lcd "M" ; Lastmemnum
'    Wait 1
'  End If
  Locate 1 , 1
  Tmpvco = Vcofreq * Freqstepreal
  Tmpvcofreqstring = Str(tmpvco)
  Vcofreqstring = Format(tmpvcofreqstring , "000.000")
  Locate 1 , 1
  Lcd Vcofreqstring ; " " ; Freqstepdisp
  Tmp = Eefrequencies(lastmemnum)
  Tmpvco = Tmp * Freqstepreal
  Tmpvcofreqstring = Str(tmpvco)
  Vcofreqstring = Format(tmpvcofreqstring , "000.000")
  Locate 2 , 1
  Lcd Vcofreqstring
  Locate 2 , 15
  Lcd "M" ; Lastmemnum

End Sub

End

'Note: when Fsteps, Fstepsdisp changes, Fstepsnum constant must be updated accordingly!
'Frequency step values available
Fsteps:
Data 1% , 2% , 4% , 10% , 20% , 40% , 100% , 200%

'Frequency step value in display
Fstepsdisp:
Data " 0.050" , " 0.100" , " 0.200" , " 0.500" , " 1.000" , " 2.000" , " 5.000" , "10.000"