Linux - Доступ к шине SPI из пространства пользователя

Предыдущая  Содержание  Следующая V*D*V

http://brew-j2me.blogspot.com/

 

Android Karthik Thursday, May 6, 2010

 

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

 

Чтобы включить взаимодействие с SPI из пользовательского пространства, необходимо его разрешить в ядре.

 

Давайте сначала посмотрим основные настройки ядра, необходимые для включения поддержки SPI.

 

CONFIG_SPI

CONFIG_SPI_MASTER

CONFIG_SPI_SPIDEV

 

CONFIG_SPI_SPIDEV разрешает для нас ядро SPI пользовательского пространства.

 

Большинство процессоров для увеличения производительности и простоты использования имеют встроенный модуль шины SPI. Если ваша платформа имеет соответствующий драйвер устройства Linux, включите соответствующую опцию.

 

Например, для платформы OMAP24xx или OMAP34xx необходимо включить CONFIG_SPI_OMAP24XX, чтобы использовать встроенный в процессор модуль McSPI.

 

Теперь для экспорта шины SPI в пространство пользователя необходимо настроить файл платы.

 

Добавляем этот кусочек кода в файл board*.c.

 

/* Structure for configuing McSPI */

static struct spi_board_info board_spi3_board_info[] = {

    {

        .modalias    = "spidev",/* Представление SPI в пространстве пользователя */

        .max_speed_hz = 500000, /* Скорость SPI. */

        .bus_num     = 3,       /* Номер шины McSPI */

        .chip_select = 0,       /* Выбор кристалла для McSPI */

        .mode        = 0,       /* Режим SPI */

    },

};

 

и добавляем регистрацию шины SPI в функцию board_init файла board*.c.

 

/* Регистрируем SPI устройство */

spi_register_board_info(board_spi3_board_info, ARRAY_SIZE(board_spi3_board_info));

 

Теперь после загрузки системы вы должны увидеть в файловой системе ваше SPI устройство в каталоге /dev, например, /dev/spidev2.0 (2 - номер шины SPI, 0 - выбор кристалла).

 

Для передачи и приёма SPI сообщений устройству /dev/spidevx.y можно использовать стандартные вызовы open, read, write и close.

 

Открыть устройство SPI можно используя следующий вызов:

 

int fd = 0;

fd = open("/dev/spidev2.0", O_RDWR);

if (fd < 0)

{

    printf("SPI : can't open device");

    return -1;

}

 

Теперь, используя вызовы ioctl можно настроить SPI.

 

Установка режима SPI:

 

ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);

if (ret == -1)

{

    printf("SPI : can't set spi mode");

    return 1;

}

 

Запрос режима SPI

 

ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);

if (ret == -1)

{

    printf("SPI : can't get spi mode");

    return 1;

}

 

Другими параметрами шины SPI можно управлять аналогичным способом.

 

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

 

struct spi_ioc_transfer mesg[1] = { 0, };

 

mesg[0].tx_buf = (unsigned long)out_buffer;

mesg[0].len = num_out_bytes;

 

ret = ioctl(fd, SPI_IOC_MESSAGE(1), mesg);

To receive SPI message

struct spi_ioc_transfer mesg[1] = { 0, };

 

mesg[0].rx_buf = (unsigned long)out_buffer;

mesg[0].len = num_out_bytes;

 

ret = ioctl(fd, SPI_IOC_MESSAGE(1), mesg);

 

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

 

int spidev_if_write_read(unsigned int num_out_bytes,

                         unsigned char *out_buffer,

                         unsigned int num_in_bytes,

                         unsigned char *in_buffer)

{

    struct spi_ioc_transfer mesg[2] = { 0, };

    uint8_t num_tr = 0;

    int ret;

 

    if((out_buffer != NULL) && (num_out_bytes != 0))

    {

        mesg[0].tx_buf = (unsigned long)out_buffer;

        mesg[0].rx_buf = (unsigned long)NULL;

        mesg[0].len = num_out_bytes;

        mesg[0].cs_change = 0;

        num_tr++;

    }

 

    if((in_buffer != NULL) && (num_in_bytes != 0))

    {

        mesg[1].tx_buf = (unsigned long)NULL;

        mesg[1].rx_buf = (unsigned long)in_buffer;

        mesg[1].len = num_in_bytes;

        num_tr++;

    }

 

    if(num_tr > 0)

    {

        ret = ioctl(fd, SPI_IOC_MESSAGE(num_tr), mesg);

        if(ret == 1)

        {

            return 1;

        }

    }

 

    return 0;

}

 

Переменная cs_change=0 запрещает изменение состояния сигнала CS между двумя транзакциями.

 

Предыдущая  Содержание  Следующая