Making a Bluetooth adapter for a Car Phone from the 90's

Hmm... I just thought of a potentially relevant difference between my waveform generator testing and actual audio output: my waveform generator is very limited on how far the signal can be offset in the negative direction, so I was testing with a signal that never went negative, while still grounding the second wire. So my signal was swinging from 0V - 0.5V when the handset was behaving well, and I encountered the strange behavior after the signal started exceeding 0.5V max.

With the actual audio produced by my MCU/circuit, it swings +/- around 0V, so if I doubled the voltage to be 1V peak-peak for volume compensation, it still wouldn't exceed +0.5V (but would also swing down to -0.5V).

I have no idea whether this is actually a relevant difference or not that would make it "safer" for me to double my signal voltage.
 
It may also be possible that it was actually my waveform generator causing the loud "pop" sound? It's not a super high quality waveform generator because it's part of a 3-in-1 tool that cost $200, so it may have some "glitches" when changing voltage level?

I'm really just scared of exceeding the voltage levels I have observed from the original phone, because I'm pretty close to having no idea what I'm doing with electronics and I don't want to damage the phone.
 
Last edited:
You should connect your audio via a capacitor to block any DC, this makes the DC offset of the generator of no relevance, and will make the signal both negative and positive.

Your fears are totally without merit - preamplifiers don't 'blow up' with a slight increase in signal level, if you stick mains directly in the socket there's likely to be an issue however In a similar vein, if you connect the output of a 500W amplifier directly to a mike input that will cause damage as well - a low power amplifier (perhaps as much as 10W or more) is unlikely to cause damage though.

It's quite simple, strap the input as single ended, use a DC blocking capacitor, attenuate the signal from the micro to a suitable level (and this can vary over a pretty impressive range)
 
You're confusing yourself, the point of differential (balanced) inputs is so you can have the microphone 100's of feet away,
In the case of the phone, it's because power for the LCD, audio amp, keypad etc. is fed through a thin curly cable along with the audio.

If the same ground were used, the varying voltage drop on the cable would be superimposed on the audio.

Using a differential feed avoids any ground noise being introduced.
 
You should connect your audio via a capacitor to block any DC
Already taken care of in my actual audio circuit. I just wasn't doing this when testing with the waveform generator (didn't really understand the magic of that capacitor at the time).

Your fears are totally without merit...
Thanks for the reassurance. I'll play around with some R values to get the output closer to 1V peak-peak. To help alleviate my fears, I do have a junk handset I'm using for testing just in case I do something stupid. So your assurance plus some successful extended testing with the junk handset should be good.

Using a differential feed avoids any ground noise being introduced.
I can definitely hear noise through the speaker whenever digital UART commands are transmitted. Something I can live with for now while I develop the rest of the functionality, but I'll want to solve it eventually. I wasn't sure if that noise was caused by my current lack of differential audio signal, or if I just needed to refine my circuit to reduce/isolate noise in general (being on a breadboard with haphazard component placement and no large ground plane probably isn't helping).


After I mess around with it a bit more, I'll post more details of where I'm at now (circuit diagram, waveforms on the oscilloscope, demo of actual sound coming through the handset, etc.). I just received a package today with a digital potentiometer so I can start programmatically controlling volume and a PICKIT 4 so I can switch over to developing for the PIC18F27Q43 and bump up my DAC resolution from 5-bit to 8-bit
 
Last edited:
After way more time and struggle than I'd like to admit, I now have my project ported over to the PIC18F27Q43, running at 32MHz now, with audio tones being generated through the 8-bit DAC at 10kHz sampling rate. It sounds pretty decent, but there's definitely some noise still (most noticeably interference from the UART communication).



I used the 2-stage RC network suggested by rjenkinsgb , and it seems to have produced nice results.

Here's the circuit (questions about fine tuning this later in this post):

And here's some before/after examples of the raw waveforms from the DAC (with DAC output disconnected from the rest of the circuit for measurement), then the filtered waveforms at the wiper of the POT with volume turned all the way up (with handset audio wire disconnected for measurement).

769Hz:


1333Hz:


769Hz + 1333Hz:


938Hz + 1200Hz





So now I'm a bit lost and hoping for some guidance on how to tune the R/C values to get the desired power output to the handset:
  • With the handset fully connected directly to the original phone transceiver, I observe about 0.5V peak-peak on both of the differential audio lines.
  • With the handset audio line disconnected from my circuit, I observe about 0.76-0.8V peak-to-peak when my volume POT is turned all the way up.
  • But after I connect the handset audio line to the output of my circuit, it drops to about 0.45V peak-to-peak, which is quite close to the original 0.5V, but I'm aiming for about 1V peak-to-peak for now to regain the max volume that is lost by supplying only a single audio signal and grounding the second audio input to the handset.
Nigel Goodwin - BTW, I did actually try out the PWM approach to generating the tones. The code change was extremely easy, because I used the same exact code and hard-coded waveform sample data, but just wrote out to the PWM duty cycle instead of writing out to the DAC. The end result was decent, but more noisy than the DAC approach (with the same exact circuit; maybe it requires different filtering configuration)? It was an interesting experiment, but the DAC approach seems to be working better for now.

Bonus progress for today: I have a functioning replica of the original phone's battery level display (based on ADC input of the supply voltage from the transceiver, divided down to be below 5V). I showed this in a previous video, but it was a proof-of-concept with a hard-coded batter level value at the time.
 
Last edited:
You could add another opamp and filter from the DAC, but configured for inverting, to drive the other line?

Or halving the series resistors and doubling the capacitor values, to increase the voltage to the pot?
 
I started working on code to manage sounds (ability to define/play multi-note tone sequences for ringtone, etc.), so of course I had to make the phone play part of a song. A friend challenged me to make it play "Axel F" when calling 911:

 
Here's the list of ringtones from the PIC Nokia ringtone player, if you want to add extra tunes:

C:
#ifdef AllTheSmallThings
    /* AllTheSmallThings */
    const unsigned char static Melody[] = {"8e6,8e6,e6,e6,p,8e6,8f6,e6,d6,p,8d6,8e6,d6,c6,p,8e6,8e6,e6,c.6,e.6,8e6,e6,8e6,e6,8c6,c6,c6,c6,8d6,d6,8d6,d6,8d6,f6,8c6,c6,c6,c6"};
    defaultoctave = 5;
    defaultduration = 4;
    beat_speed = 218;  //160;
#endif

#ifdef AdamsFamilyTheme
    /* AdamsFamilyTheme */
     const unsigned char static Melody[] = {"8c6,f6,8a6,f6,8c6,b,g.6,8f6,e6,8g6,e6,8e,a,f.6,8c6,f6,8a6,f6,8c6,b,g.6,8f6,e6,8c6,d6,8e6,f.6,8c6,8d6,8e6,8f6,1p,8d6,8e6,8f#6,8g6,1p,8d6,8e6,8f#6,8g6,p,8d6,8e6,8f#6,8g6,p,c6,8e6,1f6"};
    defaultoctave = 5;
    defaultduration = 4;
    beat_speed = 218;  //160;
#endif

#ifdef AxelF
    /* AxelF */
    const unsigned char static Melody[] = {"32p,8g,8p,16a#.,8p,16g,16p,16g,8c6,8g,8f,8g,8p,16d.6,8p,16g,16p,16g,8d#6,8d6,8a#,8g,8d6,8g6,16g,16f,16p,16f,8d,8a#,2g,4p,16f6,8d6,8c6,8a#,4g,8a#.,16g,16p,16g,8c6,8g,8f,4g,8d.6,16g,16p,16g,8d#6,86,8a#,8g,8d6,8g6,16g,16f,16p,16f,8d,8a#,2g"};
    defaultoctave = 5;
    defaultduration = 4;
    beat_speed = 204;  //125;
#endif

#ifdef AxelF2
    /* AxelF - mod to 8A#6*/
    const unsigned char static Melody[] = {"32p,8g,8p,16a#.,8p,16g,16p,16g,8c6,8g,8f,8g,8p,16d.6,8p,16g,16p,16g,8d#6,8d6,8a#6,8g,8d6,8g6,16g,16f,16p,16f,8d,8a#6,2g,4p,16f6,8d6,8c6,8a#6,4g,8a#6.,16g,16p,16g,8c6,8g,8f,4g,8d.6,16g,16p,16g,8d#6,86,8a#6,8g,8d6,8g6,16g,16f,16p,16f,8d,8a#6,2g"};
    defaultoctave = 5;
    defaultduration = 4;
    beat_speed = 204;  //125;
#endif

#ifdef HappyBirthday
    /* HappyBirthday */
    const unsigned char static Melody[] = {"8g.,16g,a,g,c6,2b,8g.,16g,a,g,d6,2c6,8g.,16g,g6,e6,c6,b,a,8f6.,16f6,e6,c6,d6,2c6,8g.,16g,a,g,c6,2b,8g.,16g,a,g,d6,2c6,8g.,16g,g6,e6,c6,b,a,8f6.,16f6,e6,c6,d6,2c6"};
    defaultoctave = 5;
    defaultduration = 4;
    beat_speed = 204; //125;
#endif

#ifdef Itchy
    /* Itchy & Scratcy */
    const unsigned char static Melody[] = {"8c,8a5,4p,8c,8a,4p,8c,a5,8c,a5,8c,8a,4p,8p,8c,8d,8e,8p,8e,8f,8g,4p,8d,8c,4d,8f,4a#,4a,2c7"};
    defaultoctave = 6;
    defaultduration = 8;
    beat_speed = 233; //198;
#endif

#ifdef MissionImpossible
    /* Mission Impossible */
    const unsigned char static Melody[] = {"16d5,16d#5,16d5,16d#5,16d5,16d#5,16d5,16d5,16d#5,16e5,16f5,16f#5,16g5,8g5,4p,8g5,4p,8a#5,8p,8c6,8p,8g5,4p,8g5,4p,8f5,8p,8p,8g5,4p,4p,8a#5,8p,8c6,8p,8g5,4p,4p,8f5,8p,8f#5,8p,8a#5,8g5,1d5"};
    defaultoctave = 6;
    defaultduration = 4;
    beat_speed = 214; //150;
#endif
 
You could add another opamp and filter from the DAC, but configured for inverting, to drive the other line?

Or halving the series resistors and doubling the capacitor values, to increase the voltage to the pot?

I just learned about the INA105, which looks like a good candidate for generating my inverted signal. It can be setup as a unity gain or an inverting unity gain without any external components.



I believe it would make sense for me to keep my existing unity gain op amp as-is just for buffering the output of the DAC before filtering and volume control, then add one of these after my coupling cap and volume control to generate my inverted signal?

Would it be best to use two of these (one as a unity gain, the other as an inverting unity gain) to ensure some sort of "consistency"/"balance" between both inputs to the handset audio?

I also need to consider that I'll eventually also need to take audio from the Bluetooth chip and convert it to differential input to the handset, so I think it would make most sense to generate that differential signal as close to the handset connection as possible (do any audio mixing/switching between MCU output and Bluetooth audio, and volume control, before generating differential signals).
 

Yes, that definitely makes more sense for the overall system.

The opamp is also very interesting for multiple applications - though it does need a dual supply or minimum 10V single supply, from the data.
 
Here's the list of ringtones from the PIC Nokia ringtone player, if you want to add extra tunes:

Thanks

Is that some kind of common/standard notation for describing simple melodies? That looks much more concise than the hack job I threw together in one afternoon . Can you point me to an explanation of that notation format?

I need to decide how far I want to go with this music/ringtone stuff. I have an extremely simple but verbose approach for defining my note sequences right now (array of structs containing pointers to hard-coded arrays of waveform sample data and duration in milliseconds for each note), but I don't really need anything more than this to define the very simple tones/effects of the original phone.

Now I'm considering supporting a string notation like your examples, and even supporting 2 separate tracks that play simultaneously (because my tone generator code is setup to play single and dual tones, so why not take advantage of that for some harmonies or bass lines in the music?).

I'm liking the idea of having several fun ringtones available to choose as a user setting, and still have a replica of the original ringtone available.
 
Nigel Goodwin Wow, that's a pretty clever way to generate any frequency (within reason) from a single sine lookup table. I think I will try to switch over to that approach, but still probably use the DAC rather than PWM. I like how the frequency can be changed without losing the current "position" within the waveform, so no "popping" sounds when changing frequencies.

I'm guessing his simpler 1-stage filter is possible due to the higher sample rate (62kHz, compared to my current 10kHz)?

Thanks for sharing!
 
I've been continuing development of general functionality of the phone, such as:
  • Ability to store/recall/browse phone numbers in a directory of up to 30 numbers.
  • Improving sound-related code to manage volume levels and target audio output (ear speaker vs. loud speaker).
  • Implementing volume control via SPI communication with a digital potentiometer.
  • Switching to a new method of generating tones.
  • Storing many persistent settings in EEPROM (LCD viewing angle, volume levels, last dialed number, last browse index within the number directory, phone number directory entries, 3 speed dial numbers, etc)

Here's a demo of some phone number directory and volume control functionality:



I switched my tone generation to the approach that Nigel Goodwin shared, using only a single sine wave lookup table to generate a wide range of tone frequencies with very little error. Here's a more detailed explanation of the approach (which I didn't find until I had figured it out myself already): https://www.romanblack.com/one_sec.htm#BDA

In that example, they used 6-bit precision for the "integer" part of the index into the lookup table (64 samples in the table), and 16-bit precision for the "fractional" portion. I found the 16-bit fractional precision to be overkill. With 8-bit fractional precision, I'm generating tones with frequency error in the +/-0.02% range, which is way better than the amount of error with my previous 1-waverform-per-frequency approach. To reduce error in the voltage level per sample, I use 8-bit precision for the "integer" part. So I have a 256 sample sine wave table, containing 8-bit sample values, and 8-bit fractional precision for my iterator through that sine wave table. I also bumped my sampling rate up to 20kHz so I can generate some higher frequency tones.

Here's examples of a dual 941Hz + 1477Hz tone, both as raw DAC output from my MCU at 20kHz, and after filtering to smooth it out:




Managing the volume level and speaker output has been a fun challenge:
  • There are multiple volume levels for different kinds of sounds.
  • Some kinds of sounds always go to the loudspeaker, while others go to the ear speaker or loudspeaker, depending on whether the handset is off-hook or on-hook (wherever the user is expected to be "listening").
  • There can be an ongoing "background" sound with one volume level and speaker output (e.g., the "call failed" tone) that gets temporarily interrupted by a sound with a different volume level and speaker output (e.g., a button press beep).
  • I basically have a "sound manager" that supports two "channels" (background and foreground), 5 volume level modes, and 2 target outputs (loudspeaker only, or smart selection depending on the handset on-hook status). It manages changing volume via the digital pot, and switching which speaker is active, as sounds are played/stopped, volume levels are changed, background channel gets interrupted by a sound on the foreground channel, or the on-hook status changes.
  • Timing the switching of speakers with when to begin playing the next sound was fun because of the slow 800 baud communication with the handset to enable/disable speakers. I have to briefly stop the sound, allow time for one speaker to become disabled, before I can re-enable the sound.
  • I also had to implement a special case for speaker commands to jump to the front of the UART send buffer. Otherwise, there were situations where the speaker changes would be delayed by a bunch of screen update commands (as much as 200ms delay in some cases!).
It will get even more complicated when I start mixing in the need to switch between generated tones or passing through voice audio (through volume control), or controlling whether generated tones go to the handset, or to the Bluetooth module as DTMF beeps output over the phone call (or both?)
 
Last edited:
Today I implemented the ability to store names with phone numbers in the directory. Directory entries can now be browsed in alphabetical order when displaying names, or directory index order when displaying numbers. You can also jump directly to entries starting with a particular letter.

This is all a replica of the original behavior of the car phone (except I only support 30 entries instead of 99 due to limited EEPROM size).

 
I started trying to work with the BM62 Bluetooth module. I got it soldered to a breadboard adapter and spent many hours fighting with inadequate documentation and arcane configuration tools to reach a dead end (UPDATE: crisis averted - it was a short between two pins caused by sloppy soldering; more in upcoming post).

I successfully updated the firmware and wrote a custom configuration to the module. It shows up as an available Bluetooth device on my phone, but pairing fails. The LED indicators on the board seem to indicate that it is stuck in an infinite reboot loop (restarts about once every second).

I’ve tried many combinations of configuration options, and even some of the provided default/demo configurations, trying to just get anything to work. Documentation for this stuff is horrendous, and there’s practically zero online community/forum support for it (most forum threads about it have zero responses and are a couple years old).

This infinite reboot behavior makes no sense, so I’m left to assume I messed something up when soldering the chip to the board (my first attempt of soldering any kind of small surface mount connections). I’m starting to think my best path forward is to order a new chip and adapter board and pay an expert to solder it for me this time to rule out hardware issues.
 
Last edited:
Cookies are required to use this site. You must accept them to continue using the site. Learn more…