Before we begin: PSoC 4 is my first foray from 8-bit AVRs and PICs into ARM territory; at this point, I'm just getting the hang of these MCUs and their visual programming, so feel free to suggest new information sources, better ways of doing things etc.
In this project, I'll present a little hack that allows us to generate tones using the IDAC component in PSoC 4 MCUs. Here's how it looks and sounds like. Well, actually it sounds a bit better in real life:
1. From IDAC to DAC
When I noticed that the PSoC had DAC (Digital-to-Analog Converter), I wanted to generate an approximated sine wave with it to drive a speaker. Then I read a little and discovered that it wasn't a regular DAC but an IDAC - it gives analog *current* instead of analog *voltage*. Hmmm. But that can be easily fixed using Ohm's law!
We know that Voltage (V) = Current (I) times Resistance (R). So if we pass different currents from the IDAC's output through the same resistor, they will create different voltages. According to the datasheet, the MCU I used can produce 0 to 612uA through its 8-bit IDAC. Yes, that's *micro*Amperes. Going through a 680R resistor, for example, we do the math and get 0 to 0.378V.
Now, in theory we can put a 10KOhm resistor and go up to 6.12V. So far I couldn't find specific information, but intuition tells me that the MCU will not even go near its own supply voltage without a fight, and it will not end well. Better play safe.
2. Sine-ification and Amplification
To generate an IDAC "Sine wave" I pre-calculated sine values, scaled them to the range of 0-255 (using MS Excel) and stored them as a const array of bytes in the program code. Then, in the main() function, I simply pushed these values one after the other into the IDAC component, with very short delays in between, over and over again. The assigned output pin was connected to GND through the 680R resistor, and measuring the voltage across the resistor I got this nice picture on the scope:
Cool, but it can't drive a speaker; the voltage is low and there's no current we can actually use. So let's add an OpAmp. I used an NE5532 because that's what I had nearby; the chip has two OpAmps inside but I only need one. I connected its IN- pin to GND through a 10K resistor, IN+ to the voltage at the IDAC output pin (with the previous setup still in place), and the OpAmp's output through a 47K resistor back to IN-. Again, nothing magical about these resistor values, just taking what's at hand to get a reasonable amplification. For more info on doing this, check out the Wikipedia entry for non-inverting amplifiers: https://en.wikipedia.org/wiki/Operational_amplifier#Non-inverting_amplifier
The waveform at the OpAmp's output has the same shape and timing as before, but it goes from 0 to ~2.1V, and the OpAmp is capable of giving enough current at these voltages to drive the speaker. The result is a clear tone, much more pleasant than the shrill of square-wave output (where a digital output pin is driven HIGH and LOW alternately). To get higher or lower frequencies, decrease or increase the delay in the main loop.
Pleasing as it is, I didn't want the tone to play indefinitely. So I added a simple momentary switch, from GND to a digital input pin with internal pull-up. I added a timer component and set it to trip every 20ms; the interrupt function (ISR) just raises a "flag" . When this flag is detected in the main loop, the switch input is read and if it has changed, the IDAC component is turned on or off accordingly.
3. Meet the Creator
Here's the "top design" of the system in the PSoC Creator 3.3 IDE. The Timer is fed from the default clock, and the button (switch) pin is "floating" here because it's not used by any other component, simply read in software.
And here's the configuration of the IDAC and the Timer:
The code is rather simple and crude; I attached the main.c file to this project if you want to take a look at it.
Two important notes about using the IDAC: first, the output pin for the IDAC should be defined as a not-quite-intuitive Analog / High Impedance (!) Analog . This wasn't mentioned, as far as I could see, in the IDAC component datasheet - I learned this from looking at an example project.
Second, the IDAC is relatively slow. It takes ~10us to settle on new values (so says the datasheet). Multiply that by the number of samples in your sine wave and see that you can't really get high frequency sounds using this method. Not that it matters - IDAC sound is nothing more than an exercise and a hack.
4. A note about the hardware
As you can see, although this project is tagged "CY8Ckit 049", I used my own little setup based an a different chip from the same family - the CY8C4245PVI-482. This really doesn't matter - you can do the exact same project with the 049 kit, except of course you'll have to add the Bootloader component to the design before burning it to the chip.
Thank you for your time, I hope this has been useful (or at least interesting), and perhaps I'll have more advanced and practical projects to show in the future. Bye!
Comments