Driving an AdaFruit ST7735 TFT display with a netduino

Color Flow

AdaFruit recently released a sweet little TFT display that I was dying to hook up to a netduino: the display features a resolution of 128*160 pixels, is capable of showing 18-bit colors and has a microSD card reader on the back of the breakout board. As usual, Limor wrote a nicely detailed Arduino tutorial showing how to connect the display and how to write sketches to drive it.

The Arduino driver relies on the ability of the Atmega168/368 to toggle digital lines extremely fast, which does not work well on the netduino due to the latency introduced by the .Net Micro Framework: even when configured to use hardware SPI, the Arduino driver constantly toggles a data/command output line, rspin below, which would be unbearably slow on the netduino if the same method were applied.

You can see an example of this in the drawPixel function:

 
void ST7735::drawPixel(uint8_t x, uint8_t y,uint16_t color) {
  if ((x >= width) || (y >= height)) return;
  setAddrWindow(x,y,x+1,y+1);
  // setup for data
  *portOutputRegister(rsport) |= rspin;
  *portOutputRegister(csport) &= ~ cspin;
  spiwrite(color >> 8);
  spiwrite(color);
  *portOutputRegister(csport) |= cspin;
}

Driving the ST7735 on the netduino

The  netduino has one advantage over the Arduino: it has plenty of RAM. So, instead of toggling I/O lines slowly all the time and using next to zero RAM, the netduino driver allocates a 40K buffer corresponding to the resolution of the display in 12-bit depth colors (16 bits per pixel) and leaves the ST7735 in ‘data’ mode upon initialization.

Drawing always happens on the internal buffer first. Then, whenever the actual display needs refreshing, the display I/O operations are performed using hardware SPI, blasting the entire 40K buffer. It may sound crazy but using this method on the netduino is faster than refreshing a single pixel while toggling an I/O line!

Take a look at the following netduino code to see how this works, compared to the Arduino driver drawPixel funtion above:

private void Initialize() {
<...>
DataCommand.Write(Command);
Write((byte)LcdCommand.DISPON);
Thread.Sleep(50);

DataCommand.Write(Command);
Write((byte)LcdCommand.NORON);  // normal display on
Thread.Sleep(10);

SetAddressWindow(0, 0, Width - 1, Height - 1);

DataCommand.Write(Data);
}

private void SetPixel(int x, int y, ushort color) {

if ((x < 0) || (x >= Width) || (y < 0) || (y >= Height)) return;
var index = ((y * Width) + x) * sizeof(ushort);
SpiBuffer[index] = (byte) (color >> 8);
SpiBuffer[++index] = (byte)(color);
}
 
public void Refresh() {
Spi.Write(SpiBuffer);
}

The caveat is that allocating a 40K buffer on the netduino does not leave room for much object allocation afterwards. In fact, memory is so tight that OutOfMemory exceptions will be common if not careful and planning your application accordingly.

Before going any further, let’s look at the display in action on the netduino. Please forgive the quality of the video as the camera on my phone doesn’t do justice to the display.

Pretty zippy, huh?

Some hacking required…

As I was trying to get the ST7735 display to work with the netduino, I discovered that the display would stop communicating when configuring SPI to run @ 10 MHz or above.

This is a huge issue for a couple reasons: the speed of the SPI bus determines the display frame rate on the netduino and secondly, mounting a microSD card on the netduino configures SPI to run @ 10 MHz minimum. No matter what. This meant that I could either use the display or the microSD card but never together, preventing scenarios such as loading pictures from the microSD card for display for instance.

Based on previous experience, I began suspecting that the CD4050B logic level-shifter on the ST7735 breakout board was the root cause of the issue and decided to take it out of the equation altogether by shorting out its pins so that it would no longer convert signals. Since the netduino works at a 3.3v logic level, there was no risk of damaging the display driver.

CD4050B - Before hack
CD4050B – Before hack
CD4050B - Before hack
CD4050B – After hack

Sure enough, eliminating the logic-level shifter allowed me to initialize SPI @ 40MHz on the netduino as well as using the the microSD card reader without any issues.

Connecting the AdaFruit ST7735 display to the netduino

  • netduino GND -> ST7735 GND
  • netduino Vcc (3.3v or 5.0v) -> ST7735 Vcc
  • netduino D8 (or other Dx pin) -> ST7735 RESET
  • netduino D7 (or other Dx pin) -> ST7735 D/C
  • netduino D10 -> ST7735 CARD_CS
  • netduino D9 (or other Dx pin) ->ST7735 TFT_CS
  • netduino D11 -> ST7735 MOSI
  • netduino D13 -> ST7735 SCK
  • netduino D12 -> ST7735 MISO

Note that the ST7735 LITE pin can be connected to netduino Vcc (3.3v or 5.0v) or any of the netduino’s PWM pins if you’d like to control the intensity of the display’s back light.

As always, you can find the code as part of the netduino.helpers library.

Conclusion

The AdaFruit ST7735 TFT is a fast, bright and convenient all-in-one display and microSD reader:

Using it on the netduino is sub-optimal for the time being due to the memory requirements involved in making the display work at a decent frame rate but, if used carefully, it is possible to achieve very cool results with it right now. Keep in mind that the memory requirement will eventually go away once the netduino starts supporting native ARM code with .Net Micro Framework 4.2, letting applications toggle I/O lines super fast.

Finally, my only wish is for AdaFruit Industries to consider producing versions of their products without built-in logic level-shifters as they can negatively impact some micro controllers such as the netduino.

Happy hacking!

Color Flow image courtesy of Bartelme Design

 

Update on 08/23/2011: here’s the same hack applied to the stand-alone version on the adafruit microSD card reader, this time with a 10K resistor between Vcc and Gnd to ensure that the electrical behavior of the chip remains stable.

 

 

 

 

About these ads

47 comments

  1. Pingback: Driving an Adafruit TFT Display with a Netduino « adafruit industries blog
  2. ladyada · May 29, 2011

    thanks for noting that the cd4050 is poor at high frequencies, we’ll look for a better 4050 that can handle higher speeds. the poor arduino maxes out at 4 mhz :) in the meantime, shorting the pins is a pretty good solution.

  3. Mario Vernari · May 29, 2011

    Fabien: the demo is amazing. I will try to do it with another TFT module as well.
    1- I wonder why they chosen an “ancient” CMOS chip, when it’s clear that there’s need for MHz frequencies.
    2- The shorts across the chip are not a good choice electrically speaking, because they places the chip in a unstable state, with high current consumption. However, I agree that it would be the easiest workaround.
    3- Funny (or sad) when you say “Netduino has plenty of RAM”…whaaa!…I own a Netduino Plus and the few RAM available is the major problem!
    Thank you very much indeed.
    Cheers

    • Mike Donovan · May 29, 2011

      > 2- The shorts across the chip are not a good choice electrically speaking, because they places the chip in a unstable state, with high current consumption.

      While you’ve got the iron out, why not just remove that chip completely?

      • Fabien Royer · May 29, 2011

        Removing the chip was not needed to get me unblocked at the time :)

    • Fabien Royer · May 29, 2011

      Thanks Mario :) Shorting out the pins is just a hack to get me unblocked while I was figuring things out.
      I should have soldered a large resistor (10M ohm) between Vcc and GND on the 4050 to deal with the electrical issue you pointed out.

      Cheers,
      -Fabien.

      • ericfort · May 29, 2011

        rather than the 10M resistor between Vcc and GND, what about just lifting these 2 pins off the board so they are not connected. the chip then should draw no power at all with signals simply traveling accross the solder bridges. this does seem to work with no issues. (tested before and after the mod with graphicstest-highspeed.pde on the arduino, will hook it to beagle bone soon as a display.

        Eric

      • Fabien Royer · May 29, 2011

        There’s always more than one way of doing things :)

  4. Pingback: Electronics-Lab.com Blog » Blog Archive » Driving an Adafruit TFT Display with a Netduino
  5. ladyada · May 29, 2011

    in our defense…now that we examined the datasheet, it says max clk freq is 15MHz and thats assuming there’s no slewing issues (which you almost certainly will have with a breadboard and long wires)

  6. Pingback: Build a ‘Klout Klock’, track your influence and time. « Fabien's Bit Bucket
  7. AA (@Ark_kun) · May 29, 2011

    Hello.

    What do you think about using the “2.8” TFT Touch Shield for Arduino” ( http://www.adafruit.com/products/376 http://www.ladyada.net/products/tfttouchshield/ ) with Netduino? Looks like it has built-in RAM buffer, so the memory shouldn’t be an issue.

    I only started using my Netduino+ and I can’t asses the possibility/complexity of using this shield with Netduino.
    What are your thoughts?

    • Fabien Royer · May 29, 2011

      Hi there,
      I have started working on a driver and a hardware interface for 8 bit parallel addressing this touch screen. So, stay tuned :)
      Cheers,
      -Fabien.

      • marc young · May 29, 2011

        Any updates to this? I currently have a project nearing completion with the arduino + 2.8 tft touchscreen. Would like to port this to netduino =)

      • Fabien Royer · May 29, 2011

        Any update on what exactly? Not sure what you’re asking.

      • marc young · May 29, 2011

        You had said you were working on a driver for the 2.8 touchscreen a while ago, was curious if you made any progress

      • Fabien Royer · May 29, 2011

        Ah! Yes. Don’t waste your time trying to drive a QVGA touch screen, such as the 2.8″ TFT touchscreen by Adafruit, from a Netduino or Netduino+ 2: the latency of the .Net MF makes it dreadfully slow and literally unusable.
        With a Netduino, I would recommend taking a different approach, such as connecting a Nwazet Touch Display to a Netduino using the method I described in this article.

        I hope this helps.
        -Fabien.

      • Marc Young · May 29, 2011

        I’ve thought about getting a netduino, but I’d rather get the Netduino Plus 2 to play with. Will that touchscreen work with it even though the cabling is for the Go! ? Obviously I wouldn’t be able to use the cable provided but would it still be plug and play with the drivers/library?

      • Marc Young · May 29, 2011

        Nevermind i actually read your article you posted now =). I’ll look into it, thanks for the pointers!

  8. Niels van de Pas (@NVDPas) · May 29, 2011

    Hello,

    I’m looking around for things I can add to my “SpyCar”. I want to make a car with a camera, microphone and bleeper. Since this will be a remote control car, I have two Netduinos. Would you recommend this screen and the camera described in your most recent post communicating to each other using XBees?

    • Fabien Royer · May 29, 2011

      Hey Niels,

      Are you looking for a ‘live’ video feed from the spy car or are you interested in taking still snapshots on command? Knowing your requirements would help me better answer your questions.

      Cheers,
      -Fabien.

      • Niels van de Pas (@NVDPas) · May 29, 2011

        Hi Fabien,

        Sorry for my late answer. I would like to have a live video feed. The situation I would like most would be being able to store the video as well, but I’ll skip that for now, displaying a live feed is enough.

      • Fabien Royer · May 29, 2011

        Hi Niels,

        Given your live video requirement, I believe that the best approach is for you to use the NTSC output of the VC0706 camera, connected to a small video transmitter which would allow you to receive the live feed on a standard TV tuner. Taking snapshots, even at a small resolution will be too slow for live video. In addition, you’re have to find a way to decompress the JPEG images before displaying them on the ST7735 TFT screen, which will be very slow.

        I hope this helps.

        Cheers,
        -Fabien.

  9. Niels van de Pas (@NVDPas) · May 29, 2011

    Hi Fabien,

    Thank you for your reply, but I have one question still unanswered: can I use XBees for sending the data back and forth (instead of a video transmitter, as you mentioned)?

      • nvdpas · May 29, 2011

        Hello, here I’m again. Do I need the drivers from the netduino.helpers library for the camera and the screen? Or can I just connect the camera somehow to the transmitter and the screen in a way to the receiver?

      • Fabien Royer · May 29, 2011

        The netduino helpers library will make it easy for you to initialize the camera and turn the NTSC signal ON / OFF. However, there are other ways to achieve the same results. You may even be able to configure the camera to always output its NTSC signal through a one-time configuration using the VC0706 CommTool software. However, I have never tried doing it this way.

      • Fabien Royer · May 29, 2011

        Yes, it looks like this transmitter / receiver pair will do the trick. Just make sure that the transmitter will accept an NTSC video composite signal before you buy.
        Also, both of these require a 12v power supply so you’ll need to do a conversion to get regulated 5v DC to power the camera and the micro controller.

    • Fabien Royer · May 29, 2011

      Yes, you could you XBee transceivers as a replacement for a serial TTL cable to communicate with the camera and receive snapshot data.

      • nvdpas · May 29, 2011

        Hello Fabien,

        I want to thank you for your great help! Now I can buy the parts that are needed.

  10. Michiel · May 29, 2011

    Hi Fabian,

    thanks for your post. Would you know when the .net MF 4.2 arrives and how you would utilize with the TFT without the hack?

    • Fabien Royer · May 29, 2011

      Hi Michiel, The .NET MF should ship early this Fall from what I hear. About the ST7735 display: it can be used w/o the hack if you don’t need to access the microSD card on the display and you configure SPI to communicate below 10Mhz. I definitely plan on experimenting with .NET MF 4.2 and this display and will report my findings here. Stay tuned :)

  11. Peter Baines · May 29, 2011

    Hello Fabien,

    With the release of the .Net Micro Framework 4.2 are you going to be re-visiting this code to take account of the fast IO switching. I have already ported your lib to VB and created a DLL. Some examples drawing text would be very usefull too. Great work so far though. I have been coding in .net for about 15 years but am just moving into the Micro framwork.

    Cheers Pete.

    • Fabien Royer · May 29, 2011

      Hi Pete,

      Unfortunately, native ARM code support is not (yet) part of the .Net MF 4.2, so re-visiting this driver is moot at this point. About the text drawing: you should dig into the netduino helpers samples to see how the marquee drawing sample is implemented in the AdaFruit LPD8806 LED strip driver.

      Cheers,
      -Fabien.

  12. Kamal Mostafa · May 29, 2011

    Hi Fabien-

    Thanks very much for publishing your findings about the slow level shifter on the Adafruit 1.8″ TFT module. Not surprisingly, the issue also affects the Adafruit module when used with the Raspberry Pi. Readers may be interested to know that the (almost) identical module available from SainSmart doesn’t have this problem. I can drive the SainSmart 1.8″ TFT module just fine with 32 MHz SPI (8x faster than I can reliably drive the Adafruit module): http://www.whence.com/rpi/

    • Fabien Royer · May 29, 2011

      You’re welcome. Great work on that fb driver, btw :)
      Cheers,
      -Fabien.

  13. John · May 29, 2011

    Hi Fabien,

    Nice Article! I tried converting your driver code to .net micro 4.2. I had to change the ExtendedSpiConfiguration to SPI.Configuration because the BitsPerTransfer field was throwing an exception. Now, I get some communication with the display, but not correctly. There is a row of random colored pixels along two edges and all the drawing functions are distorted. Just curious if you have any ideas offhand on where to look for the problem?

    Thanks!
    John

    • Fabien Royer · May 29, 2011

      Hi John,

      Thanks :)

      Yes, changing ExtendedSpiConfiguration to SPI.Configuration is fine.
      ‘ExtendedSpiConfiguration’ used to be needed to configure variable bit SPI communication back in .Net MF 4.1.x and it may have been deprecated since then. It’s been a while since I touched the .Net MF and I have not kept up with the latest changes, so I don’t know for sure. About the “random colored pixels along two edges and all the drawing functions are distorted”: the two issues are likely caused by the same root cause which is the initialization of the IC driver which specifies the number of rows and columns. There may have been hardware changes since I wrote this driver, and it’s possible that the initialization sequence needs tweaking.

      I hope this is helpful to you.

      Best regards,
      -Fabien.

  14. John · May 29, 2011

    Thanks Fabien,

    Well, I got it working, but I am not sure I figured out why yet!! The following edits made it work perfectly (each commented out line is replaced by the one following it). I just removed the offsets and everything works perfectly now! I haven’t figured out what these offsets were for yet (do you recall?).

    Also, one other question if you don’t mind. What do you use to create the *.BIN binary images?

    Thanks again!
    John

    private void SetAddressWindow(byte x0, byte y0, byte x1, byte y1)
    {
    DataCommand.Write(Command);
    Write((byte)LcdCommand.CASET); // column addr set
    DataCommand.Write(Data);
    Write(0x00);

    // Write((byte) (x0 + 2)); // XSTART
    Write((byte) (x0 )); // XSTART

    Write(0x00);
    // Write((byte) (x1 + 2)); // XEND

    Write((byte) (x1)); // XEND
    DataCommand.Write(Command);
    Write((byte)LcdCommand.RASET); // row addr set
    DataCommand.Write(Data);
    Write(0x00);

    // Write((byte) (y0 + 1)); // YSTART
    Write((byte) (y0)); // YSTART

    Write(0x00);

    // Write((byte) (y1 + 1)); // YEND
    Write((byte) (y1)); // YEND

    DataCommand.Write(Command);
    Write((byte)LcdCommand.RAMWR); // write to RAM
    }

  15. Fabien Royer · May 29, 2011

    Hi John,

    It started out as a hobby in 2007 and as a way to teach myself electronics. It turned into a full time job in December of 2011. If you wander to http://nwazet.com you can see what I’ve been up to since then ;)

    Cheers,
    -Fabien.

    • John · May 29, 2011

      That’s impressive Fabien! I am an IC designer (analog) by day and learning netduino/etc out of curiosity and to do a few side projects. I was interested to see how well managed code could work in an embedded app (my previous experience had been with TI DSPs/PIC/MSP430 so this was a new concept to me). So far my experience has been mixed. For slow, complicated things it is great and a big time saver. However, I often find it is hard to get the timing I need (even in human interface stuff) and of course if I need to toggle digital outputs directly the performance is dismal (a task so easy to accomplish on even the cheapest traditional micro). I assume as processor power continues to increase (and cost reduce) the managed route will eventually find a way to take over much of the embedded space. I am curious of your opinion of this given your expertise and insight in this area.

      Do you think the majority of embedded apps will eventually run managed code?

      What areas of commercial applications currently use managed code?

      How is .NETMF perceived in the field? Has it gained serious traction in commercial applications or is it more of a hobbyist thing at this time?

      What does Microsoft hope to get out of providing the .NETMF (i.e. what is in it for them — how do they plan to make money from it? I assume it is license free even in commercial apps now?)

      Thanks if you have the time to comment at all!
      John

  16. Fabien Royer · May 29, 2011

    Thanks :)

    I agree with your assessment: managed code is great when latency doesn’t matter. It’s great to use for ‘command and control’ applications and rapid prototyping. It does save a huge amount of development time in these spaces.

    Outside of that, you need something else for building real time applications or the ability to mix C and managed code. Unfortunately, that’s not always possible with all .Net MF ports, Netduino being one of them, sadly. You have to go to GHI for that and even then, it comes with caveats.

    About the perception of the .Net MF in the field of embedded apps: much like ‘Rodney Dangerfield’, it doesn’t get any respect ;) Being born at MSFT has had a great deal to do with it in the first place: it’s a powerful stigma to overcome in a world where OSS has dominated tool chains and platforms for a long time. Whether this is deserved is an entirely different story.

    I don’t believe that MSFT has any intentions of investing in .Net in the future, let alone the .Net MF. MSFT has very little to gain from either technologies anymore.

    The .Net MF is indeed license free, whether for fun or for profit :)

    Cheers,
    -Fabien.

    PS: I only speak for myself, based on my personal experiences.

  17. kevin ross · May 29, 2011

    hi….i found this blog by accident after many hours trawling you tube and google. i am trying to build a small 1.8″ lcd project. my aim is to create a unit that will display a short looped video on power up and to just keep it running till power is taken away. i have been looking for an off the shelf mp4 player or similar that could do the job but in nearly every case a start up menu is displayed. i have a small amount of experience with arduino boards but i have never actually written code relying mainly on software. any help/info would be greatly appreciated. my unending thanks in advance.

    regards

    kevin

  18. cacycleworks · May 29, 2011

    Thanks for your work! It alone convinced me to try .NET! The Adafruit 1.8″ TFT joystick shield is my chosen de-facto human interface for embedded projects I make. I’m starting to implement my latest project in netduino and am left with a question: how do you print text? I can’t find a print() function…

    My project: http://goo.gl/1siAe4

  19. Robert · May 29

    Has anyone tried level shifting using an N fet with the gate at 5 volts? You can drive a low through the source-drain but only about 3 volts will get through for a high level signal. Tpd ~ zero.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s