Speed of Cobra whilst drawing

Hi everyone,

Firstly, I’ve just got my cobra and it’s a dream to develop for. I’m new to netmf so I hope none of these questions are too silly. :slight_smile:

I’m working on a project with a FEZ Cobra and one of the 7inch screens (which is beautiful btw :D) and I’m finding the whole thing a little slow. For my application I will need much faster performance but I realise that I’m dealing with lots of images so I was looking for some advice.

Am I wasting lots of processor time sending a my bitmap buffer to the LCD? My tests didn’t show much of a speed increase when I reduced the size of the buffer in half.

Is there a way to update only small parts of the lcd to speed things up?

Is WPF much faster?

I’ve gone with the bitmap approach because that’s what I’m familiar with but I will listen to reason.

Other than these issues my experience with FEZ has been most positive.

Thanks in advance.
-Thom.

Thom,

Welcome to the forum!

I highly recommend to check this thread:

http://www.tinyclr.com/forum/1/1904/

It is hard to say without an example of your code.

Search for Pyxis2 on this forum and check the codeplex as well:
http://pyxis2.codeplex.com/

So here is my codes;

I’ve got a full screen background image that is loaded into the LCD buffer once. Then many small squares are drawn on top. Touching one of these squares changes it’s state and a different colour is displayed.

Interaction with the grid is slow and the screen only updates a couple of times a second. Really only very small pieces of the screen need to be updated at any time but i’ve not worked out how to do that yet.


using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using Microsoft.SPOT.Input;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Touch;
using GHIElectronics.NETMF.Hardware;
using System.Threading;

namespace BopperSequencer
{
    public class Program : Microsoft.SPOT.Application, IEventListener
    {
        static Bitmap bs = Resources.GetBitmap(Resources.BitmapResources.blue_small);
        static Bitmap bl = Resources.GetBitmap(Resources.BitmapResources.blue_large);
        static Bitmap rl = Resources.GetBitmap(Resources.BitmapResources.red_large);
        static Bitmap rs = Resources.GetBitmap(Resources.BitmapResources.red_small);

        private static byte currentEditChannel = 0;
        private static Channel[] channels = new Channel[16];

        static int tx, ty, ticker;

        public bool OnEvent(BaseEvent ev)
        {
            TouchEvent touchEvent = ev as TouchEvent;

            if (touchEvent != null)
            {
                tx = touchEvent.Touches[0].X;
                ty = touchEvent.Touches[0].Y;
                if (tx > 18 && ty > 64 && tx < (18 + (16 * 18)) && ty < (64 + (18 * 16)))
                {
                    tx -= 18;
                    ty -= 64;
                    tx /= 18;
                    ty /= 18;
                    //Debug.Print("FLIP CELL AT " + tx + " / " + ty);
                    flipCellAt(tx, ty);
                }
            }
            return true;
        }

        public static void Main()
        {
            // The start-up logo will take effect after the first reset
            Bitmap logo = Resources.GetBitmap(Resources.BitmapResources.splash_logo);
            Configuration.StartUpLogo.Set(logo.GetBitmap(), (SystemMetrics.ScreenWidth - logo.Width) / 2, (SystemMetrics.ScreenHeight - logo.Height) / 2);
            Configuration.LCD.EnableLCDBootupMessages(false);
            Program myApplication = new Program();

            LCD = myApplication.CreateLCD();

            // Create the object that configures the GPIO pins to buttons.
            GPIOButtonInputProvider inputProvider = new GPIOButtonInputProvider(null);

            Touch.Initialize(myApplication);
            const int CAL_POINTS = 5;
            short[] sx = new short[CAL_POINTS] { 400, 80, 80, 720, 720 };
            short[] sy = new short[CAL_POINTS] { 240, 48, 432, 432, 48 };
            short[] cx = new short[CAL_POINTS] { 510, 159, 160, 846, 855 };
            short[] cy = new short[CAL_POINTS] { 494, 233, 765, 754, 236 };
            Microsoft.SPOT.Touch.Touch.ActiveTouchPanel.SetCalibration(CAL_POINTS, sx, sy, cx, cy);
            channels[0] = new Channel(0);

            while (true)
            {
                ticker++;
                if (ticker == 16) ticker = 0;
                
                //draw main grid
                for (int y = 0; y < 16; y++)
                {
                    for (int x = 0; x < 16; x++)
                    {
                        if (isCurrentChannelCellOn(x, y))
                            LCD.DrawImage(18 + x * 18, 64 + y * 18, rs, 0, 0, 16, 16);
                        else
                            LCD.DrawImage(18 + x * 18, 64 + y * 18, bs, 0, 0, 16, 16);
                    }
                }
                
                //draw the limiter
                for (int x = 0; x < 16; x++)
                {
                    LCD.DrawImage(18 + x * 18, 33, rs, 0, 0, 16, 16);
                }

                //draw the ticker
                for (int x = 0; x < 16; x++)
                {
                    if (ticker == x)
                        LCD.DrawImage(18 + x * 18, 64 + 288 + 13,rs,0,0, 16, 16);
                    else
                        LCD.DrawImage(18 + x * 18, 64 + 288 + 13, rs, 0, 0, 16, 16);
                }
    
                //draw pattern grid
                for (int y = 0; y < 4; y++)
                {
                    for (int x = 0; x < 8; x++)
                    {
                        LCD.DrawImage(18 + x * (36), 64 + 288 + 13 + 28 + (y * 18), rl, 0, 0, 34, 16);
                    }
                }

                LCD.Flush(0,0,400,400);
            }

        }

        private static bool isCurrentChannelCellOn(int x, int y)
        {
            return channels[currentEditChannel].getCurrentFrame().getCell(x, y).state == Cell.CELL_NOTE_ON;
        }

        private static void flipCellAt(int x, int y)
        {
            Cell c = channels[currentEditChannel].getCurrentFrame().getCell(x, y);
            if (c.state == Cell.CELL_NOTE_ON)
                c.state = Cell.CELL_NOTE_OFF;
            else
                c.state = Cell.CELL_NOTE_ON;
        }

        private static Bitmap LCD;

        private Bitmap CreateLCD()
        {
            Bitmap LCD = Resources.GetBitmap(Resources.BitmapResources.background);
            return LCD;
        }

        private void OnButtonUp(object sender, RoutedEventArgs evt)
        {
            ButtonEventArgs e = (ButtonEventArgs)evt;

            // Print the button code to the Visual Studio output window.
            Debug.Print(e.Button.ToString());
        }


    }
}


You get better performance on 320x240 screen. You have 800x480 pixels which works nicely with EMX but not if you are moving things on the screen. If this is what you need then you may want to consider ChipworkX? It is about 6 times faster

Nothing on the screen has to move around, There are just a lot of buttons that need to change colour. As they don’t change size I’ve had a similar setup working on an LCD running with a much slower processor by selectively redrawing the screen.

Is there any way of doing this? 99% of the time I will only need to update a 16x16 region of the image and if this is slow because I’m waiting for LCD.Flush() to return then that might help.

Otherwise, am I losing speed just by running an LCD of that size?

I’d rather not have to buy another, smaller, screen. :frowning:

I always hate seeing Multiplication and division in main loops

Flush is relatively quick (I have the 4.3 ) and pretty good response from the touch panel… I draw 96 x 96 tiles which are divisible by 8.

I know NETMF math is native and probably quite quick… If I had this loop I would optimise tiles to 16 pixels apart and " << 4 " instead of " * 18 "…

I also forgot once, that its not a desktop PC and has limitations.

Thomas (Skewworks) has really good code that is well optimised (I think he has a 7" on a cobra aswell.

Cheers Ian

I’ve tried various versions of this code and even when most of those loops are removed the speed stays pretty much the same. If my speed issues were related to unoptimised multiplication before I’ve implemented any logic at all then I’m in real trouble.

For my application I need to make sure my app logic can run in less than 215 ms. This includes, at most, updating one 16x16 area of the screen and one 16x32 area of the screen. If I can’t update only these areas then I may have a problem.

I will do some testing tonight to find out if the flush is what is taking up all the time. If it is (or if just using such a big screen is slowing everything down) then I may have to change to another screen size.

Thanks for all the replies and suggestions, this is a very friendly community :slight_smile: Even if this device is not suitable for my current application then I’m sure I will find another cool use for it.

graphics is fast if you have pr-made Bitmap objects and then when you need the, you just draw that pre-made bitmap on the LCD main bitmap.

Look at this video please microframeworkprojects.com

we have a little video game running so the update rate is reasonable.

EMX has a lot of RAM so use that for your advantage

Gus,

I think that’s what I’m trying in the code above.

I have downloaded that game example, I will compare it to my code when I get home tonight.

Then I will start timing things, see if I can work out what’s eating the time up.

Cheers :slight_smile:

Thom,

I’ve done a fair amount of messing around with graphics on the Cobra; I know your woes and, I think, the best way to address them.

First, if you’re using TinyCore [italic]for the love of all that is good and just rip it out right now![/italic] TinyCore is what runs WPF and so much as having a reference to it will severely slow down your efforts. If you’re working about collecting touches without it I have examples for that on Fezzer.com & in Pyxis 2.

Secondly, those for loops; if there is anyway you can get away without the loops do so. I’ve found they slow things down on the graphic end a good deal, because they’re managed loops.

Try those out and let me know if you still have issues.

Skewworks, thanks for the tips, I’ve removed tinycore and will look into handling touches again later on. Right now I’ll concentrate on getting the performance I need.

I’ve done some more tests and found some interesting results. The flush really doesn’t seem to be eating up the time. (I’d really thought that would be it)

I tried removing the main grid loop and it sped up everything a huge amount. I figured that It would be all the calls to LCD.DrawBitmap so I implemented a system like the one in my previous project which has a flag for each cell telling the system that it needs to be drawn so it only draws each cell once. The performance was the same.

Looks like I’m spending my whole time in that managed loop just like some of you had suggested. I will try and write a smarter version that doesn’t need to check each cell every loop.

Thanks again for all your suggestions.

So with some crazy optimisations I’ve managed to get the loop drawing full screen at 49-50 ms per frame (150 when gc)

I’ve optimised out all the multiplications with a pre-calculated array lookup but that made no measurable difference.

That means in the worst case I’ve still got about 50ms to play with. I will measure again once I’ve got my touch code back in.

@ screwworks

First of all thanks for your work (pyxis2)! I downloaded the software from your website and i ran it on my Fez Cobra because my graphics are very slow, it all looked good but now it stucks at a screen that is changing color (Red, green, blue, Black, white, blocks etc). I wonder if u can help me fix this. Or help me to remove pyxis2, because i’am just starting with the Fez Cobra and have a lack of experience:(

@ jvers

I’ve been thru this a couple of times. One of the great things about these little computers is how easy it is to reload them back to their factory state and just start over with a clean slate. Take a look at the “Updating the Firmware” video out on YouTube (from the downloads section here on tinyclr) - YouTube it walks you thru the entire process, I have done it and it is very painless. Watch the video a couple of times, get everything set up ahead of time (TeraTerm, MFDeploy, file locations,etc) and it will take you only a few minutes to complete.

pyxis2 is basically an application. Just load another application to remove it.

Mike, I think know what he is referring to…pyxis2 does leave a few things behind, some not all that important, like the skeworks startup screen. I also had some issues after loading another app with getting my touchscreen callibration set up again, not sure why. For me it was easier to just reload everything back to the factory settings.

It sounds to me like he is referring to the bootloader lcd test cycle. The thing I got on my lcd after i’d updated but before deploying any code. it goes red, green, blue, black, white, chess board.

I just deployed a new app.

@ mike
If i debug another project it loads (usb is working leds go on etc, but i still see the boot cycle instead of my application:( (UPDATE: even my buttons work! i can’t see them because i see only the bootloader but they work!)

@ Stephen Hamilton thanks for the tutorial but when i have it in restore mode and i want to select the driver windows says the best driver is already installed :frowning: so i can’t load the driver
UPDATE! i just finished the complete tutorial but the red, green, blue etc screen is still on my device :(!! please help me

- YouTube here is a video of the changing screen

Maybe it has something to do with the error i get while debugging Pyxis2:
The thread ‘’ (0x2) has exited with code 0 (0x0).
#### Exception System.Exception - 0xffffffff (1) ####
#### Message:
#### GHIElectronics.NETMF.IO.PersistentStorage::.ctor [IP: 0000] ####
#### Skewworks.Pyxis.Kernel.DriveManager::MountSD [IP: 0007] ####
#### Skewworks.Pyxis.Kernel.DriveManager::.ctor [IP: 0038] ####
#### Skewworks.Pyxis.Kernel.PyxisAPI::.ctor [IP: 0062] ####
#### Skewworks.Pyxis.Program::Main [IP: 0003] ####
A first chance exception of type ‘System.Exception’ occurred in GHIElectronics.NETMF.IO.dll
The thread ‘’ (0x5) has exited with code 0 (0x0).

When you do not have the correct lcd configuration, the 7" display start showing these rotating colors. This is normal.

Start with small program and set the LCD configuration as the documentation shows

@ Gus
Thanks for your reply, were just forgotten that part (Shame on us :-[ )
Now can successfully load my projects again!

Can i make some sort of check for the display being configured?