Hi Gents,
I supplied it from laboratory power supply and result is the same. Tried with few different LCD … same results.
I have something like that:
https://pl.aliexpress.com/wholesale?catId=0&initiative_id=SB_20180629080107&SearchText=1%2C44+tft
I have plugged:
PC0-> CS
PC1->Reset
PC2-> Shield light
PC3-> A0 (RS)
PB13-> SCK
PB15-> SDA
SPI2 channel MOSI, MISO was not connected but I tried to pull it dwon and up, always with same result.
I have checked also your suggestion Gus with separate thread and led. Led freezes also.
Below you can find my code:
using GHIElectronics.TinyCLR.Pins;
using System;
using System.Diagnostics;
using System.Threading;
using System.Drawing;
namespace TinyCLRSample
{
class Program
{
private static Random random = new Random();
public static string RandomString(int length)
{
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var stringChars = new char[length];
var random = new Random();
for (int i = 0; i < stringChars.Length; i++)
{
stringChars[i] = chars[random.Next(chars.Length)];
}
return new String(stringChars);
}
static void Main()
{
Thread.Sleep(1000);
DisplayN18 n18 = new DisplayN18(G30.SpiBus.Spi2, G30.GpioPin.PC1, G30.GpioPin.PC3, G30.GpioPin.PC2, G30.GpioPin.PC0, true);
Thread.Sleep(100);
while (true)
{
Thread.Sleep(50);
string d = RandomString(5);
n18.DrawText(20, 20, d,2, Color.Red,Color.Green);
}
}
}
}
N18Driver:
using System;
using GHIElectronics.TinyCLR.Devices.Gpio;
using System.Threading;
using GHIElectronics.TinyCLR.Devices.Spi;
using System.Drawing;
using TinyCLRSample.dev;
namespace TinyCLRSample
{
/// <summary>A CharacterDisplay module for Microsoft .NET Gadgeteer</summary>
public class DisplayN18
{
#region constants
private const byte St7735Madctl = 0x36;
private const byte MadctlMy = 0x80;
private const byte MadctlMx = 0x40;
private const byte MadctlMv = 0x20;
private const byte MadctlBgr = 0x08;
#endregion
#region fields
private readonly SpiDevice _dev;
private readonly GpioPin _resetPin;
private readonly GpioPin _backlightPin;
private readonly GpioPin _rsPin;
private readonly byte[] _byteArray;
private readonly ushort[] _shortArray;
private bool _isBgr;
public enum DisplayOrientation
{
Square = 0,
Portrait = 0xC8,
Landscape = 0x68
}
private readonly DisplayOrientation _orientation;
#endregion
#region property
public int Height { get; }
public int Width { get; }
/// <summary>Whether or not the backlight is enabled.</summary>
public bool BacklightEnabled
{
get => _backlightPin.Read() == GpioPinValue.High;
set => _backlightPin.Write(value ? GpioPinValue.High : GpioPinValue.Low);
}
#endregion
#region constructor
/// <summary>
/// Constructs a new instance.
/// </summary>
/// <param name="spiControllerName"></param>
/// <param name="digitalResetPin3"> Pin3 of S socket which is the reset pin</param>
/// <param name="digitalBackLightPin4">Pin4 of S socket which is the backlight pin</param>
/// <param name="digitalRsPin5">Pin5 of S socket which is the RS pin</param>
/// <param name="digitalCsPin6"></param>
/// <param name="isBrg">Set to true if color must be in BRG order, false for RGB order mode</param>
public DisplayN18(string spiControllerName, int digitalResetPin3, int digitalBackLightPin4, int digitalRsPin5, int digitalCsPin6, bool isBrg = false)
{
_orientation = DisplayOrientation.Square;
_byteArray = new byte[1];
_shortArray = new ushort[2];
_isBgr = isBrg;
var controller = GpioController.GetDefault();
_resetPin = controller.OpenPin(digitalResetPin3);
_resetPin.SetDriveMode(GpioPinDriveMode.Output);
_backlightPin = controller.OpenPin(digitalBackLightPin4);
_backlightPin.SetDriveMode(GpioPinDriveMode.Output);
BacklightEnabled = false;
_rsPin = controller.OpenPin(digitalRsPin5);
_rsPin.SetDriveMode(GpioPinDriveMode.Output);
var settings = new SpiConnectionSettings(digitalCsPin6)
{
ClockFrequency = 40000000, // 12 000 kHz
Mode = SpiMode.Mode0,
SharingMode = SpiSharingMode.Exclusive,
DataBitLength = 8
};
_dev = SpiDevice.FromId(spiControllerName, settings);
Reset();
ConfigureDisplay();
Height = 128;
Width = 128;
Clear();
BacklightEnabled = true;
}
#endregion
#region methods
public void Clear()
{
var data = new byte[256];
for (int i = 0; i < 128; i++)
{
DrawRaw(data, 0, i, 128, 1);
}
}
private void ConfigureDisplay()
{
WriteCommand(0x11);//Sleep exit
Thread.Sleep(120);
//ST7735R Frame Rate
WriteCommand(0xB1);
WriteData(0x01); WriteData(0x2C); WriteData(0x2D);
WriteCommand(0xB2);
WriteData(0x01); WriteData(0x2C); WriteData(0x2D);
WriteCommand(0xB3);
WriteData(0x01); WriteData(0x2C); WriteData(0x2D);
WriteData(0x01); WriteData(0x2C); WriteData(0x2D);
WriteCommand(0xB4); //Column inversion
WriteData(0x07);
//ST7735R Power Sequence
WriteCommand(0xC0);
WriteData(0xA2); WriteData(0x02); WriteData(0x84);
WriteCommand(0xC1); WriteData(0xC5);
WriteCommand(0xC2);
WriteData(0x0A); WriteData(0x00);
WriteCommand(0xC3);
WriteData(0x8A); WriteData(0x2A);
WriteCommand(0xC4);
WriteData(0x8A); WriteData(0xEE);
WriteCommand(0xC5); //VCOM
WriteData(0x0E);
SetOrientationOverride(DisplayOrientation.Square);
//ST7735R Gamma Sequence
WriteCommand(0xe0);
WriteData(0x0f); WriteData(0x1a);
WriteData(0x0f); WriteData(0x18);
WriteData(0x2f); WriteData(0x28);
WriteData(0x20); WriteData(0x22);
WriteData(0x1f); WriteData(0x1b);
WriteData(0x23); WriteData(0x37); WriteData(0x00);
WriteData(0x07);
WriteData(0x02); WriteData(0x10);
WriteCommand(0xe1);
WriteData(0x0f); WriteData(0x1b);
WriteData(0x0f); WriteData(0x17);
WriteData(0x33); WriteData(0x2c);
WriteData(0x29); WriteData(0x2e);
WriteData(0x30); WriteData(0x30);
WriteData(0x39); WriteData(0x3f);
WriteData(0x00); WriteData(0x07);
WriteData(0x03); WriteData(0x10);
WriteCommand(0x2a);
WriteData(0x00); WriteData(0x00);
WriteData(0x00); WriteData(0x7f);
WriteCommand(0x2b);
WriteData(0x00); WriteData(0x00);
WriteData(0x00); WriteData(0x9f);
WriteCommand(0xF0); //Enable test command
WriteData(0x01);
WriteCommand(0xF6); //Disable ram power save mode
WriteData(0x00);
WriteCommand(0x3A); //65k mode
WriteData(0x05);
WriteCommand(0x29); //Display on
}
/// <summary>Draws an image to the screen.</summary>
/// <param name="bitmap">The bitmap to be drawn to the screen</param>
/// <param name="x">Starting X position of the image.</param>
/// <param name="y">Starting Y position of the image.</param>
public void DrawBitmap(Bitmap bitmap, int x, int y)
{
var vram = new byte[bitmap.Width * bitmap.Height * 2];
NativeBitmapConverter(bitmap, vram);
DrawRaw(vram, x, y, bitmap.Width, bitmap.Height);
}
/// <summary>
/// Draws a string to the screen
/// </summary>
/// <param name="str">String to display</param>
/// <param name="font">Font used to display text</param>
/// <param name="x">Starting X position of the text</param>
/// <param name="y">Starting Y position of the text</param>
/// <param name="color">Color used to display text</param>
public void DrawString(string str, Font font, int x, int y, Color color)
{
var image = new Bitmap(12 * str.Length, 15);
var grap = Graphics.FromImage(image);
grap.DrawString(str, font, new SolidBrush(color), 0, 0);
DrawBitmap(image, x, y);
}
/// <summary>
/// Draw a fill rectangle on display
/// </summary>
/// <param name="x">x coordinate of pixel</param>
/// <param name="y">y coordinate of pixel</param>
/// <param name="width">width of rectangle</param>
/// <param name="height">height of rectangle</param>
/// <param name="color">color of rectangle</param>
public void DrawFillRect(int x, int y, int width, int height, Color color)
{
// Prepare data
byte[] data = new byte[width * height * 2];
byte[] a = color.To565ByteArray();
for (int i = 0; i < width * height; i++)
{
data[i * 2] = a[0];
data[i * 2 + 1] = a[1];
}
DrawRaw(data, x, y, width, height);
}
public void DrawChar(int x, int y, char c, int size, Color colorFont, Color colorBackground)
{
if ((x >= Width) || // Clip right
(y >= Height) || // Clip bottom
((x + 6 * size - 1) < 0) || // Clip left
((y + 8 * size - 1) < 0)) // Clip top
return;
for (byte i = 0; i < 6; i++)
{
byte line;
if (i == 5)
line = 0x0;
else
//line = pgm_read_byte(font+(c*5)+i);
line = TinyCLRSample.dev.Glcfont.MEM[(c * 5) + i];
for (byte j = 0; j < 8; j++)
{
if ((line & 0x1) != 0)
{
if (size == 1) // default size
DrawPixel(x + i, y + j, colorFont);
else
{ // big size
DrawFillRect(x + (i * size), y + (j * size), size, size, colorFont);
}
}
else
{
if (size == 1) // default size
DrawPixel(x + i, y + j, colorBackground);
else if (colorBackground != Color.Transparent)
{ // big size
DrawFillRect(x + i * size, y + j * size, size, size, colorBackground);
}
}
line >>= 1;
}
}
}
public void DrawLine(int startX, int startY, int endX, int endY, Color color)
{
int steep = (System.Math.Abs(endY - startY) > System.Math.Abs(endX - startX)) ? 1 : 0;
if (steep != 0)
{
int tmp;
tmp = startX;
startX = startY;
startY = tmp;
tmp = endX;
endX = endY;
endY = tmp;
}
if (startX > endX)
{
int tmp;
tmp = startX;
startX = endX;
endX = tmp;
tmp = startY;
startY = endY;
endY = tmp;
}
int dx, dy;
dx = endX - startX;
dy = System.Math.Abs(endY - startY);
int err = dx / 2;
int ystep = 0;
if (startY < endY)
{
ystep = 1;
}
else
{
ystep = -1;
}
for (; startX < endX; startX++)
{
if (steep != 0)
{
DrawPixel(startY, startX, color);
}
else
{
DrawPixel(startX, startY, color);
}
err -= dy;
if (err < 0)
{
startY += ystep;
err += dx;
}
}
}
public void DrawText(int x, int y, string txt, int size, Color colortext, Color colorBackground, bool wrap = true)
{
int cursorX = x;
int cursorY = y;
char[] text = txt.ToCharArray();
foreach (char c in text)
{
if (c == '\n')
{
cursorY += size * 8;
cursorX = 0;
}
else if (c == '\r')
{
// skip em
}
else
{
DrawChar(cursorX, cursorY, c, size, colortext, colorBackground);
cursorX += size * 6;
if (wrap && (cursorX > (Width - size * 6)))
{
cursorY += size * 8;
cursorX = 0;
}
}
}
}
public void DrawPixel(int x, int y, Color color)
{
byte[] a = color.To565ByteArray();
DrawRaw(a, x, y, 1, 1);
}
private void DrawRaw(byte[] rawData, int x, int y, int width, int height)
{
var orientedWidth = Width;
var orientedHeight = Height;
if (x > orientedWidth || y > orientedHeight)
return;
if (x + width > orientedWidth)
width = orientedWidth - x;
if (y + height > orientedHeight)
height = orientedHeight - y;
SetClippingArea(x, y, width - 1, height - 1);
WriteCommand(0x2C);
WriteData(rawData);
}
private void NativeBitmapConverter(Bitmap bitmap, byte[] vram)
{
// TODO: method must be optimized: for display on full screen in FEZ Spider II it takes around 25 sec.
int idx = 0;
for (int j = 0; j < bitmap.Height; j++)
for (int i = 0; i < bitmap.Width; i++)
{
var ab = bitmap.GetPixel(i, j).To565ByteArray();
vram[idx] = ab[0];
vram[idx + 1] = ab[1];
idx += 2;
}
}
private void Reset()
{
_resetPin.Write(GpioPinValue.Low);
Thread.Sleep(150);
_resetPin.Write(GpioPinValue.High);
}
private void SetClippingArea(int x, int y, int width, int height)
{
_shortArray[0] = (ushort)x;
_shortArray[1] = (ushort)(x + width);
WriteCommand(0x2A);
WriteData(_shortArray);
_shortArray[0] = (ushort)y;
_shortArray[1] = (ushort)(y + height);
WriteCommand(0x2B);
WriteData(_shortArray);
}
private void SetFormat(DisplayOrientation orientation, bool isBgr)
{
WriteCommand(St7735Madctl);
var bgr = (byte)(isBgr ? MadctlBgr : 0);
switch (orientation)
{
case DisplayOrientation.Square: WriteData((byte)(0x00 | bgr)); break;
case DisplayOrientation.Portrait: WriteData((byte)(MadctlMx | MadctlMy | bgr)); break;
case DisplayOrientation.Landscape: WriteData((byte)(MadctlMv | MadctlMy | bgr)); break;
default: throw new ArgumentException("orientation");
}
}
private void SetOrientationOverride(DisplayOrientation orientation)
{
SetFormat(orientation, _isBgr);
Thread.Sleep(1);
}
/// <summary>Swaps the red and blue channels if your display has them reversed.</summary>
public void SwapRedBlueChannels()
{
_isBgr = !_isBgr;
SetFormat(_orientation, _isBgr);
}
private void WriteCommand(byte command)
{
byte[] byteArray = new byte[1];
byteArray[0] = command;
_rsPin.Write(GpioPinValue.Low);
_dev.Write(byteArray);
}
private void WriteData(byte data)
{
byte[] byteArray = new byte[1];
byteArray[0] = data;
WriteData(byteArray);
}
private void WriteData(byte[] byteArray)
{
_rsPin.Write(GpioPinValue.High);
_dev.Write(byteArray);
}
private void WriteData(ushort[] data)
{
_rsPin.Write(GpioPinValue.High);
foreach (ushort us in data)
{
// Data must be sent in reverse order
byte[] bData = BitConverter.GetBytes(us);
byte[] dataToSend = new byte[bData.Length];
for (int i = 0; i < bData.Length; i++)
{
dataToSend[dataToSend.Length - 1 - i] = bData[i];
}
_dev.Write(dataToSend);
}
}
#endregion
}
public static class DisplayN18Extension
{
public static byte[] To565ByteArray(this Color color)
{
byte[] ba = new byte[2];
var c = color.To565Color();
ba[0] = (byte)(((c.R & 0x1f) << 3) | ((c.G >> 3) & 0x07));
ba[1] = (byte)(((c.G & 0x07) << 5) | (c.B & 0x1f));
return ba;
}
private static Color To565Color(this Color color)
{
var c = Color.FromArgb((byte)(color.R / 255.0 * 31), (byte)(color.G / 255.0 * 63),
(byte)(color.B / 255.0 * 31));
return c;
}
}
}
Best Regards