Configure/Create OcPoC

This page details the process of creating a new OcPoC Project from scratch.

Requirements

  • Xilinx Vivado‡
  • Xilinx SDK‡
  • Linux-Xlnx‡
  • U-Boot-Xlnx‡
  • Device-Tree-Xlnx‡

v2015.4 or newer, items suffixed with Xlnx can be cloned from Xilinx's Github. All items need to be the same version.

Creating a default OcPoC Project

  1. Open Vivado
  2. Create a new Project in Vivado, select RTL Project
  3. Do not specify any files to import, but create a pin_constr file
  4. For Default Part, search for and select xc7z010clg400-1
  • You will now have a basic project
  1. Select Create Block Design, name it armps
  2. In the diagram space, click the 'add IP' button, add a ZYNQ7 Processing System

Setting up the ARMPS

  1. Double Click on the newly created ZYNQ7 Processing System IP core, to open the configuration window.

  2. Select PS-PL Configuration, open the dropdown for AXI non-secure enablement, open GP Master AXI interface, select M AXI GPO Interface

  3. Select Peripheral I/O Pins, Check the following boxes, and change the accompanying settings:
    //: # (No touchy the pin chart!)
    | Section | Subsection | Peripheral IO Pins |
    | --- | --- | --- |
    |Quad Spi Flash | | 1-6 |
    |Ethernet 0 | | 16-27 |
    |USB 0 | | 28-39 |
    |SD 0 | | 40-45 |
    |SPI 0 | | EMIO |
    |SPI 1 | | EMIO |
    |UART 0 | | EMIO |
    |UART 1 | | 48,49 |
    |I2C 0 | | EMIO |
    |I2C 1 | | EMIO |
    |CAN 0 | | EMIO |
    |GPIO MIO | | 0, 7-15, 47, 50, 51 |
    |GPIO MIO |USB PHY Reset |46 |
    |GPIO EMIO | | EMIO |

  4. Select Clock Configuration on the Left pane, open Processor Memory Clocks, set the following:
    //: # (No touchy mah chart!)
    | Component | Clock Source | Requested Frequency(MHz) |
    |--- |--- |--- |
    |CPU |ARM PLL |667 |
    |DDR |DDR PLL |534 |

  5. Open IO Peripheral Clocks, set the following:
    //: # (No touchy mah chart!)
    | Component | Clock Source | Requested Frequency(MHz) |
    |--- |--- |--- |
    |SMC |IO PLL |100 |
    |QSPI |IO PLL |200 |
    |ENET 0 |IO PLL |1000 Mbps |
    |ENET 1 |IO PLL |1000 Mbps |
    |SDIO |IO PLL |100 |
    |SPI |IO PLL |166.667 |
    |CAN |IO PLL |100 |

  6. Open PL Fabric Clocks, set the following:
    //: # (No touchy mah chart!)
    | Component | Clock Source | Requested Frequency(MHz) |
    |--- |--- |--- |
    |FC_CLK0 |IO PLL |100 |
    |FC_CLK0 |IO PLL |50 |

  7. Open DDR Configuration

NameSelect
Memory TypeDDR3
Memory PartMT41J128M16 HA-15E
Effective DRAM Bus Width32 Bit
Burst Length8
DDR534
Internal Vref
  1. Open Interrupts, Open the Fabric Interrupts submenu, Open the PL-PS Interrupt Ports, check the box for IRQ_F2P
  2. Return to the block diagram, and add interface ports to the following:
  • DDR
  • FIXED_IO
  • UART_PS_0
  • IIC_PS_0
  • IIC_PS_1
  • SPI_PS_0
  • SPI _PS_1
  • CAN_PS_0

Adding the remaining IP cores

  1. In the block diagram add an AXI interconnect IP core
  2. If adding the following IP, run connection Automation, select the 50 MHz clock These IP must operate at 50 MHz:
  • AXI_OCPOC_PWM
  • RC_RECEIVER_INPUT
  1. If adding the following IP, run connection automation and select the 100 MHz clock (Settings, accessed by double clicking the IP core):
  • 8 AXI_UART16550
    • 16550
    • ▢ Use External CLK for BAUD rate
    • ▢ Enable External Receiver CLK
  • 4 AXI_I2C
    • SCL Clock Frequency - 100
    • Address Mode - 7 bits
    • SCL Inertial Delay - 30
    • SDA Inertial Delay - 5
    • Active State of SDA - 1
    • General Purpose Output Width - 1
    • Default GPO Port Output Value - 0x00
  • 1 XADC_WIZ
  • 1 xlconcat
  • 2 xlconstant (set the value in one to 0 and one set to 1)
  1. Connect all the UART and I2C interrupts to the xlconcat - The xlconcat IP can handle up to 16 signals, but users will need to modify it manually in the IP core settings. The default project requires 12 interrupts, however it's recommended that you use only as many as necessary.
  2. Expand all the UART output, Connect all the CTSN and RIN to the xlconstant with the value of 0 in it. Repeat with DCDN & DSRN, and set to 1
  3. Create interface ports for all the I2C, UART, PWM, and RC_RECEIVER

Wrapping the Block Diagram

In the Sources Window, right click on block diagram - if you followed the DEFAULT PROJECT, it'll be armps. Right-click on the block diagram and select Create HDL Wrapper.

Double wrapping the Block Diagram

This section is currently required for users using SBUS communication, if not sure, then do this part as well.

For the default build, create a new verilog source based on APPENDIX A

That block of code effectively creates a module of the previous wrapper block design, and inverts the RX line of the SBUS serial line. At the time of writing, it wasn't possible to isolate the RX line of a serial IP without a wrapper.

If you're already familiar with verilog, then it should be fairly straight forward. The parts of interest are:

input sbus_in

wire sbus_rx;
wire sbus_tx;
assign sbus_rx = ~sbus_in;

.UART_PL_0_baudoutn()
.UART_PL_0_ddis(),
.UART_PL_0_dtrn(),
.UART_PL_0_out1n(),
.UART_PL_0_out2n(),
.UART_PL_0_rtsn(),
.UART_PL_0_rxd(sbus_rx),
.UART_PL_0_rxrdyn(),
.UART_PL_0_txd(sbus_tx),
.UART_PL_0_txrdyn(),

which invert the SBUS line on a given (UART_PL_0 IP in our case) IP interface port.

Assigning Pins

In the pin_constr you'll use TCL commands to assign pins in a fashion like:

set_property PACKAGE_PIN H18 [get_ports CAN_PS_0_rx]
set_property IOSTANDARD LVCMOS33 [get_ports CAN_PS_0_rx]

on the I2C lines also be sure to include something like:

set_property PULLUP true [get_ports IIC_PL_1_scl_io]

The full list of pins is in APPENDIX B

Assigning Addresses

Open the block diagram again. Select the Address Editor in the main workspace. Edit it to reflect the following:

CellOffset Address
axi_iic_00x416_00000
xadc_wiz_00x43C5_00000
axi_iic_10x4161_0000
axi_iic_20x4162_0000
axi_iic_30x4163_0000
AXI_OcPoC_PWM_Controller_00x43C0_0000
RC_Receiver_Input_00x43CA_0000
axi_uart_16550_00x43C1_0000
axi_uart_16550_10x43C2_0000
axi_uart_16550_20x43C3_0000
axi_uart_16550_30x43C4_0000
axi_uart_16550_40x43C6_0000
axi_uart_16550_50x43C7_0000
axi_uart_16550_60x43C8_0000
axi_uart_16550_70x43C9_0000

Implementation, Synthesis and Exporting the Bitstream

  1. Make sure all your sources - including your block diagram are saved.
  2. Click the Start Implementation in the Flow Navigator
  • There may be a prompt that you need to complete synthesis, click Yes or Ok
  1. Once Synthesis and Implementation are complete, write the bitstream
  2. Export the Hardware, Bitstream, and Launch Xilinx SDK

Appendix A: Second Wrapper

`timescale 1 ps / 1 ps

module ocpoc_top
(   input CAN_PS_0_rx,
    output CAN_PS_0_tx,
    input pulse_train_in,
    input Vaux15_v_n,
    input Vaux15_v_p,
    inout [14:0]DDR_addr,
    inout [2:0]DDR_ba,
    inout DDR_cas_n,
    inout DDR_ck_n,
    inout DDR_ck_p,
    inout DDR_cke,
    inout DDR_cs_n,
    inout [3:0]DDR_dm,
    inout [31:0]DDR_dq,
    inout [3:0]DDR_dqs_n,
    inout [3:0]DDR_dqs_p,
    inout DDR_odt,
    inout DDR_ras_n,
    inout DDR_reset_n,
    inout DDR_we_n,
    inout FIXED_IO_ddr_vrn,
    inout FIXED_IO_ddr_vrp,
    inout [53:0]FIXED_IO_mio,
    inout FIXED_IO_ps_clk,
    inout FIXED_IO_ps_porb,
    inout FIXED_IO_ps_srstb,
    inout IIC_PS_0_scl_io,
    inout IIC_PS_0_sda_io,
    inout IIC_PS_1_scl_io,
    inout IIC_PS_1_sda_io,    
    inout IIC_PL_1_scl_io,
    inout IIC_PL_1_sda_io,
    inout IIC_PL_2_scl_io,
    inout IIC_PL_2_sda_io,
    inout IIC_PL_3_scl_io,
    inout IIC_PL_3_sda_io,
    input UART_PS_0_rxd,
    output UART_PS_0_txd,
    input UART_PL_1_rxd,
    output UART_PL_1_txd,
    input UART_PL_2_rxd,
    output UART_PL_2_txd,
    input UART_PL_3_rxd,
    output UART_PL_3_txd,
    input UART_PL_4_rxd,
    output UART_PL_4_txd,
    input UART_PL_5_rxd,
    output UART_PL_5_txd,
    input UART_PL_6_rxd,
    output UART_PL_6_txd,
    input UART_PL_7_rxd,
    output UART_PL_7_txd,
    output pwm_0,
    output pwm_1,
    output pwm_2,
    output pwm_3,
    output pwm_4,
    output pwm_5,
    output pwm_6,
    output pwm_7,
    output pwm_8,
    output pwm_9,
    output pwm_10,
    output pwm_11,
    inout SPI_PS_0_io0_io,
    inout SPI_PS_0_io1_io,
    inout SPI_PS_0_sck_io,
    output SPI_PS_0_ss1_o,
    output SPI_PS_0_ss2_o,
    inout SPI_PS_0_ss_io,
    inout SPI_PS_1_io0_io,
    inout SPI_PS_1_io1_io,
    inout SPI_PS_1_sck_io,
    inout SPI_PS_1_ss_io,
    input sbus_in
);
wire sbus_rx;
wire sbus_tx;
assign sbus_rx = ~sbus_in;
armps_wrapper  armps_wrapper_i
(    .CAN_PS_0_rx( CAN_PS_0_rx ),
     .CAN_PS_0_tx( CAN_PS_0_tx ),
     .DDR_addr( DDR_addr ),
     .DDR_ba( DDR_ba ),
     .DDR_cas_n(  DDR_cas_n),
     .DDR_ck_n( DDR_ck_n ),
     .DDR_ck_p( DDR_ck_p ),
     .DDR_cke( DDR_cke ),
     .DDR_cs_n( DDR_cs_n ),
     .DDR_dm(  DDR_dm),
     .DDR_dq( DDR_dq),
     .DDR_dqs_n(DDR_dqs_n  ),
     .DDR_dqs_p( DDR_dqs_p ),
     .DDR_odt(DDR_odt  ),
     .DDR_ras_n(DDR_ras_n  ),
     .DDR_reset_n( DDR_reset_n ),
     .DDR_we_n(DDR_we_n  ),
     .FIXED_IO_ddr_vrn(  FIXED_IO_ddr_vrn),
     .FIXED_IO_ddr_vrp( FIXED_IO_ddr_vrp ),
     .FIXED_IO_mio( FIXED_IO_mio ),
     .FIXED_IO_ps_clk( FIXED_IO_ps_clk ),
     .FIXED_IO_ps_porb( FIXED_IO_ps_porb ),
     .FIXED_IO_ps_srstb(  FIXED_IO_ps_srstb),
     .iic_pl_0_scl_io(),
     .iic_pl_0_sda_io(),
     .iic_pl_1_scl_io(IIC_PL_1_scl_io),
     .iic_pl_1_sda_io(IIC_PL_1_sda_io),
     .iic_pl_2_scl_io(IIC_PL_2_scl_io),
     .iic_pl_2_sda_io(IIC_PL_2_sda_io),
     .iic_pl_3_scl_io(IIC_PL_3_scl_io),
     .iic_pl_3_sda_io(IIC_PL_3_sda_io),
     .iic_ps_0_scl_io(IIC_PS_0_scl_io),
     .iic_ps_0_sda_io(IIC_PS_0_sda_io),
     .iic_ps_1_scl_io(IIC_PS_1_scl_io),
     .iic_ps_1_sda_io(IIC_PS_1_sda_io),
     .pwm_0(pwm_0  ),
     .pwm_1( pwm_1 ),
     .pwm_2(pwm_2  ),
     .pwm_3(  pwm_3),
     .pwm_4( pwm_4 ),
     .pwm_5( pwm_5 ),
     .pwm_6(  pwm_6),
     .pwm_7( pwm_7 ),
     .pwm_8(pwm_8),
     .spi_ps_0_io0_io( SPI_PS_0_io0_io ),
     .spi_ps_0_io1_io(  SPI_PS_0_io1_io),
     .spi_ps_0_sck_io( SPI_PS_0_sck_io ),
     .spi_ps_0_ss1_o( SPI_PS_0_ss1_o ),
     .spi_ps_0_ss2_o( SPI_PS_0_ss2_o ),
     .spi_ps_0_ss_io( SPI_PS_0_ss_io ),
     .spi_ps_1_io0_io(SPI_PS_1_io0_io  ),
     .spi_ps_1_io1_io( SPI_PS_1_io1_io ),
     .spi_ps_1_sck_io( SPI_PS_1_sck_io ),
     .spi_ps_1_ss_io( SPI_PS_1_ss_io ),
     .UART_PS_0_rxd(UART_PS_0_rxd),
     .UART_PS_0_txd(UART_PS_0_txd),
     .UART_PL_0_baudoutn(),
     .UART_PL_0_ddis(),
     .UART_PL_0_dtrn(),
     .UART_PL_0_out1n(),
     .UART_PL_0_out2n(),
     .UART_PL_0_rtsn(),
     .UART_PL_0_rxd(sbus_rx),
     .UART_PL_0_rxrdyn(),
     .UART_PL_0_txd(sbus_tx),
     .UART_PL_0_txrdyn(),
     .UART_PL_1_baudoutn(),
     .UART_PL_1_ddis(),
     .UART_PL_1_dtrn(),
     .UART_PL_1_out1n(),
     .UART_PL_1_out2n(),
     .UART_PL_1_rtsn(),
     .UART_PL_1_rxd(UART_PL_1_rxd),
     .UART_PL_1_rxrdyn(),
     .UART_PL_1_txd(UART_PL_1_txd),
     .UART_PL_1_txrdyn(),
     .UART_PL_2_baudoutn(),
     .UART_PL_2_ddis(),
     .UART_PL_2_dtrn(),
     .UART_PL_2_out1n(),
     .UART_PL_2_out2n(),
     .UART_PL_2_rtsn(),
     .UART_PL_2_rxd(UART_PL_2_rxd),
     .UART_PL_2_rxrdyn(),
     .UART_PL_2_txd(UART_PL_2_txd),
     .UART_PL_2_txrdyn(),
     .UART_PL_3_baudoutn(),
     .UART_PL_3_ddis(),
     .UART_PL_3_dtrn(),
     .UART_PL_3_out1n(),
     .UART_PL_3_out2n(),
     .UART_PL_3_rtsn(),
     .UART_PL_3_rxd(UART_PL_3_rxd),
     .UART_PL_3_rxrdyn(),
     .UART_PL_3_txd(UART_PL_3_txd),
     .UART_PL_3_txrdyn(),
     .UART_PL_4_baudoutn(),
     .UART_PL_4_ddis(),
     .UART_PL_4_dtrn(),
     .UART_PL_4_out1n(),
     .UART_PL_4_out2n(),
     .UART_PL_4_rtsn(),
     .UART_PL_4_rxd(UART_PL_4_rxd),
     .UART_PL_4_rxrdyn(),
     .UART_PL_4_txd(UART_PL_4_txd),
     .UART_PL_4_txrdyn(),
     .UART_PL_5_baudoutn(),
     .UART_PL_5_ddis(),
     .UART_PL_5_dtrn(),
     .UART_PL_5_out1n(),
     .UART_PL_5_out2n(),
     .UART_PL_5_rtsn(),
     .UART_PL_5_rxd(UART_PL_5_rxd),
     .UART_PL_5_rxrdyn(),
     .UART_PL_5_txd(UART_PL_5_txd),
     .UART_PL_5_txrdyn(),
     .UART_PL_6_baudoutn(),
     .UART_PL_6_ddis(),
     .UART_PL_6_dtrn(),
     .UART_PL_6_out1n(),
     .UART_PL_6_out2n(),
     .UART_PL_6_rtsn(),
     .UART_PL_6_rxd(UART_PL_6_rxd),
     .UART_PL_6_rxrdyn(),
     .UART_PL_6_txd(UART_PL_6_txd),
     .UART_PL_6_txrdyn(),
     .UART_PL_7_baudoutn(),
     .UART_PL_7_ddis(),
     .UART_PL_7_dtrn(),
     .UART_PL_7_out1n(),
     .UART_PL_7_out2n(),
     .UART_PL_7_rtsn(),
     .UART_PL_7_rxd(UART_PL_7_rxd),
     .UART_PL_7_rxrdyn(),
     .UART_PL_7_txd(UART_PL_7_txd),
     .UART_PL_7_txrdyn(),
     .pulse_train_in(pulse_train_in),
     .Vaux15_v_n(Vaux15_v_n),
     .Vaux15_v_p(Vaux15_v_p));
endmodule

Appendix B: FPGA Pin Information

FPGA PinLocationVivado FunctionNotes
R17Pin 15pulse_train_inPPM; Programmable
L16USB UARTUART_PS_0_rxd/dev/ttyPS1; Telemetry; Programmable
L17USB UARTUART_PS_0_txd/dev/ttyPS1; Telemetry; Programmable
F16Port 1UART_PL_4_rxd/dev/ttyS4; Programmable
G18Port 1UART_PL_4_txd/dev/ttyS4; Programmable
E19Tricolor LED I2C Clock LineIIC_PS_1_scl_io/dev/i2c-1; Recommend to leave alone
F19Tricolor LED I2C Data LineIIC_PS_1_sda_io/dev/i2c-1; Recommend to leave alone
L19Onboard SPI Bus to IMUs and BaroSPI_PS_0_io0_ioRecommend to leave alone
L20Onboard SPI Bus to IMUs and BaroSPI_PS_0_io1_ioRecommend to leave alone
L15Onboard SPI Bus to IMUs and BaroSPI_PS_0_sck_ioRecommend to leave alone
D19Onboard SPI Chip Select to IMUSPI_PS_0_ss_io/dev/spidev1.0; Recommend to leave alone
A20Onboard SPI Chip Select to BaroSPI_PS_0_ss1_o/dev/spidev1.1; Recommend to leave alone
H17Onboard SPI Chip Select to IMUPI_PS_0_ss2_o/dev/spidev1.0; Recommend to leave alone
D18Unlabeled Port Next to SD card slotSPI_PS_1_io0_io/dev/spidev2.0; Programmable
E18Unlabeled Port Next to SD card slotSPI_PS_1_io1_io/dev/spidev2.0; Programmable
E17Unlabeled Port Next to SD card slotSPI_PS_1_sck_io/dev/spidev2.0; Programmable
F17Unlabeled Port Next to SD card slotSPI_PS_1_ss_io/dev/spidev2.0; Programmable
C20Port 3CAN_PS_0_rxRecommend to leave alone
H18Port 3CAN_PS_0_txRecommend to leave alone
V15Pin 16sbus_in/dev/ttyS2; only an input; Programmable
G17Port 2UART_PL_2_txd/dev/ttyS5; Programmable
H16Port 2UART_PL_2_rxd/dev/ttyS5; Programmable
M15Port 8UART_PL_3_txd/dev/ttyS6; Programmable
M14Port 8UART_PL_3_rxd/dev/ttyS6; Programmable
Y14Pin 13IIC_PS_0_scl_io/dev/i2c-0; Designated for flow device; Programmable
W15Pin 14IIC_PS_0_sda_io/dev/i2c-0; Designated for flow device; Programmable
V18PWM 0 / Pin 0pwm_0Programmable
T19PWM 1 / Pin 1pwm_1Programmable
P15PWM 2 / Pin 2pwm_2Programmable
U18PWM 3 / Pin 3pwm_3Programmable
P16PWM 4 / Pin 4pwm_4Programmable
Y19PWM 5 / Pin 5pwm_5Programmable
W20PWM 6 / Pin 6pwm_6Programmable
W19PWM 7 / Pin 7pwm_7Programmable
Y17PWM 8 / Pin 8pwm_8Programmable
Y16PWM 9 / Pin 9pwm_9Programmable
Y18PWM 10 / Pin 10pwm_10Programmable
W14PWM 11 / Pin 11pwm_11Programmable
J16VoltageVaux15_v_nRecommend to leave alone
K16VoltageVaux15_v_pRecommend to leave alone
K18Port 5UART_PL_1_txd/dev/ttyS0; Programmable
J18Port 5UART_PL_1_rxd/dev/ttyS0; Programmable
N17Port 6IIC_PL_1_scl_io/dev/i2c-4; Programmable
P18Port 6IIC_PL_1_sda_io/dev/i2c-4; Programmable
R18Port 6UART_PL_7_rxd/dev/ttyS3; Programmable
T17Port 6UART_PL_7_txd/dev/ttyS3; Programmable
P19Port 7IIC_PL_2_scl_io/dev/i2c-5; Programmable
T20Port 7IIC_PL_2_sda_io/dev/i2c-5; Programmable
P20Port 7UART_PL_5_rxd/dev/ttyS7; Programmable
R19Port 7UART_PL_5_txd/dev/ttyS7; Programmable
V20Port 9IIC_PL_3_scl_io/dev/i2c-3; Programmable
U20Port 9IIC_PL_3_sda_io/dev/i2c-3; Programmable
U19Port 9UART_PL_6_rxd/dev/ttyS1; Programmable
W16Port 9UART_PL_6_txd/dev/ttyS1; Programmable

What’s Next

After creating your main project and the bit-stream, you will be working in Xilinx SDK. The next immediate step is to create the First Stage Bootloader & Device Tree. Generally, you can get away without having to build the U-boot, but it will be posted for completeness.