Перейти к содержанию
    

AT91SAM960 - не работает SPI

Процессор AT91SAM9260

 

Из документации ядра 2.6.28 взял пример работы с SPI - spidev_test.c

В конфигурации ядра сделал все как описывали на форуме. Все подключилось.

В /dev появилось устройство spidev. Пример заработал - обращения к драйверу проходят.

Передача вроде должна идти.А вот данных осцилографом не вижу.

 

Распечатал на консоль значения портов и регистров SPI - режимы вроде установлены верно.

А передачи нет. При этом датафлэш висящая на SPI работает отлично, и когда идет

обращение к ней, то осцилографом все прекрасно видно.

 

Подскажите в чем тут загвоздка?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нет только данных или тактов тоже?

 

ни тактов ни данных. А вот при установке режима чипселект реагирует:

 

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....ну понятно....реального обмена то нет....А флэшка работает и посмеивается надо мной....Я в тупике....

Изменено пользователем Pasa

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Может кто подскажет точку входа и в каком файле искать

 

ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);

 

попробую лог на консоль....черз printk.....вдруг поможет

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Эксперименты привели к следующему: вызовы write и read прекрасно работают. А если через ioctl вызывать spidev_ioctl(для полнодуплексного обмена), то из драйвера SPI (atmel_spi.c) идет возврат с ошибкой опций устновленного протокола. И естественно передачи никакой нет. По исходнику посмотрел - там где анализ на нулевую скорость передачи и ноль бит в слове. В уровень spidev.c структура с параметрами доходит нормально(параметры ставятся в верхнем юзерском слое в самой проге). А потом где-то теряются/затираются/обнуляются и до дравера SPI не доходят. Вот счас пробую проследить всю цепочку...

 

Мда....вот уж не ожидал таких плясок с бубном....не покидает ощущение, что ну не может быть таких ошибок в ядре и я не совсем правильно пользуюсь вызовами ioctl(). Но ведь все взято из примера в документации которая идет с самим ядром. Хотя с другой стороны в этом самом примере сходу нашел одну описку/опечатку/ошибку.

 

Может кто сталкивался с таким и подскажет что-нибудь дельное? Уж больно не хочется лезть в потроха ядра, править его и с ужасом думать о следущих "танцах", когда придется браться за сокеты и шину I2C

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

#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);

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

to lamination:

 

Ваш пример сразу заработал. Огромное спасибо.

 

В примере из документации по ядру main() организована по другому. Хотя там структура на передачу вроде инициализируется.

Попробую найти где же там допущены неточности из-за которых видимо этот пример и не работает. Вообщем даже интерсно....покопаюсь.

 

Еще раз огромное спасибо. Похоже дело сдвинулось с мертвой точки

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Итак, небольшое резюме по итогам работы с 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 работает отлично, никаких проблем отмечено пока не было.

Все вышесказанное сугубо ИМХО, если ошибся где - поправьте. Надеюсь это поможет остальным избежать граблей,

на которые наступил я.

 

Еще раз всем спасибо за помощь и внимание.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добрый день. я новичёк в линуксе, начал разбираться с платой SK-AT91SAM9XE512.

 

"Из документации ядра 2.6.28 взял пример работы с SPI - spidev_test.c

В конфигурации ядра сделал все как описывали на форуме. Все подключилось."

 

Не подскажите попобробнее, как работать с примером spidev_test ?

Может ткнёте, а где описывалось на форуме , чтобы всё подключилось ?

Что надо сделать, чтобы в /dev появились файлы у-в spi ?

 

Пробовал создать - mknod /dev/spi0 c 153 0 , что то не очень создаются ...

Пробовал скомпилить spidev_test - на выходе a.out , загружаю на плату

линукс запускать его не хочет ...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Итак, небольшое резюме по итогам работы с 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]);

 

Вобщем достаточно глюкавый пример и/или интрефейс.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...