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
Is there something you were trying to do that may have caused this issue to occur?
Just a few things to consider:
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.
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!
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.
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?
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.
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.
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 = 600000local 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
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)
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.
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?
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.
To enable a script to be loaded when it powers up write a "1" to the LUA_RUN_DEFAULT register.
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