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:

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#

  1. Follow this Generate HDL Code for Simscape Models until the step that opens the HDL version of the model

  2. Add Vivado as synthesis tool with hdlsetuptoolpath

  3. Right-click the subsystem -> HDL Code -> HDL Workflow Advisor

  4. 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

  1. The IP-Core is now generated

  2. Copy the IP-Core to the IP-Core folder in the ultrazohm_sw repository. Note: the IP-Core is already present in the repository.

  3. Add IP-Core to Vivado, wire the Core to Clocks, Reset and AXI

  4. Assign an address to the IP-Core (Address Editor)

  5. Build bitstream & export XSA

Video#

Software#

  1. Open Vitis

  2. Generate Workspace

  3. The software driver for the IP-core is located in Vitis/software/Baremetal/src/IP_Cores/uz_simscapeExample/

  4. Add the following code to main.c (of R5) to the init_ip_cores section of the switch-case.

    Listing 19 Snippet of main.c with initialization of the simscape IP-Core. //.... marks left out code#
     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 }
    
  5. 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);
    
  6. 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, and JSO_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;
    
  7. Set #define UZ_SIMSCAPEEXAMPLE_USE_IP 1 in IP_Cores/uz_simscapeExample/uz_simscapeExample_staticAllocator.h

  8. Build the project

  9. Power on the UltraZohm, flash the program

  10. Add hardware_multiplication to expressions of R5

  11. Open Javascope, the output signals can be watched and logged to file

Video#

More information#