ESP-01 with FM receiver module

176 views
Skip to first unread message

Bugs

unread,
Dec 12, 2019, 11:37:20 AM12/12/19
to annex_w...@googlegroups.com
Similar to the example I posted elsewhere but with no display or buttons - just a simple HTML page to control from web browser - and working with a tiny ESP8266 module.
The program takes a simple text file of station names and frequencies (sample attached) and performs basic control of an RDA5807 modules via I2C.
The RDA-specific sub routines are grouped at the end of the program so can be re-used en bloc.
There is a volume slider, mute button and signal strength indicator. No graphics have been used - feel free...

The boards are available very cheaply on ebay but some fine soldering is required unless a more expensive module is bought.
The first picture shows a working lash-up with a purchased voltage regulator (both modules require 3.3 volts) and a couple of audio output capacitors feeding a headphone jack socket.
I managed to destroy my first two modules by using a commercial power supply board which had 18 volts on the input of its 3.3 volt regulator (LM317T) and let spikes through. This has now been recycled.
The RDA5807 module is the small (11mm square) green pcb soldered to a piece of perfboard to make it breadboard-compatible.
The white wire is the aerial - the module works better in a box with a telescopic whip aerial and better still with a proper outside aerial and a good coaxial feed.
The wiring needs little explanation, the usual two pullups on the ESP-01 pins, power and ground to both modules and SDA and SCL between them.
No serial USB is connected so the ESP-01 will need programming  with Annex  beforehand.

The second photo shows an alternative voltage regulator and a PAM8403 (5 volt supply) stereo audio amplifier which could drive e.g an old pair of passive PC speakers etc.
Using an ESP-01 would enable a very small radio in a knob and button-free box fed from a 5 volt wall wart power supply.

esp01.jpg

pam.jpg



CODE: xxxx.bas

'Simple FM receiver using RDA5807 module
'displays up to 12 station names, a volume slider, mute button and signal strength.
'Needs a text file with local FM station names and frequencies
'see local station file "stations.txt" as example

RDAaddr = &h11
RDActrlreg = &h02
RDAfreqreg = &h03
RDAvolreg = &h05
RDAssireg = &h0b

freq = 0
freqB = 0
freqH = 0
freqL = 0
muted = 0
rssi = 0

' read in text file of station names (8 chars max) and frequencies
fl$="/stations.txt"
maxstn=val(file.read$(fl$,1))  'first line sets number of stations in the file 
if maxstn>12 then maxstn=12  ' a maximum of 12 to fit a single screen
  
dim station$(maxstn)
dim stnfreq(maxstn)
dim but$(maxstn)  'the buttons

For i=1 to maxstn
  a$=file.read$(fl$,i+1)  
  n = instr(a$,",")  
  b$=left$(trim$(left$(a$,n-1)),8)  'truncate long station names
  c$=trim$(mid$(a$,n+1))   
  station$(i)=b$
  stnfreq(i)=int(val(c$)*10)
Next i

I2C.SETUP 0,2   'usual I2C pins
 
RDAinit  'initialise the RDA5807 to Europe/USA FM band 100kHz spacing etc

text$ = "FM Radio"
sldvol=1
txtssi$="  "
gosub drawscreen
setfreq 1
OnHtmlReload drawscreen
         
wait

drawscreen:
'draw the screen
cls

a$= TEXTBOX$(text$)
a$=a$+ "<br>"

a$=a$+TEXTBOX$(txtssi$)
a$=a$+"<br>"
 html a$
' create the station buttons
a$=""
for i=1 to maxstn
  stn$= station$(i) 
  a$=a$+  BUTTON$(stn$, buttonclick) 
  if (i mod 2) =0 then a$=a$+ "<br>"
next i
a$=a$+ "<br>"
html a$
' add the other screen items 

 a$=SLIDER$(sldvol, 0, 15)
 a$=a$+ "<br>"
 OnHtmlChange setvol
 a$=a$+BUTTON$("X", muteclick) 
 a$=a$+ "<br>"
 html a$
 
return

dorssi:  'routine called by timer to update signal strength display value
  RDAssi
  txtssi$= str$(rssi)
  refresh
return

setvol:
    'RDA5807 volume is 0 to 15      
  if HtmlEventVar$="sldvol" then
    v = sldvol    
    RDAvol v  
  endif        
return

buttonclick:   
 ' have to search for the button
 for id=1 to maxstn
   if station$(id)=HtmlEventButton$ then exit for
 next id
 if id>maxstn then return 
 setfreq id 
return

muteclick:
  if muted = 0 then muted = 1 else muted = 0  
  RDAmute muted
return

sub setfreq(id)
  f$ = str$(stnfreq(id)/10)
  t$ = station$(id) & " on " & f$
  text$= t$ 'change text line to show station and frequency  
  freq =  stnfreq(id)
  RDAfreq freq
  timer0 300, dorssi  'start the timer for signal strength display
  refresh
end sub

'_________________________________________________

'RDA5807 routines

sub RDAinit
' Initialize the RDA5807M chip  with a soft reset for 500ms 
  I2C.BEGIN RDAaddr
  I2C.WRITE RDActrlreg  ' Register address &h02
  I2C.WRITE &hD0  'normal audio, no mute, stereo, bass boost
  I2C.WRITE &h03 ' soft reset bit 1
  stat = I2C.END 
  if stat<>0 then wlog "I2C error ";stat
  pause 500 ' wait 500ms
   
  I2C.BEGIN RDAaddr 
  I2C.WRITE RDActrlreg  
  I2C.WRITE &hD0
  I2C.WRITE &h0D ' Setup the radio for communications
  stat = I2C.END
  if stat<>0 then wlog "I2C error ";stat
  pause(500)
  RDAvol 1
end sub

sub RDAfreq(f)
  freqB = f - 870 ' chip needs to have freq offset from lowest freq (870)
  freqH = freqB>>2 ' need to break the offset freq into 2 parts (hi/low)
  freqL = (freqB AND 3) <<6 ' Shift channel selection for matching register &h03 
   
  I2C.BEGIN RDAaddr
  I2C.WRITE RDAfreqreg   
  I2C.WRITE freqH ' write High freq byte
  I2C.WRITE (freqL + &h10) ' write Low freq byte
  stat = I2C.END
  if stat<>0 then wlog "I2C error ";stat
  RDAssi
end sub

sub RDAvol(v)
' The volume is from 0-F, leave all the other bitss (&h84D0 - &h84DF)
  v = v and &h0f 
  v = v + &hD0 
  I2C.BEGIN RDAaddr
  I2C.WRITE RDAvolreg 
  I2C.WRITE &h84  ' reserved bits - don't change
  I2C.WRITE v ' set volume to v
  stat = I2C.END
  if stat<>0 then wlog "I2C error ";stat
end sub

sub RDAmute(m)
  if m = 1 then reg = &hA0 else reg = &HD0    
  I2C.BEGIN RDAaddr
  I2C.WRITE RDActrlreg 
  I2C.WRITE reg
  I2C.WRITE &h0D ' leave other bits
  stat = I2C.END
  if stat<>0 then wlog "I2C error ";stat
end sub

sub RDAssi  
  rssi = I2C.ReadRegByte( RDAaddr, RDAssireg)
  rssi = rssi and &hfe
  rssi = rssi >>2 
end sub



stations.txt

cicciocb

unread,
Dec 12, 2019, 3:26:21 PM12/12/19
to Annex WiFi RDS
Nice project, and a good example on how implement "drivers" directly into the basic.

Great work, bugs!

Bugs

unread,
Dec 14, 2019, 11:20:19 AM12/14/19
to Annex WiFi RDS
I wired a small proto board to squeeze into the base of one of a pair of 3" passive PC speakers.
If any one else plays, the PAM8403 data sheet has some dire warnings about how to destroy the chip.
I had to insert 100k resistors between the receiver output and the amplifier input as the gain was far too high.
With only 3" speakers there was not much chance of hearing any bass so the coupling capacitors were only 100nF.
The circuit is attached (may be errors) but the photographs took about 12MB which would not be a welcome email attachment so the complete pdf is available (I hope) at this dropbox link:-


fmradio.pdf

cicciocb

unread,
Dec 14, 2019, 12:07:48 PM12/14/19
to Annex WiFi RDS
Nice job Bugs.
I think it worth a project page on the web site.

cicciocb

Michael Stevens

unread,
Dec 14, 2019, 5:41:18 PM12/14/19
to Annex WiFi RDS
Hi cicciocb,

A nice piece of work from Mr Bugs, I agree would make a nice little project page to show off the flexibility of Annex Basic. A good demonstration of the tools you have created and where people are taking them in own area of hobby interests. Nice little radio alarm clock springs to mind straight away, NTP time server and possibly a DS3231 RTC as a fallback solution. 

Bugs, I think previously you had indicated you had an interest in amateur radio, if that is the case is a similar module based on a Silabs chip (the number is escaping me at present) that with an XTAL change can be pushed to 144MHz  - now somewhat coming back to me that you need to vary this input and an I2C synth module was required. I have that module so must have been planning to experiment at some stage. All the same, is good work from Basic and I think is a nice example for others to follow and add features they want. Learning is priceless and whilst this all seems trivial at a level of making an FM Radio can become far more complex when we get some success and delve into matters with datasheets. 

Regards
Mike.

cicciocb

unread,
Dec 15, 2019, 7:07:00 AM12/15/19
to Annex WiFi RDS
It works also for the ESP32 with the same code.


Bugs

unread,
Dec 15, 2019, 10:34:45 AM12/15/19
to Annex WiFi RDS
Thanks for the comments.  I have tinkered a bit by adding a "status" line at the bottom which just shows any detected I2C errors or "muted".
Also save the last station used and the volume setting to a file so when booted again it starts where you left it.

Many thanks to cicciocb who kindly provided the attached styles.css file and modified the html to vastly improve the appearance!

Modified code:-

CODE: xxxx.bas

'Simple FM receiver using RDA5807 module
'displays up to 12 station names, a volume slider, mute button and signal strength.
'Needs a text file with local FM station names and frequencies
'see local station file "stations.txt" as example

RDAaddr = &h11
RDActrlreg = &h02
RDAfreqreg = &h03
RDAvolreg = &h05
RDAssireg = &h0b

freq = 0
freqB = 0
freqH = 0
freqL = 0
muted = 0
rssi = 0
oldssi=-1
status$="Initialising"
chdelay=15000  '15 seconds before save a change
chtime=0  'time of a change
vol=0

' read in text file of station names (8 chars max) and frequencies
fl$="/stations.txt"
maxstn=val(file.read$(fl$,1))  'first line sets number of stations in the file 
if maxstn>12 then maxstn=12  ' a maximum of 12 
  
dim station$(maxstn)
dim stnfreq(maxstn)
dim but$(maxstn)  'the buttons

For i=1 to maxstn
  a$=file.read$(fl$,i+1)  
  n = instr(a$,",")  
  b$=left$(trim$(left$(a$,n-1)),8)  'truncate long station names
  c$=trim$(mid$(a$,n+1))   
  station$(i)=b$
  stnfreq(i)=int(val(c$)*10)
Next i

I2C.SETUP 0,2   'usual I2C pins

fl$="/lastfv.txt"
if file.exists(fl$) then
  a$=file.read$(fl$)
  id=val(word$(a$,1))
  vol=val(word$(a$,2))
else
  id=1  'start at first station if no file available
  vol=1  'and low volume
endif
text$ = "FM Radio"
sldvol=vol
txtssi$="  "
gosub drawscreen
OnHtmlReload drawscreen
pause(3000)
status$=""
   RDAinit  'initialise the RDA5807 to Europe/USA FM band 100kHz spacing etc    
   v=vol   'don't want rdavol to change vol variable
    RDAvol v 
   setfreq id
wait

drawscreen:
'draw the screen
cls
a$ = |<link rel="stylesheet" href="styles.css">|
a$=a$ & TEXTBOX$(text$)
a$=a$+ "<br>"
a$=a$+TEXTBOX$(txtssi$)
a$=a$+"<br>"
 html a$
' create the station buttons
a$=""
for i=1 to maxstn
  stn$= station$(i) 
  a$=a$+  BUTTON$(stn$, buttonclick,"but") 
  if (i mod 2) =0 then a$=a$+ "<br>"
next i
a$=a$+ "<br>"
html a$
' add the other screen items 
 a$=SLIDER$(sldvol, 0, 15,1,"slider")
 a$=a$+ "<br>"
 OnHtmlChange setvol
 a$=a$+BUTTON$("X", muteclick,"mute") 
 a$=a$+ "<br>"
 a$=a$ & textbox$(status$)
 html a$ 
  autorefresh 300
return

dorssi:  'routine called by timer to update signal strength display value etc
  
  RDAssi
  if rssi<>oldssi then
    txtssi$= str$(rssi)
    'refresh
    oldssi=rssi
  endif
  if chtime>0 
    if millis>=(chtime+chdelay)  then
      chtime=0  'clear flag 
      file.save fl$,str$(id) & " " & str$(vol)     
    endif
   endif
return

setvol:
    'RDA5807 volume is 0 to 15      
  if HtmlEventVar$="sldvol" then
    vol = sldvol 
    v=vol   'don't want rdavol to change vol variable
    RDAvol v  
    chtime=millis  'flag a change
  endif        
return

buttonclick:   
 ' have to search for the button
 for id=1 to maxstn
   if station$(id)=HtmlEventButton$ then exit for
 next id
 if id>maxstn then return 
 setfreq id 
return

muteclick:
  if muted = 0 then muted = 1 else muted = 0 
  if muted=1 then status$="Muted" else status$="" 
  RDAmute muted
  'refresh
return

sub setfreq(id)
  f$ = str$(stnfreq(id)/10)
  t$ = station$(id) & " on " & f$
  text$= t$ 'change text line to show station and frequency  
  freq =  stnfreq(id)
  RDAfreq freq
  chtime=millis  'flag a change
  timer0 300, dorssi  'start the timer for signal strength display
  'refresh
end sub

'_________________________________________________

'RDA5807 routines

sub RDAinit
' Initialize the RDA5807M chip  with a soft reset for 500ms 
  I2C.BEGIN RDAaddr
  I2C.WRITE RDActrlreg  ' Register address &h02
  I2C.WRITE &hD0  'normal audio, no mute, stereo, bass boost
  I2C.WRITE &h03 ' soft reset bit 1
  stat = I2C.END 
  if stat<>0 then
    status$="RDAinit 1 I2C error " &str$(stat)
   wlog status$
  endif
  pause 1000 ' wait 500ms
   
  I2C.BEGIN RDAaddr 
  I2C.WRITE RDActrlreg  
  I2C.WRITE &hD0
  I2C.WRITE &h0D ' Setup the radio for communications
  stat = I2C.END
  if stat<>0 then
    status$="RDAinit 2 I2C error " &str$(stat)
   wlog status$
  endif
  pause(500)
 ' RDAvol 1
end sub

sub RDAfreq(f)
  freqB = f - 870 ' chip needs to have freq offset from lowest freq (870)
  freqH = freqB>>2 ' need to break the offset freq into 2 parts (hi/low)
  freqL = (freqB AND 3) <<6 ' Shift channel selection for matching register &h03 
   
  I2C.BEGIN RDAaddr
  I2C.WRITE RDAfreqreg   
  I2C.WRITE freqH ' write High freq byte
  I2C.WRITE (freqL + &h10) ' write Low freq byte
  stat = I2C.END
  if stat<>0 then
    status$="RDAfreq I2C error " &str$(stat)
   wlog status$
  endif
  pause(500)
  RDAssi
end sub

sub RDAvol(v)
' The volume is from 0-F, leave all the other bitss (&h84D0 - &h84DF)
  v = v and &h0f 
  v = v + &hD0 
  I2C.BEGIN RDAaddr
  I2C.WRITE RDAvolreg 
  I2C.WRITE &h84  ' reserved bits - don't change
  I2C.WRITE v ' set volume to v
  stat = I2C.END
  if stat<>0 then
    status$="RDAvol I2C error " &str$(stat)
   wlog status$
  endif
end sub

sub RDAmute(m)
  if m = 1 then reg = &hA0 else reg = &HD0    
  I2C.BEGIN RDAaddr
  I2C.WRITE RDActrlreg 
  I2C.WRITE reg
  I2C.WRITE &h0D ' leave other bits
  stat = I2C.END
  if stat<>0 then
    status$="RDAmute I2C error " &str$(stat)
   wlog status$
  endif
styles.css
Reply all
Reply to author
Forward
0 new messages