Tuesday, April 2, 2019

63 dB step attenuator UPDATE 5/9/19

While I was working on the power meter function for the latest version of the SNA, I used several fixed attenuators for checking linearity and calibration.  It would be a lot easier if I had a variable step attenuator.  I have several  digital controlled attenuator modules that I bought one eBay a while ago, and I guess it is time to use some of  them. There are several models available.

   The ones I plan on using are the simplest with only 6 control pins for a total attenuation of 31.5 dB in .5 dB steps.  I am going to connect two in series with the control lines paralleled for a total of 63 dB in 1 dB steps. 

 I will use an Arduino Nano  with a small OLED display for control of the attenuator.  A rotary encoder will be used to select the attenuation level, and the push button switch will be used to select ether 1 or 10 dB steps.  Everything should fit in a small 3D printed cabinet along with a 9 volt battery for power.  The attenuator module runs on 3.3 volts, but the current draw is low enough that I can power it directly from the 3.3 volt output of the Nano.  The module also needs 3.3 volt logic level, so I will use a simple voltage divider on the control lines to drop the 5 volt level of the Nano down to 3.3 volts.  I found that some modules had 10K pull down resistors to ground and others did not.  I hand wired the first one, but laid out and ordered some board so I could build several more.  I laid out the board with provision for optional pull down resistors if needed.  The modules come with female SMA connectors.  I replaced one of them with a male connector so I could connect them directly together without having to use a short cable.  This also made it easier to do the board and case design.

After building the board I worked on the software.  It is very simple, with just checking the rotary encoder and incrementing or decrementing the attenuation value by the step size which can be changed by pressing the encoder button.  If there is an encoder event, the attenuator control lines are set to the correct value.  

void setAtten() {
  int atten = AttenValue;
  if (atten >= 32) {
    digitalWrite(DB_32, HIGH);
    atten = atten - 32;
  else  digitalWrite(DB_32, LOW);
  if (atten >= 16) {
    digitalWrite(DB_16, HIGH);
    atten = atten - 16;
  else  digitalWrite(DB_16, LOW);
  if (atten >= 8) {
    digitalWrite(DB_8, HIGH);
    atten = atten - 8;
  else  digitalWrite(DB_8, LOW);
  if (atten >= 4) {
    digitalWrite(DB_4, HIGH);
    atten = atten - 4;
  else  digitalWrite(DB_4, LOW);
  if (atten >= 2) {
    digitalWrite(DB_2, HIGH);
    atten = atten - 2;
  else  digitalWrite(DB_2, LOW);
  if (atten >= 1) digitalWrite(DB_1, HIGH);
  else  digitalWrite(DB_1, LOW);

To check the proper logic I used to set these lines, I used a little less than $10  eight channel USB logic analyzer I picked up on eBay.  The first logic analyzer I used was abound 1980, and was a 16 channels unit and cost several thousand dollars.  At that time the software in the unit was very basic, with only simple trigger options.  The little USB unit uses a open source program called Sigrok PulseView.  It is also a fairly basic program, with similar trigger options to the one I used before.  But, it also has several advanced functions such as being able to decode I2C, serial, and other data streams to the binary,hex, or ASCII values sent or received. 
 I connected the logic analyzer to the 6 control lines going to the attenuator modules and another line to one of the rotary encoder pins.  As I turned the rotary encoder I captured the logic levels on all the connected pins.  The results are shown in this diagram.  With the delay I have between value changes, I was not able to get smooth continuations  change in values.  But each turn of the rotary encoder produced the proper logic level changes to the attenuator modules.

Now all I have to do is finish the 3D printed case and put everything together.

UPDATE 5/9/19
I received the additional pair of attenuators I ordered, finally finished the project.  I added some header pins to the power connectors on the two attenuator modules.  This way I can just  plug into  header sockets mounted to the back of the controller board.
I have been using 9 volt batteries for powering most of the smaller projects, and usually use a rechargeable battery.  This has meant that I have to remove the back cover from the unit to change the battery.  I recently found some 9V batteries that have a built in charge controller, and can be recharged through a Micro USB connector mounted on the bottom of the battery.  This has made it possible to just include an access hole on the case to allow connecting of the USB cable for recharging.  they cost a little more than the  rechargeable batteries I have been using, but the convenience makes up for the slight difference.
This version of the the battery has built in red and green LED indicators in the bottom of the battery, so I made the access hole large enough so I can see the status when recharging.

When I was happy with the final design of the printed case, I added some laser print decals.  I also painted the inside of the case and bottom cover with several coats of an acrylic paint that contains some actual powered copper.  Have not checked, but hope this will provide a little additional shielding to help reduce any radiated signal.  After I was finished, I measured the signal attenuation at various values and found it to be quite accurate.  Also measured insertion loss with it set to 0 dB, and found about a 3 dB loss at all frequencies I am interested in. 

Link to dropbox files


  1. Really nice job DuWayne. Thank you for sharing.

  2. Thanks for sharing, I have built the SNA jr V2, Sweeperino jr, and the Power meter. Good times!!

  3. Nice job DuWayne. I wonder is that 3dB linear across the range of the attenuation?

  4. Instead of parallelling ALL the control lines, separate out the two 0.5dB control lines.... Now you've got the "in 0.5dB steps" back for just one extra control line.

  5. Would be easy to do, but not something I needed.

  6. I am trying to compile with Arduino 1.8.7 but getting the error
    " 'read_btn' was not declared in this scope".
    I am not familiar with the C language.
    Can anyone help me to fix this error

    1. The file encoder.ino must also be in in the same folder as the main StepAtten.ino

    2. Hi DuWayne,
      Thanks a lot, this was a great help.
      I made a second error.
      The file “Rotary.cpp” was also in the same directory, this is also wrong.
      Now it compiles flawless.
      73 on7ch

  7. hi nice project , i have a HMC470 https://ae01.alicdn.com/kf/HTB1HoB4b.CF3KVjSZJnq6znHFXaj/HMC470-Digital-RF-Attenuator-Module-DC-3GHz-1dB-Step-to-31dBManual-control-and-program-control-FOR.jpg_220x220xz.jpg_.webp
    but it is a 5bit controled attenuator, any idea on how i could use your code and wire in to the arduino , i am a electronic engeneer but a bad coder and french on top of all that thanks

  8. Looks like you just need to connect the ground and v1-v5 pins to the Arduino. Make sure you define them with the associated pins on the Arduino

  9. hello, and thank you for your fast reply , same wiring and no code change ? kind regards