I am trying to sample a 8bit input using sample clock and 'start sampling' trigger. Here's how I configure the task:
DAQmxErrChk(DAQmxCreateTask("",&samplHandle));
DAQmxErrChk(DAQmxCreateDIChan(samplHandle,"Dev1/port1/line2:7,Dev1/port2/line0:1","",DAQmx_Val_ChanForAllLines)); // choose my 8 bit DI lines PFI2:PFI9
DAQmxErrChk(DAQmxCfgSampClkTiming(samplHandle,"/Dev1/PFI0",1000000.0,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,length));
DAQmxErrChk(DAQmxCfgDigEdgeStartTrig(samplHandle,"/Dev1/PFI1",DAQmx_Val_Rising));
DAQmxErrChk(DAQmxRegisterEveryNSamplesEvent(samplHandle,DAQmx_Val_Acquired_Into_Buffer,length,0,Callback,this));
DAQmxErrChk(DAQmxTaskControl(samplHandle,DAQmx_Val_Task_Commit));
When I run it in QT Creator it gives me this error:
DAQmx Error: Specified property is not supported by the device or is not applicable to the task.
Property: DAQmx_StartTrig_Type
Task Name: _unnamedTask<0>
Status Code: -200452
DAQmx Error: Task specified is invalid or does not exist.
Status Code: -200088
Previously, when I used analog input instead of digital, I did not have any problems. Any one has a clue what's wrong with my channel configuration?
I am using PCI6259 and BNC2110.
You can use the PCI 6259 to do what you describe, but you need to configure the card a little differently. You would think it would be as straightforward as assigning a start trigger signal and terminal, like you're doing, but M Series devices are not as flexible as the newer X Series devices.
First, M Series devices do not support start triggers for digital tasks [1]:
M Series devices do not have an independent DI or DO Start Trigger for
digital waveform acquisition or generation.
Second, M Series devices can only acquire digital waveforms on port 0, and not on port 1 or 2. Before you can update your program, you will need to rewire your external connections and use lines from port 0. Your device, the NI 6259, has 32 lines for digital waveform measurements [2]:
Waveform Characteristics (Port 0 Only) -- NI 6254/6259: Port 0 (P0.<0..31>)
PFI/Port 1/Port 2 Functionality -- Static digital input, static digital output, timing input, timing output
Once you switch to port 0, there are two approaches you can take:
Use another subsystem on the card to provide the trigger and clock.
Use "change detection" to acquire a sample whenever any line has a transition.
Using another subsystem
M Series devices have analog input and counter/frequency output subsystems, and either one of these can be used to provide a start trigger and sample clock for your digital input measurements [1a]:
For example, consider the case where you are using AI Sample Clock as the
source of DI Sample Clock. To initiate pulses on AI Sample Clock (and
therefore on DI Sample Clock), you use AI Start Trigger to trigger the start
of an AI operation. The AI Start Trigger causes the M Series device to
begin generating AI Sample clock pulses, which in turn generates
DI Sample clock pulses.
If you are using a Counter output as the source of DI Sample Clock, the
counter’s start trigger, enables the counter which drives DI Sample Clock.
NI-DAQmx installs C examples that show how to use the API to configure tasks [3]. There are few that you can mix together to accomplish your design:
Continuously Read Digital Channel - External Clock
This can be the basis for the digital task settings
Continuously Acquire Voltage Samples - External Clock - Digital Start
This shows how to configure an analog task for an external sample clock and external digital start trigger, which can be doubled as the sample clock and start trigger for the digital task
Continuous Analog Input and Read Digital Channel
This is how you can synchronize the analog and digital subsystems
Generate Digital Pulse Train - Continuous - Digital Start
This is how you would configure a counter task to be the sample clock and start trigger
Keep in mind that the file names on disk for the examples are abbreviated.
Using change detection
M Series devices can detect rising edges, falling edges, or either edge individually on each DIO line. You can configure the task to raise an interrupt whenever a change is detected [1b]:
The DAQ devices synchronize each DI signal to 80MHzTimebase, and then sends the
signal to the change detectors. The circuitry ORs the output of all enabled
change detectors from every DI signal. The result of this OR is the Change
Detection Event signal.
As long as your input signals change slowly (100 Hz or less), you can use this technique to acquire the data. If they change must faster, it is unlikely that the program would be able to service the interrupts quickly enough. Because of this constraint, I would recommend trying the first approach.
The DAQmx C example [3] for this type of measurement is called Read Digital Channel - Change Detection.
References
[1a] M Series User Manual :: Digital Waveform Triggering (page 99..100)
[1b] M Series User Manual :: DI Change Detection (page 104..105)
http://digital.ni.com/manuals.nsf/websearch/2025C99AB0614F9E8625748000577B9A
[2] NI 625x Specifications :: Digital I/O/PFI
http://digital.ni.com/manuals.nsf/websearch/210C73CBF91128B9862572FF0076BE85
[3] Text Based NI-DAQmx Data Acquisition Examples :: ANSI C
http://www.ni.com/white-paper/6999/en/#ANSIC
Related
I am working on a project where I am using a Keithley 2400 Sourcemeter to measure surface conductivity of a specific material. I have a fixed delay number (say 1000 ms) between each measurement (I am using LabTracer 2.0). For the purpose of my project I have to measure the conductivity on three different points on the surface of the specimen. In order to achieve that I am using an Arduino microcontroller which controls the circuit’s endings – three resistors on different places on the surface of the material. The Arduino board starts the process when it is being triggered by the Keithley (when the current flow starts – utilizing analogRead() )
My problem is that the delay time of Keithley is not exactly 1000 ms, and this causes out of sync phenomena.
An ideal solution to this would be if I could get an output in real-time each time a new measurement is taken by the Keithley. In that way I could use this output as a reference to whether open or close the circuit. The analogRead command is useful for the start of the circuit, as it gives an output when the current flow starts. Ideally I would like to receive another output for each new measurement.
The way I am thinking the whole process is this:
Initialization of the circuit by setting resistor_1 to OPEN
Start Keithley
Take measurement
CLOSE resistor_1
OPEN resistor_2
If new measurement is taken then:
CLOSE resistor_2
OPEN resistor_3
If new measurement is taken then:
CLOSE resistor_3
OPEN resistor_1
etc…
Any suggestions on that would be much appreciated. Thanks in advance!
I am generating a certain signal (digital pulse) in one of my verilog module running on programmable logic in Xilinx Zynq chip. Signal is pretty fast, with clock of about 200MHz.
I also have a simple linux and framebuffer Qt interface running for later controlling my application.
How can I sample my signal in order to make oscilloscope like interface inside my Qt app? I want to be able to provide visual of the pulse I am generating.
What do I need to use to be able to sample enough data at such clock frequency? And how do I pass it with kernel module or mmap to Qt?
You would do best to do what most oscilloscopes do: sample the data to RAM, and only then transfer it to the processor for display/analaysis, at a more "relaxed" pace.
On the FPGA side you will need a state machine that detects some sort of start or trigger condition, probably after a bit in a mode register is set from the software side to arm it.
The state machine will then fill samples into a buffer made of one or more block rams. If you want to placing the trigger somewhere in the middle of the samples captured, you should it as a circular buffer, and have it record continuously, stopping configurable number of samples after the trigger, so that some desired number from before the trigger condition remain un-overwritten by newer ones following it.
Since FPGA block rams are typically dual port, you can simply hook the other port up to your CPU bus for readout. You will probably want a register to read the state of the sampling state machine, and if you go with the circular buffer approach, the address where it stopped, so that you can unwrap the data to a linear record of time.
Trying to do streaming realtime sampling might be possible, but would be a lot harder and it is not clear that you could do anything meaningful with the data so produced in real time. Still, if you want to try you would probably need to put a FIFO buffer in between the sampling and the processor bus, as you will probably only be able to consume data in chunks, while having to service other operations in between, so something is needed to absorb the constant-rate inflow of samples. Another approach could be to try to build a DMA engine which would write samples directly to external system ram, but that will likely be even harder.
You could also see if there are any high speed interfaces available in the CPU which you could leverage - they might be things originally intended for video, for example.
It also appears that you are measuring only a digital signal, ie, probalby one bit. If you want to handle a higher input sample rate than the FPGA fabric can support, that could mean you could potentially use something like a deserializer block at the edge of the FPGA to turn the 1-bit input stream into a slower stream of wider samples to store.
In terms of output, once you have a vector of samples in a buffer it's pretty simple to turn that into a scope/logic analyzer type plot, with as much zooming, cursor annotation, automatic measurement or whatever you like.
Also don't forget that if the intent is only to use this during development, FPGAs and their tools often have the ability to build a logic analyzer right into the design, with the data claimed over the programming interface for plotting on a PC.
I am using the readstream interface to sample at 100hz, I have been able to integrate the interface into Oscilloscope application. I just have a doubt in the way I pass on the buffer value on to the packet to be transmitted . Currently this is how I am doing it :
uint8_t i=0;
event void ReadStream.bufferDone( error_t result,uint16_t* buffer, uint16_t count )
{
if (reading < count )
i++;
local.readings[reading++] = buffer[i];
}
I have defined a buffer size of 50, I am not sure this is the way to do it as I am noticing just one sample per packet even though I have set Nreadings=2.
Also the sampling rate does not seem to be 100 samples/second when I check.I am not doing something right in the way I pass data to the packet to be transmitted.
I think I need to clarify a few things according to your questions and comments.
Reading a single sample from an accelerometer on micaZ motes works as follows:
Turn on the accelerometer.
Wait 17 milliseconds. According to the ADXL202E (the accelerometer) datasheet, startup time is 16.3 ms. This is because this particular hardware is capable of providing first reading not immediately after being powered on, but with some delay. If you decrease this delay, you will likely get a wrong reading, however, the behavior is undefined, so you may sometimes get a correct reading or the result may depend on environment conditions, such as ambient temperature. Changing this 17-ms delay to a lower value is certainly a bad idea.
Read values (in two axes) from the Analog to Digital Converter (ADC), which as an MCU component that converts analog output voltage of the accelerometer to the digital value (an integer). The speed at which ADC can sample is independent from the parameters of the accelerometer: it is another piece of hardware.
Turn off the accelerometer.
This is what happens when you call Read.read() in your code. You see that the maximum frequency at which you can sample is once every 17 ms, that is, 58 samples per second. It may be even a bit smaller because of some overhead from MCU or inaccuracy of timers. This is true when you sample by calling Read.read() in a loop or every fixed interval, because this call itself lasts no less than 17 ms (I mean the delay between the command and the event).
What you may want to do is:
Turn on the accelerometer.
Wait 17 ms.
Perform series of reads.
Turn off the accelerometer.
If you do so, you have one 17-ms delay for a set of samples instead of such delay for each sample. What is important, these steps have nothing to do with the interface you use for performing readings. You may call Read.read() multiple times in your application, however, it cannot be the same implementation of the read command that is already implemented for this accelerometer, because the existing implementation is responsible for turning on and off the accelerometer, and it waits 17 ms before reading each sample. For convenience, you may implement the ReadStream interface instead and call it once in your application.
Moreover, you wrote that ReadStream used a microsecond timer and is independent from the 17-ms settling time of the ADC. That sentence is completely wrong. First of all, you cannot say that an interface uses or does not use a timer. The interface is just a set of commands and events without their definitions. A particular implementation of the interface may use timers. The Read and ReadStream interfaces may be implemented multiple times on different platforms by various hardware components, such as accelerometers, thermometers, hygrometers, magnetometers, and so on. Secondly, the 17-ms settling time refers to the accelerometer, not the ADC. And no matter which interface you use, Read or ReadStream, and which timers a driver uses, milli- or microsecond, the 17-ms delay is always required after powering on the accelerometer. As I mentioned, you probably want to make this delay once per multiple reads instead of once per a single read.
It seems that the TinyOS source code already contains an implementation of the accelerometer driver providing the ReadStream interface which allows you to sample continuously. Look at the AccelXStreamC and AccelYStreamC components (in tos/sensorboards/mts300/).
The ReadStream interface consists of two commands. postBuffer(val_t *buf, uint16_t count) is called to provide a buffer for samples. In the accelerometer driver, val_t is defined as uint16_t. You may post multiple buffers, one by one. This command does not yet start sampling and filling buffers. For that purpose, there is a read(uint32_t usPeriod) command, which directs the device to start filling buffers by sampling with the specified period (in microseconds). When a buffer is full, you get an event bufferDone(error_t result, val_t *buf, uint16_t count) and a component starts filling a next buffer, if any. If there are no buffers left, you get additionally an event readDone(error_t result, uint32_t usActualPeriod), which passes to your application a parameter usActualPeriod, which indicates an actual sampling period and may be different (especially, higher) from a period you requested when calling read due to some hardware constraints.
So the solution is to use the ReadStream interface provided by AccelXStreamC and AccelYStreamC (or maybe some higher-level components that use them) and pass an expected period in microseconds to the read command. If the actual period is lower than one you expect, this means that sampling at higher rate is impossible either due to hardware constraints or because it was not implemented in the ADC driver. In the second case, you may try to fix the driver, although it requires good knowledge of low-level programming. The ADC driver source code for this platform is located in tos/chips/atm128/adc.
I have a PIC24 based system equipped with a 24 bit, 8 channels ADC (google MCP3914 Evaluation Board for more details...).
I have got the board to sample all of the 8 channels, store the data in a 512x8 buffer and transmit the data to PC using a USB module when the buffer is full (it's is done by different interrupts).
The only problem is that when the MCU is transmitting data (UART transmission interrupt has higher priority than the ADC reading interrupt) the ADC is not sampling data hence there will be data loss (sample rate is around 500 samples/sec).
Is there any way to prevent this data loss? maybe some multitasking?
Simply transmit the information to the UART register without using interrupts but by polling the bit TXIF
while (PIR1.TXIF == 0);
TXREG = "the data you want to send";
The same applies to the ADC conversion : if you were using interruptions to start / stop a conversion, simply poll the required bits (ADON) and thats it.
The TX bits and AD bits may vary depending on your PIC.
That prevents the MCU to enter an interrupt service routine and loose 3-4 samples.
In PIC24 an interrupt can be assigned one of the 8 priorities. Take a look at the corresponding section in the "Family Reference Manual" -> http://ww1.microchip.com/downloads/en/DeviceDoc/70000600d.pdf
Alternatively you can use DMA channels which are very handy. You can configure your ADC to use the DMA, and thus sampling and feeding the buffer won't use any CPU Time, same goes for UART I beleive.
http://ww1.microchip.com/downloads/en/DeviceDoc/39742A.pdf
http://esca.atomki.hu/PIC24/code_examples/docs/manuallyCreated/Appendix_H_ADC_with_DMA.pdf
I'm new to microcontroller programming and I have interfaced my microcontroller board to another device that provides a status based on the command send to it but, this status is provided on the same I/O pin that is used to provide data. So basically, I have an 8-bit data line that is used as an output from the microcontroller, but for certain commands I get a status back on one of the data lines if I choose to read it. So I would be required to change the direction of this one line to read the status thus converting this line as an ouput to an input and then back to an output. Is this acceptable programming or will this changing of the I/O pin this frequently cause instability?
Thanks.
There should not be any problem with changing the direction of the I/O line to read the status returned by the peripheral provided that you change the state of the line to an input before the peripheral starts to drive the line and then do not try to drive the line as an output until the peripheral stops driving it. What you must try to avoid is contention between the two driver devices, i.e. having the two ends being driven to opposite states by the processor and peripheral. This would result in, at best a large spike in the power consumption or worse blown pin driver circuitry in the processor, peripheral or both.
You do not say what the processor or peripheral are so I cannot tell whether there are any control bits in the interface that enable the remote device to output the status so that you can know whether the peripheral is driving the line at any time.
I've done this on digital I/O pins without any problems but I'm very far from an expert on this. It probably depends entirely on which microcontroller you are using though.
Yes, it's perfectly fine to change I/O direction on microcontroller repeatedly.
That's the standard method of communicating over open-collector buses such as I2C and the iButton. (see PICList: busses for links to assembly-language code examples).
transmit 0 bit: set output LATx bit to 0, and then set TRISx bit to OUTPUT.
transmit 1 bit: keep output LATx bit at 0, and set TRIS bit to INPUT (let external resistor pull-up line to high)
listen for response from peripheral: keep output LATx bit at 0, and set TRIS bit to INPUT. Let external resistor pull-up line to high when peripheral is transmitting a 1, or let the peripheral pull the line low when peripheral is transmitting a 0. Read the bit from the PORTx pin.
If both ends of the bus correctly follow this protocol (in particular, if neither end actively drives the line to high), then you never have to worry about contention or current spikes.
It`s important to remember that any IO switching in high speed generates EMI.
Depending of switching frequency, board layout and devices sensibilities, this EMI can affect performance and reliability of your application.
If you are having problems in your application use an oscilloscope to check for irradiated EMI in your board lanes.