Обзор ядра Linux

Поддержка периферии в Linux

В таблице 2.1 приведены сведения о поддерживаемой периферии в Linux 4.14 для различных микросхем.

Таблица 2.1 - Поддержка периферии в Linux 4.14

Микросхема

Кодовое имя

Версия ядра Linux

UART

MFBSP-SPI

MFBSP-GPIO

MFBSP-LPORT

Ethernet

1892ВМ15Ф

МС-30SF6

Linux 4.14

1892ВК016

MCT-04

Linux 4.14

✖️

✖️

1892ВМ206

MCT-06

Linux 4.14

➕ - присутствует драйвер
➖ - отсутствует драйвер
✖️ - отсутствует контроллер в микросхеме

Исходный код ядра Linux

Исходный код ядра Linux содержит:

  • драйверы периферии:
    • arch/mips/multicore/*.c

    • arch/mips/multicore/*.h

  • файлы управления и поддержки чипов:
    • arch/mips/include/asm/mach-multicore/*.c

    • arch/mips/include/asm/mach-multicore/*.h

  • файлы конфигурации:
    • arch/mips/multicore/Kconfig.

Поддержка драйверов Linux

MFBSP SPI

MFBSP SPI может работать в режиме Master и в режиме Slave.

Далее описан алгоритм передачи данных из MFBSP-SPI0(host) в MFBSP-SPI1(Slave):

  • включить поддержку spidev, установив параметр CONFIG_SPI_SPIDEV

  • включить CONFIG_MULTICORE_MFBSP

  • включить CONFIG_MULTICORE_MFBSP0_SPI_HOST и CONFIG_MULTICORE_MFBSP1_SPI_DEVICE

  • в CONFIG_CMDLINE требуется дописать параметр spidev.bufsiz со значением, равным количеству цепочек DMA, умноженным на размер одной цепочки,т.е. CONFIG_MULTICORE_SPI_DMA_COUNT_OF_CHAINS умножается на CONFIG_MULTICORE_SPI_DMA_ONE_CHAIN_SIZE. Параметр CONFIG_CMDLINE выглядит следующим образом:

    console=ttyS0,115200N8 root=/dev/ram spidev.bufsiz=163840
    
  • в примере, который запускается из user-space, константу READ_FILE требуется заменить на файл, из которого программа будет считывать данные и посылать их в MFBSP-SPI1(Slave):

    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <string.h>
    #include <linux/ioctl.h>
    
    #define SPI0 "/dev/spidev0.0"
    #define SPI1 "/dev/mc_spi_slave_1"
    #define READ_FILE "/etc/init.d/1024K_file"
    #define WRITE_FILE "/etc/init.d/test_spi.txt"
    
    #define GET_ONE_CHAIN_SIZE_SPI_SLAVE _IOR('r', 5, int *)
    #define GET_COUNT_OF_CHAINS_SPI_SLAVE _IOR('r', 6, int *)
    
    int file_len = 0;
    int read_pos = 0;
    int write_pos = 0;
    size_t buffer_len;
    
    /* Calculate count of symbols in file */
    int num_chars(char* path) {
          int fd_read_file;
          char filepath[100];
          off_t size;
    
          strcpy(filepath, path);
          fd_read_file = open(filepath, O_RDONLY);
          if (fd_read_file == -1) {
                printf("Could not open file %s", filepath);
                return 0;
          }
    
          off_t pos = lseek(fd_read_file, 0, SEEK_CUR);
          if (pos != (off_t)-1) {
                size = lseek(fd_read_file, 0, SEEK_END);
                lseek(fd_read_file, pos, SEEK_SET);
          }
    
          close(fd_read_file);
    
          return size;
    }
    
    int main(void) {
          int fd, fd_write_spi, fd_read_spi, fd_read_file, fd_write_file;
          char* buffer;
          int read_size;
          int write_size;
          size_t bytes_read;
          size_t bytes_write;
          int one_chain_size = 0;
          int count_of_chains = 0;
    
          file_len = num_chars(READ_FILE);
    
          fd = open(SPI1, O_RDONLY);
          if (fd == -1) {
                printf("open() error\n");
                return -1;
          }
    
          ioctl(fd, GET_ONE_CHAIN_SIZE_SPI_SLAVE, &one_chain_size);
          ioctl(fd, GET_COUNT_OF_CHAINS_SPI_SLAVE, &count_of_chains);
          buffer_len = one_chain_size * count_of_chains;
          buffer = (char*)malloc(buffer_len * sizeof(char));
          if (buffer == NULL) {
                printf("cannot allocate %d of memory\n", buffer_len);
                return -1;
          }
          close(fd);
    
    
          fd_write_spi = open(SPI0, O_WRONLY);
          if (fd_write_spi == -1) {
                printf("open() error\n");
                return -1;
          }
    
          fd_read_spi = open(SPI1, O_RDONLY);
          if (fd_read_spi == -1) {
                printf("open() error\n");
                return -1;
          }
    
          fd_read_file = open(READ_FILE, O_RDONLY);
          if (fd_read_file == -1) {
                printf("open() error\n");
                return -1;
          }
    
          fd_write_file = creat(WRITE_FILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
          if (fd_write_file == -1) {
                printf("open() error\n");
                return -1;
          }
    
          do {
                /* Write to SPI */
                if (file_len - write_pos > buffer_len) {
                      write_size = buffer_len;
                      write_pos += buffer_len;
                } else {
                      write_size = file_len - write_pos;
                      write_pos += write_size;
                }
                memset(buffer, 0, write_size);
                bytes_read = read(fd_read_file, buffer, write_size);
                bytes_write = write(fd_write_spi, buffer, write_size);
    
                /* Read from SPI */
                if (file_len - read_pos > buffer_len) {
                      read_size = buffer_len;
                      read_pos += buffer_len;
                } else {
                      read_size = file_len - read_pos;
                      read_pos += read_size;
                }
                memset(buffer, 0, read_size);
                bytes_read = read(fd_read_spi, buffer, read_size);
                bytes_write = write(fd_write_file, buffer, read_size);
          } while (read_pos != file_len);
    
          close(fd_write_spi);
          close(fd_read_spi);
          close(fd_read_file);
          close(fd_write_file);
    
          return 0;
    }
    
  • для того, чтобы убедиться, что переданный файл равен полученному файлу, можено воспользоваться утилитой diff:

    $ diff /etc/init.d/test_file /etc/init.d/test_spi.txt
    

MFBSP LPORT

MFBSP LPORT может работать в режиме Master и в режиме Slave.

Далее описан пример передачи данных из MFBSP-LPORT0(host) в MFBSP-LPORT1(Slave).

Требуется:

  • включить CONFIG_MULTICORE_MFBSP

  • включить CONFIG_MULTICORE_MFBSP0_LPORT_HOST и CONFIG_MULTICORE_MFBSP1_LPORT_DEVICE

  • в примере, который запускается из user-space, константу READ_FILE заменить на файл, из которого программа будет считывать данные и посылать их в MFBSP-LPORT1(Slave):

    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <string.h>
    #include <linux/ioctl.h>
    
    #define LPORT0 "/dev/lport_0"
    #define LPORT1 "/dev/lport_1"
    #define READ_FILE "/etc/init.d/1024K_file"
    #define WRITE_FILE "/etc/init.d/test_lport.txt"
    
    #define LPORT_GET_ONE_CHAIN_SIZE _IOR('l', 7, int *)
    #define LPORT_GET_COUNT_OF_CHAINS _IOR('l', 8, int *)
    
    int file_len = 0;
    int read_pos = 0;
    int write_pos = 0;
    size_t buffer_len;
    
    /* Calculate count of symbols in file */
    int num_chars(char* path) {
          int n, c = 0;
          FILE* fp;
          char filepath[100];
    
          strcpy(filepath,path);
          fp = fopen(filepath, "r");
          if (fp == NULL) {
                printf("Could not open file %s", filepath);
                return 0;
          }
    
          for (n = getc(fp); n != EOF; n = getc(fp))
                c = c + 1;
          fclose(fp);
    
          return c;
    }
    
    int main(void) {
          int fd, fd_write_lport, fd_read_lport, fd_read_file, fd_write_file;
          char* buffer;
          int read_size;
          int write_size;
          size_t bytes_read;
          size_t bytes_write;
          int one_chain_size = 0;
          int count_of_chains = 0;
    
          file_len = num_chars(READ_FILE);
    
          fd = open(LPORT0, O_RDONLY);
          if (fd == -1) {
                printf("open() error\n");
                return -1;
          }
    
          ioctl(fd, LPORT_GET_ONE_CHAIN_SIZE, &one_chain_size);
          ioctl(fd, LPORT_GET_COUNT_OF_CHAINS, &count_of_chains);
          buffer_len = one_chain_size * count_of_chains;
          buffer = (char*)malloc(buffer_len * sizeof(char));
          if (buffer == NULL) {
                printf("cannot allocate %d of memory\n", buffer_len);
                return -1;
          }
          close(fd);
    
    
          fd_write_lport = open(LPORT0, O_WRONLY);
          if (fd_write_lport == -1) {
                printf("open() error\n");
                return -1;
          }
    
          fd_read_lport = open(LPORT1, O_RDONLY);
          if (fd_read_lport == -1) {
                printf("open() error\n");
                return -1;
          }
    
          fd_read_file = open(READ_FILE, O_RDONLY);
          if (fd_read_file == -1) {
                printf("open() error\n");
                return -1;
          }
    
          fd_write_file = creat(WRITE_FILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
          if (fd_write_file == -1) {
                printf("open() error\n");
                return -1;
          }
    
          do {
                /* Write to LPORT */
                if (file_len - write_pos > buffer_len) {
                      write_size = buffer_len;
                      write_pos += buffer_len;
                } else {
                      write_size = file_len - write_pos;
                      write_pos += write_size;
                }
                bytes_read = read(fd_read_file, buffer, write_size);
                bytes_write = write(fd_write_lport, buffer, write_size);
                sleep(1);
    
                /* Read from LPORT */
                if (file_len - read_pos > buffer_len) {
                      read_size = buffer_len;
                      read_pos += buffer_len;
                } else {
                      read_size = file_len - read_pos;
                      read_pos += read_size;
                }
                bytes_read = read(fd_read_lport, buffer, read_size);
                bytes_write = write(fd_write_file, buffer, read_size);
                sleep(1);
    
          } while (bytes_read != 0);
    
          close(fd_write_lport);
          close(fd_read_lport);
          close(fd_read_file);
          close(fd_write_file);
    
          return 0;
    }
    

MFBSP GPIO

В таблице 2.2 приведены сведения о подключенных к MFBSP GPIO светодиодах для различных плат

Таблица 2.2 - Доступные светодиоды

Плата

Интерфейс

Выводы

MC-30SF6EM-6U

MFBSP3

LDAT3_0-7 LACK3 LCLK3

MCT-04EM-3U

MFBSP0

LDAT0_5-7

MCT-06EM-6U

MFBSP0

LDAT0_4-7

✖️ - отсутствие светодиодов, подключенных к MFBSP GPIO

В таблице 2.3 приведено соотвествие внешнего вывода MFBSP GPIO и номера GPIO

Таблица 2.3 - Соотвествие внешнего вывода и GPIO

Внешний вывод MFBSP GPIO

GPIO

LACK

GPIO0

LCLK

GPIO1

LDAT[0:7]

GPIO[2:9]

Далее описан пример взаимодействия с MFBSP0 LDAT0_4 (GPIO6) на MCT-06EM-6U, который включает LED0.

Требуется:

  • включить CONFIG_MULTICORE_MFBSP

  • включить CONFIG_MULTICORE_MFBSP0_GPIO

  • Далее описаны команды взаимодействия c GPIO6 через sysfs:

    • Включаем GPIO6. 06 - MFBSP0, LDAT0_4:

      $ echo "06" > /sys/class/gpio/export
      
    • Устанавливаем направление для GPIO. Возможные варианты - out или in:

      $ echo "out" > /sys/class/gpio/gpio6/direction
      
    • Устанавливаем значение GPIO4. Возможные варианты - 1 или 0:

      $ echo "1" > /sys/class/gpio/gpio6/value
      
  • Наблюдаем горящий светодиод LED0

Ethernet

Для MCT-06 включение драйвера Ethernet происходит через CONFIG_MULTICORE_ETH. Для остальных микросхем включение драйвера Ethernet происходит через CONFIG_MULTICORE_NEW_ETH_DRV.

Запуск теста Ethernet:

  • на host-машине, которая находится в одной сети с target:

    $ iperf -s;
    
  • на target-системе выполнить (1.2.3.4-ip-адрес host-машины):

    $ iperf -c 1.2.3.4