C Problem mit TouchPanel Interrupt am XV-TFT60D

0n3 70uch

Neues Mitglied
26. Mai 2010
54
0
0
Wermelskirchen
Sprachen
  1. ANSI C
Hallo,

nachdem ich mich nun lange Zeit nicht mehr mit den AVRs beschäftigt habe, bestellt ich mir vor einigen tagen ein 4,3 Zoll XV-TFT60D Display. Soweit bin ich auch ganz begeistert von dem guten Stück.
Allerdings habe ich jetzt ein (oder besser zwei) Problem(e) mit meiner Interrupt Abfrage für die Touchscreen Koordinaten. Da ich den Dirk nicht weiter per E-Mail belästigen möchte, frage ich hier im Forum mal nach ;).

Den Code habe ich größtenteils aus dem Beispiel "MenuDemo" übernommen und ein wenig auf mein Projekt angepasst. Allerdings lasse ich einen Interrupt auslösen, wenn eine fallende Flanke vom TINT Signal erzeugt wird, also wenn ein Touchscreen Event besteht. Das ganze funktioniert soweit auch ganz gut, nur überspringt mein Mikroprozessor (ATmega32) scheinbar diese Passage:

Code:
if (touchy < (272-71)) return;

Im unteren Bereich des Displays befindet sich ein Menüs mit vier auswählbaren Icons. Das Menü soll auch nur gewechselt werden, wenn in diesem unteren Bereich etwas ausgewählt wird. Leider wechselt das Display aber das Menü auch, wenn ich ich im oberen Bereich (also über den Icons) etwas auswähle. Meine Funktion "Play_Break ();" ist ihm scheinbar auch vollkommen egal :).

Das zweite Problem besteht im Timing:
Code:
do
	{
		DisplayDecimal16 (45, 60, meter);
		DisplayDecimalSigned16 (5, 130, (100 - meter));

		for (i=0; i<100; i++)
		{
			if (scantouch == TOUCH)
			{
				Menu_Scan ();		//This routine manages menu_state variable
				Play_Break ();
				scantouch = NOTOUCH;
			}
			
			_delay_ms (10);
		}
		
	} while (!(menu_state & (1<<menu_state_changed)));
Ich muss grundsätzlich mit der for-Schleife eine gewisse Zeit überbrücken, weil ansonsten sämtliche TouchEvents ignoriert werden. Die Lösung mit der Pause gefällt mir leider gar nicht, gibt es vielleicht noch einen besseren Lösungsansatz? Ich vermute mal, dass der Displaycontroller nach dem "DisplayDecimalSigned16 (5, 130, (100 - meter));" noch etwas beschäftigt ist und somit nicht sofort auf ein TouchEvent reagieren kann.

So hier noch die vollständige "main.c" Datei:
Code:
#include <avr/io.h>		//Headerdatei für Ports
#include <avr/wdt.h>
#include <util/delay.h> 
#include <stdlib.h>		//Headerdatei für Standardroutinen
#include <avr/interrupt.h>	//Headerdatei für Interrupts
#include <avr/pgmspace.h>

#include "Display_SPI.h"
#include "Display_Graphics.h"
#include "Display_Numerical.h"
#include "Display_TouchPanel.h"
#include "Display_UserMemory.h"
#include "Display_Text.h"
#include "Display_System.h"

#define nop() __asm volatile ("nop")
#define menu_state_changed 0
#define PLAY 1
#define BREAK 0
#define TOUCH 1
#define NOTOUCH 0



//Funktionen
void Menu_Init (uint8_t index);
void Menu_Scan (void);
void Play_Break (void);

void Parameter_show (void);
void Parameter_settings (void);
void Container (void);
void Shutdown (void);




//variables used by menu
uint8_t menu_index;
uint8_t menu_state;

uint8_t pulse;
uint8_t counter_meter = PLAY;
uint16_t meter;

uint8_t scantouch;
uint16_t touchx, touchy;



//Interrupt bei fallender Flanke an PD2		//Hallsensor event
ISR (INT0_vect)
{
	if (counter_meter == BREAK) return;
	
	if (pulse < 1)	//Anzahl der Impulse für einen Meter		//12 magneten = 9meter/270impulse 30imp/meter
	{
		pulse++;
	}
	else
	{
		pulse = 0;
		meter++;
	}
}



//Interrupt bei fallender Flanke an PD3		//Touch event
ISR (INT1_vect)
{
	uint8_t data;
	
	if (!(TOUCHPANEL_EVENT)) return;
	
	data = TouchPanel_ReadEvent();
	if (!(data & TOUCH_EVENT_DOWN)) return;
	
	if (scantouch == TOUCH) return;
	
	if (!(TouchPanel_ReadDown(&touchx, &touchy))) return;
	
	scantouch = TOUCH;
}



int main (void)
{
	SPI_Init ();	// Display Interface

	_delay_ms (100);
	_delay_ms (100);
	_delay_ms (100);

	while (DISPLAY_BUSY) {nop(); }

	TouchPanel_SetConfig (TOUCH_EVENT_DOWN);	//Enable Event TOUCH_EVENT_DOWN
	TouchPanel_ReadEvent();

	//Standardeinstellung am Display vornehmen
	SetPenColor (0, 0, 0);
	SetBrushColor (255, 255, 255);
	SetUserFlashMemoryFont (60, 0);	//Standardschrift
	NumericalConfig (1<<1);		//Zahlen ohne führende Null
	SetDisplayMode (DISPLAYMODE_Landscape);
	FillScreen_BrushColor ();	// Clear screen
	SetBacklightIntensity (255);	// Max. backlight brightness

	menu_index = 255;
	Menu_Init (0);	// Initialize menu 0
	
	//Interrupt INT0 an PD2 und INT1 an PD3 auf fallende Flanke stellen
	MCUCR |= (1<<ISC11)|(1<<ISC01);
	GICR |= (1<<INT1)|(1<<INT0);
	sei ();				//Interrupt global aktivieren
  
	while(1)
	{
		if (0 == menu_index) Parameter_show();
		else
		if (1 == menu_index) Parameter_settings();
		else
		if (2 == menu_index) Container();
		else
		if (3 == menu_index) Shutdown();
	}

	return 0;
}



//Hauptmenü initialisieren
void Menu_Init (uint8_t index)
{
	if (index == menu_index) return;	//Menü bereits aktiv
	
	DisplayImagePackage_Image(0, 272-71, 0, index);	//Passendes Menübild laden

	menu_index = index;
	menu_state |= (1<<menu_state_changed);
}



//Hauptmenü Tastendruck abfragen
void Menu_Scan (void)
{
	uint8_t i;
	uint16_t menu;

	if (touchy < (272-71)) return;
	
	for (i=0; i<4; i++)
	{
		if ((touchx > menu) && (touchx < (menu+120)))
		{
			Menu_Init(i);
			return;
		}

		menu += 120;
	}
}



//Play und Pausen Funktion der Streckenmessung
void Play_Break (void)
{
	if ((touchx < 386) || (454 < touchx)) return;
	if ((touchy < 91) || (159 < touchy)) return;
	
	if (counter_meter == PLAY)
	{
		DisplayImagePackage_Image (386, 91, 3, 1);
		counter_meter = BREAK;
	}
	else
	{
		DisplayImagePackage_Image (386, 91, 3, 0);
		counter_meter = PLAY;
	}
}



//Hauptmenue: Parameter show
void Parameter_show (void)
{
	uint8_t i;
	
	DrawRect_BrushColorFill (0, 0, 480, 272-72);	// Clear Application Screen
	
	SetBrushColor (205, 205, 205);
	DrawRect_BrushColorFill (0, 0, 480, 50);
	SetUserFlashMemoryFont (61, 0);	//40px Arial proportional character align
	DisplayText (5, 5, "Produktname");
	SetBrushColor (255, 255, 255);
	
	DisplayText (240, 75, "Meter");
	DisplayText (240, 145, "Meter");
	SetUserFlashMemoryFont (62, 2);	//60px Arial center align
	
	if (counter_meter == PLAY)
	{
		DisplayImagePackage_Image (386, 91, 3, 0);
	}
	else
	{
		DisplayImagePackage_Image (386, 91, 3, 1);
	}
	
	menu_state &= ~(1<<menu_state_changed);  // confirm status flag

	//Hauptschleife in der Routine
	do
	{
		DisplayDecimal16 (45, 60, meter);
		DisplayDecimalSigned16 (5, 130, (100 - meter));

		for (i=0; i<100; i++)
		{
			if (scantouch == TOUCH)
			{
				Menu_Scan ();		//This routine manages menu_state variable
				Play_Break ();
				scantouch = NOTOUCH;
			}
			
			_delay_ms (10);
		}
		
	} while (!(menu_state & (1<<menu_state_changed)));
	
	SetUserFlashMemoryFont (60, 0);	//Standardschrift
}



//Hauptmenue: Parameter settings
void Parameter_settings (void)
{
	DrawRect_BrushColorFill (0, 0, 480, 272-72);  // Clear Application Screen
	
	SetBrushColor (205, 205, 205);
	DrawRect_BrushColorFill (0, 0, 480, 50);
	SetUserFlashMemoryFont (61, 0);	//40px Arial proportional character align
	DisplayText (5, 5, "Achtung!");
	SetBrushColor (255, 255, 255);
	
	SetUserFlashMemoryFont (60, 0);	//Standardschrift
	DisplayText (5, 55, "Moechten Sie die Auswahl wirklich bestaetigen?");
	DisplayImagePackage_Image (0, 129, 1, 0);
	
	menu_state &= ~(1<<menu_state_changed);  // confirm staus flag

	//Hauptschleife in der Routine
	do
	{
		if (scantouch == TOUCH)
		{
			Menu_Scan ();		//This routine manages menu_state variable
			scantouch = NOTOUCH;
		}
		
	} while (!(menu_state & (1<<menu_state_changed)));
	
	SetUserFlashMemoryFont (60, 0);	//Standardschrift
}



//Hauptmenue: Container
void Container (void)
{
	DrawRect_BrushColorFill (0, 0, 480, 272-72);  // Clear Application Screen

	DisplayImagePackage_Image (0, 0, 2, 1);

	menu_state &= ~(1<<menu_state_changed);  // confirm status flag

	//Hauptschleife in der Routine
	do
	{
		if (scantouch == TOUCH)
		{
			Menu_Scan ();		//This routine manages menu_state variable
			scantouch = NOTOUCH;
		}
		
	} while (!(menu_state & (1<<menu_state_changed)));
}



//Hauptmenue: Shutdown
void Shutdown (void)
{
	DrawRect_BrushColorFill (0, 0, 480, 272-72);  // Clear Application Screen
	
	DisplayImagePackage_Image (0, 0, 2, 0);
	
	menu_state &= ~(1<<menu_state_changed);  // confirm status flag

	//Hauptschleife in der Routine
	do
	{
		if (scantouch == TOUCH)
		{
			Menu_Scan ();		//This routine manages menu_state variable
			scantouch = NOTOUCH;
		}
		
	} while (!(menu_state & (1<<menu_state_changed)));
}

Gruß
Fabi
 
Hallo Fabi!

Ich kann zwar bekannterweise kein C, aber vielleicht hilft dir folgendes weiter.....

Wenn du einen Interrupt auslöst, wenn der Touch berührt wurde, dann solltest du für die Dauer der Abfrage (Event, Down/Up) den Interrupt deaktivieren.

Das INT-Signal vom TTFT bleibt solange erhalten, bis du es mit dem EVENT abfragst.
Erst nach dem Abfragen des Events wird das Signal zurück gesetzt!

Wenn mich nicht alles täuscht hat Dirk im Beispiel extra keinen Interrupt am AVR verwendet, sondern pollt einfach nur einen beliebigen Eingangspin.
Letztlich ist das auch unproblematischer, weil das INT-Signal am Display ja bis zur nächsten EVENT-Abfrage anliegt. :wink:


Grüße,
Cassio
 
Letztlich ist das auch unproblematischer, weil das INT-Signal am Display ja bis zur nächsten EVENT-Abfrage anliegt. :wink:

Hallo Cassio,

danke für deine schnelle Antwort.

Hab ehrlich gesagt nicht damit gerechnet, dass ein Low Level am TIFT bis zur Abfrage erhalten bleibt. Erklärt aber auch warum am Oszilloskop die Länge des Signals immer unterschiedlich war ;).

Werde das ganze mal eben ausprobieren und melde mich dann wieder...

Gruß
Fabi
 
Jetzt habe ich schon mal einen Teilerfolg :).

Hier der passende Code:
Code:
#include <avr/io.h>		//Headerdatei für Ports
#include <avr/wdt.h>
#include <util/delay.h> 
#include <stdlib.h>		//Headerdatei für Standardroutinen
#include <avr/interrupt.h>	//Headerdatei für Interrupts
#include <avr/pgmspace.h>

#include "Display_SPI.h"
#include "Display_Graphics.h"
#include "Display_Numerical.h"
#include "Display_TouchPanel.h"
#include "Display_UserMemory.h"
#include "Display_Text.h"
#include "Display_System.h"

#define nop() __asm volatile ("nop")
#define menu_state_changed 0
#define PLAY 1
#define BREAK 0
#define TOUCH 1
#define NOTOUCH 0



//Funktionen
uint8_t scantouch (void);
void Menu_Init (uint8_t index);
void Menu_Scan (void);
void Play_Break (void);

void Parameter_show (void);
void Parameter_settings (void);
void Container (void);
void Shutdown (void);




//variables used by menu
uint8_t menu_index;
uint8_t menu_state;

uint8_t pulse;
uint8_t counter_meter = PLAY;
uint16_t meter;

uint16_t touchx, touchy;



//Interrupt bei fallender Flanke an PD2		//Hallsensor event
ISR (INT0_vect)
{
	if (counter_meter == BREAK) return;
	
	if (pulse < 1)	//Anzahl der Impulse für einen Meter		//12 magneten = 9meter/270impulse 30imp/meter
	{
		pulse++;
	}
	else
	{
		pulse = 0;
		meter++;
	}
}



int main (void)
{
	SPI_Init ();	// Display Interface

	_delay_ms (100);
	_delay_ms (100);
	_delay_ms (100);

	while (DISPLAY_BUSY) {nop(); }

	TouchPanel_SetConfig (TOUCH_EVENT_DOWN);	//Enable Event TOUCH_EVENT_DOWN
	TouchPanel_ReadEvent();

	//Standardeinstellung am Display vornehmen
	SetPenColor (0, 0, 0);
	SetBrushColor (255, 255, 255);
	SetUserFlashMemoryFont (60, 0);	//Standardschrift
	NumericalConfig (1<<1);		//Zahlen ohne führende Null
	SetDisplayMode (DISPLAYMODE_Landscape);
	FillScreen_BrushColor ();	// Clear screen
	SetBacklightIntensity (255);	// Max. backlight brightness

	menu_index = 255;
	Menu_Init (0);	// Initialize menu 0
	
	//Interrupt INT0 an PD2 und INT1 an PD3 auf fallende Flanke stellen
	MCUCR |= (1<<ISC01);
	GICR |= (1<<INT0);
	sei ();				//Interrupt global aktivieren
  
	while(1)
	{
		if (0 == menu_index) Parameter_show();
		else
		if (1 == menu_index) Parameter_settings();
		else
		if (2 == menu_index) Container();
		else
		if (3 == menu_index) Shutdown();
	}

	return 0;
}



//Funktion zur Abfrage der Touchscreenkoordinaten
uint8_t scantouch (void)
{
	uint8_t data;
	
	if (!(TOUCHPANEL_EVENT)) return NOTOUCH;
	
	data = TouchPanel_ReadEvent();
	if (!(data & TOUCH_EVENT_DOWN)) return NOTOUCH;
	
	if (!(TouchPanel_ReadDown(&touchx, &touchy))) return NOTOUCH;
	
	return TOUCH;
}
	
	

//Hauptmenü initialisieren
void Menu_Init (uint8_t index)
{
	if (index == menu_index) return;	//Menü bereits aktiv
	
	DisplayImagePackage_Image(0, 272-71, 0, index);	//Passendes Menübild laden

	menu_index = index;
	menu_state |= (1<<menu_state_changed);
}



//Hauptmenü Tastendruck abfragen
void Menu_Scan (void)
{
	uint8_t i;
	uint16_t menu;

	if (touchy < (272-71)) return;
	
	for (i=0; i<4; i++)
	{
		if ((touchx > menu) && (touchx < (menu+120)))
		{
			Menu_Init(i);
			return;
		}

		menu += 120;
	}
}



//Play und Pausen Funktion der Streckenmessung
void Play_Break (void)
{
	if ((touchx < 386) || (454 < touchx)) return;
	if ((touchy < 91) || (159 < touchy)) return;
	
	if (counter_meter == PLAY)
	{
		DisplayImagePackage_Image (386, 91, 3, 1);
		counter_meter = BREAK;
	}
	else
	{
		DisplayImagePackage_Image (386, 91, 3, 0);
		counter_meter = PLAY;
	}
}



//Hauptmenue: Parameter show
void Parameter_show (void)
{
	uint8_t i;
	
	DrawRect_BrushColorFill (0, 0, 480, 272-72);	// Clear Application Screen
	
	SetBrushColor (205, 205, 205);
	DrawRect_BrushColorFill (0, 0, 480, 50);
	SetUserFlashMemoryFont (61, 0);	//40px Arial proportional character align
	DisplayText (5, 5, "Produktname");
	SetBrushColor (255, 255, 255);
	
	DisplayText (240, 75, "Meter");
	DisplayText (240, 145, "Meter");
	SetUserFlashMemoryFont (62, 2);	//60px Arial center align
	
	if (counter_meter == PLAY)
	{
		DisplayImagePackage_Image (386, 91, 3, 0);
	}
	else
	{
		DisplayImagePackage_Image (386, 91, 3, 1);
	}
	
	menu_state &= ~(1<<menu_state_changed);  // confirm status flag

	//Hauptschleife in der Routine
	do
	{
		DisplayDecimal16 (45, 60, meter);
		DisplayDecimalSigned16 (5, 130, (100 - meter));

		for (i=0; i<100; i++)
		{
			_delay_ms (10);
			
			if (scantouch () == TOUCH)
			{
				Menu_Scan ();		//This routine manages menu_state variable
				Play_Break ();
			}
		}
		
	} while (!(menu_state & (1<<menu_state_changed)));
	
	SetUserFlashMemoryFont (60, 0);	//Standardschrift
}



//Hauptmenue: Parameter settings
void Parameter_settings (void)
{
	DrawRect_BrushColorFill (0, 0, 480, 272-72);  // Clear Application Screen
	
	SetBrushColor (205, 205, 205);
	DrawRect_BrushColorFill (0, 0, 480, 50);
	SetUserFlashMemoryFont (61, 0);	//40px Arial proportional character align
	DisplayText (5, 5, "Achtung!");
	SetBrushColor (255, 255, 255);
	
	SetUserFlashMemoryFont (60, 0);	//Standardschrift
	DisplayText (5, 55, "Moechten Sie die Auswahl wirklich bestaetigen?");
	DisplayImagePackage_Image (0, 129, 1, 0);
	
	menu_state &= ~(1<<menu_state_changed);  // confirm staus flag

	//Hauptschleife in der Routine
	do
	{
		if (scantouch () == TOUCH)
		{
			Menu_Scan ();		//This routine manages menu_state variable
		}
		
	} while (!(menu_state & (1<<menu_state_changed)));
	
	SetUserFlashMemoryFont (60, 0);	//Standardschrift
}



//Hauptmenue: Container
void Container (void)
{
	DrawRect_BrushColorFill (0, 0, 480, 272-72);  // Clear Application Screen

	DisplayImagePackage_Image (0, 0, 2, 1);

	menu_state &= ~(1<<menu_state_changed);  // confirm status flag

	//Hauptschleife in der Routine
	do
	{
		if (scantouch () == TOUCH)
		{
			Menu_Scan ();		//This routine manages menu_state variable
		}
		
	} while (!(menu_state & (1<<menu_state_changed)));
}



//Hauptmenue: Shutdown
void Shutdown (void)
{
	DrawRect_BrushColorFill (0, 0, 480, 272-72);  // Clear Application Screen
	
	DisplayImagePackage_Image (0, 0, 2, 0);
	
	menu_state &= ~(1<<menu_state_changed);  // confirm status flag

	//Hauptschleife in der Routine
	do
	{
		if (scantouch () == TOUCH)
		{
			Menu_Scan ();		//This routine manages menu_state variable

		}
		
	} while (!(menu_state & (1<<menu_state_changed)));
}

Dafür ist ein anderes Problem auftaucht, welches ich schon einmal hatte:
Für y-Werte die größer als vermutlich 255 sind, reagiert das Display nicht mehr.

Die Pause konnte ich leider auch noch nicht entfernen :(...

Gruß
Fabi
 
Hallo Fabi!

Hm... nun ja... ich kann immer noch kein C, aber hast du die Variablen für X und Y auch als WORD dimensioniert?
Oder muss man das bei C vorher nicht machen? :hmmmm:

Tatsache ist jedenfalls, dass du beim 4,3 Zoll TTFT eine Auflösung von 480 x 272 hast!

Die 480 passen nun mal nicht in ein Byte..... das ja nach 255 überläuft.


Kannst ja noch mal ein wenig schauen, ob es daran liegen könnte.
Ich muss jetzt mal in die Waagerechte..... und beim C-Programm kann ich dir ja leider sowieso nicht helfen. :wink:


Gutes Gelingen,
Cassio
 
Die 480 passen nun mal nicht in ein Byte..... das ja nach 255 überläuft.

Ach so ganz vergessen zu erwähnen:
Ich nutze das Display im Landscape Mode, somit machen also die 272 Pixel Probleme. In horizontale Richtung (480 Pixel) funktioniert das ganze komischerweise.


Ich muss jetzt mal in die Waagerechte..... und beim C-Programm kann ich dir ja leider sowieso nicht helfen.
Du hast mir auch ohne C Kenntnisse gut geholfen! Werde jetzt auch mal das Bett hüten...

Gruß
Fabi
 
Hallo Fabi!

Was ich eben noch vergessen habe.....

Solltest du mit dem Interrupt weiterarbeiten wollen musst du ebenfalls sicherstellen, dass bei jedem SPIOUT der Interrupt deaktiviert ist!

Wenn du nämlich gerade Daten zum Display schickst und dabei den Touch berührst, wird die Datenübermittlung natürlich vom AVR abgebrochen!
Das kommt natürlich gar nicht gut. :cool:

Wie schon erwähnt.....
Unproblematischer ist die Abfrage des Touch durch Pollen eines Pins am AVR.


So, nun aber...... gute Nacht! :wink:
Cassio
 
Hallo zusammen, hallo Fabi!

A. Y-Koordinate lesen
Ich habe einige Ideen. Zunächst möchte ich auf das Problem mit der Y-Koordinate eingehen. In der Demo werden die Pointer der uint16_t Variablen touchx und touchy der Routinen
  • TouchPanel_ReadDown
  • TouchPanel_ReadCont
  • TouchPanel_ReadUp
übergeben. Ich habe mehrere Studio 4 Projekte, dort funktioniert es einwandfrei. Ich habe allerdings festgestellt, dass es bei Studio 5 nicht richtig funktioniert. Der zweite Parameter &touchy wird nicht richtig übergeben oder es passiert sonst was. Die Ursache habe ich noch nicht rausgefunden, vielleicht sieht ja jemand etwas an meinem Code.

Ich habe es daraufhin etwas anders gelöst. Einfaches workaround: Die beiden Parameter werden der Routine nicht mehr übergeben, sondern sind global bekannt.

Ändere hier einmal die drei Routinen folgendermaßen ab:
x und y durch deine Variablennamen touchx und touchy ersetzen.
In Display_TouchPanel.c
Code:
uint8_t TouchPanel_ReadCont(void)
{
  uint16_t data;

  if (!SendCommand(CMD_TouchPanel_ReadCont)) return 0;  // execution fails


  data = (uint16_t)SPI_RW(0xFF)<<8;  // MSB x
  data |= SPI_RW(0xFF);              // LSB x

  x = data;

  data = (uint16_t)SPI_RW(0xFF)<<8;  // MSB y
  data |= SPI_RW(0xFF);              // LSB y

  y = data;

  SPI_SS_HIGH                           // Deselect SPI
  WaitWhileDisplayBusy();               // Wait while Display signals BUSY

  return 1;  // successfull

}

uint8_t TouchPanel_ReadDown(void)
{
  uint16_t data;

  if (!SendCommand(CMD_TouchPanel_ReadDown)) return 0; // execution fails

  data = (uint16_t)SPI_RW(0xFF)<<8;  // MSB x
  data |= SPI_RW(0xFF);              // LSB x

  x = data;

  data = (uint16_t)SPI_RW(0xFF)<<8;  // MSB y
  data |= SPI_RW(0xFF);              // LSB y

  y = data;

  SPI_SS_HIGH                           // Deselect SPI
  WaitWhileDisplayBusy();               // Wait while Display signals BUSY

  return 1;
}

uint8_t TouchPanel_ReadUp(void)
{
  uint16_t data;

  if (!SendCommand(CMD_TouchPanel_ReadUp)) return 0; // execution fails

  data = (uint16_t)SPI_RW(0xFF)<<8;  // MSB x
  data |= SPI_RW(0xFF);              // LSB x

  x = data;

  data = (uint16_t)SPI_RW(0xFF)<<8;  // MSB y
  data |= SPI_RW(0xFF);              // LSB y

  y = data;

  SPI_SS_HIGH                           // Deselect SPI
  WaitWhileDisplayBusy();               // Wait while Display signals BUSY

  return 1;
}

Damit Display_TouchPanel.c die Variablen kennt, noch folgendes einfügen (am besten direkt nach #include ...):
Code:
extern uint16_t x, y;

In Display_TouchPanel.h nun noch die alten Prototypes durch die neuen ersetzen:
Code:
uint8_t TouchPanel_ReadCont(void);
uint8_t TouchPanel_ReadDown(void);
uint8_t TouchPanel_ReadUp(void);

Ich bin übrigens mit einem neuen Template-Code beschäftigt, der bezüglich des benötigten Speicherpatz, genügsamer ist, als der aktuelle Demo-Code. Wenn alles soweit funktioniert, werde ich den wahrscheinlich irgendwann in der nächsten Woche fertig haben.

B. Nun noch etwas zum Interrupt:

Ein Kommando setzt sich ja aus mehrern Bereichen zusammen:
  • BUSY abfragen
  • Kommando übertragen
  • n Parameter übertragen
Wenn man im Hauptprogramm nun Display-Kommandos ausführt, was passiert, wenn das Displaymodul ein Touchergeignis via TINT\ signalisiert und in der ISR des ensprechenden externen Interrupts ebenfalls Kommandos ausgeführt werden (ReadEvent, ReadCont ...)? Das Protokoll im Hauptprogramm wird unterbrochen, nicht zuende geführt. Hier müsste dafür gesorgt werden, dass bevor eine Displayroutine im Hauptprogramm ausgeführt wird, der Interrupt deaktiviert wird, damit im Ablauf nichts unterbrochen wird. Nach der Displayroutine wird der Interrupt wieder aktiviert.

Hier gibts ein "aber": Was gewinnt man durch einen Interrupt? Ist der notwendig?
In der Demo ist es so, dass der TINT\ Pin gepollt wird. Tritt ein vorher freigegebenes Touchereignis ein, wird dies über TINT\ signalisiert, und zwar solange (Signal ist low), bis man die Events liest. Das Display behält sich also die Ereignisse und die entsprechenden Koordinaten für Down, Cont und Up. Man muss sich die Daten also nicht super schnell "abholen".
Im Moment ist es so, dass die ISR ein Flag (uint8_t scantouch) setzt, um dem Hauptprogramm mitzuteilen, dass ein TINT\ aufgetreten ist. Das Hauptprogramm pollt dieses Flag, man gewinnt also keine Zeit, man kann auch direkt den TINT\ Pin pollen.
Ich bin der Meinung, dass man dann einen Interrupt verwenden sollte, wenn im Hauptprogramm über längere Zeit kein pollen möglich ist. Das kommt nun auf die Anwendung und allgemein auf die Programmstruktur an. Nach meiner Einschätzung reicht es, wenn man alle 20ms zum pollen kommt, man würde dann 50mal in der Sekunde ein Touchereignis erkennen, das könnte schon zum "malen" reichen, für Menüauswertung allemal. ;)

Das mit dem notwendigen delay ist mir noch nicht ganz klar. Ich würde erst mal die Sache unter dem Punkt A. ändern, vielleicht löst sich die Sache dann von alleine.

Allgemein nochmal was zu Interrupts:
Variablen, die in ISRs verwendet werden, sollten als volatile definiert werden. Bei Variablen mit einer Größe von mehr als 1 Byte (uint16_t zum Beispiel), muss man darauf achten, dass bei Auswertung oder Änderung in der Hauptroutine, nicht die ISR dazwischenfunkt und ein Teilbyte ändert! Hier gibt es mehrere Lösungsansätze, der einfachste ist wahrscheinlich vor dem Zugriff in der Hauptroutine Interrupts zu deaktivieren und danach wieder zu aktivieren.

Ich hoffe dies hilft etwas weiter.

Grüße,
Dirk
 
Hallo Dirk,

Zu A.:
Dein Lösungsvorschlag mit den extern deklarierten Variablen funktioniert einwandfrei. Die y-Koordinate wird jetzt immer richtig übergeben. Einen Fehler konnte ich leider nicht entdecken... Jedoch ist mir aufgefallen, dass die Koordinate für y scheinbar beim ersten mal korrekt übergeben wird. Erst danach funktioniert es nicht mehr und für Werte größer 255 reagiert das Display einfach nicht.

Hier die drei angepassten Dateien für die "Nachwelt" festgehalten ;):
Anhang anzeigen Main.c.txt
Anhang anzeigen Display_TouchPanel.c.txt
Anhang anzeigen Display_UserMemory.h.txt

Das Problem mit der y-Koordinate wurde nun gelöst, allerdings bleibt die Sache mit der Pause leider weiterhin bestehen. Es funktioniert so zwar ganz gut, aber schön ist das ja nicht gerade ;).

Zu B.:
Die Idee mit dem Interrupts zur Abfrage von TouchEvents habe ich verworfen... hier habt mich überzeugt, dass es Blödsinn ist.

Zum allgemeinen Umgang mit Interrupts:

Worin besteht den jetzt genau der unterschied von "volatile". Habe eigentlich alle globalen Variablen bis dato immer mit "volatile" deklariert. In deinem Quelltext habe ich dann allerdings gesehen, dass es scheinbar auch ohne gut funktioniert... Jetzt habe ich jedenfalls die Variablen, welche in der Interruptroutine behandelt werden, wieder mit einen "volatile" ausgestattet.

Vielen Dank für eure Hilfe!
Gruß
Fabi
 
Hallo Fabi!

zu A.
Mich würde es schon mal interessieren, was der Compiler hier genau macht und warum sich hier anscheinend was geändert hat, ich schaue mit das bei Gelegenheit einmal genauer an. Das mit dem delay überlege ich mir auch nochmal, für heute bin ich schon zu müde dafür.
(Du machst manchmal eine Ausgabe von Werten mit maximal möglicher Frequenz innerhalb einer Schleife, ohne dass sich die ausgegebenen Werte eventuell ändern. Das ist zum Beispiel so in der einen do-while-Schleife. Dieses würde ich eventuell verbessern, dann ist auch der SPI Bus nicht permanent aktiv)

zu deiner Frage mit dem volatile:
Hier zitiere ich einfach mal die avr-lib.c FAQ:
When using the optimizer, in a loop like the following one:
Code:
uint8_t flag;
...
ISR(SOME_vect) {
  flag = 1;
}
...

        while (flag == 0) {
                ...
        }
the compiler will typically access flag only once, and optimize further accesses completely away, since its code path analysis shows that nothing inside the loop could change the value of flag anyway. To tell the compiler that this variable could be changed outside the scope of its code path analysis (e. g. from within an interrupt routine), the variable needs to be declared like: volatile uint8_t flag

Du teilst dem Compiler durch volatile also mit, dass die Variable auch außerhalb der Schleife (von der ISR) geändert werden kann. Bei Variablen ab 2 Byte Größe musst du aber trotzdem dafür sorgen, dass die ISR nicht dazwischenfunken kann. Eine globale Variable musst du nicht grundsätzlich als volatile deklarieren, nur dann, wenn sie in einer ISR geändert werden kann und auch im Hauptprogramm verwendet wird. (In meinem Quelltext habe ich sie nicht mit volatile deklariert, da ich dort keine ISR habe, die sie ändert.)

Gruß,
Dirk
 
Mich würde es schon mal interessieren, was der Compiler hier genau macht und warum sich hier anscheinend was geändert hat, ich schaue mit das bei Gelegenheit einmal genauer an.
Ist schon irgendwie komisch... mal geht es und dann wieder nicht...
Ich verwende die avr-libc Version 1:1.7.1-2 und gcc-avr 1:4.5.3-2, vielleicht hilft dir das ja weiter.

(Du machst manchmal eine Ausgabe von Werten mit maximal möglicher Frequenz innerhalb einer Schleife, ohne dass sich die ausgegebenen Werte eventuell ändern.
Jetzt ist auch das Problem mit dem _delay auch gelöst :). Scheinbar war wirklich der Displaycontroller etwas zu sehr mit den ständig neuen Werten beschäftigt (obwohl es ja unter Umständen gar keine Wertänderung gab), sodass er nicht mehr auf ein TouchEvent reagieren konnte.


Du teilst dem Compiler durch volatile also mit, dass die Variable auch außerhalb der Schleife (von der ISR) geändert werden kann. Bei Variablen ab 2 Byte Größe musst du aber trotzdem dafür sorgen, dass die ISR nicht dazwischenfunken kann. Eine globale Variable musst du nicht grundsätzlich als volatile deklarieren, nur dann, wenn sie in einer ISR geändert werden kann und auch im Hauptprogramm verwendet wird. (In meinem Quelltext habe ich sie nicht mit volatile deklariert, da ich dort keine ISR habe, die sie ändert.)
Ah, verstanden. Danke!

Gruß
Fabi
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)