'( ################################################################################ project: FM Radio - RDA5807M chip -------------------------------------------------------------------------------- name : RDA5807M_Test5.bas copyright : (c) Chris Hirt, OE3HBW, Austria, JN87AQ, 2021 purpose : Controller for FM Radio with RDA5807M micro : ATmega644-20PU programmer : homebrew (STK200/STK300 emulation) compiler : MCS BASCOM-AVR 2.0.8.4 - 001 flash : 6% code build : V16 @ 08112021 (08. Nov. 2021) status : Test RSD functionality -------------------------------------------------------------------------------- ########################### HARDWARE ########################################### '----------------------------- uC ATmega644P 40 PDIP 20 MHz PIN 01 PB0 PORTB.0 T0 / XCK0 02 PB1 PORTB.1 T1 / CLKO 03 PB2 PORTB.2 INT2 / AIN0 04 PB3 PORTB.3 OC0A / AIN1 05 PB4 PORTB.4 OC0B / SS 06 PB5 MOSI ISP MOSI 07 PB6 MISO ISP MISO 08 PB7 SCK ISP SCK 09 /RESET ISP RST 10 VCC +5V 11 GND 0V 12 XTAL2 Quartz 16.0000 MHz 13 XTAL1 Quartz 16.0000 MHz 14 PD0 PORTD.0 RXD --> RS232 15 PD1 PORTD.1 TXD --> RS232 16 PD2 PORTD.2 INT0 / RXD1 17 PD3 PORTD.3 INT1 / TXD1 18 PD4 PORTD.4 OC1B / XCK1 19 PD5 PORTD.5 OC1A 20 PD6 PORTD.6 OC2B / ICP 21 PD7 PORTD.7 OC2A 22 PC0 PORTC.0 TWI SCL --> I2C Bus SCL RDA5807M 23 PC1 PORTC.1 TWI SDA --> I2C Bus SDA RDA5807M 24 PC2 PORTC.2 TCK --> LCD RS 25 PC3 PORTC.3 TMS --> LCD E 26 PC4 PORTC.4 TDO 27 PC5 PORTC.5 TDI 28 PC6 PORTC.6 TOSC1 29 PC7 PORTC.7 TOSC2 30 AVCC VCC +5V 31 AGDN GND 0V 32 AREF ADC REF 33 PA7 PORTA.7 ADC7 --> LCD DB7 34 PA6 PORTA.6 ADC6 --> LCD DB6 35 PA5 PORTA.5 ADC5 --> LCD DB5 36 PA4 PORTA.4 ADC4 --> LCD DB4 37 PA3 PORTA.3 ADC3 38 PA2 PORTA.2 ADC2 39 PA1 PORTA.1 ADC1 40 PA0 PORTA.0 ADC0 ----------------------------- LCD YL162-90 PIN 01 VSS GND 02 VDD +5V 03 V0 -2.5V ! 04 RS Register Select 05 R/W Read/Write --> GND 06 E Enable 07 D0 (Data 0, 4-Bit mod open) 08 D1 (Data 1, 4-Bit mod open) 09 D2 (Data 2, 4-Bit mod open) 10 D3 (Data 3, 4-Bit mod open) 11 D4 (Data 4) 12 D5 (Data 5) 13 D6 (Data 6) 14 D7 (Data 7) 15 Background Light + BL2 Background Light - ----------------------------- RDA5807M Modul RRD-102 V2.0 PIN 01 SDA 02 SCL 03 NC 04 NC 05 VDD 06 GND 07 ROUT 08 LOUT 09 RCK 10 Ant ################################################################################ ') '$PROG &HFF,&HD7,&HD9,&HFC 'Take care! Fuse Bits !!! $regfile = "m644pdef.dat" 'ATmega644P $crystal = 16000000 '16.0 MHz 'stack and framesize not optimized! $hwstack = 128 $framesize = 128 $swstack = 128 $lib "I2C_TWI.lbx" 'include TWI Lib --> force BASCOM to use the hardware TWI '----- Config I2C -------------------------------------------------------------- Config SDA = PortC.1 'Configures a port pin for use as serial data SDA Config SCL = PortC.0 'Configures a port pin for use as serial clock SCL Config Twi = 400000 'TWI = I2C clock speed is 400 kHz '----- Config LCD -------------------------------------------------------------- Config LCD = 16 * 2 Config LCDmode = Port Config LCDbus = 4 Config LCDpin = Pin , Db4 = PortA.4 , Db5 = PortA.5 , Db6 = PortA.6 , Db7 = PortA.7 , Rs = PortC.2 , E = PortC.3 '----- Config RDA5807M --------------------------------------------------------- 'RDA5807M Register @ RDA Datasheet RDA5807M V1.8 August 2014 'My default binary register values for Expert Mode '---- Writeable Register ---- const RegH02 = &b1010_0010_0000_0101 'register h02 default value 'Reg02_DHIZ = 1 Audio Output normal 'Reg02_DMUTE = 0 Mute 'Reg02_MONO = 1 Mono 'Reg02_BASS = 0 Bass Boost disabled 'Reg02_RCLK_NCM = 0 Clock always supplied 'Reg02_RCLK_DIM = 0 Not direkt input mode 'Reg02_SEEKUP = 1 Seek up 'Reg02_SEEK = 0 Disable seek 'Reg02_SKMODE = 0 Wrap band limit 'Reg02_CLKMODE = 000 32.7680 kHz Quartz 'Reg02_RDS_EN = 0 RDS/RBDS enable 'Reg02_NEWMETHD = 1 New demodulation method enable 'Reg02_SOFT_RST = 0 Not Soft_Reset 'Reg02_ENABLE = 1 Power Up enable const RegH03 = &b0000_0000_0000_1100 'register h03 default value 'Reg03_CHAN = 0000000000 Channel (FM Europe, 100 kHz) 'Reg03_DIRMODE = 0 Direct control mode disabled 'Reg03_TUNE = 0 Tune disabled 'Reg03_BAND = 11 Band select 50-65 MHz (Expert Mode!) 'Reg03_SPACE = 00 Channel spacing 100 kHz const RegH04 = &b0000_1110_0000_0000 'register h04 default value 'Reg04_RSVD = 0 Reserved 'Reg04_STCIEN = 0 Seek/Tune complete interrupt disable 'Reg04_RBDS = 0 RDS only 'Reg04_RDSFIFOE = 0 RDS FIFO Mode enable 'Reg04_DE = 1 Deemphasis 75 us 'Reg04_RDSFIFOC = 1 Clear RDS FIFO 'Reg04_SOFTMUTE = 1 Softmute enable 'Reg04_AFCD = 0 AFC enable 'Reg04_RSVD = 00000000 Reserved (I2S, GPIO 1-3) const RegH05 = &b0000_1000_1010_1111 'register h05 default value 'Reg05_INTMODE = 0 Interrupt mode off 'Reg05_SEEKMODE = 00 Default seek mode (not RSSI seek mode) 'Reg05_RSVD = 0 Reserved 'Reg05_SEEKTH = 1000 Seek SNR value 'Reg05_LNA_PORT = 10 LNAP (positiv) 'Reg05_LNA_IC = 10 LNA current 2.5 mA 'Reg05_VOLUME = 1111 DAC gain control (Volume 0-15 log) const RegH06 = &b0000_0000_0000_0000 'register h06 default value 'Reg06_RSVD = 0 Reserved 'Reg06_OPENMODE = 00 Open behind registers reading function 'Reg06_I2S = 0000000000000 I2S parameter const RegH07 = &b0100_0000_0000_0011 'register h07 default value 'Reg07_RSVD = 0 Reserved 'Reg07_THSOFTBL = 10000 Noise soft blend threshold (2 dB steps) 'Reg07_6550MODE = 0 Band 50-76 MHz (Expert Mode!) 'Reg07_RSVD = 0 Reserved 'Reg07_SEEKTHOD = 000000 Mode disable (only with RSSI seek mode) 'Reg07_SOFTBLEN = 1 Softblend enable 'Reg07_FREQMODE = 1 Frequence setting in Expert Mode! const RegH08 = &b0000_0000_0000_0000 'register h08 default value 'Reg_FREQ_DRCT = &b0000_0000_0000_0000 Frequency in Expert Mode '---- Read only Register ----- 'Reg00 = &b1000_0101_0000_0100 'Reg00_CHIPID = &b1000_0101_0000_0100 = &h5804 'Reg0A = &b0000_0100_0000_0000 'Reg0A_RDSR = 0 RDS/RBDS groupnot ready 'Reg0A_STC = 0 Seek/Tune complete flag (not complete) 'Reg0A_SF = 0 Seek succesfull 'Reg0A_RDSS = 0 RDS decoder not synchronized 'Reg0A_BLK_E = 0 RDS Block E not found 'Reg0A_ST = 1 Stereo indicator - Stereo 'Reg0A_READCHAN = 0000000000 Read channel 'Reg0B = &b0000_0000_0000_0000 'Reg0B_RSSI = 0000000 RSSI 'Reg0B_FM_TRUE = 0 Current channel is not a station 'Reg09_FM_READY = 0 FM not ready 'Reg0B_RSVD = 00 Reserved 'Reg0B_ABCDE = 0 Block ID of register h0C, h0D, h0E, h0F 'Reg0B_BLERA = 00 RDS_DATA_0 - Null errors requiring correction 'Reg0B_BLERB = 00 RDS_DATA_1 - Null errors requiring correction 'Reg0C = RDSA 'Reg0D = RDSB 'Reg0E = RDSC 'Reg0F = RDSD '---- RDA5807M chip I2C address ---- 'Device Address = h10 for sequential read/write mode 'Device Address = h11 for random access read/write mode 'Sequential read/write mode Const SEQ_WriteAdr = &h20 'Const SEQ_ReadAdr = &h21 'Random Access read/write mode Const RND_WriteAdr = &h22 Const RND_ReadAdr = &h23 '---------------------------- Const FMstart = 50000000 'Start frequency = 50 MHz Const FMend = 115535000 'End frequency = 115.535 MHz '----- Test-Frequencies ----- 'Const FMfreq = 88200000 'BC OE3 'Const FMfreq = 90300000 'BC OE1 Const FMfreq = 92400000 'BC FM4 'Const FMfreq = 95800000 'BC Radio-NOE '----- Declarations ------------------------------------------------------------ Dim Freq As DWord 'FM frequency in Hz Dim hB As Byte Dim lB As Byte Dim regW As Word Dim fx As DWord Dim FreqDW As DWord Dim FreqW As Word Dim MT As Word Dim si As Word Dim rssi As Byte '--- RDS --- Dim RDS As Word Dim RDSstat1 As Word Dim RDSstat2 As Word Dim RDSstatus As Byte Dim RDSR As Byte Dim stat As Byte Dim RDSA As Word Dim RDSB As Word Dim RDSC As Word Dim RDSD As Word Dim RDSerr As Byte Dim GT As Byte Dim B0 As Byte Dim PS1 As Byte Dim PS0 As Byte Dim C10 As Byte Dim PSChr1 As String * 1 Dim PSChr0 As String * 1 Dim PSN As String * 8 Dim cnt As Byte Dim T1 As Byte Dim T2 As Byte Dim hours As Byte Dim minutes As Byte Dim LTO As Byte Dim Tms As String * 5 Dim TStr As String * 5 Declare Sub I2CwriteRegister(ByVal reg As Byte , ByVal cont As Word) Declare Function I2CreadRegister(ByVal reg As Byte) As Word Declare Sub RDA5807M_SetMyDefault() Declare Sub RDA5807M_Init() Declare Sub RDA5807M_SetMute() Declare Sub RDA5807M_SetFrequency(ByVal newF As DWord) Declare Sub RDA5807M_GetRSSI() '--- RDS --- Declare Sub RDA5807M_RDSinit() Declare Sub RDA5807M_RDSstatus() Declare Sub RDA5807M_RDSdata() Declare Sub DecodeRDSdata() Declare Sub RDA5807M_ProcessRDS() '####################### Main ################################################## Cls 'Clear display Cursor Off Noblink 'Hide cursor I2Cinit 'Initializes the I2C SCL and SDA pins Wait 1 Call RDA5807M_Init() 'Initialized RDA5807M Freq = FMfreq 'Testfrequency Call RDA5807M_SetFrequency(Freq) 'Set Freq_Direct LCD Freq ; " Hz" Waitms 400 'Wait at least 400 ms Call RDA5807M_GetRSSI() 'Read actual RSSI value Lowerline LCD rssi ; " units" Wait 2 Cls Call RDA5807M_ProcessRDS() 'Show RDS data End 'of program '######################## Subs ################################################# Sub I2CwriteRegister(ByVal reg As Byte , ByVal cont As Word) 'write cont in register reg I2cstart 'START condition I2cwbyte RND_WriteAdr 'RDA5807M address / random write mode I2cwbyte reg 'Register reg I2cwbyte High(cont) 'High Byte of cont I2cwbyte Low(cont) 'Low Byte of cont I2cstop 'STOP condition End Sub Function I2CreadRegister(ByVal reg As Byte) As Word 'read from reg register I2cstart 'START condition I2cwbyte RND_WriteAdr 'RDA5807M address / random write mode I2cwbyte reg 'Register reg I2cstop 'STOP condition I2cstart 'START condition I2cwbyte RND_ReadAdr 'RDA5807M address / random read mode I2crbyte hB , ack 'read high Byte I2crbyte lB , Nack 'read low Byte I2cstop 'STOP condition regW = hb 'hb in word LSB shift regW , left , 8 'shift to MSB regW = regW + lB 'lB in LSB I2CreadRegister = regW 'return register Word End Function Sub RDA5807M_SetMyDefault() 'Set my default values for Expert Mode I2cstart 'START condition I2cwbyte SEQ_WriteAdr 'RDA5807M address / sequential write mode I2cwbyte High(RegH02) I2cwbyte Low(RegH02) I2cwbyte High(RegH03) I2cwbyte Low(RegH03) I2cwbyte High(RegH04) I2cwbyte Low(RegH04) I2cwbyte High(RegH05) I2cwbyte Low(RegH05) I2cwbyte High(RegH06) I2cwbyte Low(RegH06) I2cwbyte High(RegH07) I2cwbyte Low(RegH07) I2cwbyte High(RegH08) I2cwbyte Low(RegH08) I2cstop 'STOP condition End Sub Sub RDA5807M_Init() 'Initialize chip Call I2CwriteRegister(&h02 , &b0000_0000_0000_0010) 'SOFT_RESET - reset chip Waitms 50 'Wait 50 ms Call I2CwriteRegister(&h02 , &b0000_0000_0000_0001) 'ENABLE = 1 - Power On Waitms 600 'Stabilization Call RDA5807M_SetMyDefault() 'Set my default values Waitms 50 End Sub Sub RDA5807M_SetMute() 'Set mute/unmute - change state MT = I2CreadRegister(&h02) If MT.14 = 1 Then 'No mute - normnal operation MT = MT XOR &b0100_0000_0000_0000 'Change to mute Else MT = MT OR &b0100_0000_0000_0000 'Change to normal operation End If Call I2CwriteRegister(&h02 , MT) 'Write Mute state End Sub Sub RDA5807M_SetFrequency(ByVal newF As DWord) 'Set Frequency 50 - 115.535 MHz If newF < FMstart Then newF = FMstart 'Lowest frequency 50 MHz If newF > FMend Then newF = FMend 'Highest frequency 115 MHz fx = newF - FMstart 'Difference frequency FreqDW = fx / 1000 'Frequency with Space 1 kHz FreqW = FreqDW 'Typecasting --> MAX = 65535 Call I2CwriteRegister(&h08 , FreqW) 'Set frequency --> RegH08 Waitms 100 'Wait 100 ms Call RDA5807M_SetMute() 'Change Mute state End Sub Sub RDA5807M_GetRSSI() 'Return radio station strength information si = I2CreadRegister(&h0B) Shift si , right , 9 rssi = Low(si) 'for RDS, the RSSI should be greater than 65 units! End Sub '------------------- RSD --------------------------- Sub RDA5807M_RDSinit() 'Init RDS - write RDS register values RDS = I2CreadRegister(&h02) 'Read RegH02 If RDS.3 = 0 Then RDS = RDS OR &b0000_0000_0000_1000 Call I2CwriteRegister(&h02 , RDS) 'RegH02 [3] RDS Enable Waitms 50 RDS = I2CreadRegister(&h04) 'Read RegH04 RDS.13 = 0 'RegH04 [13] Only RDS RDS.12 = 0 'RegH04 [12] RDS_FIFO disable RDS.10 = 0 'RegH04 [10] RDS_FIFO no clear Call I2CwriteRegister(&h04 , RDS) 'Config RDS Waitms 50 End Sub Sub RDA5807M_RDSstatus() 'RDS Status Byte 'Status Byte: RDSR, RDSS, BLK_EF, ABCD_E, BLERA BLERA, BLERB BLERB RDSstat1 = I2CreadRegister(&h0A) 'Read RegH0A RDSstat2 = I2CreadRegister(&h0B) 'Read RegH0B RDSstat2 = RDSstat2 AND &b0000_0000_0001_1111 RDSstat2.7 = RDSstat1.15 'RDSR - RDSready RDSstat2.6 = RDSstat1.12 'RDSS - RDSsync RDSstat2.5 = RDSstat1.11 'BLKEF RDSstatus = Low(RDSstat2) 'Status Byte RDSR = RDSstatus.7 'RDSready End Sub 'In the documented RDA5807M registers &h0A - &h0F no readout of the BLERC and 'BLERD is possible. Without a documented function description, it is also not 'possible to map the exact sequence of RDS synchronization in the program code. 'RDSS is therefore not considered for the first test. Sub RDA5807M_RDSdata() 'Read RDS data - Blocks and Group Type 'read RDS Data Blocks A-D 'Block E is not considered for this RDS test RDSA = I2CreadRegister(&h0C) RDSB = I2CreadRegister(&h0D) RDSC = I2CreadRegister(&h0E) RDSD = I2CreadRegister(&h0F) RDSerr = 0 stat = RDSstatus AND &b0000_1100 If stat < 3 Then stat = RDSstatus AND &b0000_0011 'BLERA < 3 If stat < 2 Then 'BLERB < 2 GT = High(RDSB) 'Group Type Code GT = GT AND &b1111_0000 B0 = RDSB.11 'Version Flag A or B (0 or 1) 'mask Group Type for hexadecimal notation GT = &h0A OR GT GT = GT OR B0 Else RDSerr = 1 End If Else RDSerr = 1 End If End Sub Sub DecodeRDSdata() 'Decode RDS Data 'Simple version only for Program Service Name and Time as test. Only Group '0A, 0B and 4A are analyzed for this first RDS test If GT = &h0A OR GT = &h0B Then 'Group Type h0A OR &h0B for PS C10 = Low(RDSB) C10 = C10 AND &b0000_0011 PS0 = Low(RDSD) 'b0 - b7 PS1 = High(RDSD) 'b8 - b15 PSChr1 = Chr(PS1) PSChr0 = Chr(PS0) Select Case C10 Case 0: MID(PSN , 1 , 1) = PSChr1 MID(PSN , 2 , 1) = PSChr0 Incr cnt Case 1: MID(PSN , 3 , 1) = PSChr1 MID(PSN , 4 , 1) = PSChr0 Incr cnt Case 2: MID(PSN , 5 , 1) = PSChr1 MID(PSN , 6 , 1) = PSChr0 Incr cnt Case 3: MID(PSN , 7 , 1) = PSChr1 MID(PSN , 8 , 1) = PSChr0 Incr cnt End Select End If If GT = &h4A Then 'Group Type for Time 'Minutes T1 = Low(RDSD) Shift T1 , right , 6 T2 = High(RDSD) AND &b0000_1111 Shift T2 , left , 2 minutes = T2 + T1 'Hours T1 = High(RDSD) Shift T1 , right , 4 T2 = Low(RDSC) AND &b0000_0001 Shift T2 , left , 4 hours = T2 + T1 'take into account Local Time Offset LTO = Low(RDSD) AND &b0001_1111 Shift LTO , right , 1 T1 = Low(RDSD) If T1.5 = 1 Then 'Sign of LTO is minus hours = hours - LTO Else hours = hours + LTO End If 'Simple format the Time-String Tms = Str(hours) If hours < 10 Then Tms = "0" + Tms TStr = Tms + ":" Tms = Str(minutes) If minutes < 10 Then Tms = "0" + Tms TStr = TStr + Tms 'new local Time String at the full minute End If End Sub Sub RDA5807M_ProcessRDS() 'Process RDS Call RDA5807M_RDSinit() 'init RDS register values PSN = Space(8) TStr = Space(5) cnt = 0 Do 'continuous polling of rds data RDSerr = 0 Call RDA5807M_RDSstatus() 'determine the RDS status If RDSR = 1 Then 'check RDS ready (RDSR) Call RDA5807M_RDSdata() 'read RDS Blocks If RDSerr = 0 Then Call DecodeRDSdata() 'decode RDS blocks End If End If If cnt = 4 Then Locate 1 , 1 LCD "*" ; PSN ; "*" 'show Program Service Name cnt = 0 End If Locate 2 , 1 LCD "# " ; TStr ; " #" 'show RDS Time (local time zone!) Waitms 40 Loop End Sub '############################ End Of File ######################################