Exception thrown: 'System.NotSupportedException' in GHIElectronics.TinyCLR.Drawing.dll

Hi, I’m working on creating a series of screens as a UI for users to navigate using the SCM20260D processor with TinyCLR in Visual Studio 2022. All referenced NuGet packages are on version 2.2.0.4200. I worked towards this goal by modifying the screen behavior in the SCM20260D Dev board demo code located here: GitHub - ghi-electronics/TinyCLR-Samples: Sample projects and demos for TinyCLR OS.

My modifications include replacing icons as the primary method of moving between screens with buttons, however, occasionally when pressing a button I get the following exception:

#### Exception System.NotSupportedException - CLR_E_NOT_SUPPORTED (1) ####
    #### Message: 
    #### System.Drawing.Internal.Bitmap::Flush [IP: 0000] ####
    #### System.Drawing.Graphics::Flush [IP: 001c] ####
    #### GHIElectronics.TinyCLR.UI.Bitmap::Flush [IP: 000c] ####
    #### GHIElectronics.TinyCLR.UI.Media.MediaContext::RenderMessageHandler [IP: 010a] ####
    #### GHIElectronics.TinyCLR.UI.Threading.Dispatcher::PushFrameImpl [IP: 0054] ####
    #### GHIElectronics.TinyCLR.UI.Threading.Dispatcher::PushFrame [IP: 0018] ####
    #### GHIElectronics.TinyCLR.UI.Threading.Dispatcher::Run [IP: 0006] ####
    #### GHIElectronics.TinyCLR.UI.Application::Run [IP: 0066] ####
    #### MR_200.Program::Main [IP: 0147] ####
Exception thrown: 'System.NotSupportedException' in GHIElectronics.TinyCLR.Drawing.dll
[Default DispatcherException Handler] Exception caught: System.NotSupportedException

However, nowhere in my code do I call the flush function from System.Drawing.Internal.Bitmap, and in fact I am not using a bitmap at all since I removed icons altogether for this project, so I was hoping I could get further insight into what’s going on. Here is an example button press that is causing the error reliably:

private Button lightButton;

public MainMenuWindow(string text, int width, int height) : base(text, width, height)
{
	...
	
	this.lightButton = new Button()
	{
		Child = new GHIElectronics.TinyCLR.UI.Controls.Text(Resources.GetFont(Resources.FontResources.droid_reg24), "Light")
		{
			ForeColor = Colors.Black,
			HorizontalAlignment = HorizontalAlignment.Center,
			VerticalAlignment = VerticalAlignment.Center,
		},
		Width = 400,
		Height = 50,
	};

	this.lightButton.Click += this.LightButtonClick;
}

//turn flashlight on or off when light button is pressed
private void LightButtonClick(object sender, RoutedEventArgs e)
{
	if (e.RoutedEvent.Name.CompareTo("TouchUpEvent") == 0 && MainWindow.touchDebounce == 0)
	{
		MainWindow.touchDebounce = 200;
		MainWindow.buzzer.Start();
		Thread.Sleep(10);
		MainWindow.buzzer.Stop();
		if (MainWindow.FlashLight1.Read() == GpioPinValue.Low)
		{
			MainWindow.FlashLight1.Write(GpioPinValue.High);
			MainWindow.FlashLight2.Write(GpioPinValue.High);
		}
		else
		{
			MainWindow.FlashLight1.Write(GpioPinValue.Low);
			MainWindow.FlashLight2.Write(GpioPinValue.Low);
		}
	}
}

All buttons are added correctly, Flashlight1 and Flashlight2 are defined as follows in the main window:

//flashlights
FlashLight1 = GpioController.GetDefault().OpenPin(SC20260.GpioPin.PI9);
FlashLight1.SetDriveMode(GpioPinDriveMode.Output);
FlashLight1.Write(GpioPinValue.Low);

FlashLight2 = GpioController.GetDefault().OpenPin(SC20260.GpioPin.PJ7);
FlashLight2.SetDriveMode(GpioPinDriveMode.Output);
FlashLight2.Write(GpioPinValue.Low);

The click button should simply toggle the lines hooked up to flashlight LED’s from high to low and vice versa when pressed, which it does, but it always outputs this error as well. The oddest part is that in the click button code, if I put the following, it does not triggered the exception:

private void LightButtonClick(object sender, RoutedEventArgs e)
{
	if (e.RoutedEvent.Name.CompareTo("TouchUpEvent") == 0 && MainWindow.touchDebounce == 0)
	{
		MainWindow.touchDebounce = 200;
		MainWindow.buzzer.Start();
		Thread.Sleep(10);
		MainWindow.buzzer.Stop();
		if (MainWindow.FlashLight1.Read() == GpioPinValue.Low)
		{
			MainWindow.FlashLight1.Write(GpioPinValue.High);
			MainWindow.FlashLight2.Write(GpioPinValue.High);
		}
		else
		{
			MainWindow.FlashLight1.Write(GpioPinValue.Low);
			MainWindow.FlashLight2.Write(GpioPinValue.Low);
		}
                Thread.Sleep(1000);
	}
}

I have been trying to figure out how to fix this issue for a few days now and would greatly appreciate knowing if it is an internal library issue or if there is any guidance that anyone has in how to deal with it, as a not supported exception referencing a function that I am not calling is a bit confusing, especially for a function that is simply changing a Gpio Pinout value. Thank you for your time.

EDIT: I do want to note that I also occasionally see this error when hitting a button to go back to the last screen I was on, for example when exiting a menu.

EDIT 2: did more testing and even if I comment out the entire function within the click button aside from the if statement for event routing and touch screen debounce timing, I still get the exception output.

I think it’s because you haven’t defined the child Text Height and Width properties. I usually just make the Height equal to the _font.Height property and Width equal to the parent width.

System.Drawing.Font fnt = Resources.GetFont(Resources.FontResources.droid_reg24);
this.lightButton = new Button()
	{
		Child = new GHIElectronics.TinyCLR.UI.Controls.Text(fnt, "Light")
		{
			ForeColor = Colors.Black,
			HorizontalAlignment = HorizontalAlignment.Center,
			VerticalAlignment = VerticalAlignment.Center,
            Height = fnt.Height, 
            Width = 400,
		},
		Width = 400,
		Height = 50,
	};

1 Like

Code still throws the same error even if I add the height and width for the text as done in your suggestion. Also I believe if it were something similar to your theory then all my buttons would be outputting that exception instead of just a few here and there. Appreciate the advice though!

I don’t have a crisp answer for you, but one thing that I find very interesting is that you say ‘occasionally’ this gets thrown. When you say that, do you mean that a given button sometimes throws and sometimes does not, or did you mean that some buttons throw and some do not, but the ones that do, do so 100% of the time.

You also mentioned that you don’t call the Flush routine that is throwing. That’s understandable. Flush is called under the covers by many of the image/graphics routines, and those calls may come as part of an internal render cycle rather that a call stack originating within your code.

In the TinyCLR library source on github, I traced through the code around these flush calls, and particularly System.Drawing.Internal.Bitmap::Flush. This function is a call out to native code, so I can’t see the line that is throwing. It’s the native code that is throwing.

Where I have seen this in the past is when the bitmap format is bad or some parameter is out of range. That is, the block of data being flushed isn’t a bitmap format that the native code recognizes or the parameters are asking the native code to do something beyond it’s capabilities. And that’s why I am asking about whether this is probabilistically or deterministically reproducible. If it is probabilistic, then maybe it’s memory corruption (since it worked with the same bits elsewhere). If it is deterministic, then we need to figure out which calling parameter the native code doesn’t like. If this is a deterministic failure for some buttons or screens, are you using a different bitmap or font in those places? Is it in a supported format?

It’s hard for me to be more specific without a local repro to dig into. Hope this helps in some small way.

Hi,

  1. First, can you run the sample project where you took the source code, any exception?
  2. Second, adding your code step by step, so you will know what line or what modify caused exception.

In our side, calling native flush thrown unsupported exception when the screen is setup for rotation and the bitmap you flush is not full screen. UI window width and high need to be same as native screen if you want to rotate the screen, any size different to native screen is not supported yet.

Did you rotate the screen? if so, how did you setup your code?

  1. If you think it is a bug, send us a simple project so we can test quickly.

@mcalsyn Yes to both cases, some buttons reliably output the exception, some only do seemingly at random, it’s primarily that one light button and back buttons that take you back to a previous screen in UI. I am using the same font on all buttons and am not using a bitmap as far as I know, as the demo that I modified for this program only used the bitmap for icons as far as I could tell, which my program does not have any of.

@Dat_Tran

  1. The demo project does not throw any exceptions, however it primarily uses icons while I primarily use buttons, so it could have to do with that.

  2. The issue with that is that if I add a time delay, such as a breakpoint within the button press, it no longer throws the exception, which means that I cannot debug the issue line by line.

I did rotate the screen so that it would match up with touch screen coordinates, which may be the cause of the error, I’ll do a bit more testing and get back to you on whether or not I think it is the screen rotate issue or a bug for point 3!

Did you rotate 90 or 180?

I think you rotate 90 or 270, that cause screen width and high different.

There are two place to set:

Native:

var controllerSetting = new GHIElectronics.TinyCLR.Devices.Display.ParallelDisplayControllerSettings {
                // 480x272
                Width = 480,
                Height = 272,
}

UI:

var mainWindow = new MainWindow(480, 272);

Make sure they are same.

For touch, you need to add rotate in touch driver.

If you are using our FT5xx6 driver, below is how:

touch = new FT5xx6Controller(i2cDevice, interrupt);
touch.Orientation = FT5xx6Controller.TouchOrientation.Degrees0;

Basically, if the bitmap you are flushing is not same exactly size with native screen AND rotate 90 or 270 then the exception will be thrown.
UI is simply a hidden bitmap where you draw everything on it (button, label…).

1 Like

I did rotate 90:

var controllerSetting = new ParallelDisplayControllerSettings
            {
                
                Width = 800,
                Height = 800,
                DataFormat = DisplayDataFormat.Rgb565,
                Orientation = DisplayOrientation.Degrees90, //Rotate display.
                PixelClockRate = 40000000,
                PixelPolarity = false,
                DataEnablePolarity = false,
                DataEnableIsFixed = false,
                HorizontalFrontPorch = 200,
                HorizontalBackPorch = 1,
                HorizontalSyncPulseWidth = 87,
                HorizontalSyncPolarity = true,
                VerticalFrontPorch = 101,
                VerticalBackPorch = 29,
                VerticalSyncPulseWidth = 3,
                VerticalSyncPolarity = true
            };

            public static int Width => 800;
            public static int Height => 800;
//Main function loop
        static void Main()
        {
            //Configure Screen
            Display displayController = new Display();
            displayController.InitializeDisplay();

            //Initialize Touch
            //Input.Touch.InitializeTouch();

            MainApp = new Program(Display.DisplayController);

            var mainWindow = new MainWindow(Display.Width, Display.Height, displayController);

            //create windows:
            var mainMenuWindow = new MainMenuWindow("Main Menu", Display.Width, Display.Height);
            mainWindow.RegisterWindow(mainMenuWindow);
            
            //Run The App
            MainApp.Run(mainWindow);
        }

I have a 800x480 screen in landscape mode by default which I wish to use in portrait mode as a 480x800, however if I tried to make width 480 and the height 800, the bottom of the screen was cut off, and if I make the width 800 and the height 480, then the top half of the screen shows an empty top bar and some empty buttons and the bottom half is shifted up with a little of what is supposed to be the top of the screen jutting out from the bottom, so I had to make the screen act as an 800x800. I can try to use the original dimensions and rotate by 270 instead and see if it makes any difference, I’ll let you know how it goes.

if the input 800x800 shouldn’t throw exception.

What configuration that have exception?

We need to look both display config and UI config as well.

Could you give me more information on what you mean by what configuration have that exception?
As far as I know the UI is just the main menu window which I posted in my code, which has the light button and its click button which I also posted the configuration of.

I mean the exception happened before you change to 800x800, or it still happen even already set 800x800?

If width == height no matter rotation is, the size, width, height are always same then should not throw exception.

Weird to me that you still have exception if already set 800x800.

It only happens when I press certain buttons, the light button click event I initially posted is an example, and it triggers even if that event’s function is empty aside from checking if it was routed from a touch up event. For example:

//turn flashlight on or off when light button is pressed
        private void LightButtonClick(object sender, RoutedEventArgs e)
        {
            if (e.RoutedEvent.Name.CompareTo("TouchUpEvent") == 0 && MainWindow.touchDebounce == 0)
            {
            }
        }

triggers the exception every time. It never happens during startup while configuring my window size, or when registering any of the windows in the program.cs file.

I will note that the following however no longer triggers the exception:

//turn flashlight on or off when light button is pressed
        private void LightButtonClick(object sender, RoutedEventArgs e)
        {
            if (e.RoutedEvent.Name.CompareTo("TouchUpEvent") == 0 && MainWindow.touchDebounce == 0)
            {
                Thread.Sleep(1000);
            }
        }

which is odd because I can’t think of why a timing issue would trigger a not-supported exception. The exception also doesn’t trigger if I make the light button click close and re-open the main menu window where it is located, though some other buttons which navigate between windows also throw this error.

and that exception still not support exception or different exception?

Could you please send us a simple project?

Same exception every time, always about that flush function, I will try and send a simple project, but my current project is pretty long, so trying to parse out the important parts and still make the code work while having the exception trigger may take a bit of time.

Okay, made a pretty simple program, what method would you like for me to use to send it to you?

you can send to me directly: x@y.com

x: dat.tran
y: ghielectronics

Sent it off, hope it helps, I realize that it will be tricky to use since it relies on having a touch screen display hooked up with a specific backlight power line, but hopefully it’s simple enough that you can get something working.

Hello, we see the problem.

That exception is OK to ignore. We will correct in next release, but that exception shouldn’t stop or effect anything.

There are 3 issues in your project so far:

  1. We see you use the backlight pin is PK0, then later you use pwm to set brightness on PA15, not sure how these pins are connected in your board.

  2. Touch: In MainWindow.cs, line 129

_touch.Orientation = FT5xx6Controller.TouchOrientation.Degrees180; 

This won’t work if your screen is rotate 90. Touch and display rotation need to be matched.

  1. You already set, let say 90, or any:
_touch.Orientation = FT5xx6Controller.TouchOrientation.Degrees90; 

Then in touch up and touch down events, no need to change TouchX or TouchY. They are already calculated in touch driver and this is purpose of _touch.Orientation property.

I mean:

Program.MainApp.InputProvider.RaiseTouch(800 - e.X, e.Y, ......)

must be:

Program.MainApp.InputProvider.RaiseTouch(e.X, e.Y, ......)

e.X, e.Y are calculated internally to match with rotation already, no need to change.

But these issues are not related exception and the exception is OK to ignore.

Thank for helping us on the issue.

Thanks you so much for your help, glad I could bring it to your attention and that it doesn’t cause any major issues with my code!

  1. I essentially have 2 backlight enable lines, one being PA15 going to a transistor which allows the BL- pin of the display to connect to ground so current can flow through the backlight, and one of which enables the backlight voltage to be 10.5 volts which connects to the BL+ pin of the display. If either line goes low, then the backlight voltage no longer flows through the backlight on the board. This was the best work around I could think of that still gave control of both pins. I could alternatively just set PK0 high at all times and just use PA15 to control the brightness, but this current setup works without issue as far as I can tell.

  2. The touch screen controller hardware is external to the display and is essentially default oriented as though the screen was rotated 90 degrees. This means that even if I were to not rotate the orientation of either at all, my e.X and e.Y arguments would be reversed from the button setup orientation so no button click event would ever trigger.

  3. Lastly, the touch controller hardware defaults the top right of the screen to be 0,0 whereas the button placement in tinyCLR uses the top left to be 0,0. Again, this means that even when I have the orientations fixed in point 2, my e.X shows my distance from the right side of the screen while my button’s X start and end coordinate refer to it’s distance from the left side of the screen. Combine that with the previously mentioned 800x800 fix for a 480x800 screen, and it considers most presses on the screen to actually be off the physical display. To fix this, I reverse the touch event’s reported x coordinate by subtracting it from 800, effectively making the top left corner of the screen the origin on both devices.

1 Like

yes, let us know if you see any other strange issue.