Shioiri YoshiakiShasha Liulukasmaximus89SophiaXue
Published © MIT

M5Stack FM Radio

An FM radio (RDA5807) powered by UIFlow. πŸ“»

IntermediateProtip10 hours188
M5Stack FM Radio

Things used in this project

Hardware components

M5Stack FIRE IoT Development Kit (PSRAM 2.0)
M5Stack FIRE IoT Development Kit (PSRAM 2.0)
×1
RDA Microelectronics rda5807
×1

Story

Read more

Code

FM Radio Code

MicroPython
Turns your M5Stack into an FM radio
from m5stack import *
from m5ui import *
import i2c_bus

clear_bg(0x222222)

btnA = M5Button(name="ButtonA", text="ButtonA", visibility=False)
btnB = M5Button(name="ButtonB", text="ButtonB", visibility=False)
btnC = M5Button(name="ButtonC", text="ButtonC", visibility=False)
label1 = M5TextBox(21, 74, "FM", lcd.FONT_DejaVu56,0xFFFFFF, rotate=0)
rgb = RGB_Bar()

i2c_l = i2c_bus.get(i2c_bus.PORTA)
i2cAddr = (0x22 >> 1)

def register_short(register, value=None, buf=bytearray(2)):
  if value is None:
    i2c_l.readfrom_mem_into(i2cAddr, register, buf)
    return buf[0]*256 + buf[1]
  buf[0] = (value & 0xff00) >> 8
  buf[1] = value & 0x00ff
  i2c_l.writeto_mem(i2cAddr, register, buf)

def write_u16(address, val):
  return register_short(address, val)

def read_u16(address):
  return register_short(address)
  
def getRegister(address):
  return read_u16(address)

def updateRegister(reg, mask, value):
  write_u16(reg, (read_u16(reg) & ~mask | value))
  
def lowByte(byte):
  return byte & 0x0F
  
def highByte(byte):
  return byte >> 4

RDA5807M_BandLowerLimits = [8700, 7600, 7600, 6500, 5000]
RDA5807M_BandHigherLimits = [10800, 9100, 10800, 7600, 6500]
RDA5807M_ChannelSpacings = [100, 200, 50, 25]
RDA5807M_BAND_WEST = (0x0 << 2)
RDA5807M_BAND_JAPAN = (0x1 << 2)
RDA5807M_BAND_WORLD = (0x2 << 2)
RDA5807M_BAND_EAST = (0x3 << 2)
RDA5807M_BAND_MASK = 0x000C
RDA5807M_BAND_SHIFT = 2
RDA5807M_REG_CHIPID = 0x00  
RDA5807M_REG_CONFIG = 0x02
RDA5807M_REG_TUNING = 0x03
RDA5807M_REG_VOLUME = 0x05
RDA5807M_REG_BLEND = 0x07
RDA5807M_REG_STATUS = 0x0A
RDA5807M_REG_RSSI = 0x0B
RDA5807M_FLG_ENABLE = 0x0001
RDA5807M_FLG_SEEKUP = 0x0200
RDA5807M_FLG_SEEK = 0x0100
RDA5807M_FLG_EASTBAND65M = 0x0200
RDA5807M_FLG_SKMODE = 0x0080
RDA5807M_FLG_RDS = 0x0008
RDA5807P_FLG_I2SSLAVE = 0x1000
RDA5807M_FLG_DHIZ = 0x8000
RDA5807M_FLG_NEW = 0x0004
RDA5807M_FLG_DMUTE = 0x4000
RDA5807M_STATUS_STC = 0x4000
RDA5807M_VOLUME_MASK = 0x000F
RDA5807M_SPACE_MASK = 0x0003
RDA5807M_READCHAN_MASK = 0x03FF
RDA5807M_RSSI_MASK = 0xFE00
RDA5807M_RSSI_SHIFT = 9
MUTE = False

#lcd.clear()
#lcd.print(volume, 0, 0, 0xffffff)

def seekDown():
  updateRegister(RDA5807M_REG_CONFIG, (RDA5807M_FLG_SEEKUP | RDA5807M_FLG_SEEK | RDA5807M_FLG_SKMODE), (RDA5807M_REG_CHIPID | RDA5807M_FLG_SEEK | RDA5807M_FLG_SEEK | RDA5807M_FLG_SKMODE))

def seekUp():
  updateRegister(RDA5807M_REG_CONFIG, (RDA5807M_FLG_SEEKUP | RDA5807M_FLG_SEEK | RDA5807M_FLG_SKMODE), (RDA5807M_FLG_SEEKUP | RDA5807M_FLG_SEEK | RDA5807M_FLG_SKMODE))

def mute(m):
  global MUTE
  if m == True:
    updateRegister(RDA5807M_REG_CONFIG, RDA5807M_FLG_DMUTE, 0x00)
    MUTE = True
  else:
    updateRegister(RDA5807M_REG_CONFIG, RDA5807M_FLG_DMUTE, RDA5807M_FLG_DMUTE)
    MUTE = False

def volumeDown():
  volume = read_u16(RDA5807M_REG_VOLUME) & RDA5807M_VOLUME_MASK
  volume = volume - 1 if volume - 1 > -1 else 0
  updateRegister(RDA5807M_REG_VOLUME, RDA5807M_VOLUME_MASK, volume)
  if volume == 0:
    mute(True)
  return volume
  
def volumeUp():
  volume = read_u16(RDA5807M_REG_VOLUME) & RDA5807M_VOLUME_MASK
  volume = volume + 1 if volume + 1 <= 15 else 15
  updateRegister(RDA5807M_REG_VOLUME, RDA5807M_VOLUME_MASK, volume)
  if MUTE == True:
    mute(False)
  return volume
  
def getBandAndSpacing():
  band = read_u16(RDA5807M_REG_TUNING) & (RDA5807M_BAND_MASK | RDA5807M_SPACE_MASK)
  space = band & RDA5807M_SPACE_MASK
  if (band & RDA5807M_BAND_MASK == RDA5807M_BAND_EAST) and not (read_u16(RDA5807M_REG_BLEND) & RDA5807M_FLG_EASTBAND65M):
    band = (band >> RDA5807M_BAND_SHIFT) + 1
  else:
    band = band >> RDA5807M_BAND_SHIFT
  return space, band
  
def getFrequency():
  space, band = getBandAndSpacing()
  return int((RDA5807M_BandLowerLimits[lowByte(space)] + (read_u16(RDA5807M_REG_STATUS) & RDA5807M_READCHAN_MASK) * RDA5807M_ChannelSpacings[highByte(band)] / 10))

def getRSSI():
  return (read_u16(RDA5807M_REG_RSSI) & RDA5807M_RSSI_MASK) >> RDA5807M_RSSI_SHIFT

write_u16(RDA5807M_REG_CONFIG, (RDA5807M_FLG_DHIZ | RDA5807M_STATUS_STC | RDA5807P_FLG_I2SSLAVE | RDA5807M_FLG_SEEKUP | RDA5807M_FLG_RDS | RDA5807M_FLG_NEW | RDA5807M_FLG_ENABLE))
updateRegister(RDA5807M_REG_TUNING, RDA5807M_BAND_MASK, RDA5807M_BAND_WEST)

def buttonA_pressed():
  seekDown()
  
def buttonB_pressed():
  global MUTE
  mute(not MUTE)

def buttonC_pressed():
  seekUp()
 
buttonA.wasPressed(callback=buttonA_pressed)
buttonB.wasPressed(callback=buttonB_pressed)
buttonC.wasPressed(callback=buttonC_pressed)

lastTime = 0

seekUp()

while True:
  if time.ticks_us() - lastTime >= 2000000:
    lastTime = time.ticks_us()
    rssi = getRSSI()
    label1.setText(str(getFrequency()))
    if rssi >= 45:
      rgb.set_all(0x0000ff)
    elif rssi >= 40:
      rgb.set_all(0x00ff00)
    elif rssi >= 35:
      rgb.set_all(0xffff00)
    else:
      rgb.set_all(0xff0000)
  wait(0.001)

FMRadio

FMRadio

Credits

M5STACK_RUSSIA

Comments

Add projectSign up / Login