Problem G120 with methods of Debug class

When running without debugging, G120 will freeze for several seconds and recover back to normal when my program runs at any method of Debug class like Debug.Print() or Debug.GC(). I’ve found the problem from OLED display. But, when debugging, everything seems OK! If no method of Debug class in codes, G120 will freeze periodically also! I guess that Debug.GC() should be executed by system automatically. There’re only Thread class and SPI communication there. How to fix the problem? Is it a G120 bug?

When you hit a situation like this, the best way to get help is to create as small an application as possible, that can demonstrate the behaviour you see, and provide that here to see if others can replicate it. Can you consistently repro this? If so, that means you should be able to create a project that can show off the behaviour and GHI and everyone else can look at it

There’s the demo project, which can show the situation I’ve described. Any solution?



using System.Threading;
using GHI.Premium.Hardware;
using GHI.Premium.System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using Microsoft.SPOT.Presentation.Media;

namespace iPressG120
{
    public class MyProgram
    {
        private readonly OledDriver oled;
        private readonly Thread painter;
        private readonly Font font;
        private bool toggle;

        public MyProgram()
        {
            font = Resources.GetFont(Resources.FontResources.NinaB);
            oled = new OledDriver(SPI.SPI_module.SPI3, G120.Pin.P1_8, G120.Pin.P0_26, G120.Pin.P0_25);
            painter = new Thread(Paint);
            painter.Start();
        }

        private void Paint()
        {
            var bitmap = new Bitmap(128, 40);
            var framebuffer = new byte[128*40*2];
            while (true)
            {
                bitmap.Clear();
                bitmap.DrawText(toggle.ToString(), font, Color.White, 5, 10);
                toggle = !toggle;
                Util.BitmapConvertBPP(bitmap.GetBitmap(), framebuffer, Util.BPP_Type.BPP16_BGR_BE);
                oled.FlushRawBitmap(0, 0, 128, 40, framebuffer);
                Thread.Sleep(100);
            }
        }

        public static void Main()
        {
            var program = new MyProgram();
            while (true)
            {
                Thread.Sleep(2000);
                //If uncommented, it will be frozen for several seconds!
                //If commented, it will be frozen too!
                //Debug.Print("Debug infos");
            }
        }
    }
    public class OledDriver
    {
        private readonly SPI spi;
        private readonly OutputPort rst;
        private readonly OutputPort dc;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="spimod"></param>
        /// <param name="chipSelect"></param>
        /// <param name="rstPin">Pin4</param>
        /// <param name="dcPin">Pin3</param>
        public OledDriver(SPI.SPI_module spimod,Cpu.Pin chipSelect,Cpu.Pin rstPin,Cpu.Pin dcPin)
        {
            rst = new OutputPort(rstPin,true);
            dc = new OutputPort(dcPin,true);

            var spiConfig = new SPI.Configuration(chipSelect, false, 0, 0, false, true, 18000, spimod);
            spi = new SPI(spiConfig);
            spi.Write(new byte[] { 0x00 });

            Reset();
            InitializeDisplay();
        }

        public uint Height
        {
            get { return 128; }

        }

        public uint Width
        {
            get { return 128; }
        }

        private void Reset()
        {
            rst.Write(false);
            Thread.Sleep(100);
            rst.Write(true);
            Thread.Sleep(50);
        }


        private readonly byte[] ba = new byte[1];

        /// <summary>
        /// Gets or sets a value that indicates whether the thread should sleep after a send operation.
        /// </summary>
        private bool sleepAfterSend;

        /// <summary>
        /// Gets or sets the amount of time to sleep (if <see cref="sleepAfterSend"/> is <b>true</b>)
        /// after a send operation.
        /// </summary>
        private const int Sleeptime = 1;

        /// <summary>
        /// Sends a command to the display device.
        /// </summary>
        /// <param name="command">The command to send.</param>
        /// <param name="data">The command data.</param>
        private void Send(byte command, byte[] data)
        {
            ba[0] = command;
            dc.Write(false);
            spi.Write(ba);
            if (data != null && data.Length > 0)
            {
                dc.Write(true);
                spi.Write(data);
            }
            if (sleepAfterSend) 
                Thread.Sleep(Sleeptime);
        }

        //private byte[] vram;

        /// <summary>
        /// Initializes the display.
        /// </summary>
        protected void InitializeDisplay()
        {
            //vram = new byte[Width * Height * 2];

            sleepAfterSend = true;

            SendParams(Cmd.SetCommandLock1, 0x12);
            SendParams(Cmd.SetCommandLock1, 0xB1);
            SendParams(Cmd.SetSleepModeON0);
            SendParams(Cmd.FrontClockDividerAndOscillatorFrequency1, 0xF1); // DIVSET = 1, Oscillator frequency = 15
            SendParams(Cmd.SetMuxRatio1, 0x7F);
            SendParams(Cmd.SetDisplayOffset1, 0x00);
            SendParams(Cmd.SetDisplayStartLine1, 0x00);
            SendParams(Cmd.SetRemapAndColorDepth1, 0x74); // 65K (16 bit) color
            SendParams(Cmd.SetGPIO1, 0x00);
            SendParams(Cmd.FunctionSelection1, 0x01); // internal VDD
            SendParams(Cmd.SetSegmentLowVoltage3, 0xA0, 0xB5, 0x55); // External VSL

            SendParams(Cmd.SetContrastCurrentForColourABC3, 0xC8, 0x80, 0xC8);
            SendParams(Cmd.MasterContrastCurrentControl1, 0x0F); // halve output currents 

            SendParams(Cmd.UseBuiltinLinearLUT0);

            SendParams(Cmd.SetResetAndPrechargePeriod1, 0x32); // minimum periods allowed
            SendParams((Cmd)0xB2, 0xA4, 0x00, 0x00); // "Enhance Driving Scheme Capability" - undocumented setting?
            SendParams(Cmd.SetPrechargeVoltage1, 0x17);
            SendParams(Cmd.SetSecondPrechargePeriod1, 0x01); // minimum period allowed
            SendParams(Cmd.SetVCOMHVoltage1, 0x05);
            SendParams(Cmd.SetDisplayModeNORMAL0);
            var vram = new byte[128*2];
            for (var i = 0; i < 128; i++)
                SendParams(Cmd.WriteRAMCommand0, vram);
            //SendParams(Cmd.WriteRAMCommand0, vram);
            SendParams(Cmd.SetSleepModeOFF0);

            sleepAfterSend = false;
        }

        private void SendParams(Cmd cmd, params byte[] args)
        {
            Send((byte)cmd, args);
        }

        private void Send(Cmd cmd, byte[] args)
        {
            Send((byte)cmd, args);
        }

        // from SSD1351 datasheet
        private enum Cmd
        {
            SetColumnAddress2 = 0x15,
            SetRowAddress2 = 0x75,
            WriteRAMCommand0 = 0x5C,
            ReadRAMCommand0 = 0x5D,
            SetRemapAndColorDepth1 = 0xA0,
            SetDisplayStartLine1 = 0xA1,
            SetDisplayOffset1 = 0xA2,
            SetDisplayModeOFF0 = 0xA4,
            SetDisplayModeALLON0 = 0xA5,
            SetDisplayModeNORMAL0 = 0xA6,
            SetDisplayModeINVERSE0 = 0xA7,
            FunctionSelection1 = 0xAB,
            SetSleepModeON0 = 0xAE,
            SetSleepModeOFF0 = 0xAF,
            SetResetAndPrechargePeriod1 = 0xB1,
            FrontClockDividerAndOscillatorFrequency1 = 0xB3,
            SetSegmentLowVoltage3 = 0xB4,
            SetGPIO1 = 0xB5,
            SetSecondPrechargePeriod1 = 0xB6,
            LookUpTableForGrayScalePulseWidth63 = 0xB8,
            UseBuiltinLinearLUT0 = 0xB9,
            SetPrechargeVoltage1 = 0xBB,
            SetVCOMHVoltage1 = 0xBE,
            SetContrastCurrentForColourABC3 = 0xC1,
            MasterContrastCurrentControl1 = 0xC7,
            SetMuxRatio1 = 0xCA,
            SetCommandLock1 = 0xFD
        }

        public void FlushRawBitmap(byte x, byte y, byte width, byte height, byte[] buffer)
        {
            SendParams(Cmd.SetColumnAddress2, x, (byte)(x + width - 1));
            SendParams(Cmd.SetRowAddress2, y, (byte) (y + height - 1));
            Send(Cmd.WriteRAMCommand0, buffer);
        }
    }
}

Instead of While(true) and Sleep(2000), can you try Sleep(Timeout.Infinite) without the while…

When a program is started, it is the best that the root thread is never used any more…

also try to increase the Sleep(100) when painting, to calibrate how much time the system really make to send the image to the OLED… 100ms seems few no ?

I’ve tried to use Sleep(Timeout.Infinite). Same result. Howevert, I’ve found out that when the line “Debug.EnableGCMessages(false);” in Main(), it’s works and the frozen’s gone. The G120 implementation of output to console when non-debugging may be something wrong!