Ник:
Пароль:

Контакты

E-mail: info@starterkit.ru
тел.: +7 922 680-21-73
тел.: +7 922 680-21-74
Телеграм: t.me/starterkit_ru
Партнеры:
otladka.com.ua - г.Киев

Способы оплаты

User Info


Добро пожаловать,
Guest

Регистрация или входРегистрация или вход
Потеряли пароль?Потеряли пароль?

Ник:
Пароль:

ПользователейПользователей:1
Поисковых ботовПоисковых ботов:3
ГостейГостей:1

ОбновитьПодробнееВсегоВсего:5
Форум » starterkit.ru » Embedded Linux
AT91SAM9G45 + TSLIB
Pavel Ivanchenko
Добавлено 07.10.2010 16:37 Редактировалось 07.10.2010 16:40
0
Сообщение: 1
Pavel Ivanchenko
Admin
4.39

Пункты: 91406
Регистрация: 24.03.2009
Пол: Мужчина
Включаю драйвер TS в BSP, создал GPIO SPI, примерно как описано здесь, подключил к нему драйвер ADS7846, по первым признакам все нормально - драйвер успешно грузится, активность на SPI линиях "адекватная", прерывание по нажатию срабатывает.
НО!!!
По началу долго не мог понять, в чем дело - некоторые пины GPIO SPI "через раз" работали как надо, иногда просто на них небыло никакой активности, всю BSP перешерстил - не пересекаются они ни с чем.
Потом, вдруг, "волшебным образом" SPI линии заработали как надо, двигаюсь далее, собираю TSLIB (вернее она уже была собрана, по сути с ней адекватность на линиях проверял) и тут выясняется шайтан-момент - при запуске ts_print и ts_print_raw, все работает как положено (координаты правильно показывает), но при запуске ts_calibrate чтение координат не пашет ...
Выяснилось, что при запуске ts_calibrate, входная линия (со стороны ARM) PENIRQ становится выходом и на ней бегают какие то импульсы ...
Интуитивно полагаю, что при открытии фреймбуфера прошел какой то косяк и какой то неправильно смапившийся буфер сводит полтом с ума регистры ввода вывода, кстати, при этом на самом fb все отображается правильно.
Полез копаться в сорцах ...
Стал поочередно отковыривать функции на предмет глюка, выяснилось, что с самой инициализацией fb проблем нет, а вот вывод уже ломает картину ...
Может кто какой криминал заметит?
Код
/*
* fbutils.c
*
* Utility routines for framebuffer interaction
*
* Copyright 2002 Russell King and Doug Lowder
*
* This file is placed under the GPL. Please see the
* file COPYING for details.
*
*/

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/time.h>

#include <linux/vt.h>
#include <linux/kd.h>
#include <linux/fb.h>

#include "font.h"
#include "fbutils.h"

union multiptr {
unsigned char *p8;
unsigned short *p16;
unsigned long *p32;
};

static int con_fd, fb_fd, last_vt = -1;
static struct fb_fix_screeninfo fix;
static struct fb_var_screeninfo var;
static unsigned char *fbuffer;
static unsigned char **line_addr;
static int fb_fd=0;
static int bytes_per_pixel;
static unsigned colormap [256];
__u32 xres, yres;

static char *defaultfbdevice = "/dev/fb0";
static char *defaultconsoledevice = "/dev/tty";
static char *fbdevice = NULL;
static char *consoledevice = NULL;

int open_framebuffer(void)
{
struct vt_stat vts;
char vtname[128];
int fd, nr;
unsigned y, addr;

if ((fbdevice = getenv ("TSLIB_FBDEVICE")) == NULL)
fbdevice = defaultfbdevice;

if ((consoledevice = getenv ("TSLIB_CONSOLEDEVICE")) == NULL)
consoledevice = defaultconsoledevice;

if (strcmp (consoledevice, "none") != 0) {
sprintf (vtname,"%s%d", consoledevice, 1);
fd = open (vtname, O_WRONLY);
if (fd < 0) {
perror("open consoledevice");
return -1;
}

if (ioctl(fd, VT_OPENQRY, &nr) < 0) {
perror("ioctl VT_OPENQRY");
return -1;
}
close(fd);

sprintf(vtname, "%s%d", consoledevice, nr);

con_fd = open(vtname, O_RDWR | O_NDELAY);
if (con_fd < 0) {
perror("open tty");
return -1;
}

if (ioctl(con_fd, VT_GETSTATE, &vts) == 0)
last_vt = vts.v_active;

if (ioctl(con_fd, VT_ACTIVATE, nr) < 0) {
perror("VT_ACTIVATE");
close(con_fd);
return -1;
}

if (ioctl(con_fd, VT_WAITACTIVE, nr) < 0) {
perror("VT_WAITACTIVE");
close(con_fd);
return -1;
}

if (ioctl(con_fd, KDSETMODE, KD_GRAPHICS) < 0) {
perror("KDSETMODE");
close(con_fd);
return -1;
}

}

fb_fd = open(fbdevice, O_RDWR);
if (fb_fd == -1) {
perror("open fbdevice");
return -1;
}

if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &fix) < 0) {
perror("ioctl FBIOGET_FSCREENINFO");
close(fb_fd);
return -1;
}

if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &var) < 0) {
perror("ioctl FBIOGET_VSCREENINFO");
close(fb_fd);
return -1;
}
xres = var.xres;
yres = var.yres;

fbuffer = mmap(NULL, fix.smem_len, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fb_fd, 0);
if (fbuffer == (unsigned char *)-1) {
perror("mmap framebuffer");
close(fb_fd);
return -1;
}
memset(fbuffer,0,fix.smem_len);

bytes_per_pixel = (var.bits_per_pixel + 7) / 8;
line_addr = malloc (sizeof (__u32) * var.yres_virtual);
addr = 0;
for (y = 0; y < var.yres_virtual; y++, addr += fix.line_length)
line_addr [y] = fbuffer + addr;

return 0;
}

void close_framebuffer(void)
{
munmap(fbuffer, fix.smem_len);
close(fb_fd);


if(strcmp(consoledevice,"none")!=0) {

if (ioctl(con_fd, KDSETMODE, KD_TEXT) < 0)
perror("KDSETMODE");

if (last_vt >= 0)
if (ioctl(con_fd, VT_ACTIVATE, last_vt))
perror("VT_ACTIVATE");

close(con_fd);
}

free (line_addr);
}

void put_cross(int x, int y, unsigned colidx)
{
line (x - 10, y, x - 2, y, colidx);
line (x + 2, y, x + 10, y, colidx);
line (x, y - 10, x, y - 2, colidx);
line (x, y + 2, x, y + 10, colidx);

#if 1
line (x - 6, y - 9, x - 9, y - 9, colidx + 1);
line (x - 9, y - 8, x - 9, y - 6, colidx + 1);
line (x - 9, y + 6, x - 9, y + 9, colidx + 1);
line (x - 8, y + 9, x - 6, y + 9, colidx + 1);
line (x + 6, y + 9, x + 9, y + 9, colidx + 1);
line (x + 9, y + 8, x + 9, y + 6, colidx + 1);
line (x + 9, y - 6, x + 9, y - 9, colidx + 1);
line (x + 8, y - 9, x + 6, y - 9, colidx + 1);
#else
line (x - 7, y - 7, x - 4, y - 4, colidx + 1);
line (x - 7, y + 7, x - 4, y + 4, colidx + 1);
line (x + 4, y - 4, x + 7, y - 7, colidx + 1);
line (x + 4, y + 4, x + 7, y + 7, colidx + 1);
#endif
}

void put_char(int x, int y, int c, int colidx)
{
int i,j,bits;

for (i = 0; i < font_vga_8x8.height; i++) {
bits = font_vga_8x8.data [font_vga_8x8.height * c + i];
for (j = 0; j < font_vga_8x8.width; j++, bits <<= 1)
if (bits & 0x80)
pixel (x + j, y + i, colidx);
}
}

void put_string(int x, int y, char *s, unsigned colidx)
{
int i;
for (i = 0; *s; i++, x += font_vga_8x8.width, s++)
put_char (x, y, *s, colidx);
}

void put_string_center(int x, int y, char *s, unsigned colidx)
{
size_t sl = strlen (s);
put_string (x - (sl / 2) * font_vga_8x8.width,
y - font_vga_8x8.height / 2, s, colidx);
}

void setcolor(unsigned colidx, unsigned value)
{
unsigned res;
unsigned short red, green, blue;
struct fb_cmap cmap;

#ifdef DEBUG
if (colidx > 255) {
fprintf (stderr, "WARNING: color index = %u, must be <256\n",
colidx);
return;
}
#endif

switch (bytes_per_pixel) {
default:
case 1:
res = colidx;
red = (value >> 8) & 0xff00;
green = value & 0xff00;
blue = (value << 8) & 0xff00;
cmap.start = colidx;
cmap.len = 1;
cmap.red = &red;
cmap.green = &green;
cmap.blue = &blue;
cmap.transp = NULL;

if (ioctl (fb_fd, FBIOPUTCMAP, &cmap) < 0)
perror("ioctl FBIOPUTCMAP");
break;
case 2:
case 4:
red = (value >> 16) & 0xff;
green = (value >> 8) & 0xff;
blue = value & 0xff;
res = ((red >> (8 - var.red.length)) << var.red.offset) |
((green >> (8 - var.green.length)) << var.green.offset) |
((blue >> (8 - var.blue.length)) << var.blue.offset);
}
colormap [colidx] = res;
}

static inline void __setpixel (union multiptr loc, unsigned xormode, unsigned color)
{
switch(bytes_per_pixel) {
case 1:
default:
if (xormode)
*loc.p8 ^= color;
else
*loc.p8 = color;
break;
case 2:
if (xormode)
*loc.p16 ^= color;
else
*loc.p16 = color;
break;
case 4:
if (xormode)
*loc.p32 ^= color;
else
*loc.p32 = color;
break;
}
}

void pixel (int x, int y, unsigned colidx)
{
unsigned xormode;
union multiptr loc;

if ((x < 0) || ((__u32)x >= var.xres_virtual) ||
(y < 0) || ((__u32)y >= var.yres_virtual))
return;

xormode = colidx & XORMODE;
colidx &= ~XORMODE;

#ifdef DEBUG
if (colidx > 255) {
fprintf (stderr, "WARNING: color value = %u, must be <256\n",
colidx);
return;
}
#endif

loc.p8 = line_addr [y] + x * bytes_per_pixel;
__setpixel (loc, xormode, colormap [colidx]);
}

void line (int x1, int y1, int x2, int y2, unsigned colidx)
{
int tmp;
int dx = x2 - x1;
int dy = y2 - y1;

if (abs (dx) < abs (dy)) {
if (y1 > y2) {
tmp = x1; x1 = x2; x2 = tmp;
tmp = y1; y1 = y2; y2 = tmp;
dx = -dx; dy = -dy;
}
x1 <<= 16;
/* dy is apriori >0 */
dx = (dx << 16) / dy;
while (y1 <= y2) {
pixel (x1 >> 16, y1, colidx);
x1 += dx;
y1++;
}
} else {
if (x1 > x2) {
tmp = x1; x1 = x2; x2 = tmp;
tmp = y1; y1 = y2; y2 = tmp;
dx = -dx; dy = -dy;
}
y1 <<= 16;
dy = dx ? (dy << 16) / dx : 0;
while (x1 <= x2) {
pixel (x1, y1 >> 16, colidx);
y1 += dy;
x1++;
}
}
}

void rect (int x1, int y1, int x2, int y2, unsigned colidx)
{
line (x1, y1, x2, y1, colidx);
line (x2, y1, x2, y2, colidx);
line (x2, y2, x1, y2, colidx);
line (x1, y2, x1, y1, colidx);
}

void fillrect (int x1, int y1, int x2, int y2, unsigned colidx)
{
int tmp;
unsigned xormode;
union multiptr loc;

/* Clipping and sanity checking */
if (x1 > x2) { tmp = x1; x1 = x2; x2 = tmp; }
if (y1 > y2) { tmp = y1; y1 = y2; y2 = tmp; }
if (x1 < 0) x1 = 0; if ((__u32)x1 >= xres) x1 = xres - 1;
if (x2 < 0) x2 = 0; if ((__u32)x2 >= xres) x2 = xres - 1;
if (y1 < 0) y1 = 0; if ((__u32)y1 >= yres) y1 = yres - 1;
if (y2 < 0) y2 = 0; if ((__u32)y2 >= yres) y2 = yres - 1;

if ((x1 > x2) || (y1 > y2))
return;

xormode = colidx & XORMODE;
colidx &= ~XORMODE;

#ifdef DEBUG
if (colidx > 255) {
fprintf (stderr, "WARNING: color value = %u, must be <256\n",
colidx);
return;
}
#endif

colidx = colormap [colidx];

for (; y1 <= y2; y1++) {
loc.p8 = line_addr [y1] + x1 * bytes_per_pixel;
for (tmp = x1; tmp <= x2; tmp++) {
__setpixel (loc, xormode, colidx);
loc.p8 += bytes_per_pixel;
}
}
}
Спуститься к концу Подняться к началу
Персональная информация
Jury093
Добавлено 07.10.2010 21:01 Сообщение: 2
Jury093
4.5

Пункты: 54233
Регистрация: 25.05.2009
Пол: Мужчина
Из: Санкт-Петербург
Цитата
Может кто какой криминал заметит?

полистал выложенный исходник, в первом приближении все нормально. Из низкоуровневых обращений вижу __setpixel.
Я бы более внимательно проверил исходники фреймбуфера 9Г45, может там идет "левое" или неправильное переназначение пина, типа отрабатывали драйвер экрана на внешнем прерывание и забыли закоментировать..
например в драйвере экрана НУК950 присутствуют вот такие строки непонятной нужности:
Код
/* config gpio output */
modify_gpio(W90X900_VA_GPIO + 0x54, mach_info->gpio_dir,
mach_info->gpio_dir_mask);
modify_gpio(W90X900_VA_GPIO + 0x58, mach_info->gpio_data,
mach_info->gpio_data_mask);

Можно попробовать для начала убрать все из п/п main и оставить открыть/закрыть фреймбуфер - если глючки пропали, то искать строку их вызывающую..

На любой вопрос есть любой ответ.
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 08.10.2010 01:31 Сообщение: 3
sasamy
4.70

Пункты: 77078
Регистрация: 14.08.2009
Цитата

Стал поочередно отковыривать функции на предмет глюка, выяснилось, что с самой инициализацией fb проблем нет, а вот вывод уже ломает картину ...


Честно говоря слабо представляю как может драйвер fb влиять на работу устройства ввода :) Я бы для начала попробовал отключить fb в ядре и проверить что с event device что-то действительно валится - простым cat.
Спуститься к концу Подняться к началу
Персональная информация
Pavel Ivanchenko
Добавлено 08.10.2010 09:43 Сообщение: 4
Pavel Ivanchenko
Admin
4.39

Пункты: 91406
Регистрация: 24.03.2009
Пол: Мужчина
Сам драйвер FB вроде не причем, если запустить проигрывание AVI или в графической консоли весь экран забить, PENIRQ остается PENIRQ, а вот стоит запуститть ts_calibrate или ts_test, как начинаются чудеса ...
Причем, выбери я другой GPIO пин, наверное и не заметил бы даже, но это все причина серьезно призадуматься - как в системе с защищенной памятью такое может происходить ...
Сам контроллер тачскрина (и все что с ним связано) работает нормально, если запускать ts_print (ts_print_raw) координаты читаются правильно, PENIRQ ведет себя как положено, просто какой тогда смысл в этой TSLIB, если нельзя откалибровать.
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 08.10.2010 11:40 Редактировалось 08.10.2010 11:56 Сообщение: 5
sasamy
4.70

Пункты: 77078
Регистрация: 14.08.2009
Цитата
Причем, выбери я другой GPIO пин, наверное и не заметил бы даже, но это все причина серьезно призадуматься - как в системе с защищенной памятью такое может происходить ...


Запросто - вот тут мапятся физические адреса памяти в адресное пространство пользовательского процесса

Код

fbuffer = mmap(NULL, fix.smem_len, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fb_fd, 0);


если VSCREENINFO имеет некоректные значения или структура обрабатывается неправильно то можно смапить "случайно" и память io практически любых регистров и заслать туда мусор. Ошибка может быть и в ф-ции mmap - многие драйверы fb переопределяют ее на свою реализациюю

PS думаю что в твоей реализации пплаты используется другая область физической памяти нежели в оригинальной плате, fbcon работает через read/write и поэтому это не сказалось. в общем в первую очередь посмотри что в драйвере fb задан правильный адрес физической памяти
Спуститься к концу Подняться к началу
Персональная информация
Pavel Ivanchenko
Добавлено 08.10.2010 11:55 Редактировалось 08.10.2010 11:56 Сообщение: 6
Pavel Ivanchenko
Admin
4.39

Пункты: 91406
Регистрация: 24.03.2009
Пол: Мужчина
Как уже говорил, я пробовал коментарить содержимое всех функций вывода, оставив только open_framebuffer и close_framebuffer, при этом ts_calibrate уже не ломала PENIRQ (хотя и не показывала ничего).
Тоже первым делом на это подумал, распечаталд все используемые значения, все правильно передается.
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 08.10.2010 11:58 Сообщение: 7
sasamy
4.70

Пункты: 77078
Регистрация: 14.08.2009
Цитата
Как уже говорил, я пробовал коментарить содержимое всех функций вывода, оставив только open_framebuffer и close_framebuffer, при этом ts_calibrate уже не ломала PENIRQ (хотя и не показывала ничего).
Тоже первым делом на это подумал, распечаталд все используемые значения, все правильно передается.


Естественно в этом случае ничего не сломается - ты же ничего не пишешь при таком раскладе в эту область памяти а просто мапишь ее.
Спуститься к концу Подняться к началу
Персональная информация
Pavel Ivanchenko
Добавлено 10.10.2010 19:20 Сообщение: 8
Pavel Ivanchenko
Admin
4.39

Пункты: 91406
Регистрация: 24.03.2009
Пол: Мужчина
Собрал Qt, тот же эффект, что склоняет мысли в сотону бага драйвера FB (а может и силикона) ...
Как выяснилось, описываемого эффекта не наблюдается в 16 битном режиме цветности (обнаружил совершенно случайно, отчаявшись понять причины происходящего).
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 11.10.2010 01:04 Редактировалось 11.10.2010 01:05 Сообщение: 9
sasamy
4.70

Пункты: 77078
Регистрация: 14.08.2009
Цитата

Как выяснилось, описываемого эффекта не наблюдается в 16 битном режиме цветности (обнаружил совершенно случайно, отчаявшись понять причины происходящего).


Скорей всего при 16 битах при записи просто недотягивает до регистров gpio. Есть подозрение на баг в описании ресурсов lcdfb, попробуй так:
добавь в файле board-sam9m10g45ek.c в структуре ek_lcdc_data инициализацию smem_len :

static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
.lcdcon_is_backlight = true,
.default_bpp = 32,
.default_dmacon = ATMEL_LCDC_DMAEN,
.default_lcdcon2 = AT91SAM9G45_DEFAULT_LCDCON2,
.default_monspecs = &at91fb_default_monspecs,
.guard_time = 9,
.lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB,
>>>>> .smem_len = 0,
};
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 11.10.2010 02:08 Сообщение: 10
sasamy
4.70

Пункты: 77078
Регистрация: 14.08.2009
Еще попробуй переопределить ф-цию fb_mmap

static int atmel_lcdfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
unsigned int offset = vma->vm_pgoff << PAGE_SHIFT;

if (offset < info->fix.smem_len) {
return dma_mmap_writecombine(info->dev, vma, info->screen_base,
info->fix.smem_start,
info->fix.smem_len);
}

return -EINVAL;
}
.............
static struct fb_ops atmel_lcdfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = atmel_lcdfb_check_var,
.fb_set_par = atmel_lcdfb_set_par,
.fb_setcolreg = atmel_lcdfb_setcolreg,
.fb_pan_display = atmel_lcdfb_pan_display,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
>>>> .fb_mmap = atmel_lcdfb_mmap,
};
Спуститься к концу Подняться к началу
Персональная информация
Форум » starterkit.ru » Embedded Linux