2017-01-29 21 views
3

Я пытаюсь научиться писать базовый драйвер SPI, а ниже - функция зонда, которую я написал.SPI linux driver

Что я пытаюсь сделать здесь, это установить устройство spi для рамки (datasheet) и использовать spi_sync_transfer()api description, чтобы получить идентификатор производителя от чипа.

Когда я выполняю этот код, я могу видеть данные на шине SPI с помощью логического анализатора, но я не могу его прочитать с помощью rx-буфера. Я что-то упустил? Может кто-нибудь, пожалуйста, помогите мне с этим?

static int fram_probe(struct spi_device *spi) 
{ 
    int err; 
    unsigned char ch16[] = {0x9F,0x00,0x00,0x00};// 0x9F => 10011111 
    unsigned char rx16[] = {0x00,0x00,0x00,0x00}; 

    printk("[FRAM DRIVER] fram_probe called \n"); 

    spi->max_speed_hz = 1000000; 
    spi->bits_per_word = 8; 
    spi->mode = (3); 

    err = spi_setup(spi); 
     if (err < 0) { 
      printk("[FRAM DRIVER::fram_probe spi_setup failed!\n"); 
      return err; 
     } 
    printk("[FRAM DRIVER] spi_setup ok, cs: %d\n", spi->chip_select); 
    spi_element[0].tx_buf = ch16; 
    spi_element[1].rx_buf = rx16; 

    err = spi_sync_transfer(spi, spi_element, ARRAY_SIZE(spi_element)/2); 
    printk("rx16=%x %x %x %x\n",rx16[0],rx16[1],rx16[2],rx16[3]); 

    if (err < 0) { 
     printk("[FRAM DRIVER]::fram_probe spi_sync_transfer failed!\n"); 
     return err; 
    } 

    return 0; 
} 
+0

Здесь очень много проблем с этим кодом. Прежде всего, это ** не ** драйвер SPI. Во-вторых, вы должны понимать, как общаться с SPI в ядре и в пространстве пользователя.В-третьих, вам нужно узнать, как работает аппаратный уровень шины SPI. Какие сигналы у него есть и как они меняются во времени. – 0andriy

+0

Ядро имеет два типа драйверов, которые можно было бы назвать драйверами SPI. Это, по-видимому, функция пробника 'spi_driver', созданная путем регистрации' struct spi_driver' с 'module_spi_driver()'. Поэтому я считаю, что это вполне разумно назвать драйвером SPI. Другой тип - это мастер-драйвер, определяемый 'struct spi_master' и зарегистрированный в' spi_register_master() '. – TrentP

+0

@TrentP, это не главный мастер SPI, я стою исправлен. – 0andriy

ответ

1

spi_element не указан в этом примере. Вы должны показать это, а также как все элементы массива заполнены. Но только из кода, который там, я вижу пару ошибок.

Необходимо установить параметр lenspi_transfer. Вы назначили буфер TX или RX ch16 или rx16, но не задали длину буфера в обоих случаях.

Вы должны обнулить все поля, не используемые в spi_transfer.

Если вы установите длину до четырех, вы не отправите правильную команду в соответствии с таблицей данных. RDID ожидает одну команду байта, после которой будет следовать четыре байта выходных данных. Вы пишете команду четыре команды байта в своей первой передаче, а затем читаете четыре байта данных. Tx_buf в первой передаче должен быть только одним байтом.

И, наконец, неверно указано количество передач, указанное в качестве последнего аргумента spi_sync_transfer(). В этом случае должно быть 2, потому что вы определили два, spi_element[0] и spi_element[1]. Вы можете использовать ARRAY_SIZE(), если spi_element был объявлен для этого сообщения, и вы хотите отправить все передачи в массиве.

Рассмотрите это как способ лучше заполнить spi_transfers. Он позаботится об обнулении полей, которые не используются, определяет переносы в удобном для восприятия способом, а изменение размера буфера или количества переводов автоматически учитывается в остальном коде.

const char ch16[] = { 0x8f }; 
char rx16[4]; 
struct spi_transfer rdid[] = { 
    { .tx_buf = ch16, .len = sizeof(ch16) }, 
    { .rx_buf = rx16, .len = sizeof(rx16) }, 
}; 
spi_transfer(spi, rdid, ARRAY_SIZE(rdid)); 

Поскольку у вас есть сферы, не забудьте проверить, что эта операция происходит под одного чипа выбора импульса. Я обнаружил, что более одного драйвера SPI для Linux имеет ошибку, которая генерирует выборку микросхем, когда она не должна. В некоторых случаях переключение с TX на RX (как сделано выше) вызовет импульс CS. В других случаях CS-импульс генерируется для каждого слова (8 бит здесь) данных.

Другая вещь, которую вы должны изменить, - это использовать dev_info(&spi->dev, "device version %d", id)', а также dev_err() для печати сообщений. Это вставляет имя устройства стандартным способом вместо жестко закодированного нестандартного и непоследовательного «текста [FRAME DRIVER] ::». И задает уровень сообщения в зависимости от ситуации.

Кроме того, рассмотрите возможность поддержки дерева устройств в драйвере для чтения свойств устройства. Затем вы можете делать такие вещи, как изменение частоты шины SPI для этого устройства без переустановки драйвера ядра.

+0

Большое спасибо за ваше объяснение и помощь. Я изменил функции, как вы предлагали, и, похоже, дает мне то, что я ожидаю. Большое спасибо! –