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
- Open Vivado
- Create a new Project in Vivado, select RTL Project
- Do not specify any files to import, but create a pin_constr file
- For Default Part, search for and select xc7z010clg400-1
- You will now have a basic project
- Select Create Block Design, name it armps
- In the diagram space, click the 'add IP' button, add a ZYNQ7 Processing System
Setting up the ARMPS
-
Double Click on the newly created ZYNQ7 Processing System IP core, to open the configuration window.
-
Select PS-PL Configuration, open the dropdown for AXI non-secure enablement, open GP Master AXI interface, select M AXI GPO Interface
-
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 | -
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 | -
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 | -
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 | -
Open DDR Configuration
Name | Select |
---|---|
Memory Type | DDR3 |
Memory Part | MT41J128M16 HA-15E |
Effective DRAM Bus Width | 32 Bit |
Burst Length | 8 |
DDR | 534 |
Internal Vref | ▢ |
- Open Interrupts, Open the Fabric Interrupts submenu, Open the PL-PS Interrupt Ports, check the box for IRQ_F2P
- 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
- In the block diagram add an AXI interconnect IP core
- 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
- 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)
- 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.
- 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
- 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:
Cell | Offset Address |
---|---|
axi_iic_0 | 0x416_00000 |
xadc_wiz_0 | 0x43C5_00000 |
axi_iic_1 | 0x4161_0000 |
axi_iic_2 | 0x4162_0000 |
axi_iic_3 | 0x4163_0000 |
AXI_OcPoC_PWM_Controller_0 | 0x43C0_0000 |
RC_Receiver_Input_0 | 0x43CA_0000 |
axi_uart_16550_0 | 0x43C1_0000 |
axi_uart_16550_1 | 0x43C2_0000 |
axi_uart_16550_2 | 0x43C3_0000 |
axi_uart_16550_3 | 0x43C4_0000 |
axi_uart_16550_4 | 0x43C6_0000 |
axi_uart_16550_5 | 0x43C7_0000 |
axi_uart_16550_6 | 0x43C8_0000 |
axi_uart_16550_7 | 0x43C9_0000 |
Implementation, Synthesis and Exporting the Bitstream
- Make sure all your sources - including your block diagram are saved.
- Click the Start Implementation in the Flow Navigator
- There may be a prompt that you need to complete synthesis, click Yes or Ok
- Once Synthesis and Implementation are complete, write the bitstream
- 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 Pin | Location | Vivado Function | Notes |
---|---|---|---|
R17 | Pin 15 | pulse_train_in | PPM; Programmable |
L16 | USB UART | UART_PS_0_rxd | /dev/ttyPS1; Telemetry; Programmable |
L17 | USB UART | UART_PS_0_txd | /dev/ttyPS1; Telemetry; Programmable |
F16 | Port 1 | UART_PL_4_rxd | /dev/ttyS4; Programmable |
G18 | Port 1 | UART_PL_4_txd | /dev/ttyS4; Programmable |
E19 | Tricolor LED I2C Clock Line | IIC_PS_1_scl_io | /dev/i2c-1; Recommend to leave alone |
F19 | Tricolor LED I2C Data Line | IIC_PS_1_sda_io | /dev/i2c-1; Recommend to leave alone |
L19 | Onboard SPI Bus to IMUs and Baro | SPI_PS_0_io0_io | Recommend to leave alone |
L20 | Onboard SPI Bus to IMUs and Baro | SPI_PS_0_io1_io | Recommend to leave alone |
L15 | Onboard SPI Bus to IMUs and Baro | SPI_PS_0_sck_io | Recommend to leave alone |
D19 | Onboard SPI Chip Select to IMU | SPI_PS_0_ss_io | /dev/spidev1.0; Recommend to leave alone |
A20 | Onboard SPI Chip Select to Baro | SPI_PS_0_ss1_o | /dev/spidev1.1; Recommend to leave alone |
H17 | Onboard SPI Chip Select to IMU | PI_PS_0_ss2_o | /dev/spidev1.0; Recommend to leave alone |
D18 | Unlabeled Port Next to SD card slot | SPI_PS_1_io0_io | /dev/spidev2.0; Programmable |
E18 | Unlabeled Port Next to SD card slot | SPI_PS_1_io1_io | /dev/spidev2.0; Programmable |
E17 | Unlabeled Port Next to SD card slot | SPI_PS_1_sck_io | /dev/spidev2.0; Programmable |
F17 | Unlabeled Port Next to SD card slot | SPI_PS_1_ss_io | /dev/spidev2.0; Programmable |
C20 | Port 3 | CAN_PS_0_rx | Recommend to leave alone |
H18 | Port 3 | CAN_PS_0_tx | Recommend to leave alone |
V15 | Pin 16 | sbus_in | /dev/ttyS2; only an input; Programmable |
G17 | Port 2 | UART_PL_2_txd | /dev/ttyS5; Programmable |
H16 | Port 2 | UART_PL_2_rxd | /dev/ttyS5; Programmable |
M15 | Port 8 | UART_PL_3_txd | /dev/ttyS6; Programmable |
M14 | Port 8 | UART_PL_3_rxd | /dev/ttyS6; Programmable |
Y14 | Pin 13 | IIC_PS_0_scl_io | /dev/i2c-0; Designated for flow device; Programmable |
W15 | Pin 14 | IIC_PS_0_sda_io | /dev/i2c-0; Designated for flow device; Programmable |
V18 | PWM 0 / Pin 0 | pwm_0 | Programmable |
T19 | PWM 1 / Pin 1 | pwm_1 | Programmable |
P15 | PWM 2 / Pin 2 | pwm_2 | Programmable |
U18 | PWM 3 / Pin 3 | pwm_3 | Programmable |
P16 | PWM 4 / Pin 4 | pwm_4 | Programmable |
Y19 | PWM 5 / Pin 5 | pwm_5 | Programmable |
W20 | PWM 6 / Pin 6 | pwm_6 | Programmable |
W19 | PWM 7 / Pin 7 | pwm_7 | Programmable |
Y17 | PWM 8 / Pin 8 | pwm_8 | Programmable |
Y16 | PWM 9 / Pin 9 | pwm_9 | Programmable |
Y18 | PWM 10 / Pin 10 | pwm_10 | Programmable |
W14 | PWM 11 / Pin 11 | pwm_11 | Programmable |
J16 | Voltage | Vaux15_v_n | Recommend to leave alone |
K16 | Voltage | Vaux15_v_p | Recommend to leave alone |
K18 | Port 5 | UART_PL_1_txd | /dev/ttyS0; Programmable |
J18 | Port 5 | UART_PL_1_rxd | /dev/ttyS0; Programmable |
N17 | Port 6 | IIC_PL_1_scl_io | /dev/i2c-4; Programmable |
P18 | Port 6 | IIC_PL_1_sda_io | /dev/i2c-4; Programmable |
R18 | Port 6 | UART_PL_7_rxd | /dev/ttyS3; Programmable |
T17 | Port 6 | UART_PL_7_txd | /dev/ttyS3; Programmable |
P19 | Port 7 | IIC_PL_2_scl_io | /dev/i2c-5; Programmable |
T20 | Port 7 | IIC_PL_2_sda_io | /dev/i2c-5; Programmable |
P20 | Port 7 | UART_PL_5_rxd | /dev/ttyS7; Programmable |
R19 | Port 7 | UART_PL_5_txd | /dev/ttyS7; Programmable |
V20 | Port 9 | IIC_PL_3_scl_io | /dev/i2c-3; Programmable |
U20 | Port 9 | IIC_PL_3_sda_io | /dev/i2c-3; Programmable |
U19 | Port 9 | UART_PL_6_rxd | /dev/ttyS1; Programmable |
W16 | Port 9 | UART_PL_6_txd | /dev/ttyS1; Programmable |
Updated over 5 years ago
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.