1
\$\begingroup\$

Background

I wanted to make a simple function generator with an ATmega328 and an R2R resistor network, similar to Jesper Hansen's Mini DDS (Direct Digital Synthesis).

To make the function generation firmware run fast enough, I believe I have to wire an entire PORT (all of its 8 output pins) on the ATmega328 to the R2R resistor network. This way I can write one full byte to the port with a single command, like so:

PORTD = B10101000;

On the ATmega328, I think PORT D is the only port I can use like that. ATmega328 pinout and port distribution is below.

ATmega328 pinout

The Problem

The problem I'm facing is that I also want to use the ATmega328 serial port for programming the board, but the serial port is also on PORT D (pins PD0 and PD1), thus creating a conflict.

Proposed Solution

After some research, I've decided that I could get away with the design below. The relevant part is circled in green.

My schematics combining UART and R2R network

With that circuit I think I'll be able to use the serial pins for programming the board and also, but not at the same time, drive the R2R network to produce a sine wave.

Considerations

The considerations I gathered so far, including contributions from comments, are the following:

  1. R17 is required to protect whatever is connected to the RX line (e.g. MAX232 IC) when ATmega pin 2 is changed to an output to drive the R2R network. That will prevent a large current from being sourced by the MAX232 IC when the pin is driven low.

  2. R17 value (1kΩ) will slow down RX line a bit (increase rise and fall times), but according to what I understood from this answer by Leon Heller - Resistors in series with Tx and Rx, it won't be enough to prevent serial communication (pending experiments to prove it).

  3. I won't be able to use both functions at the same time, but that's ok, as I plan to switch between functions in the firmware.

  4. RX and TX lines are linked to each other by a 50kΩ equivalent resistance, by R1, R2 and R3. That will create a 0.1mA current in and out of each pin, when they show different logic levels. I think that won't be a problem, but further experiments are required.

Questions

My questions are:

  1. Will my circuit work? If not, why not?
  2. Will this circuit burn or stress my ATmega or whatever I connect to the serial connector?
  3. Is there a better way to do it using an ATmega328 and the R2R network?

I know there are a lot of ADC chips out there that would help me solve this problem easily and would make my miniDDS more precise, but I wanted to start out with these requirements.

\$\endgroup\$
  • 1
    \$\begingroup\$ Moving up to a ATmegaXX4(A/P) will give you 4 8-bit buses, so you can use (almost) any at your leisure. \$\endgroup\$ – Ignacio Vazquez-Abrams May 6 '14 at 0:02
  • 1
    \$\begingroup\$ Were you planning to just plug in the MAX232 or similar just for programming? About the only problem I can spot is that RX line being high or low to would interfere with your output to some degree. \$\endgroup\$ – PeterJ May 6 '14 at 0:29
  • 1
    \$\begingroup\$ You are going to run into a problem with the configuration in your 2nd picture. Your RX and TX line are tied together through 50Kohm resistance. On top of that, your signals are going to have longer rise and fall times because of these resistors so the device you'll be talking to might not understand the atmega328 \$\endgroup\$ – Funkyguy May 6 '14 at 14:08
  • 1
    \$\begingroup\$ I couldn't really say, I want to say you'll be safe but I literally have no justification as to why. If you have to do it that way, then you'll have to do some experimentation. I don't know if this will damage your controller though. \$\endgroup\$ – Funkyguy May 6 '14 at 20:57
  • 1
    \$\begingroup\$ why cant you have just a nice big two-circuit switch, which changes the rout from TX/RX to serial header, or to the R2R Ladder? \$\endgroup\$ – KyranF May 7 '14 at 23:59
1
+50
\$\begingroup\$

I have answers for all your stated questions:

  • Your circuit will not provide a varying voltage on the output by itself, just a varying current source. The actual voltage generated will depend highly on the impedance of the device connected to the output. You may want to fix this with an additional resistor to ground, and/or an opamp.
  • Your circuit will likely allow serial communication, especially at slower rates like 19200 which I think are by default used by Arduino-style serial bootloaders. The 50 kOhm pull-up effect doesn't matter. The 1 kOhm resistance doesn't slow down too much.
  • Your circuit is unlikely to burn or stress the Atmega or the serially connected device.
  • I can think of three other ways, see below.

The first way would be to use a ICSP USB programmer to program the Atmega instead of serial programming, Arduino-style. This is more robust, faster, and avoids the problem entirely, and optimizes for BOM cost for the actual device (at the expense of requiring a few dollars of programmer hardware if you need to actually program it.) This can be implemented even on an Arduino board.

The second way is to run the Atmega328p on the internal RC oscillator, not using a crystal, and use port B instead of port D for the DDS output. This leaves the serial port entirely un-touched.

The third way is to write PORTB and PORTD one after the other, and use PORTB for the two bits that the serial port uses. This will generate a two-cycle glitch at about 4-8 Mhz. Given that you will need a low-pass filter anyway to generate any kind of smooth waveform, you simply need to lower the cut-off frequency of that filter to eliminate these glitches. To properly write the two ports in sequence, load the values into registers, disable interrupts, write the two ports, and re-enable interrupts.

Finally, you could use a small-signal diode (like 1N4148) instead of R17.

\$\endgroup\$
  • \$\begingroup\$ Thanks for the detailed answer. That's what I was looking for. One question though: I need the serial communication to work at 76800 and 115200. Will my circuit work at those speeds? \$\endgroup\$ – Ricardo May 8 '14 at 18:34
  • \$\begingroup\$ Also, can you tell me how to place the 1N4148 on the RX line? Does the anode goes into the ATmega RX pin? \$\endgroup\$ – Ricardo May 8 '14 at 18:41
  • 1
    \$\begingroup\$ The circuit will likely work at 115200 bps. Compare to I2C at 1400 kHz, where a 2 kOhm pull-up provides sufficient current. Separately, if the idea is to let the RX pin pull up the output network, but not let the output network affect the RX pin, then anode to RX, cathode to network, would be the right direction. Beware the voltage drop of the diode, though -- this may or may not be a problem for you. \$\endgroup\$ – Jon Watte May 9 '14 at 20:25
  • \$\begingroup\$ Thank you so much for taking the time to answer my question. That was exactly the kind of response I wanted! The bounty is yours. Congratulations!! \$\endgroup\$ – Ricardo May 10 '14 at 22:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.