N18 display module usage

I’m sourcing a display for a project using the FEZ Cerberus board. Is the N18 module compatible with the cerb board? The example use code shows use of bitmaps being sent to the N18. Can someone show code for sending simple text to the display? I’d hate to have to figure out how to update a big bitmap byte sequence each time just to update some text on it. Some graph examples would be nice also. I’m assuming you’d need to store the bitmaps on an SD card for grabbing as needed? How would you put it in the board otherwise? Thanks.

Technically the N18 display works with the Cerberus. Drawing text is as simple as drawing text on a bitmap and then render the bitmap to the screen.

HOWEVER, keep in mind that due to the limited memory on the Cerberus you cannot have a single bitmap that matches the screen size. So you need to break the image up into portions and render the entire screen piece by piece to the display. I think there is documentation on this for the OLED display on the Cerberus, the principal is the same. You need to manage this segmentation in your code.

Here is a quick and dirty example of rendering text to a bitmap and then rendering that to the N18 display that I just tested on the Cerberus. OF course it is very simplistic but at least demonstrates that the Cerb can use this display.


using Microsoft.SPOT;
using Microsoft.SPOT.Presentation.Media;

namespace CerbN18Test
{
    public partial class Program
    {
        Font _font;

        void ProgramStarted()
        {
            _font = Resources.GetFont(Resources.FontResources.small);

            string message = "Hello";
            int width;
            int height;

            // Calculate the size bitmap required to render the text
            _font.ComputeExtent(message, out width, out height);

            // Create a bitmap for the text
            Bitmap bmp = new Bitmap(width, height);

            // Render the text to the bitmap
            bmp.DrawText(message, _font, Colors.Green, 0, 0);
            
            // Render the bitmap to the screen
            display_N18.Draw(bmp, 0, 0);

            // Use Debug.Print to show messages in Visual Studio's "Output" window during debugging.
            Debug.Print("Program Started");
        }
    }
}

Wow! That actually seems FEZ now! Thanks!

What about a simple bar graph example. Would like to make a simple signal indicator for the cellular module. Kind of like on a normal cell phone. Thanks.

This gets better :slight_smile: the next release will allow you to use full screen bitmap, even WPF and glide :wink:

3 Likes

Ok, I’ve order 2 of these modules to tinker with. Am I correct in thinking that I will have to load the BMPs from an SD card or do I add it as a resource some how in VS? I’m thinking I would have different versions of a cellular signal BMP file for different signal levels to show. If I change one area with each new file as signal changes, will I have to reload all the other sections of the screen as well? The source code looks as though it just refreshes at the x,y coordinates you tell it to redraw. Is that correct?

With Cerberus?

@ logictechs - You could load the bitmaps directly from the SD card or from the resources. What I do with the Cerberus is convert the bitmaps to the TinyBitmap format and I store that in the resources. That way you do not incur the memory overhead of .NETMF converting from the Bitmap to TinyBitmap. I just have a little desktop app that I run on my bitmaps which converts them. if anyone is interested I will clean-up the code and share it on code share.

Just to give an alternative option, you could also dynamically generate the bitmap. For example the following code shows a battery level indicator with configurable outline color, indicator level color etc. This has the advantage that you do not have multiple bitmaps, only one which is used to render the different states dynamically.

And yes, you do not need to update the entire screen, Display_N18.Draw will only update the portion of the screen that is affected.

Again just a quick example so there is no input validation etc.


using Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation.Media;

namespace CerbN18Test
{
    public partial class Program
    {
        Font _font;

        void ProgramStarted()
        {
            _font = Resources.GetFont(Resources.FontResources.small);

            string message = "Battery Level Indicator";
            int width;
            int height;

            // Calculate the size bitmap required to render the text
            _font.ComputeExtent(message, out width, out height);

            // Create a bitmap for the text
            Bitmap bmp = new Bitmap(width, height);

            // Render the text to the bitmap
            bmp.DrawText(message, _font, Colors.Yellow, 0, 0);
            
            // Render the bitmap to the screen
            display_N18.Draw(bmp, 0, 0);

            BatteryStateIndicator bi = new BatteryStateIndicator(100, 15, Colors.White, Colors.Green, Colors.Red);
            
            var level8 = bi.Render(8);
            display_N18.Draw(level8, 0, 20);

            var level50 = bi.Render(50);
            display_N18.Draw(level50, 0, 40);

            var level100 = bi.Render(100);
            display_N18.Draw(level50, 0, 60);

            // Use Debug.Print to show messages in Visual Studio's "Output" window during debugging.
            Debug.Print("Program Started");
        }
    }

    public class BatteryStateIndicator
    {
        private Bitmap _bmp;
        private Color _outlineColor;
        private Color _indicatorColor;
        private Color _indicatorLowColor;
        private int _tipWidth;
        private int _tipHeight;
        private int _tipTop;

        public BatteryStateIndicator(int width, int height, Color outlineColor, Color indicatorColor, Color indicatorLowColor)
        {
            _bmp = new Bitmap(width, height);
            _outlineColor = outlineColor;
            _indicatorColor = indicatorColor;
            _indicatorLowColor = indicatorLowColor;

            _tipWidth = System.Math.Max(2, (int)(width * 0.03));
            _tipHeight = System.Math.Max(3, height * 2 / 5);
            _tipTop = (_bmp.Height - _tipHeight) / 2;
        }

        public Bitmap Render(byte percentage)
        {
            int rightEdge = _bmp.Width - _tipWidth;
            int fillWidth = (int)((rightEdge - 4) * (percentage / 100.0));
            
            _bmp.DrawRectangle(_outlineColor, 1, 0, 0, rightEdge, _bmp.Height, 0, 0, 0, 0, 0, Color.Black, 0, 0, Bitmap.OpacityOpaque);
            _bmp.DrawRectangle(_outlineColor, 1, rightEdge - 1, _tipTop, _tipWidth, _tipHeight, 0, 0, 0, 0, 0, Color.Black, 0, 0, Bitmap.OpacityOpaque);

            Color indicatorColor = _indicatorColor;
            if (percentage < 10)
            {
                indicatorColor = _indicatorLowColor;
            }
            _bmp.DrawRectangle(indicatorColor, 1, 2, 2, fillWidth, _bmp.Height - 4, 0, 0, indicatorColor, 0, 0, indicatorColor, fillWidth + 2, 0, Bitmap.OpacityOpaque);

            return _bmp;
        }
    }
}


Wow that FEZ now! Thanks for the help taylorza!

Now that’s a silly question… :wink:

But he keeps asking :wink: :slight_smile:

Ok, I’ll bite. Please share the little desktop app that you run on my bitmaps which converts them at code share. Thanks!

Ok, I guess that was a silly question :). It just does not do anything special so I did not think it was really worth wasting a code share entry. But I will add some error check and post it this weekend.

Got my new toys, I mean gadgets today! The N18 is a pretty awesome and FEZ module so far! I have it running on a Cerbuino Bee with an accelerometer. Was able to modify the bar graphing code a bit to display the values from the sensor.

Here’s the modified code to create the bars:

private Bitmap Render(double percentage)
        {
            _bmp = new Bitmap(100, 15);
            _outlineColor = Colors.White;
            _indicatorColor = Colors.Green;
            _indicatorLowColor = Colors.Red;

            _tipWidth = 0;// System.Math.Max(2, (int)(100 * 0.03));
            _tipHeight = 0;// System.Math.Max(3, 15 * 2 / 5);
            _tipTop = 0;// (_bmp.Height - _tipHeight) / 2;

            Color indicatorColor = _indicatorColor;
            if (percentage < 0)
            {
                percentage = System.Math.Abs(percentage);
                indicatorColor = _indicatorLowColor;
            }

            int rightEdge = _bmp.Width - _tipWidth;
            //int fillWidth = (int)((rightEdge - 4) * (percentage / 100.0));
            int fillWidth = (int)((rightEdge - 4) * percentage);

            _bmp.DrawRectangle(_outlineColor, 1, 0, 0, rightEdge, _bmp.Height, 0, 0, 0, 0, 0, Color.Black, 0, 0, Bitmap.OpacityOpaque);
            _bmp.DrawRectangle(_outlineColor, 1, rightEdge - 1, _tipTop, _tipWidth, _tipHeight, 0, 0, 0, 0, 0, Color.Black, 0, 0, Bitmap.OpacityOpaque);

            
            _bmp.DrawRectangle(indicatorColor, 1, 2, 2, fillWidth, _bmp.Height - 4, 0, 0, indicatorColor, 0, 0, indicatorColor, fillWidth + 2, 0, Bitmap.OpacityOpaque);

            return _bmp;
        }

A positive value is green, negative is red.

Here’s the code to use the bmp:

void displaysignal(double percentage,uint x,uint y)
        {
            display_N18.Draw(Render(percentage), x, y);
        }
3 Likes

@ logictechs - Nice! Just one note, you should avoid re-creating the bitmap every time, rather allocate the bitmap once and then reuse it to draw each of the graphs. This will reduce the number of objects created/destroyed which will in turn reduce the number of Garbage collections you incur, which on these devices can be a huge win.

Btw. I posted the code to convert from a desktop image to the raw TinyBitmap format.

Thanks for the info and post. To reuse the bmp, I would simply declare it at the top like:


static mybmp = new Bitmap(100,15)

;

Right? Then simply change it on the fly with the rendering function as needed?

@ logictechs - That is correct.