Xilinx Vivado Design Suite 16.1 and Embedded Processing

Main Documents Used

Duckworth's General Approach:

http://ece.wpi.edu/~rjduck/Microblaze%20MCS%20Tutorial%20Vivado%20v1.pdf

(local copy: https://docs.google.com/a/umn.edu/viewer?a=v&pid=sites&srcid=dW1uLmVkdXxteHB0ZXN0fGd4OjdjNmY4YWJjYTE1NmJjNzk)

Xilinx: 2016.1 - Vivado IP Integrator - How to Package a MicroBlaze Block Design containing an ELF

http://www.xilinx.com/support/answers/67083.html

Problem

Duckworth’s approach no longer worked with 2016.1 because it no longer created the microblaze_mcs_0_sdk.xml file when I got to the SDK selecting the Hardware Platform Specification. (It will find the microblaze_mcs_0.xml file though.) (See page 10 of your tutorial: http://ece.wpi.edu/~rjduck/Microblaze%20MCS%20Tutorial%20Vivado%20v1.pdf)

As the IP change log indicated, the software was stream lined and so some of the steps outlined were no longer needed..

Fix Following Mostly Duckworth's Approach:

* Indicates follow Duckworth’s paper

1. Create in Vivado the top module*

2. Add the Microblaze IP*

3. Use the Verilog Instatiation Template and update Top Module*

4. Synthesize*

5. In Vivado 2016.1 create: File -> Export -> Export Hardware

6. In Vivado, launch SDK: File -> Launch SDK. This will not only launch SDK but will create the entire hardware platform specification file stuff for you. So skip to page 10 of Duckworth.

7. Skip the next pages on the board support packages and go directly to the application project, page 12 of Duckworth.

8. Go directly to File -> New Application Project and the rest is the same.

9. Associate the ELF file.*

10. Add constraint file.*

11. Generate Bit File*

12. Program.*

Comments:

When you close the project and later want to re-edit the SDK files, it will complain at first when opening SDK from within Vivado about the hardware file being outdated. Just ignore it and it will work fine.

Vivado Microblaze MCS with a 1 msec Fixed Timer Interrupt

Based on this document: https://embeddedmicro.com/tutorials/mojo/embedded-processors

A Fixed Timer Interrupt with a 1 msec period is added to the MC Microblaze in the IP design. The SDK then calls a function which hangs until its counter, which is incremented by the interrupt, reaches the calling value. In the example below, this will create a 1 second delay after which the SDK again prints some information to the terminal via the UART.

//Works

// reads switches and sends the settings in HEX every 1 second over UART to Terminal at 115000 Baud;

// based on Duckworth and interrupt document below.

//VERILOG CODE ------------------------------------------------

module TopMod(

input sys_clk,

input reset,

input rx,

output tx,

input [7:0] sw,

output [7:0] leds

);

wire FIT1_Toggle; //not used

//----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG

microblaze_mcs_0 mcs_0 (

.Clk(sys_clk), // input wire Clk

.Reset(reset), // input wire Reset

.FIT1_Interrupt(), // output wire FIT1_Interrupt

.FIT1_Toggle(FIT1_Toggle), // output wire FIT1_Toggle

.INTC_IRQ(), // output wire INTC_IRQ

.UART_rxd(rx), // input wire UART_rxd

.UART_txd(tx), // output wire UART_txd

.GPIO1_tri_i(sw), // input wire [7 : 0] GPIO1_tri_i

.GPIO1_tri_o(leds) // output wire [7 : 0] GPIO1_tri_o

);

// INST_TAG_END ------ End INSTANTIATION Template ---------

endmodule

//SDK CODE ------------------------------------------------

#include <stdio.h>

#include "platform.h"

#include "xil_printf.h"

#include "xparameters.h" // add

#include "xiomodule.h" // add

volatile u32 ct = 0; // millisecond counter variable

//function which is called by the interrupt every millisecond

void MytimerTick( void* ref) {

ct++; // increase ct every millisecond (presumably updated by interrupt every msec)

}

// polling function which will hang until interrupt has been called ms times

void Mydelay( u32 ms) {

ct = 0; // set the counter to 0

while (ct < ms) // wait for ms number of milliseconds (resets ct first and stays in while loop while ms is bigger than ct and ct is global and updated by MyTimerTick above every ms)

;

}

int main()

{

init_platform();

print("Hello World\n\r");

u32 data;

u16 my_secs = 0;

XIOModule gpi;

XIOModule gpo;

print("Reading switches and writing to LED port\n\r");

data = XIOModule_Initialize(&gpi, XPAR_IOMODULE_0_DEVICE_ID);

data = XIOModule_Start(&gpi);

data = XIOModule_Initialize(&gpo, XPAR_IOMODULE_0_DEVICE_ID);

data = XIOModule_Start(&gpo);

microblaze_register_handler(XIOModule_DeviceInterruptHandler,

XPAR_IOMODULE_0_DEVICE_ID); // register the interrupt handler

// Makes the connection between the Id of the interrupt source and the associated handler that is to run when the interrupt is recognized.

XIOModule_Connect(&gpo, XIN_IOMODULE_FIT_1_INTERRUPT_INTR, MytimerTick,

NULL); // register timerTick() as our interrupt handler

XIOModule_Enable(&gpo, XIN_IOMODULE_FIT_1_INTERRUPT_INTR); // enable the interrupt

microblaze_enable_interrupts(); // enable global interrupts

while (1)

{

data = XIOModule_DiscreteRead(&gpi, 1); // read switches (channel 1)

XIOModule_DiscreteWrite(&gpo, 1, data); // turn on LEDs (channel 1)

xil_printf("Seconds Elapsed: %d Switches: %X\n\r",my_secs, data );

my_secs++;

Mydelay(1000); // will hang on this function for 1000 interrupts, i.e., one second

}

cleanup_platform();

return 0;

}

Interrupt with xil_printf of Floating Point Numbers and Math Functions

In the example below, (which uses the same block design as the above example), the values of the switches are read and then with the function logf converted to a their natural log. Since the printf takes 100 kB the xil_printf function was instead used. However, since that function cannot display floating number the trick shown below was used to break the numbers into the integer and remainder part for printing the number. Note: you must include the math.h file into the code to use logf.

#include <stdio.h>

#include "platform.h"

#include "xil_printf.h"

#include "xparameters.h" // add

#include "xiomodule.h" // add

#include "math.h"

volatile u32 ct = 0;

void MytimerTick(void* ref) {

ct++; // increase ct every millisecond

}

void Mydelay(u32 ms) {

ct = 0; // set the counter to 0

while (ct < ms) // wait for ms number of milliseconds

;

}

int main()

{

init_platform();

u32 data;

u16 my_secs = 0;

XIOModule gpi;

XIOModule gpo;

xil_printf("MyBASYS3_Intr_june2016_v1 project \n\r");

xil_printf("Reading switches and writing to LED port\n\r");

data = XIOModule_Initialize(&gpi, XPAR_IOMODULE_0_DEVICE_ID);

data = XIOModule_Start(&gpi);

data = XIOModule_Initialize(&gpo, XPAR_IOMODULE_0_DEVICE_ID);

data = XIOModule_Start(&gpo);

microblaze_register_handler(XIOModule_DeviceInterruptHandler,

XPAR_IOMODULE_0_DEVICE_ID); // register the interrupt handler

XIOModule_Connect(&gpo, XIN_IOMODULE_FIT_1_INTERRUPT_INTR, MytimerTick,

NULL); // register timerTick() as our interrupt handler

XIOModule_Enable(&gpo, XIN_IOMODULE_FIT_1_INTERRUPT_INTR); // enable the interrupt

microblaze_enable_interrupts(); // enable global interrupts

float myfloat;

int whole, thousands;

while (1)

{

data = XIOModule_DiscreteRead(&gpi, 1); // read switches (channel 1)

XIOModule_DiscreteWrite(&gpo, 1, data); // turn on LEDs (channel 1)

myfloat = logf((float) data);

whole = myfloat;

thousands = (myfloat-whole)*1000; //convert decimals to integers

xil_printf("ln(switch): %d.%03d ", whole, thousands );

//printf("%f ", myfloat); // takes 100 kb

xil_printf("Seconds Elapsed: %d Switches: %X\n\r",my_secs, data );

my_secs++;

//print("Ticking\n\r");

Mydelay(1000);

}

cleanup_platform();

return 0;

}