Go Down

Topic: MCUFRIEND_kbv Library for Uno 2.4, 2.8, 3.5, 3.6, 3.95 inch mcufriend Shields (Read 531543 times) previous topic - next topic

david_prentice

X = 20
Y = 25
W = 280
H = 255

(the display is 480x320)
It is easy to draw your new graph data.  Just erase the last column of your scroll window and plot your new point in the last column.

However any text that you want to appear "stationary" becomes a bit fiddly when you want to draw on a moving target.

Here is an example sketch.   I used your dimensions for the box outline.   The scroll area is 280 - 2 = 278.

You can see that drawing text is fairly expensive.   And you will notice a slight jitter.
The trick is:  avoid stationary text in the scroll area.  Then you can hardware scroll as fast as you like.

But another strategy is in Henning Karlsen's UTFT demo.   Look at how he moves the Sine Wave in software.

Code: [Select]

#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;
#include <glcdfont.c>   //7x5 font from Adafruit_GFX (static)

const int SZ = 5;

// should work on any Adafruit_GFX library
void drawChar2(int16_t x, int16_t y, uint8_t c,
               uint16_t color, uint8_t size_x,
               uint16_t sstart, uint16_t swid)
{
    uint16_t bg = TFT_BLACK;  //we always draw background
   
    if (x >= sstart + swid) x -= swid;  //ensure x is in scroll area.
    // Char bitmap = 5 columns.  col #0 = blank, col #1-5 = letter
    for (int8_t i = 0; i < 6; i++) { // 7x5 uses 6x8 rectangle
        uint8_t line, fline;
        uint16_t pixel;
        if (i > 0) fline = pgm_read_byte(&font[c * 5 + i - 1]);
        for (int8_t k = 0; k < size_x; k++) {
            line = fline;
            uint16_t col = x + i * size_x + k;
            if (col >= sstart + swid) col -= swid;
            for (int8_t j = 0; j < 8; j++, line >>= 1) {
                pixel = bg;   //background colour
                if ((line & 1) && i > 0) pixel = color;
                tft.fillRect(col, y + j * size_x, 1, size_x, pixel);
            }
        }
    }
}

// setAddrWindow() and pushColors() syntax varies with libraries
void drawChar3(int16_t x, int16_t y, uint8_t c,
               uint16_t color, uint8_t size_x,
               uint16_t sstart, uint16_t swid)
{
    uint16_t bg = TFT_BLACK;  //we always draw background
   
    if (x >= sstart + swid) x -= swid;  //ensure x is in scroll area.
   
    // Char bitmap = 5 columns.  col #0 = blank, col #1-5 = letter
    for (int8_t i = 0; i < 6; i++) { // 7x5 uses 6x8 rectangle
        uint8_t line, fline;
        uint16_t pixel;
        if (i > 0) fline = pgm_read_byte(&font[c * 5 + i - 1]);
        for (int8_t k = 0; k < size_x; k++) {
            line = fline;
            uint16_t col = x + i * size_x + k;
            if (col >= sstart + swid) col -= swid;
            tft.setAddrWindow(col, y, col, y + 8 * size_x - 1);
            uint8_t first = 1;
            for (int8_t j = 0; j < 8; j++, line >>= 1) {
                pixel = bg;   //background colour
                if ((line & 1) && i > 0) pixel = color;
                for (int8_t m = 0; m < size_x; m++) {
                    tft.pushColors(&pixel, 1, first); //i.e pushColor(pixel)
                    first = 0;
                }
            }
        }
    }
}

void drawStr(int16_t x, int16_t y, uint8_t msg[],
             uint16_t color, uint8_t size_x = 1,
             uint16_t sstart = 0, uint16_t swid = 0)
{
    if (swid == 0) swid = tft.width();
    for (int i = 0; msg[i] != 0; i++) {
        drawChar3(x, y, msg[i], color, size_x, sstart, swid);
        x += 6 * size_x;
    }
}

void setup()
{
    uint16_t ID = tft.readID();
    if (ID == 0xD3D3) ID = 0x1289;
    tft.begin(ID);
    tft.setRotation(3);
    tft.fillScreen(TFT_BLACK);
    tft.drawRect(25, 20, 280, 255, TFT_WHITE);
    tft.drawRect(26 + 278 - 1, 21, 1, 253, TFT_YELLOW);
    tft.drawRect(25, 275, 280, 44, TFT_WHITE);
    tft.setTextColor(TFT_RED, TFT_WHITE); //for regular printing
    delay(1000);
}

void loop()
{
    static int ofs = -1;
    if (++ofs >= 278) ofs = 0;
    tft.vertScroll(26, 278, ofs);
    uint32_t us = micros();
    int x = 26 + ofs, y = 278;
    drawStr(x, y, "X axis ms", TFT_BLUE, 2, 26, 278);
    drawStr(80 + ofs, 5, "<< scroll", TFT_GREEN, 1, 26, 278);
    us = micros() - us;
    tft.setCursor(310, 5);
    tft.print("regular print methods:");
    tft.setCursor(310, 25);
    tft.print("drawStr took ");
    tft.print(us);
    tft.print("us ");
    delay(50);
    drawStr(320, 40, "drawStr out of box area", TFT_CYAN); //uses font size=1, full screen
}


David.

AdiGitalEU

This is brilliant! Thank you very much for writing the sketch David. I understand a lot more now.

From what I see, excluding the areas with the text ("<< scroll", "X axis ms") has to be done the way you demonstrated.

The current project I'm working on is a UI where each element is self-drawing object, unaware of any other "surroundings" (more or less). The hardware scrolling graph would be perfect in this scenario if it was possible to define square area like say:

vertScroll(top, scrollLines, left, scrollColumns, ofs);

But I understand it's a hardware limitation. I think I'll dedicate a fullscreen page in my UI to implement it as the speed is butter smooth - I can move the text outside the scroll area. For smaller graphs in form of an UI element I might have to go with UTFT version as you suggested. I did it before for my 3D printer UI.

Once again - thank you for the help!

xebbmw

I do NOT like the Mcufriend pcb with empty SOIC-8 footprint and missing AMS1117-3.3 regulator.
It takes too much current.   It might damage a Uno/Mega 3.3V regulator.   The screen gets warm.

David.
Hi David,

I just read your post and I have such a LCD screen with missing 3.3 regulator. The footprint for SOIC-8 is there and empty. Is AMS1117-3.3 in SOIC-8 suitable or another regulator is required.

Do you have somewhere a picture to see how this is mounted?

Thanks

david_prentice

The SOIC-8 footprint is for a 3.3V Flash chip.
There is no footprint for a AMS1117

The 2.4 inch shields are probably ok.   Does the screen get hot?   Does it take a lot of current from the 3.3V pin?

David.

xebbmw

The SOIC-8 footprint is for a 3.3V Flash chip.
There is no footprint for a AMS1117

The 2.4 inch shields are probably ok.   Does the screen get hot?   Does it take a lot of current from the 3.3V pin?

David.
You are right, SOIC-8 seems to be a flash chip.

I have checked the LCD, it draws about 140mA at the pin for 3.3V. It does not seems to get very hot, for the moment I am still testing it but after 3-4 hours does not feel hot.

I am designing a PCB right now for my rig, maybe would be good to power the LCD from a different from a separate voltage regulator connected from the main power supply.

david_prentice

Look at the spec for the 3.3V pin on a Uno or Mega. 

Quote
DC Current per I/O Pin    20 mA
DC Current for 3.3V Pin    50 mA
The 74HC245 chips are not input voltage tolerant.    Which means that current flows from the GPIO pins.
The shields should use 74LVC245 or similar.

74HC is fine for a Due because it already has 3.3V GPIO logic.   And the backlight is safe too.  Because:
Quote
Total DC Output Current on all I/O lines    130 mA
DC Current for 3.3V Pin    800 mA
DC Current for 5V Pin    800 mA
David.

dduehren

Trying to use mcufriend_kbv library on Nano 33 IOT.

I'm new to posting, etc so I hope I'm doing this properly.

I have a Kuman SC3A or SC3A-1.  It has an 9486 controller.  And it plugs into an UNO R4 and works just fine.  For a variety of reasons I want to use it with a Nano 33 IOT.

The Nano 33 IOT is different from a normal UNO in several respects.
1. It runs at 48MHz
2. It operates at 3.3V
3. The port to pin mapping is completely different.

None the less, I got a couple of things to "work" by assigning the same pins on the Nano as they are on the UNO.
1. LCD_ID_readreg sketch works fine. Produces same result as with the UNO.  And properly identifies the 9486.
2. I modified the vendor's simple sketch, replacing port oriented bit banging by copying some of the stuff from LCD_ID_readreg. The sketch works but the colors are not nearly as bright as they are when it runs on the UNO.  And I re-ran it on the UNO to make sure my changes weren't the cause.

So far,  nothing else works.  tft.readID fails producing a result of 0x9494

So I'm looking for some guidance.  I suspect it's mainly due to timing.  I've attached the modified kuman sketch




david_prentice

Ouch.   I don't have a Nano 33 IOT.   And it has a very different pinout to Zero, M0 or M0_Pro

If the readreg sketch is working 100% with the default "shield wiring" I will write the appropriate "driver".

Do you have a GitHub account?
It is a fiddly to get all the bits correct.

David.

david_prentice

Here we are:
Code: [Select]

//####################################### NANO IOT 33 ############################
#elif defined(__SAMD21G18A__) && defined(ARDUINO_SAMD_NANO_33_IOT)     //regular UNO shield on NANO IOT 33
#warning building for NANO IOT 33
//LCD pins   |D7  |D6  |D5  |D4  |D3  |D2  |D1  |D0  | |RD |WR |RS  |CS  |RST |
//SAMD21 pin |PA6 |PA4 |PA5 |PA7 |PB11|PB10|PA20|PA18| |PA2|PB2|PA11|PA10|PB08|
#define WRITE_DELAY { WR_ACTIVE4; }
#define IDLE_DELAY  { WR_IDLE2; }
#define READ_DELAY  { RD_ACTIVE8;}
// configure macros for the control pins
#define RD_PORT PORT->Group[0] //PA02
#define RD_PIN  2
#define WR_PORT PORT->Group[1] //PB02
#define WR_PIN  2
#define CD_PORT PORT->Group[0] //PA11
#define CD_PIN  11
#define CS_PORT PORT->Group[0] //PA10
#define CS_PIN  10
#define RESET_PORT PORT->Group[1] //PB08
#define RESET_PIN  8
// configure macros for data bus
#define AMASK         ((15<<4)|(1<<18)|(1<<20))
#define BMASK         (3<<10)   //
#define WRMASK        ((0<<22) | (1<<28) | (1<<30)) //
#define RDMASK        ((1<<17) | (1<<28) | (1<<30)) //
#define write_8(x)   { \
        PORT->Group[0].OUTCLR.reg = AMASK; PORT->Group[1].OUTCLR.reg = BMASK;  \
        PORT->Group[0].OUTSET.reg  = \
                                     (((x) & (1<<0)) << 18) | (((x) & (1<<1)) << 20) | \
                                     (((x) & (1<<4)) <<  3) | (((x) & (1<<5)) <<  0) | \
                                     (((x) & (1<<6)) >>  2) | (((x) & (1<<7)) >>  1); \
        PORT->Group[1].OUTSET.reg  = (((x) & (3<<2)) << 10); \
    }

#define read_8()      ( \
                        ((PORT->Group[0].IN.reg & (1<<18)) >> 18)\
                        | ((PORT->Group[0].IN.reg & (1<<20)) >> 19)\
                        | ((PORT->Group[0].IN.reg & (1<<7)) >> 3)\
                        | ((PORT->Group[0].IN.reg & (1<<5)) >> 0)\
                        | ((PORT->Group[0].IN.reg & (1<<4)) << 2)\
                        | ((PORT->Group[0].IN.reg & (1<<6)) << 1)\
                        | ((PORT->Group[1].IN.reg & (3<<10)) >> 8)\
                      )
#define setWriteDir() { \
        PORT->Group[0].DIRSET.reg = AMASK; \
        PORT->Group[0].WRCONFIG.reg = (AMASK & 0xFFFF) | WRMASK; \
        PORT->Group[1].DIRSET.reg = BMASK; \
        PORT->Group[1].WRCONFIG.reg = (BMASK & 0xFFFF) | WRMASK; \
    }
#define setReadDir()  { \
        PORT->Group[0].DIRCLR.reg = AMASK; \
        PORT->Group[0].WRCONFIG.reg = (AMASK & 0xFFFF) | RDMASK; \
        PORT->Group[1].DIRCLR.reg = BMASK; \
        PORT->Group[1].WRCONFIG.reg = (BMASK & 0xFFFF) | RDMASK; \
    }
#define write8(x)     { write_8(x); WRITE_DELAY; WR_STROBE; IDLE_DELAY; }
#define write16(x)    { uint8_t h = (x)>>8, l = x; write8(h); write8(l); }
#define READ_8(dst)   { RD_STROBE; READ_DELAY; dst = read_8(); RD_IDLE2; RD_IDLE; }
#define READ_16(dst)  { uint8_t hi; READ_8(hi); READ_8(dst); dst |= (hi << 8); }

// Shield Control macros.
#define PIN_LOW(port, pin)    (port).OUTCLR.reg = (1<<(pin))
#define PIN_HIGH(port, pin)   (port).OUTSET.reg = (1<<(pin))
#define PIN_OUTPUT(port, pin) (port).DIRSET.reg = (1<<(pin))



Please check the build macro: ARDUINO_NANO_IOT_33
And check the port to pin assignments in your variant file.
And put this block in shield.h before the SAMD21 ZERO #elif block

Untested.   Please report back.

David.

Edit.   Corrected the spelling for the build macro.  Added a Warning message to confirm that the correct conditional block has been built.

dnh

Hello David

 I have found a lot of controller data sheet

 HX8340-B(T).pdf
 RM68090_datasheet_v04_20110427
 RM68041 datasheet_V06_20100416
RM68140_datasheet_V0.3_20120605
....

Are you interested to get a copy ?

Kindly

Daniel

david_prentice

I have the first 3.

The RM68041 datasheet_V06_20100416 says RM68042 on the Front page !!!

Raydium sent me RM68140GA0 Data Sheet (Rev 0.2 March 2014)

Thanks for the offer.   What datasheets are you looking for?

David.

dnh

David 

My RM68041 datasheet_V06_20100416.pdf file first page contains :

   RM68041 Data Sheet
   Single Chip Driver with 262K color
   for 320RGBx480 a-Si TFT LCD
   Revision:0.6
   Date:Apr. 16, 2010

Daniel

david_prentice

Mine says:
Quote
RM68042 Data Sheet
Single Chip Driver with 262K color
for 320RGBx480 a-Si TFT LCD
Revision:0.6
Date:Apr. 16, 2010
with the RM68042 Data Sheet in a large bold Font.

Hey-ho,  ctl-D in Acrobat Reader shows the file was modified in 2017.

All a bit academic since I have never seen a controller with ID=0x6804
Have you ?

David.

dduehren

David,

Thanks for the post.  In it you say: Please check the build macro: ARDUINO_NANO_IOT_33
And check the port to pin assignments in your variant file.
And put this block in shield.h before the SAMD21 ZERO #elif block

So being a beginner with Arduino but an EE by training and who long ago did embedded coding in assembly, I'm not stranger to data sheets, etc.  The problem is understanding how the code works.  I had looked at the SAMD datasheet and was hoping I didn't have to figure out all the port logic.  So naturally I have a few questions from your post.

1. I have to figure out where the build macro is stored.  (On Arduino site somewhere). I was hoping by writing the code to pin numbers, I could bypass all the port to pin assignments and hoped the underlying code would do it for me.  Hopeful naivety, I suppose.  Though it is how I got the kuman _uno sketch to mostly work.

2. Naturally I'd like to make my code as portable as possible, since I may end up using a Raspberry Pi if the UI code becomes too complex.  The SAMD has a lot more memory so I'm hoping it will be able to do the job.   Can I continue to write to pins digitalRead(Pin); rather than set bits in ports.  Is there some reason to deal with ports at all?  If I use pins, I can just have a mapping.h file for each configuration I want to use.

I'll get back to you once I try the changes you suggest.  Thanks for getting back to me.


david_prentice

Build macro:
Build any sketch with verbose Compile.  And look at the defines e.g.
Code: [Select]

Compiling sketch...
"C:\\Program Files (x86)\\Arduino-1.8.9\\hardware\\tools\\avr/bin/avr-g++" -c -g -Os -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD -flto -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10809 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR "-IC:\\Program Files (x86)\\Arduino-1.8.9\\hardware\\arduino\\avr\\cores\\arduino" "-IC:\\Program Files (x86)\\Arduino-1.8.9\\hardware\\arduino\\avr\\variants\\standard" "-IC:\\Users\\David Prentice\\Documents\\Arduino\\libraries\\Adafruit_GFX_Library" "-IC:\\Users\\David Prentice\\Documents\\Arduino\\libraries\\ST7789_kbv" "-IC:\\Program Files (x86)\\Arduino-1.8.9\\hardware\\arduino\\avr\\libraries\\SPI\\src" "C:\\Users\\DAVIDP~1\\AppData\\Local\\Temp\\arduino_build_284724\\sketch\\scroll_graph_as7.ino.cpp" -o "C:\\Users\\DAVIDP~1\\AppData\\Local\\Temp\\arduino_build_284724\\sketch\\scroll_graph_as7.ino.cpp.o"

The defines are:
Code: [Select]

-DF_CPU=16000000L -DARDUINO=10809 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR

The example was for a UNO.  Since you are building for a NANO_IOT_33 you will have something like:
Code: [Select]
-DARDUINO_SAMD_NANO_33_IOT
Please check the spelling and tell me.

Regarding the library.  
1.  Install the Beta from GitHub.   Not the Release from the IDE Library Manager.
2.  Edit mcufriend_shield.h
3.  Search for SAMD
4.  You will find the #elif block for ZERO and M0 PRO
Code: [Select]

//################################# ZERO and M0_PRO ############################
#elif defined(__SAMD21G18A__)   //regular UNO shield on ZERO or M0_PRO

5.  insert the new block here.   with correct spelling for the "build macro"
6.  then it will test your #elif 33_IOT before looking at the #elif ZERO block
7.  save the file on your PC

Please just follow instructions.

I will explain how it works if and when it works.

Oh.   It will be faster than a Mega.   About the same speed as a Uno.

David.

Edit.  I have edited the earlier post #2978 and corrected the spelling for you.   And checked the variant.cpp file for the pin usage.

Go Up