Noob boot question - how to get FEZ Cerberus to boot into code when not attached to PC under debug

Sorry if this has been asked before because I have Googled and looked on the forum but I don’t really know the name of it to search for. Bootloader? TinyCLR? GHIConfig???

Now, I was under the impression, if you deploy and then run in debug, code from a PC to a FEZ (Cerberus in this case) then the same code should still be present when it is next powered up and it will run without the debug environment. I’m sure I had this happen on my FEZ Cerbot (though of course that has its own batteries…???).

Then I thought about it and read up and figured I’d need to use the GHI config tool and VS to do the following steps:

  1. Deploy release build to device using VS2015
  2. Use the config tool to pull a HEX image from the device and store it on PC hard drive
  3. Use the config tool to erase the device then load the HEX image back to the device burning it into EEPROM

I’ve done this two or three times now and the code doesn’t seem to start - that is, no LEDs flash. I have no logging or anything but I put in a ‘step one, flash the LEDs’ stage so I’d know it was booting… no joy. It sometimes starts on the battery (like, twice) but mostly not. And it runs fine under the debug environment. Power when not on PC power is a fully charged 10Ah battery with a 2A USB interface. Same USB cable into the USB 1.3 SP card.

.Net MF 4.3
VS2015 on Windows 10
Latest SDK etc
Firmware 4.3.8.1
FEZ Cerberus
USB 1.3 SP Power on socket 8
SN3218 LED Driver on I2C pin 8&9 on Socket 1 (400kHz)
One analogue in pin5 and one digital interrupt in pin 4 on Socket 4

Thanks in advance.

Correct. Your code will run a bit slower in Debug though so there could be a problem with the initialization when running at full speed.

Ah OK thanks. So there’s no need to do any of the HEX read/clear/load stuff?

I’ll put some debug LED stuff in and some sleep statements before the I2C setup. As that’s about the only thing that might be time critical (it’s the only thing on the system except for the analogue input)

:slight_smile:

@ adamwynne - Hi, may be it’s the best if you show your code. Sometimes it’s easy for a experienced user to see the pitfalls.
Kind regards
RoSchmi

If you want to eliminate possible problems, VS2013 is the platform you want :slight_smile:

@ Brett, @ RoSchmi

OK, stripped the code down to the bare minimum.
Also installed fresh VS2013 SP5 and the latest GHI SDKs etc
None of this helped…

As I figured, it seems to be the write to the I2C. The first Reset command in fact.
Putting in a long delay ahead of this doesn’t seem to help.
However I put in a retry and that works fine - though it’s a nasty hack.

Here’s the code:
This one doesn’t work even with a 1 second delay before the reset command.
And Just the reset command kills the ticker timer too.


using System.Threading;
using Gadgeteer.SocketInterfaces;
using GT = Gadgeteer;

namespace SimpleDrumTestApp
{
    public partial class Program
    {
        void ProgramStarted()
        {
            GT.Timer timer = new GT.Timer(1000);
            timer.Tick += Timer_Tick;
            timer.Start();

            SetUpSn3218();
        }

        private void Timer_Tick(GT.Timer timer)
        {
            PulseDebugLED();
        }

        private const int I2CAddress = 0x54;
        private I2CBus _device;

        private void SetUpSn3218()
        {
            var socket = GT.Socket.GetSocket(1, true, null, null);
            _device = I2CBusFactory.Create(socket, I2CAddress, 100, null);
            Thread.Sleep(1000); // even with this, it kills the timer
            Reset();
            Enable();
            EnableLeds(0xFFFFF);
            Output(new[] {255, 255, 255});
        }

        private enum Command
        {
            EnableOutput = 0x00,
            SetPwmValues = 0x01,
            EnableLeds = 0x13,
            Update = 0x16,
            Reset = 0x17
        }

        public void Enable()
        {
            WriteBlockData(Command.EnableOutput, 0x01);
        }

        public void Disable()
        {
            WriteBlockData(Command.EnableOutput, 0x00);
        }

        public void Reset()
        {
            WriteBlockData(Command.Reset, 0xff);
        }

        public void EnableLeds(int bitmask)
        {
            WriteBlockData(Command.EnableLeds, bitmask & 0x3f, (bitmask >> 6) & 0x3f, (bitmask >> 12) & 0X3f);
            WriteBlockData(Command.Update, 0xff);
        }

        public void Output(params int[] levels)
        {
            WriteBlockData(Command.SetPwmValues, levels);
            WriteBlockData(Command.Update, 0xff);
        }

        private void WriteBlockData(Command command, params int[] data)
        {
            if (_device == null)
                return;

            var buffer = new byte[data.Length + 1];
            buffer[0] = (byte) command;
            for (var idx = 1; idx <= data.Length; idx++)
            {
                buffer[idx] = (byte) data[idx - 1];
            }
            _device.Write(buffer);
        }
    }
}

And, here’s my kludgy fix:


  private void WriteBlockData(Command command, params int[] data)
        {
            if (_device == null)
                return;

            var buffer = new byte[data.Length + 1];
            buffer[0] = (byte) command;
            for (var idx = 1; idx <= data.Length; idx++)
            {
                buffer[idx] = (byte) data[idx - 1];
            }
    
            bool done = false;
            while (!done)
            {
                try
                {
                    _device.Write(buffer);
                    done = true;
                }
                catch (Exception)
                {
                    Thread.Sleep(100);
                }
            }
        }

Any ideas how to properly start up the I2C interface for this chip?

Chip spec sheet here:

(In fact some of the code was ‘borrowed’ from Mr Stov - he uses an async block… clue there… however I presumed that await/async isn’t part of .Net MF?


 private async Task<I2cDevice> InitializeDevice()
        {
            // initialize I2C communications
            try
            {
                var deviceSelector = I2cDevice.GetDeviceSelector(I2CControllerName);
                var i2CDeviceControllers = await DeviceInformation.FindAllAsync(deviceSelector);
                var i2CSettings = new I2cConnectionSettings(I2CAddress) {BusSpeed = I2cBusSpeed.FastMode};
                return await I2cDevice.FromIdAsync(i2CDeviceControllers[0].Id, i2CSettings);
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine("Exception: {0}", e.Message);
                return null;
            }
        }

I’ not sure if this will solve your problem, but… :
In Gadgeteer projects timer do not work properly until the ProgramStarted method has finished.
So, if your initialization SetUpSn3218() hangs, the timer will not work properly as ProgramStarted never gets finished.
As a first try, I would set the timer.start() after SetUpSN3218() (not sure if this helps).
As a second try, I would take the initialization SetUpSN3218() out of ProgramStarted and do the initialization in the tick eventhandler of a second timer (run once) which is started as the last command in ProgramStarted.
As a third try, I would do the initialization in a new thread, which is created in the tick eventhandler of this second timer.

and…
try thread.sleep(…) after Setup(), Enable() and EnableLeds(0xFFFFF);

@ adamwynne - The problem is that your Timer instance is local to the ProgramStarted method. When this method completes, and the local variable goes out of scope, the timer is eligible for GC and that is probably what is happening, the timer is getting garbage collected and therefore killing your timer. Make the timer a member of the class rather than a local variable and you should be in better shape.

OK, I think this has solved it:
Pulling the timer into a member field, yes of course. However the thing that seems to really fix it is calling the I2C init code from the first timer event. Thanks everyone for your brilliant support!

public partial class Program
    {
        GT.Timer _timer;
        void ProgramStarted()
        {
            _timer = new GT.Timer(1000);
            _timer.Tick += Timer_Tick;
            _timer.Start();
        }

        private bool hasRunOnce;
        private void Timer_Tick(GT.Timer timer)
        {
            if (!hasRunOnce)
            {
                SetUpSn3218();
                hasRunOnce = true;
            }
            PulseDebugLED();
        }

...


        private void SetUpSn3218()
        {
            var socket = GT.Socket.GetSocket(1, true, null, null);
            _device = I2CBusFactory.Create(socket, I2CAddress, 100, null);
            Reset();
            Enable();
            EnableLeds(0xFFFFF);
            Output(new[] {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 });
        }

...

   private void WriteBlockData(Command command, params int[] data)
        {
            if (_device == null)
                return;

            var buffer = new byte[data.Length + 1];
            buffer[0] = (byte) command;
            for (var idx = 1; idx <= data.Length; idx++)
            {
                buffer[idx] = (byte) data[idx - 1];
            }
            _device.Write(buffer);
        }



1 Like

@ adamwynne - Glad to hear that you have it sorted. I normally include a RunOnce timer to allow time for the ProgramStarted thread to complete before initializing any of my setting/interfaces.

@ taylorza - theoretically you are right and myself I alway declare the timer as a class member as well.
Practically in Gadgeteer application a timer declared in ProgramStarted seems to be not garbagecollected.
This little test code for example runs without problems:


namespace GadgeteerApp1
{
    public partial class Program
    {
        int loopCtr = 0;
        
        void ProgramStarted()
        {
            GT.Timer timer = new GT.Timer(1000); // every second (1000ms)
            timer.Tick +=timer_Tick;
            timer.Start();
            Debug.Print("Program Started");
        }

        void timer_Tick(GT.Timer timer)
        {
            loopCtr++;
            // do something......
            string firstString = "edghawiresrkz€rktzz serh tgurhi etkr#puklz dtgjjrtgdokzujtilot drtjztpulr üpöui+uiüozoüpzoüfkzdh stijhtrr";
            string secondString = string.Empty;
            for (int i = 0; i < 100; i++)
            {
                secondString = firstString;
                firstString = secondString;
            }
            PulseDebugLED();
            Debug.Print("Event No: " + loopCtr);
        }
    }
}

Do you know an explantion why it’s not killed by GC?

Has a GC actually ocurred? That is, have you seen the debug output indicating that a GC occured, because by my reading of your source code, the timer is a candidate for collection. Your code in the loop is not chruning memory - it is just swapping references. Change that code to add i.ToString() to the end of the strings, or just force a call to the GC and I think you will see the timer get collected.

@ mcalsyn - I’ll try later, when I am back at home. But even in the outcommented Gadgeteer Template which appears in every new Gadgeteer application showing how to use a timer, the timer instance is declared in the ProgramStarted method.

You are right about that - the comments do show it the way you have it. But the rule is simple : if there’s no ref, you get GC’d, so either there’s a non-obvious reference there, or you’re living on borrowed time.

If you do an explicit GC and it doesn’t get collected, then there’s a mysterious ref hanging about. I suppose there could be a static collection of all timers somewhere that keeps this instance alive as long as the timer is active. Now I’m curious and will have to go read the source.

Yup - your timer does not get disposed because there is a global table of timers (‘activeTimers’ hashtable). This is a quirk of the Gadgeteer timer implementation. I’m not terribly fond of this implementation :

The relevant code from Timer.cs in the Gadgeteer source:

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Microsoft Corporation.  All rights reserved.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Gadgeteer
{
    using Microsoft.SPOT;
    using System.Collections;
    using System;

    /// <summary>
    /// Provides a timer to enable periodic status checks or actions, or a one-off stopwatch.
    /// </summary>
    /// <remarks>
    /// This class wraps the <see cref="Microsoft.SPOT.DispatcherTimer"/> class to provide 
    /// a simpler API for your Gadgeteer application.
    /// </remarks>
    public class Timer
    {
        private DispatcherTimer dt;
        private static Hashtable activeTimers = new Hashtable();
1 Like

@ mcalsyn - thank you, one more thing that I know now. At least in computers: every thing has it’s reason, even if we do not know it :wink:

1 Like

Ah yes, I forgot that the Gadgeteer timers are maintained in a Hashtable, in fact I forgot that Gadgeteer had an extended implementation of the Timer outside of the NETMF Timer class…