Strange Display/SPI Problem

Getting a strange random crash using the SITCore Experimenter kit. When using the display AND the IR receiver I am getting the following random exception when the DrawBuffer command is called on the ST7735Controller object at the same time as a IR command is received.

Exception was thrown: System.InvalidOperationException
#### Exception System.InvalidOperationException - CLR_E_INVALID_OPERATION (1) ####
#### Message:
#### GHIElectronics.TinyCLR.Devices.Spi.Provider.SpiControllerApiWrapper::WriteRead [IP: 0000] ####
#### GHIElectronics.TinyCLR.Devices.Spi.SpiDevice::WriteRead [IP: 001d] ####
#### GHIElectronics.TinyCLR.Devices.Spi.SpiDevice::Write [IP: 000b] ####
#### GHIElectronics.TinyCLR.Devices.Spi.SpiDevice::Write [IP: 0009] ####
#### GHIElectronics.TinyCLR.Drivers.Sitronix.ST7735.ST7735Controller::SendCommand [IP: 001a] ####
#### GHIElectronics.TinyCLR.Drivers.Sitronix.ST7735.ST7735Controller::DrawBuffer [IP: 0004] ####
Exception thrown: ‘System.InvalidOperationException’ in GHIElectronics.TinyCLR.Devices.Spi.dll

If no commands are received on the NecIRDecoder this crash never happens. What might I be missing here? Thanks!

Can you try to simplify your code to narrow the problem to a small example that we can look into?

I was guessing it was going to be a conflict in SPI usage, but the NEC IR component is only using standard GPIO… But my next guess will be it’s data driven, that you’re writing something that you received via IR and that’s causing it (this is just a guess - lets see your simple program to repro it)

what firmware are you using?

Firmware: 2.1.0.6400

Code:

using GHIElectronics.TinyCLR.Devices.Gpio;
using GHIElectronics.TinyCLR.Devices.Spi;
using GHIElectronics.TinyCLR.Drivers.BasicGraphics;
using GHIElectronics.TinyCLR.Drivers.Infrared;
using GHIElectronics.TinyCLR.Drivers.Sitronix.ST7735;
using GHIElectronics.TinyCLR.Pins;
using System;
using System.Collections;
using System.Diagnostics;
using System.Text;
using System.Threading;

namespace IRSample
{
    internal class Program
    {
       
        static void Main()
        {
            bool power = false;
            //connect the IR receiver to PIN 1 of the FEZBit
            var receivePin = GpioController.GetDefault().OpenPin(FEZBit.GpioPin.P1);
            var ir = new NecIRDecoder(receivePin);

            //Display the power status using the onboard LED
            GpioPin led = GpioController.GetDefault().OpenPin(FEZBit.GpioPin.Led);
            led.SetDriveMode(GpioPinDriveMode.Output);

            //Init the display controller
            ST7735Controller st7735 = null;
            BasicGraphics basicGfx = new BasicGraphics(160, 128, ColorFormat.Rgb565);
            uint colorBlue = BasicGraphics.ColorFromRgb(0, 0, 255);

            // Display Get Ready ////////////////////////////////////
            var spi = SpiController.FromName(FEZBit.SpiBus.Display);
            var gpio = GpioController.GetDefault();
            st7735 = new ST7735Controller(
            spi.GetDevice(ST7735Controller.GetConnectionSettings
                (SpiChipSelectType.Gpio,
                    gpio.OpenPin(FEZBit.GpioPin.DisplayChipselect))), //CS pin.
                    gpio.OpenPin(FEZBit.GpioPin.DisplayRs), //RS pin.
                    gpio.OpenPin(FEZBit.GpioPin.DisplayReset) //RESET pin.
                );
            var backlight = gpio.OpenPin(FEZBit.GpioPin.Backlight);
            backlight.SetDriveMode(GpioPinDriveMode.Output);
            backlight.Write(GpioPinValue.High);
            st7735.SetDataAccessControl(true, true, false, false); //Rotate the screen.
            st7735.SetDrawWindow(0, 0, 160, 128);
            st7735.Enable();

            UpdateIndicators(power, basicGfx, colorBlue, st7735, led);

            ir.OnDataReceivedEvent += (address, command) =>
            {
                Debug.WriteLine("A: " + address + " C: " + command);
                power = !power;

                UpdateIndicators(power, basicGfx, colorBlue, st7735, led);
            };

            ir.OnRepeatEvent += () =>
            {
                Debug.WriteLine("Repeat!");
            };

            Thread.Sleep(Timeout.Infinite);

        }
 
        public static void UpdateIndicators(bool pwr, BasicGraphics bGfx, uint color, ST7735Controller screen, GpioPin led)
        {
            bGfx.Clear();
            bGfx.DrawString("Power: " + (pwr ? "ON" : "OFF"), color, 10, 40, 2, 2);
            try
            {
                screen.DrawBuffer(bGfx.Buffer); //Exception occurs on this call
                led.Write(pwr ? GpioPinValue.High : GpioPinValue.Low);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }
    }
}

Output Window:
Found debugger!

Create TS.

Loading Deployment Assemblies.

Attaching deployed file.

Assembly: mscorlib (2.1.0.0) Attaching deployed file.

Assembly: GHIElectronics.TinyCLR.Devices.Spi (2.1.0.0) Attaching deployed file.

Assembly: GHIElectronics.TinyCLR.Native (2.1.0.0) Attaching deployed file.

Assembly: GHIElectronics.TinyCLR.Devices.Gpio (2.1.0.0) Attaching deployed file.

Assembly: GHIElectronics.TinyCLR.Drivers.BasicGraphics (2.1.1.0) Attaching deployed file.

Assembly: GHIElectronics.TinyCLR.Drivers.Sitronix.ST7735 (2.1.0.0) Attaching deployed file.

Assembly: IRSample (1.0.0.0) Attaching deployed file.

Assembly: GHIElectronics.TinyCLR.Drivers.Infrared (2.1.0.0) Resolving.

The debugging target runtime is loading the application assemblies and starting execution.
Ready.

‘GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll’ (Managed): Loaded ‘C:\Users\crazy\OneDrive\Development\TinyCLR\Blinky\IRSample\bin\Debug\pe…\GHIElectronics.TinyCLR.Native.dll’, Skipped loading symbols. Module is optimized and the debugger option ‘Just My Code’ is enabled.
‘GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll’ (Managed): Loaded ‘C:\Users\crazy\OneDrive\Development\TinyCLR\Blinky\IRSample\bin\Debug\pe…\GHIElectronics.TinyCLR.Devices.Gpio.dll’, Skipped loading symbols. Module is optimized and the debugger option ‘Just My Code’ is enabled.
‘GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll’ (Managed): Loaded ‘C:\Users\crazy\OneDrive\Development\TinyCLR\Blinky\IRSample\bin\Debug\pe…\GHIElectronics.TinyCLR.Devices.Spi.dll’, Skipped loading symbols. Module is optimized and the debugger option ‘Just My Code’ is enabled.
‘GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll’ (Managed): Loaded ‘C:\Users\crazy\OneDrive\Development\TinyCLR\Blinky\IRSample\bin\Debug\pe…\GHIElectronics.TinyCLR.Drivers.BasicGraphics.dll’, Skipped loading symbols. Module is optimized and the debugger option ‘Just My Code’ is enabled.
‘GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll’ (Managed): Loaded ‘C:\Users\crazy\OneDrive\Development\TinyCLR\Blinky\IRSample\bin\Debug\pe…\GHIElectronics.TinyCLR.Drivers.Sitronix.ST7735.dll’, Skipped loading symbols. Module is optimized and the debugger option ‘Just My Code’ is enabled.
‘GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll’ (Managed): Loaded ‘C:\Users\crazy\OneDrive\Development\TinyCLR\Blinky\IRSample\bin\Debug\pe…\GHIElectronics.TinyCLR.Drivers.Infrared.dll’, Skipped loading symbols. Module is optimized and the debugger option ‘Just My Code’ is enabled.
‘GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll’ (Managed): Loaded ‘C:\Users\crazy\OneDrive\Development\TinyCLR\Blinky\IRSample\bin\Debug\pe…\IRSample.exe’, Symbols loaded.
The thread ‘’ (0x2) has exited with code 0 (0x0).
Step into: Stepping over non-user code ‘IRSample.Program.’
A: 0 C: 0
Repeat!
A: 0 C: 0
A: 0 C: 0
A: 0 C: 0
Repeat!
A: 0 C: 0
Repeat!
A: 0 C: 0
A: 0 C: 0
Repeat!
A: 0 C: 0
A: 0 C: 0
#### Exception System.InvalidOperationException - CLR_E_INVALID_OPERATION (3) ####
#### Message:
#### GHIElectronics.TinyCLR.Devices.Spi.Provider.SpiControllerApiWrapper::WriteRead [IP: 0000] ####
#### GHIElectronics.TinyCLR.Devices.Spi.SpiDevice::WriteRead [IP: 001d] ####
#### GHIElectronics.TinyCLR.Devices.Spi.SpiDevice::Write [IP: 000b] ####
#### GHIElectronics.TinyCLR.Devices.Spi.SpiDevice::Write [IP: 0009] ####
#### GHIElectronics.TinyCLR.Drivers.Sitronix.ST7735.ST7735Controller::DrawBuffer [IP: 0019] ####
#### IRSample.Program+<>c__DisplayClass0_0::b__0 [IP: 003a] ####
#### GHIElectronics.TinyCLR.Drivers.Infrared.NecIRDecoder::Rx_ValueChanged [IP: 017d] ####
#### GHIElectronics.TinyCLR.Devices.Gpio.GpioPin::OnValueChanged [IP: 000e] ####
#### GHIElectronics.TinyCLR.Devices.Gpio.Provider.GpioControllerApiWrapper::OnDispatcher [IP: 0047] ####
Exception thrown: ‘System.InvalidOperationException’ in GHIElectronics.TinyCLR.Devices.Spi.dll
Exception was thrown: System.InvalidOperationException
Repeat!
The program ‘[6] TinyCLR application: Managed’ has exited with code 0 (0x0).

This issue appears to be tied to the Persist slow clock option. I had this turned on originally. I reflashed the controller and ran the same program with no issues. Then I turned on the Persist slow clock option again and it immediately returned.

Perfect, we will check

We could reproduce it. Thank for your information.

Change your SPI clock if you need Persist slow clock, and let us know if it still happen. So far we don’t see any more after reduce SPI clock.

var setting = ST7735Controller.GetConnectionSettings(SpiChipSelectType.Gpio, gpio.OpenPin(FEZBit.GpioPin.DisplayChipselect));

setting.ClockFrequency = 6_000_000;           

st7735 = new ST7735Controller(
                    spi.GetDevice(setting),
                    gpio.OpenPin(FEZBit.GpioPin.DisplayRs), //RS pin.
                    gpio.OpenPin(FEZBit.GpioPin.DisplayReset) //RESET pin.
                );

Or just simple:

Instead of using

screen.DrawBuffer(bGfx.Buffer);

use:

screen.DrawBuffer(bGfx.Buffer, 0, 0, 160, 128);

The second ignores everything, only focus on write, faster and no error.