'******************************************************************************* '* Name : SI470X.PBP * '* Author : Darrel Taylor * '* Date : 6/30/2012 * '* Version : 1.1 * '* Notes : For use with the Si4703 radio IC and PicBasic Pro V.3.0.6.x * '* : http://support.melabs.com/threads/280 * '******************************************************************************* '* Options : Note that they are #DEFINE instead of just DEFINE '* #DEFINE USE_RDS ; enable ALL RDS functions '* #DEFINE USE_TIME '* #DEFINE USE_GENRE ; decodes PTY (program type), Rock Country etc '* #DEFINE USE_RADIOTEXT ; decodes song title, station ID '* #DEFINE USE_PACKETTRACK ; Packet tracking (gives Complete indication) '* #DEFINE RDS_MAXERRORS 2 ; 0=best text(slower), 3=bad text(faster) '* #DEFINE CLEARTEXT_ONCHANGE '* '* Commands '* SI470X_INITIALIZE ; Initialize the Radio chip '* SI470X_GET ; Reads all registers '* SI470X_GETSTATUS ; Reads only statusrssi and readchan '* SI470X_UPDATE ; Write all writable registers '* SI470X_VOLUME() ; UP, DN or 0-15 '* SI470X_TUNE() ; in Mhz*10, 943 = 94.3Mhz '* SI470X_SEEK() ; UP, DN '* SI470X_REGION() ; USA, Europe, Australia, Japan, JapanWide '* SI470X_SEEKSNR() ; 0=disabled, 1=most stops, 7=fewest stops '* SI470X_SEEKIMP() ; 0=disabled, 1=most stops, 15=fewest stops '* SI470X_SPACE() ; 0=200khz, 1=100khz, 2=50khz '* SI470X_BAND() ; 0=87.5-108, 1=76-108, 2=76-90, 3=reserved '* SI470X_SOFTMUTEATTACK() ; 0=fastest, 3=slowest '* SI470X_SOFTMUTEATTEN() ; 0=16dB, 1=14dB, 2=12dB, 3=10dB '* '* Variables '* SI470X_CURRENTVOLUME '* SI470X_CURRENTBAND '* SI470X_CURRENTSPACE '* SI470X_CURRENTFREQUENCY '* SI470X_CURRENTRSSI '* SI470X_MINFREQUENCY '* SI470X_MAXFREQUENCY '* '* '* Subroutines '* SI470X_INIT : Reset the Radio, Power it up, and read all registers '* SI470X_WRITE : Writes registers 2-7 '* SI470X_Read : Reads all registers '* '* I2C_ERROR flag is set if there is no ACK from the radio. '******************************************************************************* '* For more information about this module, go to ... '* http://support.melabs.com/threads/280 '* '* Get the Si4073 datasheet from Silicon Labs '* http://www.silabs.com/products/audiovideo/fmreceivers/Pages/Si470203.aspx '******************************************************************************* INCLUDE "MODULES.pbpmod" : CHECK_VERSION $10 ; requires MODULES ver. 1.0 DEFINE I2C_HOLD 1 ;----[Si470X Registers]----------------------------------------------------- Si_REGS VAR WORD[16] deviceid VAR Si_REGS[0] ' Read Only chipid VAR Si_REGS[1] ' Read Only powercfg VAR Si_REGS[2] ' R/W DSMUTE VAR powercfg.15 DMUTE VAR powercfg.14 MONO VAR powercfg.13 RDSM VAR powercfg.11 SKMODE VAR powercfg.10 SEEKUP VAR powercfg.9 SEEK VAR powercfg.8 SiDISABLE VAR powercfg.6 SiENABLE VAR powercfg.0 channel VAR Si_REGS[3] ' R/W TUNE VAR channel.15 sysconfig1 VAR Si_REGS[4] ' R/W RDSIEN VAR sysconfig1.15 STCIEN VAR sysconfig1.14 RDS VAR sysconfig1.12 DE VAR sysconfig1.11 AGCD VAR sysconfig1.10 sysconfig2 VAR Si_REGS[5] ' R/W sysconfig3 VAR Si_REGS[6] ' R/W test1 VAR Si_REGS[7] ' R/W XOSCEN VAR test1.15 AHIZEN VAR test1.14 test2 VAR Si_REGS[8] ' R/W, Reserved bootconfig VAR Si_REGS[9] ' R/W, Reserved statusrssi VAR Si_REGS[10] ' Read Only RDSR VAR statusrssi.15 STC VAR statusrssi.14 SF_BL VAR statusrssi.13 AFCRL VAR statusrssi.12 RDSS VAR statusrssi.11 ST VAR statusrssi.8 readchan VAR Si_REGS[11] ' Read Only rdsa VAR Si_REGS[12] ' Read Only rdsb VAR Si_REGS[13] ' Read Only rdsc VAR Si_REGS[14] ' Read Only rdsd VAR Si_REGS[15] ' Read Only set_freq VAR word I2C_ERROR VAR BIT UP CON $81 DN CON $80 DOWN CON $80 USA CON 0 Europe CON 1 Australia CON 2 Japan CON 3 JapanWide CON 4 SI470X_CURRENTVOLUME VAR BYTE SI470X_CURRENTBAND VAR BYTE SI470X_CURRENTSPACE VAR BYTE SI470X_CURRENTFREQUENCY VAR WORD SI470X_CURRENTRSSI VAR BYTE SI470X_MINFREQUENCY VAR WORD SI470X_MAXFREQUENCY VAR WORD SI470X_TempB VAR BYTE SI470X_TempW VAR WORD #IFDEF USE_RDS LastRDSR VAR BIT #IFDEF USE_GENRE GENRE VAR BYTE[8] PTY VAR BYTE LASTPTY VAR BYTE GENRE_CHANGED VAR BIT #ENDIF #IFDEF USE_RADIOTEXT RADIOTEXT VAR BYTE[64] RADIOTEXT_CHANGED VAR BIT RADIOTEXT_LENGTH VAR BYTE RDS_LENGTH4 VAR BYTE RDS_Idx VAR BYTE RADIOTEXT_MAXERRORS VAR BYTE RDS_ERRCOUNT VAR BYTE #IFDEF USE_PACKETTRACK RadioTextErrors VAR BYTE[32] RadioText_Complete VAR BIT #ENDIF ; USE_PACKETTRACK #ENDIF ; USE_RADIOTEXT #IFDEF USE_TIME RDS_TIME VAR BYTE[4] RDS_TIME_CHANGED VAR BIT RDS_TIME_CHANGED = 0 #ENDIF ; USE_TIME #ENDIF ; USE_RDS #IFDEF USE_RDS @ #DEFINE RDS_LED_OK ; OK to use RDS_LED if specified #IFDEF USE_RADIOTEXT #IFNDEF RDS_MAXERRORS #IFNDEF USE_PACKETTRACK #DEFINE RDS_MAXERRORS 0 ; default to 0 errors if not defined #ELSE #DEFINE RDS_MAXERRORS 1 ; unless tracking packets, 0 not allowed #ENDIF #ENDIF #IFDEF USE_PACKETTRACK ; if using Packet Tracking RADIOTEXT_MAXERRORS = 2 #ELSE #IF RDS_MAXERRORS = 0 ; transfer #DEFINE to PBP var RADIOTEXT_MAXERRORS = 0 #ENDIF #IF RDS_MAXERRORS = 1 RADIOTEXT_MAXERRORS = 1 #ENDIF #IF RDS_MAXERRORS = 2 RADIOTEXT_MAXERRORS = 2 #ENDIF #IF RDS_MAXERRORS = 3 RADIOTEXT_MAXERRORS = 3 #ENDIF #ENDIF #ENDIF #ENDIF ASM variable ON = 1 variable OFF = 0 variable ENABLE = 1 variable DISABLE = 0 ifndef enable variable Enable = 1 variable enable = 1 variable Disable = 0 variable disable = 0 endif ifdef _STEREO_LED ; if STEREO_LED is used LOW?T _STEREO_LED ; set to OUTPUT LOW endif ifdef RDS_LED_OK ifdef _RDS_LED ; if RDS_LED is used LOW?T _RDS_LED ; set to OUTPUT LOW endif endif ENDASM GOTO Over_SiSUBs ;----[Write to Radio's Registers]------------------------------------------- USERCOMMAND "SI470X_UPDATE" SI470X_WRITE: I2C_ERROR = 0 i2cwrite Si470X_sda,Si470X_scl,$20,[Si_REGS(2),Si_REGS(3),Si_REGS(4), _ Si_REGS(5),Si_REGS(6),Si_REGS(7)],SiError ;,Si_REGS(8),Si_REGS(9)] ; 8 and 9 are reserved RETURN ; the rest are read-only ASM SI470X_UPDATE? macro L?CALL _SI470X_WRITE endm ENDASM ;----[Update LED states for RDS and STEREO]------------------------------------- USERCOMMAND "SI470X_UPDATE_LEDS" ASM ifndef _LED_POLARITY #DEFINE _LED_POLARITY 1 ; default to Active HIGH endif SI470X_UPDATE_LEDS? macro local STEREO_LED_NoChange, RDS_LED_NoChange ifdef _STEREO_LED ; if STEREO_LED is used if (_LED_POLARITY == 1) CMPEQ?TTL _STEREO_LED, _ST, STEREO_LED_NoChange MOVE?TT _ST, _STEREO_LED else CMPNE?TTL _STEREO_LED, _ST, STEREO_LED_NoChange MOVE?TT _ST, _LED_POL_TEMP BIT?FLIP _LED_POL_TEMP MOVE?TT _LED_POL_TEMP, _STEREO_LED endif STEREO_LED_NoChange endif ifdef RDS_LED_OK ifdef _RDS_LED ; if RDS_LED is used if (_LED_POLARITY == 1) CMPEQ?TTL _RDS_LED, _RDSS, RDS_LED_NoChange ; MOVE?TT _RDSS, _RDS_LED else CMPNE?TTL _RDS_LED, _RDSS, RDS_LED_NoChange MOVE?TT _RDSS, _LED_POL_TEMP BIT?FLIP _LED_POL_TEMP MOVE?TT _LED_POL_TEMP, _RDS_LED endif endif RDS_LED_NoChange endif endm ENDASM ;----[Read ALL Radio Registers]--------------------------------------------- USERCOMMAND "SI470X_GET" SI470X_READ: I2C_ERROR = 0 i2cread Si470X_sda,Si470X_scl,$20,[Si_REGS(10),Si_REGS(11),Si_REGS(12), _ Si_REGS(13),Si_REGS(14),Si_REGS(15),Si_REGS(0), _ Si_REGS(1),Si_REGS(2),Si_REGS(3),Si_REGS(4),Si_REGS(5), _ Si_REGS(6),Si_REGS(7),Si_REGS(8),Si_REGS(9)],SiError SI470X_CURRENTVOLUME = sysconfig2 & $0F SI470X_CURRENTRSSI = statusrssi & $FF SI470X_CURRENTSPACE = (sysconfig2 >> 4) & %11 SI470X_CURRENTBAND = (sysconfig2 >> 6) & %11 SI470X_CURRENTFREQUENCY = (readchan & $1FF) IF SI470X_CURRENTSPACE = %00 THEN SI470X_CURRENTFREQUENCY = SI470X_CURRENTFREQUENCY * 2 ; 200khz ELSEIF SI470X_CURRENTSPACE = %10 THEN SI470X_CURRENTFREQUENCY = SI470X_CURRENTFREQUENCY / 2 ; 50khz ENDIF IF SI470X_CURRENTBAND = %00 THEN ; 87.5–108 MHz (USA, Europe) SI470X_CURRENTFREQUENCY = SI470X_CURRENTFREQUENCY + 875 SI470X_MINFREQUENCY = 875 SI470X_MAXFREQUENCY = 1081 ELSEIF SI470X_CURRENTBAND = %01 THEN ; 76–108 MHz (Japan wide band) SI470X_CURRENTFREQUENCY = SI470X_CURRENTFREQUENCY + 760 SI470X_MINFREQUENCY = 760 SI470X_MAXFREQUENCY = 1080 ELSEIF SI470X_CURRENTBAND = %10 THEN ; 76–90 MHz (Japan) SI470X_CURRENTFREQUENCY = SI470X_CURRENTFREQUENCY + 760 SI470X_MINFREQUENCY = 760 SI470X_MAXFREQUENCY = 900 ; ELSEIF SI470X_CURRENTBAND = %11 THEN ; Reserved ENDIF SI470X_UPDATE_LEDS RETURN ASM SI470X_GET? macro L?CALL _SI470X_READ endm ENDASM ;----[read only STATUSRSSI and READCHAN]------------------------Optimizes------- USERCOMMAND "SI470X_GETSTATUS" ASM Expand_SI470X_STAT macro ifndef SI470X_STAT_Expanded #define SI470X_STAT_Expanded ENDASM GOTO Over_Stat SI470X_STAT: I2C_ERROR = 0 i2cread Si470X_sda,Si470X_scl,$20,[Si_REGS(10),Si_REGS(11)] SI470X_UPDATE_LEDS RETURN Over_Stat: ASM endif endm SI470X_GETSTATUS? macro Expand_SI470X_STAT L?CALL _SI470X_STAT endm ENDASM ;----[Set error flag if I2C not acknowledged]----------------------------------- SiError: I2C_ERROR = 1 RETURN ;----[Clear RADIOTEXT array - fill with spaces]--------------------------------- #IFDEF USE_RDS #IFDEF USE_RADIOTEXT USERCOMMAND "RADIOTEXT_CLEAR" RADIOTEXT_CLEAR_CODE: ARRAYWRITE RadioText,[REP " "\64] ; clear RadioText array RETURN ASM RADIOTEXT_CLEAR? macro L?CALL _RADIOTEXT_CLEAR_CODE endm ENDASM #ENDIF ; USE_RADIOTEXT #ENDIF ; USE_RDS ;----[Initialize Si470X Radio]-------------------------------------------------- USERCOMMAND "SI470X_INITIALIZE" SI470X_INIT: LOW Si470X_SDA ; start with SDA LOW PAUSE 1 LOW Si470X_RST ; reset the device PAUSE 1 INPUT Si470X_RST ; release reset PAUSE 1 INPUT Si470X_SDA ; release SDA SI470X_GET ; read all registers XOSCEN = 1 ; turn on 32khz oscillator SI470X_UPDATE pause 500 ; wait for crystal to setup SI470X_GET ; read all registers DMUTE = 1 ; Mute Disable SiEnable = 1 ; Powerup Enable SI470X_UPDATE pause 150 SI470X_GET #IFDEF USE_RDS RDS = 1 ; enable RDS RDSM = 1 ; Verbose Mode #IFDEF USE_RDS_INTERRUPTS RDSIEN = 1 ; enable RDS Interrupts sysconfig1.3 = 0 ; SI470X_GPIO2 is STC/RDS interrupt sysconfig1.2 = 1 #ENDIF SI470X_UPDATE #IFDEF USE_RADIOTEXT RADIOTEXT_CLEAR ; clear the radiotext beffur RADIOTEXT_Changed = 1 ; indicate text has changed #IFDEF USE_PACKETTRACK ; if using packet tracking RadioText_Complete = 0 ; indicate radiotext capture is not complete #ENDIF #ENDIF #ENDIF RETURN ASM SI470X_INITIALIZE? macro L?CALL _SI470X_INIT endm ENDASM ;----[Set channel spacing]------------------------------------------------------ USERCOMMAND "SI470X_SPACE" ; 0=200khz, 1=100khz, 2=50khz ASM SI470X_SPACE?C macro Cspc L?CALL _SI470X_READ MOVE?CT Cspc >> 1, _sysconfig2,5 MOVE?CT Cspc, _sysconfig2 + 1,4 L?CALL _SI470X_WRITE endm SI470X_SPACE?B macro Bspc L?CALL _SI470X_READ MOVE?TT Bspc,1, _sysconfig2,5 MOVE?TT Bspc,0, _sysconfig2,4 L?CALL _SI470X_WRITE endm SI470X_SPACE?W macro Wspc L?CALL _SI470X_READ MOVE?TT Wspc,1, _sysconfig2,5 MOVE?TT Wspc,0, _sysconfig2,4 L?CALL _SI470X_WRITE endm SI470X_SPACE?N macro Nspc L?CALL _SI470X_READ MOVE?TT Nspc,1, _sysconfig2,5 MOVE?TT Nspc,0, _sysconfig2,4 L?CALL _SI470X_WRITE endm ENDASM ;----[Select frequency range]--------------------------------------------------- USERCOMMAND "SI470X_BAND" ; 0=87.5-108, 1=76-108, 2=76-90, 3=reserved ASM SI470X_BAND?C macro Cband L?CALL _SI470X_READ MOVE?CT Cband >> 1, _sysconfig2, 7 MOVE?CT Cband, _sysconfig2 + 1, 6 L?CALL _SI470X_WRITE endm SI470X_BAND?B macro Bband L?CALL _SI470X_READ MOVE?TT Bband,1, _sysconfig2, 7 MOVE?TT Bband,0, _sysconfig2, 6 L?CALL _SI470X_WRITE endm SI470X_BAND?W macro Wband L?CALL _SI470X_READ MOVE?TT Wband,1, _sysconfig2, 7 MOVE?TT Wband,0, _sysconfig2, 6 L?CALL _SI470X_WRITE endm SI470X_BAND?N macro Nband L?CALL _SI470X_READ MOVE?TT Nband,1, _sysconfig2, 7 MOVE?TT Nband,0, _sysconfig2, 6 L?CALL _SI470X_WRITE endm ENDASM ;----[Set Region radio is used in]---------------------------------------------- USERCOMMAND "SI470X_REGION" ; 0=USA, 1=Europe, 2=Australia ASM ; 3=Japan, 4=JapanWide Expand_SI470X_SETREGION macro ifndef SI470X_SETREGION_Expanded #define SI470X_SETREGION_Expanded ENDASM GOTO Over_SETREGION SI470X_SETREGION: SELECT CASE SI470X_TempB CASE Europe SI470X_BAND(0) ; 87.5-108 Mhz SI470X_SPACE(1) ; 100 Khz CASE Japan SI470X_BAND(2) ; 76-90 Mhz SI470X_SPACE(1) ; 100 Khz CASE JapanWide SI470X_BAND(1) ; 76-108 Mhz SI470X_SPACE(1) ; 100 Khz CASE ELSE ;USA, Australia SI470X_BAND(0) ; 87.5-108 Mhz SI470X_SPACE(0) ; 200 Khz END SELECT RETURN Over_SETREGION: ASM endif endm SI470X_REGION?C macro Cregion MOVE?CB Cregion, _SI470X_TempB Expand_SI470X_SETREGION L?CALL _SI470X_SETREGION endm SI470X_REGION?B macro Bregion MOVE?BB Bregion, _SI470X_TempB Expand_SI470X_SETREGION L?CALL _SI470X_SETREGION endm SI470X_REGION?W macro Wregion MOVE?WB Wregion, _SI470X_TempB Expand_SI470X_SETREGION L?CALL _SI470X_SETREGION endm SI470X_REGION?N macro Nregion MOVE?NB Nregion, _SI470X_TempB Expand_SI470X_SETREGION L?CALL _SI470X_SETREGION endm ENDASM ;----[Seek Signal to Noise Ratio]----------------------------------------------- USERCOMMAND "SI470X_SEEKSNR" ; 0=disabled, 1=most stops, 7=fewest stops ASM Expand_SI470X_SETSEEKSNR macro ifndef SI470X_SETSEEKSNR_Expanded #define SI470X_SETSEEKSNR_Expanded ENDASM GOTO Over_SETSEEKSNR SI470X_SETSEEKSNR: SI470X_GET SI470X_TempB = SI470X_TempB MIN 7 ; limit SNR to 0-7 sysconfig3.LowByte = (sysconfig3.LowByte & $0F) | (SI470X_TempB << 4) SI470X_UPDATE RETURN Over_SETSEEKSNR: ASM endif endm SI470X_SEEKSNR?C macro Csnr MOVE?CB Csnr, _SI470X_TempB Expand_SI470X_SETSEEKSNR L?CALL _SI470X_SETSEEKSNR endm SI470X_SEEKSNR?B macro Bsnr MOVE?BB Bsnr, _SI470X_TempB Expand_SI470X_SETSEEKSNR L?CALL _SI470X_SETSEEKSNR endm SI470X_SEEKSNR?W macro Wsnr MOVE?WB Wsnr, _SI470X_TempB Expand_SI470X_SETSEEKSNR L?CALL _SI470X_SETSEEKSNR endm SI470X_SEEKSNR?N macro Nsnr MOVE?NB Nsnr, _SI470X_TempB Expand_SI470X_SETSEEKSNR L?CALL _SI470X_SETSEEKSNR endm ENDASM ;----[Seek FM Implse rejection]------------------------------------------------- USERCOMMAND "SI470X_SEEKIMP" ; 0=disabled, 1=most stops, 15=fewest stops ASM Expand_SI470X_SETSEEKIMP macro ifndef SI470X_SETSEEKIMP_Expanded #define SI470X_SETSEEKIMP_Expanded ENDASM GOTO Over_SETSEEKIMP SI470X_SETSEEKIMP: SI470X_GET SI470X_TempB = SI470X_TempB MIN 15 ; limit IMP to 0-15 sysconfig3.LowByte = (sysconfig3.LowByte & $F0) | SI470X_TempB SI470X_UPDATE RETURN Over_SETSEEKIMP: ASM endif endm SI470X_SEEKIMP?C macro Cimp MOVE?CB Cimp, _SI470X_TempB Expand_SI470X_SETSEEKIMP L?CALL _SI470X_SETSEEKIMP endm SI470X_SEEKIMP?B macro Bimp MOVE?BB Bimp, _SI470X_TempB Expand_SI470X_SETSEEKIMP L?CALL _SI470X_SETSEEKIMP endm SI470X_SEEKIMP?W macro Wimp MOVE?WB Wimp, _SI470X_TempB Expand_SI470X_SETSEEKIMP L?CALL _SI470X_SETSEEKIMP endm SI470X_SEEKIMP?N macro Nimp MOVE?NB Nimp, _SI470X_TempB Expand_SI470X_SETSEEKIMP L?CALL _SI470X_SETSEEKIMP endm ENDASM ;----[Softmute Speed]----------------------------------------------------------- USERCOMMAND "SI470X_SOFTMUTEATTACK" ; 0=fastest, 3=slowest ASM SI470X_SOFTMUTEATTACK?C macro Catk L?CALL _SI470X_READ MOVE?CT Catk >> 1, _sysconfig3 + 1, 7 MOVE?CT Catk, _sysconfig3 + 1, 6 L?CALL _SI470X_WRITE endm SI470X_SOFTMUTEATTACK?B macro Batk L?CALL _SI470X_READ MOVE?TT Batk,1, _sysconfig3 + 1, 7 MOVE?TT Batk,0, _sysconfig3 + 1, 6 L?CALL _SI470X_WRITE endm SI470X_SOFTMUTEATTACK?W macro Watk L?CALL _SI470X_READ MOVE?TT Watk,1, _sysconfig3 + 1, 7 MOVE?TT Watk,0, _sysconfig3 + 1, 6 L?CALL _SI470X_WRITE endm SI470X_SOFTMUTEATTACK?N macro Natk L?CALL _SI470X_READ MOVE?TT Natk,1, _sysconfig3 + 1, 7 MOVE?TT Natk,0, _sysconfig3 + 1, 6 L?CALL _SI470X_WRITE endm ENDASM ;----[Softmute Attenuation]----------------------------------------------------- USERCOMMAND "SI470X_SOFTMUTEATTEN" ; 0=16dB, 1=14dB, 2=12dB, 3=10dB ASM SI470X_SOFTMUTEATTEN?C macro Catn L?CALL _SI470X_READ MOVE?CT Catn >> 1, _sysconfig3 + 1, 7 MOVE?CT Catn, _sysconfig3 + 1, 6 L?CALL _SI470X_WRITE endm SI470X_SOFTMUTEATTEN?B macro Batn L?CALL _SI470X_READ MOVE?TT Batn,1, _sysconfig3 + 1, 5 MOVE?TT Batn,0, _sysconfig3 + 1, 4 L?CALL _SI470X_WRITE endm SI470X_SOFTMUTEATTEN?W macro Watn L?CALL _SI470X_READ MOVE?TT Watn,1, _sysconfig3 + 1, 5 MOVE?TT Watn,0, _sysconfig3 + 1, 4 L?CALL _SI470X_WRITE endm SI470X_SOFTMUTEATTEN?N macro Natn L?CALL _SI470X_READ MOVE?TT Natn,1, _sysconfig3 + 1, 5 MOVE?TT Natn,0, _sysconfig3 + 1, 4 L?CALL _SI470X_WRITE endm ENDASM ;----[Tune frequency UP, DN or Mhz*10]------------------------------------------ USERCOMMAND "SI470X_TUNE" SI470X_FREQ VAR SI470X_TempW Khz VAR SI470X_TempB FREQ2CHANNEL: SI470X_GET IF SI470X_CURRENTSPACE = 0 THEN Khz = 20 ELSEIF SI470X_CURRENTSPACE = 2 THEN Khz = 5 ELSE Khz = 10 ENDIF Channel = (Channel & $FE00) | (((SI470X_FREQ * 10) - (SI470X_MINFREQUENCY * 10)) / Khz) HSEROUT ["Space=",DEC SI470X_CURRENTSPACE, _ " MINFREQ=",DEC SI470X_MINFREQUENCY, _ " Channel=",DEC Channel, _ " Freq=",DEC SI470X_FREQ,13,10] TUNE = 1 SI470X_UPDATE WAIT4STC: WHILE !STC SI470X_GETSTATUS WEND TUNE = 0 SEEK = 0 SI470X_UPDATE #IFDEF USE_RDS #IFDEF USE_GENRE ARRAYWRITE GENRE,[REP " "\8] GENRE_CHANGED = 1 LASTPTY = 0 PTY = 0 #ENDIF #IFDEF USE_RADIOTEXT RADIOTEXT_CLEAR RADIOTEXT_CHANGED = 1 #IFDEF USE_PACKETTRACK ARRAYWRITE RadioTextErrors,[REP RADIOTEXT_MAXERRORS\32] #ENDIF RDS_LENGTH4 = 0 #ENDIF #ENDIF RETURN ASM SI470X_TUNE?C macro Freq MOVE?CW Freq, _SI470X_FREQ L?CALL _FREQ2CHANNEL endm SI470X_TUNE?W macro Freq MOVE?WW Freq, _SI470X_FREQ L?CALL _FREQ2CHANNEL endm SI470X_TUNE?N macro Freq MOVE?NW Freq, _SI470X_FREQ L?CALL _FREQ2CHANNEL endm SI470X_TUNE?B macro Freq error "SI470X_TUNE cannot use a BYTE variable. Use a constant or word." endm SI470X_TUNE?T macro Freg,Fbit error "SI470X_TUNE cannot use a BIT variable. Use a constant or word." endm ENDASM ;----[Execute a SEEK, UP or DOWN]----------------------------------------------- USERCOMMAND "SI470X_SEEK" ASM SI470X_SEEK?C macro Cdir L?CALL _SI470X_READ MOVE?CT Cdir, _SEEKUP MOVE?CT 1, _SEEK L?CALL _SI470X_WRITE L?CALL _WAIT4STC endm SI470X_SEEK?T macro DirReg, DirBit L?CALL _SI470X_READ MOVE?TT DirReg, DirBit, _SEEKUP MOVE?CT 1, _SEEK L?CALL _SI470X_WRITE L?CALL _WAIT4STC endm SI470X_SEEK?B macro Dir L?CALL _SI470X_READ MOVE?BT Dir, _SEEKUP MOVE?CT 1, _SEEK L?CALL _SI470X_WRITE L?CALL _WAIT4STC endm SI470X_SEEK?W macro Dir L?CALL _SI470X_READ MOVE?WT Dir, _SEEKUP MOVE?CT 1, _SEEK L?CALL _SI470X_WRITE L?CALL _WAIT4STC endm ENDASM ;----[Adjust Volume, Up, DN or 0-15]-------------------------------------------- USERCOMMAND "SI470X_VOLUME" ASM Expand_SI470X_VOLUMEDN macro ifndef SI470X_VOLUMEDN_Expanded #define SI470X_VOLUMEDN_Expanded ENDASM GOTO Over_VOLUMEDN SI470X_VOLUMEDN: SI470X_GET IF SI470X_CURRENTVOLUME > 0 THEN SI470X_CURRENTVOLUME = SI470X_CURRENTVOLUME - 1 @ Expand_SI470X_SETVOLUME GOTO SI470X_SETVOLUME ENDIF RETURN Over_VOLUMEDN: ASM endif endm Expand_SI470X_VOLUMEUP macro ifndef SI470X_VOLUMEUP_Expanded #define SI470X_VOLUMEUP_Expanded ENDASM GOTO Over_VOLUMEUP SI470X_VOLUMEUP: SI470X_GET IF SI470X_CURRENTVOLUME < $F THEN SI470X_CURRENTVOLUME = SI470X_CURRENTVOLUME + 1 @ Expand_SI470X_SETVOLUME GOTO SI470X_SETVOLUME ENDIF RETURN Over_VOLUMEUP: ASM endif endm Expand_SI470X_SETVOLUME macro ifndef SI470X_SETVOLUME_Expanded #define SI470X_SETVOLUME_Expanded ENDASM GOTO Over_SETVOLUME SI470X_SETVOLUME: sysconfig2 = (sysconfig2 & $fff0) | (SI470X_CURRENTVOLUME & $0F) SI470X_UPDATE RETURN Over_SETVOLUME: ASM endif endm SI470X_VOLUME?C macro Cvol if (Cvol == _DOWN) Expand_SI470X_VOLUMEDN L?CALL _SI470X_VOLUMEDN else if (Cvol == _UP) Expand_SI470X_VOLUMEUP L?CALL _SI470X_VOLUMEUP else MOVE?CW Cvol, _SI470X_CURRENTVOLUME Expand_SI470X_SETVOLUME L?CALL _SI470X_SETVOLUME endif endif endm SI470X_VOLUME?B macro Bvol MOVE?BB Bvol, _SI470X_CURRENTVOLUME Expand_SI470X_SETVOLUME L?CALL _SI470X_SETVOLUME endm SI470X_VOLUME?W macro Wvol MOVE?WB Wvol, _SI470X_CURRENTVOLUME Expand_SI470X_SETVOLUME L?CALL _SI470X_SETVOLUME endm SI470X_VOLUME?N macro Nvol MOVE?NB Nvol, _SI470X_CURRENTVOLUME Expand_SI470X_SETVOLUME L?CALL _SI470X_SETVOLUME endm ENDASM ;----[Clear errors when Packet Tracking]---------------------------------------- #IFDEF USE_RDS #IFDEF USE_RADIOTEXT #IFDEF USE_PACKETTRACK USERCOMMAND "RDS_CLEARERRORS" RDS_CLEARERRORS_CODE: ARRAYWRITE RadioTextErrors,[REP RADIOTEXT_MAXERRORS\32] #IFDEF CLEARTEXT_ONCHANGE ARRAYWRITE RadioText,[REP " "\64] ; clear RadioText array #ENDIF RETURN ASM RDS_CLEARERRORS? macro L?CALL _RDS_CLEARERRORS_CODE endm ENDASM #ENDIF ; USE_PACKETTRACK #ENDIF ; USE_RADIOTEXT #ENDIF ; USE_RDS ;----[Test if RADIOTEXT reception is complete]---------------------------------- #IFDEF USE_RDS #IFDEF USE_RADIOTEXT #IFDEF USE_PACKETTRACK USERCOMMAND "RDS_CHECKCOMPLETE" RDS_CHECKCOMPLETE_CODE: RadioText_Complete = 1 FOR Si470x_TempB = 0 TO ((RADIOTEXT_LENGTH / 2) - 1) IF RadioTextErrors(Si470x_TempB) != 0 THEN RadioText_Complete = 0 NEXT Si470x_TempB RETURN ASM RDS_CHECKCOMPLETE? macro L?CALL _RDS_CHECKCOMPLETE_CODE endm ENDASM #ENDIF ; USE_PACKETTRACK #ENDIF ; USE_RADIOTEXT #ENDIF ; USE_RDS ;----[Test if prviously completed RADIOTEXT is changing]------------------------ #IFDEF USE_RDS #IFDEF USE_RADIOTEXT #IFDEF USE_PACKETTRACK USERCOMMAND "RADIOTEXT_ERRORTEST" RADIOTEXT_ERRORTEST_CODE: RDS_CHECKCOMPLETE IF RadioText_Complete THEN RDS_CLEARERRORS #IFDEF CLEARTEXT_ONCHANGE RADIOTEXT_CLEAR #ENDIF ENDIF RETURN ASM RADIOTEXT_ERRORTEST? macro L?CALL _RADIOTEXT_ERRORTEST_CODE endm ENDASM #ENDIF ; USE_PACKETTRACK #ENDIF ; USE_RADIOTEXT #ENDIF ; USE_RDS ;----[Keep text within printable characters (32-126)]--------------------------- #IFDEF USE_RDS #IFDEF USE_RADIOTEXT USERCOMMAND "VALIDATECHAR" RDS_VALIDATECHAR: IF Si470X_TempB < 32 THEN Si470X_TempB = " " IF Si470X_TempB > 126 THEN Si470X_TempB = " " RETURN ASM VALIDATECHAR?B macro Bin MOVE?BB Bin, _SI470X_TempB L?CALL _RDS_VALIDATECHAR MOVE?BB _SI470X_TempB, Bin endm ENDASM #ENDIF ; USE_RADIOTEXT #ENDIF ; USE_RDS ;----[Process RDS packets]------(Should be called every ~40mS]------------------ #IFDEF USE_RDS USERCOMMAND "SI470X_RDS_PROCESS" RDS_PROCESS_CODE: SI470X_GET #IFDEF USE_RADIOTEXT RADIOTEXT_Changed = 0 #ENDIF IF RDSS THEN ; if RDS is synchronized IF !RDSR OR LastRDSR THEN GOTO PacketNotReady #IFDEF USE_GENRE IF ((statusrssi.10 << 1) | statusrssi.9) = 0 AND _; no blockA errors AND ((readchan.15 << 1) | readchan.14) = 0 THEN ; no blockB errors PTY = (rdsb >> 5) & %11111 IF PTY != LASTPTY THEN LASTPTY = PTY GOSUB RDS_GENRE GENRE_CHANGED = 1 ENDIF ENDIF #ENDIF ; USE_GENRE #IFDEF USE_TIME IF ((statusrssi.10 << 1) | statusrssi.9) = 0 AND _; no blockA errors AND ((readchan.15 << 1) | readchan.14) = 0 THEN ; no blockB errors IF (rdsb & $F000) = $4000 THEN ; group = time ARRAYWRITE RDS_TIME,[rdsa,rdsb,rdsc,rdsd] RDS_TIME_CHANGED = 1 ENDIF ENDIF #ENDIF ; USE_TIME ; IF RDSMODE THEN ; showing RDS string #IFDEF USE_RADIOTEXT IF ((statusrssi.10 << 1) | statusrssi.9) = 0 AND _; no blockA errors AND ((readchan.15 << 1) | readchan.14) = 0 THEN ; no blockB errors IF (rdsb & $F000) = $2000 THEN ; group = radiotext RDS_Idx = (rdsb & $F) << 2 RDS_LENGTH4 = RDS_LENGTH4 MAX (rdsb & $F) RADIOTEXT_LENGTH = (RDS_LENGTH4 + 1) << 2 RDS_ERRCOUNT = (readchan.13 << 1) | readchan.12 #IFDEF USE_PACKETTRACK IF RDS_ERRCOUNT <= RadioTextErrors(RDS_Idx >> 1) THEN ; better blkC error? #ELSE IF RDS_ERRCOUNT <= RADIOTEXT_MAXERRORS THEN ; no blockC errors #ENDIF ; USE_PACKETTRACK ValidateChar(rdsc.HighByte) ValidateChar(rdsc.LowByte) IF (rdsc.HighByte != RadioText(RDS_Idx)) OR _ ; if chars changed (rdsc.LowByte != RadioText(RDS_Idx + 1)) THEN RADIOTEXT_Changed = 1 RadioText(RDS_Idx) = rdsc.HighByte ; save the 2 chars RadioText(RDS_Idx + 1) = rdsc.LowByte #IFDEF USE_PACKETTRACK IF RDS_ERRCOUNT = 0 THEN RADIOTEXT_ERRORTEST ;text change test RadioTextErrors(RDS_Idx >> 1) = RDS_ERRCOUNT RadioText(RDS_Idx) = rdsc.HighByte ; save the 2 chars RadioText(RDS_Idx + 1) = rdsc.LowByte ELSE IF RDS_ERRCOUNT < RadioTextErrors(RDS_Idx >> 1) THEN RADIOTEXT_Changed = 1 ENDIF RadioTextErrors(RDS_Idx >> 1) = RDS_ERRCOUNT #ENDIF ; USE_PACKETTRACK ENDIF ENDIF RDS_ERRCOUNT = (readchan.11 << 1) | readchan.10 #IFDEF USE_PACKETTRACK IF RDS_ERRCOUNT <= RadioTextErrors(RDS_Idx >> 1) THEN ; better blkD error? #ELSE IF RDS_ERRCOUNT <= RADIOTEXT_MAXERRORS THEN ; no blockD errors #ENDIF ValidateChar(rdsd.HighByte) ValidateChar(rdsd.LowByte) IF (rdsd.HighByte != RadioText(RDS_Idx + 2)) OR _ ; if chars changed (rdsd.LowByte != RadioText(RDS_Idx + 3)) THEN RADIOTEXT_Changed = 1 RadioText(RDS_Idx + 2) = rdsd.HighByte ; save the 2 chars RadioText(RDS_Idx + 3) = rdsd.LowByte #IFDEF USE_PACKETTRACK IF RDS_ERRCOUNT = 0 THEN RADIOTEXT_ERRORTEST ;text change test RadioTextErrors((RDS_Idx >> 1) + 1) = RDS_ERRCOUNT RadioText(RDS_Idx + 2) = rdsd.HighByte ; save the 2 chars RadioText(RDS_Idx + 3) = rdsd.LowByte ELSE IF RDS_ERRCOUNT < RadioTextErrors((RDS_Idx >> 1) + 1) THEN RADIOTEXT_Changed = 1 ENDIF RadioTextErrors((RDS_Idx >> 1) + 1) = RDS_ERRCOUNT #ENDIF ; USE_PACKETTRACK ENDIF ENDIF ENDIF ENDIF #ENDIF ;USE_RADIOTEXT ; ELSE ; show raw RDS groups ;<--- shouldn't be here --- ; FOR RDS_Idx = $C TO 15 ; HSEROUT [HEX4 Si_REGS(RDS_Idx)," "] ; NEXT RDS_Idx ; IF (rdsb & $F000) = $2000 THEN ; HSEROUT [" ",rdsc >> 8, rdsc & $FF, rdsd >> 8, rdsd & $FF] ; ENDIF ; HSEROUT [13,10] ; ENDIF PacketNotReady: LastRDSR = RDSR ENDIF #IFDEF USE_PACKETTRACK RDS_CHECKCOMPLETE #ENDIF ; USE_PACKETTRACK RETURN ASM SI470X_RDS_PROCESS? macro L?CALL _RDS_PROCESS_CODE endm ENDASM #ENDIF ; USE_RDS ;------------------------------------------------------------------------------- #IFDEF USE_RDS #IFDEF USE_GENRE RDS_GENRE: SELECT CASE PTY CASE 1 : ARRAYWRITE GENRE,[" News "] CASE 2 : ARRAYWRITE GENRE,[" Inform "] CASE 3 : ARRAYWRITE GENRE,[" Sports "] CASE 4 : ARRAYWRITE GENRE,[" Talk "] CASE 5 : ARRAYWRITE GENRE,[" Rock "] CASE 6 : ARRAYWRITE GENRE,["ClasRock"] CASE 7 : ARRAYWRITE GENRE,["AdultHit"] CASE 8 : ARRAYWRITE GENRE,["SoftRock"] CASE 9 : ARRAYWRITE GENRE,[" Top_40 "] CASE 10 : ARRAYWRITE GENRE,["Country "] CASE 11 : ARRAYWRITE GENRE,[" Oldies "] CASE 12 : ARRAYWRITE GENRE,[" Soft "] CASE 13 : ARRAYWRITE GENRE,["Nostalga"] CASE 14 : ARRAYWRITE GENRE,[" Jazz "] CASE 15 : ARRAYWRITE GENRE,["Classicl"] CASE 16 : ARRAYWRITE GENRE,[" R_&_B "] CASE 17 : ARRAYWRITE GENRE,["Soft_R&B"] CASE 18 : ARRAYWRITE GENRE,["Language"] CASE 19 : ARRAYWRITE GENRE,["Rel_Musi"] CASE 20 : ARRAYWRITE GENRE,["Rel_Talk"] CASE 21 : ARRAYWRITE GENRE,["Persnlty"] CASE 22 : ARRAYWRITE GENRE,[" Public "] CASE 23 : ARRAYWRITE GENRE,["College "] CASE 29 : ARRAYWRITE GENRE,["Weather "] CASE 30 : ARRAYWRITE GENRE,[" Test "] CASE 31 : ARRAYWRITE GENRE,["ALERT ! "] CASE ELSE : ARRAYWRITE GENRE,[" "] END SELECT RETURN #ENDIF ; USE_GENRE #ENDIF ; USE_RDS ;------------------------------------------------------------------------------- #IFDEF USE_PRESETS #IF USE_PRESETS > 0 EE_Presets DATA WORD 875 DATA WORD 877 DATA WORD 879 DATA WORD 881 DATA WORD 881 DATA WORD 881 DATA WORD 881 DATA WORD 881 DATA WORD 881 DATA WORD 881 #IF USE_PRESETS > 10 DATA WORD 881 DATA WORD 881 DATA WORD 881 DATA WORD 881 DATA WORD 881 DATA WORD 881 DATA WORD 881 DATA WORD 881 DATA WORD 881 DATA WORD 881 #ENDIF USERCOMMAND "SI470X_PRESET" USERCOMMAND "SI470X_SAVE_PRESET" READ_PRESET: SI470X_TempB = (EE_Presets & $FF) + (SI470X_TempB << 1) READ SI470X_TempB, WORD SI470X_TempW SI470X_Tune(SI470X_TempW) RETURN WRITE_PRESET: SI470X_GET SI470X_TempB = (EE_Presets & $FF) + (SI470X_TempB << 1) WRITE SI470X_TempB, WORD SI470X_CURRENTFREQUENCY RETURN ASM SI470X_PRESET?C macro PSN MOVE?CB PSN, _SI470X_TempB L?CALL _READ_PRESET endm SI470X_PRESET?B macro PSN MOVE?BB PSN, _SI470X_TempB L?CALL _READ_PRESET endm SI470X_PRESET?W macro PSN MOVE?BB PSN, _SI470X_TempB L?CALL _READ_PRESET endm SI470X_PRESET?N macro PSN MOVE?BB PSN, _SI470X_TempB L?CALL _READ_PRESET endm SI470X_SAVE_PRESET?C macro PSN MOVE?CB PSN, _SI470X_TempB L?CALL _WRITE_PRESET endm SI470X_SAVE_PRESET?B macro PSN MOVE?BB PSN, _SI470X_TempB L?CALL _WRITE_PRESET endm SI470X_SAVE_PRESET?W macro PSN MOVE?BB PSN, _SI470X_TempB L?CALL _WRITE_PRESET endm SI470X_SAVE_PRESET?N macro PSN MOVE?BB PSN, _SI470X_TempB L?CALL _WRITE_PRESET endm ENDASM #ENDIF #ENDIF ;----[Force Macro Insertion]---------------------------------------------------- @ ifdef ForceMacros HIGH R0.0 ; HIGH?T LOW R0.0 ; LOW?T IF R0.0 != R0.0 THEN R0.0 = R0.0 ; CMPEQ?TTL IF R0.0 = R0.0 THEN R0.0 = R0.0 ; CMPNE?TTL @ endif Over_SiSUBs ;----[Version information for this Module]---------------------------------- MODULE_VERSION $11 MODULE_NAME "Si470x v1.1" MODULE_URL "Si470x.pbpmod","http://support.melabs.com/threads/280"