Pasa 0 21 ноября, 2009 Опубликовано 21 ноября, 2009 · Жалоба Процессор AT91SAM9260 Из документации ядра 2.6.28 взял пример работы с SPI - spidev_test.c В конфигурации ядра сделал все как описывали на форуме. Все подключилось. В /dev появилось устройство spidev. Пример заработал - обращения к драйверу проходят. Передача вроде должна идти.А вот данных осцилографом не вижу. Распечатал на консоль значения портов и регистров SPI - режимы вроде установлены верно. А передачи нет. При этом датафлэш висящая на SPI работает отлично, и когда идет обращение к ней, то осцилографом все прекрасно видно. Подскажите в чем тут загвоздка? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vmp 0 21 ноября, 2009 Опубликовано 21 ноября, 2009 · Жалоба Нет только данных или тактов тоже? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Pasa 0 21 ноября, 2009 Опубликовано 21 ноября, 2009 (изменено) · Жалоба Нет только данных или тактов тоже? ни тактов ни данных. А вот при установке режима чипселект реагирует: 1 вариант: mode =0; 2 вариант: mode |= SPI_CS_HIGH; С разработчиком схемы сидели вдвоем и смотрели установленные биты в регистрах портов и SPI.....все вроде нормально ------------------------------------------------------------------------------- { mode =0; bits = 8; speed = 400000; delay=10; fd = open(device, O_RDWR); if (fd < 0) pabort("can't open device"); /* * spi mode */ ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); if (ret == -1) pabort("can't set spi mode"); ret = ioctl(fd, SPI_IOC_RD_MODE, &mode); if (ret == -1) pabort("can't get spi mode"); /* * bits per word */ ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); if (ret == -1) pabort("can't set bits per word"); ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits); if (ret == -1) pabort("can't get bits per word"); /* * max speed hz */ ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); if (ret == -1) pabort("can't set max speed hz"); ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); if (ret == -1) pabort("can't get max speed hz"); printf("spi mode: %d\n", mode); printf("bits per word: %d\n", bits); printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); transfer(fd); } нигде по ошибке не выходит, я так понимаю что с драйвером общение нормально идет ---------------------------------------------------------------------- и transfer отрабатывает нормально....ошибку не пишет static void transfer(int fd) { int ret; uint8_t tx[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x95, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD, 0xF0, 0x0D, }; uint8_t rx[ARRAY_SIZE(tx)] = {0, }; struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)tx, .rx_buf = (unsigned long)rx, .len = ARRAY_SIZE(tx), .delay_usecs = delay, .speed_hz = speed, .bits_per_word = bits, }; for (ret = 0; ret < ARRAY_SIZE(tx); ret++) rx[ret] = 1; ret = ioctl(fd, SPI_IOC_MESSAGE(10), &tr); if (ret == 1) pabort("can't send spi message"); for (ret = 0; ret < ARRAY_SIZE(tx); ret++) { if (!(ret % 6)) puts(""); printf("%.2X ", rx[ret]); } puts(""); } Как был приемный буфер заполнен моими 1 , так и остается с 1....ну понятно....реального обмена то нет....А флэшка работает и посмеивается надо мной....Я в тупике.... Изменено 22 ноября, 2009 пользователем Pasa Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vmp 0 22 ноября, 2009 Опубликовано 22 ноября, 2009 · Жалоба Тут уже ничего не подскажу - проблема явно не с железом, а с софтом, так что надо пытать специалистов по линуксу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Pasa 0 23 ноября, 2009 Опубликовано 23 ноября, 2009 · Жалоба Может кто подскажет точку входа и в каком файле искать ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); попробую лог на консоль....черз printk.....вдруг поможет Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Pasa 0 25 ноября, 2009 Опубликовано 25 ноября, 2009 · Жалоба Эксперименты привели к следующему: вызовы write и read прекрасно работают. А если через ioctl вызывать spidev_ioctl(для полнодуплексного обмена), то из драйвера SPI (atmel_spi.c) идет возврат с ошибкой опций устновленного протокола. И естественно передачи никакой нет. По исходнику посмотрел - там где анализ на нулевую скорость передачи и ноль бит в слове. В уровень spidev.c структура с параметрами доходит нормально(параметры ставятся в верхнем юзерском слое в самой проге). А потом где-то теряются/затираются/обнуляются и до дравера SPI не доходят. Вот счас пробую проследить всю цепочку... Мда....вот уж не ожидал таких плясок с бубном....не покидает ощущение, что ну не может быть таких ошибок в ядре и я не совсем правильно пользуюсь вызовами ioctl(). Но ведь все взято из примера в документации которая идет с самим ядром. Хотя с другой стороны в этом самом примере сходу нашел одну описку/опечатку/ошибку. Может кто сталкивался с таким и подскажет что-нибудь дельное? Уж больно не хочется лезть в потроха ядра, править его и с ужасом думать о следущих "танцах", когда придется браться за сокеты и шину I2C Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lamination 0 26 ноября, 2009 Опубликовано 26 ноября, 2009 · Жалоба #include <stdio.h> #include <fcntl.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <linux/types.h> #include <linux/spi/spidev.h> int main(){ int fd; int status; unsigned char u8_ret; unsigned int u32_ret; struct spi_ioc_transfer xfer[2]; unsigned char buf[10]; fd = open("/dev/spi1.1",O_RDWR); if (fd == -1){ printf("error on open device,%d\n",fd); return -1; } status = ioctl(fd,SPI_IOC_RD_MODE,&u8_ret); printf("RD_MODE(%d) :0x%x,",status,u8_ret); status = ioctl(fd,SPI_IOC_RD_LSB_FIRST,&u8_ret); printf("LSB_FIRST(%d) :0x%x,",status,u8_ret); status = ioctl(fd,SPI_IOC_RD_BITS_PER_WORD,&u8_ret); printf("BITS_PER_WORD(%d) :0x%x,",status,u8_ret); status = ioctl(fd,SPI_IOC_RD_MAX_SPEED_HZ,&u32_ret); printf("MAX_SPEED_HZ(%d) :0x%x\n",status,u32_ret); u8_ret = 8; status = ioctl(fd,SPI_IOC_WR_BITS_PER_WORD,&u8_ret); printf("set BITS_PER_WORD(%d) :0x%x\n",status,u8_ret); u32_ret = 1000000; status = ioctl(fd,SPI_IOC_WR_MAX_SPEED_HZ,&u32_ret); printf("set MAX_SPEED_HZ(%d) :0x%x\n",status,u32_ret); memset(xfer, 0, sizeof xfer); memset(buf, 0, sizeof buf); buf[0] = 0xaa; xfer[0].tx_buf = (__u64) buf; xfer[0].len = 1; xfer[1].rx_buf = (__u64) buf; xfer[1].len = 4; status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer); printf("ioctl return %d\n",status); printf("buf[0]=%d, buf[1]=%d, buf[2]=%d\n",buf[0],buf[1],buf[2]); return 0; } В board-sam9260ek.c : ..... static struct spi_board_info ek_spi_devices[] = { .... { /* SPI device 1,CS 0*/ .modalias = "spidev", .chip_select = 0, .max_speed_hz = 15 * 1000 * 1000, .bus_num = 1, }, { /* SPI device 1, CS 1*/ .modalias = "spidev", .chip_select = 1, .max_speed_hz = 15 * 1000 * 1000, .bus_num = 1, }, { /* SPI device 1, CS 2*/ .modalias = "spidev", .chip_select = 2, .max_speed_hz = 15 * 1000 * 1000, .bus_num = 1, }, { /* SPI device 1, CS 3*/ .modalias = "spidev", .chip_select = 3, .max_speed_hz = 15 * 1000 * 1000, .bus_num = 1, }, .... } Ядро версии 2.6.30 Если работают read и write, то вероятней всего вы забыли сделать memset(xfer, 0, sizeof xfer); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Pasa 0 26 ноября, 2009 Опубликовано 26 ноября, 2009 · Жалоба to lamination: Ваш пример сразу заработал. Огромное спасибо. В примере из документации по ядру main() организована по другому. Хотя там структура на передачу вроде инициализируется. Попробую найти где же там допущены неточности из-за которых видимо этот пример и не работает. Вообщем даже интерсно....покопаюсь. Еще раз огромное спасибо. Похоже дело сдвинулось с мертвой точки Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Pasa 0 27 ноября, 2009 Опубликовано 27 ноября, 2009 · Жалоба Итак, небольшое резюме по итогам работы с SPI для AT91SAM9260(ядро 2.6.28): Начну с конца, с драйвера шины SPI (файл atmel_spi.c) В функции atmel_spi_transfer() есть такой код: if (xfer->bits_per_word || xfer->speed_hz) { dev_dbg(&spi->dev, "no protocol options yet\n"); return -ENOPROTOOPT; } xfer->bits_per_word и xfer->speed_hz собственно и есть те самые параметры, которые передаются в драйвер из пользовательского приложения, где инциализируется структура spi_ioc_transfer. Если эти параметры не обнулить(всю структуру нулить не обязательно, достаточно только этих двух) то мы и нарываемся на "отлуп" в виде "no protocol options yet". Для чего это сделано я не разбирался. Вроде логичным было-бы сделать наооборот - считать ошибкой когда параметры передачи не установлены или сброшены в ноль. Ведь эти самые структуры spi_ioc_transfer можно паковать в массивы и подсовывать драйверу для передачи через вызов ioctl(fd, SPI_IOC_MESSAGE(кол-во мессаг), адрес_массива_структур); При этом была бы теоретическая возможность каждую мессагу слать с собственными параметрами передачи(понятно, что для этого нужно было-бы драйверу перепрограммировать аппаратные регистры контроллера SPI). Возможно это невозвожно(пардон за тавталогию) или есть какие-либо причины мне неизвестные. А может я просто до конца не разобрался. Но сделано так, как сделано. Поэтому всем, кто как и я будет юзать пример работы с SPI, взятый из документации ядра, файл spidev_test.c: перед вызовом ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); сделайте как минимум tr.speed_hz = 0; tr.bits_per_word = 0; Без этого будете получать "no protocol options yet" . И еще одна описка/опечатка: ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); if (ret == 1) pabort("can't send spi message"); Привильно будет if (ret < 0) т.к. в ret при успешной передаче будет возвращаться ОБЩЕЕ число переданных/принятых байт во ВСЕЙ пачке(массиве) структур, которые мы подготовили к моменту вызова ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); // здесь передается ОДНО сообщение по SPI Если сделать ret = ioctl(fd, SPI_IOC_MESSAGE(5), array_st_mess_spi) - то будет передано 5 сообщений из массива структур array_st_mess_spi, которые мы должны предварительно подготовить, а именно - проинициализировать указатели на приемо/передающие буфера, длину передачи и ОБНУЛИТЬ speed_hz и bits_per_word. И в ret вернется ОБЩЕЕ число переданных байт всех 5 посылок. В случае неудачи у меня было ret < 0 . Вот собственно и все. На сегодняшний момент SPI работает отлично, никаких проблем отмечено пока не было. Все вышесказанное сугубо ИМХО, если ошибся где - поправьте. Надеюсь это поможет остальным избежать граблей, на которые наступил я. Еще раз всем спасибо за помощь и внимание. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
coolzero 0 16 июня, 2010 Опубликовано 16 июня, 2010 · Жалоба Добрый день. я новичёк в линуксе, начал разбираться с платой SK-AT91SAM9XE512. "Из документации ядра 2.6.28 взял пример работы с SPI - spidev_test.c В конфигурации ядра сделал все как описывали на форуме. Все подключилось." Не подскажите попобробнее, как работать с примером spidev_test ? Может ткнёте, а где описывалось на форуме , чтобы всё подключилось ? Что надо сделать, чтобы в /dev появились файлы у-в spi ? Пробовал создать - mknod /dev/spi0 c 153 0 , что то не очень создаются ... Пробовал скомпилить spidev_test - на выходе a.out , загружаю на плату линукс запускать его не хочет ... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
A.t.a.m.a.n 0 5 сентября, 2011 Опубликовано 5 сентября, 2011 · Жалоба Итак, небольшое резюме по итогам работы с SPI для AT91SAM9260(ядро 2.6.28): Начну с конца, с драйвера шины SPI (файл atmel_spi.c) В функции atmel_spi_transfer() есть такой код: if (xfer->bits_per_word || xfer->speed_hz) { dev_dbg(&spi->dev, "no protocol options yet\n"); return -ENOPROTOOPT; } xfer->bits_per_word и xfer->speed_hz собственно и есть те самые параметры, которые передаются в драйвер из пользовательского приложения, где инциализируется структура spi_ioc_transfer. Если эти параметры не обнулить(всю структуру нулить не обязательно, достаточно только этих двух) то мы и нарываемся на "отлуп" в виде "no protocol options yet". Обновим тему. Я юзаю плату Atmel NGW100, Linux версия 2.6.27.6 Там код atmel_spi.c отличается, но всё равно есть ошибки. Если в spidev_test.c оставить следующий код как есть tr.speed_hz = speed; tr.bits_per_word = bits; При bits = 16, передача/приём у меня проходили без ошибок, но первые 4 бита каждого 2-го байта (элемента массива) в приёмном буфере оставались нулевыми ! если обнулить переменные tr.speed_hz = 0; tr.bits_per_word = 0; код отрабатывает как ожидалось Кроме этого если использовать буфер с 2х байтными данными то необходимо откорректировать строчку tr.len = ARRAY_SIZE(tx) * sizeof(tx[0]); Вобщем достаточно глюкавый пример и/или интрефейс. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться