rollyng
Posts: 21
Joined: Sat Dec 10, 2016 4:08 pm
Location: Hong Kong SAR

How to get stable 2KHz square wave with MCP4725 on RPi3?

Fri Aug 04, 2017 7:43 pm

Hi,
I am trying to generate 2KHz square wave via a MCP4725 on RPi3. I need to vary the voltage somewhere between 0 to 5Vpp, so I cannot use the digital GPIO pins and I get this MCP4725 from Adafruit.
I connect the MCP4275 and I can see it on the I2C bus.
I copy the Adafuit example and modify it as little bit, however when I run the following Python code it does not produce the 2 KHz square wave.

Code: Select all

import time

# Import the MCP4725 module.
import Adafruit_MCP4725

# Create a DAC instance.
dac = Adafruit_MCP4725.MCP4725()

# Loop forever alternating through different voltage outputs.
print('Press Ctrl-C to quit...')
while True:
    dac.set_voltage(0)
    time.sleep(0.00025)
    dac.set_voltage(4095)
    time.sleep(0.00025)
The square wave produced is only about 800 Hz. If I reduce the sleep to 0.00001, it gives about 2 KHz but it is not stable but oscillates from 1 KHz to 2 KHz. This is unacceptable for my application.

I have took a movie on this and I wonder if it is a software issue? I am aware of the following possibilities:
1) I2C speed default to RPi3 is too low, I should change to 3400000 (max 3.4 Mbps according to MCP4725)
2) bad cable but my cable is short and only about 10 cm
3) Adafruit python lib is slow, so I should change to pigpio python lib instead. But I have no idea on how to use those on MCP4725, http://abyz.co.uk/rpi/pigpio/python.html#i2c_open

Thank you!
Rolly

rollyng
Posts: 21
Joined: Sat Dec 10, 2016 4:08 pm
Location: Hong Kong SAR

Re: How to get stable 2KHz square wave with MCP4725 on RPi3?

Sat Aug 05, 2017 4:44 am

Hi all,
I have made some changes to /boot/config.txt and reboot

Code: Select all

dtparam=i2c_arm_baudrate=1700000
With

Code: Select all

time.sleep(0.00025)
I have 0.9 to 1.2 kHz.

With

Code: Select all

time.sleep(0.000125)
I have 0.9 to 1.8 kHz.

With

Code: Select all

time.sleep(0.000125)
I have 1.5 to 2.1 kHz.

My situation improves a bit if I have no other windows opened in X, the 2 kHz square wave still oscillates from 1.5 to 2.1 kHz but less often.

Finally, if I changed to

Code: Select all

time.sleep(0.00001)
I have quite stable 3 kHz! It only oscillates if I open a X window ... so I suppose this is a software issue? Should I change to C?

Btw, my RPi3 is running raspberrypi 4.9.35-v7+

Any suggestions?

Thanks,
Rolly
Last edited by rollyng on Sat Aug 05, 2017 4:36 pm, edited 2 times in total.

piras77
Posts: 148
Joined: Mon Jun 13, 2016 11:39 am

Re: How to get stable 2KHz square wave with MCP4725 on RPi3?

Sat Aug 05, 2017 8:07 am

Raspbian is no real-time operating system. That is, there is no guarantee when a command gets executed. A process may be suspended any time for short (a few us) or long periods (more than 100ms). Hence, in order to produce a stable signal, you cannot rely on any Raspbian userland process (whether written in Python or C or whatever language you choose).

Anyway, instead of using sleep (as in you program), you may want to wait until a moment in time is reached. That is: wait until t0 is reached and then execute your code, wait until t0+0.5ms is reached and then execute your code, wait until t0+1ms is reached... and so on. This may give you better results (at least if you use C), and especially on a multi-core Pi (if you attach the process to a dedicated CPU). But it won't solve the problem in general.

The only way I'm aware of to achieve real-time behavior from Raspbian userland is to employ DMA.

So, you may wanna think again about using the GPIO square wave generator, and connect it somehow to your DAC.

User avatar
Ferdinand
Posts: 236
Joined: Sun Dec 01, 2013 2:24 pm
Location: Leiderdorp, NL

Re: How to get stable 2KHz square wave with MCP4725 on RPi3?

Sat Aug 05, 2017 8:41 am

Hi rollyng,


3 choices:

1) use in this case a micro controller like an arduino because it has no operating system. Timing is much better defined.

Or

2) Use c instead if python, because timing is well defined in c.

Or

3) connect a arduino, running 2 kHz, to a gpio pin. Write a small interrupt program to update your dac.
Timing is less critical because the os is forced to react on each interrupt on the gpio pin.
Success with your project!
Ferdinand

User avatar
rpdom
Posts: 15868
Joined: Sun May 06, 2012 5:17 am
Location: Chelmsford, Essex, UK

Re: How to get stable 2KHz square wave with MCP4725 on RPi3?

Sat Aug 05, 2017 9:36 am

Getting the timing right on the Pi isn't a problem if you use one of the hardware PWM outputs (you'll probably have to disable analogue audio for that to work as that uses both PWM channels). The issue is to control the output voltage. Some sort of i2c based amplifier might work. Feed the 2KHz clock in from the Pi PWM channel (or external source), then adjust the gain accordingly.

rollyng
Posts: 21
Joined: Sat Dec 10, 2016 4:08 pm
Location: Hong Kong SAR

Re: How to get stable 2KHz square wave with MCP4725 on RPi3?

Sat Aug 05, 2017 4:19 pm

Hi piras77,

Thank you for the suggestions, I was using pigpio python library to produce square wave and I know the hardware clock is very stable to MHz. But since I need to alternate the square wave Vpp, I was force to use the DAC. But I have not tried anything on DMA yet and I will look into this.

Greeting,
Rolly
piras77 wrote:
Sat Aug 05, 2017 8:07 am
Raspbian is no real-time operating system. That is, there is no guarantee when a command gets executed. A process may be suspended any time for short (a few us) or long periods (more than 100ms). Hence, in order to produce a stable signal, you cannot rely on any Raspbian userland process (whether written in Python or C or whatever language you choose).

Anyway, instead of using sleep (as in you program), you may want to wait until a moment in time is reached. That is: wait until t0 is reached and then execute your code, wait until t0+0.5ms is reached and then execute your code, wait until t0+1ms is reached... and so on. This may give you better results (at least if you use C), and especially on a multi-core Pi (if you attach the process to a dedicated CPU). But it won't solve the problem in general.

The only way I'm aware of to achieve real-time behavior from Raspbian userland is to employ DMA.

So, you may wanna think again about using the GPIO square wave generator, and connect it somehow to your DAC.

rollyng
Posts: 21
Joined: Sat Dec 10, 2016 4:08 pm
Location: Hong Kong SAR

Re: How to get stable 2KHz square wave with MCP4725 on RPi3?

Sat Aug 05, 2017 4:21 pm

Hi Ferdinand,

Thanks and I will try to write a small C script to do my task, but adding extra hardware is not preferred because I like to keep my setup simple.

Greeting,
Rolly
Ferdinand wrote:
Sat Aug 05, 2017 8:41 am
Hi rollyng,


3 choices:

1) use in this case a micro controller like an arduino because it has no operating system. Timing is much better defined.

Or

2) Use c instead if python, because timing is well defined in c.

Or

3) connect a arduino, running 2 kHz, to a gpio pin. Write a small interrupt program to update your dac.
Timing is less critical because the os is forced to react on each interrupt on the gpio pin.

rollyng
Posts: 21
Joined: Sat Dec 10, 2016 4:08 pm
Location: Hong Kong SAR

Re: How to get stable 2KHz square wave with MCP4725 on RPi3?

Sat Aug 05, 2017 4:35 pm

Hi rpdom,
Thank you and I was using the pigpio python library from Joan and I agree that hardware PWM provides the most stable square wave to MHz. However, I need a i2c amplifier and I have little experience on these devices, can this MCP4725 work a the amplifier? Any special wiring needed?
https://cdn-shop.adafruit.com/datasheets/mcp4725.pdf

Greeting,
Rolly
rpdom wrote:
Sat Aug 05, 2017 9:36 am
Getting the timing right on the Pi isn't a problem if you use one of the hardware PWM outputs (you'll probably have to disable analogue audio for that to work as that uses both PWM channels). The issue is to control the output voltage. Some sort of i2c based amplifier might work. Feed the 2KHz clock in from the Pi PWM channel (or external source), then adjust the gain accordingly.

rollyng
Posts: 21
Joined: Sat Dec 10, 2016 4:08 pm
Location: Hong Kong SAR

Re: How to get stable 2KHz square wave with MCP4725 on RPi3?

Sat Aug 05, 2017 4:47 pm

Hi all,

Some update to my experience on this MCP4725 on RPi3 with Python.
1) The maximum I2C speed I can set by modifying the /boot/config.txt is 1700000 (1.7 mbps), if I double the I2C speed to 3.4 mbps, the Python code fails to write and crashed.
2) With I2C at 1.7 mbps, I found that the following Python produces fairly stable square wave at 3 kHz

Code: Select all

import time
import Adafruit_MCP4725
dac = Adafruit_MCP4725.MCP4725()
while True:
    dac.set_voltage(0)
    time.sleep(0.00001)
    dac.set_voltage(4095)
    time.sleep(0.00001)
3) After trials and errors, I found a simple solution at produce 1.92 to 2.08 kHz, which is calling the voltage update twice in the loop before sleep.

Code: Select all

import time
import Adafruit_MCP4725
dac = Adafruit_MCP4725.MCP4725()
while True:
    dac.set_voltage(0)
    dac.set_voltage(0)
    time.sleep(0.00001)
    dac.set_voltage(4095)
    dac.set_voltage(4095)
    time.sleep(0.00001)
Your comments are welcome.

Greeting,
Rolly

piras77
Posts: 148
Joined: Mon Jun 13, 2016 11:39 am

Re: How to get stable 2KHz square wave with MCP4725 on RPi3?

Sun Aug 06, 2017 6:28 am

Hi rollyng,

I can only repeat what I already wrote above.

(1) Your approach with time.sleep() is very inaccurate because the sleep call will vary in time. Same for code execution; especially on a Pi-3 with varying core-clock.

(2) Instead, get the moment in time and wait for the next moment in time. I guess in Python you use time.time(). For a 2 kHz signal you would then use intervals of 0.25ms for each level.

(3) This won't prevent process suspension. Run your program and watch the signal over a long period of time. Maybe you get lucky and it works, maybe not. Sticking your process to a dedicated CPU (see taskset) may improve your odds.

(4) Using DMA will solve the problem. However, I guess that's beyond your skill set.

(5) Use the GPIO square wave generator and use it to switch the output of your DAC. Maybe a simple transistor switch would already be sufficient. Or use an analog switch as in the 74/4066 circuit.

Best of luck!

edit: changed ADC to DAC

Return to “Interfacing (DSI, CSI, I2C, etc.)”