; ARDFLP.ASM ; Current Version: 1.90 ; ; PIC Based controller for an ARDF transmitter ; THIS IS THE LOW-POWER VERSION USING A 16F684 which ; uses an 32kHz xtal for the required timing ; ; Created by Wim de Vree PE1GRL - pe1grl@amsat.org ; ; Brief overview: ; This program controls an ARDF transmitter and ; also generates the required audio signals. See ; the related WEB page for more details about this program. ; http://pe1grl.khds.nl/ardftimer/ardfctrl.htm ; ; Supported image resolutions: ;---------------------------------------------------------------------- ; 2006-12-30 0.00 Initial creation, adding I2C memory interface ; and serial handlers ; 2007-01-01 Big rewrite to tune I2C code (standard code ; was not fast enough, added sequential reading) ; 2007-01-02 Initial PWM code added, PWM carrier at 40 kHz ; PWM modulation at 10 kHz. ; 2007-01-04 Added configuration code (save/store controller ; settings in EE. ; Added limited length of WAV files (do not loop ; complete I2C memory ; 2007-01-05 Main Clock Timing added (based on TMR1) ; 2007-01-06 Added multiple sound options: ; WAV file / Single Tone / Morse_keyed / Sound Effect ; Completed "Cycle" code ; 2007-01-08 Startup code (with SYNC switch) added ; 2007-01-09 0.30 Rewritten for a software UART to facilitate porting ; to other micros (like the smaller 16F684) ; Included initial CW generation code ; 2007-01-10 Added MO and MOx code modes ; 2007-01-11 0.40 Added "Shutdown" Options after a specified time ; 2007-01-14 0.50 Low-Power version for 16F684 with internal clock ; and external 32 kHz crystal. Initial testing done ; Uses PWM 32 kHz carrier and 8 kHz modulation ; 2007-01-17 0.70 Major revisions, now timing is related to the 32kHz ; oscillator, INTOSC Calibrate command added. ; 2007-01-22 0.80 Merging with 16F628 Sources: ; - Memory Detection ; - DDS Tone generation ; - Startup and Error diagnostic LED sequences ; 2007-01-27 0.90 CW mode now supports keyed (CW) and cont. PTT (FM) ; Various bugfixed with PWM module and AutoShutdown ; Prepared for Tone sequences ; 2007-02-01 Added Playback of Tone sequence ; 2007-02-02 1.00 Completed sequence playback ; Using TMR0 for DelayNms routine (DDS and WAV ints. ; make a software loop very unaccurate) ; 2007-02-03 Small bug fixes: ; - Wrong errorcode on failing XTAL osc. ; - Bug in MOx sending sequence ; CW speed is now user configurable ; 2007-02-04 Rewrote CW part, user defined messages are now possible ; CW autoflag added to distinguish between the modes ; 2007-02-05 1.10 Added '@' command to reset the PIC, removed auto-reset ; after writing the EE ; Tone sequence length specified in 10millisecond increments ; Transmitter delay (time from switching power to transmit ; increased from 10 to 100 milliseconds ; 2007-02-06 1.20 When sending an MOx message, end with a word space ; When "CONTINIOUS mode" and "no startup delay" AND ; "SW_SYNC low during startup" ignore the sync switch ; and directly go transmitting ; 2007-03-19 Rewritten for different method of sending MOx sequences ; Now merged with normal CW messages. Allows a stop after ; each character. The message is built in RAM before the ; transmission start depending on the AUTO_ID setting. ; 2007-03-20 1.30 Working oscillator calibration function added ; Version ID kicked to 1.3 ; 2007-03-22 DDS output level can be set to 100% and 50% ; 2007-04-17 1.40 Rewrite to 24bit adressing (support memory > 512kBit) ; Added proper Memory Detection both Atmel & Microchip ; for now only 512K / 1024K types ; 2007-04-19 Code added to do a software reset for I2C chips ; Banking code added for 1024K chips ; 2007-04-22 Completed 17bit playback (1024K chips) ; Started with Effect (siren) ; 2007-04-23 1.50 Completed version with I2C_Reset / Big Wavs / Siren ; 2007-04-27 Detectie voor Atmel 512kBit (op I2C address 0) ; 2007-04-28 1.70 Sequenced transmit added (On-Off sequence specified) ; 2007-04-29 1.80 In sequenced transmit each step had its own modulation ; type (audio/CW/Tone/Effect etc..) ; 2007-05-03 Started with implementation of NOKIA ringtone playback ; 2007-05-04 1.90 Moved some option bits around to make room for ringtone ; option. (AUTO_CW and KEYED_CW to 2nd option word, ; SEQUENCED_TX to 1st option word) ; Also direct transmission can be started if SEQUENCED_TX ; is selected and the SYNC connector is grounded at startup. ; 2007-05-06 Completed RingTone playback ; 2007-05-07 Recovery beacon added an other cleanups ; 2007-05-08 2.0 Jutberg beta-version ; 2007-05-09 Bug fix in CW sending ; "Staccato" Option added for ringtone playback LIST P=16F684 include __config _CP_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _PWRTE_ON & _FCMEN_OFF & _IESO_OFF ;***************************************************************************** ; Equates, I/O, vars ;***************************************************************************** RESET_V EQU 0x0000 ; Address of RESET Vector ISR_V EQU 0x0004 ; Address of Interrupt Vector CLOCKFREQ EQU .80000 ; 8 MHz internal oscillator ; I2C SPECIFICATION #define SDA TRISA, 0 #define SCL TRISA, 1 #define I2CMASK b'00000011' #define I2CPORT PORTA #define error24XX SystemFlags,7 ; Error in EE write ; TIMING SPECIFICATION #define E_10Seconds Events,0 ; Raise this flag every 10 seconds #define E_Minute Events,1 ; Raise this flag on a 1 minute event #define CYCLED_TX Options,0 ; Cycled or Continious Transmission #define SEQUENCED_TX Options,1 ; 0= normal cycling, 1= sequenced #define RINGMODE Options,2 ; Audio Mode "Ringtones" #define TSEQMODE Options,3 ; Audio Mode "Tone Sequence" #define TONEMODE Options,4 ; Audio Mode "Tone" #define WAVEMODE Options,5 ; Audio Mode "Wave File" #define CWMODE Options,6 ; Audio Mode "Morse code" #define EFFECTMODE Options,7 ; Audio Mode "Sound Effects" #define DDS_HALVE Options2,0 ; DDS output halved (matches WAV better) #define KEYED_CW Options2,1 ; PTT switched with key #define AUTO_CW Options2,2 ; Sending of MOx messages / fixed text #define RT_STACCATO Options2,3 ; Internote spacing in Ringtone Playback #define RECOVERYBEACON Options2,4 ; Recovery beacon enable #define TXisACTIVE SystemFlags,0 ; The transmitter is active #define PWMisON SystemFlags,1 ; The PWM audio system is on #define SHUTDOWNACTIVE SystemFlags,2 ; If set enable the shutdown counter #define DDSisON SystemFlags,3 ; The PWM DDS system is on #define swSYNC PORTA,2 ; Switch for SYNC #define pinLED PORTC,0 ; Status LED #define pinTMRT PORTC,1 ; Power to transmitter #define pinTX PORTC,2 ; Serial I/O out #define pinKEY PORTC,3 ; PTT down on transmitter #define pinRX PORTC,4 ; Serial I/O in #define pinPWM PORTC,5 ; PWM audio signal #define SerialReceive SerialIn #define SerialSend SerialOut ;***************************************************************************** ; Variable definitions ;***************************************************************************** CBLOCK 0x20 Options ; Various option bits Options2 ; More options StartupDelay ; Initial transmitting delay in minutes CycleDelay ; CycleDelay in minutes CycleID ; CycleID of transmitter CycleCount ; Nr. of transmitters in cycle ToneIncLo,ToneIncHi ; DDS Phase inc. for single tone ShutdownDelay ; Delay after which to stop transmission OscillatorTune ; Internal oscillator tuning (for 16F684) DitDelay ; Delay for a "dit" in CW (in millisecs) RecoveryDelay ; Recovery Beacon delay in minutes Reserved ; Future Options WaveSizeLo ; Length of Wave File in I2C WaveSizeMi WaveSizeHi SCRATCH: 4 ; 8 scratch values CycleIndex ; Current index in cycle CycleDelayCnt ; SystemFlags ; Flag word to tag errors TEMP Events Ticks,Secs10,Minutes ; Main Clock Timing Counter WaveCntLo ; Counter in Wave Playback WaveCntMi WaveCntHi CSum PWMValue:2 ; Next value for PWM generator I2CMemType ; External Memory Size & Type (0K/32K/64K/128K) I2CBank0,I2CBank1 ; I2C addresses for 64K memory banks PhaseRegLo,PhaseRegHi ; phase reg lo & hi PhaseIncLo,PhaseIncHi ; phase inc lo * hi Index ; Index Pointer for playback of CW and sequences TSDuration ; Duration of tone TSPhaseLo,TSPhaseHi ; Phase Increments for Tone Effect ; Effect bits T_Options RTdata:2 ; Ringtone data DefOctave,DefLength ; Default Octave & Note Length Octave,Length ; Actual Octave & Note Length RTindex ; Index in ringtone RTsize ; Size of ringtone data RTTempoLo,RTTempoHi ; Tempo (initial note length) in ms RTLengthLo,RTLengthHi ; Length of Note in milliseconds LastVariable ; For debugging test ENDC CBLOCK 0x7C ; Some allocations in "shared" memory temp_S temp_W temp_PCH ENDC CBLOCK 0xA0 DataBuf:.32 ; Databuffer for uploading sounds & CW messages ENDC ;***************************************************************************** ; SOME MACROS COPIED FROM MACROS.INC TO CREATE A STANDALONE BUILDABLE FILE ;***************************************************************************** BANK1: MACRO ERRORLEVEL -302 ; enable warning "register is in bank 1" bsf STATUS,RP0 ENDM BANK0: MACRO ERRORLEVEL +302 ; enable warning "register is in bank 1" bcf STATUS,RP0 ENDM INT_ON MACRO bsf INTCON, GIE ENDM INT_OFF MACRO bcf INTCON, GIE ; disable interrupts btfsc INTCON, GIE goto $-2 ; loop until they are REALLY off ENDM NOP2 MACRO goto $+1 ENDM NOP3: MACRO goto $+1 nop ENDM ;***************************************************************************** ;***************************************************************************** ; Program start ;***************************************************************************** ORG RESET_V ; RESET vector location RESET GOTO START ;***************************************************************************** ; This is the Periperal Interrupt routine. ; Activated after a TMR1 or TMR2 interrupt ;***************************************************************************** ORG ISR_V ; Interrupt vector location INTERRUPT movwf temp_W ; Save W and STATUS swapf STATUS,W movwf temp_S bcf STATUS,RP0 ; insure bank 0 i_CheckTmr2 btfss PIR1,TMR2IF goto i_CheckTmr1 bcf PIR1,TMR2IF ; Clr Timer2 interrupt btfsc PWMisON ; PWM - Wave system enabled ? goto i_doWAV ; Yep, do PWM Wave btfss DDSisON goto i_CheckTmr1 ; Huh ? unkown int. reason, discard i_DoDDS movfw PCLATH ; We meed PCH for sinus lookup movwf temp_PCH ; so save a copy clrf PCLATH ; Select first 2K/256 bytes movfw PhaseIncLo ; Do PWM DDS (tone) addwf PhaseRegLo,F ; Increment the 16bit phase skpnc incf PhaseRegHi,F movfw PhaseIncHi addwf PhaseRegHi,F rrf PhaseRegHi,W ; Sinus table contains 128 positions andlw 0x7F call SineTable ; Get output value btfss DDS_HALVE ; Halve the DDS output ? goto i_DDSLoadValue movwf PWMValue ; Mis-use PWMValue for temp storage clrc rrf PWMValue,W ; Output = Output / 2 addlw 0x40 ; DC offset, now from 0x40 to 0xBF i_DDSLoadValue call SplitPWMValue ; split in 6 and 2 bit part movfw PWMValue movwf CCPR1L ; High 6 bits of PWM movfw PWMValue+1 movwf CCP1CON ; Low 2 bits of PWM movfw temp_PCH ; Restore PCLATH movwf PCLATH goto i_CheckTmr1 i_doWAV ; Next PWM value is already available, write to the hardware movfw PWMValue movwf CCPR1L ; High 6 bits of PWM movfw PWMValue+1 movwf CCP1CON ; Low 2 bits of PWM ; Do a check if the wave sample exceeds 65K, if not ; faster code can be used because we don't have to ; select between I2C adresses movf WaveSizeHi,F skpz goto i_bigWAV i_smallWAV movfw WaveSizeLo ; Check if we can use iorwf WaveSizeMi,W ; an "auto-rollover" skpnz goto i_SeqRead ; Yes, we can movf WaveCntLo,F ; Decrement Wave Counter skpnz decf WaveCntMi,F decf WaveCntLo,F movfw WaveCntLo ; Check for end of wave sample iorwf WaveCntMi,W skpz goto i_SeqRead ; No, read next movfw WaveSizeLo ; Yes, reset to begin movwf WaveCntLo movfw WaveSizeMi movwf WaveCntMi call ReadLastSeqEPROM ; Dummy Read clrf EEE_AddrHi ; Read initial PWM value clrf EEE_AddrLo call ReadMultiEPROM btfsc error24XX goto ShowI2CError goto i_SplitPWMValue i_bigWAV call DecWaveCnt24 ; Decrement wave counter skpnz ; End check for end of wave sample goto i_bigWAVreset incf EEE_AddrLo,F ; Track I2C adsress skpnz ; To detect bank switch incf EEE_AddrHi,F movfw EEE_AddrLo iorwf EEE_AddrHi,W skpz ; On a 64K boundary ? goto i_SeqRead ; No, use sequential read i_bigWAVBankSW call ReadLastSeqEPROM ; Dummy Read clrf EEE_AddrHi ; Reset EEE adress clrf EEE_AddrLo movfw I2CBank1 ; Select Second Bank movwf EEE_CS goto i_bigWavRead ; an read data i_bigWAVreset movfw WaveSizeLo ; Yes, reset to begin movwf WaveCntLo movfw WaveSizeMi movwf WaveCntMi movfw WaveSizeHi movwf WaveCntHi call ReadLastSeqEPROM ; Dummy Read clrf EEE_AddrHi ; Reset EEE adress clrf EEE_AddrLo movfw I2CBank0 movwf EEE_CS ; Select First Bank i_bigWavRead call ReadMultiEPROM btfsc error24XX goto ShowI2CError goto i_SplitPWMValue i_SeqRead call ReadSeqEPROM ; retreive next PWM value i_SplitPWMValue call SplitPWMValue i_CheckTmr1 btfss PIR1,TMR1IF ; Is it a TMR1 interrupt ? goto i_done bcf PIR1,TMR1IF ; clear timer1 interrupt flag decfsz Ticks,f ; 1 tick every 2 seconds so 5 in 10 secs goto i_done bsf E_10Seconds ; Raise this flag every 10 seconds movlw .5 movwf Ticks ; Reset Tick Counter movlw .10 ; Keep track of 10 second ticks addwf Secs10,F ; to raise 1 minute events movlw .60 subwf Secs10,W bnz i_done bsf E_Minute ; raise 1 minute event clrf Secs10 incf Minutes,F i_done swapf temp_S,W ; Restore W and STATUS movwf STATUS swapf temp_W,F swapf temp_W,W retfie ; -------------FULL VOLTAGE SWING (0..255) ------------- ; Sinustable: 128 entries for 360 degrees, output values ; between 0 and 255 which result in aprox. 4V t-t output ; Keep this table in PAGE0 as PCLATH is kept at 0x00 SineTable: ; THIS FULL VOLTAGE SWING (0..255) addwf PCL,F ; returns an 8bit result dt 0x80, 0x86, 0x8c, 0x93, 0x99, 0x9f, 0xa5, 0xab dt 0xb1, 0xb6, 0xbc, 0xc1, 0xc7, 0xcc, 0xd1, 0xd5 dt 0xda, 0xde, 0xe2, 0xe6, 0xea, 0xed, 0xf0, 0xf3 dt 0xf5, 0xf8, 0xfa, 0xfb, 0xfd, 0xfe, 0xfe, 0xff dt 0xff, 0xff, 0xfe, 0xfe, 0xfd, 0xfb, 0xfa, 0xf8 dt 0xf5, 0xf3, 0xf0, 0xed, 0xea, 0xe6, 0xe2, 0xde dt 0xda, 0xd5, 0xd1, 0xcc, 0xc7, 0xc1, 0xbc, 0xb6 dt 0xb1, 0xab, 0xa5, 0x9f, 0x99, 0x93, 0x8c, 0x86 dt 0x80, 0x7a, 0x74, 0x6d, 0x67, 0x61, 0x5b, 0x55 dt 0x4f, 0x4a, 0x44, 0x3f, 0x39, 0x34, 0x2f, 0x2b dt 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x13, 0x10, 0x0d dt 0x0b, 0x08, 0x06, 0x05, 0x03, 0x02, 0x02, 0x01 dt 0x01, 0x01, 0x02, 0x02, 0x03, 0x05, 0x06, 0x08 dt 0x0b, 0x0d, 0x10, 0x13, 0x16, 0x1a, 0x1e, 0x22 dt 0x26, 0x2b, 0x2f, 0x34, 0x39, 0x3f, 0x44, 0x4a dt 0x4f, 0x55, 0x5b, 0x61, 0x67, 0x6d, 0x74, 0x7a ;---------------------------------------------------------------------------- ; SplitPWMValue splits the 8bit value into a 6- and 2 bit part ; which are loaded into the PWM registers ;---------------------------------------------------------------------------- SplitPWMValue movwf PWMValue swapf PWMValue,W andlw b'00110000' iorlw b'00001100' ; Set PWM mode, 1-channel movwf PWMValue+1 ; Low 2 bits of PWM rrf PWMValue,F ; Get high 6 bits rrf PWMValue,F movlw 0x3F andwf PWMValue,F return ;---------------------------------------------------------------------------- ; Decrement a 24bit wave counter and return Zero Status Yes/No ;---------------------------------------------------------------------------- DecWaveCnt24: decfsz WaveCntLo,F goto _dec24nz movfw WaveCntMi iorwf WaveCntHi,W ; Sets Zero status return _dec24nz clrz ; set _Z=0 incfsz WaveCntLo,W ; Rollover ? return decfsz WaveCntMi,F ; NOTE: Does not affect Zero status incfsz WaveCntMi,W ; Rollover ? return decfsz WaveCntHi,F ; NOTE: Does not affect Zero status return return ;***************************************************************************** ; Initialize processor registers ;***************************************************************************** START ; POWER_ON Reset (Beginning of program) CLRF STATUS ; Do initialization, Select bank 0 CLRF INTCON ; Clear int-flags, Disable interrupts CLRF PCLATH ; Keep in lower 2KByte CLRF PORTA ; ALL PORT output should output Low. CLRF PORTC movlw 0x07 movwf CMCON0 ; DISABLE comparators clrwdt ; required for switching the prescaler movlw b'11010010' ; TMR0 on internal clock/8, prescaler->TMR0 BANK1 movwf OPTION_REG clrf ANSEL ; Disable A/D converter movlw b'01110000' ; Select 8 MHz clock movwf OSCCON ; Load clock MOVLW b'00000111' ; RA0-3 inputs (I2C & SYNC switch) MOVWF TRISA MOVLW b'00010000' ; RC4 input (RX), others output MOVWF TRISC BSF OPTION_REG, NOT_RAPU ; Disable PORTA pull-ups BANK0 bcf pinTX ; RS232 to idle movlw 0x20 ; Clear memory in BANK0 movwf FSR _memclear clrf INDF incf FSR,F movlw 0x7F subwf FSR,w bnz _memclear movlw Options ; Get configuration values from EEPROM movwf FSR ; And copy them to RAM movlw .16 ; 16 bytes to read movwf GenCount ; Mis-use I2C counter, we need it in shared memory movlw low EE_CFG BANK1 ; BANK1 (EE registers are here) movwf EEADR ; Load starting address _ReadSettings bsf EECON1,RD ; Initiate EE read movfw EEDATA movwf INDF ; Copy including terminating 0 incf FSR,f ; To next location in buffer incf EEADR,f ; To next location in EE decfsz GenCount,f goto _ReadSettings BANK0 movfw OscillatorTune ; Adjust oscillator if the tune value BANK1 ; Adjust internal oscillator movwf OSCTUNE BANK0 call I2C_Init call I2C_Reset ; Software reset on I2C bus clrf SystemFlags ; clrf Options ; FOR DEBUG TEST ONLY ; bsf CYCLED_TX ; FOR DEBUG TEST ONLY ; bsf SEQUENCED_TX ; FOR DEBUG TEST ONLY ; bsf TSEQMODE ; FOR DEBUG TEST ONLY ; bsf RINGMODE ; bsf KEYED_CW ; goto FoxStartup ; FOR DEBUG TEST ONLY ; Configure TMR1 and start the oscillator movlw b'00001110' ; 1:1 prescaler, TMR1 off, OSC on, ASYNC, EXTERNAL movwf T1CON ; The LP oscillator is notoriously slow, check if the oscillator ; has started. Preload it (otherwise it takes 2 seconds to time ; out) and check every 100 ms if the counter has wrapped ; (only occurs if the oscillator is running) movlw 0x80 movwf TMR1H ; Preset the timer clrf TMR1L bcf PIR1,TMR1IF bsf T1CON,TMR1ON ; Start the Timer movlw .30 ; Max startup is 3 seconds movwf Counter _csdly movlw .100 call DelayNms btfsc PIR1,TMR1IF ; Skip if not counted out goto ClockOK ; Yep, its running decfsz Counter,F goto _csdly movlw .3 ; Oops, osccilator did not start goto ShowError ; Show the error code ClockOK: bcf T1CON,TMR1ON ; Stop the Timer bcf PIR1,TMR1IF ; Clear the int. flag clrf TMR1L ; reset the timer clrf TMR1H call EEE_GetMemType ; Check for External Memory StartupFlash movlw .2 ; 2 Flashes if no memory movwf Counter movf I2CMemType,F skpz incf Counter,F ; 3 Flashes if memory found _sf bsf pinLED movlw .200 call DelayNms bcf pinLED movlw .200 call DelayNms decfsz Counter,F goto _sf ; ESCAPE MECHANISM: If the FOX is not in the "standard" ; cycling mode but should always transmit or use sequenced ; transmission skip the SYNC check if the line is held low ; and go directly to the transmit mode btfsc swSYNC ; Sync Switch low ? goto ConfigLoop ; No, normal operation btfss CYCLED_TX ; Continious Transmission goto FoxStartup ; YES: Start Transmitter btfsc SEQUENCED_TX ; Sequenced Transmit goto FoxStartup ; YES: Start Transmitter ConfigLoop: bcf pinLED ; LED is OFF call SerialTest ; If serial char received bc ParseSerial ; Process it btfsc swSYNC ; Sync Switch pressed ? goto ConfigLoop call StopTone movlw .250 ; switch should be down at least .5 second movwf Counter SyncLoop: btfsc swSYNC goto ConfigLoop movlw .2 ; 250 * 2 milliseconds = .5 second call DelayNms decfsz Counter,F goto SyncLoop WaitSyncRelease bsf pinLED ; Led goes on btfss swSYNC ; Wait for SYNC release goto WaitSyncRelease bcf pinLED ; Led off again goto FoxStartup ; Start with FOX schedule ParseSerial call StopTone call SerialReceive ; Wait for a command to arrive call SerialSend ; echo command back xorlw 'V' ; V = Version Information bz cmdSendVersion xorlw 'V' xorlw 'D' ; D = Dump I2C memory bz cmdDownloadMem xorlw 'D' xorlw 'U' ; U = Upload I2C memory bz cmdUploadMem xorlw 'U' xorlw 'T' ; T = Test commando bz FoxStartup ; bz Timer1Test xorlw 'T' xorlw 'R' ; R = Read EE configuration (from PIC->PC) bz cmdReadConfig xorlw 'R' xorlw 'W' ; W = Write EE configuration (from PC->PIC) bz cmdWriteConfig xorlw 'W' xorlw 'C' ; C = Calibrate (show int. freq) bz cmdCalibrate xorlw 'C' xorlw '@' ; @ = Reset system bz RESET goto ConfigLoop ;---------------------------------------------------------------------------- ; GoActive is the main controller loop. It does the following steps: ; 1) Start the timing system ; 1) Delay the specified amount of minutes ; 2) Go Active (continious mode) OR Cycle the loop of transmitters ;---------------------------------------------------------------------------- FoxStartup: bcf SHUTDOWNACTIVE ; Disable auto-shutdown movf ShutdownDelay,F skpz ; if value != 0 bsf SHUTDOWNACTIVE ; enable shutdown counter bcf RECOVERYBEACON ; Disable recovery beacon movf RecoveryDelay,F skpz ; if value != 0 bsf RECOVERYBEACON ; enable shutdown counter ; Initialize timing system, based on TMR1 bcf T1CON,TMR1ON ; Stop the Timer (should be off anyway) bcf E_10Seconds ; Init all settings bcf E_Minute movlw .5 ; 5 ticks per 10 second period movwf Ticks clrf Secs10 clrf Minutes clrf TMR1H ; reset timer clrf TMR1L bcf PIR1,TMR1IF ; clear timer1 interrupt flag BANK1 bsf PIE1,TMR1IE ; Enable TMR1 interrupt BANK0 bsf INTCON,PEIE ; Peripheral interrupts enabled bsf INTCON,GIE ; Global interrupts enabled bsf T1CON,TMR1ON ; Start the Timer movf StartupDelay,F bz FoxActive ; No StartupDelay goto transmit StartLoop: sleep ; TMR1 interrupt will wake system nop ; Just a dummy (recovered from sleep) btfss E_10Seconds ; Was it TMR1 tick ? goto StartLoop ; Nope, try again call FlashLed ; Every 10 seconds show a short flash bcf E_10Seconds btfss E_Minute ; Minute has passed ?? goto StartLoop ; Nope, wait bcf E_Minute ; clear the flag decfsz StartupDelay,F ; Decrement wait counter goto StartLoop ; More minutes to Wait FoxActive: btfsc CYCLED_TX goto CycledTransmit ;---------------------------------------------------------------------------- ; Continious Transmission ;---------------------------------------------------------------------------- ContTransmit: bsf pinLED ; Status led on bsf pinTMRT ; Transmitter on movlw .100 call DelayNms ; Wait 100 milliseconds bsf pinKEY ; PTT switch down call StartAudio btfss CWMODE ; Are we in CW mode ? goto _ct1 btfsc KEYED_CW ; Patch for sending carriers bcf pinKEY ; PTT off and modulation off bcf DDSisON ; (If CW tekst starts with ' ') _ct1 btfsc CWMODE ; Are we in CW mode ? call CW_DoChar ; Send a CW character btfsc TSEQMODE ; Are we in Tone Sequence mode ? call TSeqDoTone ; Play a tone btfsc EFFECTMODE ; Effect Mode ? call UpdateEffect btfsc RINGMODE ; Are we in RingTone mode ? call PlayRingToneNote btfss E_Minute ; Minute has passed ?? goto _ct1 ; No, wait bcf E_Minute call ShutdownCheck ; Yes, update shutdowncounter goto _ct1 ;---------------------------------------------------------------------------- ; Cycled transmission with N transmitters ;---------------------------------------------------------------------------- CycledTransmit: btfsc SEQUENCED_TX ; Sequenced of normal ARDF cycling ? goto SequencedTransmit clrf CycleIndex movfw CycleDelay movwf CycleDelayCnt ; Minute counter in active step CycleLoop movfw CycleID ; Test if in active Cycle xorwf CycleIndex,W bnz NoActiveCycle Active bsf pinLED ; Status led on bsf pinTMRT ; Transmitter on movlw .100 call DelayNms ; Wait 100 milliseconds bsf pinKEY ; PTT switch down call StartAudio btfss CWMODE ; Are we in CW mode ? goto _A1 btfsc KEYED_CW ; Patch for sending carriers bcf pinKEY ; PTT off and modulation off bcf DDSisON ; (If CW tekst starts with ' ') _A1 call CheckForEndOfStep iorlw 0 bnz _A2 ; End of step in cycle reached btfsc CWMODE ; Are we in CW mode ? call CW_DoChar ; Send a CW char btfsc TSEQMODE ; Are we in Tone Sequence mode ? call TSeqDoTone ; Play a tone btfsc EFFECTMODE ; Effect Mode ? call UpdateEffect ; Update Effect btfsc RINGMODE ; Are we in RingTone mode ? call PlayRingToneNote goto _A1 ; Try again _A2 call StopAudio bcf pinKEY ; PTT released bcf pinTMRT ; Transmitter off bcf pinLED ; Status led off goto CycleLoop NoActiveCycle: sleep ; TMR1 interrupt will wake system nop ; Just a dummy (recovered from sleep) call CheckForEndOfStep iorlw 0 bz NoActiveCycle ; Not at end of step, wait goto CycleLoop ; End of step in cycle reached CheckForEndOfStep: _wfeos btfss E_10Seconds ; 10seconds have passed ?? retlw 0 ; No bcf E_10Seconds decfsz CycleDelayCnt,F ; All 10sec units of step passed ?? retlw 0 ; No movfw CycleDelay ; Reload step delay movwf CycleDelayCnt incf CycleIndex,F ; Increment cycle step movfw CycleIndex xorwf CycleCount,W ; End reached ? skpnz clrf CycleIndex ; Yep, reset to first step btfss E_Minute ; Also a minute has passed ? retlw 1 ; No, return 10sec tick count true bcf E_Minute ; Yep, also a minute has passed call ShutdownCheck ; Do shutdown check retlw 1 ;---------------------------------------------------------------------------- ; Sequenced transmission, an array with ON and OFF periods are givven ; ; TXSequence variables are overlayed with standard Cycling variables ; for sequenced transmission a rather rude copy is made of the normal ; cycling mode. ;---------------------------------------------------------------------------- #define SeqIndex CycleIndex #define SeqDelay CycleDelay #define SeqDelayCnt CycleDelayCnt SequencedTransmit clrf SeqIndex movlw .8 ; Longer than max. sequence length movwf CycleCount ; Allows re-use of CheckForEndOfStep SequenceLoop clrc rlf SeqIndex,W ; Get position (Index *2) addlw low EE_TXSEQ ; Add start address of table BANK1 ; BANK1 (EE registers are here) movwf EEADR ; Load starting address bsf EECON1,RD ; Initiate EE read movfw EEDATA BANK0 movwf SeqDelay ; Duration of sequence step movf SeqDelay,F ; Test duration length bnz _seqOK ; Zero Duration ? clrf SeqIndex ; Yes, Reset to start of TX definition goto SequenceLoop ; and read again _seqOK movfw SeqDelay movwf SeqDelayCnt ; 10sec tick counter in current step BANK1 incf EEADR,F ; Load options for this step bsf EECON1,RD ; Initiate EE read movfw EEDATA BANK0 movwf T_Options ; Temp storage of modulation option btfss T_Options,0 ; Active or Inactive Step ?? goto _seqNotActive movlw b'11111100' ; Effect mode mask andwf T_Options,F movfw Options andlw b'00000011' ; Keep these bits iorwf T_Options,W ; add modulation option movwf Options _seqActive bsf pinLED ; Status led on bsf pinTMRT ; Transmitter on movlw .100 call DelayNms ; Wait 100 milliseconds bsf pinKEY ; PTT switch down call StartAudio btfss CWMODE ; Are we in CW mode ? goto _seqA1 btfsc KEYED_CW ; Patch for sending carriers bcf pinKEY ; PTT off and modulation off bcf DDSisON ; (If CW tekst starts with ' ') _seqA1 call CheckForEndOfStep iorlw 0 bnz _seqA2 ; End of step in cycle reached btfsc CWMODE ; Are we in CW mode ? call CW_DoChar ; Send a CW char btfsc TSEQMODE ; Are we in Tone Sequence mode ? call TSeqDoTone ; Play a tone btfsc EFFECTMODE ; Effect Mode ? call UpdateEffect ; Update Effect btfsc RINGMODE ; Are we in RingTone mode ? call PlayRingToneNote goto _seqA1 ; Try again _seqA2 call StopAudio bcf pinKEY ; PTT released bcf pinTMRT ; Transmitter off bcf pinLED ; Status led off goto SequenceLoop _seqNotActive: sleep ; TMR1 interrupt will wake system nop ; Just a dummy (recovered from sleep) call CheckForEndOfStep iorlw 0 bz _seqNotActive ; Not at end of step, wait goto SequenceLoop ; End of step in cycle reached ;---------------------------------------------------------------------------- ; Start Audio ;---------------------------------------------------------------------------- StartAudio: btfsc TONEMODE goto StartTone btfsc WAVEMODE goto StartPWM btfsc CWMODE goto StartCWMode btfsc EFFECTMODE goto StartEffect btfsc TSEQMODE goto StartToneSeq btfsc RINGMODE goto StartRingTone bsf TONEMODE ; Huh ? no known mode, default to goto StartTone ; Single Tone mode StopAudio: btfsc TONEMODE goto StopTone btfsc WAVEMODE goto StopPWM btfsc CWMODE goto StopTone btfsc EFFECTMODE goto StopTone btfsc TSEQMODE goto StopTone btfsc RINGMODE goto StopTone ;---------------------------------------------------------------------------- ; Start the PWM audio system ;---------------------------------------------------------------------------- StartPWM: movfw WaveSizeLo ; Load with the size movwf WaveCntLo ; of the wavetable movfw WaveSizeMi movwf WaveCntMi movfw WaveSizeHi movwf WaveCntHi clrf EEE_AddrHi ; Read initial PWM value clrf EEE_AddrLo movfw I2CBank0 ; Select 1st 64K movwf EEE_CS INT_OFF call ReadMultiEPROM INT_ON btfsc error24XX goto ShowI2CError bsf PWMisON ; Enable PWM lookup goto StartTMR2 ; returns via StartTMR2 StopPWM: BANK1 bcf PIE1,TMR2IE ; Timer 2 interrupt off BANK0 bcf T2CON, TMR2ON ; Stop Timer2 bcf PWMisON ; Disable PWM lookup INT_OFF call ReadLastSeqEPROM ; Dummy Read to stop INT_ON return ;---------------------------------------------------------------------------- ; Start the DDS Tone generator ;---------------------------------------------------------------------------- StartTone: movfw ToneIncLo ; Load phase increment movwf PhaseIncLo movfw ToneIncHi movwf PhaseIncHi clrf PhaseRegLo clrf PhaseRegHi bsf DDSisON ; Enable DDS lookup goto StartTMR2 ; returns via StartTMR2 StopTone: BANK1 bcf PIE1,TMR2IE ; Timer 2 interrupt off BANK0 bcf T2CON, TMR2ON ; Stop Timer2 bcf DDSisON return StartEffect: clrf Effect clrf PhaseIncLo ; Siren effect movlw .3 ; Phase inc continuously adjusted movwf PhaseIncHi clrf PhaseRegLo clrf PhaseRegHi bsf DDSisON ; Enable DDS lookup goto StartTMR2 ; returns via StartTMR2 StartCWMode call BuildCWMessage ; Build the message clrf Index ; Start at begin goto StartTone ; And start the tone generator StartToneSeq clrf Index ; Start at begin of sequence goto StartTone ; And start the tone generator StartRingTone call LoadRingToneHeader movf RTsize,F skpz goto StartTone ; Valid Ringtone in EE bcf RINGMODE ; Not valid, clear this mode bsf TONEMODE ; and switch back to TONE mode goto StartTone ;---------------------------------------------------------------------------- ; Start TMR2 for PWM at 7.825 kHz (shared code for Tones and Waves) ;---------------------------------------------------------------------------- StartTMR2 ; PWM system setup movlw b'00011000' movwf T2CON ; Stop Timer2, Prescaler = 1:1, Postscaler = 1:4 clrf TMR2 ; Clear Timer2 register BANK1 movlw .63 ; 0 -> 63 movwf PR2 BANK0 movlw .31 ; 50 % duty cycle movwf CCPR1L movlw b'00111100' ; Enable PWM mode, lsb's are 1 movwf CCP1CON bcf PIR1,TMR2IF ; Clr Timer2 interrupt BANK1 bsf PIE1,TMR2IE ; Timer 2 interrupt on BANK0 bsf INTCON,PEIE ; Peripheral interrupts enabled bsf INTCON,GIE ; Global interrupts enabled bsf T2CON, TMR2ON ; Timer2 starts to increment return ;---------------------------------------------------------------------------- ; ReadNextTone: retrieve the duration and frequency of the next tone to ; play. Known bug: This code will hangup the controller if the table is empty ; so make sure this never happens !!!!!!! ;---------------------------------------------------------------------------- ReadNextTone movlw TSDuration movwf FSR ; FSR points where to put result movlw low EE_TSEQ addwf Index,W ; StartLocation in EE BANK1 ; BANK1 (EE registers are here) movwf EEADR ; Load starting address bsf EECON1,RD ; Initiate EE read of Duration movfw EEDATA movwf INDF ; Duration incf FSR,F incf EEADR,F bsf EECON1,RD ; Initiate EE read movfw EEDATA movwf INDF ; Phase Inc low incf FSR,F incf EEADR,F bsf EECON1,RD ; Initiate EE read movfw EEDATA movwf INDF ; Phase Inc high BANK0 movlw .3 addwf Index,F movfw Index xorlw .48 ; Loop over max 16 definitions skpnz clrf Index ; Reset to start of definition movf TSDuration,F ; Test duration skpnz ; if zero goto ReadNextTone ; read next value, end was reached return ;---------------------------------------------------------------------------- ; BuildCWMessage: Builds a buffer containing the characters to transmit ; in CW mode. Depending on the AUTO_CW setting the data comes from EE ; or is generated locally (MOx sequences) ; Known bug: This code will hangup the controller if the table is empty ; so make sure this never happens !!!!!!! ;---------------------------------------------------------------------------- BuildCWMessage btfsc AUTO_CW ; Auto or manual message text ? goto BuildMOMessage BuildEEMessage movlw DataBuf movwf FSR ; FRS points to RAM buffer movlw low EE_CWTXT ; StartLocation of CW msg in EE BANK1 ; BANK1 (EE registers are here) movwf EEADR ; Load starting address _bldmsgloop bsf EECON1,RD ; Initiate EE read incf EEADR,F ; To next EE location movfw EEDATA movwf INDF ; Store in RAM buffer incf FSR,F ; Point to next char in buffer iorlw 0 ; Test character for end of msg bnz _bldmsgloop ; If NO, read next character BANK0 return BuildMOMessage movlw DataBuf movwf FSR ; FRS points to RAM buffer movlw 'M' movwf INDF incf FSR,F movlw 'O' movwf INDF incf FSR,F btfss CYCLED_TX goto _cwEOT ; Just MO is enough movfw CycleID ; Add the Cycle ID (nr of dots) addlw 0x21 ; Here the DOT sequences are mapped movwf INDF incf FSR,F _cwEOT movlw ' ' ; End MOx message with a space movwf INDF incf FSR,F clrf INDF ; Terminate message return ;---------------------------------------------------------------------------- ; ReadNextMsgChar: retrieve the next CW character to transmit ; Known bug: This code will hangup the controller if the table is empty ; so make sure this never happens !!!!!!! ;---------------------------------------------------------------------------- ReadNextMsgChar movlw DataBuf addwf Index,W ; Current location in buffer movwf FSR movfw INDF incf Index,F ; Point to next char in table iorlw 0 ; Test character for zero skpz ; End of Table reached ? return ; No, return with character clrf Index ; Yes, Reset Index goto ReadNextMsgChar ; and try again ;---------------------------------------------------------------------------- ; Shutdowncheck: Call when a minute has passed, it will ; check the counter, decrement it, and if expired: ; Disable all activity and place the system in sleep mode ; (lowest possible power consumption) ;---------------------------------------------------------------------------- ShutdownCheck btfss SHUTDOWNACTIVE return ; Not enabled, return decfsz ShutdownDelay,F ; decrement counter return ; Not expired btfsc RECOVERYBEACON ; Recovery Beacon active ? goto RecoveryWait ; Yep INT_OFF ; No, Power down clrf T1CON ; Timer1 off clrf T2CON ; Timer2 off bcf pinKEY ; PTT off bcf pinTMRT ; Transmitter off bcf pinLED ; Status led off sleep ; Stop all activity ; First wait the required nr. of minutes RecoveryWait movf RecoveryDelay,F ; Counter at zero ? bz RecoveryTransmit bcf pinKEY ; PTT off bcf pinTMRT ; Transmitter off bcf pinLED ; Status led off bcf DDSisON bcf PWMisON clrf TMR2 ; Stop Timer2 RecoveryLoop sleep ; TMR1 interrupt will wake system nop ; Just a dummy (recovered from sleep) btfss E_10Seconds ; Was it TMR1 tick ? goto RecoveryLoop ; Nope, try again call FlashLed ; Every 10 seconds show a short flash bcf E_10Seconds btfss E_Minute ; Minute has passed ?? goto RecoveryLoop ; Nope, wait bcf E_Minute ; clear the flag decfsz RecoveryDelay,F ; Decrement wait counter goto RecoveryLoop ; More minutes to Wait ;---------------------------------------------------------------------------- ; The recovery beacon is a single tone and the transmitter is keyed ; every 1.5 seconds in which it will transmit for 500 milliseconds ; This method will prolong the battery life ;---------------------------------------------------------------------------- RecoveryTransmit clrf T1CON ; Timer1 off, no longer needed bsf pinLED ; Status led on bsf pinTMRT ; Transmitter on movlw .100 call DelayNms ; Wait 100 milliseconds bsf pinKEY ; PTT switch down call StartTone movlw .250 ; For 500 milliseconds call DelayNms ; generate a tone movlw .250 call DelayNms call StopTone bcf pinKEY ; PTT off bcf pinTMRT ; Transmitter off bcf pinLED ; Status led off movlw .250 ; For 750 milliseconds call DelayNms ; keep silent movlw .250 call DelayNms movlw .150 call DelayNms goto RecoveryTransmit ;---------------------------------------------------------------------------- ; SendVersion echos the version number over the serial ; interface. Formatted: binary, 2 bytes: ; AAAABBBB CCCCDDDD ; AAAA = Controller ID 0 = 16F628A + 10 MHz Xtal ; 1 = 16F688 + internal 8 MHz + 32 kHz Xtal ; BBBB = I2C Memorysize in 256kUnits ; 0 = No Memory ; 1 = 256kbit (24C256) 4.2 seconds audio ; 2 = 512kbit (24C512) 8.4 seconds audio ; 3 = 1024kBit (24C1024) 16.8 seconds audio ; ; CCCC = Major version number ; DDDD = Minor version number ;---------------------------------------------------------------------------- cmdSendVersion: movfw I2CMemType ; Get Memory Size in high nibble andlw 0x03 ; 2 bits used for size iorlw 0x10 ; add the processor type (16F684=1) call SerialSend movlw 0x20 ; version 1.9 call SerialSend goto ConfigLoop ;---------------------------------------------------------------------------- ; cmdCalibrate can be used to calibrate the system ; It starts the TMR1 oscillator so the 32768 frequency can ; be tuned with a small trimmer and generates the processor ; clock on the LED (This is the CPU clock / 8 so 250 kHz for ; an 8 MHz frwquency) ; The routine is exited if an invalid calibration value is send ; with the high bit set in oscillator tune value ;---------------------------------------------------------------------------- cmdCalibrate call SerialReceive ; Get Calibration Value call SerialSend movwf TEMP btfsc TEMP,7 ; High bit set = Stop goto ConfigLoop movfw TEMP andlw 0x1F BANK1 movwf OSCTUNE ; Load calibation value BANK0 ; movlw .10 ; Allow osc. to get to new freq. ; call DelayNms _calloop bsf pinLED nop goto $+1 bcf pinLED btfss pinRX ; Test for Leading Edge of startbit goto _calloop ; No, try again goto cmdCalibrate ;------------------------------------------------------------------ cmdReadConfig: clrf Counter ; Send complete EE, starting at 0 _rdconfig movfw Counter BANK1 movwf EEADR ; Set EE address bsf EECON1,RD ; EE read initiated movfw EEDATA BANK0 call SerialSend ; Send EE byte incfsz Counter,F goto _rdconfig goto ConfigLoop cmdWriteConfig: call SerialReceive ; Get starting adres BANK1 movwf EEADR ; Set EE address BANK0 call SerialSend ; echo back call SerialReceive ; Get Count movwf Counter call SerialSend ; echo back _loadloop: call SerialReceive BANK1 movwf EEDATA bsf EECON1,WREN INT_OFF ; Disable interrupts movlw 0x55 ; Write required sequence movwf EECON2 movlw 0xAA movwf EECON2 bsf EECON1,WR INT_ON ; Enable interrupts again btfsc EECON1,WR ; wait for write to complete ( typ. 10 mSec) goto $-1 bcf EECON1,WREN incf EEADR,f BANK0 movlw '#' ; ack char call SerialSend decfsz Counter,F goto _loadloop goto ConfigLoop ;------------------------------------------------------------------ cmdDownloadMem call SerialReceive ; Wait for nr_of_bytes movwf Counter call SerialSend call SerialReceive ; Get BANK adres (bit 17-23) call SelectEPROM call SerialSend call SerialReceive ; Get Hi-Byte of I2C mem address movwf EEE_AddrHi call SerialSend ; echo command back call SerialReceive ; Get Lo-Byte of I2C mem address movwf EEE_AddrLo call SerialSend ; echo command back call ReadEPROM btfsc error24XX goto ShowI2CError _dloop movfw EEE_Byte call SerialSend bcf error24XX call ReadNextEPROM btfsc error24XX goto ShowI2CError decfsz Counter,F goto _dloop goto ConfigLoop cmdUploadMem: call SerialReceive ; Wait for nf_of_bytes movwf EEE_Byte call SerialSend call SerialReceive ; Get BANK adres (bit 17-23) call SelectEPROM call SerialSend call SerialReceive ; Get Hi-Byte of I2C mem address movwf EEE_AddrHi call SerialSend ; echo command back call SerialReceive ; Get Lo-Byte of I2C mem address movwf EEE_AddrLo call SerialSend ; echo command back clrf CSum ; Reset Checksum movfw EEE_Byte ; Databytes to read movwf TEMP movlw DataBuf movwf FSR ; FSR to databuffer _GetData call SerialReceive ; Get databyte movwf INDF ; store in databuf addwf CSum,F ; Update Checksum incf FSR,F decfsz TEMP,F goto _GetData movfw CSum ; Echo Checksum of rxdata call SerialSend call SerialReceive call SerialSend sublw 'G' ; "Go" command bnz ConfigLoop ; Skip writing if not "Go" movlw DataBuf movwf FSR ; FSR points to data bsf pinLED call WritePageEPROM ; Write the data in I2C EE bcf pinLED btfsc error24XX goto ShowI2CError movlw '#' ; Acknowledge data written call SerialSend goto ConfigLoop ;---------------------------------------------------------------------------- ; ShowError gives an error indication ; It uses the led to repeatedly give a series of short flashes ; call with the requested NR of flashes in "W" ; Current error codes: ; 2 flashes = I2C (memory) Error ; 3 flashes = 32kHz oscillator did not start ;---------------------------------------------------------------------------- ShowI2CError movlw .2 ; I2C = 2 flashes ShowError: INT_OFF BANK0 movwf TEMP _se1 movfw TEMP movwf Counter _se2 call FlashLed movlw .200 call DelayNms decfsz Counter,F goto _se2 movlw .3 movwf Counter _se3 movlw .255 call DelayNms decfsz Counter,F goto _se3 goto _se1 FlashLed bsf pinLED movlw .30 call DelayNms bcf pinLED return ;-------------------------------------------------------------------- ; SerialIO routines, using a software UART ; fixed for 19K2, 8 databits, No Parity, 2 stopbits with 8MHz clock ; Note: Using 2 stop bits will free up some processor time ; to allow processing of received characters, the complete ; I/O is polled. ;-------------------------------------------------------------------- SERIAL_DATA equ (SCRATCH) ; Data In/Out SERIAL_COUNT equ (SCRATCH+1) ; Bit Counter SERIAL_DELAY equ (SCRATCH+2) ; Bit Delay Counter SerialTest clrc btfsc pinRX ; Dirty routine to poll arrival of setc ; serial characters return ; Carry SET: Leading Edge detected, Carry FALSE: Idle SerialIn btfss pinRX ; Test for Leading Edge of startbit goto SerialIn ; No, try again movlw .8 ; 8 databits expected movwf SERIAL_COUNT clrf SERIAL_DATA ; Clear character movlw .15 movwf SERIAL_DELAY decfsz SERIAL_DELAY,F ; Delay half bit time (26.04u) goto $-1 nop ; tuning nops btfss pinRX ; Check valid startbit goto SerialIn ; Not Valid, just a spike ?? NOP3 ; tuning nops SerialIn2 movlw .32 movwf SERIAL_DELAY ; Delay full bit time decfsz SERIAL_DELAY,F goto $-1 clrc ; Default '0' bit rrf SERIAL_DATA,F ; shift the databyte btfss pinRX ; '0' or '1' ?? bsf SERIAL_DATA,7 ; Insert '1' bit decfsz SERIAL_COUNT,F ; Decrement bit counter goto SerialIn2 ; More bits to come movlw .32 movwf SERIAL_DELAY ; Delay full bit time decfsz SERIAL_DELAY,F goto $-1 clrc NOP3 ; tuning nops btfsc pinRX ; Check valid stopbit setc ; Not Valid, set carry movfw SERIAL_DATA ; return with received return ; character in 'W' SerialOut movwf SERIAL_DATA ; Character to transmit movlw .8 movwf SERIAL_COUNT ; 8 bits to transmit bsf pinTX ; Set start bit movlw .33 movwf SERIAL_DELAY ; Delay full bit time (52.08u) decfsz SERIAL_DELAY,F goto $-1 SerialOut2 rrf SERIAL_DATA,F skpc bsf pinTX ; Transmit SPACE skpnc bcf pinTX ; Transmit MARK movlw .31 movwf SERIAL_DELAY ; Delay full bit time decfsz SERIAL_DELAY,F goto $-1 NOP2 ; tuning nops decfsz SERIAL_COUNT,F goto SerialOut2 rrf SERIAL_DATA,F bcf pinTX ; Set Stop bit movlw .66 movwf SERIAL_DELAY ; Delay 2* full bit time decfsz SERIAL_DELAY,F goto $-1 movfw SERIAL_DATA ; Return with char send in 'W' return ;-------------------------------------------------------------------- ; TseqDoTone: Play a single tone from the sequence stored in EE ;-------------------------------------------------------------------- TSeqDoTone call ReadNextTone ; Option is FrequencyList INT_OFF ; No ints. while the new movfw TSPhaseLo ; phase increment is loaded movwf PhaseIncLo movfw TSPhaseHi ; phase increment is loaded movwf PhaseIncHi INT_ON movlw .10 ; Tone length in 10 ms units movwf TEMP _tsdt movfw TSDuration call DelayNms ; Wait the duration of this tone decfsz TEMP,F goto _tsdt return UpdateEffect movlw .10 call DelayNms btfsc Effect,0 goto _effectDown _effectUp INT_OFF movlw 0x10 addwf PhaseIncLo,F skpnc incf PhaseIncHi,F INT_ON movfw PhaseIncHi xorlw .30 ; Upper boundary skpnz bsf Effect,0 ; Set direction to down return _effectDown INT_OFF movlw 0x10 subwf PhaseIncLo,F skpc decf PhaseIncHi,F INT_ON movfw PhaseIncHi xorlw .2 ; Lower boundary skpnz bcf Effect,0 ; Set direction to UP return ;-------------------------------------------------------------------- ; CW_DoChar: Get next char from the table and play it ;-------------------------------------------------------------------- CW_DoChar call ReadNextMsgChar ;-------------------------------------------------------------------- ; Send a character as Morse Code, call with the looked up CW code ; The PC does the ASCII->CW translation, saving us to maintain a ; lookup table in the PIC ;-------------------------------------------------------------------- CW_SendChar movwf SCRATCH movlw high CW_Table movwf PCLATH ; Set PCH to proper page movfw SCRATCH ; Character to transmit call CW_Table ; Get CW representation clrf PCLATH ; restore PCH movwf SCRATCH movf SCRATCH,F ; Test for zero bz CW_WaitChar ; NUL char = word pause cw_loop clrc rrf SCRATCH,F ; shift LSB in carry movf SCRATCH,F ; Test for zero bz cw_done bnc _dodit ; Carry not set: do DIT _dodah: call CW_SendDah ; Carry set: do DAH goto _done _dodit: call CW_SendDit ; Carry not set: do DIT _done: btfsc KEYED_CW bcf pinKEY ; Only if Keyed CW, not in FM bcf DDSisON call CW_WaitDit ; Pauze between dah/dits goto cw_loop ; next dit or dah cw_done call CW_WaitDit ; end of char: 2 extra dits call CW_WaitDit return CW_SendDah btfsc KEYED_CW bsf pinKEY ; Only if Keyed CW, not in FM bsf DDSisON goto CW_WaitDah CW_SendDit btfsc KEYED_CW bsf pinKEY ; Only if Keyed CW, not in FM bsf DDSisON goto CW_WaitDit CW_WaitChar call CW_WaitDit ; Wordpause: 3 already done, add 4 CW_WaitDah call CW_WaitDit ; Dah = 3 * Dit call CW_WaitDit CW_WaitDit movfw DitDelay ; Delay in milliseconds call DelayNms return ;-------------------------------------------------------------------- ; Get the memorysize of the external memory, currently only checks ; if memory is found of not found, the size is not determined. ;-------------------------------------------------------------------- EEE_GetMemType clrf I2CMemType ; Set Memory Size to 0 clrf I2CBank0 clrf I2CBank1 clrf EEE_AddrHi ; Try to read at address 0 clrf EEE_AddrLo movlw b'10100000' ; Select I2C subaddress 0 movwf EEE_CS call ReadEPROM btfsc error24XX goto _noM1024 ; Memory Not Found, try next call I2C_Init bcf error24XX movlw b'10101000' ; Select I2C subaddress 4 movwf EEE_CS call ReadEPROM btfsc error24XX goto _A512 ; Not 1M Microchip movlw b'10101000' ; 128kByte Microchip 24LC1025 detected movwf I2CBank0 ; Uses chip adress 4 & 0 movlw b'10100000' movwf I2CBank1 movlw .3 movwf I2CMemType return _A512 call I2C_Init bcf error24XX ; Reset the error status movlw b'10100000' ; 64kByte Atmel 24AT512detected movwf I2CBank0 ; Uses chip adress 0 movwf I2CBank1 ; Bank1 also accesses Bank0 movlw .2 movwf I2CMemType return _noM1024: call I2C_Init bcf error24XX movlw b'10101010' ; Select I2C subaddress 5 movwf EEE_CS call ReadEPROM btfsc error24XX goto _noA1024 ; Memory Not Found, try next movlw b'10101000' ; 128kByte Atmel ATC1024 detected movwf I2CBank0 ; Uses chip adress 4 & 5 movlw b'10101010' movwf I2CBank1 movlw .3 movwf I2CMemType return _noA1024: call I2C_Init bcf error24XX movlw b'10101000' ; Select I2C subaddress 4 movwf EEE_CS call ReadEPROM btfsc error24XX return ; Memory Not Found movlw b'10101000' ; 65kByte chip or less detected movwf I2CBank0 ; Uses chip adress 4 movwf I2CBank1 ; Let bank1 access bank0 movlw .2 movwf I2CMemType return ;***************************************************************************** ; RINGTONE routines ;***************************************************************************** PlayRingToneNote movfw RTindex ; Check for end of melody xorwf RTsize,W bnz _nextNote movlw .6 ; End reached, set back to movwf RTindex ; begin (ignore header) ; bcf DDSisON ; INT_OFF ; goto $ _nextNote call GetRTEntry ; Get next note movfw RTTempoHi ; Initial Duration stuff movwf RTLengthHi ; based on BPM tempo movfw RTTempoLo movwf RTLengthLo btfss RTdata,6 ; Dotted tone ? goto _notDotted clrc rrf RTTempoHi,W ; Get half length value movwf SCRATCH+1 ; into scratch variable rrf RTTempoLo,W movwf SCRATCH movfw SCRATCH ; Add the two addwf RTLengthLo,F ; to get the length * 1.5 skpnc incf RTLengthHi,F movfw SCRATCH+1 addwf RTLengthHi,F _notDotted movlw high GetRTFreqLo ; Initial Frequency stuff movwf PCLATH ; Set PCH to proper page movfw RTdata ; Note frequency to phase inc. andlw 0x0F call GetRTFreqLo movwf TSPhaseLo movfw RTdata andlw 0x0F call GetRTFreqHi movwf TSPhaseHi clrf PCLATH movfw DefLength movwf Length btfss RTdata,5 ; Use default length (duration) ? goto _defLen rlf RTdata+1,W ; No, get length from 2nd byte andlw 0x70 movwf Length swapf Length,F _defLen movfw DefOctave movwf Octave btfss RTdata,4 ; Use default octave (scale) ? goto _shiftOctave movfw RTdata+1 ; No, get octave from 2nd byte andlw 0x07 movwf Octave ; Octave encoding: The table holds the frequencies for octave 7 ; The encoding for octaves: 0=oct7,1=oct6,2=oct5 etc. ; So use the ovtave value as counter in a right shift loop _shiftOctave movfw Octave ; Table is for octave 7 bz _shiftLength _aOctaveLoop clrc rrf TSPhaseHi,F rrf TSPhaseLo,F decfsz Octave,F goto _aOctaveLoop _shiftLength decf Length,F bz _rtPlay clrc rrf RTLengthHi,F rrf RTLengthLo,F goto _shiftLength _rtPlay INT_OFF ; No ints. while the new movfw TSPhaseLo ; phase increment is loaded movwf PhaseIncLo movfw TSPhaseHi ; phase increment is loaded movwf PhaseIncHi INT_ON _rtWait movlw .1 call DelayNms ; Wait the duration of this tone movf RTLengthLo,F ; Decrement LengthWave Counter skpnz decf RTLengthHi,F decf RTLengthLo,F movfw RTLengthLo ; Check for end of note delay iorwf RTLengthHi,W skpz goto _rtWait ; No, next millisecond wait btfss RT_STACCATO ; Add internote spacing ? return INT_OFF ; Staccato: Yes, pause clrf PhaseIncLo ; 20 milliseconds between the notes clrf PhaseIncHi INT_ON movlw .20 call DelayNms return ; NOTE: There is no syntax checking on the header data, ; it should be formatted in the proper way !!!!!!!!!!! LoadRingToneHeader: clrf RTindex ; Index to start clrf RTsize ; Size to zero call GetRTEntry ; Read default length & octave movfw RTdata+1 andlw 0x7 movwf DefOctave rlf RTdata+1,W andlw 0x70 movwf DefLength swapf DefLength,F call GetRTEntry clrf RTTempoLo rrf RTdata,F rrf RTTempoLo,F rrf RTdata,W rrf RTTempoLo,F andlw 0x1F movwf RTTempoHi ; Hi 7 bits of Tempo movfw RTdata+1 andlw 0x3F iorwf RTTempoLo,F ; Low 6 bits of Tempo call GetRTEntry bcf RT_STACCATO ; Custom extension on Nokia btfsc RTdata,6 ; Ringtones: add a "staccato" bsf RT_STACCATO ; bit (so length only 12 bits) clrf RTsize ; For now: just 8 bits for the length rrf RTdata,F ; Because total EE size < 256 bytes rrf RTsize,F ; Actually just 80 bytes for the ringtone rrf RTdata,W rrf RTsize,F movfw RTdata+1 andlw 0x3F iorwf RTsize,F return GetRTEntry movlw low EE_RINGTONE ; Base address addwf RTindex,W ; Add index BANK1 ; BANK1 (EE registers are here) movwf EEADR ; Load address bsf EECON1,RD ; Initiate EE read movfw EEDATA BANK0 movwf RTdata incf RTindex,F btfss RTdata,7 return ; 1-byte entry BANK1 ; BANK1 (EE registers are here) incf EEADR,F ; increment address bsf EECON1,RD ; Initiate EE read movfw EEDATA BANK0 movwf RTdata+1 incf RTindex,F return ;***************************************************************************** ; NOTE: THIS VERSION IS TUNED FOR 8/10 MHZ PICS AND USES 400 KBIT I2C ;***************************************************************************** ; I^2C master send/receive routines for 24Cxxx EEPROM memory chips ; Supported chips: 24C32, 24C64, 24256 and 24C512 ; Uses 100 kHz timing when used with a 4 MHz Xtal ; ; Program 24C32.INC ; Author Wim de Vree, pe1grl@amsat.org ; Revision history ; 2003-00-00 Created from Drew Vasalov's code ; 2003-00-00 Fixed I2C 100 kHz timing, it was not according to spec ; (probably only worked on 400 kHz devices) ; 2004-09-06 Modified for larger devices (16 bit adressing mode) ; 2004-10-06 Added support for WritePage functionality ; 2005-10-31 Added support for ReadNext functionality ; Improved Start/Stop timing to meet spec. ; 2005-11-01 Added support for 20MHz X-tal freq ; 2005-11-04 Fixed delayloop for 20 MHz ; 2005-11-06 Bugfix in ReadEPROMNext (W was not cleared) ; 2006-12-30 Timing routines for 10 MHz added ; 2007-01-01 Optimized version for 10 MHz PIC and 400 kHz I2C only ; 2007-01-02 Sequential Reads added ; 2007-01-05 Delay on EE Write reduced from 10 to 7 millisecond ; (Datasheet specifies max 5 millisecond) ; 2007-??-?? Removed the delay as reloading of the next buffer ; with data takes longer than the required delay ;***************************************************************************** ; ; Some timing notes on I2C memory ; - General library: Read Random: 467 usec, Read Next: 182 usec [10MHz PIC] ; - Optimized 10Mhz: Read Random: 264 usec, Read Next: 120 usec [10MHz PIC] ; - Theoretical : Read Random: 112 usec, Read Next: 45 usec ; ; - Seq. Read : Theoretical: 22 usec, 10Mhz PIC: 52 usec ;The following defines should be created in the main program ;#define SDA TRISB, 3 ;#define SCL TRISB, 0 ;#define I2CMASK b'00001001' ;#define I2CPORT PORTB ;#define error24XX SystemFlags,4 ; Error in EE write ; ;Uses 6 Bytes in Shared Memory (0x70-0x75) ; ;USAGE: ; I2C_Init : Inits I2C datalines, no arguments ; ReadEPROM : reades a single byte, load EEE_Addr with the starting adress ; returns the result in "W" ; WriteEPROM : writes a single byte, load EEE_Addr and EEE_Byte ; WritePageEPROM : Writes multiple bytes, Load EEE_Addr, EEE_Byte with the cnt ; and FSR with the starting address ; All functions will raise the error24XX bitflag ERRORLEVEL -302 ; disable warning "register is in bank 1" ; NOTE: Eprom vars should be accesible from BANK1 (so in shared mem) CBLOCK 0x70 GenCount ; generic counter/temp register (use with caution) EEE_AddrHi ; EEPROM memory address to be accessed EEE_AddrLo ; EEPROM memory address to be accessed EEE_CS ; I2C chip select adress EEE_Byte ; DataByte read/written from/to EEPROM is stored in this register OutputByte ; used for holding byte to be output to EEPROM flags ; flag bit register ENDC ;------ Define port pins: RB2=SDA=data, RB1=SCL=clock ;------ Pins are connected via 4.7K pullup resistors for passive control ;------ Any port pins can be used. ; SelectEPROM sets the 65K bank to use. ; Please note: ; For 512K memory chips from MicroChip: ; BANK0 is I2C chip address 0x04 ; For 512K memory chips from Atmel ; BANK0 is I2C chip address 0x00 ; For 1024K memory chips from ATMEL: ; BANK0 is I2C chip address 0x04 ; BANK1 is I2C chip address 0x05 ; For 1024K memory chips from MicroChip: ; BANK0 is I2C chip address 0x04 ; BANK1 is I2C chip address 0x00 ; This is to support 512K and 1M chips, for the 1M chip from Microchip ; addressline A2 should be tied to +5 Volt for the ATMEL version this is ; a NC pin and the same hardware can now be used for both chips. SelectEPROM movwf TEMP ; Bit 17..23 of memory adress movfw I2CBank0 ; Adres of first 64K bank btfsc TEMP,0 ; Only bit17 is used movfw I2CBank1 ; Adres of second 64K bank movwf EEE_CS movfw TEMP return ; Call with: EEPROM address in EEE_AddrHi and EEE_AddrLo ; Returns with: byte in Data_Buf ReadEPROM bsf STATUS, RP0 ; select Bank 1 for TRISB access (passive SCL/SDA control) call I2C_Start movfw EEE_CS ; Get EE chip address andlw 0xFE ; send "dummy" write to set address call Byte_Out btfsc flags,0 goto Error_Routine ; NOTE: MUST USE "RETURN" FROM THERE movfw EEE_AddrHi call Byte_Out btfsc flags, 0 goto Error_Routine movfw EEE_AddrLo call Byte_Out btfsc flags, 0 goto Error_Routine bcf SCL ; pull clock line low in preparation for 2nd START bit call I2C_Start movfw EEE_CS iorlw 0x01 ; request data read from EPROM call Byte_Out btfsc flags, 0 goto Error_Routine ;------ Note that Byte_Out leaves with SDA line freed to allow slave to send data in to master. call Byte_In call I2C_Stop movfw EEE_Byte ; put result into W register for returning to CALL bcf STATUS, RP0 ; leave with Bank 0 active as default return ; Call with: EEPROM address in EEE_AddrHi and EEE_AddrLo ; Returns with: byte in Data_Buf, does not issue a stop ; condition, so sequential reads are possible ReadMultiEPROM bsf STATUS, RP0 ; select Bank 1 for TRISB access (passive SCL/SDA control) call I2C_Start movfw EEE_CS ; Get EE chip address andlw 0xFE ; send "dummy" write to set address call Byte_Out btfsc flags,0 goto Error_Routine ; NOTE: MUST USE "RETURN" FROM THERE movfw EEE_AddrHi call Byte_Out btfsc flags, 0 goto Error_Routine movfw EEE_AddrLo call Byte_Out btfsc flags, 0 goto Error_Routine bcf SCL ; pull clock line low in preparation for 2nd START bit call I2C_Start movfw EEE_CS iorlw 0x01 ; request data read from EPROM call Byte_Out btfsc flags, 0 goto Error_Routine ;------ Note that Byte_Out leaves with SDA line freed to allow slave to send data in to master. call Byte_In call I2C_Ack bcf STATUS, RP0 ; leave with Bank 0 active as default movfw EEE_Byte ; put result into W register for returning to CALL return ; Sequential reading: acknowledge with an ACK (needs ReadMulti before to setup seq. reading) ReadSeqEPROM bsf STATUS, RP0 ; select Bank 1 for TRISB access (passive SCL/SDA control) call Byte_In call I2C_Ack movfw EEE_Byte ; put result into W register for returning to CALL bcf STATUS, RP0 ; leave with Bank 0 active as default return ; Sequential reading: Stop reading (acknowledge with a STOP condition) ReadLastSeqEPROM bsf STATUS, RP0 ; select Bank 1 for TRISB access (passive SCL/SDA control) call Byte_In call I2C_Stop movfw EEE_Byte ; put result into W register for returning to CALL bcf STATUS, RP0 ; leave with Bank 0 active as default return ; Returns with: byte in Data_Buf ReadNextEPROM bsf STATUS, RP0 ; select Bank 1 for TRISB access (passive SCL/SDA control) call I2C_Start movfw EEE_CS iorlw 0x01 ; request data read from EPROM call Byte_Out btfsc flags, 0 goto Error_Routine ;------ Note that Byte_Out leaves with SDA line freed to allow slave to send data in to master. call Byte_In call I2C_Stop movfw EEE_Byte ; put result into W register for returning to CALL bcf STATUS, RP0 ; leave with Bank 0 active as default return ; WritePageEPROM ; Call with: EEPROM starting adres in EEE_ADDR ; Count in EEE_Byte ; Source starts at location pointed by FSR ; Returns with: nothing, but an Error flag can be raised WritePageEPROM bsf STATUS, RP0 ; select Bank 1 for TRISB access (passive SCL/SDA control) call I2C_Start movfw EEE_CS ; Get EE chip address andlw 0xFE ; send write to set address call Byte_Out btfsc flags, 0 goto Error_Routine ; NOTE: MUST USE "RETURN" FROM THERE movfw EEE_AddrHi call Byte_Out btfsc flags, 0 goto Error_Routine movfw EEE_AddrLo call Byte_Out btfsc flags, 0 goto Error_Routine WriteLoop movfw INDF ; move data to be sent to W call Byte_Out btfsc flags, 0 goto Error_Routine incf FSR,F decfsz EEE_Byte,F ; Misused as a counter here goto WriteLoop call I2C_Stop bcf STATUS, RP0 ; leave with Bank 0 active by default ; movlw .7 ; COMMENTED OUT FOR ARDF PROGRAM ; call DelayNms ; 10ms delay max. required for EPROM write cycle return ;------ This routine reads one byte of data from the EPROM into Data_Buf Byte_In clrf EEE_Byte movlw 0x08 ; 8 bits to receive movwf GenCount ControlIn rlf EEE_Byte,F ; shift bits into buffer bcf SCL ; pull clock line low nop ; Meet I2C timing specs nop bsf SCL ; pull clock high to read bit bcf STATUS, RP0 ; select Bank 0 to read PORTB bits directly! btfss SDA ; test bit from EPROM (if bit=clear, skip because Data_Buf is clear) goto $+2 bsf EEE_Byte, 0 ; read bit into 0 first, then eventually shift to 7 bsf STATUS, RP0 ; Back to Bank 1 decfsz GenCount,F goto ControlIn return ;------ This routine sends out the byte in the W register and then waits for ACK from EPROM (256us timeout period) Byte_Out movwf OutputByte movlw 0x08 ; 8 bits to send movwf GenCount rrf OutputByte,F ; shift right in preparation for next loop ControlOut rlf OutputByte,F ; shift bits out of buffer bcf SCL ; pull clock line low btfsc OutputByte, 7 ; send current "bit 7" goto BitHigh bcf SDA goto ClockOut BitHigh bsf SDA nop ClockOut bsf SCL ; pull clock high after sending bit decfsz GenCount,F goto ControlOut nop bcf SCL ; pull clock low for ACK change nop bsf SDA ; free up SDA line for slave to generate ACK nop ; wait for slave to pull down ACK bsf SCL ; pull clock high for ACK read clrf GenCount ; reuse as a timeout counter (to 256 [2ms]) to test for ACK WaitForACK bsf STATUS, RP0 ; select Bank1 for GenCount access incf GenCount,F ; increase timeout counter each time ACK is not received bz No_ACK_Rec bcf STATUS, RP0 ; select Bank0 to test SDA PORTB input directly! btfsc SDA ; test pin. If clear, EEPROM is pulling SDA low for ACK goto WaitForACK ; ...otherwise, continue to wait bsf STATUS, RP0 ; select Bank1 as default during these routines bcf flags, 0 ; clear flag bit (ACK received) return ;------ No ACK received from slave (must use "return" from here) ;; Typically, set a flag bit to indicate failed write and check for it upon return. No_ACK_Rec bsf flags, 0 ; set flag bit return ; returns to Byte_Out routine (Bank 1 selected)\ ;------- Send I2C start signal I2C_Start bsf SDA ; pull data line high - data transition during clock low NOP3 ; To meet data setup time bsf SCL ; pull clock line high to begin generating START NOP3 ; Comply with spec bcf SDA ; 2nd START - data line low return ;------- Send I2C stop signal I2C_Stop bcf SCL ; extra cycle for SDA line to be freed NOP3 ; To meet I2C spec bcf SDA ; ensure SDA line low before generating STOP NOP3 ; To meet I2C spec bsf SCL ; pull clock high for STOP NOP3 ; To meet I2C spec bsf SDA ; STOP - data line high return ;=============================================================================== I2C_Init bcf STATUS,RP0 clrf flags ; clear I2C error flag movfw I2CPORT ; for EEPROM operation, andlw ~I2CMASK ; load zero into SDA and SCL movwf I2CPORT ; for passive control of bus bsf STATUS,RP0 NOP2 bsf SDA NOP2 bsf SCL bcf STATUS,RP0 return I2C_Ack bcf SCL ; Pull Clock Low nop ; To meet I2C spec bcf SDA ; Pull SDA Low (Acknowledge) nop ; To meet I2C spec bsf SCL ; pull clock high for acknowledge NOP2 bcf SCL ; nop bsf SDA ; Release SDA line return ;=============================================================================== ; I2C_Reset ensures a software reset of I2C devices: ; 1) Send START bit 2) Send 9 "1" bits 3) Send START bit 4) Send STOP bit ; For more info see Microchip appnote AN709 or Atmel AT24C1024 Datasheet ;=============================================================================== I2C_Reset bsf STATUS, RP0 ; select Bank 1 for TRISB access call I2C_Start bcf SCL ; Clock low NOP3 bsf SDA ; Data high movlw .9 ; 9 '1' bits to send movwf GenCount _rstloop bsf SCL NOP3 bcf SCL NOP3 decfsz GenCount,F goto _rstloop call I2C_Start call I2C_Stop bcf STATUS,RP0 ; Select Bank 0 return ;------ No ACK received from slave. This is the error handler. Error_Routine bcf STATUS, RP0 ; select Bank0 as default before returning home #ifdef ErrorCounter incf ErrorCounter,F ; Error occured #endif #ifdef error24XX bsf error24XX ; Raise serial eeprom error #endif return ; returns to INITIAL calling routine ;---------------------------------------------------------------------------- ; Delay N milliseconds, range 1-255 msec. ; This routine uses hardware timer TMR0 as due to all the interrupts ; (WAV generation takes 60% CPU, DDS 20% CPU in interrupts) a software ; loop will be very inaccurate. Side effect: BANK0 should be the current ; selected bank ;---------------------------------------------------------------------------- DelayNms movwf GenCount clrf TMR0 Delay_Start bcf INTCON,T0IF movlw .6 ; Preload TMR0 for 1millisecond addwf TMR0,F ; it does 1 tick / 4 usec (prescaler) btfss INTCON,T0IF goto $-1 decfsz GenCount, F goto Delay_Start return ERRORLEVEL +302 ; enable warning "register is in bank1" ;---------------------------------------------------------------------------- ; CW lookuptable, replaces an ASCII char between 0x20 and 0x5F with its ; equivalent in Morse. The bits are processed right to left, a 0 indicates ; a "dot", a 1 a "dash" and are filled with an extra 1 bit to indicate the ; end of the character. Table is kept at the end of the Flash memory ;---------------------------------------------------------------------------- org 0x780 CW_Table addlw 0xE0 ; Offset ASCII 0x20 becomes 0x00 andlw 0x3F ; Keep in table addwf PCL,F dt b'00000000' ; 0x20 ' ' dt b'00000010' ; 0x21 '!' Used for MOE (1 dot) dt b'00000100' ; 0x22 '"' Used for MOI (2 dots) dt b'00001000' ; 0x23 '#' Used for MOS (3 dots) dt b'00010000' ; 0x24 '$' Used for MOH (4 dots) dt b'00100000' ; 0x25 '%' Used for MO5 (5 dots) dt b'01000000' ; 0x26 '&' Used for MO? (6 dots) dt b'10000000' ; 0x27 ''' Used for MO? (7 dots) dt b'00011111' ; 0x28 '(' Special ---- dt b'00111111' ; 0x29 ')' Special ----- dt b'01111111' ; 0x2A '*' Special ------ dt b'11111111' ; 0x2B '+' Special ------- dt b'01110011' ; 0x2C ',' --..-- dt b'00000000' ; 0x2D '-' dt b'01101010' ; 0x2E '.' .-.-.- dt b'00101001' ; 0x2F '/' -..-. dt b'00111111' ; 0x30 '0' ----- dt b'00111110' ; 0x31 '1' .---- dt b'00111100' ; 0x32 '2' ..--- dt b'00111000' ; 0x33 '3' ...-- dt b'00110000' ; 0x34 '4' ....- dt b'00100000' ; 0x35 '5' ..... dt b'00100001' ; 0x36 '6' -.... dt b'00100011' ; 0x37 '7' --... dt b'00100111' ; 0x38 '8' ---.. dt b'00101111' ; 0x39 '9' ----. dt b'01000111' ; 0x3A ':' ---... dt b'01010101' ; 0x3B ';' -.-.-. dt b'00000000' ; 0x3C '<' dt b'00000000' ; 0x3D '=' dt b'00000000' ; 0x3E '>' dt b'01001100' ; 0x3F '?' ..--.. dt b'01010110' ; 0x40 '@' .--.-. dt b'00000110' ; 0x41 'A' .- dt b'00010001' ; 0x42 'B' -... dt b'00010101' ; 0x43 'C' -.-. dt b'00001001' ; 0x44 'D' -.. dt b'00000010' ; 0x45 'E' . dt b'00010100' ; 0x46 'F' ..-. dt b'00001011' ; 0x47 'G' --. dt b'00010000' ; 0x48 'H' .... dt b'00000100' ; 0x49 'I' .. dt b'00011110' ; 0x4A 'J' .--- dt b'00001101' ; 0x4B 'K' -.- dt b'00010010' ; 0x4C 'L' .-.. dt b'00000111' ; 0x4D 'M' -- dt b'00000101' ; 0x4E 'N' -. dt b'00001111' ; 0x4F 'O' --- dt b'00010110' ; 0X50 'P' .--. dt b'00011011' ; 0x51 'Q' --.- dt b'00001010' ; 0x52 'R' .-. dt b'00001000' ; 0x53 'S' ... dt b'00000011' ; 0x54 'T' - dt b'00001100' ; 0x55 'U' ..- dt b'00011000' ; 0x56 'V' ...- dt b'00001110' ; 0x57 'W' .-- dt b'00011001' ; 0x58 'X' -..- dt b'00011101' ; 0x59 'Y' -.-- dt b'00010011' ; 0x5A 'Z' --.. dt b'10101010' ; 0x5B '[' Special .-.-.-. dt b'00000000' ; 0x5C '\' dt b'11010101' ; 0x5D ']' Special -.-.-.- dt b'00000000' ; 0x5E '^' dt b'00000000' ; 0x5F unused GetRTFreqHi: andlw 0x0F ; Keep in table addwf PCL,F dt 0x00 ; Pauze 0 Hz dt 0x39 ; A 1760 Hz - 14723 dt 0x3C ; A# 1865 Hz - 15602 dt 0x40 ; B 1976 Hz - 16530 dt 0x44 ; C 2093 Hz - 17509 dt 0x48 ; C# 2218 Hz - 18555 dt 0x4C ; D 2349 Hz - 19651 dt 0x51 ; D# 2489 Hz - 20822 dt 0x56 ; E 2736 Hz - 22060 dt 0x5B ; F 2794 Hz - 23373 dt 0x60 ; F# 2960 Hz - 24762 dt 0x66 ; G 3136 Hz - 26234 dt 0x6C ; G# 3320 Hz - 27774 GetRTFreqLo: addwf PCL,F dt 0x00 ; Pauze 0Hz dt 0x83 ; A 1760 Hz - 14723 dt 0xF2 ; A# 1865 Hz - 15602 dt 0x92 ; B 1976 Hz - 16530 dt 0x65 ; C 2093 Hz - 17509 dt 0x7B ; C# 2218 Hz - 18555 dt 0xC3 ; D 2349 Hz - 19651 dt 0x56 ; D# 2489 Hz - 20822 dt 0x2C ; E 2736 Hz - 22060 dt 0x4D ; F 2794 Hz - 23373 dt 0xBA ; F# 2960 Hz - 24762 dt 0x7A ; G 3136 Hz - 26234 dt 0x7E ; G# 3320 Hz - 27774 ;***************************************************************************** ; EEPROM contents: Keeps some user settings ;***************************************************************************** ; EE layout: ; 16 bytes for configuration info ; 16 bytes for sequenced transmission ; 16 bytes for CW text message ; 16 bytes spare ; 80 bytes for tone sequences and ringtones ;***************************************************************************** org 0x2100 ; Room for 16 byte configuration data EE_CFG de 0x10 ; Various Option bits de 0 ; More Option bits de 0 ; Initial transmitting delay in minutes de 6 ; CycleDelay in 10second units (1min) de 0 ; CycleID of transmitter de 2 ; Nr. of transmitters in cycle de 0x00,0x10 ; DDS Phase increment for single tone de .240 ; Delay after which to stop transmission (4hrs) de 0x00 ; Oscillator tune value de .200 ; 'Dit' delay for CW (100 = 12WPM) de 0,0 ; reserved for future expansion de 0x00,0x00,0x00 ; Length of Wave File (24bit) EE_TXSEQ ; MAX 8 entries de 1, b'10000001' ; 10 seconds EFFECT modulation 1 de 1, b'01000001' ; 10 seconds CW modulation 2 de 1, b'00000000' ; 10 seconds OFF 3 de 0,0 ; unused 4 de 0,0 ; unused 5 de 0,0 ; unused 6 de 0,0 ; unused 7 de 0,0 ; unused 8 EE_CWTXT de "PE1GRL TST ",0 ; CW message, terminated with 0 EE_TSEQ org 0x2140 ; Tone Sequences, Max 16 pairs de 0x05,0x12,0x0D ; Duration / Phase Inc Low, Hi 1 de 0x0A,0x9B,0x13 ; Duration / Phase Inc Low, Hi 2 de 0x0F,0x24,0x1A ; Duration / Phase Inc Low, Hi 3 de 0x14,0xAE,0x20 ; Duration / Phase Inc Low, Hi 4 de 0x19,0x37,0x27 ; Duration / Phase Inc Low, Hi 5 de 0x1E,0xC0,0x2D ; Duration / Phase Inc Low, Hi 6 de 0x23,0x49,0x34 ; Duration / Phase Inc Low, Hi 7 de 0x28,0xC0,0x2D ; Duration / Phase Inc Low, Hi 8 de 0x2D,0x37,0x27 ; Duration / Phase Inc Low, Hi 9 de 0x32,0xAE,0x20 ; Duration / Phase Inc Low, Hi 10 de 0x37,0x24,0x1A ; Duration / Phase Inc Low, Hi 11 de 0x3C,0x9B,0x13 ; Duration / Phase Inc Low, Hi 12 de 0,0,0 ; Duration / Phase Inc Low, Hi 13 de 0,0,0 ; Duration / Phase Inc Low, Hi 14 de 0,0,0 ; Duration / Phase Inc Low, Hi 15 de 0,0,0 ; Duration / Phase Inc Low, Hi 16 ; DEFAULT RINGTONE "If I were a rich man" ; Rikasmiesjos:d=8,o=5,b=320:g,f,g,f,4e,4c,4p,e,f,g,f,g,f,e,f,g,a,a#,a,a#, ; a,4g,4p,4g#,4g,4f#,4f,d#,d,c,d,4d#,4p,d#,d,c,d,4d#,4c,4g,4p EE_RINGTONE org 0x2180 ; Max 128 bytes de 0x80,0xA2 ; Header, defaults de 0x97,0xDC ; Header, tempo de 0x80,0x7E ; Header, length de 0x0B,0x09,0x0B,0x09,0xA8,0x18,0xA4,0x18 de 0xA0,0x18,0x08,0x09,0x0B,0x09,0x0B,0x09 de 0x08,0x09,0x0B,0x01,0x02,0x01,0x02,0x01 de 0xAB,0x18,0xA0,0x18,0xAC,0x18,0xAB,0x18 de 0xAA,0x18,0xA9,0x18,0x07,0x06,0x04,0x06 de 0xA7,0x18,0xA0,0x18,0x07,0x06,0x04,0x06 de 0xA7,0x18,0xA4,0x18,0xAB,0x18,0xA0,0x18 END