Jump to content

STM32F4 Discovery to XPT2046 (ADS7843)


ivan47

Recommended Posts

So my LCD module has built in touchscreen with XPT2046 module (I've read it's compatible with ADS7843).

I've connected it to my Discovery board using SPI interface (using TM's library). And it works (at least I think it works).

There are few things that bothers me. I don't know how to interpret the data coming from XPT2046 (I wanna know the relation

between binary data coming from SPI port to actual point on 240x320 screen, I'm trying to write function to print coordinates

to "USART debug port"). I'm using Standard Peripheral Drivers. These are my functions:

void XPT2046_Init(){
TM_GPIO_Init(XPT2046_CS_PORT, XPT2046_CS_PIN, TM_GPIO_Mode_OUT, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_Medium);
GPIO_SetBits(XPT2046_CS_PORT, XPT2046_CS_PIN);
TM_SPI_Init(XPT2046_SPI, XPT2046_SPI_PINS);
}

//Test function
void XPT2046_GetCoordinates(){
uint8_t datay[2];
uint8_t datax[2];
GPIO_ResetBits(XPT2046_CS_PORT, XPT2046_CS_PIN);
TM_SPI_Send(XPT2046_SPI, 0x90); //you will get back data which you can ignore
//Wait for busy
TM_SPI_ReadMulti(XPT2046_SPI, datay, 0x00, 2); //receive 2 bytes, send 0x00 dummy bytes, 2 bytes
TM_SPI_Send(XPT2046_SPI, 0xD0); //you will get back data which you can ignore
//Wait for busy
TM_SPI_ReadMulti(XPT2046_SPI, datax, 0x00, 2); //receive 2 bytes, send 0x00 dummy bytes, 2 bytes
GPIO_SetBits(XPT2046_CS_PORT, XPT2046_CS_PIN);
/*Debugging purposes*/
TM_USART_Puts(USART1,(char*) datay);
TM_USART_Puts(USART1,"\n\r");
TM_USART_Puts(USART1,(char*) datax);
TM_USART_Puts(USART1,"\n\r");
}

DOUT(MISO) - PB14

DIN(MOSI) - PB15

CLK - PB13

CS - PB12

Also I would like to import these function to board.h file so I can use touchscreen with my uGFX project.

I opened ginput_lld_mouse_board_st_stm32f4_discovery.h file that is written using ChibiOS functions (I don't use it in my project, I use raw32),

and I don't understand some functions, for example:

static inline uint16_t read_value(GMouse* m, uint16_t port) {
static uint8_t txbuf[3] = {0};
static uint8_t rxbuf[3] = {0};
(void) m;

txbuf[0] = port;
spiExchange(&SPID2, 3, txbuf, rxbuf);

return ((uint16_t)rxbuf[1] << 5) | (rxbuf[2] >> 3);
}

I'd like to implement my own code (using Standard Peripheral Drivers) here.

Link to comment
Share on other sites

Hello ivan47,

Please note that we don't provide support for other libraries.

If you're not using ChibiOS/RT then it would be the easiest to copy the actual board template file (which you can find under /drivers/ginput/touch/ADS7843/) and fill in the corresponding routines using the SPI API from the stdperiph library that you're using. Sadly we don't provide examples for this as it is very hardware dependent.

What is uint16_t port argument in function?

It's the touch controllers register you want to read/write from (port is probably indeed not the best name here). Note that this interface is specific to the implementation of the uGFX ADS7843 driver. To implement the board file for your project you just have to make sure that you write this value to the bus before you read. Everything else is taken care of for you.

~ Tectu

Link to comment
Share on other sites

To implement your read routine in the board file, copy the chibios example but replace the chibios call with the equivalent function from your spi library. It should be almost a one for one api call replacement. The spiexchange chibios call just writes some bytes on the spi port and then reads some bytes - in this case it writes one byte and then reads 2 bytes.

You won't need to worry about the details of how to extract the reading from those values returned by the read call - the driver handles all that, and lots of signal conditioning for you. If you are interested in the details have a look at the driver source code and then also the ginput mouse layer which handles all the heavy lifting associated with processing mouse coordinates.

Link to comment
Share on other sites

To implement your read routine in the board file, copy the chibios example but replace the chibios call with the equivalent function from your spi library. It should be almost a one for one api call replacement. The spiexchange chibios call just writes some bytes on the spi port and then reads some bytes - in this case it writes one byte and then reads 2 bytes.

In your case this would be TM_SPI_Send() and TM_SPI_ReadMulti().

Note that you also need to initialize the SPI peripheral yourself in the init() routine of the board file (just copy the content from the XPT2046_Init() function from your first post).

The acquire_bus() and release_bus() routines can be used to handle the CS (Chip Select) signal of your touch controller.

~ Tectu

Link to comment
Share on other sites

Hello. So I finally got some free time and I implemented functions to gmouse_lld_ADS7843.h file.

Now I want to make programe that will create some buttons on my 320x240 screen (again, I'm using Keil 5,

Standard Peripheral libraries (RAW32 application) ). By pressing buttons something should happen (toggle LEDs...).

But I got this errors:

Build target 'STM32F4-Discovery USB'
assembling startup_stm32f40_41xxx.s...
compiling main.c...
..\XPT2046\XPT2046.h(14): warning: #1295-D: Deprecated declaration XPT2046_Init - give arg types
extern void XPT2046_Init();
..\XPT2046\XPT2046.h(15): warning: #1-D: last line of file ends without a newline
extern void XPT2046_GetCoordinates(uint8_t* tx, uint8_t* rx);
.\User\gfxconf.h(85): warning: #47-D: incompatible redefinition of macro "GDISP_INCLUDE_FONT_UI2" (declared at line 61)
#define GDISP_INCLUDE_FONT_UI2 TRUE
User\main.c(61): warning: #68-D: integer conversion resulted in a change of sign
wi.g.show = TRUE;
User\main.c(71): error: #20: identifier "NULL" is undefined
ghButton1 = gwinButtonCreate(NULL, &wi);
User\main.c(53): warning: #177-D: variable "gl" was declared but never referenced
static GListener gl;
User\main.c(54): warning: #550-D: variable "ghButton1" was set but never used
static GHandle ghButton1;
User\main.c(56): warning: #177-D: function "createWidgets" was declared but never referenced
static void createWidgets(void) {
User\main.c: 7 warnings, 1 error
compiling gdisp.c...
.\User\gfxconf.h(85): warning: #47-D: incompatible redefinition of macro "GDISP_INCLUDE_FONT_UI2" (declared at line 61)
#define GDISP_INCLUDE_FONT_UI2 TRUE
..\00-uGFX\src/gdriver/gdriver.h(90): warning: #83-D: type qualifier specified more than once
typedef const struct GDriverVMT const GDriverVMTList[1];
C:\Users\Ivan47\Desktop\ILI9341\00-uGFX\src\gdisp\gdisp.c(586): warning: #83-D: type qualifier specified more than once
extern const GDISPVMT const GDISPVMT_OnlyOne[1];
C:\Users\Ivan47\Desktop\ILI9341\00-uGFX\src\gdisp\gdisp.c(607): warning: #68-D: integer conversion resulted in a change of sign
initDone = TRUE;
C:\Users\Ivan47\Desktop\ILI9341\00-uGFX\src\gdisp\gdisp.c(1729): error: #20: identifier "M_PI" is undefined
sedge = round(radius * ((sbit & 0x99) ? sin(start*M_PI/180) : cos(start*M_PI/180)));
C:\Users\Ivan47\Desktop\ILI9341\00-uGFX\src\gdisp\gdisp.c(1856): error: #20: identifier "M_PI" is undefined
sxb = FP2FIXED(radius*cos(start*M_PI/180)); sy = -round(radius*sin(start*M_PI/180));
C:\Users\Ivan47\Desktop\ILI9341\00-uGFX\src\gdisp\gdisp.c(2675): warning: #767-D: conversion from pointer to smaller integer
switch ((orientation_t) value) {
C:\Users\Ivan47\Desktop\ILI9341\00-uGFX\src\gdisp\gdisp.c(3260): warning: #188-D: enumerated type mixed with another type
mf_render_aligned(font, x, y, justify, str, 0, drawcharglyph, g);
C:\Users\Ivan47\Desktop\ILI9341\00-uGFX\src\gdisp\gdisp.c(3298): warning: #188-D: enumerated type mixed with another type
mf_render_aligned(font, x, y, justify, str, 0, fillcharglyph, g);
C:\Users\Ivan47\Desktop\ILI9341\00-uGFX\src\gdisp\gdisp.c: 7 warnings, 2 errors
".\Targets\STM32F4_Discovery\project.axf" - 3 Error(s), 14 Warning(s).
Target not created.
Build Time Elapsed: 00:00:11

So, there is undefined identifier NULL (probably my mistake), and two errors concerning M_PI.

There are also some questions about gmouse_lld_ADS7843_board.h file:

What does getpin_pressed(GMouse* m) do, and do I necessarily need to implement it ?

What does aquire_bus(GMouse* m) and release_bus(GMouse* m) do (also, do I need to implement them)?

I can send link to whole project.

Link to comment
Share on other sites

It looks like you're not including the c standard libraries hence you are missing NULL. About M_PI: This is sadly not properly defined in the C standard and every compiler / library does it differently. These days you usually just have to #include (which is already done for you) and tell the linker to use the math library (you need to pass the -lm flag to the linker). I don't know how you would do this in Keil, sorry. I'm sure Google will help.

If you want to bypass the problem for now just make sure that GDISP_NEED_ARC is disabled in your configuration file.

What does getpin_pressed(GMouse* m) do, and do I necessarily need to implement it?

getpin_pressed() is a function that the GINPUT driver polls to see whether the touchscreen is pressed or not. This function need to return TRUE when the touchscreen is pressed and FALSE otherwise. Note that in case of the ADS7843 controller this is actually a dedicated pin (PENIRQ when I remember correctly). You can simply hook it up to a GPIO and return it's state.

What does aquire_bus(GMouse* m) and release_bus(GMouse* m) do (also, do I need to implement them)?

These two functions are called by the GINPUT driver at the beginning and at the end of a communication with the touch controller. These functions are very helpful when you happen to have more than one device talking on that bus etc. In your case, you can simply pull the CS line low in aquire_bus() and high in release_bus().

I hope that helps.

~ Tectu

Link to comment
Share on other sites

Okay. I "manualy" defined M_PI and I included stdio.h in my main.c file. That took care of those problems, I also included some other modules

in my project (there were some linker errors ). Then I modified my main file and it looks like this:

systemticks_t gfxSystemTicks(void);
systemticks_t gfxMillisecondsToTicks(delaytime_t ms);

systemticks_t gfxSystemTicks(void)
{
return SysTick->VAL;
}

systemticks_t gfxMillisecondsToTicks(delaytime_t ms)
{
return ms;
}

coord_t i, j;
coord_t width, height;

//////////////
static GListener gl;
static GHandle ghButton1;

static void createWidgets(void) {
GWidgetInit wi;

// Apply some default values for GWIN
gwinWidgetClearInit(&wi);
wi.g.show = TRUE;

// Apply the button parameters
wi.g.width = 100;
wi.g.height = 30;
wi.g.y = 10;
wi.g.x = 10;
wi.text = "Push Button";

// Create the actual button
ghButton1 = gwinButtonCreate(NULL, &wi);
}
//////////////


int main(void) {

GEvent* pe;
font_t font = gdispOpenFont("DejaVuSans12");
font_t font1 = gdispOpenFont("fixed_10x20");
font_t font2 = gdispOpenFont("fixed_7x14");
font_t font3 = gdispOpenFont("fixed_5x8 ");


/* Initialize system */
//SystemInit();

/*Initialize USART for debugging*/
TM_USART_Init(USART1, TM_USART_PinsPack_2, 9600);

/* Put string to USART */
TM_USART_Puts(USART1, "Hello world\n\r"); //Debug
// Initialize delay
TM_DELAY_Init();

//gfxSleepMilliseconds(1000);
gfxInit();

TM_USART_Puts(USART1, "Hello world\n\r"); //Debug

// Set the widget defaults
gwinSetDefaultFont(gdispOpenFont("UI2"));
gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE);
gdispClear(White);

// Attach the mouse input
gwinAttachMouse(0);

// create the widget
createWidgets();

// We want to listen for widget events
geventListenerInit(&gl);
gwinAttachListener(&gl);
gdispDrawString(100,100,"Hello", font, Green);
while(1) {
// Get an Event
pe = geventEventWait(&gl, TIME_INFINITE);

switch(pe->type) {
case GEVENT_GWIN_BUTTON:
if (((GEventGWinButton*)pe)->gwin == ghButton1) {
// Our button has been pressed
gdispDrawString(60,60,"Hello", font, Green);
}
break;

default:
break;
}
}
}

Now the application enters the "calibration mode" (Blue screen with crosshair), but nothing happens. I trace the program and realized it enters Hard Fault routine while running gfxInit when it gets to around 506th line in ginput_mouse.c .

	// Wait for the mouse to be pressed
while(!(m->r.buttons & GINPUT_MOUSE_BTN_LEFT))
gfxSleepMilliseconds(CALIBRATION_POLL_PERIOD);

Anyone have an idea what am I doing wrong. I left link to whole project in Keil.

http://www.mediafire.com/download/6ewrh ... ILI9341.7z

Help!

Link to comment
Share on other sites

Hi Ivan47,

There is an easy to use, Keil ready sample for the same setup you have online (http://jopl.dlnet.us/graphlcdarm.php) :)

I made a quick connection with the LCD board I have (TFT_320QVT, same controller chips) and it works fine.

I had to make some changes in the XPT2046/ADS7846 conversion routine, but that was quite easy.

Made a video:

https://drive.google.com/file/d/0B3B79f ... sp=sharing

I hope it helps!

Link to comment
Share on other sites

Me again. I tried the other day to get button example (from the wiki site) working but no luck. This is my main.c:

/* Include core modules */
#include "stm32f4xx.h"
/* Include my libraries here */
#include "defines.h"
#include "tm_stm32f4_delay.h" //Credits go to Tilen Majerle
#include "tm_stm32f4_disco.h" //Credits go to Tilen Majerle
#include "tm_stm32f4_spi.h" //Credits go to Tilen Majerle
#include "tm_stm32f4_ili9341.h" //Credits go to Tilen Majerle
#include "tm_stm32f4_fonts.h" //Credits go to Tilen Majerle
#include "tm_stm32f4_usart.h" //Credits go to Tilen Majerle
#include "XPT2046.h"
#include "gfx.h"

#include

//#ifdef HSE_VALUE
// #undef HSE_VALUE
// #define HSE_VALUE ((uint32_t) 8000000)
//#endif

/* Private function prototypes -----------------------------------------------*/
systemticks_t gfxSystemTicks(void);
systemticks_t gfxMillisecondsToTicks(delaytime_t ms);

systemticks_t gfxSystemTicks(void)
{
return SysTick->VAL;
}

systemticks_t gfxMillisecondsToTicks(delaytime_t ms)
{
return ms;
}

coord_t i, j;
coord_t width, height;

//////////////
static GListener gl;
static GHandle ghButton1;

static void createWidgets(void) {
GWidgetInit wi;

// Apply some default values for GWIN
gwinWidgetClearInit(&wi);
wi.g.show = TRUE;

// Apply the button parameters
wi.g.width = 100;
wi.g.height = 30;
wi.g.y = 10;
wi.g.x = 10;
wi.text = "Push Button";

// Create the actual button
ghButton1 = gwinButtonCreate(NULL, &wi);
}
//////////////


int main(void) {

GEvent* pe;
font_t font = gdispOpenFont("DejaVuSans12");
font_t font1 = gdispOpenFont("fixed_10x20");
font_t font2 = gdispOpenFont("fixed_7x14");
font_t font3 = gdispOpenFont("fixed_5x8 ");


/* Initialize system */
//SystemInit();

/*Initialize USART for debugging*/
TM_USART_Init(USART1, TM_USART_PinsPack_2, 9600);

/* Put string to USART */
TM_USART_Puts(USART1, "Hello world\n\r"); //Debug
// Initialize delay
TM_DELAY_Init();

//gfxSleepMilliseconds(1000);
gfxInit();

TM_USART_Puts(USART1, "Hello world\n\r"); //Debug



// Set the widget defaults
gwinSetDefaultFont(gdispOpenFont("UI2"));
gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE);
gdispClear(White);

// Attach the mouse input
gwinAttachMouse(0);

// create the widget
createWidgets();

// We want to listen for widget events
geventListenerInit(&gl);
gwinAttachListener(&gl);
gdispDrawString(100,100,"Hello1", font, Green);
while(1) {
// Get an Event
pe = geventEventWait(&gl, TIME_INFINITE);

switch(pe->type) {
case GEVENT_GWIN_BUTTON:
if (((GEventGWinButton*)pe)->gwin == ghButton1) {
// Our button has been pressed
gdispDrawString(60,60,"Hello", font, Green);
}
break;

default:
break;
}
}
}

This is my gfxconf.h :

#ifndef _GFXCONF_H
#define _GFXCONF_H

/* The operating system to use. One of these must be defined - preferably in your Makefile */
//#define GFX_USE_OS_CHIBIOS TRUE
//#define GFX_USE_OS_WIN32 FALSE
//#define GFX_USE_OS_LINUX FALSE
//#define GFX_USE_OS_OSX FALSE
#define GFX_USE_OS_RAW32 TRUE

/* GFX sub-systems to turn on */
#define GFX_USE_GDISP TRUE
#define GFX_USE_GWIN TRUE //
#define GFX_USE_GINPUT TRUE //
#define GFX_USE_GEVENT TRUE

#define GFX_USE_GTIMER TRUE
#define GFX_USE_GQUEUE FALSE

/* Features for the GDISP sub-system. */
#define GDISP_NEED_VALIDATION TRUE
#define GDISP_NEED_CLIP TRUE
#define GDISP_NEED_CIRCLE TRUE
#define GDISP_NEED_ELLIPSE TRUE
#define GDISP_NEED_ARC TRUE
#define GDISP_NEED_CONVEX_POLYGON TRUE
#define GDISP_NEED_TEXT TRUE
//u slucaju koristenja nekog fonta treba ga promijeniti u TRUE
#define GDISP_NEED_ANTIALIAS FALSE
#define GDISP_NEED_UTF8 FALSE
#define GDISP_NEED_TEXT_KERNING FALSE
#define GDISP_INCLUDE_FONT_UI1 FALSE
#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE
#define GDISP_INCLUDE_FONT_DEJAVUSANS10 FALSE
#define GDISP_INCLUDE_FONT_DEJAVUSANS12 TRUE
#define GDISP_INCLUDE_FONT_DEJAVUSANS16 FALSE
#define GDISP_INCLUDE_FONT_DEJAVUSANS20 TRUE
#define GDISP_INCLUDE_FONT_DEJAVUSANS24 FALSE
#define GDISP_INCLUDE_FONT_DEJAVUSANS32 FALSE
#define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12 FALSE
#define GDISP_INCLUDE_FONT_FIXED_10X20 TRUE
#define GDISP_INCLUDE_FONT_FIXED_7X14 TRUE
#define GDISP_INCLUDE_FONT_FIXED_5X8 TRUE
#define GDISP_INCLUDE_FONT_DEJAVUSANS12_AA FALSE
#define GDISP_INCLUDE_FONT_DEJAVUSANS16_AA FALSE
#define GDISP_INCLUDE_FONT_DEJAVUSANS20_AA FALSE
#define GDISP_INCLUDE_FONT_DEJAVUSANS24_AA FALSE
#define GDISP_INCLUDE_FONT_DEJAVUSANS32_AA FALSE
#define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12_AA FALSE
#define GDISP_INCLUDE_USER_FONTS FALSE
#define GDISP_NEED_CONTROL TRUE //
#define GDISP_NEED_MULTITHREAD TRUE//
#define GDISP_USE_DMA FALSE

/* GDISP fonts to include */
#define GDISP_INCLUDE_FONT_UI2 TRUE

#define GQUEUE_NEED_ASYNC FALSE

/* Features for the GWIN subsystem. */
#define GWIN_NEED_WINDOWMANAGER FALSE
#define GWIN_NEED_WIDGET TRUE //
#define GWIN_NEED_BUTTON TRUE //
#define GWIN_BUTTON_LAZY_RELEASE TRUE //
#define GWIN_NEED_FRAME FALSE

/* Features for the GINPUT subsystem. */
#define GINPUT_NEED_MOUSE TRUE
#define GINPUT_TOUCH_STARTRAW FALSE
#define GINPUT_TOUCH_NOTOUCH FALSE
#define GINPUT_TOUCH_NOCALIBRATE FALSE
#define GINPUT_TOUCH_NOCALIBRATE_GUI TRUE
#define GINPUT_MOUSE_POLL_PERIOD 100 //
#define GINPUT_MOUSE_CLICK_TIME 300
#define GINPUT_TOUCH_CXTCLICK_TIME 700
#define GINPUT_TOUCH_USER_CALIBRATION_LOAD FALSE
#define GINPUT_TOUCH_USER_CALIBRATION_SAVE FALSE
#define GINPUT_NEED_TOGGLE FALSE
#endif /* _GFXCONF_H */

Link to comment
Share on other sites

Sometimes ugfx needs to measure the time difference between two events. These functions are wrappers around the HAL of your board, so something like this should do the trick:

systemticks_t gfxSystemTicks(void)
{
return HAL_GetTick();
}

systemticks_t gfxMillisecondsToTicks(delaytime_t ms)
{
return ms; // because 1 HAL tick is 1 ms as per the HAL reference manual
}

Edit: Oh I see you already have those. Well the purpose is simply to give ugfx a time base.

Link to comment
Share on other sites

Me again. I tried the other day to get button example (from the wiki site) working but no luck.

Can you please give a detailed description of what is not working? We need all the information that we can have in order to help you. What do you see on your screen? Is the backlight on? Did you see the startup logo? Are you using a dev-board or is it breadboard with long wires? etc...

If you see artifacts or garbage on the screen a photo is always helpful as well.

~ Tectu

Link to comment
Share on other sites

Hey. So, just like before, I get the uGfx logo for short period and then it enters the "calibration mode" (Blue screen with crosshair), but nothing happens. I trace the program and realized it enters Hard Fault routine while running gfxInit when it gets to around 506th line in ginput_mouse.c .

If I define GINPUT_TOUCH_STARTRAW in gfxconf.h true, program draws the button and XPT2046 sends some data (i know that because I put function to print the data to USART every time program enters XPT2046_GetCoordinates() ), but nothing happens.

Link to comment
Share on other sites

Okay. I'm using Keil uVision 5 as my IDE. I'm using STM32F4 Discovery board and I use ILI9341 320x240 display and 4-wire resistive touchscreen which is controlled by the XPT2046. The communication between ILI9341 and XPT2046 is done using SPI interface on my STM32 board.

I'm not sure if this is it, but this is link to screenshoot of Call Stack prior to HardFault:

http://www.mediafire.com/view/ccku1gc4a ... lStack.jpg

Sorry, but I'm not sure if Keil can generate some text file with Call Stack.

Link to comment
Share on other sites

So I trace program to the point before HardFault function. It enters the gfxYield() and executes function to the _longjmp(current->cxt, 1); and jumps to the HardFault.

I'm not sure why because the programs enters and executes gfxYield() few times before that.

http://www.mediafire.com/view/r5t8r635t ... Stack2.jpg

But there are no variables in scope (at least my debugger says it).

Link to comment
Share on other sites

The multi threading is jumping off the rails for some reason. To debug this take note of the cxt field generated by each call to create thread (the set jump call). When the fault happens you will then be able to work out where it was trying to get to by looking at the cxt value in the long jump call.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...