So I’m working on a project where I’m using a Maple Mini clone ( STM32F103CBT6 ) to load bitmap images from the built in SD card reader on a ST7735 TFT LCD screen. Basically the sketch first shows a menu where there is a list of options (text drawn to the TFT) and you use buttons to go through and select an option. When you select an option it then loads and displays a bitmap to the screen. I’ve got it working fine with the standard arduino SD library but after it loads the bitmap and then returns to the menu the whole sketch runs a lot slower. And I can’t figure out why. The amount of time it takes to load and display the bitmap is just fine, it’s just after that everything else runs slower.
Does the clockrate somehow get slowed down after an SD card read? Is there anyway to speed it back up again?
This is the code I’m using to load and display the bitmap files:
void bmpDraw(char *filename, uint8_t x, uint8_t y) {
File bmpFile;
int bmpWidth, bmpHeight; // W+H in pixels
uint8_t bmpDepth; // Bit depth (currently must be 24)
uint32_t bmpImageoffset; // Start of image data in file
uint32_t rowSize; // Not always = bmpWidth; may have padding
uint8_t sdbuffer[3*20]; // pixel buffer (R+G+B per pixel)
uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer
boolean goodBmp = false; // Set to true on valid header parse
boolean flip = true; // BMP is stored bottom-to-top
int w, h, row, col;
uint8_t r, g, b;
uint32_t pos = 0, startTime = millis();
if((x >= TFTscreen.width()) || (y >= TFTscreen.height())) return;
Serial.println();
Serial.print("Loading image '");
Serial.print(filename);
Serial.println('\'');
// Open requested file on SD card
if ((bmpFile = SD.open(filename)) == NULL) {
Serial.print("File not found");
return;
}
// Parse BMP header
if(read16(bmpFile) == 0x4D42) { // BMP signature
Serial.print("File size: "); Serial.println(read32(bmpFile));
(void)read32(bmpFile); // Read & ignore creator bytes
bmpImageoffset = read32(bmpFile); // Start of image data
Serial.print("Image Offset: "); Serial.println(bmpImageoffset, DEC);
// Read DIB header
Serial.print("Header size: "); Serial.println(read32(bmpFile));
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if(read16(bmpFile) == 1) { // # planes -- must be '1'
bmpDepth = read16(bmpFile); // bits per pixel
Serial.print("Bit Depth: "); Serial.println(bmpDepth);
if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
goodBmp = true; // Supported BMP format -- proceed!
Serial.print("Image size: ");
Serial.print(bmpWidth);
Serial.print('x');
Serial.println(bmpHeight);
// BMP rows are padded (if needed) to 4-byte boundary
rowSize = (bmpWidth * 3 + 3) & ~3;
// If bmpHeight is negative, image is in top-down order.
// This is not canon but has been observed in the wild.
if(bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}
// Crop area to be loaded
w = bmpWidth;
h = bmpHeight;
if((x+w-1) >= TFTscreen.width()) w = TFTscreen.width() - x;
if((y+h-1) >= TFTscreen.height()) h = TFTscreen.height() - y;
// Set TFT address window to clipped image bounds
TFTscreen.setAddrWindow(x, y, x+w-1, y+h-1);
for (row=0; row<h; row++) { // For each scanline...
// Seek to start of scan line. It might seem labor-
// intensive to be doing this on every line, but this
// method covers a lot of gritty details like cropping
// and scanline padding. Also, the seek only takes
// place if the file position actually needs to change
// (avoids a lot of cluster math in SD library).
if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
else // Bitmap is stored top-to-bottom
pos = bmpImageoffset + row * rowSize;
if(bmpFile.position() != pos) { // Need seek?
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); // Force buffer reload
}
for (col=0; col<w; col++) { // For each pixel...
// Time to read more pixel data?
if (buffidx >= sizeof(sdbuffer)) { // Indeed
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
}
// Convert pixel from BMP to TFT format, push to display
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
TFTscreen.pushColor(TFTscreen.Color565(r,g,b));
} // end pixel
} // end scanline
Serial.print("Loaded in ");
Serial.print(millis() - startTime);
Serial.println(" ms");
} // end goodBmp
}
}
bmpFile.close();
if(!goodBmp) Serial.println("BMP format not recognized.");
}
// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.
uint16_t read16(File f) {
uint16_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read(); // MSB
return result;
}
uint32_t read32(File f) {
uint32_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); // MSB
return result;
}
(a) Do you share the SPI with the TFT and the SD-Card?
So I guess there is a setClockDivider() in the SD-Card sketch which slows down the TFT display (if the display is a SPI device – your code is not complete, I don’t see your included TFT library)
(b) Did you have the Serial Monitor your computer always open?
I see that you use “serial.begin” and “serial.print” -> It’s a common problem, that if the serial monitor is not connected while included any “serial.xxx” the STM32F1xx board slows down. So try to remove *every* “Serial.xxx”
I’m using the Adafruit ST7735 Library (although it might be modified, I can’t remember)
And in the CPP file for that there is a setClockDivider() in there. How should I change it to make it work?
/***************************************************
This is a library for the Adafruit 1.8" SPI display.
This library works with the Adafruit 1.8" TFT Breakout w/SD card
----> http://www.adafruit.com/products/358
The 1.8" TFT shield
----> https://www.adafruit.com/product/802
The 1.44" TFT breakout
----> https://www.adafruit.com/product/2088
as well as Adafruit raw 1.8" TFT display
----> http://www.adafruit.com/products/618
Check out the links above for our tutorials and wiring diagrams
These displays use SPI to communicate, 4 or 5 pins are required to
interface (RST is optional)
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/
#include "Adafruit_ST7735.h"
#include <limits.h>
#include "pins_arduino.h"
#include "wiring_private.h"
#include <SPI.h>
inline uint16_t swapcolor(uint16_t x) {
return (x << 11) | (x & 0x07E0) | (x >> 11);
}
#if defined (SPI_HAS_TRANSACTION)
static SPISettings mySPISettings;
#elif defined (__AVR__)
static uint8_t SPCRbackup;
static uint8_t mySPCR;
#endif
/*
// Constructor when using software SPI. All output pins are configurable.
Adafruit_ST7735::Adafruit_ST7735(int8_t cs, int8_t rs, int8_t sid, int8_t sclk, int8_t rst)
: Adafruit_GFX(ST7735_TFTWIDTH, ST7735_TFTHEIGHT_18)
{
_cs = cs;
_rs = rs;
_sid = sid;
_sclk = sclk;
_rst = rst;
hwSPI = false;
}
*/
// Constructor when using hardware SPI. Faster, but must use SPI pins
// specific to each board type (e.g. 11,13 for Uno, 51,52 for Mega, etc.)
Adafruit_ST7735::Adafruit_ST7735(int8_t cs, int8_t rs, int8_t rst)
: Adafruit_GFX(ST7735_TFTWIDTH, ST7735_TFTHEIGHT_18) {
_cs = cs;
_rs = rs;
_rst = rst;
hwSPI = true;
_sid = _sclk = 0;
}
#if defined(CORE_TEENSY) && !defined(__AVR__)
#define __AVR__
#endif
inline void Adafruit_ST7735::spiwrite(uint8_t c) {
//Serial.println(c, HEX);
if (hwSPI) {
#if defined (SPI_HAS_TRANSACTION)
SPI.transfer(c);
#elif defined (__AVR__)
SPCRbackup = SPCR;
SPCR = mySPCR;
SPI.transfer(c);
SPCR = SPCRbackup;
// SPDR = c;
// while(!(SPSR & _BV(SPIF)));
#elif defined (__STM32F1__)
SPI.write(c);
#elif defined (__arm__)
SPI.setClockDivider(21); //4MHz
SPI.setDataMode(SPI_MODE0);
SPI.transfer(c);
#endif
} else {
// Fast SPI bitbang swiped from LPD8806 library
for(uint8_t bit = 0x80; bit; bit >>= 1) {
if(c & bit) *dataport |= datapinmask;
else *dataport &= ~datapinmask;
*clkport |= clkpinmask;
*clkport &= ~clkpinmask;
}
}
}
void Adafruit_ST7735::writecommand(uint8_t c) {
#if defined (SPI_HAS_TRANSACTION)
SPI.beginTransaction(mySPISettings);
#endif
*rsport &= ~rspinmask;
*csport &= ~cspinmask;
//Serial.print("C ");
spiwrite(c);
*csport |= cspinmask;
#if defined (SPI_HAS_TRANSACTION)
SPI.endTransaction();
#endif
}
void Adafruit_ST7735::writedata(uint8_t c) {
#if defined (SPI_HAS_TRANSACTION)
SPI.beginTransaction(mySPISettings);
#endif
*rsport |= rspinmask;
*csport &= ~cspinmask;
//Serial.print("D ");
spiwrite(c);
*csport |= cspinmask;
#if defined (SPI_HAS_TRANSACTION)
SPI.endTransaction();
#endif
}
// Rather than a bazillion writecommand() and writedata() calls, screen
// initialization commands and arguments are organized in these tables
// stored in PROGMEM. The table may look bulky, but that's mostly the
// formatting -- storage-wise this is hundreds of bytes more compact
// than the equivalent code. Companion function follows.
#define DELAY 0x80
static const uint8_t PROGMEM
Bcmd[] = { // Initialization commands for 7735B screens
18, // 18 commands in list:
ST7735_SWRESET, DELAY, // 1: Software reset, no args, w/delay
50, // 50 ms delay
ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, no args, w/delay
255, // 255 = 500 ms delay
ST7735_COLMOD , 1+DELAY, // 3: Set color mode, 1 arg + delay:
0x05, // 16-bit color
10, // 10 ms delay
ST7735_FRMCTR1, 3+DELAY, // 4: Frame rate control, 3 args + delay:
0x00, // fastest refresh
0x06, // 6 lines front porch
0x03, // 3 lines back porch
10, // 10 ms delay
ST7735_MADCTL , 1 , // 5: Memory access ctrl (directions), 1 arg:
0x08, // Row addr/col addr, bottom to top refresh
ST7735_DISSET5, 2 , // 6: Display settings #5, 2 args, no delay:
0x15, // 1 clk cycle nonoverlap, 2 cycle gate
// rise, 3 cycle osc equalize
0x02, // Fix on VTL
ST7735_INVCTR , 1 , // 7: Display inversion control, 1 arg:
0x0, // Line inversion
ST7735_PWCTR1 , 2+DELAY, // 8: Power control, 2 args + delay:
0x02, // GVDD = 4.7V
0x70, // 1.0uA
10, // 10 ms delay
ST7735_PWCTR2 , 1 , // 9: Power control, 1 arg, no delay:
0x05, // VGH = 14.7V, VGL = -7.35V
ST7735_PWCTR3 , 2 , // 10: Power control, 2 args, no delay:
0x01, // Opamp current small
0x02, // Boost frequency
ST7735_VMCTR1 , 2+DELAY, // 11: Power control, 2 args + delay:
0x3C, // VCOMH = 4V
0x38, // VCOML = -1.1V
10, // 10 ms delay
ST7735_PWCTR6 , 2 , // 12: Power control, 2 args, no delay:
0x11, 0x15,
ST7735_GMCTRP1,16 , // 13: Magical unicorn dust, 16 args, no delay:
0x09, 0x16, 0x09, 0x20, // (seriously though, not sure what
0x21, 0x1B, 0x13, 0x19, // these config values represent)
0x17, 0x15, 0x1E, 0x2B,
0x04, 0x05, 0x02, 0x0E,
ST7735_GMCTRN1,16+DELAY, // 14: Sparkles and rainbows, 16 args + delay:
0x0B, 0x14, 0x08, 0x1E, // (ditto)
0x22, 0x1D, 0x18, 0x1E,
0x1B, 0x1A, 0x24, 0x2B,
0x06, 0x06, 0x02, 0x0F,
10, // 10 ms delay
ST7735_CASET , 4 , // 15: Column addr set, 4 args, no delay:
0x00, 0x02, // XSTART = 2
0x00, 0x81, // XEND = 129
ST7735_RASET , 4 , // 16: Row addr set, 4 args, no delay:
0x00, 0x02, // XSTART = 1
0x00, 0x81, // XEND = 160
ST7735_NORON , DELAY, // 17: Normal display on, no args, w/delay
10, // 10 ms delay
ST7735_DISPON , DELAY, // 18: Main screen turn on, no args, w/delay
255 }, // 255 = 500 ms delay
Rcmd1[] = { // Init for 7735R, part 1 (red or green tab)
15, // 15 commands in list:
ST7735_SWRESET, DELAY, // 1: Software reset, 0 args, w/delay
150, // 150 ms delay
ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, 0 args, w/delay
255, // 500 ms delay
ST7735_FRMCTR1, 3 , // 3: Frame rate ctrl - normal mode, 3 args:
0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D)
ST7735_FRMCTR2, 3 , // 4: Frame rate control - idle mode, 3 args:
0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D)
ST7735_FRMCTR3, 6 , // 5: Frame rate ctrl - partial mode, 6 args:
0x01, 0x2C, 0x2D, // Dot inversion mode
0x01, 0x2C, 0x2D, // Line inversion mode
ST7735_INVCTR , 1 , // 6: Display inversion ctrl, 1 arg, no delay:
0x07, // No inversion
ST7735_PWCTR1 , 3 , // 7: Power control, 3 args, no delay:
0xA2,
0x02, // -4.6V
0x84, // AUTO mode
ST7735_PWCTR2 , 1 , // 8: Power control, 1 arg, no delay:
0xC5, // VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD
ST7735_PWCTR3 , 2 , // 9: Power control, 2 args, no delay:
0x0A, // Opamp current small
0x00, // Boost frequency
ST7735_PWCTR4 , 2 , // 10: Power control, 2 args, no delay:
0x8A, // BCLK/2, Opamp current small & Medium low
0x2A,
ST7735_PWCTR5 , 2 , // 11: Power control, 2 args, no delay:
0x8A, 0xEE,
ST7735_VMCTR1 , 1 , // 12: Power control, 1 arg, no delay:
0x0E,
ST7735_INVOFF , 0 , // 13: Don't invert display, no args, no delay
ST7735_MADCTL , 1 , // 14: Memory access control (directions), 1 arg:
0xC8, // row addr/col addr, bottom to top refresh
ST7735_COLMOD , 1 , // 15: set color mode, 1 arg, no delay:
0x05 }, // 16-bit color
Rcmd2green[] = { // Init for 7735R, part 2 (green tab only)
2, // 2 commands in list:
ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay:
0x00, 0x02, // XSTART = 0
0x00, 0x7F+0x02, // XEND = 127
ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay:
0x00, 0x01, // XSTART = 0
0x00, 0x9F+0x01 }, // XEND = 159
Rcmd2red[] = { // Init for 7735R, part 2 (red tab only)
2, // 2 commands in list:
ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay:
0x00, 0x00, // XSTART = 0
0x00, 0x7F, // XEND = 127
ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay:
0x00, 0x00, // XSTART = 0
0x00, 0x9F }, // XEND = 159
Rcmd2green144[] = { // Init for 7735R, part 2 (green 1.44 tab)
2, // 2 commands in list:
ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay:
0x00, 0x00, // XSTART = 0
0x00, 0x7F, // XEND = 127
ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay:
0x00, 0x00, // XSTART = 0
0x00, 0x7F }, // XEND = 127
Rcmd3[] = { // Init for 7735R, part 3 (red or green tab)
4, // 4 commands in list:
ST7735_GMCTRP1, 16 , // 1: Magical unicorn dust, 16 args, no delay:
0x02, 0x1c, 0x07, 0x12,
0x37, 0x32, 0x29, 0x2d,
0x29, 0x25, 0x2B, 0x39,
0x00, 0x01, 0x03, 0x10,
ST7735_GMCTRN1, 16 , // 2: Sparkles and rainbows, 16 args, no delay:
0x03, 0x1d, 0x07, 0x06,
0x2E, 0x2C, 0x29, 0x2D,
0x2E, 0x2E, 0x37, 0x3F,
0x00, 0x00, 0x02, 0x10,
ST7735_NORON , DELAY, // 3: Normal display on, no args, w/delay
10, // 10 ms delay
ST7735_DISPON , DELAY, // 4: Main screen turn on, no args w/delay
100 }; // 100 ms delay
// Companion code to the above tables. Reads and issues
// a series of LCD commands stored in PROGMEM byte array.
void Adafruit_ST7735::commandList(const uint8_t *addr) {
uint8_t numCommands, numArgs;
uint16_t ms;
numCommands = pgm_read_byte(addr++); // Number of commands to follow
while(numCommands--) { // For each command...
writecommand(pgm_read_byte(addr++)); // Read, issue command
numArgs = pgm_read_byte(addr++); // Number of args to follow
ms = numArgs & DELAY; // If hibit set, delay follows args
numArgs &= ~DELAY; // Mask out delay bit
while(numArgs--) { // For each argument...
writedata(pgm_read_byte(addr++)); // Read, issue argument
}
if(ms) {
ms = pgm_read_byte(addr++); // Read post-command delay time (ms)
if(ms == 255) ms = 500; // If 255, delay for 500 ms
delay(ms);
}
}
}
// Initialization code common to both 'B' and 'R' type displays
void Adafruit_ST7735::commonInit(const uint8_t *cmdList) {
colstart = rowstart = 0; // May be overridden in init func
pinMode(_rs, OUTPUT);
pinMode(_cs, OUTPUT);
csport = portOutputRegister(digitalPinToPort(_cs));
rsport = portOutputRegister(digitalPinToPort(_rs));
cspinmask = digitalPinToBitMask(_cs);
rspinmask = digitalPinToBitMask(_rs);
if(hwSPI) { // Using hardware SPI
#if defined (SPI_HAS_TRANSACTION)
SPI.begin();
mySPISettings = SPISettings(8000000, MSBFIRST, SPI_MODE0);
#elif defined (__AVR__)
SPCRbackup = SPCR;
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV4);
SPI.setDataMode(SPI_MODE0);
mySPCR = SPCR; // save our preferred state
//Serial.print("mySPCR = 0x"); Serial.println(SPCR, HEX);
SPCR = SPCRbackup; // then restore
#elif defined (__SAM3X8E__)
SPI.begin();
SPI.setClockDivider(21); //4MHz
SPI.setDataMode(SPI_MODE0);
#elif defined (__STM32F1__)
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV2);
SPI.setDataMode(SPI_MODE0);
SPI.setBitOrder(MSBFIRST);
#endif
} else {
pinMode(_sclk, OUTPUT);
pinMode(_sid , OUTPUT);
clkport = portOutputRegister(digitalPinToPort(_sclk));
dataport = portOutputRegister(digitalPinToPort(_sid));
clkpinmask = digitalPinToBitMask(_sclk);
datapinmask = digitalPinToBitMask(_sid);
*clkport &= ~clkpinmask;
*dataport &= ~datapinmask;
}
// toggle RST low to reset; CS low so it'll listen to us
*csport &= ~cspinmask;
if (_rst) {
pinMode(_rst, OUTPUT);
digitalWrite(_rst, HIGH);
delay(500);
digitalWrite(_rst, LOW);
delay(500);
digitalWrite(_rst, HIGH);
delay(500);
}
if(cmdList) commandList(cmdList);
}
// Initialization for ST7735B screens
//void Adafruit_ST7735::initB(void) {
// commonInit(Bcmd);
//}
// Initialization for ST7735R screens (green or red tabs)
void Adafruit_ST7735::initR(uint8_t options) {
commonInit(Rcmd1);
if(options == INITR_GREENTAB) {
commandList(Rcmd2green);
colstart = 2;
rowstart = 1;
} else if(options == INITR_144GREENTAB) {
_height = ST7735_TFTHEIGHT_144;
commandList(Rcmd2green144);
colstart = 2;
rowstart = 3;
} else {
// colstart, rowstart left at default '0' values
commandList(Rcmd2red);
}
commandList(Rcmd3);
// if black, change MADCTL color filter
if (options == INITR_BLACKTAB) {
writecommand(ST7735_MADCTL);
writedata(0xC0);
}
tabcolor = options;
}
void Adafruit_ST7735::setAddrWindow(uint8_t x0, uint8_t y0, uint8_t x1,
uint8_t y1) {
if (hwSPI) {
#if defined (__STM32F1__)
writecommand(ST7735_CASET);
*rsport |= rspinmask;
*csport &= ~cspinmask;
SPI.setDataSize (SPI_CR1_DFF);
SPI.write(x0+colstart);
SPI.write(x1+colstart);
writecommand(ST7735_RASET);
*rsport |= rspinmask;
*csport &= ~cspinmask;
SPI.write(y0+rowstart);
SPI.write(y1+rowstart);
SPI.setDataSize(0);
writecommand(ST7735_RAMWR);
#endif
} else {
writecommand(ST7735_CASET); // Column addr set
writedata(0x00);
writedata(x0+colstart); // XSTART
writedata(0x00);
writedata(x1+colstart); // XEND
writecommand(ST7735_RASET); // Row addr set
writedata(0x00);
writedata(y0+rowstart); // YSTART
writedata(0x00);
writedata(y1+rowstart); // YEND
writecommand(ST7735_RAMWR); // write to RAM
} // end else
}
void Adafruit_ST7735::pushColor(uint16_t color) {
#if defined (SPI_HAS_TRANSACTION)
SPI.beginTransaction(mySPISettings);
#endif
*rsport |= rspinmask;
*csport &= ~cspinmask;
spiwrite(color >> 8);
spiwrite(color);
*csport |= cspinmask;
#if defined (SPI_HAS_TRANSACTION)
SPI.endTransaction();
#endif
}
void Adafruit_ST7735::drawPixel(int16_t x, int16_t y, uint16_t color) {
if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;
setAddrWindow(x,y,x+1,y+1);
#if defined (SPI_HAS_TRANSACTION)
SPI.beginTransaction(mySPISettings);
#endif
*rsport |= rspinmask;
*csport &= ~cspinmask;
spiwrite(color >> 8);
spiwrite(color);
*csport |= cspinmask;
#if defined (SPI_HAS_TRANSACTION)
SPI.endTransaction();
#endif
}
void Adafruit_ST7735::drawFastVLine(int16_t x, int16_t y, int16_t h,
uint16_t color) {
// Rudimentary clipping
if((x >= _width) || (y >= _height)) return;
if((y+h-1) >= _height) h = _height-y;
setAddrWindow(x, y, x, y+h-1);
#if defined (SPI_HAS_TRANSACTION)
SPI.beginTransaction(mySPISettings);
#endif
*rsport |= rspinmask;
*csport &= ~cspinmask;
if (hwSPI) {
#if defined (__STM32F1__)
SPI.setDataSize (SPI_CR1_DFF); // Set SPI 16bit mode
lineBuffer[0] = color;
SPI.dmaSend(lineBuffer, h, 0);
SPI.setDataSize (0);
#endif
} else {
uint8_t hi = color >> 8, lo = color;
while (h--) {
spiwrite(hi);
spiwrite(lo);
} // end while
} // end else
*csport |= cspinmask;
#if defined (SPI_HAS_TRANSACTION)
SPI.endTransaction();
#endif
}
void Adafruit_ST7735::drawFastHLine(int16_t x, int16_t y, int16_t w,
uint16_t color) {
// Rudimentary clipping
if((x >= _width) || (y >= _height)) return;
if((x+w-1) >= _width) w = _width-x;
setAddrWindow(x, y, x+w-1, y);
#if defined (SPI_HAS_TRANSACTION)
SPI.beginTransaction(mySPISettings);
#endif
*rsport |= rspinmask;
*csport &= ~cspinmask;
if (hwSPI) {
#if defined (__STM32F1__)
SPI.setDataSize (SPI_CR1_DFF); // Set spi 16bit mode
lineBuffer[0] = color;
SPI.dmaSend(lineBuffer, w, 0);
SPI.setDataSize (0);
#endif
} else {
uint8_t hi = color >> 8, lo = color;
while (w--) {
spiwrite(hi);
spiwrite(lo);
}
} // end else
*csport |= cspinmask;
#if defined (SPI_HAS_TRANSACTION)
SPI.endTransaction();
#endif
}
void Adafruit_ST7735::fillScreen(uint16_t color) {
if (hwSPI) {
#if defined (__STM32F1__)
setAddrWindow(0, 0, _width - 1, _height - 1);
*rsport |= rspinmask;
*csport &= ~cspinmask;
SPI.setDataSize (SPI_CR1_DFF); // Set spi 16bit mode
lineBuffer[0] = color;
SPI.dmaSend(lineBuffer, (65535), 0);
SPI.dmaSend(lineBuffer, ((_width * _height) - 65535), 0);
SPI.setDataSize (0);
#endif
} else {
fillRect(0, 0, _width, _height, color);
} // end else
}
// fill a rectangle
void Adafruit_ST7735::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color) {
// rudimentary clipping (drawChar w/big text requires this)
if((x >= _width) || (y >= _height)) return;
if((x + w - 1) >= _width) w = _width - x;
if((y + h - 1) >= _height) h = _height - y;
setAddrWindow(x, y, x+w-1, y+h-1);
#if defined (SPI_HAS_TRANSACTION)
SPI.beginTransaction(mySPISettings);
#endif
*rsport |= rspinmask;
*csport &= ~cspinmask;
if (hwSPI) {
#if defined (__STM32F1__)
SPI.setDataSize (SPI_CR1_DFF); // Set spi 16bit mode
lineBuffer[0] = color;
if (w*h <= 65535) {
SPI.dmaSend(lineBuffer, (w*h), 0);
}
else {
SPI.dmaSend(lineBuffer, (65535), 0);
SPI.dmaSend(lineBuffer, ((w*h) - 65535), 0);
}
SPI.setDataSize (0);
#endif
} else {
uint8_t hi = color >> 8, lo = color;
for(y=h; y>0; y--) {
for(x=w; x>0; x--) {
spiwrite(hi);
spiwrite(lo);
} // end for
} // end for
} // end else
*csport |= cspinmask;
#if defined (SPI_HAS_TRANSACTION)
SPI.endTransaction();
#endif
}
// Pass 8-bit (each) R,G,B, get back 16-bit packed color
uint16_t Adafruit_ST7735::Color565(uint8_t r, uint8_t g, uint8_t b) {
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
#define MADCTL_MY 0x80
#define MADCTL_MX 0x40
#define MADCTL_MV 0x20
#define MADCTL_ML 0x10
#define MADCTL_RGB 0x00
#define MADCTL_BGR 0x08
#define MADCTL_MH 0x04
void Adafruit_ST7735::setRotation(uint8_t m) {
writecommand(ST7735_MADCTL);
rotation = m % 4; // can't be higher than 3
switch (rotation) {
case 0:
if (tabcolor == INITR_BLACKTAB) {
writedata(MADCTL_MX | MADCTL_MY | MADCTL_RGB);
} else {
writedata(MADCTL_MX | MADCTL_MY | MADCTL_BGR);
}
_width = ST7735_TFTWIDTH;
if (tabcolor == INITR_144GREENTAB)
_height = ST7735_TFTHEIGHT_144;
else
_height = ST7735_TFTHEIGHT_18;
break;
case 1:
if (tabcolor == INITR_BLACKTAB) {
writedata(MADCTL_MY | MADCTL_MV | MADCTL_RGB);
} else {
writedata(MADCTL_MY | MADCTL_MV | MADCTL_BGR);
}
if (tabcolor == INITR_144GREENTAB)
_width = ST7735_TFTHEIGHT_144;
else
_width = ST7735_TFTHEIGHT_18;
_height = ST7735_TFTWIDTH;
break;
case 2:
if (tabcolor == INITR_BLACKTAB) {
writedata(MADCTL_RGB);
} else {
writedata(MADCTL_BGR);
}
_width = ST7735_TFTWIDTH;
if (tabcolor == INITR_144GREENTAB)
_height = ST7735_TFTHEIGHT_144;
else
_height = ST7735_TFTHEIGHT_18;
break;
case 3:
if (tabcolor == INITR_BLACKTAB) {
writedata(MADCTL_MX | MADCTL_MV | MADCTL_RGB);
} else {
writedata(MADCTL_MX | MADCTL_MV | MADCTL_BGR);
}
if (tabcolor == INITR_144GREENTAB)
_width = ST7735_TFTHEIGHT_144;
else
_width = ST7735_TFTHEIGHT_18;
_height = ST7735_TFTWIDTH;
break;
}
}
void Adafruit_ST7735::invertDisplay(boolean i) {
writecommand(i ? ST7735_INVON : ST7735_INVOFF);
}
////////// stuff not actively being used, but kept for posterity
/*
uint8_t Adafruit_ST7735::spiread(void) {
uint8_t r = 0;
if (_sid > 0) {
r = shiftIn(_sid, _sclk, MSBFIRST);
} else {
//SID_DDR &= ~_BV(SID);
//int8_t i;
//for (i=7; i>=0; i--) {
// SCLK_PORT &= ~_BV(SCLK);
// r <<= 1;
// r |= (SID_PIN >> SID) & 0x1;
// SCLK_PORT |= _BV(SCLK);
//}
//SID_DDR |= _BV(SID);
}
return r;
}
void Adafruit_ST7735::dummyclock(void) {
if (_sid > 0) {
digitalWrite(_sclk, LOW);
digitalWrite(_sclk, HIGH);
} else {
// SCLK_PORT &= ~_BV(SCLK);
//SCLK_PORT |= _BV(SCLK);
}
}
uint8_t Adafruit_ST7735::readdata(void) {
*portOutputRegister(rsport) |= rspin;
*portOutputRegister(csport) &= ~ cspin;
uint8_t r = spiread();
*portOutputRegister(csport) |= cspin;
return r;
}
uint8_t Adafruit_ST7735::readcommand8(uint8_t c) {
digitalWrite(_rs, LOW);
*portOutputRegister(csport) &= ~ cspin;
spiwrite(c);
digitalWrite(_rs, HIGH);
pinMode(_sid, INPUT); // input!
digitalWrite(_sid, LOW); // low
spiread();
uint8_t r = spiread();
*portOutputRegister(csport) |= cspin;
pinMode(_sid, OUTPUT); // back to output
return r;
}
uint16_t Adafruit_ST7735::readcommand16(uint8_t c) {
digitalWrite(_rs, LOW);
if (_cs)
digitalWrite(_cs, LOW);
spiwrite(c);
pinMode(_sid, INPUT); // input!
uint16_t r = spiread();
r <<= 8;
r |= spiread();
if (_cs)
digitalWrite(_cs, HIGH);
pinMode(_sid, OUTPUT); // back to output
return r;
}
uint32_t Adafruit_ST7735::readcommand32(uint8_t c) {
digitalWrite(_rs, LOW);
if (_cs)
digitalWrite(_cs, LOW);
spiwrite(c);
pinMode(_sid, INPUT); // input!
dummyclock();
dummyclock();
uint32_t r = spiread();
r <<= 8;
r |= spiread();
r <<= 8;
r |= spiread();
r <<= 8;
r |= spiread();
if (_cs)
digitalWrite(_cs, HIGH);
pinMode(_sid, OUTPUT); // back to output
return r;
}
*/
SPI.setClockDivider(21); //4MHz
into G….le you would get as the first find:
SPI.setClockDivider(divider)
..
Arduino Due
On the Due, the system clock can be divided by values from 1 to 255. The default value is 21, which sets the clock to 4 MHz like other Arduino boards.
Try something like SPI_CLOCK_DIV2 instead of “21” for the MapleMini.
#elif defined (__arm__)
SPI.setClockDivider(21);//4MHz
SPI.setDataMode(SPI_MODE0);
SPI.transfer(c);The max SPI speed for 7735 is 15MHz (datasheet) so it may work with DIV2 (18MHz SPI).
If not stable go with DIV4 (9MHz).
AFIK
Since system clock is 72 Mhz.
DIV 2 is 36Mhz
DIV4 is 18 Mhz
I’ll need to double check, but I was pretty sure I can get the SPI clock running at 36Mhz, and I thought the setting was DIV2
I’m not sure what hardware you are running but if I use this code
SPI.setClockDivider(2);
SPI.setDataMode(SPI_MODE0);
SPI.begin();
while(1)
{
SPI.transfer(0xAA);
}
That is a good message with 36MHz SPI1, I am going to run my sdcard in cmd6 high speed mode then
Thank you everyone for your suggestions!
Thank you everyone for your suggestions!



