SPI Chipselect won't work

fofi144
Posts: 7
Joined: Fri Jan 18, 2019 5:09 pm

SPI Chipselect won't work

Postby fofi144 » Wed Jun 19, 2019 11:23 am

Hi :)

I'm currently working on a little project that uses 4 LCDs (st7735 controller). They are connected as followed:
Mosi=4 , SCK=14 , A0 = 5 , CS1=2 , CS2= 26, CS3= 25, CS4= 32

Problem: Only CS1 (GPIO2) will work. All other CS stay low. I can't think of any reason why :cry:

This is my code. I also attached the code in a .zip below. Please help, this is driving me crazy :?

Code for Main.c . Only 3 Displays are used at the moment, so the second SPI is commented out.

Code: Select all

// TFT Test for LX177B Library
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "esp_attr.h"
#include "nvs_flash.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "LX177B.h"
#include "freertos/queue.h"


//LCD Grundvariablen
TickType_t xDelay30ms = pdMS_TO_TICKS(30);


//Struct für LCD
typedef struct
{
	uint8_t Life[4];	
	uint8_t Mode;
	uint8_t Modeval;
}LCD_Trans_t;
 
//Queue für LCD (4 Einträge a 6 bytes)
QueueHandle_t  LCD_Queue_handler;

void lcd_task(void *pvParameter)
{
	//SPI Handler
	spi_device_handle_t Display_Handler[4];
	
	const uint16_t Col_a = 0b1111101000110010;
	const uint16_t Col_b = 0x291F;
	const uint16_t Col_white = 0xFFFF;
	const uint16_t Col_red =	0b1111100000000000;
	const uint16_t Col_orange =	0b1111100110000000;
	const uint16_t Col_blue = 0b0000001111100000;

	//Display Data
	LCD_Trans_t LCD_Data_REC;
	
	//Display Pos
	const uint8_t Life_y_Pos = 80;
	const uint8_t Boost_y_Pos = 100;
	
	
	
	//################ INIT #################/
	// Hardware kann nur 3 CS bedienen, daher 2 SPI Busse für 4 Geräte :(
	// Mosi=4 , SCK=14 , A0 = 5 , CS1=2 , CS2= 26, CS3= 25, CS4= 32
	// Mosi=25 , SCK=27, CS4= 18
	LX_Init_SPI(VSPI_HOST, 4, 14, 1);	
	//LX_Init_SPI(VSPI_HOST, 23, 24, 2);	
		
	LX_Create_Device(VSPI_HOST, &Display_Handler[0], 2, 5);		//pink
	LX_Create_Device(VSPI_HOST, &Display_Handler[1], 26, 5);	//gelb
	LX_Create_Device(VSPI_HOST, &Display_Handler[2], 25, 5);	//grün
	//LX_Create_Device(VSPI_HOST, &Display_Handler[3], 32, 5);	//rot
	
	LX_Init_Chip(&Display_Handler[0], BLACKTAB_128_160);
	LX_Init_Chip(&Display_Handler[1], BLACKTAB_128_160);
	LX_Init_Chip(&Display_Handler[2], BLACKTAB_128_160);
	//LX_Init_Chip(&Display_Handler[3], BLACKTAB_128_160);
	
	LX_set_orientation(&Display_Handler[0], ST7735_LANDSCAPE, BLACKTAB_128_160);
	LX_set_orientation(&Display_Handler[1], ST7735_LANDSCAPE, BLACKTAB_128_160);
	LX_set_orientation(&Display_Handler[2], ST7735_LANDSCAPE, BLACKTAB_128_160);
	//LX_set_orientation(&Display_Handler[3], ST7735_LANDSCAPE, BLACKTAB_128_160);
	
	
	while (1)
	{	
		//Neue Daten abfragen
		xQueueReceive(LCD_Queue_handler, &LCD_Data_REC, NULL);
		
		
		for (uint8_t z = 0; z < 3; z++)
		{
			//LCD SRAM löschen
			LX_delete_SRAM();		
		
			switch (LCD_Data_REC.Mode)
			{
				//Mode=1 -> Balkenanzeige
				case 1: 
					LX_draw_rect(0, 0, 159, 30, Col_b, 2);
					LX_draw_text(30, 20, "Boostmode", &FreeSans, 1, Col_a);	
			
					LX_draw_text(2, (Life_y_Pos + 12), "Leben", &TomThumb, 2, Col_white);
					LX_draw_rect(51, Life_y_Pos, 159, (Life_y_Pos + 15), Col_white, 2);
					for (int i = 1; i <= LCD_Data_REC.Life[z]; i++)
					{
						LX_fill_rect((56 + (i - 1)*(30 + 4)), (Life_y_Pos + 3), (56 + 30*i + 4*(i - 1)), (Life_y_Pos + 12), Col_red);			
					}
			
					LX_draw_text(2, (Boost_y_Pos + 12), "Boost", &TomThumb, 2, Col_white);
					LX_draw_rect(51, Boost_y_Pos, 159, (Boost_y_Pos + 15), Col_white, 2);
					LX_fill_rect(56, (Boost_y_Pos + 3), (56 + LCD_Data_REC.Modeval), (Boost_y_Pos + 12), Col_blue);	
			
				break;
	
				case 2:
					LX_draw_rect(0, 0, 159, 30, Col_b, 2);
					LX_draw_text(30, 20, "Deathmatch", &FreeSans, 1, Col_a);	
			
					LX_draw_text(2, (Life_y_Pos + 12), "Leben", &TomThumb, 2, Col_white);
					LX_draw_rect(51, Life_y_Pos, 159, (Life_y_Pos + 15), Col_white, 2);
					for (int i = 1; i <= LCD_Data_REC.Life[z]; i++)
					{
						LX_fill_rect((56 + (i - 1)*(30 + 4)), (Life_y_Pos + 3), (56 + 30*i + 4*(i - 1)), (Life_y_Pos + 12), Col_red);			
					}
			
					LX_draw_text(2, (Boost_y_Pos + 12), "Speed", &TomThumb, 2, Col_white);
					LX_draw_rect(51, Boost_y_Pos, 159, (Boost_y_Pos + 15), Col_white, 2);
					LX_fill_rect(56, (Boost_y_Pos + 3), (56 + LCD_Data_REC.Modeval), (Boost_y_Pos + 12), (Col_orange + (LCD_Data_REC.Modeval*5)));		
				break;
			
				default:
				break;
			}
		
			//Aktualisieren der 4 Endgeräte
			LX_start_full_refresh(&Display_Handler[z]);
			vTaskDelay(xDelay30ms);
			LX_stop_full_refresh(&Display_Handler[z]);
		}
	}		
}

void Queue_task(void*pvParam)
{

	LCD_Trans_t Test_Data =
	{
		.Mode = 0x01, 
		.Modeval = 50,
		.Life[0] = 1,
		.Life[1] = 2,
		.Life[2] = 3,
		.Life[3] = 0
	};
	
	while (1)
	{
		if (Test_Data.Modeval < 100)
		{
			Test_Data.Modeval++;
		}
		else
		{
			Test_Data.Modeval = 0;
		}
	
		xQueueSend(LCD_Queue_handler, (void*)&Test_Data, NULL);
		
		vTaskDelay(xDelay30ms);
	}
	
}


void app_main()
{	
	
	//Queue
	LCD_Queue_handler = xQueueCreate(6, sizeof(LCD_Trans_t));
	
	//Task erstellen
	xTaskCreate(lcd_task, "lcd_task", 2048, NULL, 5, NULL);
	xTaskCreate(Queue_task, "Queue_task", 2048, NULL, 5, NULL);
	
}
Code of the LX177B.c Display Library

Code: Select all

#include "LX177B.h"


//Globale Variablen
LCD_Data_t *LX_SRAM;
spi_transaction_t LX_DATA;
gpio_num_t A0;


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++			Hardware Defines		++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//Device auf dem SPI Bus erstellen
void LX_Create_Device(spi_host_device_t SPI, spi_device_handle_t *SPI_Handler, gpio_num_t NSEL, gpio_num_t A0_Pin)
{	
	//Pin einstellen
	A0 = A0_Pin;
	gpio_pad_select_gpio(A0_Pin);
	gpio_set_direction(A0_Pin, GPIO_MODE_OUTPUT);
	
	//Config des LCD in den Struct eintragen
	//CPHA=0 CPOL=0
	//MSb first
	//CLK mit 50% Dutycycle
	//CS geht 3 Cycle vor und nach Transaktion auf High
	spi_device_interface_config_t LX_Config;
	memset(&LX_Config, 0, sizeof(LX_Config));
	LX_Config.address_bits = 0;
	LX_Config.clock_speed_hz = SPI_MASTER_FREQ_16M;				//16,6Mhz theoretisch ok
	LX_Config.spics_io_num = NSEL;
	LX_Config.queue_size = 4;
	LX_Config.mode = 0;
	LX_Config.cs_ena_pretrans = 2;
	LX_Config.flags = SPI_DEVICE_HALFDUPLEX;
	
	//Dem zuvor initialisierten Bus ein Gerät hinzufügen
	ESP_ERROR_CHECK(spi_bus_add_device(SPI, &LX_Config, SPI_Handler));	
	ESP_LOGI(LX_TAG,"GLCD: SPI Device created, CS= %d,A0=%d",NSEL,A0_Pin);	
}


//SPI Init für das LX177B LCD
void LX_Init_SPI(spi_host_device_t SPI_Channel, gpio_num_t Mosi, gpio_num_t Clk, int DMA_Channel)
{
	//SPI Pins definieren
	spi_bus_config_t LX_bus_cfg = 
	{ 
		.miso_io_num = -1,
		.mosi_io_num = Mosi,
		.sclk_io_num = Clk,
		.quadwp_io_num = -1,
		.quadhd_io_num = -1,
		.max_transfer_sz = 128*160*2
	};

	//Init des SPI BUS selbst
	ESP_ERROR_CHECK(spi_bus_initialize(SPI_Channel, &LX_bus_cfg, DMA_Channel));
	ESP_LOGI(LX_TAG, "GLCD: SPI initialized");
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++			Interne Routinen		++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//LX Command schreiben
void inline LX_Write_Command(spi_device_handle_t *SPI_Handler, uint8_t *Data,uint8_t Bytes_to_send)
{
	//Benutzt den Buffer und macht keinen Read (wichtig für HalfDuplex)	
	gpio_set_level(A0, 0);
	
	spi_transaction_t LX_dout;
	memset(&LX_dout, 0, sizeof(LX_dout));
	LX_dout.tx_buffer = Data;
	LX_dout.length = 8*Bytes_to_send;
	
	ESP_ERROR_CHECK(spi_device_polling_start(*SPI_Handler, &LX_dout, portMAX_DELAY));
	ESP_ERROR_CHECK(spi_device_polling_end(*SPI_Handler, portMAX_DELAY)); 		
}

//LX Parameter schreiben
void inline LX_Write_Parameter(spi_device_handle_t *SPI_Handler, uint8_t *Data, uint8_t Bytes_to_send)
{
	//Benutzt den Buffer und macht keinen Read (wichtig für HalfDuplex)	
	gpio_set_level(A0, 1);
	
	spi_transaction_t LX_dout;
	memset(&LX_dout, 0, sizeof(LX_dout));
	LX_dout.tx_buffer = Data;
	LX_dout.length = 8*Bytes_to_send;
	
	ESP_ERROR_CHECK(spi_device_polling_start(*SPI_Handler, &LX_dout, portMAX_DELAY));
	ESP_ERROR_CHECK(spi_device_polling_end(*SPI_Handler, portMAX_DELAY)); 		
}


//°°°°°° Write Commandset °°°°°°°
void ST7735_write_Commandset(spi_device_handle_t *SPI_Handler, const uint8_t *Adress)
{
	uint8_t i = 1;
	uint8_t Pause = 0;
	uint8_t Pausetime = 0;
	
	CMD_t Dout;
	
	uint8_t Commands_to_send;
	uint8_t Bytes_to_send;
	
	//Anzahl der zu sendenden Befehle extrahieren
	Commands_to_send = *Adress;
	
	//Befehle nacheinander abarbeiten
	for(uint8_t ct = 0 ; ct < Commands_to_send ; ct++)
	{
		//Startwerte
		Pause = 0;					
		Bytes_to_send = 0;
		
		//CMD extrahieren
		Dout.reg = *(Adress + i);
		i++;
		
		//Anzahl Bytes extrahieren
		Bytes_to_send = *(Adress + i);	
		i++;
		
		//Pause vorhanden, Pausenindikator entfernen
		if(Bytes_to_send >= DELAY_FLAG)
		{
			Bytes_to_send = Bytes_to_send - DELAY_FLAG;
			Pause = 1;
		}
		
		//Nutzdaten auslesen
		for(uint8_t z = 0 ; z < Bytes_to_send ; z++)
		{
			Dout.data[z] = *(Adress + i);		
			i++;
		}
		
		//Senden		
		LX_Write_Command(SPI_Handler, &Dout.reg, (1));
		if (Bytes_to_send > 0)
		{
			LX_Write_Parameter(SPI_Handler, &(Dout.data[0]), Bytes_to_send);
		}
		
		
		//Pause auslesen
		if(Pause > 0)
		{
			Pausetime = *(Adress + i);
			i++;
			vTaskDelay(Pausetime / portTICK_PERIOD_MS);
		}
		
	}
	
}

//°°°°°° RAM Bereich festlegen °°°°°°°
void ST7735_window_set(spi_device_handle_t *SPI_Handler ,uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
{
	uint8_t Command[5];
			
	Command[0] = ST7735_CASET;
	LX_Write_Command(SPI_Handler, &Command[0], 1);
	Command[1] = 0x00;
	Command[2] = x1;
	Command[3] = 0;
	Command[4] = x2;
	LX_Write_Parameter(SPI_Handler, &Command[1], 4);
	
	Command[0] = ST7735_RASET;
	LX_Write_Command(SPI_Handler, &Command[0], 1);
	Command[1] = 0x00;
	Command[2] = y1;
	Command[3] = 0x00;
	Command[4] = y2;
	LX_Write_Parameter(SPI_Handler, &Command[1], 4);
	
	Command[0] = ST7735_RAMWR;		
	LX_Write_Command(SPI_Handler, &Command[0], 1);
	
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++			Benutzerroutinen		++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//°°°°°°° LCD Init °°°°°°°
void LX_Init_Chip(spi_device_handle_t *SPI_Handler, enum ST7735_DISPLAY_TYPE Colour_of_tab)
{
	uint8_t Val;
	
	
	//Init des Displaycontrollers
	switch (Colour_of_tab) 
	{
	case BLUETAB_128_160:
		ST7735_write_Commandset(SPI_Handler,st7735_blue_init);
		break;

	case GREENTAB_128_160:
		ST7735_write_Commandset(SPI_Handler,st7735_red_init1);
		ST7735_write_Commandset(SPI_Handler,st7735_red_init_green2);
		ST7735_write_Commandset(SPI_Handler,st7735_red_init3);
		break;

	case REDTAB_128_160:
		ST7735_write_Commandset(SPI_Handler,st7735_red_init1);
		ST7735_write_Commandset(SPI_Handler,st7735_red_init_red2);
		ST7735_write_Commandset(SPI_Handler,st7735_red_init3);
		break;

	case BLACKTAB_128_160:
		ST7735_write_Commandset(SPI_Handler,st7735_red_init1);
		ST7735_write_Commandset(SPI_Handler,st7735_red_init_red2);
		ST7735_write_Commandset(SPI_Handler,st7735_red_init3);
		Val = ST7735_MADCTL;
		LX_Write_Command(SPI_Handler, &Val, 1);
		Val = 0xC0;	
		LX_Write_Parameter(SPI_Handler, &Val, 1);
		break;
	}
	
	//Speicherplatz für LCD reservieren
	LX_SRAM = heap_caps_malloc(sizeof(LCD_Data_t), MALLOC_CAP_DMA);
	assert(LX_SRAM != NULL);	
}

//°°°°°°° LCD Ausrichtung °°°°°°°
void LX_set_orientation(spi_device_handle_t *SPI_Handler, enum ST7735_ORIENTATION orientation, enum ST7735_DISPLAY_TYPE Colour_of_tab)
{
	uint8_t Val;
	
	Val = ST7735_MADCTL;
	LX_Write_Command(SPI_Handler,&Val,1);

	
	switch (orientation) 
	{
		case ST7735_PORTRAIT:
			if (Colour_of_tab == BLACKTAB_128_160) 
			{
				Val = MADCTL_MX | MADCTL_MY | MADCTL_RGB;
			}
			else
			{
				Val =MADCTL_MX | MADCTL_MY | MADCTL_BGR;
			}
		break;


		case ST7735_LANDSCAPE:
			if (Colour_of_tab == BLACKTAB_128_160) 
			{
				Val =MADCTL_MY | MADCTL_MV | MADCTL_RGB;
			}
			else
			{
				Val =MADCTL_MY | MADCTL_MV | MADCTL_BGR;
			}
		break;

		case ST7735_PORTRAIT_INV:
			if (Colour_of_tab == BLACKTAB_128_160) 
			{
				Val =MADCTL_RGB;
			}
			else 
			{
				Val =MADCTL_BGR;
			}
		break;

		case ST7735_LANDSCAPE_INV:
			if (Colour_of_tab == BLACKTAB_128_160)
			{
				Val = MADCTL_MX | MADCTL_MV | MADCTL_RGB;
			}
			else
			{
				Val = MADCTL_MX | MADCTL_MV | MADCTL_BGR;
			}
		break;
	}	
	
	LX_Write_Parameter(SPI_Handler,&Val, 1);
	
}

//°°°°°°° Rechteck zeichnen °°°°°°°
void LX_fill_rect(uint8_t x1, uint8_t y1,uint8_t x2,uint8_t y2,uint16_t Colour)
{
	if ((x1 > x2) | (x2 > 159) | (x1 > 159))
	{
		ESP_LOGI(LX_TAG, "x-Coordinates corrupt");
		return;
	}
	
	if ((y1 > y2) | (y2 > 127) | (y1 > 127))
	{
		ESP_LOGI(LX_TAG, "y-Coordinates corrupt");
		return;
	}
	
	//Dots setzen
	for (uint32_t x = x1; x <= x2; x++)
	{

		for (uint32_t y = y1; y <= y2; y++)
		{
			(LX_SRAM->Dot[y][x])=Colour;	
		}
	}	
}

//°°°°°°° Kasten zeichnen °°°°°°°
void LX_draw_rect( uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t Colour,uint8_t Line_width)
{
	if ((x1 > x2) | (x2 > 159) | (x1 > 159))
	{
		ESP_LOGI(LX_TAG, "x-Coordinates corrupt");
		return;
	}
	
	if ((y1 > y2) | (y2 > 127) | (y1 > 127))
	{
		ESP_LOGI(LX_TAG, "y-Coordinates corrupt");
		return;
	}
	
	//Dots setzen linie oben
	for(uint32_t x = x1 ; x <= x2 ; x++)
	{
		for (uint8_t L = 0; L < Line_width; L++)
		{
			(LX_SRAM->Dot[y1+L][x]) = Colour;	
		}	
	}	
	
	//Dots setzen linie unten
	for (uint32_t x = x1; x <= x2; x++)
	{
		for (uint8_t L = 0; L < Line_width; L++)
		{
			(LX_SRAM->Dot[y2 - L][x])= Colour;	
		}	
	}	
	
	//Dots setzen linie senkrecht
	for (uint32_t y = y1; y <= y2; y++)
	{
		for (uint8_t L = 0; L < Line_width; L++)
		{
			(LX_SRAM->Dot[y][x1+L]) = Colour;	
		}		
	}
	
	//Dots setzen linie senkrecht
	for(uint32_t y = y1 ; y <= y2 ; y++)
	{
		for (uint8_t L = 0; L < Line_width; L++)
		{
			(LX_SRAM->Dot[y][x2 - L]) = Colour;	
		}		
	}	
}

//°°°°°°° VLINE zeichnen °°°°°°°
void LX_draw_vline( uint8_t x1, uint8_t x2, uint8_t y, uint16_t Colour, uint8_t Line_width)
{
	if ((x1 > x2) | (x2 > 159) | (x1 > 159))
	{
		ESP_LOGI(LX_TAG, "x-Coordinates corrupt");
		return;
	}
	
	if (y > 127)
	{
		ESP_LOGI(LX_TAG, "y-Coordinate corrupt");
		return;
	}
	
	//Dots setzen linie oben
	for(uint32_t x = x1 ; x <= x2 ; x++)
	{
		for (uint8_t L = 0; L < Line_width; L++)
		{
			(LX_SRAM->Dot[y + L][x]) = Colour;	
		}	
	}	
}

//°°°°°°° HLINE zeichnen °°°°°°°
void LX_draw_hline( uint8_t y1, uint8_t y2, uint8_t x, uint16_t Colour, uint8_t Line_width)
{
	if ((y1 > y2) | (y2 > 127) | (y1 > 127))
	{
		ESP_LOGI(LX_TAG, "y-Coordinates corrupt");
		return;
	}
	
	if (x > 159)
	{
		ESP_LOGI(LX_TAG, "x-Coordinate corrupt");
		return;
	}
	
	//Dots setzen linie oben
	for(uint32_t y = y1 ; y <= y2 ; y++)
	{
		for (uint8_t L = 0; L < Line_width; L++)
		{
			(LX_SRAM->Dot[y][x+L]) = Colour;	
		}	
	}	
}

//°°°°°°° CHAR zeichnen °°°°°°°
void LX_draw_char(int16_t x,int16_t y,const GFXglyph *glyph,const GFXfont *font,uint8_t size,uint16_t color) 
{
    if(size < 1) 
    {
	    ESP_LOGI(LX_TAG, "Char Size <1");
        return;
    }

    uint8_t  *bitmap = font->bitmap;
    uint16_t bo = glyph->bitmapOffset;
    uint8_t bits = 0, bit = 0;
    uint16_t set_pixels = 0;
    uint8_t  cur_x, cur_y;
	uint8_t xs, ys;
	
    for(cur_y = 0; cur_y < glyph->height; cur_y++)
    {
        for(cur_x = 0; cur_x < glyph->width; cur_x++)
        {
	        //Neues Byte für das zeichen lesen
            if(bit == 0) 
            {
                bits =*(bitmap+bo);
	            bo++;
                bit  = 0x80;
            }

            if(bits & bit) 
            {
                set_pixels++;
            }
	        else if (set_pixels > 0) 
            {
	            xs = (x + (glyph->xOffset + cur_x - set_pixels) * size);
	            ys = (y + (glyph->yOffset + cur_y) * size);
                LX_fill_rect(xs, ys,xs+(size * set_pixels), (ys +size), color);
                set_pixels=0;
            }

            bit >>= 1;
        }

        // Draw rest of line
        if (set_pixels > 0) 
        {
	        xs = (x + (glyph->xOffset + cur_x - set_pixels) * size);
	        ys = (y + (glyph->yOffset + cur_y) * size);
            LX_fill_rect(xs,ys,(xs +size * set_pixels),(ys +size),color);
            set_pixels=0;
        }
    }
}

//°°°°°°° TEXT zeichnen °°°°°°°
void LX_draw_text(int8_t x,	int8_t y,char *text,const GFXfont *p_font,uint8_t size,uint16_t color) 
{

	int32_t cursor_x = x;
	int32_t cursor_y = y;

	GFXfont font;
	memcpy(&font, p_font, sizeof(GFXfont));


	for (uint32_t text_pos = 0; text_pos < strlen(text); text_pos++) {
		char c = text[text_pos];

		if (c == '\n') {
			cursor_x = x;
			cursor_y += font.yAdvance * size;
		}
		else if (c >= font.first && c <= font.last && c != '\r') {
			GFXglyph glyph;
			memcpy(&glyph, &font.glyph[c - font.first], sizeof(GFXglyph));

			LX_draw_char(cursor_x, cursor_y, &glyph, &font, size, color);
			cursor_x += glyph.xAdvance * size;
		}

	}

}

//°°°°°°° SRAM löschen °°°°°°°
void LX_delete_SRAM()
{
	for (int i = 0; i < (128 * 160); i++)
	{
		LX_SRAM->Data[i] = 0x00;		
	}
}

//°°°°°°° LCD aktualisieren °°°°°°°
void LX_start_full_refresh(spi_device_handle_t *SPI_Handler)
{
	
	//Kompletten Speicher beschreiben
	ST7735_window_set(SPI_Handler, 0, 0, 159, 127);
		
	//Spi Struct 
	memset(&LX_DATA, 0, sizeof(LX_DATA));
	LX_DATA.length = 128*160*16;
	LX_DATA.rxlength = 0;
	LX_DATA.tx_buffer = LX_SRAM;	
	
	gpio_set_level(A0, 1);
	ESP_ERROR_CHECK(spi_device_queue_trans(*SPI_Handler, &LX_DATA, portMAX_DELAY));

}

void LX_stop_full_refresh(spi_device_handle_t *SPI_Handler)
{
	spi_transaction_t *LX_DATA_RES;

	ESP_ERROR_CHECK(spi_device_get_trans_result(*SPI_Handler, &LX_DATA_RES, portMAX_DELAY));
	assert(LX_DATA_RES == &LX_DATA);	
}




//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++++++			Datensätze			++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
const uint8_t st7735_blue_init[] =
{									// Initialization commands for 7735B screens
    18,                       		// 18 commands in list:
    ST7735_SWRESET, DELAY_FLAG,  	//  1: Software reset, no args, w/delay
      	50,                     	//     50 ms delay
    ST7735_SLPOUT, DELAY_FLAG,  	//  2: Out of sleep mode, no args, w/delay
      	255,                    	//     255 = 500 ms delay
    ST7735_COLMOD, 1 | DELAY_FLAG,  //  3: Set color mode, 1 arg + delay:
      	0x05,                   	//     16-bit color
      	10,                     	//     10 ms delay
    ST7735_FRMCTR1, 3 | DELAY_FLAG, //  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_FLAG,  //  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_FLAG,  // 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_FLAG,// 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_FLAG,  		// 17: Normal display on, no args, w/delay
      	10,                     	//     10 ms delay
    ST7735_DISPON, DELAY_FLAG,  	// 18: Main screen turn on, no args, w/delay
      	255							//     255 = 500 ms delay
};

const uint8_t st7735_red_init1[] = { // Init for 7735R, part 1 (red or green tab)
    15,                       	// 15 commands in list:
    ST7735_SWRESET,	DELAY_FLAG, //  1: Software reset, 0 args, w/delay
      	150,                    //     150 ms delay
    ST7735_SLPOUT, DELAY_FLAG,  //  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
};

const uint8_t st7735_red_init_green2[] = { // 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
};

const uint8_t st7735_red_init_red2[] = { // 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
};

const uint8_t st7735_red_init3[] = { // 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_FLAG, 		//  3: Normal display on, no args, w/delay
      	10,                     	//     10 ms delay
    ST7735_DISPON, DELAY_FLAG, 		//  4: Main screen turn on, no args w/delay
      	100                  		//     100 ms delay
};
LX177B.h

Code: Select all

#ifndef  LX177_H
#define LX177_H

	#include <stdio.h>
	#include "freertos/FreeRTOS.h"
	#include "freertos/task.h"
	#include "driver/gpio.h"
	#include "driver/spi_master.h"
	#include <stdio.h>
	#include <stdlib.h>
	#include <string.h>
	#include "driver/gpio.h"
	#include "esp_log.h"
	#include "esp_heap_caps.h" 
	#include "LX_FONT.h"

//------------------------------------------------------------------------------------------------------
//							Registerwerte und Definitionen
//------------------------------------------------------------------------------------------------------
	#define ST7735_NOP  0x00
	#define ST7735_SWRESET  0x01
	#define ST7735_RDDID  0x04
	#define ST7735_RDDST  0x09
	#define ST7735_SLPIN  0x10
	#define ST7735_SLPOUT  0x11
	#define ST7735_PTLON  0x12
	#define ST7735_NORON  0x13
	#define ST7735_INVOFF  0x20
	#define ST7735_INVON  0x21
	#define ST7735_DISPOFF  0x28
	#define ST7735_DISPON  0x29
	#define ST7735_CASET  0x2A
	#define ST7735_RASET  0x2B
	#define ST7735_RAMWR  0x2C
	#define ST7735_RAMRD  0x2E
	#define ST7735_PTLAR  0x30
	#define ST7735_COLMOD  0x3A
	#define ST7735_MADCTL  0x36
	#define ST7735_FRMCTR1  0xB1
	#define ST7735_FRMCTR2  0xB2
	#define ST7735_FRMCTR3  0xB3
	#define ST7735_INVCTR  0xB4
	#define ST7735_DISSET5  0xB6
	#define ST7735_PWCTR1  0xC0
	#define ST7735_PWCTR2  0xC1
	#define ST7735_PWCTR3  0xC2
	#define ST7735_PWCTR4  0xC3
	#define ST7735_PWCTR5  0xC4
	#define ST7735_VMCTR1  0xC5
	#define ST7735_RDID1  0xDA
	#define ST7735_RDID2  0xDB
	#define ST7735_RDID3  0xDC
	#define ST7735_RDID4  0xDD
	#define ST7735_PWCTR6  0xFC
	#define ST7735_GMCTRP1  0xE0
	#define ST7735_GMCTRN1  0xE1	
	#define DELAY_FLAG      0x80   

	//Colour of Tab
	enum ST7735_DISPLAY_TYPE {
		BLUETAB_128_160,
		GREENTAB_128_160,
		REDTAB_128_160,
		BLACKTAB_128_160,
	};

	//Orientation
	enum ST7735_ORIENTATION {
		ST7735_LANDSCAPE,
		ST7735_PORTRAIT,
		ST7735_LANDSCAPE_INV,
		ST7735_PORTRAIT_INV
	};

	//Display Modes
	enum ST7735_MADCTL_ARGS {
		MADCTL_MY = 0x80, // Mirror Y
		MADCTL_MX = 0x40, // Mirrror x
		MADCTL_MV = 0x20, // Swap XY
		MADCTL_ML = 0x10, // Scan address order
		MADCTL_RGB = 0x00,
		MADCTL_BGR = 0x08,
		MADCTL_MH = 0x04 	// Horizontal scan oder
	};

//------------------------------------------------------------------------------------------------------
//							Typendefinitionen
//------------------------------------------------------------------------------------------------------
	//Typedefs
	typedef struct __attribute__((__packed__))
	{	
		uint8_t reg;
		uint8_t data[16];		
	} CMD_t;

	typedef union
	{
		uint16_t Dot[128][160];
		uint16_t Data[20480];
	}LCD_Data_t;
//------------------------------------------------------------------------------------------------------
//							Globale Variablen
//------------------------------------------------------------------------------------------------------
	static const char *LX_TAG = "GLCD:";
	extern const uint8_t st7735_blue_init[];
	extern const uint8_t st7735_red_init1[];
	extern const uint8_t st7735_red_init_green2[];
	extern const uint8_t st7735_red_init_red2[];
	extern const uint8_t st7735_red_init3[];
	extern spi_transaction_t LX_DATA;
	extern LCD_Data_t *LX_SRAM;

//------------------------------------------------------------------------------------------------------
//							InitFunktionen mit Polling
//------------------------------------------------------------------------------------------------------

	/* SPI Init
	 * (*)Handler-> Pointer auf Handler
	 *  SPI_Channel -> SPI Channel (VSPI oder HSPI)
	 *  DMA_Channel -> (0=kein DMA, 1/2=DMA Channel 1/2)*/
	void LX_Init_SPI(spi_host_device_t SPI_Channel, gpio_num_t Mosi, gpio_num_t Clk, int DMA_Channel);

	/* Chip Init (internes Polling)*/
	void LX_Init_Chip(spi_device_handle_t *SPI_Handler, enum ST7735_DISPLAY_TYPE Colour_of_tab);

	/* Einzelnen Befehl mithilfe von Polling setzen*/
	void LX_Write_Command(spi_device_handle_t *SPI_Handler, uint8_t *Data, uint8_t Bytes_to_send);

	/* Device auf dem SPI Bus erstellen*/
	void LX_Create_Device(spi_host_device_t SPI, spi_device_handle_t *SPI_Handler, gpio_num_t NSEL, gpio_num_t A0_Pin);

	void ST7735_write_Commandset(spi_device_handle_t *SPI_Handler, const uint8_t *Adress);

	void LX_set_orientation(spi_device_handle_t *SPI_Handler, enum ST7735_ORIENTATION orientation, enum ST7735_DISPLAY_TYPE Colour_of_tab);

	void ST7735_window_set(spi_device_handle_t *SPI_Handler, uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);

	//------------------------------------------------------------------------------------------------------
	//								  SRAM Manipulationen
	//------------------------------------------------------------------------------------------------------
	void LX_delete_SRAM();
	void LX_draw_rect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t Colour, uint8_t Line_width);
	void LX_draw_hline(uint8_t y1, uint8_t y2, uint8_t x, uint16_t Colour, uint8_t Line_width);
	void LX_draw_vline(uint8_t x1, uint8_t x2, uint8_t y, uint16_t Colour, uint8_t Line_width);
	void LX_draw_char(int16_t x, int16_t y, const GFXglyph *glyph, const GFXfont *font, uint8_t size, uint16_t color);
	void LX_draw_text(int8_t x, int8_t y, char *text, const GFXfont *p_font, uint8_t size, uint16_t color);
	void LX_fill_rect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t Colour);

	//------------------------------------------------------------------------------------------------------
	//							Sendefunktionen mit Interrupt
	//------------------------------------------------------------------------------------------------------


	/*Daten aus der Arbeitsvariable an das Display senden. Die Daten werden in die Queue gelegt
	 *und müssen später unbedingt mit der stop_refresh-Funktion abgeholt werden*/
	void LX_start_full_refresh(spi_device_handle_t *SPI_Handler);

	/*Die Queue abfragen. Sollte der falsche Queue-Eintrag erwischt werden gibt es einen Assert-Fehler
	 *Folglich stürzt der Controller ab bei einem solchen Fehler*/
	void LX_stop_full_refresh(spi_device_handle_t *SPI_Handler);

#endif
Attachments
Code.zip
(17.43 KiB) Downloaded 396 times
Unbenannt.PNG
Unbenannt.PNG (42 KiB) Viewed 3153 times

Who is online

Users browsing this forum: No registered users and 146 guests