Hi,
I am running out of memory and crashing the controller while running the program shown below. I am using the USBizi 100 module on a custom board. I am running two serial ports and three input interrupts. Are there any obvious problems with this program that jump out at anyone? I have a feeling it is related to my serial port DataReceived event handler, but have had trouble understanding some solutions in other posts. Should I be garbage collecting somewhere?
It seems sometimes that an interrupt causes the memory outage. Do these take up much memory when fired?
Thank you very much in advance,
Tom
using System;
using System.Threading;
using System.IO.Ports;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Hardware;
namespace IndustrialIO
{
public class Program
{
/// <summary>
/// Stores Emergency Trip
/// </summary>
static bool emergencyBit = false;
/// <summary>
/// Sets up COM1 on the FEZ mini as the PC communication port
/// </summary>
static SerialPort COM1 = new SerialPort("COM1", 9600);
/// <summary>
/// Stores I2C device
/// </summary>
static I2CDevice myI2C;
/// <summary>
/// Create PCF8574 I/O Expander configuration
/// </summary>
static I2CDevice.Configuration PCF8574 = new I2CDevice.Configuration(0x38, 100);
/// <summary>
/// Create ADS1115 A/D Converter configuration
/// </summary>
static I2CDevice.Configuration ADS1115 = new I2CDevice.Configuration(0x48, 400);
/// <summary>
/// Set up Input Ports
/// </summary>
public static InputPort LDR = new InputPort((Cpu.Pin)FEZ_Pin.Digital.LDR, false, Port.ResistorMode.PullUp);
public static InputPort DIN1 = new InputPort((Cpu.Pin)FEZ_Pin.Digital.An0, false, Port.ResistorMode.PullDown);
public static InputPort DIN2 = new InputPort((Cpu.Pin)FEZ_Pin.Digital.An1, false, Port.ResistorMode.PullDown);
public static InputPort DIN3 = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.An2, false, Port.ResistorMode.PullDown, Port.InterruptMode.InterruptEdgeHigh);
public static InputPort DIN4 = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.Di12, false, Port.ResistorMode.PullDown, Port.InterruptMode.InterruptEdgeHigh);
public static InputPort DIN5 = new InputPort((Cpu.Pin)FEZ_Pin.Digital.Di11, false, Port.ResistorMode.PullDown);
public static InputPort DIN6 = new InputPort((Cpu.Pin)FEZ_Pin.Digital.Di13, false, Port.ResistorMode.PullDown);
public static InputPort DIN7 = new InputPort((Cpu.Pin)FEZ_Pin.Digital.Di5, false, Port.ResistorMode.PullDown);
public static InputPort DIN8 = new InputPort((Cpu.Pin)FEZ_Pin.Digital.Di6, false, Port.ResistorMode.PullDown);
public static InputPort[] inputPorts = new InputPort[] {DIN1,DIN2,DIN3,DIN4,DIN5,DIN6,DIN7,DIN8};
/// <summary>
/// Set up output ports
/// </summary>
public static OutputPort DOUT1 = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di21, false);
public static OutputPort DOUT2 = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di20, false);
public static OutputPort DOUT3 = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di23, false);
public static OutputPort DOUT4 = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di22, false);
public static OutputPort DOUT5 = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di25, false);
public static OutputPort DOUT6 = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di24, false);
public static OutputPort DOUT7 = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di27, false);
public static OutputPort DOUT8 = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di26, false);
public static OutputPort LED = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, false);
public static OutputPort[] outputPorts = new OutputPort[] { DOUT1, DOUT2, DOUT3, DOUT4, DOUT5, DOUT6, DOUT7, DOUT8 };
/// <summary>
/// Sets up PWM ports
/// </summary>
public static PWM PWM1 = new PWM(PWM.Pin.PWM2);
public static PWM PWM2 = new PWM(PWM.Pin.PWM1);
/// <summary>
/// Create LCD
/// </summary>
public static AF10216A myLCD = new AF10216A("COM4");
/// <summary>
/// Set up dSpin items
/// </summary>
// Initialize flag and busy ports for all dSpin controllers
public static InputPort flagPort = new InputPort((Cpu.Pin)FEZ_Pin.Digital.Di50, false, Port.ResistorMode.Disabled);
public static InputPort busyPort = new InputPort((Cpu.Pin)FEZ_Pin.Digital.Di47, false, Port.ResistorMode.Disabled);
public static UInt32 dSPIN_rx_data = 0;
public static dSPIN_RegsStruct_TypeDef dSPIN_RegsStruct;
public static dSpin myL6472 = null;
/// <summary>
/// X Axis configuration
/// </summary>
public static SPI.Configuration xAxisConfig = new SPI.Configuration((Cpu.Pin)FEZ_Pin.Digital.Di49,
false, // Chip Select, active-low
1000, // 1000 (nanoseconds?) setup time
1000, // 1000 (nanoseconds?) hold time
true, // Clock low on idle
true, // Data valid on falling edge
5000, // 5Mhz Clock Rate
SPI.SPI_module.SPI2); //SPI device 2
/// <summary>
/// Y Axis configuration
/// </summary>
public static SPI.Configuration yAxisConfig = new SPI.Configuration((Cpu.Pin)FEZ_Pin.Digital.Di48,
false, // Chip Select, active-low
1000, // 1000 (nanoseconds?) setup time
1000, // 1000 (nanoseconds?) hold time
true, // Clock low on idle
true, // Data valid on falling edge
5000, // 5Mhz Clock Rate
SPI.SPI_module.SPI2); //SPI device 2
/// <summary>
/// R Axis configuration
/// </summary>
public static SPI.Configuration rAxisConfig = new SPI.Configuration((Cpu.Pin)FEZ_Pin.Digital.Di51,
false, // Chip Select, active-low
1000, // 1000 (nanoseconds?) setup time
1000, // 1000 (nanoseconds?) hold time
true, // Clock low on idle
true, // Data valid on falling edge
5000, // 5Mhz Clock Rate
SPI.SPI_module.SPI2); //SPI device 2
/// <summary>
/// Default method
/// </summary>
public static void Main()
{
// Initializes Motor Controllers
InitializeMotors();
// Write to LCD
myLCD.SendCommand(AF10216A.Commands.FormFeed);
Thread.Sleep(50);
myLCD.Print("600-0061-2");
Thread.Sleep(50);
myLCD.SendCommand(AF10216A.Commands.CR);
Thread.Sleep(50);
myLCD.Print("Optics Placement");
// Attach Event Handler to 'COM1'
COM1.DataReceived += new SerialDataReceivedEventHandler(COM1_DataReceived);
// Open Com port
COM1.Open();
// Attach events to Estop & LC Inputs
DIN3.OnInterrupt += new NativeEventHandler(DIN3_OnInterrupt);
DIN4.OnInterrupt += new NativeEventHandler(DIN4_OnInterrupt);
// Set outputs low
WriteDigitalOutputs(0);
//Turn on LED
LED.Write(true);
// Set PWM
PWM1.Set(100, 50);
PWM1.Set(100, 10);
while (true)
{
}
}
/// <summary>
/// Handes DIN4 Interrupt
/// </summary>
/// <param name="data1"></param>
/// <param name="data2"></param>
/// <param name="time"></param>
static void DIN4_OnInterrupt(uint data1, uint data2, DateTime time)
{
// Debounce
Thread.Sleep(50);
// Read Emergency Input
if (DIN4.Read())
{
emergencyBit = true;
}
}
/// <summary>
/// Handles DIN3 Interrupt
/// </summary>
/// <param name="data1"></param>
/// <param name="data2"></param>
/// <param name="time"></param>
static void DIN3_OnInterrupt(uint data1, uint data2, DateTime time)
{
// Debounce
Thread.Sleep(50);
// Read Emergency Input
if (DIN3.Read())
{
emergencyBit = true;
}
}
/// <summary>
/// Initializes Controller
/// </summary>
static void InitializeMotors()
{
// Create new controller
myL6472 = new dSpin(xAxisConfig, busyPort, flagPort);
// Program x registers
L6472Setup(myL6472);
// Get status and print
dSPIN_rx_data = myL6472.dSPIN_Get_Status();
// Set y axis
myL6472.port.Config = yAxisConfig;
// Program y registers
L6472Setup(myL6472);
// Get status and print
dSPIN_rx_data = myL6472.dSPIN_Get_Status();
// Set z axis
myL6472.port.Config = rAxisConfig;
// Program r registers
L6472Setup(myL6472);
// Get status and print
dSPIN_rx_data = myL6472.dSPIN_Get_Status();
}
/// <summary>
/// Handles Data Received by COM1
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
static void COM1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
// Wait for full string
Thread.Sleep(50);
// set write buffer
string bufferString = String.Empty;
byte[] bufferWrite = null;
// Set read buffer
byte[] buffer = new byte[COM1.BytesToRead];
COM1.Read(buffer, 0, COM1.BytesToRead);
char[] read = System.Text.Encoding.UTF8.GetChars(buffer);
string readString = new string(read);
string valueString = new string(new char[3] { read[3], read[4], read[5] });
// determine command value
int value = Convert.ToInt16(valueString);
// determine what action to take...
// Check for proper start character
if (read[0] == '$')
{
// Check for analog
if (read[1] == 'A' || read[1] == 'a')
{
// Check for input
if (read[2] == 'I' || read[2] == 'i')
{
// Read and print input
bufferString = ReadADC(Convert.ToInt16(read[3].ToString()), Convert.ToInt16(read[5].ToString()));
}
}
// Check for digital
else if (read[1] == 'D' || read[1] == 'd')
{
// Check for input
if (read[2] == 'I' || read[2] == 'i')
{
// Read inputs
bufferString = ReadDigitalInputs();
}
// Check for output
else if (read[2] == 'O' || read[2] == 'o')
{
// Write outputs
bufferString = WriteDigitalOutputs(value);
}
}
// Check for stepper motor control
else if (read[1] == 'E' || read[1] == 'e')
{
// Check for emergency read
if (read[2] == 'R' || read[2] == 'r')
{
bufferString = emergencyBit.ToString();
}
// Check for emergency write
else if (read[2] == 'W' || read[2] == 'w')
{
if (value == 0)
{
emergencyBit = false;
bufferString = emergencyBit.ToString();
}
else
{
emergencyBit = true;
emergencyBit.ToString();
}
}
}
// Check for stepper motor control
else if (read[1] == 'S' || read[1] == 's')
{
// Check for move command
if (read[2] == 'M' || read[2] == 'm')
{
// Determine # of steps
string stepString = new string(new char[6] { read[6], read[7], read[8], read[9], read[10], read[11] });
// determine command value
int steps = Convert.ToInt16(stepString);
// Determine Axis #
int axis = Convert.ToInt16(read[5].ToString());
// Determine Direction
if (read[3] == '1')
{
steps *= -1;
}
// Move Steps
bufferString = StepperMove(axis, steps);
}
// Check For 'busy flag'
if (read[2] == 'B' || read[2] == 'b')
{
bool isBusy = busyPort.Read();
// Write Flag Value
bufferString = isBusy.ToString();
}
// Check For 'error flag'
if (read[2] == 'F' || read[2] == 'f')
{
bool isError = flagPort.Read();
// Write Flag Value
bufferString = isError.ToString();
}
}
// Create buffer string
bufferWrite = System.Text.Encoding.UTF8.GetBytes(bufferString + "\n");
// Return values
COM1.Write(bufferWrite, 0, bufferWrite.Length);
}
}
catch (Exception)
{
return;
}
}
/// <summary>
/// Reads the specified ADC channel and returns value
/// </summary>
/// <param name="inputNumber"></param>
/// <returns></returns>
public static string ReadADC(int resolution, int inputNumber)
{
try
{
// Dispose of old I2C
if (myI2C != null)
{
myI2C.Dispose();
}
// Set ADS1115 as I2C device
myI2C = new I2CDevice(ADS1115);
// Create transaction(s)
I2CDevice.I2CTransaction[] xAction = new I2CDevice.I2CTransaction[1];
// Build transaction bytes
// Config byte 1
byte config1 = (byte)(192 + (16 * inputNumber) + (2 * resolution) + 1);
// Config byte 2
byte config2 = 131;
// create write buffer (we need three bytes)
byte[] registerADS1115 = new byte[3] { 1, config1, config2 };
// Create write transaction
xAction[0] = I2CDevice.CreateWriteTransaction(registerADS1115);
// excecute ADS1115 setup
myI2C.Execute(xAction, 1000);
// Wait for conversion
Thread.Sleep(15);
// Set to conversion register
registerADS1115 = new byte[1] { 0 };
xAction[0] = I2CDevice.CreateWriteTransaction(registerADS1115);
// Execute set to conversion
myI2C.Execute(xAction, 1000);
// create read buffer
byte[] readADS1115 = new byte[2];
// Read ADC values
xAction[0] = I2CDevice.CreateReadTransaction(readADS1115);
myI2C.Execute(xAction, 1000);
// return values
return (readADS1115[0] * 256 + readADS1115[1]).ToString();
}
catch (Exception exp)
{
return exp.Message;
}
}
/// <summary>
/// Writes proper digital outputs
/// </summary>
/// <param name="inputs"></param>
/// <returns></returns>
public static string WriteDigitalOutputs(int outputs)
{
try
{
int registerValue = 0;
int[] intArray = new int[8];
bool[] boolArray = new bool[8];
// Check to see which command is given
// Write outputs
if (outputs <= 255)
{
// convert to binary array
int value = outputs;
for (int i = 0; i < 8; i++)
{
intArray[7 - i] = value >> (7 - i);
value -= intArray[7 - i] * (1 << (7 - i));
//populate bool array
if (intArray[7-i] == 0)
{
boolArray[7-i] = false;
}
else
{
boolArray[7-i] = true;
}
}
// change output states to match
for (int i = 0; i < boolArray.Length; i++)
{
outputPorts[i].Write(boolArray[i]);
}
// Send back register value
registerValue = outputs;
}
// Read outputs
else if (outputs == 999)
{
// convert output values into an integer
foreach (int i in intArray)
{
registerValue += intArray[i] << i;
}
}
// Return register value
return registerValue.ToString();
}
catch (Exception exp)
{
return exp.Message;
}
}
/// <summary>
/// Returns digital input values
/// </summary>
/// <param name="inputs"></param>
/// <returns></returns>
public static string ReadDigitalInputs()
{
try
{
// Sets up inputs boolean
bool[] inputs = new bool[8];
// read inputs
inputs[0] = DIN1.Read();
inputs[1] = DIN2.Read();
inputs[2] = DIN3.Read();
inputs[3] = DIN4.Read();
inputs[4] = DIN5.Read();
inputs[5] = DIN6.Read();
inputs[6] = DIN7.Read();
inputs[7] = DIN8.Read();
int input = 0;
int total = 0;
// Concatenate inputs into an integer 0-255
for (int i = 0; i < inputs.Length; i++)
{
// Check boolean, and convert to binary
if (inputs[i])
{
input = 1;
}
else
{
input = 0;
}
total += input * (int)System.Math.Pow(2, i);
}
// Return register value
return total.ToString();
}
catch (Exception exp)
{
return exp.Message;
}
}
/// <summary>
/// Sets up dSpin controller
/// </summary>
/// <param name="myL6472"></param>
public static void L6472Setup(dSpin myL6472)
{
// Reset device
myL6472.dSPIN_Reset_Device();
/* Acceleration rate settings to 466 steps/s2, range 14.55 to 59590 steps/s2 */
dSPIN_RegsStruct.ACC = (UInt16)((UInt32)(((10) * 67.108864) + 0.5)); //AccDec_Steps_to_Par
/* Deceleration rate settings to 466 steps/s2, range 14.55 to 59590 steps/s2 */
dSPIN_RegsStruct.DEC = (UInt16)((UInt32)(((10) * 67.108864) + 0.5)); //AccDec_Steps_to_Par
/* Maximum speed settings to 488 steps/s, range 15.25 to 15610 steps/s */
dSPIN_RegsStruct.MAX_SPEED = ((UInt16)(((10000) * 0.065536) + 0.5)); // MaxSpd_Steps_to_Par(488)
/* Minimum speed settings to 0 steps/s, range 0 to 976.3 steps/s */
dSPIN_RegsStruct.MIN_SPEED = ((UInt16)(((0) * 4.194304) + 0.5)); // MinSpd_Steps_to_Par(0)
/* Full step speed settings 252 steps/s, range 7.63 to 15625 steps/s */
dSPIN_RegsStruct.FS_SPD = ((UInt16)((252) * 0.065536)); // FSSpd_Steps_to_Par(252)
/* Hold duty cycle (torque) settings to 10%, range 0 to 99.6% */
dSPIN_RegsStruct.TVAL_HOLD = (byte)Macro.TorqueToPar(500); // Kval_Perc_to_Par(10)
/* Run duty cycle (torque) settings to 10%, range 0 to 99.6% */
dSPIN_RegsStruct.TVAL_RUN = (byte)Macro.TorqueToPar(1500); // Kval_Perc_to_Par(10)
/* Acceleration duty cycle (torque) settings to 10%, range 0 to 99.6% */
dSPIN_RegsStruct.TVAL_ACC = (byte)Macro.TorqueToPar(1500); // Kval_Perc_to_Par(10)
/* Deceleration duty cycle (torque) settings to 10%, range 0 to 99.6% */
dSPIN_RegsStruct.TVAL_DEC = (byte)Macro.TorqueToPar(1500); // Kval_Perc_to_Par(10)
/* Overcurrent threshold settings to 2625mA */
dSPIN_RegsStruct.OCD_TH = (byte)dSPIN_OCD_TH_TypeDef.dSPIN_OCD_TH_2625mA;
/* Step mode settings to 16 microsteps */
dSPIN_RegsStruct.STEP_MODE = (byte)dSPIN_STEP_SEL_TypeDef.dSPIN_STEP_SEL_1_16;
/* Alarm settings - all alarms enabled */
dSPIN_RegsStruct.ALARM_EN = (byte)(dSPIN_ALARM_EN_TypeDef.dSPIN_ALARM_EN_OVERCURRENT | dSPIN_ALARM_EN_TypeDef.dSPIN_ALARM_EN_THERMAL_SHUTDOWN
| dSPIN_ALARM_EN_TypeDef.dSPIN_ALARM_EN_THERMAL_WARNING | dSPIN_ALARM_EN_TypeDef.dSPIN_ALARM_EN_UNDER_VOLTAGE | dSPIN_ALARM_EN_TypeDef.dSPIN_ALARM_EN_SW_TURN_ON | dSPIN_ALARM_EN_TypeDef.dSPIN_ALARM_EN_WRONG_NPERF_CMD);
/* Internal oscillator, 2MHz OSCOUT clock, supply voltage compensation disabled, *
* overcurrent shutdown enabled, slew-rate = 290 V/us, PWM frequency = 15.6kHz */
dSPIN_RegsStruct.CONFIG = ((UInt16)dSPIN_CONFIG_OSC_MGMT_TypeDef.dSPIN_CONFIG_INT_16MHZ_OSCOUT_2MHZ) |
((UInt16)dSPIN_CONFIG_SW_MODE_TypeDef.dSPIN_CONFIG_SW_HARD_STOP) |
((UInt16)dSPIN_CONFIG_EN_VSCOMP_TypeDef.dSPIN_CONFIG_VS_COMP_DISABLE) |
((UInt16)dSPIN_CONFIG_OC_SD_TypeDef.dSPIN_CONFIG_OC_SD_ENABLE) |
((UInt16)dSPIN_CONFIG_POW_SR_TypeDef.dSPIN_CONFIG_SR_290V_us) |
((UInt16)dSPIN_CONFIG_F_PWM_INT_TypeDef.dSPIN_CONFIG_PWM_DIV_2) |
((UInt16)dSPIN_CONFIG_F_PWM_DEC_TypeDef.dSPIN_CONFIG_PWM_MUL_1);
/* Program all dSPIN registers */
myL6472.dSPIN_Registers_Set(ref dSPIN_RegsStruct);
}
/// <summary>
/// Moves stepper motor the required number of steps
/// </summary>
/// <param name="axis"></param>
/// <param name="steps"></param>
/// <returns></returns>
public static string StepperMove(int axis, int steps)
{
// Select correct axis
if (axis == 1)
{
myL6472.port.Config = xAxisConfig;
}
else if (axis == 2)
{
myL6472.port.Config = yAxisConfig;
}
else if (axis == 3)
{
myL6472.port.Config = rAxisConfig;
}
else
{
return "Incorrect Axis Specified";
}
// Determine Direction
dSPIN_Direction_TypeDef dir = dSPIN_Direction_TypeDef.FWD;
// If steps are negative, reverse
if (steps < 0)
{
dir = dSPIN_Direction_TypeDef.REV;
}
// Get status and print
dSPIN_rx_data = myL6472.dSPIN_Get_Status();
Debug.Print(dSPIN_rx_data.ToString());
Thread.Sleep(10);
// Move motor forward
myL6472.dSPIN_Move(dir, (uint)System.Math.Abs(steps));
Thread.Sleep(10);
//Wait untill not busy - busy pin test
while (myL6472.dSPIN_Busy_HW() == 0) ;
return "Move Complete";
}
}
}