Spark Logic

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; }

Replies

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.

Sign in to reply