A physical radio can be a satisfying product idea: a few clear controls, a speaker and local broadcasts, with no app or account. The first prototype may be quick to assemble. The harder question is whether it still receives something useful after you change the power supply, move the antenna and put everything in a case.
It helps to separate three jobs: receiving a station, controlling the tuner, and turning the audio into sound. A successful software connection only checks one of them.
On our bench we built a radio from a GraftSense board carrying a TEA5767 receiver module and a PAM8403 speaker amplifier, driven by a GraftPort-RP2040 controller. This note covers that setup, what our sweep result does and does not mean, and the reception and integration checks that come next.
Choose broadcast radio for the right kind of experience
FM makes sense when listening to local broadcasts is part of the experience. It suits an exhibit poorly if a particular instruction or sound has to play at a predictable moment; a stored audio clip gives you that control, while a broadcast receiver depends on the station and reception where it sits.
The product's form also affects the radio. In his April 2025 accessible FM radio case study, Simon Monk looked for a compact antenna because a telescopic one did not fit his design, and compared options on a known station while holding other conditions steady. That method is worth copying; his antenna results will not predict reception in your enclosure.
Decide where the prototype will be used, which controls a person needs, and how the antenna can be positioned. A desk radio, a handheld object and an installation inside a metal cabinet pose different questions even with the same tuner.
Follow the audio path before writing the controls
The antenna feeds the TEA5767 module. That module produces left and right analog audio, which pass through a volume potentiometer to the PAM8403 amplifier and on to the speakers. The RP2040 uses I2C to set tuning and read status. No audio travels over those two wires.
The 3.5 mm socket on this board is an antenna input, not a headphone output. Other TEA5767 boards have different sockets and audio circuits, so their connection instructions are not interchangeable.
Each speaker connects across its own amplifier output pair: L+ with L−, or R+ with R−. The negative terminals are driven outputs, not ground. Do not join them or wire them as the shared return of a headphone plug. Diodes' PAM8403 datasheet shows this differential output arrangement.
We used 4 ohm speakers labeled 3 W. That label is not a measured clean output for the assembled radio. The amplifier's 3 W headline figure assumes a 4 ohm load, a 5 V supply and 10% distortion; the enclosure, speaker and listening quality you want still need their own assessment.
The bench setup
We connected the board to the controller's I2C0 port (GP4 SDA, GP5 SCL), fitted a telescopic antenna and connected the speakers. The board takes 5 V; its schematic shows an AMS1117-3.3 regulator for the receiver section and 4.7 kohm I2C pull-ups to 3.3 V. That is why the board's power input and the controller's signal voltage are separate considerations. Start with the volume low and change wiring only with power off.
| Connection | Purpose |
|---|---|
| GP4 to SDA, GP5 to SCL | Tuner commands and status |
| 5 V input and ground | Board power |
| Antenna to the labeled antenna socket | FM reception |
| Speaker to its L+/L− or R+/R− pair | Amplified audio |
The first software check is whether address 0x60 appears on the bus. That establishes communication with the tuner. It does not show that the antenna receives a station or that the amplifier and speaker path work.
What a frequency sweep can and cannot tell you
Our program used the Radio class from Alan Wang's micropython-TEA5767 driver (MIT, now archived), in a packaged copy. It stepped from 87.5 to 108.0 MHz in 0.1 MHz steps, paused at each frequency, read the tuner's signal level from 0 to 15, and tuned back to the first frequency with the highest value. A trimmed version:
best_frequency, best_level = None, -1
for tenths in range(875, 1081):
radio.set_frequency(tenths / 10)
sleep_ms(50)
radio.read()
if radio.signal_adc_level > best_level:
best_frequency, best_level = tenths / 10, radio.signal_adc_level
Our first run waited 20 ms per step; 50 ms is a starting point to try, not a validated settling time. If every level reads zero, report that rather than presenting 87.5 MHz as a selection.
A sweep is not proof that the strongest reading is a clear station. A coarse 0 to 15 score tells you nothing about program content, audible noise or whether the frequency is useful to the listener. Check a known local station on an ordinary radio first, then compare the prototype at the same spot.
Watch the stereo setting too. In the copy we used, passing stereo=True wrote 1 to the chip's MS bit, which the NXP datasheet defines as forced mono. Passing stereo=False left stereo decoding available. Check how the version you install maps that argument.
The driver's US and JP options select frequency ranges; they are not complete regional configurations. Its fifth control byte is fixed to zero, which selects 50 microsecond de-emphasis, the receiver's frequency-response correction for the broadcast signal. Confirm the band, tuning step and de-emphasis required where the product will be used.
Our terminal reported 87.5 MHz, a signal level of 7 out of 15, and "Stereo mode: No." That is the result for that run in that room. It is not a station recommendation for another location, and because of the stereo-bit issue the last line says little about reception quality. We also made a short 12-second recording of the speaker output; one clip does not establish performance across the coverage area or inside a final enclosure.
Change one part of the setup at a time
Once a known station is audible, keep that frequency fixed and change the physical arrangement: antenna position first, then the power source, then the rest of the electronics and the enclosure. Record both the signal indication and what a listener hears. A score alone can hide a result that sounds unpleasant or drops out.
Power deserves its own comparison. In an October 2025 r/esp8266 thread, a builder reported good reception on laptop USB but poor reception after moving to a battery and boost converter. The cause was not established, but it shows why portable power should be tested as a changed system even when a meter shows the right voltage.
Run the intended power source with the controller, display and amplifier in their normal states. If reception changes, isolate the cause before adding filters at random: vary the source, the cable routing or the active subsystem one at a time. The board already has supply filtering, but we have no comparative noise or enclosure test for it.
Leave room for the antenna connection and for the volume knob to work mechanically. A case that blocks the connector, presses the antenna against a metal wall, or makes the listener hold the object in one position can undo a good bench demonstration. Test with controls and cables where they will actually be.
Evaluate the amplifier with the chosen speaker and case. Listen for distortion across the useful volume range instead of treating the top of the knob as the target, and check supply behavior and temperature at that setting. We have no measured acoustic output, battery runtime or thermal result for this setup.
A repeatable listening test
Before making several units, choose a few known stations and representative locations. For each, note the antenna arrangement, supply, volume setting, and whether a listener can find and hear the intended station. Repeat after assembly. That turns "it played once" into a test someone else can run.