Moving a TFT Touch Shield to a non-arduino board

I have this exact TFT: 4inch TFT Touch Shield - Waveshare Wiki

It provides an example for the Arduino Uno (see ‘Demo code’ on the linked page).

That example works as expected with my Uno - plug it in, upload the sketch, and everything is great.

What I’d like to do now is get this working with a ‘plain’ AVR, not a full Arduino. To accomplish that, I wired up an atmega1284p dip to one of these on a breadboard… and then kind of drew a blank on how to approach the software side of the problem.

The problem here is that I’m not clear on how or how completely I should translate the Arduino firmware to my AVR. There are several dependencies used by this module, like SPI, Wire, and probably some others that are part of the Arduino build chain. So if I want to run the code on a non-Arduino, I’d need to do one of these:

  • make my non-Arduino into an Arduino (to clarify - I want to keep the chip the same, but somehow put Arduino firmware on it),
  • modify my code to use these parts of the Arduino firmware,
  • or replace these dependencies with atmega1284p compatible functional equivalents.

As a straightforward way of getting to the meat of my problem, I copied the touch demo code, changed the .ino file to main.cpp, and tried compiling with avr-gcc. Obviously without my compiler knowing the path to any Arduino dependencies, this caused everything to blow up. But this is the starting point for this problem I imagine, I’m just not sure which of those three options I listed above is the most sane.

Could anyone provide guidance on which option to pick and then maybe some starting advice for going down the correct path?


If the 1248 is already supported, simply select it.
Otherwise create the required description for the controller, starting with boards.txt.
Then you can use your controller with the Arduino IDE.

Or figure out whether/how AVR Studio supports your controller, and which AVR library supports the controller on your TFT.

It appears the Arduino ecosystem is a black box to you. You need to understand what it is and how it works before you can port something to another system.

First and foremost, Arduino can be run on an AVR but that’s just one of the many families of processors that it supports and hardware is the least of what Arduino is. Sure, there are Arduino boards but that’s not really important to what you’re trying to do.

Arduino provides two things. The first one is a bootloader. That’s the block of code that resides on the processor and allows you to download a new program into the device without the need for an expensive, custom box of hardware from the IC manufacturer just to load the program into the processor.

The second part is the IDE which shields you from some of the uglier aspects of developing code for microcontrollers. It’s an editor but more importantly, behind the scenes, it slices and dices your code into different bits and inserts tons of stuff so you don’t have to to make the GCC-AVR compiler do its thing and emit a usable program. Then it executes avrdude which loads your new program via usb and you’re off to the races.

If you want to leave that easy world of edit-compile-download-debug, be prepared to spend possibly weeks if not months learning Atmel Studio (it’s Window only) and re-creating the wheel. When you’re done, you end up with the same thing, a working program. Okay, you’ve learned some new tools and some things about the C and possibly the C++ language but at the end of the day, there’s no real net gain. That’s what makes Arduino so popular, you can get alot done without having to do a lot of heavy lifting.

How do you go forward? It’s easy. Install the MightyCore which supports the 1284. GitHub - MCUdude/MightyCore: Arduino hardware package for ATmega1284, ATmega644, ATmega324, ATmega

Somewhere along the way, you need to acquire a USB to serial converter for downloading programs. The FT232 is popular, the CH340 and the Silabs CP2102 all do the same thing, the actual model isn’t important.

Next, you use your Uno and load the “Arduino as ISP” sketch onto it. You then use the Uno to flash the bootloader into the 1284. Once you have a bootloader on the 1284, you can compile your program and download it onto the bare 1284.

Okay, so I left out a few details but I know you’ll have some questions.

Thanks for your help! Yes, I wasn't aware that cores existed for standalone microcontrollers (or what such a base software package was supposed to be called), so thanks for clearing up that gap in my understanding.

With that, I got to the brass tacks and installed MightyCore, and got a basic blink example working on my board (I'm using a nano as ArduinoISP to upload, by the way). So great, I'm pretty confident that everything is in working order there.

I then moved to the LCD_Touch example provided in the sample code for that TFT. I changed the pin assignments in DEV_Config.h there to match with the ones I routed from my AVR (and since this seemed like an error-prone process, I double- and triple-checked my routing). I'm fairly confident that I've correctly linked up all the pins used by this module - standard SPI, LCD_CS, LCD_BL, LCD_RST, LCD_DC, TP_CS, TP_IRQ, TP_BUSY. The SPI pins are the same as the AVR's usual SPI pins of course, and all the rest are general purpose pins using the Arduino aliases with the standard configuration selected (my reference was here: MightyCore Standard Pinout).

So now core aside, this should look electrically the same as the connection when I just insert my shield into the headers on my Uno (at least for the pins that are named on the shield's headers - and I confirmed those are the only ones that matter by hooking up only those pins on my modified shield to my Uno and seeing that it worked). However, when I upload the modified program to my AVR, it starts up and turns on the backlight, and even sends some SPI commands over MOSI, but the screen never responds over MISO. The screen stays white. I also tried changing my clock source fuse from the internal RC oscillator @ 8MHz to an external 16MHz source that I provided to fall more in line with the Uno's clock. Of course, I mirrored this in my MightyCore settings and re-uploaded the bootloader. I have extended output enabled and saw that avrdude was indeed performing the fuse operation. This change in clock source made the blink sketch behave weirdly though (Seemed to flicker at 16Hz or so instead of 1Hz. I tried re-defining F_CPU in the sketch to no avail). At any rate, this dubious 16MHz clock also failed to change anything with the LCD test program.

So I was wondering what is the most likely culprit here. Could it be an issue with my clock frequency or noise due to my longer (~3 inch) wiring? Could it be an issue with MightyCore and its compatibility with this LCD module? How would I go about troubleshooting this?

My first step would be to get blink working with the 16 MHz external crystal so you have the same environment as the Uno.

I cannot view the library (on a tablet) but I’d have close look to see if it uses any direct port manipulation and if so, duplicate those assignments with the 1284.

Thanks for the suggestions.

I did confirm that the blink sketch made the LED blink at 1Hz when I was providing the 16MHz clock externally (specifically from D8 of a CKOUT-fused Nano).

I also scoured the TFT_Touch code for any direct pin usage, but it seems to be pretty solidly written and all the pin assignments seem localized to DEV_Config.h. (I already configured those pins first thing and ensured they were routed correctly).

I'm starting to ponder if I'm getting noise issues or something similar which is hampering communication. I'll look into that avenue further, but any alternative suggestions would be great too!

You did reassign the default library pin assignments, yes? I did get a look at the lib and the default control pins conflict with the hardware SPI pins (assuming the standard MightyCore configuration).

Honestly, without a schematic and code, we’re just making wild a$$ guesses.

Alright, I got it!

So first off, yes, I did reassign the pins as previously mentioned. All the SPI pins were changed to the AVR's, and the non-SPI pins were selected arbitrarily, using this image as a reference. These changes were reflected in the code and my physical wiring and I checked them multiple times.

I wanted to set up the 'debug' output in the source code which involved the serial pins, and this investigation led me to notice that some of the pins I selected for the non-SPI signals were the Rx/Tx pins. I didn't think much about that being an actual issue, but when I moved them to make way for debug and changed the assignments, suddenly everything worked.

So I guess the lesson learned here is that the Rx/Tx pins aren't supposed to be used for general purpose... maybe??? I feel like I've used them for non-serial things on Nano projects, so maybe this is just a quirk of the library.