dcsimg
Results 1 to 21 of 21
  1. #1

    Thread Starter
    Lively Member
    Join Date
    Nov 2013
    Posts
    83

    Resolved [RESOLVED] Slowdown on COM port write after 12k characters

    My program communicates with an arduino over a serial port. It sends one byte at a time every 50ms. The arduino can read them much faster than that speed. After about 12,200 bytes are sent there is a dramatic slow down in the transmission rate to about 1 byte every second or so. The bottle neck is the com port write. I have been chasing this for a couple days and now believe it has something to do with the serial port write. If I stop the program and then restart it, the speed is fine until another 12,200 bytes are sent. That figure is + or - about 100 bytes, I couldn't measure it any closer than that.

    Is there a limit to how many single bytes can be sent after a single com port open? Is there a requirement on the receiving end to do something other than simply receive the byte? I just don't understand why it slows down. The open routine is called only once and the write routine is called at 50ms intervals.

    There are no error messages, the only problem is the slowdown.

    Here is the com port configuration and the serialport.write routine.

    Code:
     Private Sub Start_Com_Port()
            Try
                SERIALPORT.Close()
            Catch ex As Exception
                MessageBox.Show(ex.Message)
            End Try
            If COMPORT = "" Then
                For Each sp As String In My.Computer.Ports.SerialPortNames
                    fCom_Port.Items.Add(sp)
                    If fCom_Port.Items.Count > 0 Then
                        fCom_Port.SelectedIndex = 0
                    End If
                Next
            End If
            fCom_Port.Items.Add(COMPORT)
            fCom_Port.SelectedIndex = 0
    
            With SERIALPORT
                Try
                    SERIALPORT.PortName = fCom_Port.SelectedItem
                Catch ex As Exception
                    MessageBox.Show(ex.Message)
                End Try
                .BaudRate = 115200
                .DataBits = 8
                .Parity = Parity.None
                .StopBits = StopBits.One
                .Handshake = Handshake.None
            End With
            Try
                SERIALPORT.Open()
            Catch ex As Exception
                MsgBox("Port " & SERIALPORT.PortName & vbCrLf & ex.Message)
            End Try
        End Sub
    
     Private count As Long = 0
    
        Private Sub writeData(dat As Byte)
            count += 1
            fTotal_Coil_Steps.Text = count
            Try
                SERIALPORT.Write(dat)
            Catch ex As Exception
                MessageBox.Show("Serial Port Write Error" & ex.Message)
            End Try
        End Sub

  2. #2
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    4,405

    Re: Slowdown on COM port write after 12k characters

    I don't see the code that calls writeData.
    You may have recursive code there, we can't tell from here.

  3. #3

    Thread Starter
    Lively Member
    Join Date
    Nov 2013
    Posts
    83

    Re: Slowdown on COM port write after 12k characters

    Here is the whole thing:
    Code:
    Imports System.IO.Ports
    
    Public Class Form1
        Private WithEvents T1 As New FastTimer      ' High accuracy timer class
    
        ' program variables
        Private MYCHAR As String                    ' Buffer for the received serial character
        Private PNT As Point                        ' Point for the location of the coil drawing
        Private SETUPFLAG As Boolean = True         ' Flag to prevent execution of events until setup is done
        Private FORWARD As Boolean = True           ' Direction flag for the slide
        Private JFORWARD As Boolean                 ' The jog direction
        Private MYINDEX As Integer                  ' Index to the wire information table
    
        ' User inputs
        Private COREOD As Single                    ' Diameter of the finished coil
        Private COREID As Single                    ' Diameter of the coil form ID
        Private CORELENGTH As Single                ' Length of the coil form
        Private WIREGAUGE As Single                 ' Gauge of the wire
        Private TOTALWINDINGS As Single             ' Total number of winding in the coil
        Private COMPORT As String                   ' Text of the Comm Port number ie. "COM1"
        Private SERIALPORT As New SerialPort        ' The io serial port
        Private PORTADDRESS As Integer              ' Serial port address
        Private STEPANGLE As Single                 ' Angular rotation of one motor step
    
        ' Calculated values
        Private WIREDIAMETER As Single              ' Diameter of the wire from the wire table
        Private RESISTANCEPER1000 As Single         ' Resistance per 1000 feet of wire from the wire table
        Private MAXAMPS As Single                   ' The maximum coil amps from the wire table
        Private INCHPERSTEP As Single               ' Distance the slide travels in one step
        Private LEADSCREW_TPI As Single             ' The threads per inch for both lead screws
        Private CURRENTCOILDIAMETER As Single       ' The current diameter of the coil for drawing it
        Private TOTALSTEPSINCOIL As Long         ' Total number of steps in the coil
        Private TOTALLAYERSINCOIL As Single         ' Total number of layers in the coil
        Private TOTALFEETOFWIREINCOIL As Single     ' Total feet of wire for the coil
    
        ' Step, Rev, Coil and Layer counters
        Private WINDSTEPCOUNTER As Long          ' Winder step counter
        Private WINDERSTEPSPERREV As Integer        ' Winder steps for 1 turn
        Private WINDSCOUNTED As Integer             ' Number of winds finished
    
        Private SLIDESTEPCOUNTER As Integer         ' Slide step counter (position of the slide)
        Private SLIDESTEPSPERLAYER As Integer       ' Slide steps for 1 layer
        Private LAYERSCOUNTED As Integer            ' Number of layers finished
    
        Private WINDSSPERLAYER As Single            ' Number of winds per layer
        Private SLIDESTEPRATIO As Integer           ' Number of winder steps per slide step
        Private CURRENTCOREDIAMETER As Single       ' The current diameter of the coil
    
        Private Sub setup()
            Read_Registry_Data()
            Start_Com_Port()
            Initialise_Buttons()
            Initialize_Constants()
            Process_Screen_Data()
            PanelCore.Show()
    
            TOTALSTEPSINCOIL = 0    ' Total number of steps in the coil
            SLIDESTEPSPERLAYER = WIREDIAMETER / INCHPERSTEP * WINDSSPERLAYER
    
            If fWhole_Layer.Checked Then
                TOTALWINDINGS = (TOTALLAYERSINCOIL - 1) * WINDSSPERLAYER
                fTotal_Windings.Text = TOTALWINDINGS
            End If
    
            SETUPFLAG = False
        End Sub
    
        ' ********************************
        ' ignore 48                   // 0
        ' set_ratio 49                // 1
        ' winder_omly 50              // 2
        ' slide_forward 51            // 3
        ' slide_reverse 52            // 4
        ' slide_forward_winder 53     // 5
        ' slide_reverse_winder 54     // 6
        ' stop_motors 55              // 7
        ' ignore all others           //
        ' ********************************
    
        Private Sub Process_Screen_Data()
            COREID = fCore_ID.Text                      ' Diameter of the coil form core
            CORELENGTH = fCore_Length.Text              ' Length of the coil form core
            WIREGAUGE = fWire_Gauge.Text                ' The wire gauge
            TOTALWINDINGS = fTotal_Windings.Text        ' Total number of windings
    
            WINDSTEPCOUNTER = 0                         ' Winder step counter
            WINDSCOUNTED = 0                            ' Number of winds finished
            fWind_Count.Text = WINDSCOUNTED
            SLIDESTEPCOUNTER = 0                        ' Slide step counter (position of the slide)
            fSlide_Steps.Text = SLIDESTEPCOUNTER
            LAYERSCOUNTED = 0                           ' Number of layers finished
            fLayer_Count.Text = LAYERSCOUNTED
    
            If fWhole_Layer.Checked Then
                TOTALWINDINGS = (TOTALLAYERSINCOIL - 1) * WINDSSPERLAYER
                fTotal_Windings.Text = TOTALWINDINGS
            End If
    
            Dim WIRE_DATA As Object
            ' WIRE DATA TAKEN FROM http://www.powerstream.com/Wire_Size.htm
            '    DIA   OHM/kFT AMPS     AWG
            WIRE_DATA = {
                0.032, 10.15, 11,       '20
                0.0285, 12.8, 9,        '21
                0.0253, 16.14, 7,       '22
                0.0226, 20.36, 4.7,     '23
                0.0201, 25.67, 3.5,     '24
                0.0179, 32.37, 2.7,     '25
                0.0159, 40.81, 2.2,     '26
                0.0142, 51.47, 1.7,     '27
                0.0126, 64.9, 1.4,      '28
                0.0113, 81.83, 1.2,     '29
                0.01, 103.2, 0.86,      '30
                0.0089, 130.1, 0.7,     '31
                0.008, 164.1, 0.53,     '32
                0.0071, 206.9, 0.43,    '33
                0.0063, 260.9, 0.33,    '34
                0.0056, 329.0, 0.27,    '35
                0.005, 414.8, 0.21,     '36
                0.0045, 523.1, 0.17,    '37
                0.004, 659.6, 0.13,     '38
                0.0035, 831.8, 0.11,    '39
                0.0031, 1049, 0.09      '40
            }
    
            WIREGAUGE = CSng(Me.fWire_Gauge.Text)
            If WIREGAUGE < 20.0 Then
                WIREGAUGE = 20
                fWire_Gauge.Text = 20
            End If
            If WIREGAUGE > 40.0 Then
                WIREGAUGE = 40
                fWire_Gauge.Text = 40
            End If
    
            ' Calculate the array index
            MYINDEX = (WIREGAUGE - 20) * 3 + 1
            ' Calculate the wire diameter fron the gauge
            WIREDIAMETER = WIRE_DATA(MYINDEX - 1)
            RESISTANCEPER1000 = WIRE_DATA(MYINDEX)
            MAXAMPS = WIRE_DATA(MYINDEX + 1)
            MYINDEX = (WIREGAUGE - 20) * 3 + 1
            ' Calculate the wire diameter fron the gauge
            WIREDIAMETER = WIRE_DATA(MYINDEX - 1)
            RESISTANCEPER1000 = WIRE_DATA(MYINDEX)
            MAXAMPS = WIRE_DATA(MYINDEX + 1)
            WINDSSPERLAYER = CLng(Convert.ToSingle(fCore_Length.Text) / (WIREDIAMETER))
            TOTALLAYERSINCOIL = TOTALWINDINGS / WINDSSPERLAYER + 1
            SLIDESTEPSPERLAYER = WIREDIAMETER / INCHPERSTEP
        End Sub
    
        Private Sub Initialize_Constants()
            STEPANGLE = 1.8                                             ' Each motor step rotates the shaft this many degrees
            LEADSCREW_TPI = 8                                           ' 8 Thread Per Inch
            WINDERSTEPSPERREV = 360 / STEPANGLE                       ' Number of steps for each turn of the cioil
            INCHPERSTEP = 1.0 / LEADSCREW_TPI / WINDERSTEPSPERREV     ' Distance the slide moves for each step
        End Sub
    
        Private Sub Control_The_Motors()                ' turn the winder and carriage 
            writeData("2")                                ' 2 = winder step
            WINDSTEPCOUNTER += 1
    
            ' Have we finished a wind?
            If WINDSTEPCOUNTER Mod WINDERSTEPSPERREV = 0 Then
                WINDSCOUNTED += 1
                fWind_Count.Text = WINDSCOUNTED        ' Update the screen
            End If
    
            'Do we need to step the slide?
            If WINDSTEPCOUNTER Mod SLIDESTEPRATIO = 0 Then
                If FORWARD Then
                    writeData("3")                        ' 3 = step the slide forward
                    SLIDESTEPCOUNTER += 1
                Else
                    writeData("4")                        ' 4 = step the slide backward
                    SLIDESTEPCOUNTER -= 1
                End If
                fSlide_Steps.Text = SLIDESTEPCOUNTER          ' Update the screen
    
                ' reverse the slide direction if we are at either end of travel
                If SLIDESTEPCOUNTER Mod SLIDESTEPSPERLAYER = 0 Then
                    FORWARD = Not (FORWARD)                     ' reverse it
                    CURRENTCOILDIAMETER += (WIREDIAMETER * 2)   ' increase the current coil diameter
                    DrawCoil()                                  ' Draw the coil 
                    LAYERSCOUNTED += 1
                    fLayer_Count.Text = LAYERSCOUNTED
                End If
            End If
    
    
            ' have we finsihed the coil?
            If WINDSTEPCOUNTER = WINDERSTEPSPERREV * TOTALWINDINGS Then
                writeData("7")                            ' turn off the motors
                T1.Stop()                               ' stop the run loop
            End If
        End Sub
    
        Private Sub Read_Registry_Data()
            ' Read the registry data
            COREID = GetSetting("COILWINDER", "STARTUP", "COREID", "0.25")
            CORELENGTH = GetSetting("COILWINDER", "STARTUP", "LENGTH", "0.5")
            WIREGAUGE = GetSetting("COILWINDER", "STARTUP", "WIREGAUGE", "20")
            TOTALWINDINGS = GetSetting("COILWINDER", "STARTUP", "WINDINGS", "250")
            COMPORT = GetSetting("COILWINDER", "STARTUP", "COMPORT", "COM1")
            fWhole_Layer.Checked = GetSetting("COILWINDER", "STARTUP", "WHOLELAYER", fWhole_Layer.Checked)
    
            fCore_ID.Text = COREID
            fCore_Length.Text = CORELENGTH
            fWire_Gauge.Text = WIREGAUGE
            fTotal_Windings.Text = TOTALWINDINGS
            If fWhole_Layer.Checked Then
                fExact_Turns.Checked = False
            Else
                fExact_Turns.Checked = True
            End If
        End Sub
    
        Private Sub Save_Registry_Data()
            SaveSetting("COILWINDER", "STARTUP", "COREID", fCore_ID.Text)
            SaveSetting("COILWINDER", "STARTUP", "LENGTH", fCore_Length.Text)
            SaveSetting("COILWINDER", "STARTUP", "WIREGAUGE", fWire_Gauge.Text)
            SaveSetting("COILWINDER", "STARTUP", "WINDINGS", fTotal_Windings.Text)
            SaveSetting("COILWINDER", "STARTUP", "WholeLayer", fWhole_Layer.Checked)
            SaveSetting("COILWINDER", "STARTUP", "COMPORT", COMPORT)
        End Sub
    
        Private Sub Start_Com_Port()
            Try
                SERIALPORT.Close()
            Catch ex As Exception
                MessageBox.Show(ex.Message)
            End Try
            If COMPORT = "" Then
                For Each sp As String In My.Computer.Ports.SerialPortNames
                    fCom_Port.Items.Add(sp)
                    If fCom_Port.Items.Count > 0 Then
                        fCom_Port.SelectedIndex = 0
                    End If
                Next
            End If
            fCom_Port.Items.Add(COMPORT)
            fCom_Port.SelectedIndex = 0
    
            With SERIALPORT
                Try
                    SERIALPORT.PortName = fCom_Port.SelectedItem
                Catch ex As Exception
                    MessageBox.Show(ex.Message)
                End Try
                .BaudRate = 115200
                .DataBits = 8
                .Parity = Parity.None
                .StopBits = StopBits.One
                .Handshake = Handshake.None
            End With
            Try
                SERIALPORT.Open()
            Catch ex As Exception
                MsgBox("Port " & SERIALPORT.PortName & vbCrLf & ex.Message)
            End Try
        End Sub
    
        Private Sub Initialise_Buttons()
            fCalculate_Button.Enabled = True
            fStart_Button.Enabled = False
            fLeft_Button.Enabled = False
            fRight_Button.Enabled = False
            fPause_Button.Enabled = False
            fContinue_Button.Enabled = False
            fReset_Button.Enabled = True
        End Sub
    
        Private Sub Calculate()
            Process_Screen_Data()
            fWire_Diameter.Text = WIREDIAMETER
            WIREGAUGE = CLng(Me.fWire_Gauge.Text)
            ' CALCULATE STEP RATIO
            SLIDESTEPSPERLAYER = WIREDIAMETER / INCHPERSTEP
            SLIDESTEPRATIO = WINDERSTEPSPERREV / SLIDESTEPSPERLAYER
            fStep_Ratio.Text = SLIDESTEPRATIO
            ' CALCULATE WINDINGS PER LAYER
            WINDSSPERLAYER = CLng(Convert.ToSingle(fCore_Length.Text) / (WIREDIAMETER))
            fWinds_Per_Layer.Text = WINDSSPERLAYER
            ' CALCULATE LAYERS
            If fExact_Turns.Checked Then
                TOTALWINDINGS = fTotal_Windings.Text
            Else
                TOTALWINDINGS = TOTALLAYERSINCOIL * WINDSSPERLAYER
            End If
            TOTALLAYERSINCOIL = TOTALWINDINGS / WINDSSPERLAYER + 1
            fTotal_Layers.Text = Format(TOTALLAYERSINCOIL, "###.00")
            SLIDESTEPSPERLAYER = WIREDIAMETER / INCHPERSTEP * WINDSSPERLAYER
            fSlide_Steps_Per_Layer.Text = SLIDESTEPSPERLAYER
            TOTALFEETOFWIREINCOIL = 0
            ' LOOP THROUGH ALL LAYERS
            Dim cd, id, wd As Single
            For I = 1 To TOTALLAYERSINCOIL - 1
                cd = COREID
                id = I - 1
                wd = WIREDIAMETER
                COREOD = Format(cd + id * wd * 2.0, "000.00")
                TOTALFEETOFWIREINCOIL += Format((3.14159265358979 * COREID * WINDSSPERLAYER / 12.0), "000.00")
            Next I
            TOTALSTEPSINCOIL = TOTALWINDINGS * WINDERSTEPSPERREV        ' Total number of steps in the coil
            fTotal_Coil_Steps.Text = Format(TOTALSTEPSINCOIL, "###,000")
    
            fTotal_Feet.Text = Format(TOTALFEETOFWIREINCOIL, "##0.00")
            fResistance.Text = Format(TOTALFEETOFWIREINCOIL * RESISTANCEPER1000 / 1000.0#, "###0.0")
            fMaxVoltage.Text = Format(fResistance.Text * MAXAMPS, "####.0")
            fTotal_Feet.Refresh()
            fCore_OD.Text = COREOD
            fTotal_Windings.Visible = True
            fTotal_Windings.Height = CURRENTCOREDIAMETER
            CURRENTCOILDIAMETER = COREOD + 2 * WIREDIAMETER
            DrawCoil()
            fCalculate_Button.Enabled = False
            fLeft_Button.Enabled = True
            fRight_Button.Enabled = True
            fStart_Button.Enabled = True
            If fWhole_Layer.Checked Then
                TOTALWINDINGS = (TOTALLAYERSINCOIL - 1) * WINDSSPERLAYER
                fTotal_Windings.Text = TOTALWINDINGS
            End If
        End Sub
    
        Private Sub Data_Changed()
            fCalculate_Button.Enabled = True
            fStart_Button.Enabled = False
            PanelCoil.Visible = False
            PanelCore.Visible = True
            '  Process_Screen_Data()
            Save_Registry_Data()
        End Sub
    
        ' CHANGED
    
        Private Sub Port_SelectedIndexChanged(sender As Object, e As EventArgs) Handles fCom_Port.SelectedIndexChanged
            If SETUPFLAG Then Exit Sub
            COMPORT = fCom_Port.SelectedItem
            Save_Registry_Data()
        End Sub
    
        Private Sub ExactREVs_CheckedChanged(sender As Object, e As EventArgs) Handles fExact_Turns.CheckedChanged
            If SETUPFLAG Then Exit Sub
            Data_Changed()
        End Sub
    
        Private Sub WholeLayer_CheckedChanged(sender As Object, e As EventArgs) Handles fWhole_Layer.CheckedChanged
            If SETUPFLAG Then Exit Sub
            Data_Changed()
        End Sub
    
        Private Sub fCore_ID_TextChanged(sender As Object, e As EventArgs) Handles fCore_ID.TextChanged
            If SETUPFLAG Then Exit Sub
            Data_Changed()
        End Sub
    
        Private Sub fCore_Length_TextChanged(sender As Object, e As EventArgs) Handles fCore_Length.TextChanged
            If SETUPFLAG Then Exit Sub
            Data_Changed()
        End Sub
    
        Private Sub fWire_Gauge_TextChanged(sender As Object, e As EventArgs) Handles fWire_Gauge.TextChanged
            If SETUPFLAG Then Exit Sub
            Data_Changed()
        End Sub
    
        Private Sub fTotal_Windings_TextChanged(sender As Object, e As EventArgs) Handles fTotal_Windings.TextChanged
            If SETUPFLAG Then Exit Sub
            Data_Changed()
        End Sub
    
        ' CLICKED
    
        Private Sub Port_Click(sender As Object, e As EventArgs) Handles fCom_Port.Click
            If SETUPFLAG Then Exit Sub
            Try
                SERIALPORT.Close()
            Catch ex As Exception
                MessageBox.Show(ex.Message)
            End Try
            fCom_Port.Items.Clear()
            For Each sp As String In My.Computer.Ports.SerialPortNames
                fCom_Port.Items.Add(sp)
                If fCom_Port.Items.Count > 0 Then
                    fCom_Port.SelectedIndex = 0
                End If
            Next
            If fCom_Port.Items.Count > 0 Then
                fCom_Port.Items.Add(fCom_Port.SelectedItem)
                fCom_Port.SelectedIndex = 0
    
                With SERIALPORT
                    .PortName = fCom_Port.SelectedItem
                    .BaudRate = 115200
                    .DataBits = 8
                    .Parity = Parity.None
                    .StopBits = StopBits.One
                    .Handshake = Handshake.None
                End With
                Try
                    SERIALPORT.Open()
                Catch ex As Exception
                    MessageBox.Show(ex.Message)
                End Try
            Else
                MsgBox("No Com Port Exists")
            End If
        End Sub
    
        Private Sub fStart_Button_Click(sender As Object, e As EventArgs) Handles fStart_Button.Click
            If SETUPFLAG Then Exit Sub
    
            'Set the running button status
            fStart_Button.Enabled = False
            fPause_Button.Enabled = False
            fLeft_Button.Enabled = False
            fRight_Button.Enabled = False
            fPause_Button.Enabled = True
            CURRENTCOILDIAMETER = COREID + 2 * WIREDIAMETER     ' Set the stert coil diameter
            SLIDESTEPCOUNTER = 0                                      ' Set the start slide position
            fSlide_Steps.Text = SLIDESTEPCOUNTER
            LAYERSCOUNTED = 1                                      ' We have a layer as soon as the winding starts
            fLayer_Count.Text = LAYERSCOUNTED
            DrawCoil()
            CURRENTCOILDIAMETER = COREID + (2 * WIREDIAMETER)   ' Set the current coil diameter
            T1.Start()
        End Sub
    
        Private Sub Pause_Button_Click(sender As Object, e As EventArgs) Handles fPause_Button.Click
            If SETUPFLAG Then Exit Sub
            T1.Stop()
            ' 7 = MOTORS OFF
            writeData("7")
            fContinue_Button.Enabled = True
            fPause_Button.Enabled = False
        End Sub
    
        Private Sub Continue_Button_Click(sender As Object, e As EventArgs) Handles fContinue_Button.Click
            If SETUPFLAG Then Exit Sub
            fContinue_Button.Enabled = False
            fPause_Button.Enabled = True
            T1.Start()
        End Sub
    
        Private Sub Calculate_Button_Click(sender As Object, e As EventArgs) Handles fCalculate_Button.Click
            If SETUPFLAG Then Exit Sub
            ' THIS ROUTINE CALCULATES PARAMETERS FROM DATA ON INPUT SCREEN.
            If SETUPFLAG Then
                Exit Sub
            End If
            Calculate()
        End Sub
    
        Private Sub Reset_Button_Click(sender As Object, e As EventArgs) Handles fReset_Button.Click
            If SETUPFLAG Then Exit Sub
            T1.Stop()
            Save_Registry_Data()
            PanelCoil.Visible = False
            writeData("7")
            SLIDESTEPCOUNTER = 0
            Try
                SERIALPORT.Close()
            Catch ex As Exception
                MessageBox.Show(ex.Message)
            End Try
            fCalculate_Button.Enabled = False
            fWire_Gauge.Enabled = True
            fTotal_Windings.Enabled = True
            fCore_ID.Enabled = True
            fCore_Length.Enabled = True
            setup()
        End Sub
    
        Private Sub Quit_Button_Click(sender As Object, e As EventArgs) Handles fQuit_Button.Click
            If SETUPFLAG Then Exit Sub
            T1.Stop()
            Save_Registry_Data()
            Application.Exit()
        End Sub
    
        ' MOUSEDOWN
    
        Private Sub fLeft_Button_MouseDown(sender As Object, e As MouseEventArgs) Handles fLeft_Button.MouseDown
            If SETUPFLAG Then Exit Sub
            T1.Stop()
            JFORWARD = False
            Timer1.Enabled = True
        End Sub
    
        Private Sub fRight_Button_MouseDown(sender As Object, e As MouseEventArgs) Handles fRight_Button.MouseDown
            If SETUPFLAG Then Exit Sub
            T1.Stop()
            JFORWARD = True
            Timer1.Enabled = True
    
        End Sub
    
        Private Sub fLeft_Button_MouseUp(sender As Object, e As MouseEventArgs) Handles fLeft_Button.MouseUp
            If SETUPFLAG Then Exit Sub
            T1.Stop()
            Timer1.Enabled = False
            writeData("7")
        End Sub
    
        Private Sub fRight_Button_MouseUp(sender As Object, e As MouseEventArgs) Handles fRight_Button.MouseUp
            If SETUPFLAG Then Exit Sub
            T1.Stop()
            Timer1.Enabled = False
            writeData("7")
    
        End Sub
    
        ' SUBS
    
        Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
            If SETUPFLAG Then Exit Sub
            T1.Stop()
            writeData("7")
            Save_Registry_Data()
            Try
                SERIALPORT.Close()
            Catch ex As Exception
                ' do nothing if there is an error
            End Try
            Application.Exit()
        End Sub
    
        Private Sub DrawCoil()
            Dim y As Double
            y = CURRENTCOILDIAMETER * 70
            PNT.X = Label16.Location.X + 10             ' x position is fixed
            PNT.Y = PanelCore.Location.Y - y / 2 + 10   ' y position varies with coil diameter
            PanelCoil.Height = y                        ' the coil height
            PanelCoil.Width = 97                        ' the width is fixed
            PanelCoil.Location = PNT
            PanelCore.Hide()
            PanelCoil.Show()
        End Sub
    
        Private count As Long = 0
    
        Private Sub writeData(dat As Byte)
            count += 1
            fTotal_Coil_Steps.Text = count
            Try
                SERIALPORT.Write(dat)
            Catch ex As Exception
                MessageBox.Show("Serial Port Write Error" & ex.Message)
            End Try
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            If SETUPFLAG Then Exit Sub
            If JFORWARD Then
                writeData("3")
                SLIDESTEPCOUNTER += 1
                fSlide_Steps.Text = SLIDESTEPCOUNTER
            Else
                writeData("4")
                SLIDESTEPCOUNTER -= 1
                fSlide_Steps.Text = SLIDESTEPCOUNTER
            End If
        End Sub
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            setup()
        End Sub
    
        Private Sub T1_Tick(sender As Object, e As EventArgs) Handles T1.Tick
            If SETUPFLAG Then Exit Sub
            Try
                Invoke(New Action(AddressOf Control_The_Motors))
            Catch
                ' do nothing if an error occurs
            End Try
    
        End Sub
    
    End Class

  4. #4
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    4,405

    Re: Slowdown on COM port write after 12k characters

    Are you confident that what you're sending to the arduino is what it expects?
    The code for that looks a little suspect.
    You have these comments in the code
    Code:
      ' ********************************
      ' ignore 48                   // 0
      ' set_ratio 49                // 1
      ' winder_omly 50              // 2
      ' slide_forward 51            // 3
      ' slide_reverse 52            // 4
      ' slide_forward_winder 53     // 5
      ' slide_reverse_winder 54     // 6
      ' stop_motors 55              // 7
      ' ignore all others           //
      ' ********************************
    Based on that it might appear, for instance, to send a stop_motors command to the arduino you should be sending the ASCII value for "7", i.e. a byte value of 55.

    Your code has the WriteData sub's parameter defined as a Byte but you're passing a string, e.g.
    Code:
    Private Sub writeData(dat As Byte)
    '...
    End Sub
    
        writeData("7")
    You obviously don't have Option Strict On otherwise that code wouldn't be allowed because of the type missmatch between the argument type passed to the sub and the parameter type it expects.
    With Option Strict Off, Visual Basic decide on how to convert the String to a Byte.
    In this case, it sees that the string can be converted to a number, i.e. 7 so a byte value of 7 will be received by writeData instead of a byte value of 55.

    If you really wanted to send a 7, then you should just send that:
    WriteData(7)

    If you really wanted to send the ASCII code value for "7", i.e. 55, then you should probably just create an enum to give names to the byte values and use those.
    Code:
      Private Enum MotorCommand As Byte
        ignore = 48  'first command is ASCII zero, each other is 1 more than the previous, e.g. set_ratio is ASCII for "1"
        set_ratio
        winder_omly
        slide_forward
        slide_reverse
        slide_forward_winder
        slide_reverse_winder
        stop_motors
      End Enum
    
    'and later sends a byte value of 55, i.e. ASCII of "7"
    WriteData(MotorCommand.stop_motors)
    Now, as for your speed issue, I guess the question is how confident are you that the high accuracy timer is working well in your scenario.
    Since you trap any exception in the tick and don't display anything or record a count for information, you don't know if you're getting exceptions or not. That could be slowing things down considerably.
    Also, since you Invoke from the tick, that tick is synchronous with the UI, i.e. the tick event won't complete until the Control_The_Motors sub has been scheduled and run on the GUI thread and has returned. If that sub is getting hung up for some reason, I don't know if you may be getting additional ticks and building up multiple invocations waiting on the GUI thread to free up from previous invocations.

    One byte every 50ms, i.e. 20 bytes per second is pretty slow so it doesn't seem reasonable that the serial port would not be keeping up.
    Have you verified that you are getting ticks at 20hz and not some much faster rate?

  5. #5

    Thread Starter
    Lively Member
    Join Date
    Nov 2013
    Posts
    83

    Re: Slowdown on COM port write after 12k characters

    Very good points.
    The write routine uses a byte, but while troubleshooting the problem I changed it to a char and used the offset and character count arguments. I changed all the calls to pass "n" to it but that did not help. Obviously I changed the write routine back to normal, but since the passing of "n" instead of a byte still worked, I didn't bother to change them back.

    The table for the motor commands shows the byte number on the PC end and the ASCII equivalent the Arduino sees. The motors respond correctly so the interpretation is working okay.

    I am very confident the timer is working well because if I comment out just the actual com port write command, the slowdown does not occur. I think that's pretty good evidence the timer is okay and the problem is in the com port write.

    I am pretty confident the timer is reasonably accurate because if it was much faster, the stepper motors would skip steps. I have double checked the motors and after 60 rotations of the winder both the winder and the slide are exactly where they are supposed to be. There are no skipped steps.

    I also made a simpler program that uses the internal timer1 to continuously send the commands at 50ms intervals. That eliminates the possibility of a problem with my timer. That program also slows down after running for a while.

    Based on all the evidence I think it pretty much points to something with the com port writes.

    There is one place where two bytes are sent back-to-back without the 50ms. After the winder steps, there is a check to see if the slide needs to step. If it does, the command to step it goes out immediately. To avoid that I will change things so it sends a single command to step both motors when required. I have commands that will step the winder and step the slider in forward or reverse as needed.

    I will also turn on option strict and clean up the stuff I changed during troubleshooting.

    I need to think about the comments you made on threading. At first blush, the sequence of writing commands is so slow, it's hard to imagine ticks piling up but It is worth checking.

    Thanks!

  6. #6
    King of sapila
    Join Date
    Oct 2006
    Location
    Greece
    Posts
    5,259

    Re: Slowdown on COM port write after 12k characters

    We had tons of issues in COM Printers with baud rates. Some worked fine at 115200 some at 9600.
    We where experiencing a slowdown at tickets after a period of time. I don't say that it is the same issue but wouldn't mind if you did a test with a lower baud rate.
    Slow as hell.

  7. #7
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    32,031

    Re: Slowdown on COM port write after 12k characters

    Hiding the exceptions is still potentially an issue. Commenting out the write doesn't rule that out. If nothing else, add a List(of String) and log any exceptions rather than ignoring them. The reason that exceptions can cause an issue is that they are REALLY slow, so if you start throwing them, then your timing may get pretty messed up at that point. Therefore, you really need to know whether or not that is an issue, and logging will tell you....eventually, as you can check the list to see whether anything is piling up.
    My usual boring signature: Nothing

  8. #8

    Thread Starter
    Lively Member
    Join Date
    Nov 2013
    Posts
    83

    Re: Slowdown on COM port write after 12k characters

    Okay, the change to 9600 baud made no difference except the count is slightly higher when the slow down occurs. It was in the low 13k area.Th really freaky thing about this is my wind counter is always at 61 when this happens.

    On to Shaggy Hiker's suggestion of not ignoring any errors.

  9. #9

    Thread Starter
    Lively Member
    Join Date
    Nov 2013
    Posts
    83

    Re: Slowdown on COM port write after 12k characters

    Everywhere there was a try, I changed it to post a message instead of ignoring the error. I also added the try-catch and message to the invoke in case there was a problem there. Unfortunately, it slowed down at 13300 +- 50 with no errors being caught and running at 9600 baud.

    One other thing was noticed: It ran until it slowed down, then I pressed the pause button which stops the timer. I noted the count and then pressed the continue button and things were still slow. So a pause of 20 or so seconds doesn't change anything. Still looks like a serial port write problem to me.
    Any other thoughts on how I might try to isolate this?

  10. #10
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    32,031

    Re: Slowdown on COM port write after 12k characters

    I would say that you have ruled out an exception being the issue, so that's a step in the right direction.

    I can't say that I have a whole lot of experience with serial port communications. When I have used them, I haven't gotten to the 10K mark, or beyond. It was always shorter periods....except for READING. I've done that for very long runs without issue. There was no writing involved in that, though. Still, I agree with the people who say that the write doesn't seem likely to be the culprit. That doesn't 'feel' right to me. A slowdown after a long run of time feels like either a memory issue or some event-issue (like the timer ticks backing up, as has been noted).

    The next thing that I'd try, which you may have already tried, cause you talked about some things like this, is to add a Stopwatch object and simply note the elapsed time once every timer tick. I'd just be putting that into a list, or some such, and might ignore the first few thousand to keep the size small. Perhaps look at timer ticks 8000 to slowdown. No matter what, you'd expect to see the slowdown show up as an increased interval. What would be interesting is if you saw the pattern be quite regular up to the slowdown, then irregular afterwards.
    My usual boring signature: Nothing

  11. #11
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Slowdown on COM port write after 12k characters

    We can't rule out that there is some bug in the SerialPort class, I've seen some people complain that it's finicky. Unfortunately to prove that, we have to rule out practically everything else. This is really, really tough to do because there is a lot of "everything else" to try. Ideally, you'd have multiple devices, especially some known "good" one that doesn't do much. And multiple computers, to rule out a bad COM port/driver.

    It's especially hard to rule out on my end because I don't have any COM ports, or devices, let alone your specific hardware. So I can't muck around and make something that mimics your device just enough to see if your code has some flaw not apparent from a readthrough.

    I think this is why I'm noticing a trend to use ethernet/wifi in lieu of COM ports lately. It's more ubiquitous and the I/O APIs are almost identical. Not to mention debugging HTTP via Wireshark is a heck of a lot easier than trying to see what's happening over the COM wire.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  12. #12
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    4,405

    Re: Slowdown on COM port write after 12k characters

    I haven't had any problem sending data regularly over multiple serial ports for months on end, but perhaps I've been lucky.
    I took a look at the send routine where I send the same message over two ports, simulating two devices sending regular avionics messages to a flight computer. The message is a 25-byte message, and I believe it is probably intended to send at around 20 hz. The timing isn't critical so I believe a background thread is used with Threading.Sleep so may be sending at 21.333 hz based on the regular 64hz clock behind the timer being divided by 3 as the "true" interval being accomplished.

    Anyway, that send looks like this.
    Code:
      Public Function SendData(ByRef data() As Byte, ByVal messageLength As Integer) As Integer
        Dim bytes_sent As Integer
        Dim test As Integer
        Try
          test = 1
          _serialPort(0).Write(data, 0, messageLength)
          test = 2
          _serialPort(1).Write(data, 0, messageLength)
          bytes_sent = messageLength
        Catch ex As Exception
          Console.WriteLine("...error writing to port(s).  Failed on Port " + test.ToString)
          bytes_sent = -1
        End Try
        Return bytes_sent
      End Function
    25 bytes * 21.333 times per second = 533.333 bytes per second over each port. That means I'm sending 32,000 bytes per minute over those ports for as long as the main simulation is being run.
    (by the way, I actually had a coworker write this portion of the code and he wasn't familiar with VB so depended a lot on looking stuff up on the web. I wouldn't have specified the ByRef and ByVal modifiers on the parameters myself or use "+" to concatenate strings).

    As I said, this software is normally just started by the users in the lab and left running for months on end. The serial is just part of the equipment simulation, there are various Ethernet connections and Avionics bus connections also controlled by this application to simulate various pieces of equipment on an aircraft.
    The primary simulation programs just connect with this simulation program whenever they startup, which is why it is usually just left running since the user doesn't normally need to directly interact with the program, unless there is a problem.

    Anyway, looking at the SerialPort.Write method again, I think I see how you're getting an ASCII code character on your arduino, even though technically you're trying to send a byte who's value is 0, 1, 2,... not 48, 49, 50,...

    The three forms of the Write method are:
    Write(String)
    Write(Byte(), Int32, Int32)
    Write(Char(), Int32, Int32)

    Since you are only passing one argument to Write, and because you have Option Strict Off, VB is using the first Write method, and converting your byte value, e.g. 1, into the String "1", and then the serial write will automatically convert the String argument into a series of ASCII characters when it is transmitted across the interface.

    I guess since it is a string you want transmitted, you should probably just change the parameter type in your SendData to
    Code:
    Private Sub writeData(dat As String)
    so you don't go through all the implicit conversions your code is going through now.
    Another option might be to try using the byte array version of write, and just send that way to see if it makes any difference.
    Code:
        Private Sub writeData(dat As Byte)
            Dim msg(0) As Byte
            count += 1
            fTotal_Coil_Steps.Text = count
            Try
                msg(0) = Asc(dat)
                SERIALPORT.Write(msg, 0, 1)
            Catch ex As Exception
                MessageBox.Show("Serial Port Write Error" & ex.Message)
            End Try
        End Sub
    Last edited by passel; Feb 5th, 2018 at 02:16 PM.

  13. #13
    Addicted Member
    Join Date
    Nov 2011
    Posts
    158

    Re: Slowdown on COM port write after 12k characters

    My thought was the Arduino buffer getting overwitten or the actual process of commanding and moving a couple of motors was taking 50ms. or greater.
    The serial port itself (as you have it configured) should run quite happily at much faster speeds and much more transmitted data all day long.
    I would perhaps try reducing the write time and not the baud rate to begin with, maybe 200ms or slower and see what kind of count you get before things slow down.
    I would also duplicate the transmitted data in a text box along with the data count so that you could check the count and data value being transmitted when things slow down, append the values so they can all be examined at the end of your run

  14. #14

    Thread Starter
    Lively Member
    Join Date
    Nov 2013
    Posts
    83

    Re: Slowdown on COM port write after 12k characters

    Passel, as mentioned previously, I tried changing the write to use SERIALPORT.Write(char, 0, 1) and it didn't help.

    I just created a simpler program that writes bytes to the com port at 50 ms intervals but without all the stuff in my original program. This should eliminate anything in my original program as a cause. This one uses the built-in timer set at 50 ms to eliminate any potential problems with my timer. It has an integer counter and a console write to keep track of ticks. It only writes to the console output window so there is no form updates happening.

    This too slows down at abut 12k ticks. All I do is comment out line 21 (ComPort.Write(2)) and, not to sound like a Timex commercial, but it then goes well past 15k at normal speed and just keeps on ticking.

    Can there be any doubt left about the problem being the .net serial port code or something in my hardware?

    I have been testing on a AilenWare laptop so my next test will be to put this on my wife's Dell desktop PC and give it a go there.

    Lest I forget, a big thank you to all the folks who help me troubleshoot this.

    I'll post the results of the test on the desktop computer when that is done.

    Here is the simpler program:
    Code:
    Imports System.IO.Ports
    Public Class Form1
        Dim ComPort As New SerialPort
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Start_Com_Port()
            run()
        End Sub
        Private Sub run()
            aTimer.AutoReset = True
            aTimer.Interval = 50 '50 mseconds
            AddHandler aTimer.Elapsed, AddressOf tick
            aTimer.Start()
        End Sub
        Private aTimer As New System.Timers.Timer
        Private count As Integer
        Private Sub tick(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs)
            Try
                ' ComPort.Write(2)
            Catch ex As Exception
                MessageBox.Show(ex.Message)
            End Try
            count += 1
            Try
                Console.WriteLine("tick " & count)
            Catch ex As Exception
                MessageBox.Show(ex.Message)
            End Try
        End Sub
        Private Sub Start_Com_Port()
            Try
                ComPort.Close()
            Catch ex As Exception
                Console.WriteLine(ex.Message)
            End Try
            With ComPort
                Try
                    ComPort.PortName = "COM3"
                Catch ex As Exception
                    Console.Write(ex.Message)
                End Try
                .BaudRate = 9600
                .DataBits = 8
                .Parity = Parity.None
                .StopBits = StopBits.One
                .Handshake = Handshake.None
            End With
            Try
                ComPort.Open()
            Catch ex As Exception
                Console.Write("Port " & ComPort.PortName & vbCrLf & ex.Message)
            End Try
        End Sub
    End Class

  15. #15

    Thread Starter
    Lively Member
    Join Date
    Nov 2013
    Posts
    83

    Re: Slowdown on COM port write after 12k characters

    Mc_VB suggested I slow the tick interval down to 200ms or slower, but my patience is wearing thin so I went to 100 ms instead and that didn't help. Next I tried one of the other suggestions and wrote the count out to a text file. Lastly, I moved everything over to my wife's desktop computer and that didn't help either. No matter what I try, this thing starts crawling at about 12-13 k steps. If it means anything, a look at the output file shows that and there are no apparent missing step counts.

    Unless someone can provide an idea to try something that has not already been tried or eliminated, I am going to stop here and declare this a serial port software issue in .net.

    It's time for me to look for another way to connect to the arduino. As you can see in the photo, I am using an Arduino UNO with a Stepper Shield on it. That makes it a little tougher to add a wifi or Bluetooth card to the system but I suspect with a little extra wiring it can be done.

    Still open to any new ideas on this.

  16. #16
    Frenzied Member
    Join Date
    Jul 2011
    Location
    UK
    Posts
    1,143

    Re: Slowdown on COM port write after 12k characters

    Any chance that the Arduino is sending data to the PC, and you are not consuming it? Any Serial.write()/Serial.print() or equivalent commands in the Arduino code?

    I've noticed a slowdown when ComPort.BytesToRead gets to 12290 unread Bytes.

  17. #17
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Slowdown on COM port write after 12k characters

    That's kind of something I thought of and forgot; if it's got some kind of buffer and you fill it, that might slow things down.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

  18. #18
    Addicted Member
    Join Date
    Nov 2011
    Posts
    158

    Re: Slowdown on COM port write after 12k characters

    I tried your console code over a usb to serial connection (no hardware attached) and enabled the Comport.Write(2) line, it ran to 28000 ticks without missing a beat , at that point I closed the app down.
    Inferrd mentions the Arduino sending data to the PC , I don't know if the Arduino does that but I do know the Basic Stamp microcontroller used to echo bytes back, that took special handling so something to look at.

    Also things could be faster and more reliable with a handshake, in this situation a software handshake would work well. Passel mentioned an array of bytes, I would lean toward this too.
    So VB.Net waits for some kind of request "send me some bytes transmits the byte array then waits for the next request while the Arduino consumes the bytes.

  19. #19

    Thread Starter
    Lively Member
    Join Date
    Nov 2013
    Posts
    83

    Re: Slowdown on COM port write after 12k characters

    This problem is fixed. Sprinkled in to some of your comments was the idea the Arduino might be sending data back to the PC and that got me looking at the Arduino end of things. I was pretty sure it was not sending data to the PC, but sure enough, it was. There were 7 Serial.print commands I used while writing and debugging the arduino code. Six (6) of them were commented out but I missed the seventh one which was echoing the '2' command that moves the winder. Every time the winder was told to step, the '2' command was echoed back out on the com port. It never really occurred to me that the debug prints were going out on the same port used to connect the arduino to the PC.

    I am retired and do these little projects mostly to have some fun. This particular bug has really stretched the idea that this was "fun".

    Still, I did learn a lot about troubleshooting and possibly the biggest lesson is to not focus on just one side of the problem when there are two sides.

    FYI: I just stopped the latest test which has been running for a while at 25 ms which is the originally intended speed. It has not slowed down and the count is 63026


    Once again, thank you to all respondents for your help getting me through this. It is greatly appreciated.

  20. #20
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    4,405

    Re: Slowdown on COM port write after 12k characters

    I've had occasion where I received data that I didn't use but didn't have control over the other side so just installed a drain, e.g. add a WithEvents to your serial port declaration, and handle the DataReceived Event.
    Code:
      Private WithEvents SERIALPORT As New SerialPort        ' The io serial port
    
      Private Sub SerialDrain(
                            sender As Object,
                            e As SerialDataReceivedEventArgs) Handles SERIALPORT.DataReceived
        Dim bitBucket As String = SERIALPORT.ReadExisting()
      End Sub

  21. #21

    Thread Starter
    Lively Member
    Join Date
    Nov 2013
    Posts
    83

    Re: Slowdown on COM port write after 12k characters

    Nice, I bet that would have worked too.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width


×
By using this site, you agree to the Privacy Policy