Controlling a Pre-Amplifier with Buttons and IR Remote

Firstly, I am not a programmer by any stretch. What I've figured out and know so far has essentially been through Google and the lovely teacher that is trial and error. Now, while I am not a well versed programmer I do know my way around circuit design. To illustrate this point I solved what should be a software problem with a hardware solution.

What I am trying to do currently has a lot of parts, but the vast majority of the parts do effectively the same thing software wise. For example say there are three momentary pushbuttons. Each button does a different function. However, functionally within the software the only difference is what is controlled. The actual logical steps are the same.

So, what it is that I am trying to do? Well I am trying to make an audio pre-amplifier that has a remote control as well as physical controls. To that end I'm using a Nano Every because I have a few on hand. I can elaborate on the specifics of the circuit, but that is not too terribly important I think for what it is I am trying to accomplish. However, the switches are debounced physically and the Arduino itself is not heavily loaded on its outputs. Think driving some 7400 series logic or an IC directly kind of thing.

What I have are 5 switches, 1 rotary encoder, and 1 IR Remote plus receiver. The rotary encoder though was mostly solved through hardware rather than software. The output of the rotary encoder from the perspective of the Arduino is just an 8-bit binary number.

Functionally, what I want the Arduino to do is the following:

  1. One switch to cycle between inputs
  2. One switch to toggle a mute and when toggled off remember which was the last input
  3. One switch to toggle an input pad (can't overload the analog stuff, it sounds bad)
  4. One switch to toggle a volume limit (basically caps the maximum value sent to the DAC)
  5. One switch to toggle a Fine Adjustment for the DAC (think like 1dB adjustment regular and 0.5dB with fine adjustment on, I'm not against velocity but I have ZERO idea how to even attempt that)
  6. A rotary encoder to control the volume up & down
  7. A remote that duplicates all those functions (there are enough buttons available and I know the commands for each individual button as confirmed on the Arduino itself)

Quick note some of these functions are just a quirk of where it is meant to be used.

I would think the best way to accomplish what I am trying to do would be a state machine of sorts. However... I have one small issue with that... a DAC. The volume control on the preamp is through some VCAs and a rotary encoder is cheaper and easier to find than a motorised potentiometer. From my understanding of state machines (I could be completely wrong here too) I would have to include a state for each possible configuration of the DAC, which is 16-bits... I think that is a bit excessive.

This is not something I cannot foresee an Arduino being able to do nor are there are any really esoteric functions to be implemented. But I know I am going to have problems when even getting a toggle to work is causing me frustration (I can be dense). Some direction and the like would be greatly appreciated!

I'm not much of a hardware person. I assume that the DAC generates the voltage for the VCA.

For the rotary encoder, you keep a variable that keeps track of the pulses; in its simplest form you send that count to the DAC. You probably only want to do that if the count changes so you need a second variable to keep track of the previous count.

The sending could look something like this

// position of rotary encoder
volatile uint16_t volume;

void setup()
{
  ...
  ...
}

void loop()
{
  setVolume(volume);
}


/*
  set the volume
  In:
    level to set
*/
void setVolume(uint16_t level)
{
  static uint16_t prevLevel;
  if (level != prevLevel)
  {
    sendToDAC(level);
    prevLevel = level;
  }
}

void sendToDAC(uint32_t level)
{
  ...
  ...
}

This does not handle the reading of the rotary encoder which will change the volume.

So you should know

So that would help to show for example what the role of the dac is.

If its controlling the amplitude you could eg use a table or alogorithm to map between the desired volume and the gain needed.

If its generating the signal maybe let it do its job and handle the gain another way.

Apologies, lots of things in the forums and such and I didn't see that one :frowning:

The schematic is still a work in progress because I'm trying to wrap my head around the code on the Arduino and some of the pin assingments are off, but that is an easy fix on the schematic itself.

  1. Analog Section
  2. Arduino and Power on Reset
  3. LED Bargraph and Rotary Encoder
  4. Power Supply

Again the schematic is incomplete in all the finishing details, but overall the ideas are laid out. Any errors will be caught as I finish it up as well. I still need to remove some extra parts that aren't necessary, complete other parts, move some things around on the Arduino, power supply isn't fully done yet, etc... As I said in my first post I generally learn through failure.

If anyone wants a more full breakdown of how the analog stuff works I've got no problems giving a run down, and if I didn't want a remote control I would do this all with discrete logic. The basic gist is the following though:

  1. Input selection via relays controlled by a 74595 shift register
  2. Additionally, all status LEDs are controlled by the 74595. I do not necessarily need the buffer transistors, but I'll likely keep them.
  3. Paralleled 2181s for volume control
  4. The actual CV value is visually reprsented in ~10% steps to an LED bargraph
  5. Transimpedance amplifier to the output with a muting relay
  6. Rotary encoder is an incremental type and a count is created to determine if it moved up or down and by what amount. This is then shifted into the Arduino whenever it wants to poll. Basically, three states: No change, Up, Down

The VCA's CV is driven differentially to improve performance and gain is added via the transimpedance stage as this generates less distortion and noise overall. I've done this with a voltage reference driving a potentiometer directly and it works without an issue.

The rotary encoder works because I am using an incremental encoder instead of an absolute. Basically, it will create create two signals. A count and a direction. By presetting the counters to 127, which I just noticed I forgot to add a control port for the AND gates... . It is "PRESET". Also, "D" is floating and I need to tie that to ground. At any rate it will increase or decrease in count and then shifting in the value and performing simple addition or subtraction allows the adjustment of the CV.

I know that the DAC expects 2 "mode" bits as it were that tell it what power state to be in, followed by the 16 data bits, and 6 don't care bits via SPI. This makes it essentially 24-bits that need to be sent to it. If the first two bits are 0 then it is in it's regular power state. From what I can gather from the datasheet it should be Mode 0 for SPI as well.

Hi @capacitor_plague ,

I believe you're right about having too much in your hands with so many different functions for the switches, most of them needing their own state machine, so my best recommendation for starters if to use as much work already done in libraries.

If you'll be working with an ESP-32 based Arduino most of your control needs might be solved using the ButtonToSwitch_ESP32 library. The switch to cycle, the toggles... even the volume up and down might be solved with the library without the use of a pot. But you might add a nice display to know the volume level from afar.

Unfortunately the AVR Arduinos' library version is a little behind schedule (I know because I'm the developer, and I've been a little lazy about it).

Take a look at the library and the information, if you need some help with it to figure if it fits your needs and how just contact me.

Good Luck!
Gaby.//

In several places, yes. You could dump all the logic IC's and the 555 and replace them with one or two MCP23017 GPIO expanders or simply a controller with more GPIOs (Arduino Mega etc.) It would reduce the hardware complexity of your circuit dramatically, allowing you to focus on the relevant bit - i.e. the analog section.

I'm not sure what kind of advice you're looking for here. It's clear you're well-versed in 1980s-style logic and analog circuit design, and as such, this is a nice exercise. So if the aim is to build something in which you leverage that competence and have fun with it, then I'd definitely continue as planned.

If you're looking to leverage the possibilities of a microcontroller design, I'd suggest to keep the analog part and dump all the rest, and basically start over. Interfacing with buttons and rotary encoders can be done directly from GPIOs without any logic IC's (the microcontroller is perfectly capable of counting up and down) and only very minimal (or even none at all!) hardware denouncing is necessary. Use the microcontroller for what it is: a controller. So use it to collect any inputs and generate any outputs necessary. Try not to bypass it with parallel hardware control circuits as it'll just make your life miserable and the device inflexible and wayward to use (btw, I don't see clear signs of your doing this; it's just a heads up).

So bit-bang those data into the DAC. What's the problem exactly? You know what kind of control data it expects, so assemble that and then stream it out into the DAC. You either use an inbuilt SPI library, or (more likely in this case) just 'manually' toggle the CLK and DAT pins in your code. It's a matter of writing (or borrowing from an existing library) a single routine that sends a bit or a byte out over SPI and then iteratively call that.

Alternatively, drop the DAC you're using now and either use a controller with inbuilt DAC you can use (e.g. STM32 series controllers; blue/black pill boards) or an external DAC for which you can find an Arduino library to make life easier programming-wise. Further alternatives are 'faking' a DAC using PWM and a simple R/C filter, which in practice works very well indeed and would most likely be perfectly adequate in this case, too. Or a digitaly-controlled pot meter in combination with a reference voltage could likewise be used here. Although SPI-controlling any given DAC is not necessarily problematic - it's just an additional hurdle to write the controls for it if you're just starting out with uC technology.

Overall, your project is fairly straightforward especially if you just drop some of the concepts that existed in the past because that's what we had available to us back then. Of course, as a starter project in the world of microcontrollers, it's challenging - not because you're trying to do something that's on the limits of what's possible (it very definitely isn't; all this is not particularly demanding technology-wise), but mostly because you still have to learn much of the basics of uC technology. So my suggestion would be to perhaps start with just the Arduino and go through the (tedious, yes) motions of blinking an LED, then controlling some kind of SPI device or a bit-banged device (a simple digital pot meter for instance), read out a rotary encoder in a reliable and convenient way, learn to handle and manipulate various data types etc. As you go along, you'll notice (hopefully) how much redundancy there is in your hardware and that you can simplify the system considerably.

The TL;DR thus boils down to the old adage of...
...kill your darlings

I'm dipping my toes into the water of it. I have other projects that I'm working on and thinking on that far more complicated than this. And baby steps for learning things is always a good approach. However, what I figured out when thinking on them was that in terms of the software I was getting way too ahead of myself and need a nice succinct starting point. The reason I am even halfway decent with discrete logic is because I have very stubbornly avoided using any sort of microcontroller. A great many of things I've built would've been better served with a tiny 8-bit microcontroller...

The reason for the whole thing around the rotary encoder was because I couldn't wrap my head around the programming to get it to do what I wanted. It's not because I think the microcontroller is too slow or incapable or the like by any stretch. Sometimes when someone who is starting out asks me about a certain part like a transistor I often forget that the built up practical experience and knowledge I have now is not how I learned about using the parts. I learned by accidentally setting them on fire and by studying schematics on how other people used them.

It's like I know what I want the controller to do, but because I have never really messed with programming before I have very little idea where to begin. I'm fine with reading, typing code, and experimenting. Good sources of information for programming I do not know. I've looked at example code and can trace and understand some of it, but not all of it.

Very quick aside the 555's job is to allow the analog power supply to come up before the microcontroller starts up and asserting control. I've had bad luck in the past mixing digital and analog stuff without some form of global power on reset :slight_smile:

I could use a micro with an inbuilt DAC, but I already have to hand a Nano Every and like a dozen of the DAC8411s to hand. While I don't have them on adapter boards I have made a functioning stream of data on the SPI port of the Nano Every. Correct? Probably not, but I was looking for activity as that can sorted out in code. I didn't post this without trying stuff beforehand. Getting the IR receiver working did take some trial and error, but I got it working. I can turn on an LED with the press of a button. But I can't get it to toggle. This is either because I am dumb or I'm missing something because I just don't know.

What I'm looking for is some direction on where to look for information. I don't know the equivalent of the Art of Electronics for programming :frowning:

Edit - Help me help myself as it were.

I thought so, yes. No shame in that, but knowing that you'll end up having an "ooooohhhh, is that all" sensation by the time you figure it out, I'd recommend looking into it anyway.

The whole 'trick' is to let the microcontroller look at the pin transitions and figure out at what point a full transition clockwise or counter-clockwise is made. You'll find some libraries that 'software debounce' this by ignoring invalid transition patterns, which turns out to be very reliable, even without any debounce hardware (although it doesn't hurt to add some of the hardware as well).

Then when you know the CW/CCW 'clicks', you can simply increment/decrement a counter in whatever way you want. The advantage to this is that it's infinitely flexible. For instance, you can program it so that a quick twist of the volume pot increments the volume by more than the actual number of 'clicks', making the controls more intuitive and making it easier/more comfortable to traverse large distances (e.g. if your volume control has very high resolution).

For inspiration, consider this library: arduino/libraries/Rotary at master · buxtronix/arduino · GitHub I've always been enamored by it because it's (1) elegantly simple, (2) well-documented and (3) quite robust. I've used this or conceptually similar approaches in virtually all of my projects.

I think that's a good way, though. It has worked for me, combined with some reading in datasheets for the hardware parts, using the C++ language reference, perusing manufacturer's code snippets in reference manuals and going through threads on forums. Put together it's possible to go pretty far even without reading books, attending courses etc.

OK, gotcha. Well, I didn't touch the matter of the power supply because it's...well, I'd have done it differently in 2024, but I'm aware that this is hi-fi audio and certain concepts tend to linger pretty long in that domain. Anyway, you could of course have the controller supervise the analog power supply as well, signaling when it's online and only then start doing stuff on the audio part. The 555 works, of course, but if you've got the controller anyway...easy enough to feed the analog supply voltage into an ADC input.

The latter, obviously. Plenty of "led toggle" examples out there that illustrate many ways to do it. Suppose you have a boolean variable 'led_state' that maintains the state of the LED, it's as simple as this:

led_state = !led_state;
digitalWrite(LED_PIN, led_state);

That's all.

Me neither, but I got by reading other people's code. In particular I'd have a good look at the many examples in the Arduino environment as well as the examples associated with the thousands of libraries out there. See how they do things.

Now, I do admit that many moons ago in my early teens, I did read a few chapters of a book on assembler programming. I think some of the key concepts stuck with me. Much later in university we had to go through some courses involving Java (which was pretty hot & new back then) that taught me the basics of object oriented programming (OOP). Having said that, you can work with Arduino fairly well without understanding much (or anything) about OOP, so that's not really a requirement. The basics of programming can be learned in whatever language or environment; you'll find it doesn't matter that much whether you learn by writing C, Java (related anyway), BASIC, Python, Rust, etc. The key principles are pretty much always the same in the sense that you have operators working on variables within code structures. Syntax is specific to the language, but the core concepts are comparable if not the same. Hence, if you want to get a book, get really any book on programming (I'd pick C++ because that's what Arduino is based on) that gets decent reviews. Really any old book will do.

If you're looking for something online, try this: C++ Tutorial
It's aimed not at embedded systems so there are some differences, but again, code structures and core principles are very much the same.
The key principles of OOP are covered here: Beginner’s Guide to Object-Oriented Programming | by Adekola Olawale | Medium But you may find this a little challenging at this point; maybe save it for a little later.

I'm sure there are books specifically on C++ for embedded systems, but just to get something going in Arduino (or STM32Cube, MoonRiver Studio etc.) I've never found them very necessary. Seriously, re-create a LED blink sketch by starting with a blank page is a perfectly fine route towards getting this going.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.