Simscape HDL#
Note
This tutorial is optional and only useful for people who plan to use the HDL coder.
The motivation for using Simscape Models on the UltraZohm is to use them as a virtual test bench that can be used with the complete signal chain of the UltraZohm from reading the current value of the Simscape model to the ADC input, transferring data to the PS, calculate the controller on the PS, transfer the duty cycle to the PWM-module and apply the output signal to the Simscape model. Additionally, Simscape Models on the UltraZohm be used to accelerate specific Simulations compared to using a desktop computer. This is especially useful for simulating a system with low time constants that you want to simulate for a long time. However, this is the most basic Mathworks example applied to the UltraZohm, and there is no focus on usability for simulation, nor is the signal chain closed. The goal of this tutorial is to provide a starting point for the user and showcase the possibilities of using existing tooling with the Ultrazohm.
This tutorial consists of:
Generating HDL-Code from a Simulink Simscape Modell
Implementation of the IP-Core
Integration of the IP-Core in the UltraZohm Vivado project
Follows this Mathworks example: Generate HDL Code for Simscape Models
Note
This tutorial is limited to show how it is done, and no explanation is provided. Please refer to the source code of the driver and testbench for insight into the details. Furthermore, the text on this page only supplements the videos which provide the actual details!
Simscape#
Generate IP-Core#
Follow this Generate HDL Code for Simscape Models until the step that opens the HDL version of the model
Add Vivado as synthesis tool with
hdlsetuptoolpath
Right-click the subsystem -> HDL Code -> HDL Workflow Advisor
Settings in HDL Workflow Advisor:
Zynq Ultrascale
&IP-Core
Target Interface:
AXI4-Lite
Reset:
Synchronous
Enable native floating point
Run Workflow to the last point
The IP-Core is now generated
Copy the IP-Core to the IP-Core folder in the ultrazohm_sw repository. Note: the IP-Core is already present in the repository.
Add IP-Core to Vivado, wire the Core to Clocks, Reset and AXI
Assign an address to the IP-Core (
Address Editor
)Build bitstream & export XSA
Video#
Software#
Open Vitis
Generate Workspace
The software driver for the IP-core is located in
Vitis/software/Baremetal/src/IP_Cores/uz_simscapeExample/
Add the following code to
main.c
(of R5) to theinit_ip_cores
section of the switch-case.1 #include "IP_Cores/uz_simscapeExample/uz_simscapeExample_staticAllocator.h" 2 uz_simscapeExample_handle sim_halfWaveRectifier; 3 4//.... 5 6 int main(void) 7 { 8 int status = UZ_SUCCESS; 9 while (1) 10 { 11 switch (initialization_chain) 12 { 13 case init_assertions: 14 uz_assert_configuration(); // This has to be the first line of code in main.c 15 initialization_chain = init_gpios; 16 break; 17 case init_gpios: 18 Initialize_AXI_GPIO(); // This has to be the second line of code in main.c since the assertion callback uses the AXI_GPIO to disable the system 19 uz_frontplane_button_and_led_init(); // This has to be the third line of code since the assertion callback uses the LEDs to indicate an error 20 initialization_chain = init_software; 21 break; 22 case init_software: 23 Initialize_Timer(); 24 uz_SystemTime_init(); 25 JavaScope_initalize(&Global_Data); 26 initialization_chain = init_ip_cores; 27 break; 28 case init_ip_cores: 29 uz_adcLtc2311_ip_core_init(); 30 Global_Data.objects.deadtime_interlock_d1 = uz_interlockDeadtime2L_staticAllocator_slotD1(); 31 uz_interlockDeadtime2L_set_enable_output(Global_Data.objects.deadtime_interlock_d1, true); 32 Global_Data.objects.pwm_d1 = initialize_pwm_2l_on_D1(); 33 Global_Data.objects.mux_axi = initialize_uz_mux_axi(); 34 sim_halfWaveRectifier = uz_simscapeExample_staticAllocator(); 35 PWM_3L_Initialize(&Global_Data); // three-level modulator 36 initialize_incremental_encoder_ipcore_on_D5(UZ_D5_INCREMENTAL_ENCODER_RESOLUTION, UZ_D5_MOTOR_POLE_PAIR_NUMBER); 37 initialization_chain = print_msg; 38 break; 39 case print_msg: 40 //.... 41 } 42 }
Add the following code to
isr.c
Top of file include:
#include "../IP_Cores/uz_simscapeExample/uz_simscapeExample.h" extern uz_simscapeExample_handle sim_halfWaveRectifier;
In function ISR_Control before
JavaScope_update()
function call
uz_simscapeExample_step_model_once(sim_halfWaveRectifier);
Add the following code to
javascope.c
Top of file include & declaration:
#include "../IP_Cores/uz_simscapeExample/uz_simscapeExample_private.h" extern uz_simscapeExample_handle sim_halfWaveRectifier;
Assign the GUI variables
JSO_ISR_ExecTime_us
,JSO_lifecheck
, andJSO_ISR_Period_us
to the output variables of the IP-Core:
js_ch_observable[JSO_ISR_ExecTime_us] = &sim_halfWaveRectifier->Vin; js_ch_observable[JSO_lifecheck] = &sim_halfWaveRectifier->IR; js_ch_observable[JSO_ISR_Period_us] = &sim_halfWaveRectifier->Vdiode;
Set
#define UZ_SIMSCAPEEXAMPLE_USE_IP 1
inIP_Cores/uz_simscapeExample/uz_simscapeExample_staticAllocator.h
Build the project
Power on the UltraZohm, flash the program
Add
hardware_multiplication
to expressions of R5Open Javascope, the output signals can be watched and logged to file