24.06.2014 Настройка и ресурсы Xilinx ZYNQ ZC702

Материал из SRNS
Перейти к: навигация, поиск
(Беспарольный доступ)
 
(не показаны 34 промежуточные версии 4 участников)
Строка 5: Строка 5:
  
 
[[Файл:ZYNQ ZC702.jpg|right|500px]]
 
[[Файл:ZYNQ ZC702.jpg|right|500px]]
{{Форма3}}
 
{{TOCright}}
 
  
== About ==
+
 
Как всегда для сохранения ценной информации, используем [[Заглавная_страница | SRNS.ru]]. Полезная информация для ZYNQ не станет исключением.
+
== Boot Modes ==
 +
[[Файл:Таблица режимов переключателя sw16.jpg|660px|sw16 modes]]
 +
 
  
 
== Запуск Linux с карты памяти ==
 
== Запуск Linux с карты памяти ==
Строка 25: Строка 25:
 
Карточку вставляем в ZYNQ, джамперы (SW16) выставляем в комбинацию '''00110''', что выглядит как:  
 
Карточку вставляем в ZYNQ, джамперы (SW16) выставляем в комбинацию '''00110''', что выглядит как:  
  
[[Файл:Wiki 7.1 boot mode switch.jpg]]
+
[[Файл:Wiki 7.1 boot mode switch.jpg|250px|SD boot mode]]
  
 
На компе запускаем скрипт:
 
На компе запускаем скрипт:
Строка 39: Строка 39:
  
 
Включаем плату и видим загрузку Linux. Для логина используем Username & Password: '''root'''.
 
Включаем плату и видим загрузку Linux. Для логина используем Username & Password: '''root'''.
 +
  
 
== Прошиваем Linux в QSPI Flash ==
 
== Прошиваем Linux в QSPI Flash ==
Строка 63: Строка 64:
 
flashcp -v uramdisk.image.gz /dev/mtd3</source>
 
flashcp -v uramdisk.image.gz /dev/mtd3</source>
 
Чтобы грузиться с QSPI Flash необходимо переключить джамперы (SW16) в комбинацию '''00010'''.
 
Чтобы грузиться с QSPI Flash необходимо переключить джамперы (SW16) в комбинацию '''00010'''.
 +
  
 
== Модификация FS ==
 
== Модификация FS ==
* Изменения FS скачанного выше релиза.
+
* '''Изменения FS скачанного выше релиза.'''
 
Необходимо развернуть образ FS из "обертки" u-boot. Для этого следует пропустить первые 64 байта:
 
Необходимо развернуть образ FS из "обертки" u-boot. Для этого следует пропустить первые 64 байта:
 
<source lang="bash">
 
<source lang="bash">
Строка 84: Строка 86:
 
Образ готов для загрузки как с SD, так и с QSPI Flash.
 
Образ готов для загрузки как с SD, так и с QSPI Flash.
  
*Модификация стандартной FS
+
* '''Модификация стандартной FS'''
 
Качаем образ FS по-умолчанию: [http://www.wiki.xilinx.com/file/view/arm_ramdisk.image.gz/419243558/arm_ramdisk.image.gz RamDisk].
 
Качаем образ FS по-умолчанию: [http://www.wiki.xilinx.com/file/view/arm_ramdisk.image.gz/419243558/arm_ramdisk.image.gz RamDisk].
 
Распаковываем его:
 
Распаковываем его:
Строка 131: Строка 133:
 
petalinux-util --webtalk off
 
petalinux-util --webtalk off
 
</source>
 
</source>
 +
  
 
== Беспарольный доступ ==
 
== Беспарольный доступ ==
Строка 137: Строка 140:
  
 
Устанавливаем все права как:
 
Устанавливаем все права как:
 +
 
''Обратите внимание, что права устанавливаются именно для подмонтированной файловой системы, а не для файлов, используемых нашим компом!''
 
''Обратите внимание, что права устанавливаются именно для подмонтированной файловой системы, а не для файлов, используемых нашим компом!''
 
<source lang="bash">
 
<source lang="bash">
Строка 145: Строка 149:
  
 
Собираем FS и грузимся со всеми нашими модификациями.
 
Собираем FS и грузимся со всеми нашими модификациями.
 +
 +
 +
== Компиляция исходников ==
 +
Необходимо установить '''ISE''', есть на сервере.
 +
Далее по окончании установки и каждый раз при открытии новой консоли необходимо устанавливать параметры среды $PATH, запуская скрипт:
 +
<source lang="bash">
 +
source <путь установки ISE>/14.7/ISE_DC/settings64.sh
 +
</source>
 +
 +
После этого уже можно стандартно использовать компилятор. Для ZYNQ zc702 он называется ''arm-xilinx-linux-gnueabi-gcc'', ну или ''arm-xilinx-linux-gnueabi-g++''.
 +
 +
 +
== Функции чтения и записи в регистры ==
 +
Литература: [[Медиа:Ug585-Zynq-7000-TRM.pdf|Техническое справочное руководство]], [[Медиа:Xtp185-zc702-schematic-rev1-1.pdf|схема]].
 +
 +
Адреса регистров описаны в техническом руководстве, B.28 (с. 1554).
 +
 +
<syntaxhighlight lang=c>
 +
#include <stdio.h>
 +
#include <stdlib.h>
 +
#include <unistd.h>
 +
#include <string.h>
 +
#include <errno.h>
 +
#include <fcntl.h>
 +
#include <signal.h>
 +
#include <sys/mman.h>
 +
 +
#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
 +
  __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)
 +
 +
#define MAP_SIZE 4096UL
 +
#define MAP_MASK (MAP_SIZE - 1)
 +
#define BASE_ADDRESS         0xF8000000
 +
 +
#define SET_AS_GPIO 0x1200
 +
#define SET_UNLOCK 0xDF0D
 +
#define SLCR_UNLOCK         0x8
 +
#define MIO_PIN_8 0x720
 +
#define MIO_PIN_10 0x728
 +
 +
/*Чтение регистров по адресу*/
 +
void register_read(unsigned long addr)
 +
{
 +
int fd;
 +
void *map_base, *virt_addr;
 +
unsigned long read_result;
 +
if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
 +
        fflush(stdout);
 +
        /* Map one page */
 +
        map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, BASE_ADDRESS & ~MAP_MASK);
 +
        if(map_base == (void *) -1) FATAL;
 +
        fflush(stdout);
 +
        virt_addr = map_base + ((BASE_ADDRESS + addr) & MAP_MASK);
 +
        read_result = *((unsigned long *) virt_addr);
 +
printf("0x%08X r: 0x%X\n", addr, read_result);
 +
fflush(stdout);
 +
}
 +
 +
/*Запись в регистр по адресу*/
 +
void register_write(unsigned long addr, unsigned long writeval)
 +
{
 +
int fd;
 +
void *map_base, *virt_addr;
 +
unsigned long read_result;
 +
if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
 +
        // printf("/dev/mem opened.\n");
 +
        fflush(stdout);
 +
        /* Map one page */
 +
        map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, BASE_ADDRESS & ~MAP_MASK);
 +
        if(map_base == (void *) -1) FATAL;
 +
        // printf("Memory mapped at address %p.\n", map_base);
 +
        fflush(stdout);
 +
        virt_addr = map_base + ((BASE_ADDRESS + addr) & MAP_MASK);
 +
*((unsigned long *) virt_addr) = writeval;
 +
read_result = *((unsigned long *) virt_addr);
 +
printf("0x%08X w: 0x%X\n", addr, read_result);
 +
}
 +
 +
 +
int main (void)
 +
{     
 +
        /*Изначально, при загрузке, MIO_PIN_8 (на нём висит диод DS12) не сконфигурирован для GPIO, исправим это.*/
 +
register_write(SLCR_UNLOCK, SET_UNLOCK); // Необходимый анлок регистров
 +
register_read(MIO_PIN_8); // Считываем начальное значение регистра
 +
register_write(MIO_PIN_8, SET_AS_GPIO); // Записываем новое значение
 +
register_read(MIO_PIN_8); // Считываем новое значение регистра
 +
}
 +
</syntaxhighlight>
 +
 +
== Управление GPIO ==
 +
Функции управления GPIO такие же как и для Impal'ы в CPU.cpp (на всякий случай копирну):
 +
<syntaxhighlight lang=c>
 +
#include <stdio.h>
 +
#include <stdlib.h>
 +
#include <unistd.h>
 +
#include <string.h>
 +
#include <errno.h>
 +
#include <fcntl.h>
 +
#include <signal.h>
 +
#include <sys/mman.h>
 +
 +
#define SYSFS_GPIO_DIR "/sys/class/gpio"
 +
 +
/* Включение режима GPIO по номеру */
 +
int gpio_export(unsigned int gpio)
 +
{
 +
 +
FILE *fid;
 +
fid = fopen(SYSFS_GPIO_DIR "/export", "w");
 +
if (fid == NULL) printf("fopen: %s\n", strerror(errno));
 +
if (fprintf(fid, "%d", gpio) <= 0)
 +
  printf("fprintf: %s\n", strerror(errno));
 +
fclose(fid);
 +
 +
    return 0;
 +
}
 +
 +
/* Настройка направления GPIO по номеру */
 +
int gpio_set_dir(unsigned int gpio, unsigned int out_flag)
 +
{
 +
 +
FILE *fid;
 +
char filename[40];
 +
sprintf(filename, SYSFS_GPIO_DIR "/gpio%d/direction", gpio);
 +
 +
fid = fopen(filename, "w");
 +
if (fid == NULL) printf("fopen %s: %s\n", filename, strerror(errno));
 +
if (out_flag) {
 +
  if (fprintf(fid, "out") <= 0)
 +
    printf("fprintf: %s\n", strerror(errno));
 +
} else {
 +
  if (fprintf(fid, "in") <= 0)
 +
    printf("fprintf: %s\n", strerror(errno));
 +
}
 +
fclose(fid);
 +
 +
    return 0;
 +
}
 +
 +
/* Установка значение GPIO по номеру */
 +
int gpio_set_value(unsigned int gpio, unsigned int value)
 +
{
 +
 +
FILE *fid;
 +
char filename[40];
 +
sprintf(filename, SYSFS_GPIO_DIR "/gpio%d/value", gpio);
 +
 +
fid = fopen(filename, "w");
 +
if (fid == NULL) printf("fopen: %s\n", strerror(errno));
 +
 +
if (value == 1) {
 +
  if (fprintf(fid, "1") <= 0)
 +
    printf("fprintf: %s\n", strerror(errno));
 +
} else {
 +
  if (fprintf(fid, "0") <= 0)
 +
    printf("fprintf: %s\n", strerror(errno));
 +
}
 +
fclose(fid);
 +
 +
    return 0;
 +
}
 +
 +
/* Чтение значения из GPIO по номеру */
 +
int gpio_get_value(unsigned int gpio)
 +
{
 +
 +
FILE *fid;
 +
char filename[40];
 +
int value;
 +
sprintf(filename, SYSFS_GPIO_DIR "/gpio%d/value", gpio);
 +
 +
fid = fopen(filename, "r");
 +
if (fid == NULL) printf("fopen: %s\n", strerror(errno));
 +
 +
if (fscanf(fid, "%1d", &value) <= 0)
 +
  printf("gpio_get_value failed: %s\n", strerror(errno));
 +
 +
fclose(fid);
 +
 +
if (value == 0)
 +
  return 0;
 +
else
 +
  return 1;
 +
 +
    return 0;
 +
}
 +
 +
/* Настройка фронта срабатывания GPIO по номеру */
 +
int gpio_set_edge(unsigned int gpio, char *edge)
 +
{
 +
  FILE *fid;
 +
char filename[40];
 +
sprintf(filename, SYSFS_GPIO_DIR "/gpio%d/edge", gpio);
 +
 +
fid = fopen(filename, "w");
 +
if (fid == NULL) printf("fopen %s: %s\n", filename, strerror(errno));
 +
 +
if (fprintf(fid, "%s", edge) <= 0)
 +
  printf("fprintf: %s\n", strerror(errno));
 +
fclose(fid);
 +
 +
    return 0;
 +
}
 +
 +
/* Открывает файл, соответствующий GPIO, по номеру */
 +
int gpio_fd_open(unsigned int gpio)
 +
{
 +
        int fd;
 +
        char buf[MAX_BUF];
 +
 +
        snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
 +
 +
        fd = open(buf, O_RDONLY | O_NONBLOCK );
 +
        if (fd < 0) {
 +
            perror("gpio/fd_open");
 +
        }
 +
        return fd;
 +
 +
}
 +
 +
int main (void)
 +
{
 +
        /* Программа поочередного мигания диодами DS23 и DS12*/
 +
register_write(SLCR_UNLOCK, SET_UNLOCK);
 +
register_read(MIO_PIN_8);
 +
register_write(MIO_PIN_8, SET_AS_GPIO);
 +
register_read(MIO_PIN_8);
 +
 +
gpio_export(10);
 +
gpio_set_dir(10, 1);
 +
gpio_export(8);
 +
gpio_set_dir(8, 1);
 +
for (;;){
 +
gpio_set_value(10, 0);
 +
printf("10: %d\n",gpio_get_value(10));
 +
gpio_set_value(8, 1);
 +
printf("8: %d\n",gpio_get_value(8));
 +
sleep(1);
 +
gpio_set_value(10, 1);
 +
printf("10: %d\n",gpio_get_value(10));
 +
gpio_set_value(8, 0);
 +
printf("8: %d\n",gpio_get_value(8));
 +
sleep(1);
 +
}
 +
 +
 +
}
 +
</syntaxhighlight>
 +
 +
== GPIO Interrupts ==
 +
Пример кода обработки прерывания по ноге GPIO 14, на ней сидит кнопка SW13.
 +
<syntaxhighlight lang=c>
 +
// Добавлена куча ашников, взятых из кода Impal´ы, наверняка нужны не все...
 +
#include <stdio.h>
 +
#include <stdlib.h>
 +
#include <unistd.h>
 +
#include <string.h>
 +
#include <errno.h>
 +
#include <fcntl.h>
 +
#include <signal.h>
 +
#include <sys/mman.h>
 +
#include <poll.h>
 +
#include <sys/time.h>
 +
#include <sys/resource.h>
 +
#include <semaphore.h>
 +
#include <pthread.h>
 +
#include <sched.h>
 +
#include <time.h>
 +
#include <sys/prctl.h>
 +
#include <math.h>
 +
#include <sys/types.h>
 +
 +
//Необходимо добавить нужные функции из предыдущих глав.
 +
 +
int main (void)
 +
{
 +
    int gpio = 14;
 +
 +
    gpio_export(gpio);
 +
    gpio_set_dir(gpio,0);
 +
    gpio_set_edge(gpio, (char*)"rising");
 +
 +
    // Технический обработчик прерваний.
 +
    int POLL_TIMEOUT = 1000;  /* 1 second */
 +
    size_t POLL_FD_MAX_BUF = 64;    /* fdset read buffer */
 +
 +
    printf("IRQ handler started\n");
 +
 +
    struct pollfd fdset[1];  // Структура параметров функции poll()
 +
 +
    int rc;
 +
    char *buf[POLL_FD_MAX_BUF];
 +
 +
    // Настройка параметров функции poll()
 +
    memset((void*)fdset, 0, sizeof(fdset));
 +
    fdset[0].fd = gpio_fd_open(gpio);
 +
    fdset[0].events = POLLPRI;  // Ожидаем одно событие - прерывание
 +
 +
    prctl(PR_SET_NAME,"recv:IRQ");
 +
 +
    for (;;) {
 +
 +
lseek(fdset[0].fd, 0, SEEK_SET); // Устанавливаем смещение на начало файла
 +
        rc = poll(fdset, 1, POLL_TIMEOUT);  // Здесь происходит ожидание прерывания
 +
 +
 +
        if (rc < 0) {
 +
            printf("IRQ handler: poll() failed!\n");
 +
            return NULL;
 +
        }
 +
 +
        if (rc == 0) {  // IRQ timeout
 +
            printf("IRQ timeout!\n");
 +
        }
 +
 +
        if (fdset[0].revents & POLLPRI) { // Прерывание действительно произошло
 +
        printf("Interrupt!\n");
 +
 +
        if (read(fdset[0].fd, buf, POLL_FD_MAX_BUF) < 0) printf("Interrupt handler problem: %s\n", strerror(errno));
 +
        }
 +
        printf("GPIO_%d: %d\n", gpio, gpio_get_value(gpio));
 +
    }
 +
}</syntaxhighlight>
 +
 +
  
 
----
 
----
 
Ссылка на [http://xgoogle.xilinx.com/search?output=xml_no_dtd&ie=UTF-8&oe=UTF-8&client=support&proxystylesheet=support&site=Answers_Docs&filter=0&resultsView=category&tab=dt&num=1000&sortBy=date&show_dynamic_navigation=1&sort=date%3AD%3AR%3Ad1&documentClass=Document&requiredfields=-Archived%3Atrue&getfields=*&q=+inmeta:Design%2520Tools%3DPetaLinux%2520SDK+inmeta:Document%2520Class%3DDocument+inmeta:Product%2520Type%3DDesign%2520Tools&dnavs=inmeta:Design%2520Tools%3DPetaLinux%2520SDK+inmeta:Document%2520Class%3DDocument+inmeta:Product%2520Type%3DDesign%2520Tools гайды] и [http://www.wiki.xilinx.com вики]
 
Ссылка на [http://xgoogle.xilinx.com/search?output=xml_no_dtd&ie=UTF-8&oe=UTF-8&client=support&proxystylesheet=support&site=Answers_Docs&filter=0&resultsView=category&tab=dt&num=1000&sortBy=date&show_dynamic_navigation=1&sort=date%3AD%3AR%3Ad1&documentClass=Document&requiredfields=-Archived%3Atrue&getfields=*&q=+inmeta:Design%2520Tools%3DPetaLinux%2520SDK+inmeta:Document%2520Class%3DDocument+inmeta:Product%2520Type%3DDesign%2520Tools&dnavs=inmeta:Design%2520Tools%3DPetaLinux%2520SDK+inmeta:Document%2520Class%3DDocument+inmeta:Product%2520Type%3DDesign%2520Tools гайды] и [http://www.wiki.xilinx.com вики]
  
[[Категория:HOWTO]]
+
 
 +
== Использование связки GDB/GDBSERVER ==
 +
 
 +
Описано [https://gist.github.com/plesiv/4bb88a175c86b119f8c7 тут].
 +
 
 +
[[Категория:HOWTO]] [[Категория:Zynq]] [[Категория:EmbeddedLinux]]
  
 
{{wl-publish: 2014-06-24 16:13:30 +0400 | Ustinov }}
 
{{wl-publish: 2014-06-24 16:13:30 +0400 | Ustinov }}

Текущая версия на 15:08, 9 июня 2018

ZYNQ ZC702.jpg


Содержание

[править] Boot Modes

Ошибка создания миниатюры: convert: unable to open image `/app/images/c/c7/___sw16.jpg': No such file or directory @ error/blob.c/OpenBlob/2641.
convert: no images defined `/tmp/transform_6ebe0c6b40eb-1.jpg' @ error/convert.c/ConvertImageCommand/3044.


[править] Запуск Linux с карты памяти

Готовые релизы Linux можно найти по данной ссылке. Выберем релиз 2014.2, т.к. он основа на ядре 3.14, к которому применим preempt_rt патч. Распаковываем архив:

tar xvJf 2014.2-release.tar.xz

Подготавливаем карту памяти как в этой статье. Из скачанного архива 2014.2-release.tar.xz на карту памяти копируем следующие файлы:

  • boot.bin
  • uImage
  • devicetree.dtb
  • uramdisk.image.gz

Карточку вставляем в ZYNQ, джамперы (SW16) выставляем в комбинацию 00110, что выглядит как:

SD boot mode

На компе запускаем скрипт:

#!/usr/bin/kermit
set line /dev/ttyUSB0
set FLOW none
set speed 115200
set serial 8n1
SET CARRIER-WATCH Off
connect

Включаем плату и видим загрузку Linux. Для логина используем Username & Password: root.


[править] Прошиваем Linux в QSPI Flash

После загрузки Linux с карты памяти, примонтируем её:

mount /dev/mmcblk0p1 /mnt

Далее вводим команду:

cat /proc/mtd

Видим следующее:

ZYNQ mtd.png

mtd0 отведен для boot.bin

mtd1 отведен для uImage

mtd2 отведен для devicetree.dtb

mtd3 отведен для uramdisk.image.gz

Соответственно, переходим в подмантированную папку /mnt и вводим следующие команды для записи:

flashcp -v boot.bin /dev/mtd0
flashcp -v uImage /dev/mtd1
flashcp -v devicetree.dtb /dev/mtd2
flashcp -v uramdisk.image.gz /dev/mtd3

Чтобы грузиться с QSPI Flash необходимо переключить джамперы (SW16) в комбинацию 00010.


[править] Модификация FS

  • Изменения FS скачанного выше релиза.

Необходимо развернуть образ FS из "обертки" u-boot. Для этого следует пропустить первые 64 байта:

dd if=uramdisk.image.gz bs=64 skip=1 of=ramdisk.image.gz

Теперь разархивируем полученный архив в папку:

mkdir ./tmp_mnt/
gunzip -c ramdisk.image.gz | sudo sh -c 'cd ./tmp_mnt/ && cpio -i'
cd ./tmp_mnt

Далее выполняем нужные изменения и снова запечатываем в архив:

sh -c 'cd ./tmp_mnt/ && sudo find . | sudo cpio -H newc -o' | gzip -9 > new_initramfs.cpio.gz

Теперь необходимо образ "завернуть" в u-boot:

mkimage -A arm -T ramdisk -C gzip -d new_initramfs.cpio.gz uramdisk.image.gz

Образ готов для загрузки как с SD, так и с QSPI Flash.

  • Модификация стандартной FS

Качаем образ FS по-умолчанию: RamDisk. Распаковываем его:

gunzip ramdisk.image.gz

Монтируем распакованное содержимое:

chmod u+rwx ramdisk.image
mkdir tmp_mnt/
sudo mount -o loop ramdisk.image tmp_mnt/
cd tmp_mnt/

Делаем нужные изменения. Размонтируем и запаковываем:

sudo umount tmp_mnt/
gzip ramdisk.image

Соответственно, для загрузки в железку данный образ должен быть "обернут" в U-Boot:

mkimage -A arm -T ramdisk -C gzip -d ramdisk.image.gz uramdisk.image.gz

Кроме того, можно создать изначально пустой образ и затем уже заполнять его файлами, как описано выше:

dd if=/dev/zero of=ramdisk.image bs=1024 count=8192
mke2fs -F ramdisk.image -L "ramdisk" -b 1024 -m 0
tune2fs ramdisk.image -i 0
chmod a+rwx ramdisk.image

[править] Установка PetaLinux SDK

Заходим тык. Качаем PetaLinux 2014.2 Installation archive for Zynq and MicroBlaze для релиза 2014.2.

Переходим в папку, куда закачали, там выполняем:

./petalinux-v2014.2-final-installer.run <путь установки>

После установки запускаем скрипт:

source <путь, куда устанавливали>/settings.sh

Проверяем, сработал ли скрипт:

echo $PETALINUX

Выключаем отправку статистики на сервера Xilinx:

petalinux-util --webtalk off


[править] Беспарольный доступ

Настройки, аналогичны этому примеру, за исключением некоторых но. Dropbear при старте платы всегда генерирует новые ключи, потому как грузится Linux из RAM. Соответвенно, забираем их из /etc/dropbear/ себе на комп. По вышеописанной инструкции модификации FS вносим эти файлы в /etc/dropbear/ и создаем в /home/root/.ssh файл authorized_keys. В него вносим содержимое нашего открытого ключа.

Устанавливаем все права как:

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

chmod 700 ./home/root
chmod 700 ./home/root/.ssh
chmod 600 ./home/root/.ssh/authorized_keys

Собираем FS и грузимся со всеми нашими модификациями.


[править] Компиляция исходников

Необходимо установить ISE, есть на сервере. Далее по окончании установки и каждый раз при открытии новой консоли необходимо устанавливать параметры среды $PATH, запуская скрипт:

source <путь установки ISE>/14.7/ISE_DC/settings64.sh

После этого уже можно стандартно использовать компилятор. Для ZYNQ zc702 он называется arm-xilinx-linux-gnueabi-gcc, ну или arm-xilinx-linux-gnueabi-g++.


[править] Функции чтения и записи в регистры

Литература: Техническое справочное руководство, схема.

Адреса регистров описаны в техническом руководстве, B.28 (с. 1554).

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/mman.h>

#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
  __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)


#define MAP_SIZE                        4096UL
#define MAP_MASK                        (MAP_SIZE - 1)
#define BASE_ADDRESS                    0xF8000000

#define SET_AS_GPIO                     0x1200
#define SET_UNLOCK                      0xDF0D
#define SLCR_UNLOCK                     0x8
#define MIO_PIN_8                       0x720
#define MIO_PIN_10                      0x728

/*Чтение регистров по адресу*/
void register_read(unsigned long addr)
{
        int fd;
        void *map_base, *virt_addr;
        unsigned long read_result;
        if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
        fflush(stdout);
        /* Map one page */
        map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, BASE_ADDRESS & ~MAP_MASK);
        if(map_base == (void *) -1) FATAL;
        fflush(stdout);
        virt_addr = map_base + ((BASE_ADDRESS + addr) & MAP_MASK);
        read_result = *((unsigned long *) virt_addr);
        printf("0x%08X r: 0x%X\n", addr, read_result);
        fflush(stdout);
}

/*Запись в регистр по адресу*/
void register_write(unsigned long addr, unsigned long writeval)
{
        int fd;
        void *map_base, *virt_addr;
        unsigned long read_result;
        if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
        // printf("/dev/mem opened.\n");
        fflush(stdout);
        /* Map one page */
        map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, BASE_ADDRESS & ~MAP_MASK);
        if(map_base == (void *) -1) FATAL;
        // printf("Memory mapped at address %p.\n", map_base);
        fflush(stdout);
        virt_addr = map_base + ((BASE_ADDRESS + addr) & MAP_MASK);
        *((unsigned long *) virt_addr) = writeval;
        read_result = *((unsigned long *) virt_addr);
        printf("0x%08X w: 0x%X\n", addr, read_result);
}


int main (void)
{      
        /*Изначально, при загрузке, MIO_PIN_8 (на нём висит диод DS12) не сконфигурирован для GPIO, исправим это.*/
        register_write(SLCR_UNLOCK, SET_UNLOCK); // Необходимый анлок регистров
        register_read(MIO_PIN_8); // Считываем начальное значение регистра
        register_write(MIO_PIN_8, SET_AS_GPIO); // Записываем новое значение
        register_read(MIO_PIN_8); // Считываем новое значение регистра
}

[править] Управление GPIO

Функции управления GPIO такие же как и для Impal'ы в CPU.cpp (на всякий случай копирну):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/mman.h>

#define SYSFS_GPIO_DIR "/sys/class/gpio"

/* Включение режима GPIO по номеру */
int gpio_export(unsigned int gpio)
{

        FILE *fid;
        fid = fopen(SYSFS_GPIO_DIR "/export", "w");
        if (fid == NULL) printf("fopen: %s\n", strerror(errno));
        if (fprintf(fid, "%d", gpio) <= 0)
          printf("fprintf: %s\n", strerror(errno));
        fclose(fid);

    return 0;
}

/* Настройка направления GPIO по номеру */
int gpio_set_dir(unsigned int gpio, unsigned int out_flag)
{

        FILE *fid;
        char filename[40];
        sprintf(filename, SYSFS_GPIO_DIR "/gpio%d/direction", gpio);

        fid = fopen(filename, "w");
        if (fid == NULL) printf("fopen %s: %s\n", filename, strerror(errno));
        if (out_flag) {
          if (fprintf(fid, "out") <= 0)
            printf("fprintf: %s\n", strerror(errno));
        } else {
          if (fprintf(fid, "in") <= 0)
            printf("fprintf: %s\n", strerror(errno));
        }
        fclose(fid);

    return 0;
}

/* Установка значение GPIO по номеру */
int gpio_set_value(unsigned int gpio, unsigned int value)
{

        FILE *fid;
        char filename[40];
        sprintf(filename, SYSFS_GPIO_DIR "/gpio%d/value", gpio);

        fid = fopen(filename, "w");
        if (fid == NULL) printf("fopen: %s\n", strerror(errno));

        if (value == 1) {
          if (fprintf(fid, "1") <= 0)
            printf("fprintf: %s\n", strerror(errno));
        } else {
          if (fprintf(fid, "0") <= 0)
            printf("fprintf: %s\n", strerror(errno));
        }
        fclose(fid);

    return 0;
}

/* Чтение значения из GPIO по номеру */
int gpio_get_value(unsigned int gpio)
{

        FILE *fid;
        char filename[40];
        int value;
        sprintf(filename, SYSFS_GPIO_DIR "/gpio%d/value", gpio);

        fid = fopen(filename, "r");
        if (fid == NULL) printf("fopen: %s\n", strerror(errno));

        if (fscanf(fid, "%1d", &value) <= 0)
          printf("gpio_get_value failed: %s\n", strerror(errno));

        fclose(fid);

        if (value == 0)
          return 0;
        else
          return 1;

    return 0;
}

/* Настройка фронта срабатывания GPIO по номеру */
int gpio_set_edge(unsigned int gpio, char *edge)
{
        FILE *fid;
        char filename[40];
        sprintf(filename, SYSFS_GPIO_DIR "/gpio%d/edge", gpio);

        fid = fopen(filename, "w");
        if (fid == NULL) printf("fopen %s: %s\n", filename, strerror(errno));

        if (fprintf(fid, "%s", edge) <= 0)
          printf("fprintf: %s\n", strerror(errno));
        fclose(fid);

    return 0;
}

/* Открывает файл, соответствующий GPIO, по номеру */
int gpio_fd_open(unsigned int gpio)
{
        int fd;
        char buf[MAX_BUF];

        snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);

        fd = open(buf, O_RDONLY | O_NONBLOCK );
        if (fd < 0) {
            perror("gpio/fd_open");
        }
        return fd;

}

int main (void)
{
        /* Программа поочередного мигания диодами DS23 и DS12*/
        register_write(SLCR_UNLOCK, SET_UNLOCK);
        register_read(MIO_PIN_8);
        register_write(MIO_PIN_8, SET_AS_GPIO);
        register_read(MIO_PIN_8);

        gpio_export(10);
        gpio_set_dir(10, 1);
        gpio_export(8);
        gpio_set_dir(8, 1);
        for (;;){
                gpio_set_value(10, 0);
                printf("10: %d\n",gpio_get_value(10));
                gpio_set_value(8, 1);
                printf("8: %d\n",gpio_get_value(8));
                sleep(1);
                gpio_set_value(10, 1);
                printf("10: %d\n",gpio_get_value(10));
                gpio_set_value(8, 0);
                printf("8: %d\n",gpio_get_value(8));
                sleep(1);
                }


}

[править] GPIO Interrupts

Пример кода обработки прерывания по ноге GPIO 14, на ней сидит кнопка SW13.

// Добавлена куча ашников, взятых из кода Impal´ы, наверняка нужны не все...
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/mman.h>
#include <poll.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <semaphore.h>
#include <pthread.h>
#include <sched.h>
#include <time.h>
#include <sys/prctl.h>
#include <math.h>
#include <sys/types.h>

//Необходимо добавить нужные функции из предыдущих глав.

int main (void)
{
    int gpio = 14;

    gpio_export(gpio);
    gpio_set_dir(gpio,0);
    gpio_set_edge(gpio, (char*)"rising");

    // Технический обработчик прерваний.
    int POLL_TIMEOUT = 1000;   /* 1 second */
    size_t POLL_FD_MAX_BUF = 64;    /* fdset read buffer */

    printf("IRQ handler started\n");

    struct pollfd fdset[1];   // Структура параметров функции poll()

    int rc;
    char *buf[POLL_FD_MAX_BUF];

    // Настройка параметров функции poll()
    memset((void*)fdset, 0, sizeof(fdset));
    fdset[0].fd = gpio_fd_open(gpio);
    fdset[0].events = POLLPRI;  // Ожидаем одно событие - прерывание

    prctl(PR_SET_NAME,"recv:IRQ");

    for (;;) {

        lseek(fdset[0].fd, 0, SEEK_SET); // Устанавливаем смещение на начало файла
        rc = poll(fdset, 1, POLL_TIMEOUT);  // Здесь происходит ожидание прерывания


        if (rc < 0) {
            printf("IRQ handler: poll() failed!\n");
            return NULL;
        }

        if (rc == 0) {  // IRQ timeout
            printf("IRQ timeout!\n");
        }

        if (fdset[0].revents & POLLPRI) { // Прерывание действительно произошло
                printf("Interrupt!\n");

                if (read(fdset[0].fd, buf, POLL_FD_MAX_BUF) < 0) printf("Interrupt handler problem: %s\n", strerror(errno));
        }
        printf("GPIO_%d: %d\n", gpio, gpio_get_value(gpio));
    }
}



Ссылка на гайды и вики


[править] Использование связки GDB/GDBSERVER

Описано тут.

[ Хронологический вид ]Комментарии

(нет элементов)

Войдите, чтобы комментировать.

Персональные инструменты
Пространства имён

Варианты
Действия
SRNS Wiki
Рабочие журналы
Приватный файлсервер
QNAP Сервер
Инструменты