Начало статьи читайте тут:
Zynq-7000 SoC — Xilinx. Z-turn Lite. Bare metal. Часть 1.
UART
Сегодня мы начнем с UART. Универсальный асинхронный приёмопередатчик (УАПП, англ. Universal Asynchronous Receiver-Transmitter, UART) — узел вычислительных устройств, предназначенный для организации связи с другими цифровыми устройствами. Преобразует передаваемые данные в последовательный вид так, чтобы было возможно передать их по одной физической цифровой линии другому аналогичному устройству. Метод преобразования хорошо стандартизован и широко применяется в компьютерной технике, особенно во встраиваемых устройствах и системах на кристалле (SoC). Один из самых распространенных интерфейсов на сегодняшний день (“Вечно молодой”). Сегодня будет два простых примера c uart, первый пример – вывод сообщения “Привет мир!” с помощью uart, который находится на ps части нашего soc (“сок”), второй пример – loopback на uart-ах на pl части.
Пример “Привет мир!”
1. Проект в Vivado не отличается от первой части, запускаем sdk и выбираем создать новое приложение для zynq.
2. В шаблонах проектов выбираем шаблон “Hello world”.
3. Компилируем и запускаем следующий код (не забываем загрузить bitstream, без bitstream результат будет неудовлетворительным).
#include <stdio.h> #include "platform.h" #include "xil_printf.h" int main() { init_platform(); print("Hello World\n\r"); cleanup_platform(); return 0; }
Если все сделали правильно, в minicom должна появиться фраза “Hello world” (sudo minicom -D /dev/ttyUSB0, имя tty посмотрите в dmesg, также не забудьте отключить контроль потока).
Пример loopback
Пример loopback – самый распространенный способ проверить корректность программной части. Чтобы сделать петлю для данных, посылаем данные через uart0, принимаем данные через uart1, посылаем данные через uart1, принимаем данные на uart0.
1. Добавляем ip axi uartlite.
2. Добавляем второй ip axi uartlite.
3. Соединяем rx (uart0)-tx (uart1) и tx (uart0)-rx (uart1).
4. В настройках zynq ip необходимо включить поддержку m_axi_gp0.
5. Нажимаем сделать автоматическое подключений линий.
6. Итоговый блок соединенных ip для примера looback.
7. В Vivado делаем экспорт hardware и запускаем SDK. В SDK создаем пустой проект.
8. Добавляем пустой файл с расширением .c и добавляем исходный код ниже. В данном коде есть переменная counter, которая увеличивается при передачи данных через каждый канал tx каждого uart. После передачи данных делаем чтение данных из другого (противоположного) uart.
/* ------------------------------------------------------------ */ /* Include File Definitions */ /* ------------------------------------------------------------ */ #include <stdio.h> #include "xparameters.h" //The hardware configuration describing constant #include "xil_io.h" //Contains the Xil_Out32 and Xil_In32 functions #include "xuartlite_l.h" // #include "xuartps_hw.h" #define uchar unsigned char #define uint unsigned short /* ------------------------------------------------------------ */ /* main function */ /* ------------------------------------------------------------ */ #define UART_1_DEVICE_ID 0xE0001000 char uart1_inbyte(void) { return XUartPs_RecvByte(UART_1_DEVICE_ID); } void uart1_outbyte(char c) { XUartPs_SendByte(UART_1_DEVICE_ID, c); } void print1(const char *ptr) { while (*ptr) { XUartPs_SendByte (UART_1_DEVICE_ID,*ptr++); } } int main() { uchar rxdb; uint8_t counter = 0; XUartLite_SetControlReg(XPAR_UARTLITE_0_BASEADDR,0x10); //enable interrupt XUartLite_SetControlReg(XPAR_UARTLITE_1_BASEADDR,0x10); //enable interrupt while(1) { counter++; XUartLite_SendByte(XPAR_UARTLITE_0_BASEADDR,counter); rxdb = XUartLite_RecvByte(XPAR_UARTLITE_1_BASEADDR); counter++; XUartLite_SendByte(XPAR_UARTLITE_1_BASEADDR,counter); rxdb = XUartLite_RecvByte(XPAR_UARTLITE_0_BASEADDR); } return 0; }
9. В окне отладки нашей программы для loopback для переменной rxdb читаем текущее состояние по приему данных из uart. Как видно из скриншота данные верны.
AXI DMA
Прямой доступ к памяти (англ. direct memory access, DMA) — режим обмена данными между устройствами компьютера или между устройством и основной памятью, в котором центральный процессор (ЦП) не участвует. Так как данные не пересылаются в ЦП и обратно, скорость передачи увеличивается.
1.Разрешаем M AXI GP0 Interface
2. Включаем прерывания для pl части.
3. Добавляем IP axi dma.
4. Настраиваем axi dma, как на картинке.
5. Делаем автоматическое соединение.
6. После автоматического соединения блок схема выглядит следующим образом.
7. Добавляем axi stream data fifo, данные fifo помещаются после передачи со стороны axi dma, после из fifo при чтении из axi dma данные забираются.
8. Добавляем блок конкатенации. Конкатенация – операция склеивания объектов линейной структуры, как правило строк. Например, конкатенация слов «микро» и «мир» даст слово «микромир». В нашем примере склеивание происходит для прерываний.
9. Делаем автоматическое соединение линий и шин для IP на блок-диаграмме. Результат соединения на картинке.
10. Далее создаем проект для SDK, делаем предварительно экспорт hardware, и создаем новый пустой проект.
11. Добавился код BSP для zynq, в файле mss выбираем создать пример для axi dma.
12. После импорта проекта выбираем пример для sg poll, загружаем bitream, компилируем проект и вперед с песней.
13. В консоли должна появится фраза об успешном прохождении теста для axi dma.
14. Генерировать проекты с bsp xilinx достаточно легко, переходим в mss файл выбираем, для чего генерировать проект, импортируем проект, компилируем и заливаем. В целях проверки создадим проект для usb msc класса устройства и запустим данный проект.
15. В dmesg появилось сообщение о том, что к ПК подключен usb msc класс устройства.