Port manipulation – LCD 8bit parallel

wizarcl
Thu Aug 06, 2015 11:51 pm
Hi everyone.
I’m trying to port Adafruit_TFTLCD library (for 8bit parallel LCD) and inside in library, control lines is controlled by macros, using port manipulation, but STM32 has a different method to make this. Using AVR, library make control using DDRA and PORTA, for example, to control port direction and values. How can I make this manipulations? Using GPIOA_BASE.CRL, GPIOA_BASE.CRH, GPIOA_BASE.IDR and GPIOA_BASE.ODR?

Follow a piece of code in pin_magic.h:

#define write8inline(d) { \
PORTD = (PORTD & B00000011) | ((d) & B11111100); \
PORTB = (PORTB & B11111100) | ((d) & B00000011); \
WR_STROBE; }
#define read8inline(result) { \
RD_ACTIVE; \
DELAY7; \
result = (PIND & B11111100) | (PINB & B00000011); \
RD_IDLE; }
#define setWriteDirInline() { DDRD |= B11111100; DDRB |= B00000011; }
#define setReadDirInline() { DDRD &= ~B11111100; DDRB &= ~B00000011; }


RogerClark
Fri Aug 07, 2015 12:49 am
The hardware is not that hard to control

Each port has multiple registers, but I think the ones you are interested in is the Output Data Register (ODR) (Not there are also a separate high speed register to Set bits, Reset bits)

If you look in system/libmaple/include/libmaple/gpio.h there is a function to toggle a single bit

static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) {
dev->regs->ODR = dev->regs->ODR ^ (1U << pin);
}

So if you do

dev->regs->ODR = 0x1234

it will set whichever port to 0x1234

Note the ports are 16 bits wide, so you will need to read / mask / write to just update just 8 bits, so thinking about it, it may actually be quicker to write to the BSSR register, e.g. something like

dev->regs->BSRR = (youNum & 0x0F) | ~(yourNum & 0x0F)<<16;

You’d need to double check this code, but I think you’ll probably get the idea.

The device “dev->” have defines in the code already

GPIOA, GPIOB, GPIOC etc etc

Anyway, that should give you a head start ..


wizarcl
Fri Aug 07, 2015 3:57 pm
RogerClark wrote:

Anyway, that should give you a head start ..

zmemw16
Fri Aug 07, 2015 8:02 pm
RogerClark wrote:
Note the ports are 16 bits wide, so you will need to read / mask / write to just update just 8 bits, so thinking about it, it may actually be quicker to write to the BSSR register, e.g. something like

dev->regs->BSRR = (youNum & 0x0F) | ~(yourNum & 0x0F)<<16;


mrburnette
Fri Aug 07, 2015 8:21 pm
zmemw16 wrote:
<…>
my braincell is overloaded and it’s been a long night/day, but where do the 0x0f masks and the << 16 come from?
0xff’s and << 8 are what i’d expect?

stephen


madias
Fri Aug 07, 2015 8:25 pm
Wizarcl please refer to my st7781 TFT library. Use the search function in this forum for my Google Drive url. I’ve done this for a similar maybe the same library you need

wizarcl
Sun Aug 23, 2015 3:35 pm
Hi friends… I tried to port Adafruit TFT LCD library to work with STM32 but I can’t control LCD. This library control 8 bit parallel LCD’s. I’m including codes for you appreciate. Changes:
In pin_magic.h:
#elif defined(__STM32F1__)

// Data pins is PA4 PA5 PA6 PA7 - PB12 PB13 PB14 PB15
#define write8inline(d) { \
GPIOA->regs->ODR = ((GPIOA->regs->ODR & 0xFF0F) | ((d << 4) & 0x00F0)); \
GPIOB->regs->ODR = ((GPIOB->regs->ODR & 0x0FFF) | ((d << 8) & 0xF000)); \
WR_STROBE; }

#define read8inline(result) { \
RD_ACTIVE; \
delayMicroseconds(1); \
result = (((GPIOA->regs->IDR & 0x00F0) >> 4) | ((GPIOB->regs->IDR & 0xF000) >> 8)); \
RD_IDLE;}

#define setWriteDirInline() { \
GPIOA->regs->CRL = ((GPIOA->regs->CRL &= 0xFFFF) | 0x33330000); \
GPIOB->regs->CRH = ((GPIOB->regs->CRH &= 0xFFFF) | 0x33330000); \
}

#define setReadDirInline() { \
GPIOA->regs->CRL = ((GPIOA->regs->CRL &= 0xFFFF) | 0x44440000); \
GPIOB->regs->CRH = ((GPIOB->regs->CRH &= 0xFFFF) | 0x44440000); \
}

// When using the TFT breakout board, control pins are configurable.
#define RD_ACTIVE rdPort->regs->BRR |= rdPinSet //PIO_Clear(rdPort, rdPinSet)
#define RD_IDLE rdPort->regs->BSRR |= rdPinSet //PIO_Set(rdPort, rdPinSet)
#define WR_ACTIVE wrPort->regs->BRR |= wrPinSet //PIO_Clear(wrPort, wrPinSet)
#define WR_IDLE wrPort->regs->BSRR |= wrPinSet //PIO_Set(wrPort, wrPinSet)
#define CD_COMMAND cdPort->regs->BRR |= cdPinSet //PIO_Clear(cdPort, cdPinSet)
#define CD_DATA cdPort->regs->BSRR |= cdPinSet //PIO_Set(cdPort, cdPinSet)
#define CS_ACTIVE csPort->regs->BRR |= csPinSet //PIO_Clear(csPort, csPinSet)
#define CS_IDLE csPort->regs->BSRR |= csPinSet //PIO_Set(csPort, csPinSet)

// As part of the inline control, macros reference other macros...if any
// of these are left undefined, an equivalent function version (non-inline)
// is declared later. The Uno has a moderate amount of program space, so
// only write8() is inlined -- that one provides the most performance
// benefit, but unfortunately also generates the most bloat. This is
// why only certain cases are inlined for each board.
#define write8 write8inline

#else


madias
Sun Aug 23, 2015 7:53 pm
…and what is connected to PC13?
If it’s the backlight than connect it to VCC, the STM32 cannot give enough power for driving the backlight for the LCD via a single pin without additional hardware.

wizarcl
Sun Aug 23, 2015 9:36 pm
madias wrote:…and what is connected to PC13?
If it’s the backlight than connect it to VCC, the STM32 cannot give enough power for driving the backlight for the LCD via a single pin without additional hardware.

RogerClark
Mon Aug 24, 2015 3:45 am
Do you mean you are powering the whole LCD from 5V, e.g. including the chips etc

This is likely to cause problems, because the STM32 is a 3.3V device not 5V device.

I recommend you power the LCD from 3.3V


wizarcl
Mon Aug 24, 2015 8:54 pm
RogerClark wrote:Do you mean you are powering the whole LCD from 5V, e.g. including the chips etc

This is likely to cause problems, because the STM32 is a 3.3V device not 5V device.

I recommend you power the LCD from 3.3V


RogerClark
Mon Aug 24, 2015 9:47 pm
Im not sure how you are going to be able to work out what is going on, without a logic analyser etc.

wizarcl
Wed Aug 26, 2015 9:04 am
RogerClark wrote:Im not sure how you are going to be able to work out what is going on, without a logic analyser etc.

ahull
Wed Aug 26, 2015 12:20 pm
wizarcl wrote:RogerClark wrote:Im not sure how you are going to be able to work out what is going on, without a logic analyser etc.

wizarcl
Sat Sep 05, 2015 1:48 am
ahull wrote:wizarcl wrote:RogerClark wrote:Im not sure how you are going to be able to work out what is going on, without a logic analyser etc.

diger67
Thu Sep 10, 2015 1:09 am
Hi. You have not worked a function void write8 (uint8_t value) due to improper #define write8inline (d). Try this. I think you will understand.

// Data pins is PA4 PA5 PA6 PA7 - PB12 PB13 PB14 PB15
#define write8inline(d) { \
GPIOA->regs->BRR = ((GPIOA->regs->BRR & 0xFF0F) | ((d << 4) & 0x00F0)); \
GPIOA->regs->BSRR = ((GPIOA->regs->BSRR & 0xFF0F) | ((~d << 4) & 0x00F0)); \
GPIOB->regs->BRR = ((GPIOB->regs->BRR & 0x0FFF) | ((d << 8) & 0xF000)); \
GPIOB->regs->BSRR = ((GPIOB->regs->BSRR & 0x0FFF) | ((~d << 8) & 0xF000)); \
WR_STROBE; }

void write8(uint8_t value)
{
write8inline(value);
}


diger67
Thu Sep 10, 2015 1:47 am
wizarcl wrote:Hi friends… I tried to port Adafruit TFT LCD library to work with STM32 but I can’t control LCD. This library control 8 bit parallel LCD’s. I’m including codes for you appreciate. Changes:
In pin_magic.h:
#elif defined(__STM32F1__)

// Data pins is PA4 PA5 PA6 PA7 - PB12 PB13 PB14 PB15
#define write8inline(d) { \
GPIOA->regs->ODR = ((GPIOA->regs->ODR & 0xFF0F) | ((d << 4) & 0x00F0)); \
GPIOB->regs->ODR = ((GPIOB->regs->ODR & 0x0FFF) | ((d << 8) & 0xF000)); \
WR_STROBE; }

#define read8inline(result) { \
RD_ACTIVE; \
delayMicroseconds(1); \
result = (((GPIOA->regs->IDR & 0x00F0) >> 4) | ((GPIOB->regs->IDR & 0xF000) >> 8)); \
RD_IDLE;}

#define setWriteDirInline() { \
GPIOA->regs->CRL = ((GPIOA->regs->CRL &= 0xFFFF) | 0x33330000); \
GPIOB->regs->CRH = ((GPIOB->regs->CRH &= 0xFFFF) | 0x33330000); \
}

#define setReadDirInline() { \
GPIOA->regs->CRL = ((GPIOA->regs->CRL &= 0xFFFF) | 0x44440000); \
GPIOB->regs->CRH = ((GPIOB->regs->CRH &= 0xFFFF) | 0x44440000); \
}

// When using the TFT breakout board, control pins are configurable.
#define RD_ACTIVE rdPort->regs->BRR |= rdPinSet //PIO_Clear(rdPort, rdPinSet)
#define RD_IDLE rdPort->regs->BSRR |= rdPinSet //PIO_Set(rdPort, rdPinSet)
#define WR_ACTIVE wrPort->regs->BRR |= wrPinSet //PIO_Clear(wrPort, wrPinSet)
#define WR_IDLE wrPort->regs->BSRR |= wrPinSet //PIO_Set(wrPort, wrPinSet)
#define CD_COMMAND cdPort->regs->BRR |= cdPinSet //PIO_Clear(cdPort, cdPinSet)
#define CD_DATA cdPort->regs->BSRR |= cdPinSet //PIO_Set(cdPort, cdPinSet)
#define CS_ACTIVE csPort->regs->BRR |= csPinSet //PIO_Clear(csPort, csPinSet)
#define CS_IDLE csPort->regs->BSRR |= csPinSet //PIO_Set(csPort, csPinSet)

// As part of the inline control, macros reference other macros...if any
// of these are left undefined, an equivalent function version (non-inline)
// is declared later. The Uno has a moderate amount of program space, so
// only write8() is inlined -- that one provides the most performance
// benefit, but unfortunately also generates the most bloat. This is
// why only certain cases are inlined for each board.
#define write8 write8inline

#else


diger67
Sat Sep 12, 2015 6:39 pm
There is a proposal to try to use the CPU and functions FSMC Adafruit. This greatly relieve the CPU. For one thing, there are only a FSMC in older STM.
Here’s an example to start ili9341.

/********************************************************************/
#include "stm32f10x_gpio.h"
#include "stm32f10x_fsmc.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x.h"

/*******************************************************************/

#define LCD_DATA ((uint32_t)0x60020000)

#define LCD_REG ((uint32_t)0x60000000)

/*******************************************************************/

void delay(uint32_t delayTime)
{
uint32_t i;
for(i = 0; i < delayTime; i++);
}

/*******************************************************************/

/*void writeLCDCommand(unsigned int reg,unsigned int value)
{
*(uint16_t *) (LCD_REG) = reg;
*(uint16_t *) (LCD_DATA) = value;
}*/

/*******************************************************************/

void LCD_Write_COM(unsigned int reg)
{
*(uint16_t *) (LCD_REG) = reg;
//*(uint16_t *) (LCD_DATA) = value;
}

/*******************************************************************/

//void writeLCDData(unsigned int data)
void LCD_Write_DATA(unsigned int data)
{
*(uint16_t *) (LCD_DATA)= data;
}

/*******************************************************************/

void Lcd_data_start(void)
{
LCD_Write_COM(0x2c);
}

/*******************************************************************/

void Global_reset(void)
{
GPIO_ResetBits(GPIOE, GPIO_Pin_1);
delay(0x0FFFFF);
GPIO_SetBits(GPIOE, GPIO_Pin_1 );
delay(0x0FFFFF);
}

/*******************************************************************/
void initAll()
{
FSMC_NORSRAMInitTypeDef fsmc;
FSMC_NORSRAMTimingInitTypeDef fsmcTiming;
GPIO_InitTypeDef gpio;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE , ENABLE);

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);

gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15;

gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &gpio);

gpio.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;

gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE, &gpio);

gpio.GPIO_Mode = GPIO_Mode_Out_PP;
gpio.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOD, &gpio);

// Здесь у нас Reset
gpio.GPIO_Pin = GPIO_Pin_1 ;
GPIO_Init(GPIOE, &gpio);

// CS
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOD, &gpio);

// RS
gpio.GPIO_Pin = GPIO_Pin_11 ;
GPIO_Init(GPIOD, &gpio);

// CS -> 1
// Reset -> 0
// RD -> 1
// RW -> 1
GPIO_SetBits(GPIOD, GPIO_Pin_7);
GPIO_ResetBits(GPIOE, GPIO_Pin_1);
GPIO_SetBits(GPIOD, GPIO_Pin_4);
GPIO_SetBits(GPIOD, GPIO_Pin_5);

fsmcTiming.FSMC_AddressSetupTime = 0x02;
fsmcTiming.FSMC_AddressHoldTime = 0x00;
fsmcTiming.FSMC_DataSetupTime = 0x05;
fsmcTiming.FSMC_BusTurnAroundDuration = 0x00;
fsmcTiming.FSMC_CLKDivision = 0x00;
fsmcTiming.FSMC_DataLatency = 0x00;
fsmcTiming.FSMC_AccessMode = FSMC_AccessMode_B;

fsmc.FSMC_Bank = FSMC_Bank1_NORSRAM1;
fsmc.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
fsmc.FSMC_MemoryType = FSMC_MemoryType_NOR;
fsmc.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
fsmc.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
fsmc.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
fsmc.FSMC_WrapMode = FSMC_WrapMode_Disable;
fsmc.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
fsmc.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
fsmc.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
fsmc.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
fsmc.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
fsmc.FSMC_ReadWriteTimingStruct = &fsmcTiming;
fsmc.FSMC_WriteTimingStruct = &fsmcTiming;
fsmc.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;

FSMC_NORSRAMInit(&fsmc);
FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE);
}

/*******************************************************************/
void initLCD()
{

Global_reset();

LCD_Write_COM(0x01); //reset
delay(15);

LCD_Write_COM(0x11);//sleep out
delay(20);

LCD_Write_COM(0x28); //display off
delay(5);
LCD_Write_COM(0xCF); //power control b
LCD_Write_DATA(0x00);
LCD_Write_DATA(0xC1); //83 81 AA
LCD_Write_DATA(0x30);
LCD_Write_COM(0xED); //power on seq control
LCD_Write_DATA(0x64); //64 67
LCD_Write_DATA(0x03);
LCD_Write_DATA(0x12);
LCD_Write_DATA(0x81);
LCD_Write_COM(0xE8); //timing control a
LCD_Write_DATA(0x85);
LCD_Write_DATA(0x00); // 01
LCD_Write_DATA(0x78); //79 78
LCD_Write_COM(0xCB); //power control a
LCD_Write_DATA(0x39);
LCD_Write_DATA(0X2C);
LCD_Write_DATA(0x00);
LCD_Write_DATA(0x34);
LCD_Write_DATA(0x02);
LCD_Write_COM(0xF7); //pump ratio control
LCD_Write_DATA(0x20);
LCD_Write_COM(0xEA); //timing control b
LCD_Write_DATA(0x00);
LCD_Write_DATA(0x00);
LCD_Write_COM(0xC0); //power control 2
LCD_Write_DATA(0x23); //26 25
LCD_Write_COM(0xC1); //power control 2
LCD_Write_DATA(0x10);// 11
LCD_Write_COM(0xC5); //vcom control 1
LCD_Write_DATA(0x3E);// 35
LCD_Write_DATA(0x28);// 3E
LCD_Write_COM(0xC7); //vcom control 2
LCD_Write_DATA(0x86); //BE 94
LCD_Write_COM(0xB1); //frame control
LCD_Write_DATA(0x00);
LCD_Write_DATA(0x18); //1B 70
LCD_Write_COM(0xB6); //display control
LCD_Write_DATA(0x08);// 0A
LCD_Write_DATA(0x82);
LCD_Write_DATA(0x27);
LCD_Write_DATA(0x00);
LCD_Write_COM(0xB7); //emtry mode
LCD_Write_DATA(0x07);
LCD_Write_COM(0x3A); //pixel format
LCD_Write_DATA(0x55); //16bit
LCD_Write_COM(0xE0);
LCD_Write_DATA(0x0F);
LCD_Write_DATA(0x31);
LCD_Write_DATA(0x2B);
LCD_Write_DATA(0x0C);
LCD_Write_DATA(0x0E);
LCD_Write_DATA(0x08);
LCD_Write_DATA(0x4E);
LCD_Write_DATA(0xF1);
LCD_Write_DATA(0x37);
LCD_Write_DATA(0x07);
LCD_Write_DATA(0x10);
LCD_Write_DATA(0x03);
LCD_Write_DATA(0x0E);
LCD_Write_DATA(0x09);
LCD_Write_DATA(0x00);
LCD_Write_COM(0x36); //mem access
//LCD_Write_DATA((1<<3)|(1<<6));
LCD_Write_DATA((1<<3)|(1<<7)); //rotate 180
LCD_Write_COM(0x29); //display on
LCD_Write_COM(0x2C);
delay(5);
/*writeLCDCommand(0x0015,0x0030);
writeLCDCommand(0x0011,0x0040);
writeLCDCommand(0x0010,0x1628);
writeLCDCommand(0x0012,0x0000);
writeLCDCommand(0x0013,0x104d);
delay(10);
writeLCDCommand(0x0012,0x0010);
delay(10);
writeLCDCommand(0x0010,0x2620);
writeLCDCommand(0x0013,0x344d);
delay(10);

writeLCDCommand(0x0001,0x0100);
writeLCDCommand(0x0002,0x0300);
writeLCDCommand(0x0003,0x1030);
writeLCDCommand(0x0008,0x0604);
writeLCDCommand(0x0009,0x0000);
writeLCDCommand(0x000A,0x0008);

writeLCDCommand(0x0041,0x0002);
writeLCDCommand(0x0060,0x2700);
writeLCDCommand(0x0061,0x0001);
writeLCDCommand(0x0090,0x0182);
writeLCDCommand(0x0093,0x0001);
writeLCDCommand(0x00a3,0x0010);
delay(10);

writeLCDCommand(0x30,0x0000);
writeLCDCommand(0x31,0x0502);
writeLCDCommand(0x32,0x0307);
writeLCDCommand(0x33,0x0305);
writeLCDCommand(0x34,0x0004);
writeLCDCommand(0x35,0x0402);
writeLCDCommand(0x36,0x0707);
writeLCDCommand(0x37,0x0503);
writeLCDCommand(0x38,0x1505);
writeLCDCommand(0x39,0x1505);
delay(10);

writeLCDCommand(0x0007,0x0001);
delay(10);
writeLCDCommand(0x0007,0x0021);
writeLCDCommand(0x0007,0x0023);
delay(10);
writeLCDCommand(0x0007,0x0033);
delay(10);
writeLCDCommand(0x0007,0x0133);*/
}

/*******************************************************************/
int main()
{
initAll();
delay(100);
initLCD();

while(1)
{
int i;

/*writeLCDCommand(0x0050, 0);
writeLCDCommand(0x0051, 239);

writeLCDCommand(0x0052, 0);
writeLCDCommand(0x0053, 319);

writeLCDCommand(32, 0);
writeLCDCommand(33, 0);*/
LCD_Write_COM(0x51);
LCD_Write_DATA(0x00);
*(uint16_t *) (LCD_REG) = 0x2C;

for (i = 0; i < 76800; i++)
{
LCD_Write_DATA(0xF800);
}
delay(0xFFFFFF);

for (i = 0; i < 76800; i++)
{
LCD_Write_DATA(0x07E0);
}
delay(0xFFFFFF);

for (i = 0; i < 76800; i++)
{
LCD_Write_DATA(0x001F);
}
delay(0xFFFFFF);

for (i = 0; i < 76800; i++)
{
LCD_Write_DATA(0x03EF);
}
delay(0xFFFFFF);
for (i = 0; i < 76800; i++)
{
LCD_Write_DATA(0xFFE0);
}
delay(0xFFFFFF);

}
}

/*******************************************************************/


diger67
Tue Sep 15, 2015 5:00 pm
Developing the theme of adaptation to the library Adafruit stm32. The library for the 16 bit bus using FSMC. It is easy to do the work for 8-bit bus.
/*******************************************************************/
#include "stm32f10x_gpio.h"
#include "stm32f10x_fsmc.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x.h"
#include "reg_9341.h"

#define DELAY_TIME 1
#define TFTWIDTH 240
#define TFTHEIGHT 320
uint8_t rotation;

const uint16_t
WIDTH, HEIGHT;
uint16_t _width, _height;

/*******************************************************************/
// Определяем адреса, по которым будем записывать данные
// Для записи данных
#define LCD_DATA ((uint32_t)0x60020000)
// Для записи команд
#define LCD_REG ((uint32_t)0x60000000)

/*******************************************************************/
// Простенькая функция задержки
void delay(uint32_t delayTime)
{
uint32_t i;
for(i = 0; i < delayTime; i++);
}

/*******************************************************************/
// Так мы будем писать команды в регистры LCD
/*void writeLCDCommand(unsigned int reg,unsigned int value)
{
*(uint16_t *) (LCD_REG) = reg;
*(uint16_t *) (LCD_DATA) = value;
}*/

/*******************************************************************/// Так мы будем писать команды в регистры LCD
void LCD_Write_COM(unsigned int reg)
{
*(uint16_t *) (LCD_REG) = reg;
//*(uint16_t *) (LCD_DATA) = value;
}

/*******************************************************************/
// А так данные..
//void writeLCDData(unsigned int data)
void LCD_Write_DATA(unsigned int data)
{
*(uint16_t *) (LCD_DATA)= data;
}

/*******************************************************************/

void Lcd_data_start(void)
{
LCD_Write_COM(0x2c);
}

/*******************************************************************/

void Global_reset(void)
{
GPIO_ResetBits(GPIOE, GPIO_Pin_1);
delay(0x0FFFFF);
GPIO_SetBits(GPIOE, GPIO_Pin_1 );
delay(0x0FFFFF);
}

/*******************************************************************/
void initAll()
{
FSMC_NORSRAMInitTypeDef fsmc;
FSMC_NORSRAMTimingInitTypeDef fsmcTiming;
GPIO_InitTypeDef gpio;

// Включаем тактирование портов
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE , ENABLE);

// И тактирование FSMC
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);

// Инициализация пинов, задейстованных в общении по FSMC
gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15;

gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &gpio);

gpio.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;

gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE, &gpio);

gpio.GPIO_Mode = GPIO_Mode_Out_PP;
gpio.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOD, &gpio);

// Здесь у нас Reset
gpio.GPIO_Pin = GPIO_Pin_1 ;
GPIO_Init(GPIOE, &gpio);

// CS
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOD, &gpio);

// RS
gpio.GPIO_Pin = GPIO_Pin_11 ;
GPIO_Init(GPIOD, &gpio);

// CS -> 1
// Reset -> 0
// RD -> 1
// RW -> 1
GPIO_SetBits(GPIOD, GPIO_Pin_7);
GPIO_ResetBits(GPIOE, GPIO_Pin_1);
GPIO_SetBits(GPIOD, GPIO_Pin_4);
GPIO_SetBits(GPIOD, GPIO_Pin_5);

// Настройка FSMC
fsmcTiming.FSMC_AddressSetupTime = 0x02;
fsmcTiming.FSMC_AddressHoldTime = 0x00;
fsmcTiming.FSMC_DataSetupTime = 0x04;//0x05
fsmcTiming.FSMC_BusTurnAroundDuration = 0x00;
fsmcTiming.FSMC_CLKDivision = 0x00;
fsmcTiming.FSMC_DataLatency = 0x00;
fsmcTiming.FSMC_AccessMode = FSMC_AccessMode_B;

fsmc.FSMC_Bank = FSMC_Bank1_NORSRAM1;
fsmc.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
fsmc.FSMC_MemoryType = FSMC_MemoryType_NOR;
fsmc.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
fsmc.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
fsmc.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
fsmc.FSMC_WrapMode = FSMC_WrapMode_Disable;
fsmc.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
fsmc.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
fsmc.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
fsmc.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
fsmc.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
fsmc.FSMC_ReadWriteTimingStruct = &fsmcTiming;
fsmc.FSMC_WriteTimingStruct = &fsmcTiming;
fsmc.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;

FSMC_NORSRAMInit(&fsmc);
FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE);

rotation = 1;
_width = TFTWIDTH;
_height = TFTHEIGHT;
}

/*******************************************************************/
void initLCD()
{
// Глобальный Reset дисплея
Global_reset();

// Пляски с бубном от китайских товарищей
LCD_Write_COM(0x01); //reset
delay(15);

LCD_Write_COM(0x11);//sleep out
delay(20);

LCD_Write_COM(0x28); //display off
delay(5);
LCD_Write_COM(0xCF); //power control b
LCD_Write_DATA(0x00);
LCD_Write_DATA(0xC1); //83 81 AA
LCD_Write_DATA(0x30);
LCD_Write_COM(0xED); //power on seq control
LCD_Write_DATA(0x64); //64 67
LCD_Write_DATA(0x03);
LCD_Write_DATA(0x12);
LCD_Write_DATA(0x81);
LCD_Write_COM(0xE8); //timing control a
LCD_Write_DATA(0x85);
LCD_Write_DATA(0x00); // 01
LCD_Write_DATA(0x78); //79 78
LCD_Write_COM(0xCB); //power control a
LCD_Write_DATA(0x39);
LCD_Write_DATA(0X2C);
LCD_Write_DATA(0x00);
LCD_Write_DATA(0x34);
LCD_Write_DATA(0x02);
LCD_Write_COM(0xF7); //pump ratio control
LCD_Write_DATA(0x20);
LCD_Write_COM(0xEA); //timing control b
LCD_Write_DATA(0x00);
LCD_Write_DATA(0x00);
LCD_Write_COM(0xC0); //power control 2
LCD_Write_DATA(0x23); //26 25
LCD_Write_COM(0xC1); //power control 2
LCD_Write_DATA(0x10);// 11
LCD_Write_COM(0xC5); //vcom control 1
LCD_Write_DATA(0x3E);// 35
LCD_Write_DATA(0x28);// 3E
LCD_Write_COM(0xC7); //vcom control 2
LCD_Write_DATA(0x86); //BE 94
LCD_Write_COM(0xB1); //frame control
LCD_Write_DATA(0x00);
LCD_Write_DATA(0x18); //1B 70
LCD_Write_COM(0xB6); //display control
LCD_Write_DATA(0x08);// 0A
LCD_Write_DATA(0x82);
LCD_Write_DATA(0x27);
LCD_Write_DATA(0x00);
LCD_Write_COM(0xB7); //emtry mode
LCD_Write_DATA(0x07);
LCD_Write_COM(0x3A); //pixel format
LCD_Write_DATA(0x55); //16bit
LCD_Write_COM(0xE0);
LCD_Write_DATA(0x0F);
LCD_Write_DATA(0x31);
LCD_Write_DATA(0x2B);
LCD_Write_DATA(0x0C);
LCD_Write_DATA(0x0E);
LCD_Write_DATA(0x08);
LCD_Write_DATA(0x4E);
LCD_Write_DATA(0xF1);
LCD_Write_DATA(0x37);
LCD_Write_DATA(0x07);
LCD_Write_DATA(0x10);
LCD_Write_DATA(0x03);
LCD_Write_DATA(0x0E);
LCD_Write_DATA(0x09);
LCD_Write_DATA(0x00);
LCD_Write_COM(0x36); //mem access
LCD_Write_DATA((1<<3)|(1<<6));
//LCD_Write_DATA((1<<3)|(1<<7)); //rotate 180
LCD_Write_COM(0x29); //display on
LCD_Write_COM(0x2C);
delay(5);
/*writeLCDCommand(0x0015,0x0030);
writeLCDCommand(0x0011,0x0040);
writeLCDCommand(0x0010,0x1628);
writeLCDCommand(0x0012,0x0000);
writeLCDCommand(0x0013,0x104d);
delay(10);
writeLCDCommand(0x0012,0x0010);
delay(10);
writeLCDCommand(0x0010,0x2620);
writeLCDCommand(0x0013,0x344d);
delay(10);

writeLCDCommand(0x0001,0x0100);
writeLCDCommand(0x0002,0x0300);
writeLCDCommand(0x0003,0x1030);
writeLCDCommand(0x0008,0x0604);
writeLCDCommand(0x0009,0x0000);
writeLCDCommand(0x000A,0x0008);

writeLCDCommand(0x0041,0x0002);
writeLCDCommand(0x0060,0x2700);
writeLCDCommand(0x0061,0x0001);
writeLCDCommand(0x0090,0x0182);
writeLCDCommand(0x0093,0x0001);
writeLCDCommand(0x00a3,0x0010);
delay(10);

// Настройки гаммы
writeLCDCommand(0x30,0x0000);
writeLCDCommand(0x31,0x0502);
writeLCDCommand(0x32,0x0307);
writeLCDCommand(0x33,0x0305);
writeLCDCommand(0x34,0x0004);
writeLCDCommand(0x35,0x0402);
writeLCDCommand(0x36,0x0707);
writeLCDCommand(0x37,0x0503);
writeLCDCommand(0x38,0x1505);
writeLCDCommand(0x39,0x1505);
delay(10);

// Включение дисплея
writeLCDCommand(0x0007,0x0001);
delay(10);
writeLCDCommand(0x0007,0x0021);
writeLCDCommand(0x0007,0x0023);
delay(10);
writeLCDCommand(0x0007,0x0033);
delay(10);
writeLCDCommand(0x0007,0x0133);*/

}

/*******************************************************************/
int main()
{
initAll();
delay(100);
initLCD();
//setRotation(0);

while(1)
{
int i;

// Начальный и конечный адреса по горизонтали
/*writeLCDCommand(0x0050, 0);
writeLCDCommand(0x0051, 239);
// Начальный и конечный адреса по вертикали
writeLCDCommand(0x0052, 0);
writeLCDCommand(0x0053, 319);

writeLCDCommand(32, 0);
writeLCDCommand(33, 0);*/
//drawPixel(30, 40, 0xFFFF);
//LCD_Write_COM(0x51);
//LCD_Write_DATA(0x00);
//*(uint16_t *) (LCD_REG) = 0x2C;

// Красный
//fillScreen(0xF800);
/*for (i = 0; i < 76800; i++)
{
LCD_Write_DATA(0xF800);
//drawPixel(30, 40, 0x0000);
}*/
//drawPixel(30, 40, 0x0000);
//delay(0xFFFFFF);
// Зеленый
//fillScreen(0x07E0);
/*for (i = 0; i < 76800; i++)
{
LCD_Write_DATA(0x07E0);
}*/
//delay(0xFFFFFF);
//Синий
//fillScreen(0x001F);
/*for (i = 0; i < 76800; i++)
{
LCD_Write_DATA(0x001F);
//drawPixel(30, 40, 0x0000);
}*/
//delay(0xFFFFFF);
//Серый
//fillScreen(0x03EF);
/*for (i = 0; i < 76800; i++)
{
LCD_Write_DATA(0x03EF);
//drawPixel(30, 40, 0x0000);
}*/
//delay(0xFFFFFF);
//fillScreen(0xFFE0);
/*for (i = 0; i < 76800; i++)
{
LCD_Write_DATA(0xFFE0);
//drawPixel(30, 40, 0x0000);
}*/
//delay(0xFFFFFF);
//fillScreen(0x0000);
/*for (i = 0; i < 76800; i++)
{
LCD_Write_DATA(0x0000);
//drawPixel(30, 40, 0x0000);
}*/

//delay(0xFFFFFF);
for(i = 0; i < 4; i++)
{
setRotation(i);
fillScreen(0x03EF);
fillRect(20, 30, 50, 70, 0xF800);
delay(0x0FFFFF);
}

}

}

/*void Adafruit_GFX(int16_t w, int16_t h)
{
WIDTH(w), HEIGHT(h);
}*/

void Rotation(uint8_t x) {
rotation = (x & 3);
switch(rotation) {
case 0:
case 2:
_width = TFTWIDTH;
_height = TFTHEIGHT;
break;
case 1:
case 3:
_width = TFTHEIGHT;
_height = TFTWIDTH;
break;
}
}

void setRotation(uint8_t x)
{

Rotation(x);

uint16_t t;
switch (rotation) {
case 2:
//Rotation(x);
t = ILI9341_MADCTL_MX | ILI9341_MADCTL_BGR;
break;
case 3:
//Rotation(x);
t = ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR;
break;
case 0:
//Rotation(x);
t = ILI9341_MADCTL_MY | ILI9341_MADCTL_BGR;
break;
case 1:
//Rotation(x);
t = ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR;
break;
}
LCD_Write_COM(ILI9341_MADCTL); // MADCTL
LCD_Write_DATA(t);
// For 9341, init default full-screen address window:
setAddrWindow(0, 0, _width - 1, _height - 1);
}

void setAddrWindow(int x1, int y1, int x2, int y2)
{
uint32_t t;

t = x1;
t <<= 16;
t |= x2;
writeRegister32(ILI9341_COLADDRSET, t); // HX8357D uses same registers!
t = y1;
t <<= 16;
t |= y2;
writeRegister32(ILI9341_PAGEADDRSET, t); // HX8357D uses same registers!
}

void fillRect(int16_t x1, int16_t y1, int16_t w, int16_t h, uint16_t fillcolor)
{
int16_t x2, y2;
// Initial off-screen clipping
if( (w <= 0 ) || (h <= 0 ) ||
(x1 >= _width) || (y1 >= _height) ||
((x2 = x1+w-1) < 0 ) || ((y2 = y1+h-1) < 0 )) return;
if(x1 < 0) { // Clip left
w += x1;
x1 = 0;
}
if(y1 < 0) { // Clip top
h += y1;
y1 = 0;
}
if(x2 >= _width) { // Clip right
x2 = _width - 1;
w = x2 - x1 + 1;
}
if(y2 >= _height) { // Clip bottom
y2 = _height - 1;
h = y2 - y1 + 1;
}

setAddrWindow(x1, y1, x2, y2);
flood(fillcolor, (uint32_t)w * (uint32_t)h);
}

void fillScreen(uint16_t color)
{
setAddrWindow(0, 0, _width - 1, _height - 1);
flood(color, (long)TFTWIDTH * (long)TFTHEIGHT);
}

void flood(uint16_t color, uint32_t len)
{
uint16_t blocks;
int i;

LCD_Write_COM(0x2c);
LCD_Write_DATA(color);
len--;

blocks = (uint16_t)(len / 64); // 64 pixels/block
while(blocks--) {
i = 16; // 64 pixels/block / 4 pixels/pass
do {
LCD_Write_DATA(color); LCD_Write_DATA(color);
LCD_Write_DATA(color); LCD_Write_DATA(color);
} while(--i);
}
for(i = (uint8_t)len & 63; i--; ) {
LCD_Write_DATA(color);
}
}

void drawPixel(int16_t x, int16_t y, uint16_t color)
{
setAddrWindow(x, y, _width-1, _height-1);
*(uint16_t *) (LCD_REG) = 0x2C;
LCD_Write_DATA(color);
}

void writeRegister32(uint16_t r, uint32_t d)
{
//CS_ACTIVE;
//CD_COMMAND;
LCD_Write_COM(r);
//write8(r);
//CD_DATA;
delay(DELAY_TIME);
LCD_Write_DATA(d>>24);
//write8(d >> 24);
delay(DELAY_TIME);
LCD_Write_DATA(d>>16);
//write8(d >> 16);
delay(DELAY_TIME);
LCD_Write_DATA(d>>8);
//write8(d >> 8);
delay(DELAY_TIME);
LCD_Write_DATA(d);
//CS_IDLE;
}

/*******************************************************************/


stevech
Tue Sep 15, 2015 8:08 pm
there’s FSMC w/DMA driver code in the HAL libraries – you could use that, or adapt that, or just study it.

diger67
Wed Sep 16, 2015 12:50 am
stevech wrote:there’s FSMC w/DMA driver code in the HAL libraries – you could use that, or adapt that, or just study it.

DavidJ
Mon Jun 20, 2016 2:29 pm
I am looking for an ADAfruit libary for the STM32F108 to interface an 8bit ILI9325.
This code looks promising but I get the error: stm32f10x_gpio.h: No such file or directory
I tried copying that file everywhere, but no luck.
Help would be very much appreciated.

zmemw16
Mon Jun 20, 2016 7:55 pm
trying a search for stm32f108 on stm’s site, no such thing

simple google for ili9325 gives 2nd link as
https://www.adafruit.com/product/335
and the 3rd link as
http://tronixstuff.com/2013/04/26/tutor … d-modules/

stephen


martinayotte
Mon Jun 20, 2016 8:48 pm
The F108 is actually a F103 with the mouth closed … :lol:

RogerClark
Mon Jun 20, 2016 9:54 pm
Googling for that file, shows that its part of STMs old CMSIS.

The libmaple core does not use the CMSIS because of historical licensing issues.

You will need to comment out that include, and then see what functions are called, and them change the library to use the libmaple equivalent functions, or possibly manipulate the hardware directly.


zmemw16
Mon Jun 20, 2016 11:59 pm
martinayotte wrote:The F108 is actually a F103 with the mouth closed … :lol:

RogerClark
Tue Jun 21, 2016 12:20 am
I’m not sure if this helps (I’d need to test it)

But I’ve been working on the HAL as a library.

I’m not sure if one library can include another library, but this may be a way to port some code based on the CMSIS albeit as long as that code is compatible with the CMSIS that is generated by the STM Cube


mrburnette
Tue Jun 21, 2016 12:18 pm
RogerClark wrote:
<…>
I’m not sure if one library can include another library<…>

RogerClark
Tue Jun 21, 2016 10:47 pm
Thanks Ray.

The HAl library, isnt really a library, its just a way to get the IDE to compile and link the STM HAL files, and read in all the headers, so that the HAL functions can be called inside the sketch.

The HAL is written in C, and seems to just be a load of disparate files, each with a grouped set of functions in them.

But its a lot of files, I have not counted them, but it looks like 100’ish, and takes up several megabytes.

Anyway, its rather experimental at the moment, but may be useful to some people.


mrburnette
Wed Jun 22, 2016 12:47 pm
RogerClark wrote:
<…>
The HAl library, isnt really a library, its just a way to get the IDE to compile and link the STM HAL files, and read in all the headers, so that the HAL functions can be called inside the sketch.
<…>
But its a lot of files, I have not counted them, but it looks like 100’ish, and takes up several megabytes.
<….

RogerClark
Wed Jun 22, 2016 9:41 pm
Hi Ray,

This confusion is my fault.

I am playing fast and loose with the Arduino Library paradigm with this.

I bent the rules a bit with the Libraries system, in the past, by making an empty library, just to put our examples in; so they can be acccessed via the menu system.

But in this case, the header does actually include some files, and the IDE does have to compile a whole loadmof files, but none of them, AFIK, are classes.

I may even remove the dummy HAL class I made, as it may not be needed at all, depending on whether any initialisation code needed to be run – and at the moment, it looks like running the default HAL_init() function screws things up, as it either messes up the clock PLLs or possibly does something strange to systick, ( I have not had time to investigate precislely what its affecting, so I am not calling HAL_init() from the library at the moment)


iwalpola
Sat Jul 02, 2016 3:12 pm
Working library

With your help of martinayotte, werefcat and diger67’s posts in http://www.stm32duino.com/viewtopic.php?f=9&t=474 I managed to port the SPI version of ILI9341 library to work with 8 bit parallel.

viewtopic.php?f=44&t=637&p=15438#p15438

github:
https://github.com/iwalpola/Adafruit_ILI9341_8bit_STM/
demo:
https://www.youtube.com/watch?v=MAkMaZyZMWM


RogerClark
Sat Jul 02, 2016 9:33 pm
Do you have the milliseconds timing debug output from the adafruit graphics demo, in your youtube video, so we can compare the speed with SPI?

martinayotte
Sun Jul 03, 2016 1:55 am
Great work, @iwalpola !

In my case with Netduino2Plus pinouts as uint8_t DPINS[] = {PC7, PC6, PA3, PA2, PB12, PB8, PB9, PA1, PA0, PA6};, I don’t think I could get much speed optimisation doing direct register access …


iwalpola
Sun Jul 03, 2016 3:25 am
RogerClark wrote:Do you have the milliseconds timing debug output from the adafruit graphics demo, in your youtube video, so we can compare the speed with SPI?

mrburnette
Sun Jul 03, 2016 2:39 pm
iwalpola wrote:
I’m also curious to know the performance as compared to SPI.

iwalpola
Sun Jul 03, 2016 5:16 pm
New benchmark after replacing regs->ODR with regs->BSRR and regs->BRR

Benchmark Time (microseconds)
Screen fill 1478774
Text 43997
Lines 376454
Horiz/Vert Lines 101883
Rectangles (outline) 65100
Rectangles (filled) 3070377
Circles (filled) 419900
Circles (outline) 285285
Triangles (outline) 90139
Triangles (filled) 713698
Rounded rects (outline) 131807
Rounded rects (filled) 3324904
Done!


ahull
Sun Jul 03, 2016 7:54 pm
iwalpola wrote:New benchmark after replacing regs->ODR with regs->BSRR and regs->BRR

Benchmark Time (microseconds)
Screen fill 1478774
Text 43997
Lines 376454
Horiz/Vert Lines 101883
Rectangles (outline) 65100
Rectangles (filled) 3070377
Circles (filled) 419900
Circles (outline) 285285
Triangles (outline) 90139
Triangles (filled) 713698
Rounded rects (outline) 131807
Rounded rects (filled) 3324904
Done!


martinayotte
Sun Jul 03, 2016 8:10 pm
Andy, even if LCD is parallel, if code has to assign GPIOs one by one, especially in the case of a shield with D2-D9, where those GPIOs are not consecutive (especially on Netduino2Plus), I/O performance is hard to achieve.

iwalpola
Sun Jul 03, 2016 8:36 pm
@Andy, Kurt’s library seems quite fast in some operations, and I’m curious to see why. I’ll git diff and report back.
@Martin Perhaps it comes down to the GFX library functions?
Very curious indeed

ahull
Sun Jul 03, 2016 8:51 pm
martinayotte wrote:Andy, even if LCD is parallel, if code has to assign GPIOs one by one, especially in the case of a shield with D2-D9, where those GPIOs are not consecutive (especially on Netduino2Plus), I/O performance is hard to achieve.

RogerClark
Sun Jul 03, 2016 10:27 pm
Interesting.

I looked at some previous postings to the forum e.g. http://www.stm32duino.com/viewtopic.php?t=862&start=40

and it looks like operations which set individual pixels are faster, but anything that fills large areas are slower.

From what I recall the adafruit SPI based library is not very effecient at writing individual pixels, and I suspect that improvements could be made to the SPI version which may improve single pixel access speed in the SPI version.
(I think the Teensy has an optimised library with fast pixel access)

Where this really comes into its own, is on boards that use the F103V or F103Z, which have whole GPIO ports that are unused.
And further speed improvements can be gained where there are separate data and address ports.


RogerClark
Sun Jul 03, 2016 11:02 pm
Just a quick followup about slow single pixel write speeds in the SPI version, and unless i have looked in the wrong file…

the drawpixel function wastes a lot of time, as it assumes its being called for a one off command, but as its called from the functions which draw triangles etc, it makes operations like triangles slow.

The simple solution, is to have 2 functions to write a pixel, one that works standalone and one that needs the SPI to be initialised for it e.g Chip Select pins etc to be toggled.
then get the triangle functions to call the non-standalone version.

Ideally the non-standalone function would be private to the class, but because the Text generator is in a separate cpp, I think to optimise the text, the new function would need to be made public, which is not ideal, but not something I would loose sleep over ;-)

void Adafruit_ILI9341_STM::drawPixel(int16_t x, int16_t y, uint16_t color) {

if ((x < 0) || (x >= _width) || (y < 0) || (y >= _height)) return;

if (hwSPI) spi_begin();
setAddrWindow(x, y, x + 1, y + 1);

*dcport |= dcpinmask;
*csport &= ~cspinmask;

spiwrite(color >> 8);
spiwrite(color);

*csport |= cspinmask;
if (hwSPI) spi_end();
}


iwalpola
Sun Jul 03, 2016 11:13 pm
@ Roger, you’re almost right, and you’re referring the SPI code, not the 8 bit parallel. The triangle drawing functions call the functions which draw lines (horizontal, vertical or inclined). These functions in turn call the draw pixel function, but only if length of line is 1px.

However, on the line drawing, screen filling etc, where there is a lot of data to be written, there was room for improvement in CHIP_SELECT toggling and toggling of RS pin (which decides whether data written is command or data).

So after adjusting (after doing a git diff), the benchmark is better than Kurt’s mod!! Maybe there is room for even more improvement, but I guess this is pretty good.

Benchmark Time (microseconds)
Screen fill 784951
Text 27277
Lines 242789
Horiz/Vert Lines 66034
Rectangles (outline) 42204
Rectangles (filled) 1630078
Circles (filled) 240487
Circles (outline) 180967
Triangles (outline) 58242
Triangles (filled) 563808
Rounded rects (outline) 84634
Rounded rects (filled) 1777583


RogerClark
Sun Jul 03, 2016 11:25 pm
Yes. I was referring to the SPI version

Does the parallel version toggle CS etc for every pixel, or did you optimise it?


iwalpola
Sun Jul 03, 2016 11:39 pm
RogerClark wrote:Yes. I was referring to the SPI version

Does the parallel version toggle CS etc for every pixel, or did you optimise it?


RogerClark
Mon Jul 04, 2016 12:43 am
iwalpola wrote:
It was doing CS toggle for every pixel write earlier (my dumb idea). Now I fixed it.

I was worried that it will interfere with the touch digitizer output available in the same module (TFT and Touch share 4 pins).


martinayotte
Mon Jul 04, 2016 2:09 am
I start to misunderstanding the whole thread here :
On every parallel 8bis transfer, there must be an CS pulse.
So, how can that be skipped for optimisation ?

RogerClark
Mon Jul 04, 2016 2:17 am
CS can probably me skipped if only one device is on SPI, but its hard coded into the Adafruit Ili9341 lib.

The other line that has to be toggled a lot is the Data / command pin

It looks like the main reason that writing single pixels is slow is not the CS line but the unnecessary calling of SPI begin transaction before writing each pixel, which takes up a huge amount of time, as the whole SPI device has to be disabled and all settings updated etc etc etc

Some minimal changes would result in a massive speed improvement in some functions e.g. drawing of diagonal lines , but the Adafruit graphics lib would need to also be updated to yield faster text speeds.

If I get time this evening, I will take a quick look at the existing code in the Adafruit_ili9341_STM lib (for F1)


iwalpola
Mon Jul 04, 2016 2:36 am
Yet another performance gain by inlining the write8special() function.
Demo (almost too fast to see):
https://youtu.be/sGU_wwX20hM

@Roger, there must surely be potential for improvement in the SPI code as well. What I learned today is that even microseconds worth of delay adds up fast when you repeat it 10000’s of times.

Benchmark Time (microseconds)
Screen fill 320577
Text 14869
Lines 129592
Horiz/Vert Lines 25437
Rectangles (outline) 16493
Rectangles (filled) 666012
Circles (filled) 104502
Circles (outline) 96406
Triangles (outline) 30358
Triangles (filled) 230338
Rounded rects (outline) 41103
Rounded rects (filled) 709046
Done!


RogerClark
Mon Jul 04, 2016 4:03 am
Thanks for posting an updated video

Re: SPI version

Yes.
Now I look at the code, there is loads of room for improvement, and like you said, even a few uS shaved off here and there in the low level functions make a big difference.

What is still slower for you is the fill stuff as you can’t benefit from DMA. Well, if the pins were adjacent from the beginning of a port you could use DMA as you can DMA to GPIO (but we don’t have any demo code for this)
But as you use pins all over the board, DMA will not really help :-(


ahull
Mon Jul 04, 2016 10:03 am
iwalpola wrote:Yet another performance gain by inlining the write8special() function.
Demo (almost too fast to see):
https://youtu.be/sGU_wwX20hM

@Roger, there must surely be potential for improvement in the SPI code as well. What I learned today is that even microseconds worth of delay adds up fast when you repeat it 10000’s of times.

Benchmark Time (microseconds)
Screen fill 320577
Text 14869
Lines 129592
Horiz/Vert Lines 25437
Rectangles (outline) 16493
Rectangles (filled) 666012
Circles (filled) 104502
Circles (outline) 96406
Triangles (outline) 30358
Triangles (filled) 230338
Rounded rects (outline) 41103
Rounded rects (filled) 709046
Done!


racemaniac
Mon Jul 04, 2016 1:54 pm
RogerClark wrote:Thanks for posting an updated video

Re: SPI version

Yes.
Now I look at the code, there is loads of room for improvement, and like you said, even a few uS shaved off here and there in the low level functions make a big difference.

What is still slower for you is the fill stuff as you can’t benefit from DMA. Well, if the pins were adjacent from the beginning of a port you could use DMA as you can DMA to GPIO (but we don’t have any demo code for this)


RogerClark
Mon Jul 04, 2016 9:28 pm
Thanks

RogerClark
Mon Jul 04, 2016 10:38 pm
@iwalpola

Can you post the code to your sketch that you use for those timing results, as I don’t think its the same sketch that I am using to compare SPI speeds

(Or post a link to the sketch source code)

Thanks

Roger


iwalpola
Tue Jul 05, 2016 9:12 pm
RogerClark wrote:post code

ahull
Tue Jul 05, 2016 10:03 pm
Benchmark Time (microseconds)
Screen fill 320577
...

RogerClark
Tue Jul 05, 2016 10:27 pm
SPI is currently giving me these results

Benchmark Time (microseconds)
Screen fill 170787
Text 22869
Lines 241990
Horiz/Vert Lines 15802
Rectangles (outline) 11547
Rectangles (filled) 355060
Circles (filled) 142830
Circles (outline) 173697
Triangles (outline) 59139
Triangles (filled) 165883
Rounded rects (outline) 59967
Rounded rects (filled) 415460


ahull
Tue Jul 05, 2016 10:32 pm
Its interesting to note that not everything is improved with DMA, line drawing and text for example appears to be slower.
Do we know what the absolute limits of the display are, in terms of speed?

iwalpola
Wed Jul 06, 2016 6:18 am
ahull wrote:Roughly how many parallel writes per second do you think you are able to manage?

iwalpola
Wed Jul 06, 2016 6:59 am
racemaniac wrote:
yes we do :p
http://www.stm32duino.com/viewtopic.php?f=18&t=1042

diger67
Wed Aug 03, 2016 9:23 pm
Hi!
I do not work in an environment with Arduino STM. But can someone come in handy. Here are a few defines. Their work is checked in Keil. Binding conclusions made to the standard location pins Shild TFT for Arduino. New definition write8inline (d) is faster than the previous version.

//Port data |D7 | D6 |D5 |D4 |D3 | D2 |D1 |D0 |
//Pin stm32 |PA8|PB10|PB4|PB5|PB3|PA10|PC7|PA9|
//control port |RST| CS | RS | WR| RD|
//Pin stm32 |PC0|PB0|PA4|PA1|PA0|

#define write8inline(d) {\
GPIOA->BSRR = (data & (1<<0)) ? GPIO_BSRR_BS9 : GPIO_BSRR_BR9;\
GPIOC->BSRR = (data & (1<<1)) ? GPIO_BSRR_BS7 : GPIO_BSRR_BR7;\
GPIOA->BSRR = (data & (1<<2)) ? GPIO_BSRR_BS10 : GPIO_BSRR_BR10;\
GPIOB->BSRR = (data & (1<<3)) ? GPIO_BSRR_BS3 : GPIO_BSRR_BR3;\
GPIOB->BSRR = (data & (1<<4)) ? GPIO_BSRR_BS5 : GPIO_BSRR_BR5;\
GPIOB->BSRR = (data & (1<<5)) ? GPIO_BSRR_BS4 : GPIO_BSRR_BR4;\
GPIOB->BSRR = (data & (1<<6)) ? GPIO_BSRR_BS10 : GPIO_BSRR_BR10;\
GPIOA->BSRR = (data & (1<<7)) ? GPIO_BSRR_BS8 : GPIO_BSRR_BR8;\
WR_STROBE;\
}

#define enportrcc() {\
RCC->APB2ENR |= ((RCC->APB2ENR &= 0xFFFFFFFF) | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN);\
AFIO->MAPR |= ((AFIO->MAPR &= 0xFFFFFFFF) | AFIO_MAPR_SWJ_CFG_JTAGDISABLE);\
GPIOA->CRL = ((GPIOA->CRL &= 0xFFF0FF00) | 0x00030033); \
GPIOC->CRL = ((GPIOC->CRL &= 0xFFFFFF0F) | 0x00000030); \
GPIOB->CRL = ((GPIOB->CRL &= 0xFFFFFFF0) | 0x00000003); \
}

#define setWriteDirInline() { \
GPIOA->CRH = ((GPIOA->CRH &= 0xFFFFF000) | 0x00000333); \
GPIOC->CRL = ((GPIOC->CRL &= 0x0FFFFFFF) | 0x30000000); \
GPIOB->CRL = ((GPIOB->CRL &= 0xFF000FFF) | 0x00333000); \
GPIOB->CRH = ((GPIOB->CRH &= 0xFFFFF0FF) | 0x00000300); \
}

#define setReadDirInline() { \
GPIOA->CRH = ((GPIOA->CRH &= 0xFFFFF000) | 0x00000444); \
GPIOC->CRL = ((GPIOC->CRL &= 0x0FFFFFFF) | 0x40000000); \
GPIOB->CRL = ((GPIOB->CRL &= 0xFF000FFF) | 0x00444000); \
GPIOB->CRH = ((GPIOB->CRH &= 0xFFFFF0FF) | 0x00000400); \
}


Rick Kimball
Wed Aug 03, 2016 10:57 pm
… this line:

#define enportrcc() {\
RCC->APB2ENR |= ((RCC->APB2ENR &= 0xFFFFFFFF) | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN);\
AFIO->MAPR |= ((AFIO->MAPR &= 0xFFFFFFFF) | AFIO_MAPR_SWJ_CFG_JTAGDISABLE);\

Are you trying to clear the APB2ENR register with the &= ((RCC->APB2ENR &= 0xFFFFFFFF) ?

It is probably easier to set it to zero or use &= ((RCC->APB2ENR &= ~0xFFFFFFFF)

Or maybe I misunderstand what you are doing there.

-rick


diger67
Wed Aug 03, 2016 11:22 pm
Rick Kimball wrote:

Are you trying to clear the APB2ENR register with the &= ((RCC->APB2ENR &= 0xFFFFFFFF) ?

It is probably easier to set it to zero or use &= ((RCC->APB2ENR &= ~0xFFFFFFFF)

Or maybe I misunderstand what you are doing there.

-rick


stevestrong
Fri Aug 26, 2016 11:14 pm
Well, I had to reinvent the wheel and adapt the original lib TFTLCD lib from Adafruit for STM32, because my LCD was an ILI9328, not an ILI9341, as iwalpola’s lib.
Also, I had to stick to digital write and read functions, because the pure register writes for pin toggling was too fast and the screen went blank!
Here my benchmark using Adafruit original graphic test ino:
TFT LCD test
TFT size is 240x320
Found ILI9328 LCD driver

Benchmark Time (microseconds)
Screen fill 1019555
Text 115645
Lines 719977
Horiz/Vert Lines 96056
Rectangles (outline) 69857
Rectangles (filled) 2155387
Circles (filled) 843279
Circles (outline) 313036
Triangles (outline) 228363
Triangles (filled) 993928
Rounded rects (outline) 146794
Rounded rects (filled) 2514008
Done!


stevestrong
Sat Sep 03, 2016 12:50 pm
After getting the LCD reset to work correctly, this is what I achieve using the Adafruit lib ported to STM32:
TFT LCD test
TFT size is 240x320
Found ILI9328 LCD driver
Benchmark Time (microseconds)
Screen fill 65561
Text 24708
Lines 141805
Horiz/Vert Lines 8723
Rectangles (outline) 7335
Rectangles (filled) 155516
Circles (filled) 134162
Circles (outline) 60283
Triangles (outline) 45012
Triangles (filled) 115087
Rounded rects (outline) 24511
Rounded rects (filled) 206878
Done!
rotation: 0, text runtime: 24708
rotation: 1, text runtime: 24972
rotation: 2, text runtime: 24973
rotation: 3, text runtime: 24985

VadimEL
Sat Sep 03, 2016 5:44 pm
C:\Documents and Settings\Vadim\Мои документы\Arduino\hardware\Arduino_STM32\STM32F1\libraries\Adafruit_TFTLCD_8bit_STM32\Adafruit_TFTLCD_8bit_STM32.h

line 84
#define read8(x) { x = read8_() ;}
===================================


stevestrong
Sat Sep 03, 2016 7:03 pm
VadimEL wrote:Adafruit_TFTLCD_8bit_STM32.h
line 84
#define read8(x) { x = read8_() ;}

Itudylla
Wed Feb 15, 2017 7:32 am
thanks a lot for letting us know about these manipulations, they make the workers’ lives easier!

Leave a Reply

Your email address will not be published. Required fields are marked *