ZPUino User Guide

The ZPUino is a 32 bit processor running at 100Mhz with a library of Wishbone peripherals. Everything is controlled by a sketch and easy Arduino style libraries. It is an Arduino compatible Soft Processor on steroids!

The ZPUino is the ZPU soft processor adapted for use with the Arduino IDE and it was conceived of and developed by Alvaro Lopes.


Quick Links

Operating Systems

Windows Vista
Windows XP
Windows 7
WIndows 8

Hardware this Guide Applies to:

ZPUino Technical Overview

Attach:zpuino.png Δ What is ZPUino

  • 32 bit soft processor running at 96Mhz.
  • Uses a modified version of the Arduino IDE to load sketches.
  • Wishbone bus for connecting peripherals such as the following:
    • Commodore 64 SID Audio Chip
    • YM2149 Audio Chip
    • POKEY Audion Chip
    • AudioMixer
    • ZX Spectrum VGA
    • HQVGA with 8-bit color
    • UART
    • GPIO
    • SPI
    • I2C
    • SigmaDelta DAC
  • Actively maintained and developed by Alvaro Lopes.
  • To learn more visit: http://www.alvie.com/zpuino or read the technical guide.


Block Diagram


ZPUino System on Chip


Learn more technical details about the ZPUino by reading the ZPUino Technical Reference.


ZPUino System On Chip

The ZPUino is intended to make it easy to make System on Chip FPGA designs by adding Wishbone Peripherals to the ZPUino Wishbone slots. The RetroCade Synth is an example of a ZPUino System on Chip design.

RetroCade Block Diagram

RetroCade Presentation
http://youtu.be/6E-USsejc5o Watch this presentation to learn the nitty gritty details of the RetroCade's internals.

ZPUino Bootloader

The ZPUino uses a bootloader that bootstraps code from SPI Flash into internal Block Ram for the Papilio One and external SDRAM for the Papilio Pro. Every ZPUino variant has a special mode that allows code to be programmed to SPI Flash to be run at the next reset. The ZAP IDE sends a special command at a specific baud rate to trigger the programming mode. After code is loaded to SPI Flash a reset is triggered and the bootloader shadows code from SPI FLash into the appropriate RAM location. This is why a ZPUino variant needs to be loaded to the Papilio board before a sketch is uploaded.

ZPUino Variants

A ZPUino variant is a custom ZPUino System on Chip design that we have pre-synthesized for a specific purpose. It contains all of the Wishbone peripherals that will be useful for a specific task, such as VGA output. A ZPUino variant is normally named after a deity from Greek Mythology which roughly indicates what type of peripherals it includes. For example the Hyperion variant includes the VGA peripheral and is named after Hyperion the "Lord of Light". Check out the ZPUino variant reference page to see all the pre-synthesized ZPUino variants that are currently available.

Upload to RAM

It is possible to speed up the process of writing sketches to the Papilio board by uploading to RAM instead of SPI Flash. To do this hold down the left shift button while pressing the Upload icon. SmallFS files will not be updated and the code changes will not persist after a power down.

ZPUino Reference

The majority of the information in this section comes from the ZPUino Technical Reference written by Alvaro Lopes. For more in depth information please refer to the technical reference.

GPIO

GPIO provides the basic input and output capabilities for the ZPUino pins connected to the Papilio FPGA board.
It uses the same Digital I/O functions that the Arduino does:

For more information refer to the GPIO section of the ZPUino Technical Reference.

Overview

The Papilio uses a "Wing" numbering scheme which allows the headers to be easily grouped into 16 or 8 bit Wing Slots.

16 Bit Wing Slots


16 Bit Wing Slots

Each 16 bit Wing slot is designated by letter. The Papilio One has three 16 bit Wing Slots that are designated as WA, WB, and WC.

Blink pin 4 on A (:source lang=c highlight='3,8':) int ledState = HIGH; void setup() {

  pinMode(WA4, OUTPUT);

} void loop() {

  delay(200);
  ledState = !ledState; 
  digitalWrite(WA4, ledState);

} (:sourcend:) Blink pin 4 on C (:source lang=c highlight='3,8':) int ledState = HIGH; void setup() {

  pinMode(WC4, OUTPUT);

} void loop() {

  delay(200);
  ledState = !ledState; 
  digitalWrite(WC4, ledState);

} (:sourcend:)


8 Bit Wing Slots


8 Bit Wing Slots

Each 16 Bit Wing slot can be divided into two 8 bit Wing slots by separating them into an upper and lower portion. Wing slot A can be broken down into WAL and WAH, B into WBL and WBH, and C into WCL and WCH.

Blink pin 4 on AL (:source lang=c highlight='3,8':) int ledState = HIGH; void setup() {

  pinMode(WAL4, OUTPUT);

} void loop() {

  delay(200);
  ledState = !ledState; 
  digitalWrite(WAL4, ledState);

} (:sourcend:) Blink pin 4 on AH which is also A12 or 12 (:source lang=c highlight='3,8':) int ledState = HIGH; void setup() {

  pinMode(WAH4, OUTPUT);

} void loop() {

  delay(200);
  ledState = !ledState; 
  digitalWrite(WAH4, ledState);

} (:sourcend:)


Arduino Numbering


Arduino Numbering

Pins can also be addressed using the standard Arduino convention of using a number.

Example sketch using Arduino referencing (:source lang=c highlight='3,8':) int ledState = HIGH; void setup() {

  pinMode(4, OUTPUT);

} void loop() {

  delay(200);
  ledState = !ledState; 
  digitalWrite(4, ledState);

} (:sourcend:)

PPS (Peripheral Pin Select)

ZPUino includes a feature which is called Peripheral Pin Select (in short, PPS). PPS allows you to map every device input or output pin (such as SPI clock and SPI datalines) to each individual pin (GPIO), thus not requiring you to perform synthesis and P&R each time you want to use a device on a different IO pin.

To determine which PPS pins are available in your ZPUino variant, take a look at the PPS section for your variant. For example, here are all of the PPS pins available for the Hyperion variant.

To simplify things, three methods are supplied to manipulate PPS: (:source lang=c :) void pinModePPS ( int pin , int value ); void outputPinForFunction ( unsigned int pin , unsigned int function ); void inputPinForFunction ( unsigned int pin , unsigned int function ); (:sourceend:)

Three register blocks exist to configure how pin selection is done.

  • GPIOPPSIN
  • GPIOPPSOUT
  • GPIOPPSMAP

Redirecting Output

In order to direct any peripheral output to a GPIO pin, you have to:

  • Configure the GPIO pin as output
  • Enable PPS on selected GPIO pin
  • Configure GPIOPPSOUT (outputPinForFunction) to the peripheral signal

Example
The following example maps Sigma Delta 1st channel into GPIO pin number 30: (:source lang=c :) void setup ( void ) {

   // Configure pin as output
   pinMode (30 , OUTPUT );
   // enable PPS on this pin
   pinModePPS (30 , HIGH );
   // Map SigmaDelta channel 1 to pin 30
   outputPinForFunction (30 , IOPIN_SIGMADELTA1 );

} (:sourceend:) Note that you can use GPIO aliases for your board instead of GPIO number. Refer to the GPIO section for more details.

Redirecting Input

In order to direct GPIO input into any peripheral, you have to:

  • Congure the GPIO pin as input;
  • Congure GPIOPPSIN (inputPinForFunction) to the peripheral signal;

Note that for input you don't need to enable PPS on the pin using pinModePPS.

Example
The following example maps USPI MISO signal (Master-In Slave-out) to GPIO pin number 10: (:source lang=c :) void setup ( void ) {

  // Configure pin as input
  pinMode (10 , INPUT );
  // Map pin 30 to USPI MISO
  inputPinForFunction (10 , IOPIN_USPI_MISO );

} (:sourceend:)

Timers

For more information refer to the Timers section of the ZPUino Technical Reference.

Timer Instantiation Example

Signal Section - Put this code in the signal section (search for #Signal)
(:source lang=vhdl :)

  signal timers_pwm1: std_logic_vector(1 downto 0);

(:sourceend:)

These signal names need to be unique and match what you put in the Wishbone section.

Wishbone Section - Put this code in the Wishbone component section (search for #Wishbone)
(:source lang=vhdl :)

  timers2_inst: zpuino_timers
  generic map (
    A_TSCENABLED        => true,
    A_PWMCOUNT          => 1,
    A_WIDTH             => 16,
    A_PRESCALER_ENABLED => true,
    A_BUFFERS           => true,
    B_TSCENABLED        => false,
    B_PWMCOUNT          => 1,
    B_WIDTH             => 24,
    B_PRESCALER_ENABLED => false,
    B_BUFFERS           => false
  )
  port map (
    wb_clk_i       => wb_clk_i,
	 	wb_rst_i    => wb_rst_i,
    wb_dat_o      => slot_read(8),
    wb_dat_i     => slot_write(8),
    wb_adr_i   => slot_address(8),
    wb_we_i        => slot_we(8),
    wb_cyc_i        => slot_cyc(8),
    wb_stb_i        => slot_stb(8),
    wb_ack_o      => slot_ack(8),

    wb_inta_o => slot_interrupt(8), -- We use two interrupt lines
    wb_intb_o => slot_interrupt(9), -- so we borrow intr line from wishbone slot 9, do not use wishbone slot 9 for anything else

    pwm_a_out   => timers_pwm1(0 downto 0),
    pwm_b_out   => timers_pwm1(1 downto 1)
  );

(:sourceend:)

Be sure to change the slot numbers to match your design.

PPS Section - Put this code in the PPS section (search for #PPS)
(:source lang=vhdl :)

    gpio_spp_data(6) <= timers_pwm1(0);          -- PPS6 : TIMER2
    gpio_spp_data(7) <= timers_pwm1(1);          -- PPS7 : TIMER3

(:sourceend:)

Be sure to change the PPS numbers to match your design.

UARTs

For more information refer to the UART section of the ZPUino Technical Reference.

UART Instantiation Example

Signal Section - Put this code in the signal section (search for #Signal)
(:source lang=vhdl :)

  signal uart2_tx, uart2_rx: std_logic; 

(:sourceend:)

These signal names need to be unique and match what you put in the Wishbone section.

Wishbone Section - Put this code in the Wishbone component section (search for #Wishbone)
(:source lang=vhdl :)

  uart2_inst: zpuino_uart
  generic map (
    bits => 4
  )
  port map (
    wb_clk_i       => wb_clk_i,
    wb_rst_i    => wb_rst_i,
    wb_dat_o      => slot_read(8),
    wb_dat_i     => slot_write(8),
    wb_adr_i   => slot_address(8),
    wb_we_i      => slot_we(8),
    wb_cyc_i       => slot_cyc(8),
    wb_stb_i       => slot_stb(8),
    wb_ack_o      => slot_ack(8),

    wb_inta_o => slot_interrupt(8),

    tx        => uart2_tx,
    rx        => uart2_rx
  );	

(:sourceend:)

Be sure to change the slot numbers to match your design.

PPS Section - Put this code in the PPS section (search for #PPS)
(:source lang=vhdl :)

  gpio_spp_data(6) <= uart2_tx;              -- PPS6 : UART2 DATA
  uart2_rx <= gpio_spp_read(1);              -- PPS0 : USPI MISO

(:sourceend:)

Be sure to change the PPS numbers to match your design.

CRC16

For more information refer to the CRC16 section of the ZPUino Technical Reference.

Interrupts

For more information refer to the Interrupts section of the ZPUino Technical Reference.

SigmaDelta DAC

SigmaDelta DAC Instantiation Example

Signal Section - Put this code in the signal section (search for #Signal)
(:source lang=vhdl :)

  signal sigmadelta1_spp_en:  std_logic_vector(1 downto 0);
  signal sigmadelta1_spp_data:  std_logic_vector(1 downto 0);

(:sourceend:)

These signal names need to be unique and match what you put in the Wishbone section.

Wishbone Section - Put this code in the Wishbone component section (search for #Wishbone)
(:source lang=vhdl :)

  sigmadelta2_inst: zpuino_sigmadelta
  port map (
    wb_clk_i       => wb_clk_i,
	 	wb_rst_i    => wb_rst_i,
    wb_dat_o      => slot_read(8),
    wb_dat_i     => slot_write(8),
    wb_adr_i   => slot_address(8),
    wb_we_i        => slot_we(8),
    wb_cyc_i        => slot_cyc(8),
    wb_stb_i        => slot_stb(8),
    wb_ack_o      => slot_ack(8),
    wb_inta_o => slot_interrupt(8),

    spp_data  => sigmadelta1_spp_data,
    spp_en    => sigmadelta1_spp_en,
    sync_in   => '1'
  );

(:sourceend:)

Be sure to change the slot numbers to match your design.

PPS Section - Put this code in the PPS section (search for #PPS)
(:source lang=vhdl :)

    gpio_spp_data(6) <= sigmadelta1_spp_data(0); -- PPS6 : SIGMADELTA DATA
    gpio_spp_data(7) <= sigmadelta1_spp_data(1); -- PPS7 : SIGMADELTA DATA

(:sourceend:)

Be sure to change the PPS numbers to match your design.

SPI

For more information refer to the SPI section of the ZPUino Technical Reference.

SPI Instantiation Example

Signal Section - Put this code in the signal section (search for #Signal)
(:source lang=vhdl :)

  signal spi3_enabled:  std_logic;
  signal spi3_mosi:  std_logic;
  signal spi3_miso:  std_logic;
  signal spi3_sck:  std_logic;

(:sourceend:)

These signal names need to be unique and match what you put in the Wishbone section.

Wishbone Section - Put this code in the Wishbone component section (search for #Wishbone)
(:source lang=vhdl :)

  spi2_inst: zpuino_spi
  port map (
    wb_clk_i       => wb_clk_i,
	 	wb_rst_i    => wb_rst_i,
    wb_dat_o      => slot_read(8),
    wb_dat_i     => slot_write(8),
    wb_adr_i   => slot_address(8),
    wb_we_i        => slot_we(8),
    wb_cyc_i        => slot_cyc(8),
    wb_stb_i        => slot_stb(8),
    wb_ack_o      => slot_ack(8),
    wb_inta_o => slot_interrupt(8),

    mosi      => spi3_mosi,
    miso      => spi3_miso,
    sck       => spi3_sck,
    enabled   => open
  );

(:sourceend:)

Be sure to change the slot numbers to match your design.

PPS Section - Put this code in the PPS section (search for #PPS)
(:source lang=vhdl :)

    gpio_spp_data(6) <= spi3_mosi;              -- PPS6 : USPI MOSI
    gpio_spp_data(7) <= spi3_sck;               -- PPS7 : USPI SCK
    spi3_miso <= gpio_spp_read(1);              -- PPS1 : USPI MISO

(:sourceend:)

Be sure to change the PPS numbers to match your design.

Libraries

SmallFS Library

HQVGA Library

VGALiquidCrystal Library


Setup ZPUino Environment

To write code for the ZPUino we have a specially modified version of the Arduino IDE called the ZAP IDE. ZAP is short for ZPUino Arduino Papilio Soft Processor IDE. Please visit the ZAP IDE QuickStart page to setup the ZPUino Environment.

Run Hello World Example

  • Open the ZPUino IDE and start a new sketch.
  • Select any ZPUino board type that matches the type of hardware you have.
  • Burn the Bootloader to load the correct ZPUino bit file to your Papilio board.
  • Paste the following code into the new sketch

Hello World Code Example (:source lang=c :) void setup() {

  //Setup Serial port
  Serial.begin(9600); 
  // prints Hello World
  Serial.println("Hello World!");

}

void loop(){

  // prints Hello World over and over
  Serial.println("Hello World!");

} (:sourcend:)

  • Determine which port the second Papilio COM port is connected to. If you are not sure which serial port is associated with the Papilio One then take a look at the Device Management tool in the Control Panel. It should be marked as Serial Converter B in the properties.


  • Set the board type to match your hardware.


  • Set the serial port to the second serial port of the Papilio that you determined in the previous step.


  • Upload the sketch to the Papilio, you should see that the sketch was loaded successfully.


  • Press the "Serial Monitor" icon, ensure the baud rate is set to 9600, and you should see Hello World!



Getting Started with Hello World VGA Sketch on the ZPUino.

http://youtu.be/MocpV6b5FYs Alvaro added a VGA controller to the ZPUino and wrote an easy to use VGA Library. His amazing work makes it easy for anyone to output VGA graphics with the Papilio.

  • Open the ZPUino IDE and start a new sketch, or select any of the VGA example sketches from the ZAP IDE.
  • Select any Hyperion Board type that matches your hardware in the ZAP IDE.
  • Burn the Bootloader to load the correct ZPUino bit file to your Papilio board.


  • Paste the following code into the new sketch

(:source lang=c :)

  1. include "VGA.h"

void setup() {

  VGA.clear();
  VGA.setBackgroundColor(BLACK);
  VGA.setColor(RED);
  VGA.printtext(30,0,"Papilio/ZPUino");
  VGA.printtext(35,10,"Hello World"); 

}

void loop() {

} (:sourcend:)

  • Upload the sketch to the Papilio and you should see the Hello World message show up on your VGA monitor!



ZPUino Tutorials

Adding extra serial ports and synthesizing a custom ZPUino SOC

Links

Video

Sketch used in the video

(:source lang=c:) //This sketch assumes a jumper wire between pin 0 and 1 on the Papilio

HardwareSerial mySerial1(8); HardwareSerial mySerial2(9);

void setup() {

  //Connect the tx pin of mySerial1 to pin 0 of the Papilio
  pinMode(0, OUTPUT);
  pinModePPS(0, HIGH);
  outputPinForFunction(0,6);

  //Connect the rx pin of mySerial2 to pin 1 of the Papilio
  pinMode(1,INPUT);
  inputPinForFunction(1,2);

  Serial.begin(9600);
  mySerial1.begin(9600);
  mySerial2.begin(9600);

}

void loop() {

  //Send a 1 out of mySerial1, read it on mySerial2, and send it out the USB serial port.
  mySerial1.write(1);
  if (mySerial2.available()) {
   Serial.println(mySerial2.read()); 
  }
  delay(500);

} (:sourceend:)

  

Share |