DAQ Matlab toolbox: how to count trigger events without an edge counter channel and how to output different value at each successive trigger - matlab

I need your help with the session based interface for the Matlab DAQ toolbox. I have not been able to find much help in the MathWorks tutorials or examples. I am currently using a USB-6003 DAQ from NI.
So basically in my system I have 2 analog output channels (ch1 and ch2) and 1 analog input channel (ch3), and what I am trying to do is to drive the output voltage in ch1 from 0V to 10V in steps of 1V, with ch2 constant and then repeat the loop in ch1 for a different voltage in ch2. As for the analog input ch3, I am triggering it some time after triggering the ch1. My triggers are being externally generated by a function generator.
What I have been struggling with is:
1) How to at each successive trigger event output a different value in the ch1.
2) And how after 11 triggers, can I change ch2 output's.
3) How to save the input in a different location between trigger events, so it does not get overwritten by the next event.
My main constraints are:
1) I cannot use an edge-counter channel to count the triggers because I only have two PFI channels and I need both, one to trigger ch1 and the other ch3 (I cannot use only one).
2) I cannot use wait or any other software time function, because I need a high speed acquisition system (it is for a laser microscope)
3) I need two have at least 2 sessions running in parallel because my DAQ does not allow simultaneous tasks in the same session.
I have attached a channel's time diagram of what I am trying to do.
Channels diagram

Caution
"I need a high speed acquisition system"
USB might not be the right option. Using USB as the control/data transport mechanism is slow compared to other computer I/O, like PCIe or EtherCAT. If, after you get this working, you determine that you need lower latency and jitter, my recommendation is to try CompactRIO and LabVIEW Real-Time.
Compounding the performance is the on-demand nature of the USB-6003. While both analong input and analog output are controlled by electrical signals (the start trigger and sample clock) and have their data automatically transferred by the driver, the digital input and counter are only software-timed, which means that reading data isn't automatic and must be prompted by you, the user, with a read command.
Since the only way you can get digital data from a USB-6003 is on-demand, your only option is to wait for it; there is no way to be notified that a new edge has arrived. Other devices (like the PCIe-63xx X Series or cDAQ-940x devices) support digital input change detection, which causes a software event to be sent to the program. If you had one of these devices, then you wouldn't have to wait.
Suggestion
However, if you change your triggering and data strategies a little, I still think you can achieve the kind of I/O you want. You'll then be able to evaluate its speed and reliability to decide if you need to upgrade DAQ hardware.
New triggering and data strategy
The core idea is: instead of keeping the channels on their own "time base", unify them to a single time base and use that to coordinate the voltage updates. By doubling the frequency of your external trigger, all three channels can share the same timing. In other words, both the analog input task and the analog output task use the same external signal as their sample clock.
Double the frequency of the FGEN's trigger signal.
Repeat an analog output sample if the level doesn't need to change.
Throw an analog input sample away if it coincides with an output level change.
The analog output samples would be:
ch1 ch2
0.0 0.0
0.0 0.0
1.0 0.0
1.0 0.0
2.0 0.0
2.0 0.0
0.0 1.0
0.0 1.0
New program strategy
Now that both the analog input and analog output are using the FGEN as their sample clock, the MATLAB routine only needs to prepare the operation and then monitor/feed it. The hardware will be able to generate and acquire without any intervention from the PC, but the PC will need to periodically read analog input data and write more analog output data to keep the driver satisfied.
I don't know how much of the DAQmx API MATLAB exposes, but you can ask the driver how many samples are left in the device's buffer
Analog input is DAQmxGetReadAvailSampPerChan (doc)
Analog output is DAQmxGetWriteSpaceAvail (doc)
Reference
NI USB-6003 Specifications
http://digital.ni.com/manuals.nsf/websearch/666A752FCC177B0186257CD8006C24C8

Related

If the PC register is simultaneously read and written, does its read data contain the previous data or the newly-written data?

If the PC register is simultaneously read and written, does its read data contain the previous data or the newly-written data? Based on my understanding of sequential circuits, the effect of the write command does not instantly take effect in the PC register due to propagation delay so, at the rising edge of the clock, the read command will get the old value. But corollary to my question is if this is the case, shouldn't the read command would also have a delay in some sense and could possibly read the newly-written data?
A program counter is normally special enough that it's not part of a register file with other registers. You don't have a "read command", its output is just always wired up to other parts that read it when appropriate. (i.e. when its output is stable and has the value you want). e.g. see various block diagrams of MIPS pipelines, or non-pipelined single-cycle or multi-cycle designs.
You'd normally build such a physical register out of edge-triggered flip-flops, I think. (https://en.wikipedia.org/wiki/Flip-flop_(electronics)). Note that a D flip-flop does latch the previous input as the current output on a clock edge, and then the input is allowed to change after that.
There's a timing window before the clock edge where the input has to remain stable, it can start to change a couple gate delays after. Note the example of a shift register built by chaining D flip-flops all with the same clock signal.
If you have a problem arranging to capture a value before it starts changing, you could design in some intentional clock skew so the flip-flop reliably latches its input before you trigger the thing providing the input to change it. (But normally whatever you're triggering will itself have at least a couple gate delays before its output actually changes, hence the shift-register made of chained D flip-flops.)
That wiki article also mentions the master-slave edge-triggered D Flip-Flop that chains 2 gated (not clocked) D latches with an inverted clock, so capturing the input happens on the opposite clock edge from updating the output with the previously-captured data.
By comparison and for example, in register files for general-purpose registers in classic RISC pipelines like MIPS, IIRC it's common to build them so write happens in the first half-cycle and read happens in the second half-cycle of the ID stage. (So write-back can "forward" to decode/fetch through the register file, keeping the window of bypass-forwarding or hazards shorter than if you did it in the other order.)
This means the write data has a chance to stabilize before you need to read it.
Overall, it depends how you design it!
If you want the same clock edge to update a register with inputs while also latching the old value to the output, you a master-slave flip-flop will do that (capture the old input into internal state, and latch the old internal state onto the outputs).
Or you could design it so the input is captured on the clock edge, and propagates to the output after a few gate delays and stays latched there for the rest of this clock cycle (or half cycle). That would be a single D flip-flop (per bit).

Optimize power consumption with STM32L4 ADC

I'm working on a firmware development on a STM32L4. I need to sample an analog signal at around 200Hz. So basically one analog to digital conversion every 5ms.
Up to now, I was starting the ADC in continuous conversion mode, triggered by a timer. However this prevents to put the STM32 in Stop mode in between conversions, which would be very efficient in terms of power consumption since 99%+ ot the time the product has nothing to do.
So my idea is to use the single conversion mode: use a low power timer to wakeup the product from Stop mode every 5ms, launch a single conversion in the LPTIM interrupt handler (waiting for ADC end of conversion in polling), and go back to Stop mode.
Do you think it makes sense or do you see problems to proceed like this ? I'm not sure about polling for a single ADC conversion inside a handler, what do you think ? I think a single conversion on one channel should be pretty fast (I run at 80MHz, the datasheet mentions a maximum sampling time of 8us)
Do I have to disable/enable ADC (the bit ADEN) between each single conversion ?
Also, I have to know how long a single conversion lasts to assess whether the solution is interesting or not. I'm confused about the sampling time (bits SMP). The reference manual states: "This sampling time must be enough for the input voltage source to charge the embedded capacitor to the input voltage level." What is the way to find the right SMP value ?
There are no problems with the general idea, LPTIM1 can generate wakeup events through the EXTI controller even in Stop2 mode.
I'm not sure about polling for a single ADC conversion inside a handler, what do you think ?
You might want to put the MCU in Sleep mode in the timer interrupt, and have the ADC trigger an interrupt when the conversion is complete. So disable SLEEPDEEP in the timer interrupt, and enable it in the ADC interrupt.
What is the way to find the right SMP value ?
Empirical method: start with the longest sampling time, and start decreasing it. When the conversion result significantly changes, go one or two steps back.

How to synchronize readout of binary streams on serial port of Matlab

I'm having an issue which is partially Matlab- and partially general programming-related, I'm hoping that somebody can help me brainstorm for solutions.
I have an external microcontroller that generates a large stream of binary data (~40kb) every 400ms and sends it via UART to a PC running Matlab scripts. The data is not encoded in hexa or dec characters, but true binary (hence, there's no terminator defined as all 256 values are possible, valid combinations of data). Baudrate is set at 1024000. In short, it takes roughly 375ms for a whole stream of data to be sent, with 25ms of dead time in between streams
In Matlab, the serial port is configured correctly (also 1024000, 8x bits, 1x stop bit, no parity, no hardware flow control, etc.). I am able to readout the data I'm sending via the microcontroller correctly (i.e. there's no corruption of data), but I'm not being able to synchronize the serial readout on Matlab. My script is as follows:
function data_show = GetDATA
if ~isempty(instrfind)
fclose(instrfind);
end
DATA_TOTAL_SIZE = 38400;
DATA_buffer = uint8(zeros(DATA_TOTAL_SIZE,1));
DATA_show = reshape(DATA_buffer(1:2:end)',[160,120])';
f_data_in = false;
f_data_out = true;
serialport = serial('COM11','BaudRate',1024000,'DataBits',8,'FlowControl','none','Parity','none','StopBits',1,...
'BytesAvailableFcnCount',DATA_TOTAL_SIZE,'BytesAvailableFcnMode','byte','InputBufferSize',DATA_TOTAL_SIZE * 2,...
'BytesAvailableFcn',#GetPortData);
fopen(serialport);
while (get(serialport,'BytesAvailable') ~= 0) % Skip first packet which might be incomplete
fread(serialport,DATA_TOTAL_SIZE,'uint8');
end
f_data_out = true;
while (1)
if (f_data_in)
DATA_buffer = fread(serialport,DATA_TOTAL_SIZE,'uint8');
DATA_show = reshape(DATA_buffer(1:2:end)',[160,120])'; %Reshape array as matrix
DATAsc(DATA_show);
disp('DATA');
end
pause(0.01);
end
fclose(serialport);
delete(serialport);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function GetPortData (obj,~)
if f_data_out
f_data_in = true;
end
end
end
The problem I see is that what I end up reading is always the correct size, but belongs to multiple streams, because I haven't found a way to tell Matlab that these 25ms of no data should be used to synchronize (i.e. data from before and after that blank period should belong to different streams).
Does anyone have any suggestions for this?
Thanks a lot!
For completeness, I would like to post the current implementation I have fixing this issue, which is probably not a suitable solution in all cases but might be useful in some.
The approach I took consists in moving into a bi-directional communication protocol, in which Matlab initiates the streaming by sending a very short command as a trigger (e.g. single, non-printable character). Given the high baudrate it does not add significant delay due to processing in the microcontroller's side.
The microcontroller, upon reception of this trigger, proceeds to transmit only one full package (as opposed to continuously streaming package at a 5Hz rate). By forcing Matlab to pickup a serial package of the known length right after issuing the trigger, it ensures that only one package and without synchronization issues is received.
Then it becomes just a matter of encapsulating the Matlab script in a routine with a 5Hz tick given by a timer, in which the sequence is repeated (send trigger, retrieve package, do whatever processing, and repeat).
Advantages of this:
It solves the synchronization problems
Disadvantages of this:
Having Matlab running on a timer tick does not ensure perfect periodicity, and hence the triggers might not always be sent at exactly 5Hz. If triggers are sent at "inconvenient" times for the microcontroller, packages might need to be skipped in order to avoid that a package is updated in memory while it is still being transmitted (since transmission takes a significant part of the 200ms time slot)
From experience, performance can vary a lot depending on what the PC running Matlab is doing. For example, it works fine when the PC is left on its own to do the acquisition, but if another program is used (e.g. Chrome), Matlab begins to lag and that results in delays in transmission of triggers.
As mentioned above, it's not a complete answer, but it is an approach that might be sufficient in some situations. If someone has a more efficient option, please fell free to share!

Micromaster 440. Ways to limit output frequency on the run?

I need to control a conveyor (driven by Micromaster 440) from a PC program using SFC14/15.
The scheme will be: Supervisors PC ->(ethernet)-> S7-1200 ->(profibus)-> Micromaster 440.
At the moment, Micromaster's output frequency is controlled via a potentiometer (analog inputs) by the "field" operator. The problem is that sometimes the operator increases the conveyor speed in order to do his job faster and this affects the production negatively. The "supervisor" wants to be able to limit output frequency using the PC program.
Of course I've seen the list of MM440 parameters and I know about P1082, but I've discovered that, unfortunately, MM440 should be stopped before the new value of P1082 takes effect. In my case it's preferable to be able to change the value on the run.
Fortunately, it seems that P0757 - P0760 - (input scaling) can be changed on the run, but this parameter has sign "first confirm", which means that
the ā€œPā€ button on the operator panel (BOP or AOP) must be pressed before the
changes take effect.
But the MM440 has only one slot for the Profibus/BOP/AOP panel and I'll be using Profibus. So, in this case, what will be the behavior of mm440 like? I want to believe that, perhaps, this condition is not obligatory when using profibus panel...
I would opt for a solution where the operator no longer operates the belt speed directly but tells the S7-1200 PLC a what speed he would like the belt to run (either by using 2 +/- buttons or a pot-meter). The PLC can then control the speed of the belt (either by analog output or 2 digital (+/-) outputs).
As an added bonus you can stop the belt when it is accidentally left on and things like that...

Using MATLAB to send multiple serial signals through the same port

I'd like to send multiple signals (4 inputs and outputs and 7 outputs) from my Laptop to a microcontroller. I'm thinking of using a USB to serial converter and multiplexing the data through the port. I'll need to write codes both in the laptop end and in the microcontroller to multiplex the data.
Eg:
Tx of microcontroller:
1.Temperature sensor ADC output->Laptop
2.Voltage sensor to laptop
3.Current Sensor to Laptop
4.Photodiode current to Laptop
So I need to write a program in the microcontroller to send the data in this order. How can I accomplish this? I was thinking of an infinite loop which sends the data with time delays in between.
At the Rx pin of Microcontroller,
Seven bit sequences. Each bit sequence will be used to set the duty cycle of a PWM generated by the microcontroller.
I also need the same multiplexing or demultiplexing arrangement in the matlab end. Here too, I'm thinking of allotting some virtual 'channels' at different instants of time. What kind of algorithm would I need?
In case you always send all the inputs/outputs at the same rate, you could simply pack them into 'packets', which always start with one or more bytes with a fixed value that form a 'packet header'. The only risk is that one of the bytes of the sensor data might have the same value as the start-byte at the moment you try to start receiving bytes and you are not yet synchronized. You can reduce this risk by making the header longer, or by choosing a start-byte that is illegal output for the sensors (typically OxFF or so).
The sending loop on the microcontroller is really easy (pseudocode):
while True:
measure_sensors()
serial.send(START_BYTE)
serial.send(temperature)
serial.send(voltage)
serial.send(current)
serial.send(photodiode)
end while
The receiving loop is a bit more tricky, since it needs to synchronize first:
while True:
data = serial.receive()
if data != START_BYTE:
print 'not synced'
continue #restart at top of while
end if
temperature = serial.receive()
voltage = serial.receive()
current = serial.receive()
photodiode = serial.receive()
do_stuff_with_measurements()
end while
This same scheme can be used for communication in both directions.