LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Periodically Extract Payload from CANBus Frames using cRIO in FPGA mode

Hi All,

 

I am new to LabVIEW and NI products and I'm trying to accomplish the following (I expected this to be simple to do!):

 

I have a bunch of CAN devices (let's say 12 of them) and I'd like to periodically read data from them. To do so, I write a certain frame (as specified in one of the device's datasheets) to set them all in operational mode. I only need to this once. To read data, I have to write a frame requesting the data and then read the frame I receive, and extract its payload. I set the bus speed to the maximum possible which is 1 Mbit/sec. I think each frame has around 109 bits max (based on the datasheet too), so my expectation is that 250 microsecond is more than enough for one request and receive operation.

 

Since I am using cRIO9022 (cRIO-9114 chassis) and a NI 9853 CAN module, I was not able to run in scan mode, which seems to be easier to do from the tutorials I saw. I had to run in FPGA mode, and so I used the section 5 in the following tutorial: http://www.ni.com/tutorial/11198/en/ combined with code from "CAN Basic (FPGA).vi" example code to come up with something. I have no problem sending and receiving the frames I want and extracting data, but I'm having trouble writing data to a file using a fixed sample rate and in real-time.

 

I have two files, the first runs on the FPGA target. It continuously runs, requesting data from the 12 elements, extracting data from the received frames and writing that to a FIFO once I read from all 12 devices. What I'm trying to do in my code is to only spend 250 microseconds to do a request/read operation. I don't know if I implemented correctly, and I'm not sure if the hardware is actually reading every 250 microseconds although I expect it to. I'm not sure how to debug that either.

 

The second program runs the FPGA target program and sets the send/receive period for it. It's supposed to record data for a set recording time and write it to a tdms file. It somewhat works but what's happening is that the data is not actually always real-time. If I set the frame send/receive period to 250us, it records for a longer time (probably another timing issue in my code). If I set it to 800 us, it seems to match real time as expected. If I set it to more, it records for a shorter amount of time. I tried recording the time elapsed and things don't seem to be timed as I expect.

 

I attached the code, I think it's simple and has enough comments. It has the project file and VIs. I included the CANOpen communication datasheet for the device(s) I'm reading from. I also included a sample log file. Rows 2 to 12505 are the data measurements and the remaining ones are "timestamps" (taken based on write-to-file time) for 12 measurements.

 

Please let me know if anything need clarification. I need help resolving my timing issues, or if you can recommend any easy way to do this. I can't be the first one trying to periodically extract and log payload from a CANBus!

 

Your help is appreciated!

 

Thanks

0 Kudos
Message 1 of 9
(5,310 Views)

Have you tried using the CAN Logging.lvproj example? This example can be found in the NI Example Finder.

0 Kudos
Message 2 of 9
(5,238 Views)

Thank you for your reply. I did take a look at it before. It logs as many frames as possible which I don't have a problem doing. My problem is with logging data for a user-specified sampling period and for a user-specified real-life time. If I use a certain sampling period, I manage to record for the time I specify (it works fine). But if I try a smaller (or larger) period, it records for longer (or shorter) than the time I specify, which makes me wonder if it represents real time.. 

 

0 Kudos
Message 3 of 9
(5,228 Views)

1. What do you mean when you say user-specified real-life time and where is this set in your code?

2. What do you mean when you say, "If I use a certain sampling period, I manage to record for the time I specify (it works fine). But if I try a smaller (or larger) period, it records for longer (or shorter) than the time I specify, which makes me wonder if it represents real time"? Additionally, how are you benchmarking these times to know that it is executing out of spec?

0 Kudos
Message 4 of 9
(5,208 Views)

1. Maybe I abused my notation a little... In the VI front panel, I have a control with the name "Recording time (sec)". If I set it to run 5 seconds, I expect to look at any clock/timer and the code takes 5 seconds to run and then stops (and only logs data collected during those 5 seconds, not older data..).

2. I have another control with the name "Frame Send+Receive Period (uSec)", let's say it's 250 us. I use it so that a request data + read data operation takes 250 us, not more, not less. However, if I set it to 250 us, and set recording time to say 5 seconds, the code runs for 12 seconds instead. I verify this by the "Elapsed Overall Time(s)" indicator in the VI panel (it uses the elapsed time function in the block diagram). I can also verify it if I use my phone timer. Also, if I do stuff with my experimental setup for 12 seconds, I can see that the entire 12 seconds was logged rather than 5 sec. If I set the period to 800 us and recording time to 5 seconds, then it runs for 5 seconds as expected. If I go with 1 ms , and 5 seconds, it records for 4 seconds instead! By representing real time, I mean if I collect for 5 seconds with a set sampling period, I expect my data points to be 1 sampling period apart (not less or more) and collected during those 5 seconds (not old data stored in the FIFO or something).

0 Kudos
Message 5 of 9
(5,194 Views)

1. I do not see how setting the "Recording time (sec)" controls the execution time of your code at all.

0 Kudos
Message 6 of 9
(5,171 Views)

It's in the WriteToFile.vi; that's my main VI, running on the host. The VI running on the FPGA is CollectData.vi. I attached a screenshot in this reply as well... I downloaded the zip I attached before, looks like all the VIs are there..

0 Kudos
Message 7 of 9
(5,167 Views)

I guess my question is that I do not understand how your logic works for controlling the length at which that piece of code executes based on the recording time control. 

0 Kudos
Message 8 of 9
(5,148 Views)

Ok, I probably implemented it wrong but here my logic:

1) In WriteToFile.vi, I set "Frame Send+Receive Period (uSec)", say 250, and pass it to the FPGA vi (CollectData.vi), so I expect the FPGA vi to take exactly 12*250 us = 3ms (number of transmitters is 12) to request and receive a data frame from each transmitter, and then write the 12 extracted payloads to the FIFO. This should be running continuously as long as WriteToFile.vi is running.

2) In WriteToFile.vi, I want to read each set of 12 payloads at a time from the FIFO, and I expect to be able to do so every 3 ms (i'm assuming everything goes smoothly, not very robust). I have the read operation in a for loop and a while loop. The while loop is supposed to stop when the elapsed time target, currently hard coded to 3 ms, is done (if I get no errors, no overflow, don't hit the stop button, which should be the ase). It doesn't have to be hard coded; I can connect it to the orange line entering the for loop instead... So I expect each while loop / each for loop iteration to take 3 ms as a result. Then, I control how many for loop iteration I want to get the desired recording time. Therefore, the number of for loop iterations should be = recording time in us divided by the 3000 us (3ms sampling period). That's how I'm using recording time; I multiply it by 1,000,000 to convert from seconds to microseconds, divide by frame+receive period (in us), divide again by 12 and that's the loop count. 

0 Kudos
Message 9 of 9
(5,144 Views)