Yep, just with a coupling cap so the input pin has no external DC applied.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?
Step one: try to identify what's going on with the wires between the handset and transceiver.
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.
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..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?
do those with three or more UARTs come in dual-in-line packages?
Nice!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)
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
};
}
Isn't that what I'm doing already? Or is there a different approach using a timer?Have you considered using a PIC timer to generate the tones?.
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).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.
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.
Why do you think you need balanced (differential) audio?.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.
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-1415917Why do you think you need balanced (differential) audio?.
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.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.
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?