Jump to content
  • 0

DigiDisco: Constant Clock output at one DIO possible ?


HoWei

Question

I do have an application, in which a constant 10MHz clock needs to be present for some time(~500ms to settle a PLL),  before I can send out the commands to the device via other DIO pins.

How would/could I set this delay/waiting time ?

So far I understood, that when I set "dwf.FDwfDigitalOutConfigure(hdwf, c_int(1))" then all configured DIOs are enabled. This would start my 10MHz clock immediately, but how to setup this delay until the other configuration for programming the device starts  - any examples ?

 

Link to comment
Share on other sites

16 answers to this question

Recommended Posts

Hi @attila,

I solved my delay-problem by "hardware-hacking" the DigitalDisco device.

I connected to the onboard 12MHz XO (next to the FTDI chip) via an resistive divider to reduce the amplitude. This provides a syncronized clock for the ADC.

I adjusted my DIO clocksignals to 4MHz - this allows me to capture without any delay time.

The only issue remaining is the  "normal" trigger in record mode via my python script - but this is already discussed in another toptic/ticket/question.

It would be very very very helpful to have a syncronous output constantly running with the same divider and counter options as a DIO.

Its just a FPGA - (almost) everything should be possible right ;-)

image.png.31e171f2bac4a4c5c169e764213a5353.png

Link to comment
Share on other sites

Hi @HoWei

You can find detailed example with ROM Logic at: https://reference.digilentinc.com/waveforms_-_rom_logic

Here I added a ROM to stop the output after one iteration and let the ADC clock running continuously.

In the script the ROM logic for DIO-12 output has inputs DIO-4 clock (5MHz) and DIO-5 output enable (sDelay+cBits).
DIO-12 <= DIO-4 and DIO-5 

# DIO12 (36) data clock output 
if True:
    rgb = (c_ubyte*cBytes)(0)
    # output is 1 when DIO 4 is 1 and DIO 5 is 1
    for i in range(cCustom.value):
        if ((i>>4)&1)==1 and ((i>>5)&1)==1 :
            rgb[i>>3] |= 1<<(i&7)

    dwf.FDwfDigitalOutEnableSet(hdwf, c_int(12), c_int(1)) # enable output
    dwf.FDwfDigitalOutTypeSet(hdwf, c_int(12), c_int(3)) # DwfDigitalOutTypeROM
    dwf.FDwfDigitalOutDividerSet(hdwf, c_int(12), c_int(1)) 
    dwf.FDwfDigitalOutDataSet(hdwf, c_int(12), rgb, c_int(cCustom.value))

It is done the same way for the bit pattern.

The script configures the DIO-13 to output 10MHz continuously, from start until stopped.
You can add other frequency/phase outputs if you need on further DIO lines.

Link to comment
Share on other sites

Hi @attila,

I do have trouble to understand what your ROM example does. Could you please elaborate in more detail - with words ?

What is the advantage of ROM ? 

 

The only thing I currently see is, that it uses twice the number of outputs. Does ROM offer the possibility to create a delay between ADC clock and data-clock of >1s ?

In my application I found that the ADC requires a stable 10MHz clock for more than 1s until valid data is at the output (it could be also 500ms - I am still debugging this delay requirement). So far I assumed 1ms, because it is enough to lock the PLL - but it needs much more time to stabelize the internal serializer (apparently).

[EDIT]: I found that after 10ms of ADC clock the ADC output data are valid - thus a delay of 10ms would solve my problem and I could use the DigiBox in our application (multiple times) !

 

Is there an internal node/pin/connector  in the DigitalDisco that would provide a syncronous 100MHz clock (the internal sample rate), which I could divide down to 10MHz/5MHz/1MHz with external circuitry ?

Or would it be even possible to "hack" the internal FPGA to make one channel a constant 10MHz clock ?

Ormaybe split the DIO outputs into 2 "banks" to control them independently ? 

Any ideas would be helpful - even if I void the warranty.

Link to comment
Share on other sites

Hi @attila,

thanks for looking into it.

What do you think about the above idea with "initial counter values" ?

So far it is working reliably for me, even if I dont understand why the initial delay with custom dataset is depending on dataset size.

Below is a screenshot of the full sequence run once with the correct runlength:

image.thumb.png.50b5c8416c1ffc20239924e05ea208e6.png

Link to comment
Share on other sites

Hi @HoWei

In the latest software version I added support for delay:
https://forum.digilentinc.com/topic/8908-waveforms-beta-download/

In the following script the DIO-0:5 (on Digital Discovery 24:29) are feed in ROM logic to stop the signals and output on DIO-8:13 (32:37).
The output with this script from a Digital Discovery is captured with an AD2.
You should update setBit functions calls with the required bit sequence.

 

image.png.f4c36f74737ec6bec75d700132d2936d.png

"""
   DWF Python Example
   Author:  Digilent, Inc.
   Revision:  2019-08-28

   Requires:                       
       Python 2.7, 3
   Description:
   DIO 0:3 custom pattern with initial delay feed in ROM logic
   DIO 4 data clock with initial delay feed in ROM
   DIO 5 enable signal for ROM to stop the outputs
   DIO 8:11 custom pattern ROM ouput
   DIO 12 data clock ROM output
   DIO 13 ADC clock
"""


from ctypes import *
from dwfconstants import *
import math
import sys
import time
import matplotlib.pyplot as plt
import numpy

if sys.platform.startswith("win"):
    dwf = cdll.dwf
elif sys.platform.startswith("darwin"):
    dwf = cdll.LoadLibrary("/Library/Frameworks/dwf.framework/dwf")
else:
    dwf = cdll.LoadLibrary("libdwf.so")


dwf.FDwfParamSet(DwfParamOnClose, c_int(0)) # 0 = run, 1 = stop, 2 = shutdown

hdwf = c_int()
print("Opening first device")
dwf.FDwfDeviceOpen(c_int(-1), byref(hdwf))

if hdwf.value == 0:
    print("failed to open device")
    quit()
    
dwf.FDwfDeviceAutoConfigureSet(hdwf, c_int(0))# 0 = the device will be configured only when calling FDwf###Configure

# variables
hzAdc = 1e7 #10MHz DIO 13 (DigitalDiscovery-DIO 37)
hzBits = 5e6 # 5MHz CLK: DIO 12 (36) and data DIO 8:11 (32:35)
sDelay = 1e-3 # 1ms

hzDO = c_double()
dwf.FDwfDigitalOutInternalClockInfo(hdwf, byref(hzDO))
cCustom = c_uint() # custom buffer size in bits
dwf.FDwfDigitalOutDataInfo(hdwf, c_int(0), byref(cCustom))



# ADC CLK DIO 13 (37) 
dwf.FDwfDigitalOutEnableSet(hdwf, c_int(13), c_int(1))
dwf.FDwfDigitalOutDividerSet(hdwf, c_int(13), c_int(int(hzDO.value/hzAdc/2)))
dwf.FDwfDigitalOutCounterSet(hdwf, c_int(13), c_int(1), c_int(1))


# custom pattern DIO 0:3 (32:35)
cBytes = cCustom.value>>3
rgb0 = (cBytes*c_byte)(0)
rgb1 = (cBytes*c_byte)(0)
rgb2 = (cBytes*c_byte)(0)
rgb3 = (cBytes*c_byte)(0)
cBits = 0
def setBit(bits):
    global rgb0
    global rgb1
    global rgb2
    global rgb3
    global cBits
    if((bits>>0)&1) : rgb0[cBits>>3] |= 1<<(cBits&7) # set bit in byte array
    if((bits>>1)&1) : rgb1[cBits>>3] |= 1<<(cBits&7)
    if((bits>>2)&1) : rgb2[cBits>>3] |= 1<<(cBits&7)
    if((bits>>3)&1) : rgb3[cBits>>3] |= 1<<(cBits&7)
    cBits += 1

setBit(0) # initial value
setBit(0x01)
setBit(0x02)
setBit(0x03)
setBit(0x0B)
for i in range(3): setBit(0)
for i in range(4): setBit(0x03)



divBit = int(hzDO.value/hzBits)
divInit = int(sDelay*hzDO.value)
for c in range(4): # configure output channels
    dwf.FDwfDigitalOutEnableSet(hdwf, c_int(c), c_int(1))
    dwf.FDwfDigitalOutTypeSet(hdwf, c_int(c), DwfDigitalOutTypeCustom)
    dwf.FDwfDigitalOutDividerSet(hdwf, c_int(c), c_int(divBit)) # sample rate
    dwf.FDwfDigitalOutDividerInitSet(hdwf, c_int(c), c_int(divBit + divInit)) # initial delay

dwf.FDwfDigitalOutDataSet(hdwf, c_int(0), byref(rgb0), c_int(cBits))
dwf.FDwfDigitalOutDataSet(hdwf, c_int(1), byref(rgb1), c_int(cBits))
dwf.FDwfDigitalOutDataSet(hdwf, c_int(2), byref(rgb2), c_int(cBits))
dwf.FDwfDigitalOutDataSet(hdwf, c_int(3), byref(rgb3), c_int(cBits))


# DIO 4 (28) data clk for ROM
dwf.FDwfDigitalOutEnableSet(hdwf, c_int(4), c_int(1))
dwf.FDwfDigitalOutCounterSet(hdwf, c_int(4), c_int(1), c_int(1))
dwf.FDwfDigitalOutDividerSet(hdwf, c_int(4), c_int(int(divBit/2)))
dwf.FDwfDigitalOutDividerInitSet(hdwf, c_int(4), c_int(int(divBit/2 + divInit)))


# DIO 5 (29) enable signal for ROM, output high for delay + data transfer length
dwf.FDwfDigitalOutEnableSet(hdwf, c_int(5), c_int(1))
dwf.FDwfDigitalOutCounterSet(hdwf, c_int(5), c_int(1), c_int(0))
dwf.FDwfDigitalOutCounterInitSet(hdwf, c_int(5), c_int(1), c_int(1))
dwf.FDwfDigitalOutDividerSet(hdwf, c_int(5), c_int(1))
dwf.FDwfDigitalOutDividerInitSet(hdwf, c_int(5), c_int(divInit + cBits*divBit))


# DIO 8:11 (32:35) ROM logic output
for c in range(4):
    rgb = (c_ubyte*cBytes)(0)
    # output is 1 when DIO 0:3 is 1 and DIO 5 is 1
    for i in range(cCustom.value):
        if ((i>>c)&1)==1 and ((i>>5)&1)==1 :
            rgb[i>>3] |= 1<<(i&7)
    
    dwf.FDwfDigitalOutEnableSet(hdwf, c_int(8+c), c_int(1)) # enable output
    dwf.FDwfDigitalOutTypeSet(hdwf, c_int(8+c), c_int(3)) # DwfDigitalOutTypeROM
    dwf.FDwfDigitalOutDividerSet(hdwf, c_int(8+c), c_int(1)) 
    dwf.FDwfDigitalOutDataSet(hdwf, c_int(8+c), byref(rgb), c_int(cCustom.value))


# DIO12 (36) data clock output 
if True:
    rgb = (c_ubyte*cBytes)(0)
    # output is 1 when DIO 4 is 1 and DIO 5 is 1
    for i in range(cCustom.value):
        if ((i>>4)&1)==1 and ((i>>5)&1)==1 :
            rgb[i>>3] |= 1<<(i&7)

    dwf.FDwfDigitalOutEnableSet(hdwf, c_int(12), c_int(1)) # enable output
    dwf.FDwfDigitalOutTypeSet(hdwf, c_int(12), c_int(3)) # DwfDigitalOutTypeROM
    dwf.FDwfDigitalOutDividerSet(hdwf, c_int(12), c_int(1)) 
    dwf.FDwfDigitalOutDataSet(hdwf, c_int(12), rgb, c_int(cCustom.value))

dwf.FDwfDigitalOutConfigure(hdwf, c_int(1))

dwf.FDwfDeviceCloseAll()

 

Link to comment
Share on other sites

I found another way to create a delay between DIOs: setting the "initial counter value".

For ADC clock (DIO 5) I do not set the inital counter --> it starts immediately after dwf.FDwfDigitalOutConfigure(hdwf, c_int(1))

For CLK and BUS (DIO0..4) i do set the initial counter to a high value (~10000) --> this ensures the CLK (DIO4) and BUS(DIO0..3) are starting after ~1ms

 

This is working in principle, but I do not understand why the initial delay of the BUS (DIO0..3) is depending on the length of the custom dataset.

The setup:

Clock (DIO4):  Pulse-Mode, Div=5 (=20MHz; T=50ns), Counter=(2,2)(=5MHz)  CounterInit=(0,300)

Bus (DIO0..3): Custom-Mode, Div=5(20MHz;t=50ns), Counter=(autoset by custom pattern)  CounterInit=(0,300)

 

The delay I  expected is 300*50ns=15us, but what I measure

Clock(DIO4): measured: 15us  --> result as expected

Bus(DIO0..3): measured: 10us --> not as expected and it is strongly depending on the data-set length - why is that ?

 

To match the delay with a dataset-length of 624, a init value of 924=300+624 is required:

Bus (DIO0..3): Custom-Mode, Div=5(20MHz;t=50ns), Counter=(autoset by custom pattern)  CounterInit=(0,924)

Why this high initial counter value ?

 

Link to comment
Share on other sites

Okay, there is no way to start and stop single DIO channels independently whilst others are still running indefinitely ?

 

Can you quickly comment to my above comment about the clock frequencies at the output:

 

I saw it also in the SDK examples and think it is not correct how the frequency is given. 

In your above example (and also in SDK python-examples), it is said to generate a 10MHz clock by:

dwf.FDwfDigitalOutDividerSet(hdwf, c_int(adc_clk),  c_int(10))                   
dwf.FDwfDigitalOutCounterSet(hdwf, c_int(adc_clk), c_int(1), c_int(1))     

But that is not correct - it generates a 5MHz clock because the counter always divides by 2 at a minimum:

dwf.FDwfDigitalOutDividerSet(hdwf, c_int(adc_clk),  c_int(10))                   #divider generates a 10MHz outpiut clock
dwf.FDwfDigitalOutCounterSet(hdwf, c_int(adc_clk), c_int(1), c_int(1))     #counter output is a 5MHz clock with 50% duty cycle and thus adc_clk is

Link to comment
Share on other sites

Hi @attila,

the bus uses a proprietary protocol with 1 clock + 4 datalines to program a custom IC. The custom IC provides analog values at a pin, which are captured by an ADC. Once the custom IC receives command 0x0B it starts to provide analog values  per rising and falling edge at the output - this is kind of a DDR but for analog values. Each analog value is sampled by the rising edges of the ADC (that is wha the ADC has a 10MHz clock).

According to your example, the clock on DIO12 is typically 5MHz syncing the bus on DIO8..11.

The ADC clock DIO13 is typically 10MHz and running at least 1ms (thats enough for ADC PLL lock) before the first DIO12 clock occurs.

The data on DIO8..11 will be user-specific for the first 4-6 samples (in my example I just count 0x1, 0x2, 0x3) until 0x0B is there - but those data are occuring only once.

Then 63 samples (127 ADC samples) cycles to provide analog values where data on DIO8..11 HAVE to be 0x0. 

The 64th sample MUST be 0x03 (this increases an internal counter to select the next memory cell).

Then 63 samples where data on DIO8..11 HAVE to be 0x0.

The 64th sample MUST be 0x03 (this increases an internal counter to select the next memory cell).

Then 63 samples where data on DIO8..11 HAVE to be 0x0.

The 64th sample MUST be 0x03  (this increases an internal counter to select the next memory cell).

... and so on ... this is repetitive until we have captured a user defined number of analog values.

 

In you above example, how did you delay the DIO8..12 - just sending 0s ?

This is what I am trying to implement currently - unfortunately I will loose ~5k samples from DigiDisco 32k data-memory, if I try to assemble the whole communication into one dataset ?

 

 

Insert other media

Link to comment
Share on other sites

One more thing I cannot achieve yet is, that once the delayed signals are activated unblocked by  dwf.FDwfDigitalIOOutputEnableSet(hdwf, c_int(0x0000)), I need to run a custom dataset for a specific time and only once. But this seems not to work, when unblocking the DIO output.

Here is what I do:

# blocking all signals except for clk
dwf.FDwfDigitalIOOutputEnableSet(hdwf, c_int(0xFFDF))    #all DIOs blocked except for DIO5
#configuring all outputs DIO0..5
dwf.FDwfDigitalOutEnableSet(hdwf, c_int(pixcmd0), c_int(1))                        # set to output
dwf.FDwfDigitalOutTypeSet(hdwf, c_int(pixcmd0), DwfDigitalOutTypeCustom)        # Custom type allows to send DataSet
dwf.FDwfDigitalOutOutputSet(hdwf, c_int(pixcmd0), DwfDigitalOutOutputPushPull)    # drive output load
dwf.FDwfDigitalOutDividerSet(hdwf, c_int(pixcmd0), c_int(div_pixcmd))             # set divider

... and so on....

dwf.FDwfDigitalOutConfigure(hdwf, c_int(1))                                #start the DIO device  (non-blocked outputs only)
time.sleep(1e-6)                                            #wait some time to ensure the ADC PLL is locked

dwf.FDwfDigitalOutRunSet(hdwf, c_double(nSamples/fpixclk))    #define time to run
dwf.FDwfDigitalOutRepeatSet(hdwf, c_int(1)) # run only once
dwf.FDwfDigitalOutConfigure(hdwf, c_int(1))                                #start the DIO device  (non-blocked outputs only)
dwf.FDwfDigitalIOOutputEnableSet(hdwf, 0x0000)            #enable all other outputs 

 

To make clear what I want to achieve, I attached a (photoshopped) image:

image.thumb.png.a74baa6c2e76c94bbe9195b2d213861d.png

Here is what I achieve:

The data on DIO0..4 are just starting arbitrarely, but I want them to start at 0x0, 0x1, 0x2 ... and so on

image.thumb.png.2327f6f82b8b4f62f45f31c7082cc50d.png

 

Link to comment
Share on other sites

After fiddling around I found the following code working, but this creates some more questions - and does not fit to my understanding of the commands. Can you please check if the below usage is correct.

1. It seems one needs to block the delayed pins (here DIO6) by using dwf.FDwfDigitalIOOutputEnableSet(hdwf, c_int(1<<6))    to not start this channel via dwf.FDwfDigitalOutConfigure(hdwf, c_int(1))  right ?

2. All channels which are not blocked will be started via  dwf.FDwfDigitalOutConfigure(hdwf, c_int(1)) 

3. A blocked channel can be enabled after writing a "0" to the corresponding bitfield in dwf.FDwfDigitalIOOutputEnableSet(hdwf, c_int(0x0000))

Is this the intended behaviour ?

dwf.FDwfDigitalIOReset(hdwf)

dwf.FDwfDigitalIOOutputEnableSet(hdwf, c_int(0x00C0)) #blocks DIO6 and DIO7 - cannot be enabled by dwf.FDwfDigitalOutConfigure(hdwf, c_int(1))

dwf.FDwfDigitalOutEnableSet(hdwf, c_int(5), c_int(1))				#set to output
dwf.FDwfDigitalOutDividerSet(hdwf, c_int(5),  c_int(5)) 			#divider generates 20MHz
dwf.FDwfDigitalOutCounterSet(hdwf, c_int(5), c_int(1), c_int(1)) 	#50% duty cycle for 10MHz

dwf.FDwfDigitalOutEnableSet(hdwf, c_int(6), c_int(1))				#set to output
dwf.FDwfDigitalOutDividerSet(hdwf, c_int(6),  c_int(5)) 			#divider generates 20MHz
dwf.FDwfDigitalOutCounterSet(hdwf, c_int(6), c_int(1), c_int(3)) 	#75% duty cycle for 5MHz

dwf.FDwfDigitalOutConfigure(hdwf, c_int(1))							#start the DIO device - but not DIO6
time.sleep(5e-3)										#wait some time 
dwf.FDwfDigitalIOOutputEnableSet(hdwf, c_int(0x0080))			#starts DIO6 clock
time.sleep(2e-3)										#wait some time
dwf.FDwfDigitalIOOutputEnableSet(hdwf, c_int(0x0000))			#starts DIO7 clock

time.sleep(1) # as long as the device are not closed the voltage output is available
dwf.FDwfDeviceCloseAll()

 

Link to comment
Share on other sites

I cannot get your example to work. I used the below code. I basically want to have the 10MHz clock running for 2us on DIO5, and then send another clock as configured on DIO6.

I only see a signal on DIO6 when I uncomment line #dwf.FDwfDigitalOutEnableSet(hdwf, c_int(6), c_int(1))   but not delayed of course.

I do not see any effect of the commands after dwf.FDwfDigitalOutConfigure(hdwf, c_int(1))    

Any idea ?

dwf.FDwfDigitalIOReset(hdwf)

dwf.FDwfDigitalOutEnableSet(hdwf, c_int(5), c_int(1))				#set to output
dwf.FDwfDigitalOutDividerSet(hdwf, c_int(5),  c_int(5)) 			#divider generates 20MHz
dwf.FDwfDigitalOutCounterSet(hdwf, c_int(5), c_int(1), c_int(1)) 	#50% duty cycle for 10MHz

#dwf.FDwfDigitalOutEnableSet(hdwf, c_int(6), c_int(1))				#set to output
dwf.FDwfDigitalOutDividerSet(hdwf, c_int(6),  c_int(5)) 			#divider generates 20MHz
dwf.FDwfDigitalOutCounterSet(hdwf, c_int(6), c_int(1), c_int(3)) 	#75% duty cycle for 5MHz

dwf.FDwfDigitalOutConfigure(hdwf, c_int(1))							#start the DIO device 
time.sleep(2e-6)													#wait some time 

dwf.FDwfDigitalIOOutputSet(hdwf, c_int(0x0000))		 				#set all outputs to logic 0
dwf.FDwfDigitalIOOutputEnableSet(hdwf, c_int(0x00FF))				#ensure only adc_clk is enabled at first
dwf.FDwfDigitalIOOutputSet(hdwf, c_int(0x00FF)) 					#enable the other outputs

time.sleep(1) # as long as the device are not closed the voltage output is available
dwf.FDwfDeviceCloseAll()

 

Link to comment
Share on other sites

I saw it also in the SDK examples and think it is not correct how the frequency is given. 

In your above example (and also in SDK python-examples), it is said to generate a 10MHz clock by:

dwf.FDwfDigitalOutDividerSet(hdwf, c_int(adc_clk),  c_int(10))                   
dwf.FDwfDigitalOutCounterSet(hdwf, c_int(adc_clk), c_int(1), c_int(1))     

But that is not correct - it generates a 5MHz clock because the counter always divides by 2 at a minimum:

dwf.FDwfDigitalOutDividerSet(hdwf, c_int(adc_clk),  c_int(10))                   #divider generates a 10MHz outpiut clock
dwf.FDwfDigitalOutCounterSet(hdwf, c_int(adc_clk), c_int(1), c_int(1))     #counter output is a 5MHz clock with 50% duty cycle and thus adc_clk is

 

Link to comment
Share on other sites

Hi @HoWei

Such long delays can be done in software/script.
1. Start the 10MHz clock using dwf.FDwfDigitalOut*
2. Wait 500ms
3. Configured the other DIOs using dwf.FDwfDigitalIO*
The DigitalOut and DigitalIO control the same DIO pins. These are muxed in the device and the IO has priority over the Out setting. The DigitalOut controls a pin only when the respective pin OE is disabled (default) in DigitaIO.

Like:
1. FDwfDigitalOutEnableSet(hdwf, 0, 1) FDwfDigitalOutDividerSet(hdwf,  0,  10) FDwfDigitalOutCounterSet(hdwf, 0, 1, 1) FDwfDigitalOutConfigure(hdwf, 1) # DIO-0 10MHz
2. sleep(0.5)
3. FDwfDigitalIOOutputSet(hdwf, 0x0000) FDwfDigitalIOOutputEnableSet(hdwf, 0xFF00) FDwfDigitalIOOutputSet(hdwf, 0x0100)  # 0xFF00 = DIO-15:8

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...