Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

Multithread Problem 3 blinking LED's


Best Answer liqdfire, 20 March 2014 - 02:56 AM

See if this is any better, I already put my logic analyzer away. 

Imports Microsoft.SPOT
Imports Microsoft.SPOT.Hardware
Imports SecretLabs.NETMF.Hardware
Imports SecretLabs.NETMF.Hardware.NetduinoPlus

Module Module1

    Dim led1 As New OutputPort(Pins.GPIO_PIN_D0, False)
    Dim led2 As New OutputPort(Pins.GPIO_PIN_D1, False)
    Dim led3 As New OutputPort(Pins.GPIO_PIN_D2, False)
    Dim led4 As New OutputPort(Pins.GPIO_PIN_D3, False)

    Private _thread1Wait As AutoResetEvent
    Private _thread2Wait As AutoResetEvent
    Private _thread3Wait As AutoResetEvent

    Private _threadX As Thread
    Private _threadY As Thread
    Private _threadZ As Thread

    Sub Main()

        _thread1Wait = New AutoResetEvent(False)
        _thread2Wait = New AutoResetEvent(False)
        _thread3Wait = New AutoResetEvent(False)

        _threadX = New Thread(AddressOf led1t)
        _threadY = New Thread(AddressOf led2t)
        _threadZ = New Thread(AddressOf led3t)


        _threadX.Start()
        _threadY.Start()
        _threadZ.Start()

        _thread1Wait.Set()
        _thread2Wait.Set()
        _thread3Wait.Set()

        System.Threading.WaitHandle.WaitAll(New System.Threading.AutoResetEvent() {_thread1Wait, _thread2Wait, _thread3Wait})

        led4.Write(True)
        Thread.Sleep(Timeout.Infinite) ' Call this here or your program will exit..
    End Sub

    Sub led1t()
        _thread1Wait.WaitOne()

        Dim x As Integer = 0

        While x < 30
            x += 1
            led1.Write(True)
            Thread.Sleep(25)
            led1.Write(False)
            Thread.Sleep(25)
            Debug.Print("Led1 Blink Count = " & x.ToString)
        End While

        _thread1Wait.Set()
        _threadZ.Join()
    End Sub

    Sub led2t()
        _thread2Wait.WaitOne()

        Dim y As Integer = 0

        While y < 15
            y += 1
            led2.Write(True)
            Thread.Sleep(25)
            led2.Write(False)
            Thread.Sleep(25)
            Debug.Print("Led2 Blink Count = " & y.ToString)
        End While

        _thread2Wait.Set()
        _threadZ.Join()
    End Sub

    Sub led3t()
        _thread3Wait.WaitOne()

        Dim z As Integer = 0

        While z < 55
            z += 1
            led3.Write(True)
            Thread.Sleep(25)
            led3.Write(False)
            Thread.Sleep(25)
            Debug.Print("Led3 Blink Count = " & z.ToString)
        End While

        _thread3Wait.Set()
    End Sub

End Module

Go to the full post


  • Please log in to reply
20 replies to this topic

#1 twinnaz

twinnaz

    Advanced Member

  • Members
  • PipPipPip
  • 38 posts
  • LocationBrampton, Ontario

Posted 19 March 2014 - 07:55 PM

I have this code that blinks 3 LED's at the same time and also counts a value in each thread.

The problem is when I deploy the project and everything starts running the LED's are out of sync and i get pauses whenever a value is reached until I push the reset button on the Netduino then everything runs as expected, but then I lose the ability to monitor the values in the debugger. Am I missing something or is this a glitch in .NETMF

Code Below 

Imports Microsoft.SPOT
Imports Microsoft.SPOT.Hardware
Imports SecretLabs.NETMF.Hardware
Imports SecretLabs.NETMF.Hardware.Netduino

Module Module1

    Dim led1 As New OutputPort(Pins.GPIO_PIN_D0, False)
    Dim led2 As New OutputPort(Pins.GPIO_PIN_D1, False)
    Dim led3 As New OutputPort(Pins.GPIO_PIN_D2, False)
    Dim led4 As New OutputPort(Pins.GPIO_PIN_D3, False)
    Public led1done As Boolean = False
    Public led2done As Boolean = False
    Public led3done As Boolean = False
    Sub Main()

        Dim x As New Thread(AddressOf led1t)
        Dim y As New Thread(AddressOf led2t)
        Dim z As New Thread(AddressOf led3t)
        Dim Done As New Thread(AddressOf DBit)

        x.Start()
        y.Start()
        z.Start()
        Done.Start()

    End Sub
    Sub led1t()

        Dim x As Integer = 0

        While x < 30
            x += 1
            led1.Write(True)
            Thread.Sleep(25)
            led1.Write(False)
            Thread.Sleep(25)
            Debug.Print("Led1 Blink Count = " & x.ToString)
            If x = 30 Then led1done = True
        End While
    End Sub
    Sub led2t()

        Dim y As Integer = 0

        While y < 15
            y += 1
            led2.Write(True)
            Thread.Sleep(25)
            led2.Write(False)
            Thread.Sleep(25)
            Debug.Print("Led2 Blink Count = " & y.ToString)
            If y = 15 Then led2done = True
        End While
    End Sub
    Sub led3t()

        Dim z As Integer = 0

        While z < 55
            z += 1
            led3.Write(True)
            Thread.Sleep(25)
            led3.Write(False)
            Thread.Sleep(25)
            Debug.Print("Led3 Blink Count = " & z.ToString)
            If z = 55 Then led3done = True
        End While
    End Sub
    Sub DBit()
        While True
            If led1done And led2done And led3done = True Then
                led4.Write(True)
                Thread.Sleep(Timeout.Infinite)


            End If
        End While
    End Sub
End Module


Netduino Plus 2


#2 liqdfire

liqdfire

    Advanced Member

  • Members
  • PipPipPip
  • 78 posts

Posted 19 March 2014 - 08:38 PM

Ok, you have a few things going on here, mainly your program is exiting as soon as it initializes everything

 

In your sub main you need to add Thread.Sleep(Timeout.Infinite) or the app will exit and I am pretty sure the CLR will dump it.

Also your threads are scoped locally, so even if the CLR does not dump they are falling out of scope, and the GC more than likely will collect them.

 

More of a stylistic, there is no need for the 4th thread, and using a ManualResetEvent for thread synchronization is a much better mechanism than a boolean. also you do not need to check if you reached your max value every loop of the while, the while will auto exit when it has reached its exit condition, so you can put your thread finished notification outside of the loop saving cpu cycles.

 

Here is a quick sample I pulled together for you (cannot run because I am at work, but looks correct)

Imports System.Threading
Imports Microsoft.SPOT
Imports Microsoft.SPOT.Hardware
Imports SecretLabs.NETMF.Hardware
Imports SecretLabs.NETMF.Hardware.Netduino

Module Module1


    Dim led1 As New OutputPort(Pins.GPIO_PIN_D0, False)
    Dim led2 As New OutputPort(Pins.GPIO_PIN_D1, False)
    Dim led3 As New OutputPort(Pins.GPIO_PIN_D2, False)

    Private _thread1Wait As ManualResetEvent
    Private _thread2Wait As ManualResetEvent
    Private _thread3Wait As ManualResetEvent

    Private _threadX As Thread
    Private _threadY As Thread
    Private _threadZ As Thread

    Sub Main()

        _thread1Wait = New ManualResetEvent(False)
        _thread2Wait = New ManualResetEvent(False)
        _thread3Wait = New ManualResetEvent(False)

        _threadX = New Thread(AddressOf led1t)
        _threadY = New Thread(AddressOf led2t)
        _threadZ = New Thread(AddressOf led3t)


        _threadX.Start()
        _threadY.Start()
        _threadZ.Start()

        System.Threading.WaitHandle.WaitAll(New System.Threading.ManualResetEvent() {_thread1Wait, _thread2Wait, _thread3Wait})

        led4.Write(True)
        Thread.Sleep(Timeout.Infinite) ' Call this here or your program will exit..
    End Sub

    Sub led1t()

        Dim x As Integer = 0

        While x < 30
            x += 1
            led1.Write(True)
            Thread.Sleep(25)
            led1.Write(False)
            Thread.Sleep(25)
            Debug.Print("Led1 Blink Count = " & x.ToString)
        End While
        _thread1Wait.Set()
    End Sub

    Sub led2t()

        Dim y As Integer = 0

        While y < 15
            y += 1
            led2.Write(True)
            Thread.Sleep(25)
            led2.Write(False)
            Thread.Sleep(25)
            Debug.Print("Led2 Blink Count = " & y.ToString)
        End While
        _thread1Wait.Set()
    End Sub

    Sub led3t()

        Dim z As Integer = 0

        While z < 55
            z += 1
            led3.Write(True)
            Thread.Sleep(25)
            led3.Write(False)
            Thread.Sleep(25)
            Debug.Print("Led3 Blink Count = " & z.ToString)
        End While

        _thread1Wait.Set()
    End Sub
End Module



#3 twinnaz

twinnaz

    Advanced Member

  • Members
  • PipPipPip
  • 38 posts
  • LocationBrampton, Ontario

Posted 19 March 2014 - 10:45 PM

thanks for making some corrections but unfortunately your code does the same thing as mines. I uploaded a video showing what it does right at deploy and then after a reset (what i want it to do ).

 

http://1drv.ms/1hJJew6


Netduino Plus 2


#4 liqdfire

liqdfire

    Advanced Member

  • Members
  • PipPipPip
  • 78 posts

Posted 20 March 2014 - 01:47 AM

ok, I think I misunderstood what you were experiencing, I almost wonder if that is not a difference thread start times right after deploy.

 

Here is a couple of screen shots, from my logic analyzer running the code I posted.

 

right after deploymeny

https://www.dropbox....fter deploy.png

 

after reset button

https://www.dropbox....after reset.png

 

You can see there is a pretty big difference in the output timings on start up after debugging



#5 liqdfire

liqdfire

    Advanced Member

  • Members
  • PipPipPip
  • 78 posts

Posted 20 March 2014 - 02:38 AM

There is quite a bit of overhead required for creating a thread, and starting it so I synchronized the thread start of execution by making the threads wait until all of them were started and in the running state. 

 

Timings with Synchro starts

https://www.dropbox....chro starts.png

Imports Microsoft.SPOT
Imports Microsoft.SPOT.Hardware
Imports SecretLabs.NETMF.Hardware
Imports SecretLabs.NETMF.Hardware.Netduino

Module Module1

    Dim led1 As New OutputPort(Pins.GPIO_PIN_D0, False)
    Dim led2 As New OutputPort(Pins.GPIO_PIN_D1, False)
    Dim led3 As New OutputPort(Pins.GPIO_PIN_D2, False)
    Dim led4 As New OutputPort(Pins.GPIO_PIN_D3, False)

    Private _thread1Wait As AutoResetEvent
    Private _thread2Wait As AutoResetEvent
    Private _thread3Wait As AutoResetEvent

    Private _threadX As Thread
    Private _threadY As Thread
    Private _threadZ As Thread

    Sub Main()

        _thread1Wait = New AutoResetEvent(False)
        _thread2Wait = New AutoResetEvent(False)
        _thread3Wait = New AutoResetEvent(False)

        _threadX = New Thread(AddressOf led1t)
        _threadY = New Thread(AddressOf led2t)
        _threadZ = New Thread(AddressOf led3t)


        _threadX.Start()
        _threadY.Start()
        _threadZ.Start()

        _thread1Wait.Set()
        _thread2Wait.Set()
        _thread3Wait.Set()

        System.Threading.WaitHandle.WaitAll(New System.Threading.AutoResetEvent() {_thread1Wait, _thread2Wait, _thread3Wait})

        led4.Write(True)
        Thread.Sleep(Timeout.Infinite) ' Call this here or your program will exit..
    End Sub

    Sub led1t()
        _thread1Wait.WaitOne()

        Dim x As Integer = 0

        While x < 30
            x += 1
            led1.Write(True)
            Thread.Sleep(25)
            led1.Write(False)
            Thread.Sleep(25)
            Debug.Print("Led1 Blink Count = " & x.ToString)
        End While

        _thread1Wait.Set()
    End Sub

    Sub led2t()
        _thread2Wait.WaitOne()

        Dim y As Integer = 0

        While y < 15
            y += 1
            led2.Write(True)
            Thread.Sleep(25)
            led2.Write(False)
            Thread.Sleep(25)
            Debug.Print("Led2 Blink Count = " & y.ToString)
        End While

        _thread2Wait.Set()
    End Sub

    Sub led3t()
        _thread3Wait.WaitOne()

        Dim z As Integer = 0

        While z < 55
            z += 1
            led3.Write(True)
            Thread.Sleep(25)
            led3.Write(False)
            Thread.Sleep(25)
            Debug.Print("Led3 Blink Count = " & z.ToString)
        End While

        _thread3Wait.Set()
    End Sub

End Module



#6 twinnaz

twinnaz

    Advanced Member

  • Members
  • PipPipPip
  • 38 posts
  • LocationBrampton, Ontario

Posted 20 March 2014 - 02:38 AM

Just expecting for all leds blink at the same time after deploying without resetting the netduino.In the first half of the video you can see that the leds aren't flashing at the same time, (whice is the part I don't want).

In the second half of the video I press the reset button and then you can see all the leds flashing in sync that's what I want right from the get go not needing to reset the netduino

Netduino Plus 2


#7 liqdfire

liqdfire

    Advanced Member

  • Members
  • PipPipPip
  • 78 posts

Posted 20 March 2014 - 02:43 AM

Something else to keep in mind, .NetMF is not a real time OS, there are no exact timing guarantees. Sleep(25) just means that the thread will sleep for no less than 25ms, but it could take a little bit longer depending what the CPU is doing. That and the fact that these devices are single core devices so even though you can create threads only one can actually run at a time, the rest is handled by the thread scheduler.



#8 twinnaz

twinnaz

    Advanced Member

  • Members
  • PipPipPip
  • 38 posts
  • LocationBrampton, Ontario

Posted 20 March 2014 - 02:50 AM

Alright tested your new code it deploys and runs as expected (blinks 3 LEDS at the same time) but after led2 reaches count it goes out of sync again. :( I read up about the timing on .netmf I was just testing some multi threading for fun, but I guess I can scrap the code now since I cant get it working. Thanks for your effort !

What would be an alternate way of flashing 3 leds in sync if I may ask. Is there another route?


Netduino Plus 2


#9 liqdfire

liqdfire

    Advanced Member

  • Members
  • PipPipPip
  • 78 posts

Posted 20 March 2014 - 02:55 AM

I think what you are seeing is the thread exiting, you can even fix that still by having it Join the other threads so they do not exit until all of them are done....

 

You could try putting them in one thread and using one loop. 

 

You could connect the LEDs to a shift register and use SPI to control it (I actually this one on a bigger project I am doing)

https://www.sparkfun.com/products/733



#10 twinnaz

twinnaz

    Advanced Member

  • Members
  • PipPipPip
  • 38 posts
  • LocationBrampton, Ontario

Posted 20 March 2014 - 02:56 AM

I just took a look at you pic. After observing I can see in the middle section on channel 0 and channel 2 that it goes out of sync Ch0 starts high and ch 2 starts low causing the ping pong light effect. I'm guessing the timing is causing this ?


Netduino Plus 2


#11 liqdfire

liqdfire

    Advanced Member

  • Members
  • PipPipPip
  • 78 posts

Posted 20 March 2014 - 02:56 AM   Best Answer

See if this is any better, I already put my logic analyzer away. 

Imports Microsoft.SPOT
Imports Microsoft.SPOT.Hardware
Imports SecretLabs.NETMF.Hardware
Imports SecretLabs.NETMF.Hardware.NetduinoPlus

Module Module1

    Dim led1 As New OutputPort(Pins.GPIO_PIN_D0, False)
    Dim led2 As New OutputPort(Pins.GPIO_PIN_D1, False)
    Dim led3 As New OutputPort(Pins.GPIO_PIN_D2, False)
    Dim led4 As New OutputPort(Pins.GPIO_PIN_D3, False)

    Private _thread1Wait As AutoResetEvent
    Private _thread2Wait As AutoResetEvent
    Private _thread3Wait As AutoResetEvent

    Private _threadX As Thread
    Private _threadY As Thread
    Private _threadZ As Thread

    Sub Main()

        _thread1Wait = New AutoResetEvent(False)
        _thread2Wait = New AutoResetEvent(False)
        _thread3Wait = New AutoResetEvent(False)

        _threadX = New Thread(AddressOf led1t)
        _threadY = New Thread(AddressOf led2t)
        _threadZ = New Thread(AddressOf led3t)


        _threadX.Start()
        _threadY.Start()
        _threadZ.Start()

        _thread1Wait.Set()
        _thread2Wait.Set()
        _thread3Wait.Set()

        System.Threading.WaitHandle.WaitAll(New System.Threading.AutoResetEvent() {_thread1Wait, _thread2Wait, _thread3Wait})

        led4.Write(True)
        Thread.Sleep(Timeout.Infinite) ' Call this here or your program will exit..
    End Sub

    Sub led1t()
        _thread1Wait.WaitOne()

        Dim x As Integer = 0

        While x < 30
            x += 1
            led1.Write(True)
            Thread.Sleep(25)
            led1.Write(False)
            Thread.Sleep(25)
            Debug.Print("Led1 Blink Count = " & x.ToString)
        End While

        _thread1Wait.Set()
        _threadZ.Join()
    End Sub

    Sub led2t()
        _thread2Wait.WaitOne()

        Dim y As Integer = 0

        While y < 15
            y += 1
            led2.Write(True)
            Thread.Sleep(25)
            led2.Write(False)
            Thread.Sleep(25)
            Debug.Print("Led2 Blink Count = " & y.ToString)
        End While

        _thread2Wait.Set()
        _threadZ.Join()
    End Sub

    Sub led3t()
        _thread3Wait.WaitOne()

        Dim z As Integer = 0

        While z < 55
            z += 1
            led3.Write(True)
            Thread.Sleep(25)
            led3.Write(False)
            Thread.Sleep(25)
            Debug.Print("Led3 Blink Count = " & z.ToString)
        End While

        _thread3Wait.Set()
    End Sub

End Module



#12 twinnaz

twinnaz

    Advanced Member

  • Members
  • PipPipPip
  • 38 posts
  • LocationBrampton, Ontario

Posted 20 March 2014 - 02:58 AM

I was thinking about controlling 3 steppers motors and having them receive the same step pulses in sync. 


Netduino Plus 2


#13 liqdfire

liqdfire

    Advanced Member

  • Members
  • PipPipPip
  • 78 posts

Posted 20 March 2014 - 02:59 AM

If you look carefully you see the pauses are directly correlated to when another channel is finished, the CLR has to cleanup the thread and notify the debugger. When you hit reset the debugger is not attached, so the overhead of notifying the debugger that the thread exited and releasing the debugging hooks is not incurred.

 

I just took a look at you pic. After observing I can see in the middle section on channel 0 and channel 2 that it goes out of sync Ch0 starts high and ch 2 starts low causing the ping pong light effect. I'm guessing the timing is causing this ?



#14 twinnaz

twinnaz

    Advanced Member

  • Members
  • PipPipPip
  • 38 posts
  • LocationBrampton, Ontario

Posted 20 March 2014 - 03:01 AM

Is it possible to just pause the thread when count is reached instead of exiting ?


Netduino Plus 2


#15 liqdfire

liqdfire

    Advanced Member

  • Members
  • PipPipPip
  • 78 posts

Posted 20 March 2014 - 03:01 AM

You could do that with a shift register easily, you write a byte to the SPI bus. Each bit of that byte represents the desired state of one of the 8 output pins, it latches them all at the exact time, and you can get very fast timings out of the SPI bus. You would just have to use some bit wise logic and thinking to determine which motor to turn on if you wanted them to step in sync but at different duty cycles.

 

 

I was thinking about controlling 3 steppers motors and having them receive the same step pulses in sync. 



#16 liqdfire

liqdfire

    Advanced Member

  • Members
  • PipPipPip
  • 78 posts

Posted 20 March 2014 - 03:02 AM

Sure just put a Sleep(Timeout.Infinite), but then you have no way to wake it up.

You could also create another set of wait events, but that does not gain you much over waiting for the other thread to exit.

 

It all depends on what the rest of your logic / program flow needs to look like.

 

Is it possible to just pause the thread when count is reached instead of exiting ?



#17 twinnaz

twinnaz

    Advanced Member

  • Members
  • PipPipPip
  • 38 posts
  • LocationBrampton, Ontario

Posted 20 March 2014 - 03:05 AM

Your last code worked perfectly !! :) What did you change?
nevermind i see you used thread join.
Thanks very much for your help really appreciate it.


Netduino Plus 2


#18 liqdfire

liqdfire

    Advanced Member

  • Members
  • PipPipPip
  • 78 posts

Posted 20 March 2014 - 03:07 AM

If you look at the last line in in led1t and led2t they do a .Join on _threadZ

A join causes the existing thread to block until the Joined thread exits. This causes the overhead of the thread exit cleanup by the CLR, etc to be delayed until the timing cycle is complete.

 

http://msdn.microsof...(v=vs.110).aspx

 

You are very welcome, hope you learned a little but about threading in .Net :)



#19 twinnaz

twinnaz

    Advanced Member

  • Members
  • PipPipPip
  • 38 posts
  • LocationBrampton, Ontario

Posted 20 March 2014 - 03:11 AM

So in short it just tells thread1 and 2 to hop into the other timing cycle until Thread z is done then the CLR kicks in?


Netduino Plus 2


#20 liqdfire

liqdfire

    Advanced Member

  • Members
  • PipPipPip
  • 78 posts

Posted 20 March 2014 - 03:14 AM

It basically puts thread 1 and 2 into a wait state, and they wake up and execute the next line when the Joined thread exits.

You very well could have continued executing code in thread 1 and 2 after the join.

 

It just so happens that the next line of code in those methods is the exit sub, which signals to the CLR that the threads are finished and it can clean them up.

 

Edit: in this case we could have gotten the exact same results by calling _thread3Wait.WaitOne()

 

 

So in short it just tells thread1 and 2 to hop into the other timing cycle until Thread z is done then the CLR kicks in?






0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.