Lua crashing | LabJack
 

Lua crashing

14 posts / 0 new
Last post
bmoorman
bmoorman's picture
Lua crashing

Hello,

My Lua script needs to output 10 pulses of various length (50ms to 10sec) consecutively to a LJTick-DAC. It reads the settings from USER_RAM registers. If it reads 1 from a certain USER_RAM register (RUN) it starts the sequence of pulses.

I have this programmed using multiple timers (CheckInterval/IntervalConfig) for reading registers and timing of the pulses. At first it was working ok but now I get crash and the T7 resets (USB connection resets) when I set RUN. It doesn't give me indication where it crashes but I have a feeling it's becasue writing and reading into same register?

The script is about 600 lines in the while loop. Is that about the limit? Or how can I debug this amout of Lua code?

Best regards

LabJack Support
labjack support's picture
At first it was working ok

At first it was working ok but now I get crash and the T7 resets (USB connection resets) when I set RUN.

Is there something you were trying to do that may have caused this issue to occur?

Just a few things to consider:

  1. Are you manually loading and starting a Lua Script onto your device?  If so, are you following the procedure we outline in the Lua Scripting section of the T-Series datasheet Load Lua Script Manually to Device?
  2. Did you try to enable the script to start up when the device starts?  If so, make sure you are saving the script to flash before enabling it Running a Script when the device powers up.

The script is about 600 lines in the while loop. Is that about the limit? Or how can I debug this amout of Lua code?

A 600 line script is longer than most scripts that typically fit onto a T-Series device however we mention the line limitation in the device's datasheet as it is a simple rule-of-thumb to keep in mind.  Please remember that your script is running on a microprocessor with limited RAM so if you are dynamically filling up an array (table in Lua terms), this may also cause run-time issues.

As for debugging your script, if possible, split it up and test your code in smaller pieces.  Once all of those smaller pieces are working, bring them together.  If necessary, you'll need to add print statements.

bmoorman
bmoorman's picture
Thanks for your comments. It

Thanks for your comments. It seems to work now after I radically reduced the lines of code and restructured according your tips.

I really have to do my best to get the final program fit into the T7!

LabJack Support
labjack support's picture
If your script is adding

If your script is adding information to or removing information from arrays it may be worth while reading over Lua's Garbage Collection documentation and forcing regular garbage collection cycles to take place.  The collectgarbage("count") function can be used to check and see how much memory is currently in use by the currently executing Lua Script.

bmoorman
bmoorman's picture
I have done all this and

I have done all this and still having huge problem.

I have the script fully working. But when I power cycle the device (just unplug and plug USB) then the exact same script crashes at a certain point (resetting the device).

To get the script working again in above situation, I alter the script slightly and put in an error in the script (e.g. I put in a call to non existing function) Upon running this altered script I get an debug error in the console log. Then I change the script to the original one and run it. It then works again without crashing.

I am now at the point of giving up on this lua scripting and rewrite the code in a laptop program. However this will set me back another day. The timing of the output signal should be quite accurate so on a microcontroller this is better then on windows.

Any more tips?

LabJack Support
labjack support's picture
Are you configuring the

Are you configuring the device at all through Kipling before running your script?  It might be worth while trying to save the device's power-up defaults before restarting your device.

LabJack Support
labjack support's picture
When you're trying to save a

When you're trying to save a script that needs to be powered on by default make sure you:

1. Run the script on your device.
2. While the script is running, press the "save to flash" button.
3. Then make sure the device is configured to run a script at start-up.  

Explicitly following steps 1 and then 2 is important as the "save to flash" button instructs the device to save the script currently running in RAM to flash.

bmoorman
bmoorman's picture
I have done this several

I have done this several times. I noticed between step 1 and 2 the script stops. So saving to flash stops the script.

But as I said the script runs without problems when I use Kipling to alter the code (as per previous post) and then run it with start button. It runs fine then until I re-power the device.

The script outputs to LJTick-DAC (3 outputs). It uses FIO6 as door contact switch (needs to be closed to run) and FIO5 to connect a start button. Maybe it is possible to try this? The commented out debug function is there to make the script work again after it stops working (when reset device)

here is the script:

local MAX_PULSE_DURATION = 600000
local MIN_PULSE_DURATION = 50
local MAX_STEPS = 10 local checkInterval=LJ.CheckInterval
local setInterval=LJ.IntervalConfig
local mbRead=MB.R   
local mbWrite=MB.W dac1Dimming = 0
dac2Dimming = 0
dac3Dimming = 0 power = {}
for i=1, MAX_STEPS do
  power[i] = 0
end
duration = {}
for i=1, MAX_STEPS do
  duration[i] = 0
end setInterval(0, 200) setInterval(4, 3000) enable = 0
run = 0
startRun = 0
step = 0
start = 1
doorCheck = 0
buttonReleased = 0
LJ.setLuaThrottle(200)
collectgarbage()
while true do
  if checkInterval(0) then
    -- read DIO FIO5
    value = mbRead(2005, 0)
    if start == 1 and run == 0 then
      print("Check door")
      start = 0
      doorCheck = 0
      enable = 0
      setInterval(1, 0)
    elseif start == 0 and value == 1 and doorCheck == 0 then
      print("Door opened")
      doorCheck = 1
      enable = 0
      setInterval(1, 0)
      run = 0
    elseif value == 0 and enable == 0 and doorCheck == 1  then
      print("Door closed, now enabled")
      enable = 1
      doorCheck = 0
      setInterval(1, 350)
      collectgarbage()
    elseif value == 1 and enable == 1 then
      print("Door opened")
      enable = 0
      run = 0
      doorCheck = 0
      setInterval(1, 0)
    end
  end
 
  if enable == 1 and checkInterval(1) then
    -- read DIO FIO6
    val = mbRead(2006, 0)
    if val == 0 and run == 0 then
      buttonReleased = 0
      run = 1  -- (re)start sequence
      print("run set to 1")
      if true then
      -- read dimming values
      dac1Dimming = mbRead(46102, 1)
      dac2Dimming = mbRead(46104, 1)
      dac3Dimming = mbRead(46106, 1)
      -- read power and duration values
      for i=1, MAX_STEPS do
        power[i] = mbRead(46108 + 4*(i-1), 1)
        duration[i] = mbRead(46110 + 4*(i-1), 1)
      end
      print("Pulse sequence steps:")
      print(string.format("Dimming [%d][%d][%d]", math.floor(dac1Dimming), math.floor(dac2Dimming), math.floor(dac3Dimming)))
      for i=1, MAX_STEPS do
        print(string.format("%d P[%d%%] T[%dms]", i,  math.floor(power[i]), math.floor(duration[i])))
      end
      end
      step = 0
      --debug()
    elseif val == 0 and run == 1 and buttonReleased == 1 then
      print("Run stopped")
      run = 0
      start = 1
      buttonReleased = 0
    elseif val == 1 and run == 1 then
      buttonReleased = 1
    end
  end   if enable == 1 and run == 1 then
    if checkInterval(3) then
      startRun = 0
      repeat
        step = step + 1
      until step == MAX_STEPS or duration[step] ~= 0
      if step == MAX_STEPS then
        run = 0
      end
      if run == 1 then
        print(string.format("Step:%d P:%d%% T:%dms", step, power[step], duration[step]))
        -- set new output voltage on 3 dac's
        voltage = power[step] / 10 * dac1Dimming / 100
        mbWrite(30000, 3, voltage)
        print(string.format(" DAC1: %fV", voltage))
        voltage = power[step] / 10 * dac2Dimming / 100
        mbWrite(30002, 3, voltage)
        print(string.format(" DAC2: %fV", voltage))
        voltage = power[step] / 10 * dac3Dimming / 100
        mbWrite(30004, 3, voltage)
        print(string.format(" DAC3: %fV", voltage))
        -- set timer interval
        setInterval(3, duration[step]) -- set timer for duration
      end
    end
    if step == 0 and startRun == 0 then
      startRun = 1
      print("Run")
      setInterval(3, 1000) -- start delay of 1 sec
    end
    if run == 0 then
      print("Stop")
    end
  elseif step ~= 0 then
    -- set output 0v
    print("Set output to zero!")
    voltage = 0
    mbWrite(30000, 3, voltage)
    print(string.format(" DAC1: %dV", voltage))
    mbWrite(30002, 3, voltage)
    print(string.format(" DAC2: %dV", voltage))
    mbWrite(30004, 3, voltage)
    print(string.format(" DAC3: %dV", voltage))
    run = 0
    step = 0
    start = 1
    doorCheck = 0
  end
  if run == 0 and checkInterval(4) then
    print(string.format("heart beat: enable(%d) run(%d) mem(%d)", enable, run, collectgarbage("count")))
  end
end --function debug ()
--end
LabJack Support
labjack support's picture
I don't know entirely what

I don't know entirely what your script is attempting to control or do however I was able to run it on a device and get it to properly configure the device to run it when it gets powered on with out making any changes.  I did this with nothing connected to the device and got a consistent heart beat: enable(0) run(0) mem(28) message.  Do you get the same with no hardware connected to your device?  Perhaps your connected hardware is putting the script/device into a state that is causing it to reboot?

I did these exact steps:
0. Copy script into Kipling's editor pane.
1. Run the script.
2. Press the "save to flash" button. (This will cause the script to stop running).
3. Ensure the device is configured to start your script.
4. You can start the script again if you want.
5. Press the reboot device button to tell the device to reboot itself or unplug/plug it back in.
6. The device then gets re-connected to Kipling.
7. The console-output starts updating again:

Lua 5.1.4  Copyright (C) 1994-2011 Lua.org, PUC-Rio
Check door
Door opened
heart beat: enable(0) run(0) mem(28)

 

bmoorman
bmoorman's picture
Yes, this works for me like

Yes, this works for me like this also. However the crash happens when you operate the 2 inputs.

The door switch needs to be closed. So FIO6 needs to be connected to GND. Then FIO5 needs to be connected to GND momentarily. This is the Run signal. The script outputs a sequence of pulse of a certain duration. So for example 1000ms at 50%, 5000ms at 80%, 1000ms at 0%, 50ms at 100%. The extra hardware is just the LJTick-DAC but not necessary to see the problem. The only thing needed is a couple of wires attached to FIO5 and 6.  It is also possible to change these to fio2/3 but these are used by DAC's. Hopefully you can see the same problem. Many thanks for looking into it.

LabJack Support
labjack support's picture
I have the script fully

I have the script fully working. But when I power cycle the device (just unplug and plug USB) then the exact same script crashes at a certain point (resetting the device).

To get the script working again in above situation, I alter the script slightly and put in an error in the script (e.g. I put in a call to non existing function) Upon running this altered script I get an debug error in the console log. Then I change the script to the original one and run it. It then works again without crashing.

Given that your script runs both when Kipling initially loads it and when your device reboots it sounds like the device is likely working correctly.

Is there a particular set of lines or case in your code that are causing the device to error and the reboot?  If not, there may be an issue with your code and handling all of your if, elseif, and else statements.

Perhaps you haven't handled all of the cases that you are trying to handle?

bmoorman
bmoorman's picture
Thanks for that comment. I

Thanks for that comment. I went over the script again and after first simplefying it and leaving things out I got it not to crash anymore in both situations. I have now re-introduced the other bits and it does not crash anymore!

Really happy about that, although I don't know what was the cause. It might be something with the multiple timers I use or as you said code handling.

One more question is: I have the lua script loaded from C# but I can't find how to set it to run from T7 powerup. Is there a register I can write to to enable this?

Thanks a lot for your help.

LabJack Support
labjack support's picture
To enable a script to be

To enable a script to be loaded when it powers up write a "1" to the LUA_RUN_DEFAULT register.

LabJack Support
labjack support's picture
Thanks for that comment. I

Thanks for that comment. I went over the script again and after first simplefying it and leaving things out I got it not to crash anymore in both situations. I have now re-introduced the other bits and it does not crash anymore!

We're glad that your script is working again but wanted to follow up and mention that if this issue starts happening again please let us know.  If you have any details about what bits you changed to make your script work feel free to share for others that browse our forums.

We did some additional testing of our interval timer functions and found that in T7 firmware 1.028 setting timer values smaller than 0.0001 using the "LJ.IntervalConfig" function can cause the device to re-set when the "LJ.CheckInterval" function is called.

If you run into this issue again can you add the following code to your script and see if "bit 4" is set to 1.  The code snippit reads a device register that stores information about why the device reset.  Bit 4 being 1 indicates that a watch dog time-out event occured.

local bootVal = MB.R(60014, 1)
print(string.format('boot val: 0x%x', bootVal))
for i=0, 9 do
  print(string.format('bit %d: %d',i,bit.band(bit.rshift(bootVal,i),1)))
end