Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

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

So I'm basically aiming to divide voltage of the DAC output so output is in the 0-0.4V range (or less for lower volume, either via adjustment to R values or manually adjustable volume pot) before feeding it into the LM386?
Yep, just with a coupling cap so the input pin has no external DC applied.

A simple R-C filter has a shallow cutoff curve, around 6 db per octave.

10K series and 10nF to ground gives a -3db point of 1592Hz; that means -15db at around 6 KHz.
Two cascaded sections like that look to give about -30db at 10KHz
(Using a calculator here:
http://sim.okawa-denshi.jp/en/CRCRtool.php )

I'd try either two or three sections into a 10K volume pot / preset, and see what the levels are like.

Again use a 10K from the LM386 input to ground and a coupling cap from the pot wiper to that.
 
I made a "Hello World" program for the handset on a microcontroller!


I simulated the original power-on sequence, then added some extra fun to show that I'm in control :).

I'm using a PIC16F1824 for now because it's a spare MCU I already had. Its memory/program size is extremely limited, and it only has 1 UART (I'll need 3 to be able to talk to the handset, transceiver, and the Bluetooth module), but it's enough to get started on developing some basic I/O code to handle user input, update the display, generate tones for button presses, etc.

This will keep me busy for a long time while wait for my Bluetooth module breadboard adapter, continue to research electronic circuit stuff I don't understand, determine which MCU I want to actually use, etc.
 
Last edited:
Will you be using the transceiver once the setup is complete?

If you do need three UARTs, I created a semi-software solution that uses some other common PIC hardware to allow it to run as a background process, rather than software bit-bashing.
 
Will you be using the transceiver once the setup is complete?

My current plan is to still "use" the transceiver, but mostly as a power supply, and to listen for commands from the transceiver that indicate low battery. This approach allows the final result to be a simple inline device that plugs into the handset and transceiver using only the handset cord and a short ethernet patch cable without any additional connections or modifications needed, and it conveniently works regardless of whether the phone is mounted in a car with external power supply, or is being carried as a battery powered portable phone.


If you do need three UARTs, I created a semi-software solution that uses some other common PIC hardware to allow it to run as a background process, rather than software bit-bashing.

I did some initial search and found that there are several Microchip PIC18 MCUs available with more than 3 UART peripherals built in, and they also have a lot more program space and memory, as well as DAC with more bits than what I'm working with now (for generating sound tones). Is there a reason I would need to or should prefer a partial software solution rather than selecting an MCU with enough built-in UARTs?

Due to program space and memory limitations, I absolutely need to get a different MCU anyway, so I may as well choose one that makes my life as easy as possible. And per-unit cost isn't much of a concern for me because it's a one-off personal project. I don't need to complicate things to save a dollar.
 
I did some initial search and found that there are several Microchip PIC18 MCUs available with more than 3 UART peripherals built in, and they also have a lot more program space and memory, as well as DAC with more bits than what I'm working with now (for generating sound tones). Is there a reason I would need to or should prefer a partial software solution rather than selecting an MCU with enough built-in UARTs?
I was thinking for simplicity of prototyping / assembly - do those with three or more UARTs come in dual-in-line packages? Surface mount ICs make things and inconvenient complex, for prototyping..

There are quite a few with two UARTs an everything else needed in DIL versions.

(There are thousands of variations so it may well be there is a triple UART in DIL, but I've not seen one).
 
Looks like I can get them in DIP. Here's an example of one with 64k program memory, 4k ram, 1k EEPROM, 5 UARTs, and 8-bit DAC: (PIC18F26Q43)
Nice!
And, by some miracle, both the 28 and 40 pin DIL ones are in stock at suppliers!!

That's not a series I knew of, but I can see I will be using those for some things in the near future.

(And note the 18F27 / 47 Q43; twice the flash and RAM - I got redirected to those at one site).
 
I've made some good progress on re-implementing some of the original user interface of the car phone. Here's a demo of some of the interactions I have implemented (everything happening on the display is 100% controlled by my code responding to button presses):


Of course, it's not actually making calls or controlling volume of any sound. But I am keeping track of the state of everything in memory.

I also wrote code to generate all the single tone and dual tone sound waveforms, output from the MCU via its 5-bit DAC at 8khz sampling rate:

IMG_6729.JPG
IMG_6730.JPG


I basically have a hard-coded array of samples for each frequency that each seamlessly loop to generate a continuous repeating waveform, with a timer setup to trigger at 8khz to output the next sample value to the DAC. For the dual tone output, I keep track of 2 separate indexes in arrays for 2 tones, add the samples from both arrays together, and divide by 2.

The fun part was generating the arrays of data. I had to figure out a whole number of samples that could create a perfectly repeating wave form that was "close enough" to each frequency I need. After working through some examples manually, I automated the algorithm. I have some JavaScript code I can run in a browser console (I'm a front-end web software engineer, so that's what I'm comfortable with for quick ad-hoc scripting) where I provide a list of target frequencies, a sample rate, and a maximum allowed error percentage for the resulting actual frequencies. It figures out the minimum number of samples necessary (and how many repeats/cycles of the sine wave within that number of samples) to produce a frequency within the specified amount of error of the target.

The script outputs the hardcoded arrays of samples, as well as a table of stats I can easily copy/paste into a spreadsheet like this:

1642657828318.png


Here's the code:
JavaScript:
function calculateToneSamples(targetFreqs, sampleRate, sampleDataBits, terminator, maxErrorPct, maxCycles = 10) {
  let totalSamples = 0;
  const tones = targetFreqs.map((targetFreq) => {
    const exactSamplesPerCycle = sampleRate / targetFreq;
    let cycles = 0;
    let intSamples, actualFreq, errorPct;
 
    do {
      ++cycles;
      intSamples = Math.round(exactSamplesPerCycle * cycles);
      actualFreq = sampleRate * cycles / intSamples;
      errorPct = (actualFreq - targetFreq) * 100 / targetFreq;
    } while(Math.abs(errorPct) > maxErrorPct && cycles < maxCycles);

    totalSamples += intSamples;

    const data = [];               
    const halfAmplitude = ((1 << sampleDataBits) - 1) / 2;               
                
    for (i = 0; i < intSamples; ++i) {               
      let value = Math.round(halfAmplitude + halfAmplitude * (Math.sin(i * cycles * 2 * Math.PI / intSamples)));
      if (value === terminator) {
        ++value;
      }
      data.push(value);
    }

    data.push(terminator);               
                
    return {
      targetFreq,
      actualFreq,
      samples: intSamples,
      cycles,
      error: errorPct,
      data
    };
  });

  // Add one sample per tone for a terminator value.
  // Multiple by 2 because each byte of data takes up a word of program memory
  const totalBytes = (totalSamples + tones.length) * 2;

  const csvReport = [
    ["Sample Rate", sampleRate].join("\t"),
    ["Max Error", `${maxErrorPct}%`].join("\t"),
    ["Target Hz", "Samples","Cycles", "Actual Hz", "Percent Error"].join("\t"),
    ...tones.map((tone) => [tone.targetFreq, tone.samples, tone.cycles, tone.actualFreq, `${tone.error}%`].join("\t")),
    ["Total Samples", totalSamples].join("\t"),
    ["Total Bytes", totalBytes].join("\t")
  ].join("\n");

  console.log(csvReport);

  return {
    totalSamples,
    totalBytes,
    tones
  };
}

And an example of using the code:

1642658082384.png



I can easily experiment with different sample rates and error tolerances to find a good balance between total size of program space needed to store the hard-coded data samples and accurate frequencies.

I will likely be bumping up the resolution on this quite a bit (on both axes) because I am switching to a PIC18F27Q43 that has 128k program space and an 8-bit DAC. I may as well get the raw output as smooth as reasonable to minimize the amount I need to rely on filtering circuitry to smooth it out.

I also experimented with the tone generator on my oscilloscope and found that I can produce sound on the phone handset with only a single sound signal by simply grounding the second connection that is supposed to be the inverted signal. I assume I'll be limited to lower max volume this way (because peak-peak voltage of the difference between the two signals will be half of what it should have been when one signal is always steady), but it will at least allow me to get started with producing sound and experimenting with sample rates, filtering, etc., to get an acceptable quality.
 
Have you considered using a PIC timer to generate the tones?.
Isn't that what I'm doing already? Or is there a different approach using a timer?

I have a timer setup to trigger its interrupt every 100 microseconds (10khz). In response to that interrupt, I first write the next value to the DAC (pre-calculated from last interrupt), then calculate the value to be output at the next interrupt by incrementing an index (or two for dual tones), index into my hard-coded waveform sample array(s) to get the sample value(s) to use, do some basic addition/division with those values to get it into its final 5-bit output range, and deal with looping back to the beginning of the arrays if the end is reached.
 
Isn't that what I'm doing already? Or is there a different approach using a timer?

I have a timer setup to trigger its interrupt every 100 microseconds (10khz). In response to that interrupt, I first write the next value to the DAC (pre-calculated from last interrupt), then calculate the value to be output at the next interrupt by incrementing an index (or two for dual tones), index into my hard-coded waveform sample array(s) to get the sample value(s) to use, do some basic addition/division with those values to get it into its final 5-bit output range, and deal with looping back to the beginning of the arrays if the end is reached.
No, you're using a DAC - you can use PWM with a PIC timer to give decent quality audio, or for your application probably even simple squarewaves (followed by a crude filter).

For an example of polyphonic sound done in that way, have a listen to the videos here:

 
you can use PWM with a PIC timer to give decent quality audio, or for your application probably even simple squarewaves (followed by a crude filter).

Thats an interesting way to make sound. I did not know about that.

Considering it now: Is that better than what I'm doing? It seems to me that what I'm doing is simpler and already getting me much closer to the desired output before applying any filtering at all. That piano project you linked to seemed to be using the PWM + filtering approach to work around a limitation of not having a DAC, but I am using a MCU with a built-in DAC already, so why not use it?

I only need to generate 8 distinct predetermined pure tones, so I don't need the flexibility of dynamically generating arbitrary tones or a large number of different tones. The hard-coded sample data for those 8 tones is pretty small, especially compared to the 128k program space I have now, so I don't think reducing memory footprint is a priority.

If you know of any benefits to this approach over what I'm doing that would be good for my purposes, please let me know. This audio signal processing/filtering stuff is black magic to me.
 
Thats an interesting way to make sound. I did not know about that.

Considering it now: Is that better than what I'm doing? It seems to me that what I'm doing is simpler and already getting me much closer to the desired output before applying any filtering at all. That piano project you linked to seemed to be using the PWM + filtering approach to work around a limitation of not having a DAC, but I am using a MCU with a built-in DAC already, so why not use it?

I only need to generate 8 distinct predetermined pure tones, so I don't need the flexibility of dynamically generating arbitrary tones or a large number of different tones. The hard-coded sample data for those 8 tones is pretty small, especially compared to the 128k program space I have now, so I don't think reducing memory footprint is a priority.

If you know of any benefits to this approach over what I'm doing that would be good for my purposes, please let me know. This audio signal processing/filtering stuff is black magic to me.

If you've got a DAC, and only need a single channel, then the DAC is fine - but depending upon the max frequency you're looking for a PWM solution can give ten bits resolution, and multiple PWM channels. You should also filter your DAC output as well.

Just bear in mind the options are there.

You can also just generate simple square waves, which may be enough for your purposes?, the original web page has long since vanished, but I've got the code from it, modified for XC8 and a 12F1840 (8 pin) - it plays RTTTL Nokia ringtones :D

My 12F1840 version isn't as accurate as the original, as it's internal oscillator can't be set to the original crystal frequency - I modified the code though, and it's 'near enough' for me.
 
Nigel Goodwin Thanks for the additional info.

The multiple PWM channels initially piqued my interest as a potential solution to generating the 2-wire differential audio: I could just generate 2 outputs at the same time, one inverted from the other.

But then I realized I really should split the single audio signal into differential as a last step. Otherwise, I'd have to ensure that any filtering/etc I do on the signal is exactly the same for both. And then I'd still have the problem of single-ended audio output from the Bluetooth module that needs to be converted to differential, so I need to figure out how to that regardless.
 
Nigel Goodwin Thanks for the additional info.

The multiple PWM channels initially piqued my interest as a potential solution to generating the 2-wire differential audio: I could just generate 2 outputs at the same time, one inverted from the other.

But then I realized I really should split the single audio signal into differential as a last step. Otherwise, I'd have to ensure that any filtering/etc I do on the signal is exactly the same for both. And then I'd still have the problem of single-ended audio output from the Bluetooth module that needs to be converted to differential, so I need to figure out how to that regardless.
Why do you think you need balanced (differential) audio?.
 
Why do you think you need balanced (differential) audio?.
Because that's what the phone handset is designed to work with: https://www.electro-tech-online.com...a-car-phone-from-the-90s.162764/#post-1415917

I have already determined that I can provide only a single audio signal and ground the second audio pin just to start testing things. It successfully produces sound, but of course that means the peak-peak voltage difference that the handset processes between the two signals is half of what it should be. This results in the sound volume being about 6dB lower than it should be.

If I want to produce sounds at full max volume, I'll eventually need to figure out how to generate an inverted "copy" of my audio signal. I really don't think I should just double the voltage of my signal to compensate for the absence of the inverted signal. It's tempting, but that might allow some smoke to escape or something :)

BTW - I successfully got some decently smooth filtered audio going from my MCU to the handset last night. Will post about that later.
 
Because that's what the phone handset is designed to work with: https://www.electro-tech-online.com...a-car-phone-from-the-90s.162764/#post-1415917

I have already determined that I can provide only a single audio signal and ground the second audio pin just to start testing things. It successfully produces sound, but of course that means the peak-peak voltage difference that the handset processes between the two signals is half of what it should be. This results in the sound volume being about 6dB lower than it should be.

If I want to produce sounds at full max volume, I'll eventually need to figure out how to generate an inverted "copy" of my audio signal. I really don't think I should just double the voltage of my signal to compensate for the absence of the inverted signal. It's tempting, but that might allow some smoke to escape or something :)

BTW - I successfully got some decently smooth filtered audio going from my MCU to the handset last night. Will post about that later.
You're confusing yourself, the point of differential (balanced) inputs is so you can have the microphone 100's of feet away, presumably you're not doing this?. Simply strap it as unbalanced and feed it a single signal - if you're bothered about (or can actually notice) the small drop in level then simply increase the level a bit to compensate, or turn the gain up. Presumably you're attenuating the signal from the micro?, so just reduce the attenuation a little to compensate.
 
Nigel Goodwin I'm not talking about microphone audio coming out of the handset (the microphone audio from the handset is a single signal). I'm talking about audio going to the handset to be played out the speaker. It's not really my design decision to make. That's already how the phone works.

I'm not really comfortable with doubling the voltage (halving the attenuation) of the signal I'm sending to the handset for audio to compensate for only having a single signal. Through some testing with a waveform generator, I found that if I increased a bit above 0.5V peak-to-peak (the normal max from the original phone at full volume), everything seems fine until I bring the signal back down to 0.5V peak-peak. During that transition from 0.6V to 0.5V, it makes a loud "pop" in the audio, so something about the audio/amplifier circuitry in the handset doesn't seem to like signals above 0.5V peak-peak. I also once saw some random output appear on the display, so I think the higher voltage audio (or maybe whatever the loud "pop" was when transitioning back down from higher voltage) may have somehow created some interference with the digital signals?

As for the reason it is differential/balanced audio? I'd guess it is because this is a car phone, where the wiring will be run through the car, from the trunk to the front of the cabin. Probably 15-20 feet length of wiring through a potentially electrically noisy environment. I don't know why the same reasoning didn't cause them to use a differential/balanced microphone. I'm just working with what I have.
 

New Articles From Microcontroller Tips

Back
Top