diff --git a/.github/workflows/check-format.yml b/.github/workflows/check-format.yml deleted file mode 100644 index 815de652..00000000 --- a/.github/workflows/check-format.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Check Format - -on: - workflow_dispatch: - push: - -jobs: - check-format: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - name: Install libraries for clang-format to work - run: wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh all - - name: Check formatting matches clang-format for CPU0 - run: ./scripts/clang-format -version && bash ./scripts/check-format0.sh - - name: Check formatting matches clang-format for CPU1 - run: ./scripts/clang-format -version && bash ./scripts/check-format1.sh diff --git a/hw/README.md b/hw/README.md deleted file mode 100644 index 01f69438..00000000 --- a/hw/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Contents of `hw/` - -**All the FPGA project related files.** - -This folder contains the FPGA design resources needed to build the Xilinx Vivado project. This project is used to compile and build the FPGA bitstream needed for AMDC operation. Only a minimal number of files are needed since most of the platform-specific HDL is structured into IP blocks (see the [`ip_repo/`](../ip_repo/) folder). - -## File Description - -- `constraints_amdc_rev*.xdc` — stores the Vivado FPGA constraints (pin voltage levels + pin mappings to HDL netlist) -- `amdc_rev*.bd` — main block diagram used in Vivado (stores logical structure of full FPGA contents) diff --git a/ip_repo/amdc_eddy_current_sensor_2.0/bd/bd.tcl b/ip_repo/amdc_eddy_current_sensor_2.0/bd/bd.tcl index 690e4e12..4804aeba 100644 --- a/ip_repo/amdc_eddy_current_sensor_2.0/bd/bd.tcl +++ b/ip_repo/amdc_eddy_current_sensor_2.0/bd/bd.tcl @@ -1,86 +1,86 @@ - -proc init { cellpath otherInfo } { - - set cell_handle [get_bd_cells $cellpath] - set all_busif [get_bd_intf_pins $cellpath/*] - set axi_standard_param_list [list ID_WIDTH AWUSER_WIDTH ARUSER_WIDTH WUSER_WIDTH RUSER_WIDTH BUSER_WIDTH] - set full_sbusif_list [list ] - - foreach busif $all_busif { - if { [string equal -nocase [get_property MODE $busif] "slave"] == 1 } { - set busif_param_list [list] - set busif_name [get_property NAME $busif] - if { [lsearch -exact -nocase $full_sbusif_list $busif_name ] == -1 } { - continue - } - foreach tparam $axi_standard_param_list { - lappend busif_param_list "C_${busif_name}_${tparam}" - } - bd::mark_propagate_only $cell_handle $busif_param_list - } - } -} - - -proc pre_propagate {cellpath otherInfo } { - - set cell_handle [get_bd_cells $cellpath] - set all_busif [get_bd_intf_pins $cellpath/*] - set axi_standard_param_list [list ID_WIDTH AWUSER_WIDTH ARUSER_WIDTH WUSER_WIDTH RUSER_WIDTH BUSER_WIDTH] - - foreach busif $all_busif { - if { [string equal -nocase [get_property CONFIG.PROTOCOL $busif] "AXI4"] != 1 } { - continue - } - if { [string equal -nocase [get_property MODE $busif] "master"] != 1 } { - continue - } - - set busif_name [get_property NAME $busif] - foreach tparam $axi_standard_param_list { - set busif_param_name "C_${busif_name}_${tparam}" - - set val_on_cell_intf_pin [get_property CONFIG.${tparam} $busif] - set val_on_cell [get_property CONFIG.${busif_param_name} $cell_handle] - - if { [string equal -nocase $val_on_cell_intf_pin $val_on_cell] != 1 } { - if { $val_on_cell != "" } { - set_property CONFIG.${tparam} $val_on_cell $busif - } - } - } - } -} - - -proc propagate {cellpath otherInfo } { - - set cell_handle [get_bd_cells $cellpath] - set all_busif [get_bd_intf_pins $cellpath/*] - set axi_standard_param_list [list ID_WIDTH AWUSER_WIDTH ARUSER_WIDTH WUSER_WIDTH RUSER_WIDTH BUSER_WIDTH] - - foreach busif $all_busif { - if { [string equal -nocase [get_property CONFIG.PROTOCOL $busif] "AXI4"] != 1 } { - continue - } - if { [string equal -nocase [get_property MODE $busif] "slave"] != 1 } { - continue - } - - set busif_name [get_property NAME $busif] - foreach tparam $axi_standard_param_list { - set busif_param_name "C_${busif_name}_${tparam}" - - set val_on_cell_intf_pin [get_property CONFIG.${tparam} $busif] - set val_on_cell [get_property CONFIG.${busif_param_name} $cell_handle] - - if { [string equal -nocase $val_on_cell_intf_pin $val_on_cell] != 1 } { - #override property of bd_interface_net to bd_cell -- only for slaves. May check for supported values.. - if { $val_on_cell_intf_pin != "" } { - set_property CONFIG.${busif_param_name} $val_on_cell_intf_pin $cell_handle - } - } - } - } -} - + +proc init { cellpath otherInfo } { + + set cell_handle [get_bd_cells $cellpath] + set all_busif [get_bd_intf_pins $cellpath/*] + set axi_standard_param_list [list ID_WIDTH AWUSER_WIDTH ARUSER_WIDTH WUSER_WIDTH RUSER_WIDTH BUSER_WIDTH] + set full_sbusif_list [list ] + + foreach busif $all_busif { + if { [string equal -nocase [get_property MODE $busif] "slave"] == 1 } { + set busif_param_list [list] + set busif_name [get_property NAME $busif] + if { [lsearch -exact -nocase $full_sbusif_list $busif_name ] == -1 } { + continue + } + foreach tparam $axi_standard_param_list { + lappend busif_param_list "C_${busif_name}_${tparam}" + } + bd::mark_propagate_only $cell_handle $busif_param_list + } + } +} + + +proc pre_propagate {cellpath otherInfo } { + + set cell_handle [get_bd_cells $cellpath] + set all_busif [get_bd_intf_pins $cellpath/*] + set axi_standard_param_list [list ID_WIDTH AWUSER_WIDTH ARUSER_WIDTH WUSER_WIDTH RUSER_WIDTH BUSER_WIDTH] + + foreach busif $all_busif { + if { [string equal -nocase [get_property CONFIG.PROTOCOL $busif] "AXI4"] != 1 } { + continue + } + if { [string equal -nocase [get_property MODE $busif] "master"] != 1 } { + continue + } + + set busif_name [get_property NAME $busif] + foreach tparam $axi_standard_param_list { + set busif_param_name "C_${busif_name}_${tparam}" + + set val_on_cell_intf_pin [get_property CONFIG.${tparam} $busif] + set val_on_cell [get_property CONFIG.${busif_param_name} $cell_handle] + + if { [string equal -nocase $val_on_cell_intf_pin $val_on_cell] != 1 } { + if { $val_on_cell != "" } { + set_property CONFIG.${tparam} $val_on_cell $busif + } + } + } + } +} + + +proc propagate {cellpath otherInfo } { + + set cell_handle [get_bd_cells $cellpath] + set all_busif [get_bd_intf_pins $cellpath/*] + set axi_standard_param_list [list ID_WIDTH AWUSER_WIDTH ARUSER_WIDTH WUSER_WIDTH RUSER_WIDTH BUSER_WIDTH] + + foreach busif $all_busif { + if { [string equal -nocase [get_property CONFIG.PROTOCOL $busif] "AXI4"] != 1 } { + continue + } + if { [string equal -nocase [get_property MODE $busif] "slave"] != 1 } { + continue + } + + set busif_name [get_property NAME $busif] + foreach tparam $axi_standard_param_list { + set busif_param_name "C_${busif_name}_${tparam}" + + set val_on_cell_intf_pin [get_property CONFIG.${tparam} $busif] + set val_on_cell [get_property CONFIG.${busif_param_name} $cell_handle] + + if { [string equal -nocase $val_on_cell_intf_pin $val_on_cell] != 1 } { + #override property of bd_interface_net to bd_cell -- only for slaves. May check for supported values.. + if { $val_on_cell_intf_pin != "" } { + set_property CONFIG.${busif_param_name} $val_on_cell_intf_pin $cell_handle + } + } + } + } +} + diff --git a/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/data/amdc_eddy_current_sensor.mdd b/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/data/amdc_eddy_current_sensor.mdd index 230dd2db..540052e0 100644 --- a/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/data/amdc_eddy_current_sensor.mdd +++ b/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/data/amdc_eddy_current_sensor.mdd @@ -1,10 +1,10 @@ - - -OPTION psf_version = 2.1; - -BEGIN DRIVER amdc_eddy_current_sensor - OPTION supported_peripherals = (amdc_eddy_current_sensor); - OPTION copyfiles = all; - OPTION VERSION = 1.0; - OPTION NAME = amdc_eddy_current_sensor; -END DRIVER + + +OPTION psf_version = 2.1; + +BEGIN DRIVER amdc_eddy_current_sensor + OPTION supported_peripherals = (amdc_eddy_current_sensor); + OPTION copyfiles = all; + OPTION VERSION = 1.0; + OPTION NAME = amdc_eddy_current_sensor; +END DRIVER diff --git a/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/data/amdc_eddy_current_sensor.tcl b/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/data/amdc_eddy_current_sensor.tcl index a9849e49..0b97f744 100644 --- a/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/data/amdc_eddy_current_sensor.tcl +++ b/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/data/amdc_eddy_current_sensor.tcl @@ -1,5 +1,5 @@ - - -proc generate {drv_handle} { - xdefine_include_file $drv_handle "xparameters.h" "amdc_eddy_current_sensor" "NUM_INSTANCES" "DEVICE_ID" "C_S00_AXI_BASEADDR" "C_S00_AXI_HIGHADDR" -} + + +proc generate {drv_handle} { + xdefine_include_file $drv_handle "xparameters.h" "amdc_eddy_current_sensor" "NUM_INSTANCES" "DEVICE_ID" "C_S00_AXI_BASEADDR" "C_S00_AXI_HIGHADDR" +} diff --git a/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/src/Makefile b/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/src/Makefile index efc84f2a..9bbff2f7 100644 --- a/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/src/Makefile +++ b/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/src/Makefile @@ -1,26 +1,26 @@ -COMPILER= -ARCHIVER= -CP=cp -COMPILER_FLAGS= -EXTRA_COMPILER_FLAGS= -LIB=libxil.a - -RELEASEDIR=../../../lib -INCLUDEDIR=../../../include -INCLUDES=-I./. -I${INCLUDEDIR} - -INCLUDEFILES=*.h -LIBSOURCES=*.c -OUTS = *.o - -libs: - echo "Compiling amdc_eddy_current_sensor..." - $(COMPILER) $(COMPILER_FLAGS) $(EXTRA_COMPILER_FLAGS) $(INCLUDES) $(LIBSOURCES) - $(ARCHIVER) -r ${RELEASEDIR}/${LIB} ${OUTS} - make clean - -include: - ${CP} $(INCLUDEFILES) $(INCLUDEDIR) - -clean: - rm -rf ${OUTS} +COMPILER= +ARCHIVER= +CP=cp +COMPILER_FLAGS= +EXTRA_COMPILER_FLAGS= +LIB=libxil.a + +RELEASEDIR=../../../lib +INCLUDEDIR=../../../include +INCLUDES=-I./. -I${INCLUDEDIR} + +INCLUDEFILES=*.h +LIBSOURCES=*.c +OUTS = *.o + +libs: + echo "Compiling amdc_eddy_current_sensor..." + $(COMPILER) $(COMPILER_FLAGS) $(EXTRA_COMPILER_FLAGS) $(INCLUDES) $(LIBSOURCES) + $(ARCHIVER) -r ${RELEASEDIR}/${LIB} ${OUTS} + make clean + +include: + ${CP} $(INCLUDEFILES) $(INCLUDEDIR) + +clean: + rm -rf ${OUTS} diff --git a/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/src/amdc_eddy_current_sensor.c b/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/src/amdc_eddy_current_sensor.c index 16283cbb..a72cf98d 100644 --- a/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/src/amdc_eddy_current_sensor.c +++ b/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/src/amdc_eddy_current_sensor.c @@ -1,6 +1,6 @@ - - -/***************************** Include Files *******************************/ -#include "amdc_eddy_current_sensor.h" - -/************************** Function Definitions ***************************/ + + +/***************************** Include Files *******************************/ +#include "amdc_eddy_current_sensor.h" + +/************************** Function Definitions ***************************/ diff --git a/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/src/amdc_eddy_current_sensor.h b/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/src/amdc_eddy_current_sensor.h index b85bdae7..3f8770a9 100644 --- a/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/src/amdc_eddy_current_sensor.h +++ b/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/src/amdc_eddy_current_sensor.h @@ -1,83 +1,83 @@ - -#ifndef AMDC_EDDY_CURRENT_SENSOR_H -#define AMDC_EDDY_CURRENT_SENSOR_H - - -/****************** Include Files ********************/ -#include "xil_types.h" -#include "xstatus.h" - -#define AMDC_EDDY_CURRENT_SENSOR_S00_AXI_SLV_REG0_OFFSET 0 -#define AMDC_EDDY_CURRENT_SENSOR_S00_AXI_SLV_REG1_OFFSET 4 -#define AMDC_EDDY_CURRENT_SENSOR_S00_AXI_SLV_REG2_OFFSET 8 -#define AMDC_EDDY_CURRENT_SENSOR_S00_AXI_SLV_REG3_OFFSET 12 -#define AMDC_EDDY_CURRENT_SENSOR_S00_AXI_SLV_REG4_OFFSET 16 -#define AMDC_EDDY_CURRENT_SENSOR_S00_AXI_SLV_REG5_OFFSET 20 -#define AMDC_EDDY_CURRENT_SENSOR_S00_AXI_SLV_REG6_OFFSET 24 -#define AMDC_EDDY_CURRENT_SENSOR_S00_AXI_SLV_REG7_OFFSET 28 - - -/**************************** Type Definitions *****************************/ -/** - * - * Write a value to a AMDC_EDDY_CURRENT_SENSOR register. A 32 bit write is performed. - * If the component is implemented in a smaller width, only the least - * significant data is written. - * - * @param BaseAddress is the base address of the AMDC_EDDY_CURRENT_SENSORdevice. - * @param RegOffset is the register offset from the base to write to. - * @param Data is the data written to the register. - * - * @return None. - * - * @note - * C-style signature: - * void AMDC_EDDY_CURRENT_SENSOR_mWriteReg(u32 BaseAddress, unsigned RegOffset, u32 Data) - * - */ -#define AMDC_EDDY_CURRENT_SENSOR_mWriteReg(BaseAddress, RegOffset, Data) \ - Xil_Out32((BaseAddress) + (RegOffset), (u32)(Data)) - -/** - * - * Read a value from a AMDC_EDDY_CURRENT_SENSOR register. A 32 bit read is performed. - * If the component is implemented in a smaller width, only the least - * significant data is read from the register. The most significant data - * will be read as 0. - * - * @param BaseAddress is the base address of the AMDC_EDDY_CURRENT_SENSOR device. - * @param RegOffset is the register offset from the base to write to. - * - * @return Data is the data from the register. - * - * @note - * C-style signature: - * u32 AMDC_EDDY_CURRENT_SENSOR_mReadReg(u32 BaseAddress, unsigned RegOffset) - * - */ -#define AMDC_EDDY_CURRENT_SENSOR_mReadReg(BaseAddress, RegOffset) \ - Xil_In32((BaseAddress) + (RegOffset)) - -/************************** Function Prototypes ****************************/ -/** - * - * Run a self-test on the driver/device. Note this may be a destructive test if - * resets of the device are performed. - * - * If the hardware system is not built correctly, this function may never - * return to the caller. - * - * @param baseaddr_p is the base address of the AMDC_EDDY_CURRENT_SENSOR instance to be worked on. - * - * @return - * - * - XST_SUCCESS if all self-test code passed - * - XST_FAILURE if any self-test code failed - * - * @note Caching must be turned off for this function to work. - * @note Self test may fail if data memory and device are not on the same bus. - * - */ -XStatus AMDC_EDDY_CURRENT_SENSOR_Reg_SelfTest(void * baseaddr_p); - -#endif // AMDC_EDDY_CURRENT_SENSOR_H + +#ifndef AMDC_EDDY_CURRENT_SENSOR_H +#define AMDC_EDDY_CURRENT_SENSOR_H + + +/****************** Include Files ********************/ +#include "xil_types.h" +#include "xstatus.h" + +#define AMDC_EDDY_CURRENT_SENSOR_S00_AXI_SLV_REG0_OFFSET 0 +#define AMDC_EDDY_CURRENT_SENSOR_S00_AXI_SLV_REG1_OFFSET 4 +#define AMDC_EDDY_CURRENT_SENSOR_S00_AXI_SLV_REG2_OFFSET 8 +#define AMDC_EDDY_CURRENT_SENSOR_S00_AXI_SLV_REG3_OFFSET 12 +#define AMDC_EDDY_CURRENT_SENSOR_S00_AXI_SLV_REG4_OFFSET 16 +#define AMDC_EDDY_CURRENT_SENSOR_S00_AXI_SLV_REG5_OFFSET 20 +#define AMDC_EDDY_CURRENT_SENSOR_S00_AXI_SLV_REG6_OFFSET 24 +#define AMDC_EDDY_CURRENT_SENSOR_S00_AXI_SLV_REG7_OFFSET 28 + + +/**************************** Type Definitions *****************************/ +/** + * + * Write a value to a AMDC_EDDY_CURRENT_SENSOR register. A 32 bit write is performed. + * If the component is implemented in a smaller width, only the least + * significant data is written. + * + * @param BaseAddress is the base address of the AMDC_EDDY_CURRENT_SENSORdevice. + * @param RegOffset is the register offset from the base to write to. + * @param Data is the data written to the register. + * + * @return None. + * + * @note + * C-style signature: + * void AMDC_EDDY_CURRENT_SENSOR_mWriteReg(u32 BaseAddress, unsigned RegOffset, u32 Data) + * + */ +#define AMDC_EDDY_CURRENT_SENSOR_mWriteReg(BaseAddress, RegOffset, Data) \ + Xil_Out32((BaseAddress) + (RegOffset), (u32)(Data)) + +/** + * + * Read a value from a AMDC_EDDY_CURRENT_SENSOR register. A 32 bit read is performed. + * If the component is implemented in a smaller width, only the least + * significant data is read from the register. The most significant data + * will be read as 0. + * + * @param BaseAddress is the base address of the AMDC_EDDY_CURRENT_SENSOR device. + * @param RegOffset is the register offset from the base to write to. + * + * @return Data is the data from the register. + * + * @note + * C-style signature: + * u32 AMDC_EDDY_CURRENT_SENSOR_mReadReg(u32 BaseAddress, unsigned RegOffset) + * + */ +#define AMDC_EDDY_CURRENT_SENSOR_mReadReg(BaseAddress, RegOffset) \ + Xil_In32((BaseAddress) + (RegOffset)) + +/************************** Function Prototypes ****************************/ +/** + * + * Run a self-test on the driver/device. Note this may be a destructive test if + * resets of the device are performed. + * + * If the hardware system is not built correctly, this function may never + * return to the caller. + * + * @param baseaddr_p is the base address of the AMDC_EDDY_CURRENT_SENSOR instance to be worked on. + * + * @return + * + * - XST_SUCCESS if all self-test code passed + * - XST_FAILURE if any self-test code failed + * + * @note Caching must be turned off for this function to work. + * @note Self test may fail if data memory and device are not on the same bus. + * + */ +XStatus AMDC_EDDY_CURRENT_SENSOR_Reg_SelfTest(void * baseaddr_p); + +#endif // AMDC_EDDY_CURRENT_SENSOR_H diff --git a/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/src/amdc_eddy_current_sensor_selftest.c b/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/src/amdc_eddy_current_sensor_selftest.c index dce88b10..c83bfb66 100644 --- a/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/src/amdc_eddy_current_sensor_selftest.c +++ b/ip_repo/amdc_eddy_current_sensor_2.0/drivers/amdc_eddy_current_sensor_v1_0/src/amdc_eddy_current_sensor_selftest.c @@ -1,60 +1,60 @@ - -/***************************** Include Files *******************************/ -#include "amdc_eddy_current_sensor.h" -#include "xparameters.h" -#include "stdio.h" -#include "xil_io.h" - -/************************** Constant Definitions ***************************/ -#define READ_WRITE_MUL_FACTOR 0x10 - -/************************** Function Definitions ***************************/ -/** - * - * Run a self-test on the driver/device. Note this may be a destructive test if - * resets of the device are performed. - * - * If the hardware system is not built correctly, this function may never - * return to the caller. - * - * @param baseaddr_p is the base address of the AMDC_EDDY_CURRENT_SENSORinstance to be worked on. - * - * @return - * - * - XST_SUCCESS if all self-test code passed - * - XST_FAILURE if any self-test code failed - * - * @note Caching must be turned off for this function to work. - * @note Self test may fail if data memory and device are not on the same bus. - * - */ -XStatus AMDC_EDDY_CURRENT_SENSOR_Reg_SelfTest(void * baseaddr_p) -{ - u32 baseaddr; - int write_loop_index; - int read_loop_index; - int Index; - - baseaddr = (u32) baseaddr_p; - - xil_printf("******************************\n\r"); - xil_printf("* User Peripheral Self Test\n\r"); - xil_printf("******************************\n\n\r"); - - /* - * Write to user logic slave module register(s) and read back - */ - xil_printf("User logic slave module test...\n\r"); - - for (write_loop_index = 0 ; write_loop_index < 4; write_loop_index++) - AMDC_EDDY_CURRENT_SENSOR_mWriteReg (baseaddr, write_loop_index*4, (write_loop_index+1)*READ_WRITE_MUL_FACTOR); - for (read_loop_index = 0 ; read_loop_index < 4; read_loop_index++) - if ( AMDC_EDDY_CURRENT_SENSOR_mReadReg (baseaddr, read_loop_index*4) != (read_loop_index+1)*READ_WRITE_MUL_FACTOR){ - xil_printf ("Error reading register value at address %x\n", (int)baseaddr + read_loop_index*4); - return XST_FAILURE; - } - - xil_printf(" - slave register write/read passed\n\n\r"); - - return XST_SUCCESS; -} + +/***************************** Include Files *******************************/ +#include "amdc_eddy_current_sensor.h" +#include "xparameters.h" +#include "stdio.h" +#include "xil_io.h" + +/************************** Constant Definitions ***************************/ +#define READ_WRITE_MUL_FACTOR 0x10 + +/************************** Function Definitions ***************************/ +/** + * + * Run a self-test on the driver/device. Note this may be a destructive test if + * resets of the device are performed. + * + * If the hardware system is not built correctly, this function may never + * return to the caller. + * + * @param baseaddr_p is the base address of the AMDC_EDDY_CURRENT_SENSORinstance to be worked on. + * + * @return + * + * - XST_SUCCESS if all self-test code passed + * - XST_FAILURE if any self-test code failed + * + * @note Caching must be turned off for this function to work. + * @note Self test may fail if data memory and device are not on the same bus. + * + */ +XStatus AMDC_EDDY_CURRENT_SENSOR_Reg_SelfTest(void * baseaddr_p) +{ + u32 baseaddr; + int write_loop_index; + int read_loop_index; + int Index; + + baseaddr = (u32) baseaddr_p; + + xil_printf("******************************\n\r"); + xil_printf("* User Peripheral Self Test\n\r"); + xil_printf("******************************\n\n\r"); + + /* + * Write to user logic slave module register(s) and read back + */ + xil_printf("User logic slave module test...\n\r"); + + for (write_loop_index = 0 ; write_loop_index < 4; write_loop_index++) + AMDC_EDDY_CURRENT_SENSOR_mWriteReg (baseaddr, write_loop_index*4, (write_loop_index+1)*READ_WRITE_MUL_FACTOR); + for (read_loop_index = 0 ; read_loop_index < 4; read_loop_index++) + if ( AMDC_EDDY_CURRENT_SENSOR_mReadReg (baseaddr, read_loop_index*4) != (read_loop_index+1)*READ_WRITE_MUL_FACTOR){ + xil_printf ("Error reading register value at address %x\n", (int)baseaddr + read_loop_index*4); + return XST_FAILURE; + } + + xil_printf(" - slave register write/read passed\n\n\r"); + + return XST_SUCCESS; +} diff --git a/ip_repo/amdc_eddy_current_sensor_2.0/example_designs/bfm_design/amdc_eddy_current_sensor_v2_0_tb.sv b/ip_repo/amdc_eddy_current_sensor_2.0/example_designs/bfm_design/amdc_eddy_current_sensor_v2_0_tb.sv index b0d5b8eb..53b91e8f 100644 --- a/ip_repo/amdc_eddy_current_sensor_2.0/example_designs/bfm_design/amdc_eddy_current_sensor_v2_0_tb.sv +++ b/ip_repo/amdc_eddy_current_sensor_2.0/example_designs/bfm_design/amdc_eddy_current_sensor_v2_0_tb.sv @@ -1,197 +1,197 @@ - -`timescale 1ns / 1ps -`include "amdc_eddy_current_sensor_v2_0_tb_include.svh" - -import axi_vip_pkg::*; -import amdc_eddy_current_sensor_v2_0_bfm_1_master_0_0_pkg::*; - -module amdc_eddy_current_sensor_v2_0_tb(); - - -xil_axi_uint error_cnt = 0; -xil_axi_uint comparison_cnt = 0; -axi_transaction wr_transaction; -axi_transaction rd_transaction; -axi_monitor_transaction mst_monitor_transaction; -axi_monitor_transaction master_moniter_transaction_queue[$]; -xil_axi_uint master_moniter_transaction_queue_size =0; -axi_monitor_transaction mst_scb_transaction; -axi_monitor_transaction passthrough_monitor_transaction; -axi_monitor_transaction passthrough_master_moniter_transaction_queue[$]; -xil_axi_uint passthrough_master_moniter_transaction_queue_size =0; -axi_monitor_transaction passthrough_mst_scb_transaction; -axi_monitor_transaction passthrough_slave_moniter_transaction_queue[$]; -xil_axi_uint passthrough_slave_moniter_transaction_queue_size =0; -axi_monitor_transaction passthrough_slv_scb_transaction; -axi_monitor_transaction slv_monitor_transaction; -axi_monitor_transaction slave_moniter_transaction_queue[$]; -xil_axi_uint slave_moniter_transaction_queue_size =0; -axi_monitor_transaction slv_scb_transaction; -xil_axi_uint mst_agent_verbosity = 0; -xil_axi_uint slv_agent_verbosity = 0; -xil_axi_uint passthrough_agent_verbosity = 0; -bit clock; -bit reset; -integer result_slave; -bit [31:0] S00_AXI_test_data[3:0]; - localparam LC_AXI_BURST_LENGTH = 8; - localparam LC_AXI_DATA_WIDTH = 32; -task automatic COMPARE_DATA; - input [(LC_AXI_BURST_LENGTH * LC_AXI_DATA_WIDTH)-1:0]expected; - input [(LC_AXI_BURST_LENGTH * LC_AXI_DATA_WIDTH)-1:0]actual; - begin - if (expected === 'hx || actual === 'hx) begin - $display("TESTBENCH ERROR! COMPARE_DATA cannot be performed with an expected or actual vector that is all 'x'!"); - result_slave = 0; $stop; - end - if (actual != expected) begin - $display("TESTBENCH ERROR! Data expected is not equal to actual.", " expected = 0x%h",expected, " actual = 0x%h",actual); - result_slave = 0; - $stop; - end - else - begin - $display("TESTBENCH Passed! Data expected is equal to actual.", - " expected = 0x%h",expected, " actual = 0x%h",actual); - end - end -endtask -integer i; -integer j; -xil_axi_uint trans_cnt_before_switch = 48; -xil_axi_uint passthrough_cmd_switch_cnt = 0; -event passthrough_mastermode_start_event; -event passthrough_mastermode_end_event; -event passthrough_slavemode_end_event; -xil_axi_uint mtestID; -xil_axi_ulong mtestADDR; -xil_axi_len_t mtestBurstLength; -xil_axi_size_t mtestDataSize; -xil_axi_burst_t mtestBurstType; -xil_axi_lock_t mtestLOCK; -xil_axi_cache_t mtestCacheType = 0; -xil_axi_prot_t mtestProtectionType = 3'b000; -xil_axi_region_t mtestRegion = 4'b000; -xil_axi_qos_t mtestQOS = 4'b000; -xil_axi_data_beat dbeat; -xil_axi_data_beat [255:0] mtestWUSER; -xil_axi_data_beat mtestAWUSER = 'h0; -xil_axi_data_beat mtestARUSER = 0; -xil_axi_data_beat [255:0] mtestRUSER; -xil_axi_uint mtestBUSER = 0; -xil_axi_resp_t mtestBresp; -xil_axi_resp_t[255:0] mtestRresp; -bit [63:0] mtestWDataL; -bit [63:0] mtestRDataL; -axi_transaction pss_wr_transaction; -axi_transaction pss_rd_transaction; -axi_transaction reactive_transaction; -axi_transaction rd_payload_transaction; -axi_transaction wr_rand; -axi_transaction rd_rand; -axi_transaction wr_reactive; -axi_transaction rd_reactive; -axi_transaction wr_reactive2; -axi_transaction rd_reactive2; -axi_ready_gen bready_gen; -axi_ready_gen rready_gen; -axi_ready_gen awready_gen; -axi_ready_gen wready_gen; -axi_ready_gen arready_gen; -axi_ready_gen bready_gen2; -axi_ready_gen rready_gen2; -axi_ready_gen awready_gen2; -axi_ready_gen wready_gen2; -axi_ready_gen arready_gen2; -xil_axi_payload_byte data_mem[xil_axi_ulong]; -amdc_eddy_current_sensor_v2_0_bfm_1_master_0_0_mst_t mst_agent_0; - - `BD_WRAPPER DUT( - .ARESETN(reset), - .ACLK(clock) - ); - -initial begin - mst_agent_0 = new("master vip agent",DUT.`BD_INST_NAME.master_0.inst.IF);//ms - mst_agent_0.vif_proxy.set_dummy_drive_type(XIL_AXI_VIF_DRIVE_NONE); - mst_agent_0.set_agent_tag("Master VIP"); - mst_agent_0.set_verbosity(mst_agent_verbosity); - mst_agent_0.start_master(); - $timeformat (-12, 1, " ps", 1); - end - initial begin - reset <= 1'b0; - #200ns; - reset <= 1'b1; - repeat (5) @(negedge clock); - end - always #5 clock <= ~clock; - initial begin - S_AXI_TEST ( ); - - #1ns; - $finish; - end -task automatic S_AXI_TEST; -begin -#1; - $display("Sequential write transfers example similar to AXI BFM WRITE_BURST method starts"); - mtestID = 0; - mtestADDR = 64'h00000000; - mtestBurstLength = 0; - mtestDataSize = xil_axi_size_t'(xil_clog2(32/8)); - mtestBurstType = XIL_AXI_BURST_TYPE_INCR; - mtestLOCK = XIL_AXI_ALOCK_NOLOCK; - mtestCacheType = 0; - mtestProtectionType = 0; - mtestRegion = 0; - mtestQOS = 0; - result_slave = 1; - mtestWDataL[31:0] = 32'h00000001; - for(int i = 0; i < 4;i++) begin - S00_AXI_test_data[i] <= mtestWDataL[31:0]; - mst_agent_0.AXI4LITE_WRITE_BURST( - mtestADDR, - mtestProtectionType, - mtestWDataL, - mtestBresp - ); - mtestWDataL[31:0] = mtestWDataL[31:0] + 1; - mtestADDR = mtestADDR + 64'h4; - end - $display("Sequential write transfers example similar to AXI BFM WRITE_BURST method completes"); - $display("Sequential read transfers example similar to AXI BFM READ_BURST method starts"); - mtestID = 0; - mtestADDR = 64'h00000000; - mtestBurstLength = 0; - mtestDataSize = xil_axi_size_t'(xil_clog2(32/8)); - mtestBurstType = XIL_AXI_BURST_TYPE_INCR; - mtestLOCK = XIL_AXI_ALOCK_NOLOCK; - mtestCacheType = 0; - mtestProtectionType = 0; - mtestRegion = 0; - mtestQOS = 0; - for(int i = 0; i < 4;i++) begin - mst_agent_0.AXI4LITE_READ_BURST( - mtestADDR, - mtestProtectionType, - mtestRDataL, - mtestRresp - ); - mtestADDR = mtestADDR + 64'h4; - COMPARE_DATA(S00_AXI_test_data[i],mtestRDataL); - end - $display("Sequential read transfers example similar to AXI BFM READ_BURST method completes"); - $display("Sequential read transfers example similar to AXI VIP READ_BURST method completes"); - $display("---------------------------------------------------------"); - $display("EXAMPLE TEST S00_AXI: PTGEN_TEST_FINISHED!"); - if ( result_slave ) begin - $display("PTGEN_TEST: PASSED!"); - end else begin - $display("PTGEN_TEST: FAILED!"); - end - $display("---------------------------------------------------------"); - end -endtask - -endmodule + +`timescale 1ns / 1ps +`include "amdc_eddy_current_sensor_v2_0_tb_include.svh" + +import axi_vip_pkg::*; +import amdc_eddy_current_sensor_v2_0_bfm_1_master_0_0_pkg::*; + +module amdc_eddy_current_sensor_v2_0_tb(); + + +xil_axi_uint error_cnt = 0; +xil_axi_uint comparison_cnt = 0; +axi_transaction wr_transaction; +axi_transaction rd_transaction; +axi_monitor_transaction mst_monitor_transaction; +axi_monitor_transaction master_moniter_transaction_queue[$]; +xil_axi_uint master_moniter_transaction_queue_size =0; +axi_monitor_transaction mst_scb_transaction; +axi_monitor_transaction passthrough_monitor_transaction; +axi_monitor_transaction passthrough_master_moniter_transaction_queue[$]; +xil_axi_uint passthrough_master_moniter_transaction_queue_size =0; +axi_monitor_transaction passthrough_mst_scb_transaction; +axi_monitor_transaction passthrough_slave_moniter_transaction_queue[$]; +xil_axi_uint passthrough_slave_moniter_transaction_queue_size =0; +axi_monitor_transaction passthrough_slv_scb_transaction; +axi_monitor_transaction slv_monitor_transaction; +axi_monitor_transaction slave_moniter_transaction_queue[$]; +xil_axi_uint slave_moniter_transaction_queue_size =0; +axi_monitor_transaction slv_scb_transaction; +xil_axi_uint mst_agent_verbosity = 0; +xil_axi_uint slv_agent_verbosity = 0; +xil_axi_uint passthrough_agent_verbosity = 0; +bit clock; +bit reset; +integer result_slave; +bit [31:0] S00_AXI_test_data[3:0]; + localparam LC_AXI_BURST_LENGTH = 8; + localparam LC_AXI_DATA_WIDTH = 32; +task automatic COMPARE_DATA; + input [(LC_AXI_BURST_LENGTH * LC_AXI_DATA_WIDTH)-1:0]expected; + input [(LC_AXI_BURST_LENGTH * LC_AXI_DATA_WIDTH)-1:0]actual; + begin + if (expected === 'hx || actual === 'hx) begin + $display("TESTBENCH ERROR! COMPARE_DATA cannot be performed with an expected or actual vector that is all 'x'!"); + result_slave = 0; $stop; + end + if (actual != expected) begin + $display("TESTBENCH ERROR! Data expected is not equal to actual.", " expected = 0x%h",expected, " actual = 0x%h",actual); + result_slave = 0; + $stop; + end + else + begin + $display("TESTBENCH Passed! Data expected is equal to actual.", + " expected = 0x%h",expected, " actual = 0x%h",actual); + end + end +endtask +integer i; +integer j; +xil_axi_uint trans_cnt_before_switch = 48; +xil_axi_uint passthrough_cmd_switch_cnt = 0; +event passthrough_mastermode_start_event; +event passthrough_mastermode_end_event; +event passthrough_slavemode_end_event; +xil_axi_uint mtestID; +xil_axi_ulong mtestADDR; +xil_axi_len_t mtestBurstLength; +xil_axi_size_t mtestDataSize; +xil_axi_burst_t mtestBurstType; +xil_axi_lock_t mtestLOCK; +xil_axi_cache_t mtestCacheType = 0; +xil_axi_prot_t mtestProtectionType = 3'b000; +xil_axi_region_t mtestRegion = 4'b000; +xil_axi_qos_t mtestQOS = 4'b000; +xil_axi_data_beat dbeat; +xil_axi_data_beat [255:0] mtestWUSER; +xil_axi_data_beat mtestAWUSER = 'h0; +xil_axi_data_beat mtestARUSER = 0; +xil_axi_data_beat [255:0] mtestRUSER; +xil_axi_uint mtestBUSER = 0; +xil_axi_resp_t mtestBresp; +xil_axi_resp_t[255:0] mtestRresp; +bit [63:0] mtestWDataL; +bit [63:0] mtestRDataL; +axi_transaction pss_wr_transaction; +axi_transaction pss_rd_transaction; +axi_transaction reactive_transaction; +axi_transaction rd_payload_transaction; +axi_transaction wr_rand; +axi_transaction rd_rand; +axi_transaction wr_reactive; +axi_transaction rd_reactive; +axi_transaction wr_reactive2; +axi_transaction rd_reactive2; +axi_ready_gen bready_gen; +axi_ready_gen rready_gen; +axi_ready_gen awready_gen; +axi_ready_gen wready_gen; +axi_ready_gen arready_gen; +axi_ready_gen bready_gen2; +axi_ready_gen rready_gen2; +axi_ready_gen awready_gen2; +axi_ready_gen wready_gen2; +axi_ready_gen arready_gen2; +xil_axi_payload_byte data_mem[xil_axi_ulong]; +amdc_eddy_current_sensor_v2_0_bfm_1_master_0_0_mst_t mst_agent_0; + + `BD_WRAPPER DUT( + .ARESETN(reset), + .ACLK(clock) + ); + +initial begin + mst_agent_0 = new("master vip agent",DUT.`BD_INST_NAME.master_0.inst.IF);//ms + mst_agent_0.vif_proxy.set_dummy_drive_type(XIL_AXI_VIF_DRIVE_NONE); + mst_agent_0.set_agent_tag("Master VIP"); + mst_agent_0.set_verbosity(mst_agent_verbosity); + mst_agent_0.start_master(); + $timeformat (-12, 1, " ps", 1); + end + initial begin + reset <= 1'b0; + #200ns; + reset <= 1'b1; + repeat (5) @(negedge clock); + end + always #5 clock <= ~clock; + initial begin + S_AXI_TEST ( ); + + #1ns; + $finish; + end +task automatic S_AXI_TEST; +begin +#1; + $display("Sequential write transfers example similar to AXI BFM WRITE_BURST method starts"); + mtestID = 0; + mtestADDR = 64'h00000000; + mtestBurstLength = 0; + mtestDataSize = xil_axi_size_t'(xil_clog2(32/8)); + mtestBurstType = XIL_AXI_BURST_TYPE_INCR; + mtestLOCK = XIL_AXI_ALOCK_NOLOCK; + mtestCacheType = 0; + mtestProtectionType = 0; + mtestRegion = 0; + mtestQOS = 0; + result_slave = 1; + mtestWDataL[31:0] = 32'h00000001; + for(int i = 0; i < 4;i++) begin + S00_AXI_test_data[i] <= mtestWDataL[31:0]; + mst_agent_0.AXI4LITE_WRITE_BURST( + mtestADDR, + mtestProtectionType, + mtestWDataL, + mtestBresp + ); + mtestWDataL[31:0] = mtestWDataL[31:0] + 1; + mtestADDR = mtestADDR + 64'h4; + end + $display("Sequential write transfers example similar to AXI BFM WRITE_BURST method completes"); + $display("Sequential read transfers example similar to AXI BFM READ_BURST method starts"); + mtestID = 0; + mtestADDR = 64'h00000000; + mtestBurstLength = 0; + mtestDataSize = xil_axi_size_t'(xil_clog2(32/8)); + mtestBurstType = XIL_AXI_BURST_TYPE_INCR; + mtestLOCK = XIL_AXI_ALOCK_NOLOCK; + mtestCacheType = 0; + mtestProtectionType = 0; + mtestRegion = 0; + mtestQOS = 0; + for(int i = 0; i < 4;i++) begin + mst_agent_0.AXI4LITE_READ_BURST( + mtestADDR, + mtestProtectionType, + mtestRDataL, + mtestRresp + ); + mtestADDR = mtestADDR + 64'h4; + COMPARE_DATA(S00_AXI_test_data[i],mtestRDataL); + end + $display("Sequential read transfers example similar to AXI BFM READ_BURST method completes"); + $display("Sequential read transfers example similar to AXI VIP READ_BURST method completes"); + $display("---------------------------------------------------------"); + $display("EXAMPLE TEST S00_AXI: PTGEN_TEST_FINISHED!"); + if ( result_slave ) begin + $display("PTGEN_TEST: PASSED!"); + end else begin + $display("PTGEN_TEST: FAILED!"); + end + $display("---------------------------------------------------------"); + end +endtask + +endmodule diff --git a/ip_repo/amdc_eddy_current_sensor_2.0/example_designs/bfm_design/design.tcl b/ip_repo/amdc_eddy_current_sensor_2.0/example_designs/bfm_design/design.tcl index 21f6fc38..5db27380 100644 --- a/ip_repo/amdc_eddy_current_sensor_2.0/example_designs/bfm_design/design.tcl +++ b/ip_repo/amdc_eddy_current_sensor_2.0/example_designs/bfm_design/design.tcl @@ -1,88 +1,88 @@ -proc create_ipi_design { offsetfile design_name } { - create_bd_design $design_name - open_bd_design $design_name - - # Create Clock and Reset Ports - set ACLK [ create_bd_port -dir I -type clk ACLK ] - set_property -dict [ list CONFIG.FREQ_HZ {100000000} CONFIG.PHASE {0.000} CONFIG.CLK_DOMAIN "${design_name}_ACLK" ] $ACLK - set ARESETN [ create_bd_port -dir I -type rst ARESETN ] - set_property -dict [ list CONFIG.POLARITY {ACTIVE_LOW} ] $ARESETN - set_property CONFIG.ASSOCIATED_RESET ARESETN $ACLK - - # Create instance: amdc_eddy_current_sensor_0, and set properties - set amdc_eddy_current_sensor_0 [ create_bd_cell -type ip -vlnv xilinx.com:user:amdc_eddy_current_sensor:2.0 amdc_eddy_current_sensor_0] - - # Create instance: master_0, and set properties - set master_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_vip master_0] - set_property -dict [ list CONFIG.PROTOCOL {AXI4LITE} CONFIG.INTERFACE_MODE {MASTER} ] $master_0 - - # Create interface connections - connect_bd_intf_net [get_bd_intf_pins master_0/M_AXI ] [get_bd_intf_pins amdc_eddy_current_sensor_0/S00_AXI] - - # Create port connections - connect_bd_net -net aclk_net [get_bd_ports ACLK] [get_bd_pins master_0/ACLK] [get_bd_pins amdc_eddy_current_sensor_0/S00_AXI_ACLK] - connect_bd_net -net aresetn_net [get_bd_ports ARESETN] [get_bd_pins master_0/ARESETN] [get_bd_pins amdc_eddy_current_sensor_0/S00_AXI_ARESETN] -set_property target_simulator XSim [current_project] -set_property -name {xsim.simulate.runtime} -value {100ms} -objects [get_filesets sim_1] - - # Auto assign address - assign_bd_address - - # Copy all address to interface_address.vh file - set bd_path [file dirname [get_property NAME [get_files ${design_name}.bd]]] - upvar 1 $offsetfile offset_file - set offset_file "${bd_path}/amdc_eddy_current_sensor_v2_0_tb_include.svh" - set fp [open $offset_file "w"] - puts $fp "`ifndef amdc_eddy_current_sensor_v2_0_tb_include_vh_" - puts $fp "`define amdc_eddy_current_sensor_v2_0_tb_include_vh_\n" - puts $fp "//Configuration current bd names" - puts $fp "`define BD_NAME ${design_name}" - puts $fp "`define BD_INST_NAME ${design_name}_i" - puts $fp "`define BD_WRAPPER ${design_name}_wrapper\n" - puts $fp "//Configuration address parameters" - - puts $fp "`endif" - close $fp -} - -set ip_path [file dirname [file normalize [get_property XML_FILE_NAME [ipx::get_cores xilinx.com:user:amdc_eddy_current_sensor:2.0]]]] -set test_bench_file ${ip_path}/example_designs/bfm_design/amdc_eddy_current_sensor_v2_0_tb.sv -set interface_address_vh_file "" - -# Set IP Repository and Update IP Catalogue -set repo_paths [get_property ip_repo_paths [current_fileset]] -if { [lsearch -exact -nocase $repo_paths $ip_path ] == -1 } { - set_property ip_repo_paths "$ip_path [get_property ip_repo_paths [current_fileset]]" [current_fileset] - update_ip_catalog -} - -set design_name "" -set all_bd {} -set all_bd_files [get_files *.bd -quiet] -foreach file $all_bd_files { -set file_name [string range $file [expr {[string last "/" $file] + 1}] end] -set bd_name [string range $file_name 0 [expr {[string last "." $file_name] -1}]] -lappend all_bd $bd_name -} - -for { set i 1 } { 1 } { incr i } { - set design_name "amdc_eddy_current_sensor_v2_0_bfm_${i}" - if { [lsearch -exact -nocase $all_bd $design_name ] == -1 } { - break - } -} - -create_ipi_design interface_address_vh_file ${design_name} -validate_bd_design - -set wrapper_file [make_wrapper -files [get_files ${design_name}.bd] -top -force] -import_files -force -norecurse $wrapper_file - -set_property SOURCE_SET sources_1 [get_filesets sim_1] -import_files -fileset sim_1 -norecurse -force $test_bench_file -remove_files -quiet -fileset sim_1 amdc_eddy_current_sensor_v2_0_tb_include.vh -import_files -fileset sim_1 -norecurse -force $interface_address_vh_file -set_property top amdc_eddy_current_sensor_v2_0_tb [get_filesets sim_1] -set_property top_lib {} [get_filesets sim_1] -set_property top_file {} [get_filesets sim_1] -launch_simulation -simset sim_1 -mode behavioral +proc create_ipi_design { offsetfile design_name } { + create_bd_design $design_name + open_bd_design $design_name + + # Create Clock and Reset Ports + set ACLK [ create_bd_port -dir I -type clk ACLK ] + set_property -dict [ list CONFIG.FREQ_HZ {100000000} CONFIG.PHASE {0.000} CONFIG.CLK_DOMAIN "${design_name}_ACLK" ] $ACLK + set ARESETN [ create_bd_port -dir I -type rst ARESETN ] + set_property -dict [ list CONFIG.POLARITY {ACTIVE_LOW} ] $ARESETN + set_property CONFIG.ASSOCIATED_RESET ARESETN $ACLK + + # Create instance: amdc_eddy_current_sensor_0, and set properties + set amdc_eddy_current_sensor_0 [ create_bd_cell -type ip -vlnv xilinx.com:user:amdc_eddy_current_sensor:2.0 amdc_eddy_current_sensor_0] + + # Create instance: master_0, and set properties + set master_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_vip master_0] + set_property -dict [ list CONFIG.PROTOCOL {AXI4LITE} CONFIG.INTERFACE_MODE {MASTER} ] $master_0 + + # Create interface connections + connect_bd_intf_net [get_bd_intf_pins master_0/M_AXI ] [get_bd_intf_pins amdc_eddy_current_sensor_0/S00_AXI] + + # Create port connections + connect_bd_net -net aclk_net [get_bd_ports ACLK] [get_bd_pins master_0/ACLK] [get_bd_pins amdc_eddy_current_sensor_0/S00_AXI_ACLK] + connect_bd_net -net aresetn_net [get_bd_ports ARESETN] [get_bd_pins master_0/ARESETN] [get_bd_pins amdc_eddy_current_sensor_0/S00_AXI_ARESETN] +set_property target_simulator XSim [current_project] +set_property -name {xsim.simulate.runtime} -value {100ms} -objects [get_filesets sim_1] + + # Auto assign address + assign_bd_address + + # Copy all address to interface_address.vh file + set bd_path [file dirname [get_property NAME [get_files ${design_name}.bd]]] + upvar 1 $offsetfile offset_file + set offset_file "${bd_path}/amdc_eddy_current_sensor_v2_0_tb_include.svh" + set fp [open $offset_file "w"] + puts $fp "`ifndef amdc_eddy_current_sensor_v2_0_tb_include_vh_" + puts $fp "`define amdc_eddy_current_sensor_v2_0_tb_include_vh_\n" + puts $fp "//Configuration current bd names" + puts $fp "`define BD_NAME ${design_name}" + puts $fp "`define BD_INST_NAME ${design_name}_i" + puts $fp "`define BD_WRAPPER ${design_name}_wrapper\n" + puts $fp "//Configuration address parameters" + + puts $fp "`endif" + close $fp +} + +set ip_path [file dirname [file normalize [get_property XML_FILE_NAME [ipx::get_cores xilinx.com:user:amdc_eddy_current_sensor:2.0]]]] +set test_bench_file ${ip_path}/example_designs/bfm_design/amdc_eddy_current_sensor_v2_0_tb.sv +set interface_address_vh_file "" + +# Set IP Repository and Update IP Catalogue +set repo_paths [get_property ip_repo_paths [current_fileset]] +if { [lsearch -exact -nocase $repo_paths $ip_path ] == -1 } { + set_property ip_repo_paths "$ip_path [get_property ip_repo_paths [current_fileset]]" [current_fileset] + update_ip_catalog +} + +set design_name "" +set all_bd {} +set all_bd_files [get_files *.bd -quiet] +foreach file $all_bd_files { +set file_name [string range $file [expr {[string last "/" $file] + 1}] end] +set bd_name [string range $file_name 0 [expr {[string last "." $file_name] -1}]] +lappend all_bd $bd_name +} + +for { set i 1 } { 1 } { incr i } { + set design_name "amdc_eddy_current_sensor_v2_0_bfm_${i}" + if { [lsearch -exact -nocase $all_bd $design_name ] == -1 } { + break + } +} + +create_ipi_design interface_address_vh_file ${design_name} +validate_bd_design + +set wrapper_file [make_wrapper -files [get_files ${design_name}.bd] -top -force] +import_files -force -norecurse $wrapper_file + +set_property SOURCE_SET sources_1 [get_filesets sim_1] +import_files -fileset sim_1 -norecurse -force $test_bench_file +remove_files -quiet -fileset sim_1 amdc_eddy_current_sensor_v2_0_tb_include.vh +import_files -fileset sim_1 -norecurse -force $interface_address_vh_file +set_property top amdc_eddy_current_sensor_v2_0_tb [get_filesets sim_1] +set_property top_lib {} [get_filesets sim_1] +set_property top_file {} [get_filesets sim_1] +launch_simulation -simset sim_1 -mode behavioral diff --git a/ip_repo/amdc_eddy_current_sensor_2.0/example_designs/debug_hw_design/amdc_eddy_current_sensor_v2_0_hw_test.tcl b/ip_repo/amdc_eddy_current_sensor_2.0/example_designs/debug_hw_design/amdc_eddy_current_sensor_v2_0_hw_test.tcl index fbb65daf..f053de7f 100644 --- a/ip_repo/amdc_eddy_current_sensor_2.0/example_designs/debug_hw_design/amdc_eddy_current_sensor_v2_0_hw_test.tcl +++ b/ip_repo/amdc_eddy_current_sensor_2.0/example_designs/debug_hw_design/amdc_eddy_current_sensor_v2_0_hw_test.tcl @@ -1,45 +1,45 @@ -# Runtime Tcl commands to interact with - amdc_eddy_current_sensor_v2_0 - -# Sourcing design address info tcl -set bd_path [get_property DIRECTORY [current_project]]/[current_project].srcs/[current_fileset]/bd -source ${bd_path}/amdc_eddy_current_sensor_v2_0_include.tcl - -# jtag axi master interface hardware name, change as per your design. -set jtag_axi_master hw_axi_1 -set ec 0 - -# hw test script -# Delete all previous axis transactions -if { [llength [get_hw_axi_txns -quiet]] } { - delete_hw_axi_txn [get_hw_axi_txns -quiet] -} - - -# Test all lite slaves. -set wdata_1 abcd1234 - -# Test: S00_AXI -# Create a write transaction at s00_axi_addr address -create_hw_axi_txn w_s00_axi_addr [get_hw_axis $jtag_axi_master] -type write -address $s00_axi_addr -data $wdata_1 -# Create a read transaction at s00_axi_addr address -create_hw_axi_txn r_s00_axi_addr [get_hw_axis $jtag_axi_master] -type read -address $s00_axi_addr -# Initiate transactions -run_hw_axi r_s00_axi_addr -run_hw_axi w_s00_axi_addr -run_hw_axi r_s00_axi_addr -set rdata_tmp [get_property DATA [get_hw_axi_txn r_s00_axi_addr]] -# Compare read data -if { $rdata_tmp == $wdata_1 } { - puts "Data comparison test pass for - S00_AXI" -} else { - puts "Data comparison test fail for - S00_AXI, expected-$wdata_1 actual-$rdata_tmp" - inc ec -} - -# Check error flag -if { $ec == 0 } { - puts "PTGEN_TEST: PASSED!" -} else { - puts "PTGEN_TEST: FAILED!" -} - +# Runtime Tcl commands to interact with - amdc_eddy_current_sensor_v2_0 + +# Sourcing design address info tcl +set bd_path [get_property DIRECTORY [current_project]]/[current_project].srcs/[current_fileset]/bd +source ${bd_path}/amdc_eddy_current_sensor_v2_0_include.tcl + +# jtag axi master interface hardware name, change as per your design. +set jtag_axi_master hw_axi_1 +set ec 0 + +# hw test script +# Delete all previous axis transactions +if { [llength [get_hw_axi_txns -quiet]] } { + delete_hw_axi_txn [get_hw_axi_txns -quiet] +} + + +# Test all lite slaves. +set wdata_1 abcd1234 + +# Test: S00_AXI +# Create a write transaction at s00_axi_addr address +create_hw_axi_txn w_s00_axi_addr [get_hw_axis $jtag_axi_master] -type write -address $s00_axi_addr -data $wdata_1 +# Create a read transaction at s00_axi_addr address +create_hw_axi_txn r_s00_axi_addr [get_hw_axis $jtag_axi_master] -type read -address $s00_axi_addr +# Initiate transactions +run_hw_axi r_s00_axi_addr +run_hw_axi w_s00_axi_addr +run_hw_axi r_s00_axi_addr +set rdata_tmp [get_property DATA [get_hw_axi_txn r_s00_axi_addr]] +# Compare read data +if { $rdata_tmp == $wdata_1 } { + puts "Data comparison test pass for - S00_AXI" +} else { + puts "Data comparison test fail for - S00_AXI, expected-$wdata_1 actual-$rdata_tmp" + inc ec +} + +# Check error flag +if { $ec == 0 } { + puts "PTGEN_TEST: PASSED!" +} else { + puts "PTGEN_TEST: FAILED!" +} + diff --git a/ip_repo/amdc_eddy_current_sensor_2.0/example_designs/debug_hw_design/design.tcl b/ip_repo/amdc_eddy_current_sensor_2.0/example_designs/debug_hw_design/design.tcl index 387fb404..fbf8b3f3 100644 --- a/ip_repo/amdc_eddy_current_sensor_2.0/example_designs/debug_hw_design/design.tcl +++ b/ip_repo/amdc_eddy_current_sensor_2.0/example_designs/debug_hw_design/design.tcl @@ -1,118 +1,118 @@ - -proc create_ipi_design { offsetfile design_name } { - - create_bd_design $design_name - open_bd_design $design_name - - # Create and configure Clock/Reset - create_bd_cell -type ip -vlnv xilinx.com:ip:clk_wiz sys_clk_0 - create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset sys_reset_0 - - #Constraints will be provided manually while pin planning. - create_bd_port -dir I -type rst reset_rtl - set_property CONFIG.POLARITY [get_property CONFIG.POLARITY [get_bd_pins sys_clk_0/reset]] [get_bd_ports reset_rtl] - connect_bd_net [get_bd_pins sys_reset_0/ext_reset_in] [get_bd_ports reset_rtl] - connect_bd_net [get_bd_ports reset_rtl] [get_bd_pins sys_clk_0/reset] - set external_reset_port reset_rtl - create_bd_port -dir I -type clk clock_rtl - connect_bd_net [get_bd_pins sys_clk_0/clk_in1] [get_bd_ports clock_rtl] - set external_clock_port clock_rtl - - #Avoid IPI DRC, make clock port synchronous to reset - if { $external_clock_port ne "" && $external_reset_port ne "" } { - set_property CONFIG.ASSOCIATED_RESET $external_reset_port [get_bd_ports $external_clock_port] - } - - # Connect other sys_reset pins - connect_bd_net [get_bd_pins sys_reset_0/slowest_sync_clk] [get_bd_pins sys_clk_0/clk_out1] - connect_bd_net [get_bd_pins sys_clk_0/locked] [get_bd_pins sys_reset_0/dcm_locked] - - # Create instance: amdc_eddy_current_sensor_0, and set properties - set amdc_eddy_current_sensor_0 [ create_bd_cell -type ip -vlnv xilinx.com:user:amdc_eddy_current_sensor:2.0 amdc_eddy_current_sensor_0 ] - - # Create instance: jtag_axi_0, and set properties - set jtag_axi_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:jtag_axi jtag_axi_0 ] - set_property -dict [list CONFIG.PROTOCOL {0}] [get_bd_cells jtag_axi_0] - connect_bd_net [get_bd_pins jtag_axi_0/aclk] [get_bd_pins sys_clk_0/clk_out1] - connect_bd_net [get_bd_pins jtag_axi_0/aresetn] [get_bd_pins sys_reset_0/peripheral_aresetn] - - # Create instance: axi_peri_interconnect, and set properties - set axi_peri_interconnect [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect axi_peri_interconnect ] - connect_bd_net [get_bd_pins axi_peri_interconnect/ACLK] [get_bd_pins sys_clk_0/clk_out1] - connect_bd_net [get_bd_pins axi_peri_interconnect/ARESETN] [get_bd_pins sys_reset_0/interconnect_aresetn] - set_property -dict [ list CONFIG.NUM_SI {1} ] $axi_peri_interconnect - connect_bd_net [get_bd_pins axi_peri_interconnect/S00_ACLK] [get_bd_pins sys_clk_0/clk_out1] - connect_bd_net [get_bd_pins axi_peri_interconnect/S00_ARESETN] [get_bd_pins sys_reset_0/peripheral_aresetn] - connect_bd_intf_net [get_bd_intf_pins jtag_axi_0/M_AXI] [get_bd_intf_pins axi_peri_interconnect/S00_AXI] - - set_property -dict [ list CONFIG.NUM_MI {1} ] $axi_peri_interconnect - connect_bd_net [get_bd_pins axi_peri_interconnect/M00_ACLK] [get_bd_pins sys_clk_0/clk_out1] - connect_bd_net [get_bd_pins axi_peri_interconnect/M00_ARESETN] [get_bd_pins sys_reset_0/peripheral_aresetn] - - # Connect all clock & reset of amdc_eddy_current_sensor_0 slave interfaces.. - connect_bd_intf_net [get_bd_intf_pins axi_peri_interconnect/M00_AXI] [get_bd_intf_pins amdc_eddy_current_sensor_0/S00_AXI] - connect_bd_net [get_bd_pins amdc_eddy_current_sensor_0/s00_axi_aclk] [get_bd_pins sys_clk_0/clk_out1] - connect_bd_net [get_bd_pins amdc_eddy_current_sensor_0/s00_axi_aresetn] [get_bd_pins sys_reset_0/peripheral_aresetn] - - - # Auto assign address - assign_bd_address - - # Copy all address to amdc_eddy_current_sensor_v2_0_include.tcl file - set bd_path [get_property DIRECTORY [current_project]]/[current_project].srcs/[current_fileset]/bd - upvar 1 $offsetfile offset_file - set offset_file "${bd_path}/amdc_eddy_current_sensor_v2_0_include.tcl" - set fp [open $offset_file "w"] - puts $fp "# Configuration address parameters" - - set offset [get_property OFFSET [get_bd_addr_segs /jtag_axi_0/Data/SEG_amdc_eddy_current_sensor_0_S00_AXI_* ]] - puts $fp "set s00_axi_addr ${offset}" - - close $fp -} - -# Set IP Repository and Update IP Catalogue -set ip_path [file dirname [file normalize [get_property XML_FILE_NAME [ipx::get_cores xilinx.com:user:amdc_eddy_current_sensor:2.0]]]] -set hw_test_file ${ip_path}/example_designs/debug_hw_design/amdc_eddy_current_sensor_v2_0_hw_test.tcl - -set repo_paths [get_property ip_repo_paths [current_fileset]] -if { [lsearch -exact -nocase $repo_paths $ip_path ] == -1 } { - set_property ip_repo_paths "$ip_path [get_property ip_repo_paths [current_fileset]]" [current_fileset] - update_ip_catalog -} - -set design_name "" -set all_bd {} -set all_bd_files [get_files *.bd -quiet] -foreach file $all_bd_files { -set file_name [string range $file [expr {[string last "/" $file] + 1}] end] -set bd_name [string range $file_name 0 [expr {[string last "." $file_name] -1}]] -lappend all_bd $bd_name -} - -for { set i 1 } { 1 } { incr i } { - set design_name "amdc_eddy_current_sensor_v2_0_hw_${i}" - if { [lsearch -exact -nocase $all_bd $design_name ] == -1 } { - break - } -} - -set intf_address_include_file "" -create_ipi_design intf_address_include_file ${design_name} -save_bd_design -validate_bd_design - -set wrapper_file [make_wrapper -files [get_files ${design_name}.bd] -top -force] -import_files -force -norecurse $wrapper_file - -puts "-------------------------------------------------------------------------------------------------" -puts "INFO NEXT STEPS : Until this stage, debug hardware design has been created, " -puts " please perform following steps to test design in targeted board." -puts "1. Generate bitstream" -puts "2. Setup your targeted board, open hardware manager and open new(or existing) hardware target" -puts "3. Download generated bitstream" -puts "4. Run generated hardware test using below command, this invokes basic read/write operation" -puts " to every interface present in the peripheral : xilinx.com:user:myip:1.0" -puts " : source -notrace ${hw_test_file}" -puts "-------------------------------------------------------------------------------------------------" - + +proc create_ipi_design { offsetfile design_name } { + + create_bd_design $design_name + open_bd_design $design_name + + # Create and configure Clock/Reset + create_bd_cell -type ip -vlnv xilinx.com:ip:clk_wiz sys_clk_0 + create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset sys_reset_0 + + #Constraints will be provided manually while pin planning. + create_bd_port -dir I -type rst reset_rtl + set_property CONFIG.POLARITY [get_property CONFIG.POLARITY [get_bd_pins sys_clk_0/reset]] [get_bd_ports reset_rtl] + connect_bd_net [get_bd_pins sys_reset_0/ext_reset_in] [get_bd_ports reset_rtl] + connect_bd_net [get_bd_ports reset_rtl] [get_bd_pins sys_clk_0/reset] + set external_reset_port reset_rtl + create_bd_port -dir I -type clk clock_rtl + connect_bd_net [get_bd_pins sys_clk_0/clk_in1] [get_bd_ports clock_rtl] + set external_clock_port clock_rtl + + #Avoid IPI DRC, make clock port synchronous to reset + if { $external_clock_port ne "" && $external_reset_port ne "" } { + set_property CONFIG.ASSOCIATED_RESET $external_reset_port [get_bd_ports $external_clock_port] + } + + # Connect other sys_reset pins + connect_bd_net [get_bd_pins sys_reset_0/slowest_sync_clk] [get_bd_pins sys_clk_0/clk_out1] + connect_bd_net [get_bd_pins sys_clk_0/locked] [get_bd_pins sys_reset_0/dcm_locked] + + # Create instance: amdc_eddy_current_sensor_0, and set properties + set amdc_eddy_current_sensor_0 [ create_bd_cell -type ip -vlnv xilinx.com:user:amdc_eddy_current_sensor:2.0 amdc_eddy_current_sensor_0 ] + + # Create instance: jtag_axi_0, and set properties + set jtag_axi_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:jtag_axi jtag_axi_0 ] + set_property -dict [list CONFIG.PROTOCOL {0}] [get_bd_cells jtag_axi_0] + connect_bd_net [get_bd_pins jtag_axi_0/aclk] [get_bd_pins sys_clk_0/clk_out1] + connect_bd_net [get_bd_pins jtag_axi_0/aresetn] [get_bd_pins sys_reset_0/peripheral_aresetn] + + # Create instance: axi_peri_interconnect, and set properties + set axi_peri_interconnect [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect axi_peri_interconnect ] + connect_bd_net [get_bd_pins axi_peri_interconnect/ACLK] [get_bd_pins sys_clk_0/clk_out1] + connect_bd_net [get_bd_pins axi_peri_interconnect/ARESETN] [get_bd_pins sys_reset_0/interconnect_aresetn] + set_property -dict [ list CONFIG.NUM_SI {1} ] $axi_peri_interconnect + connect_bd_net [get_bd_pins axi_peri_interconnect/S00_ACLK] [get_bd_pins sys_clk_0/clk_out1] + connect_bd_net [get_bd_pins axi_peri_interconnect/S00_ARESETN] [get_bd_pins sys_reset_0/peripheral_aresetn] + connect_bd_intf_net [get_bd_intf_pins jtag_axi_0/M_AXI] [get_bd_intf_pins axi_peri_interconnect/S00_AXI] + + set_property -dict [ list CONFIG.NUM_MI {1} ] $axi_peri_interconnect + connect_bd_net [get_bd_pins axi_peri_interconnect/M00_ACLK] [get_bd_pins sys_clk_0/clk_out1] + connect_bd_net [get_bd_pins axi_peri_interconnect/M00_ARESETN] [get_bd_pins sys_reset_0/peripheral_aresetn] + + # Connect all clock & reset of amdc_eddy_current_sensor_0 slave interfaces.. + connect_bd_intf_net [get_bd_intf_pins axi_peri_interconnect/M00_AXI] [get_bd_intf_pins amdc_eddy_current_sensor_0/S00_AXI] + connect_bd_net [get_bd_pins amdc_eddy_current_sensor_0/s00_axi_aclk] [get_bd_pins sys_clk_0/clk_out1] + connect_bd_net [get_bd_pins amdc_eddy_current_sensor_0/s00_axi_aresetn] [get_bd_pins sys_reset_0/peripheral_aresetn] + + + # Auto assign address + assign_bd_address + + # Copy all address to amdc_eddy_current_sensor_v2_0_include.tcl file + set bd_path [get_property DIRECTORY [current_project]]/[current_project].srcs/[current_fileset]/bd + upvar 1 $offsetfile offset_file + set offset_file "${bd_path}/amdc_eddy_current_sensor_v2_0_include.tcl" + set fp [open $offset_file "w"] + puts $fp "# Configuration address parameters" + + set offset [get_property OFFSET [get_bd_addr_segs /jtag_axi_0/Data/SEG_amdc_eddy_current_sensor_0_S00_AXI_* ]] + puts $fp "set s00_axi_addr ${offset}" + + close $fp +} + +# Set IP Repository and Update IP Catalogue +set ip_path [file dirname [file normalize [get_property XML_FILE_NAME [ipx::get_cores xilinx.com:user:amdc_eddy_current_sensor:2.0]]]] +set hw_test_file ${ip_path}/example_designs/debug_hw_design/amdc_eddy_current_sensor_v2_0_hw_test.tcl + +set repo_paths [get_property ip_repo_paths [current_fileset]] +if { [lsearch -exact -nocase $repo_paths $ip_path ] == -1 } { + set_property ip_repo_paths "$ip_path [get_property ip_repo_paths [current_fileset]]" [current_fileset] + update_ip_catalog +} + +set design_name "" +set all_bd {} +set all_bd_files [get_files *.bd -quiet] +foreach file $all_bd_files { +set file_name [string range $file [expr {[string last "/" $file] + 1}] end] +set bd_name [string range $file_name 0 [expr {[string last "." $file_name] -1}]] +lappend all_bd $bd_name +} + +for { set i 1 } { 1 } { incr i } { + set design_name "amdc_eddy_current_sensor_v2_0_hw_${i}" + if { [lsearch -exact -nocase $all_bd $design_name ] == -1 } { + break + } +} + +set intf_address_include_file "" +create_ipi_design intf_address_include_file ${design_name} +save_bd_design +validate_bd_design + +set wrapper_file [make_wrapper -files [get_files ${design_name}.bd] -top -force] +import_files -force -norecurse $wrapper_file + +puts "-------------------------------------------------------------------------------------------------" +puts "INFO NEXT STEPS : Until this stage, debug hardware design has been created, " +puts " please perform following steps to test design in targeted board." +puts "1. Generate bitstream" +puts "2. Setup your targeted board, open hardware manager and open new(or existing) hardware target" +puts "3. Download generated bitstream" +puts "4. Run generated hardware test using below command, this invokes basic read/write operation" +puts " to every interface present in the peripheral : xilinx.com:user:myip:1.0" +puts " : source -notrace ${hw_test_file}" +puts "-------------------------------------------------------------------------------------------------" + diff --git a/ip_repo/amdc_eddy_current_sensor_2.0/hdl/amdc_eddy_current_sensor_v2_0.v b/ip_repo/amdc_eddy_current_sensor_2.0/hdl/amdc_eddy_current_sensor_v2_0.v index 08568d7b..7e56d5f5 100644 --- a/ip_repo/amdc_eddy_current_sensor_2.0/hdl/amdc_eddy_current_sensor_v2_0.v +++ b/ip_repo/amdc_eddy_current_sensor_2.0/hdl/amdc_eddy_current_sensor_v2_0.v @@ -1,94 +1,94 @@ - -`timescale 1 ns / 1 ps - - module amdc_eddy_current_sensor_v2_0 # - ( - // Users to add parameters here - - // User parameters ends - // Do not modify the parameters beyond this line - - - // Parameters of Axi Slave Bus Interface S00_AXI - parameter integer C_S00_AXI_DATA_WIDTH = 32, - parameter integer C_S00_AXI_ADDR_WIDTH = 5 - ) - ( - // Users to add ports here - input wire [1:0] sensor_data_in, - input wire enable, - input wire pwm_carrier_high, - input wire pwm_carrier_low, - - output wire [1:0] sensor_control_out, - output wire done, - output wire [2:0] debug, - // User ports ends - // Do not modify the ports beyond this line - - - // Ports of Axi Slave Bus Interface S00_AXI - input wire s00_axi_aclk, - input wire s00_axi_aresetn, - input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_awaddr, - input wire [2 : 0] s00_axi_awprot, - input wire s00_axi_awvalid, - output wire s00_axi_awready, - input wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_wdata, - input wire [(C_S00_AXI_DATA_WIDTH/8)-1 : 0] s00_axi_wstrb, - input wire s00_axi_wvalid, - output wire s00_axi_wready, - output wire [1 : 0] s00_axi_bresp, - output wire s00_axi_bvalid, - input wire s00_axi_bready, - input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_araddr, - input wire [2 : 0] s00_axi_arprot, - input wire s00_axi_arvalid, - output wire s00_axi_arready, - output wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_rdata, - output wire [1 : 0] s00_axi_rresp, - output wire s00_axi_rvalid, - input wire s00_axi_rready - ); -// Instantiation of Axi Bus Interface S00_AXI - amdc_eddy_current_sensor_v2_0_S00_AXI # ( - .C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH), - .C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH) - ) amdc_eddy_current_sensor_v2_0_S00_AXI_inst ( - .S_AXI_ACLK(s00_axi_aclk), - .S_AXI_ARESETN(s00_axi_aresetn), - .S_AXI_AWADDR(s00_axi_awaddr), - .S_AXI_AWPROT(s00_axi_awprot), - .S_AXI_AWVALID(s00_axi_awvalid), - .S_AXI_AWREADY(s00_axi_awready), - .S_AXI_WDATA(s00_axi_wdata), - .S_AXI_WSTRB(s00_axi_wstrb), - .S_AXI_WVALID(s00_axi_wvalid), - .S_AXI_WREADY(s00_axi_wready), - .S_AXI_BRESP(s00_axi_bresp), - .S_AXI_BVALID(s00_axi_bvalid), - .S_AXI_BREADY(s00_axi_bready), - .S_AXI_ARADDR(s00_axi_araddr), - .S_AXI_ARPROT(s00_axi_arprot), - .S_AXI_ARVALID(s00_axi_arvalid), - .S_AXI_ARREADY(s00_axi_arready), - .S_AXI_RDATA(s00_axi_rdata), - .S_AXI_RRESP(s00_axi_rresp), - .S_AXI_RVALID(s00_axi_rvalid), - .S_AXI_RREADY(s00_axi_rready), - .miso_x(sensor_data_in[0]), - .miso_y(sensor_data_in[1]), - .enable(enable), - .pwm_carrier_high(pwm_carrier_high), - .pwm_carrier_low(pwm_carrier_low), - .sclk(sensor_control_out[0]), - .cnv(sensor_control_out[1]), - .done(done), - .debug(debug) - ); - - // Add user logic here - - // User logic ends - - endmodule + +`timescale 1 ns / 1 ps + + module amdc_eddy_current_sensor_v2_0 # + ( + // Users to add parameters here + + // User parameters ends + // Do not modify the parameters beyond this line + + + // Parameters of Axi Slave Bus Interface S00_AXI + parameter integer C_S00_AXI_DATA_WIDTH = 32, + parameter integer C_S00_AXI_ADDR_WIDTH = 5 + ) + ( + // Users to add ports here + input wire [1:0] sensor_data_in, + input wire enable, + input wire pwm_carrier_high, + input wire pwm_carrier_low, + + output wire [1:0] sensor_control_out, + output wire done, + output wire [2:0] debug, + // User ports ends + // Do not modify the ports beyond this line + + + // Ports of Axi Slave Bus Interface S00_AXI + input wire s00_axi_aclk, + input wire s00_axi_aresetn, + input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_awaddr, + input wire [2 : 0] s00_axi_awprot, + input wire s00_axi_awvalid, + output wire s00_axi_awready, + input wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_wdata, + input wire [(C_S00_AXI_DATA_WIDTH/8)-1 : 0] s00_axi_wstrb, + input wire s00_axi_wvalid, + output wire s00_axi_wready, + output wire [1 : 0] s00_axi_bresp, + output wire s00_axi_bvalid, + input wire s00_axi_bready, + input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_araddr, + input wire [2 : 0] s00_axi_arprot, + input wire s00_axi_arvalid, + output wire s00_axi_arready, + output wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_rdata, + output wire [1 : 0] s00_axi_rresp, + output wire s00_axi_rvalid, + input wire s00_axi_rready + ); +// Instantiation of Axi Bus Interface S00_AXI + amdc_eddy_current_sensor_v2_0_S00_AXI # ( + .C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH), + .C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH) + ) amdc_eddy_current_sensor_v2_0_S00_AXI_inst ( + .S_AXI_ACLK(s00_axi_aclk), + .S_AXI_ARESETN(s00_axi_aresetn), + .S_AXI_AWADDR(s00_axi_awaddr), + .S_AXI_AWPROT(s00_axi_awprot), + .S_AXI_AWVALID(s00_axi_awvalid), + .S_AXI_AWREADY(s00_axi_awready), + .S_AXI_WDATA(s00_axi_wdata), + .S_AXI_WSTRB(s00_axi_wstrb), + .S_AXI_WVALID(s00_axi_wvalid), + .S_AXI_WREADY(s00_axi_wready), + .S_AXI_BRESP(s00_axi_bresp), + .S_AXI_BVALID(s00_axi_bvalid), + .S_AXI_BREADY(s00_axi_bready), + .S_AXI_ARADDR(s00_axi_araddr), + .S_AXI_ARPROT(s00_axi_arprot), + .S_AXI_ARVALID(s00_axi_arvalid), + .S_AXI_ARREADY(s00_axi_arready), + .S_AXI_RDATA(s00_axi_rdata), + .S_AXI_RRESP(s00_axi_rresp), + .S_AXI_RVALID(s00_axi_rvalid), + .S_AXI_RREADY(s00_axi_rready), + .miso_x(sensor_data_in[0]), + .miso_y(sensor_data_in[1]), + .enable(enable), + .pwm_carrier_high(pwm_carrier_high), + .pwm_carrier_low(pwm_carrier_low), + .sclk(sensor_control_out[0]), + .cnv(sensor_control_out[1]), + .done(done), + .debug(debug) + ); + + // Add user logic here + + // User logic ends + + endmodule diff --git a/ip_repo/amdc_eddy_current_sensor_2.0/hdl/amdc_eddy_current_sensor_v2_0_S00_AXI.v b/ip_repo/amdc_eddy_current_sensor_2.0/hdl/amdc_eddy_current_sensor_v2_0_S00_AXI.v index c2f91e68..07832c22 100644 --- a/ip_repo/amdc_eddy_current_sensor_2.0/hdl/amdc_eddy_current_sensor_v2_0_S00_AXI.v +++ b/ip_repo/amdc_eddy_current_sensor_2.0/hdl/amdc_eddy_current_sensor_v2_0_S00_AXI.v @@ -1,531 +1,531 @@ - -`timescale 1 ns / 1 ps - - module amdc_eddy_current_sensor_v2_0_S00_AXI # - ( - // Users to add parameters here - - // User parameters ends - // Do not modify the parameters beyond this line - - // Width of S_AXI data bus - parameter integer C_S_AXI_DATA_WIDTH = 32, - // Width of S_AXI address bus - parameter integer C_S_AXI_ADDR_WIDTH = 5 - ) - ( - // Users to add ports here - input wire miso_x, - input wire miso_y, - input wire enable, - input wire pwm_carrier_high, - input wire pwm_carrier_low, - - output wire sclk, - output wire cnv, - output wire done, - output wire [2:0] debug, - // User ports ends - // Do not modify the ports beyond this line - - // Global Clock Signal - input wire S_AXI_ACLK, - // Global Reset Signal. This Signal is Active LOW - input wire S_AXI_ARESETN, - // Write address (issued by master, acceped by Slave) - input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR, - // Write channel Protection type. This signal indicates the - // privilege and security level of the transaction, and whether - // the transaction is a data access or an instruction access. - input wire [2 : 0] S_AXI_AWPROT, - // Write address valid. This signal indicates that the master signaling - // valid write address and control information. - input wire S_AXI_AWVALID, - // Write address ready. This signal indicates that the slave is ready - // to accept an address and associated control signals. - output wire S_AXI_AWREADY, - // Write data (issued by master, acceped by Slave) - input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA, - // Write strobes. This signal indicates which byte lanes hold - // valid data. There is one write strobe bit for each eight - // bits of the write data bus. - input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB, - // Write valid. This signal indicates that valid write - // data and strobes are available. - input wire S_AXI_WVALID, - // Write ready. This signal indicates that the slave - // can accept the write data. - output wire S_AXI_WREADY, - // Write response. This signal indicates the status - // of the write transaction. - output wire [1 : 0] S_AXI_BRESP, - // Write response valid. This signal indicates that the channel - // is signaling a valid write response. - output wire S_AXI_BVALID, - // Response ready. This signal indicates that the master - // can accept a write response. - input wire S_AXI_BREADY, - // Read address (issued by master, acceped by Slave) - input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR, - // Protection type. This signal indicates the privilege - // and security level of the transaction, and whether the - // transaction is a data access or an instruction access. - input wire [2 : 0] S_AXI_ARPROT, - // Read address valid. This signal indicates that the channel - // is signaling valid read address and control information. - input wire S_AXI_ARVALID, - // Read address ready. This signal indicates that the slave is - // ready to accept an address and associated control signals. - output wire S_AXI_ARREADY, - // Read data (issued by slave) - output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA, - // Read response. This signal indicates the status of the - // read transfer. - output wire [1 : 0] S_AXI_RRESP, - // Read valid. This signal indicates that the channel is - // signaling the required read data. - output wire S_AXI_RVALID, - // Read ready. This signal indicates that the master can - // accept the read data and response information. - input wire S_AXI_RREADY - ); - reg [31:0] data_x_out; - reg [31:0] data_y_out; - - // AXI4LITE signals - reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr; - reg axi_awready; - reg axi_wready; - reg [1 : 0] axi_bresp; - reg axi_bvalid; - reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr; - reg axi_arready; - reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata; - reg [1 : 0] axi_rresp; - reg axi_rvalid; - - // Example-specific design signals - // local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH - // ADDR_LSB is used for addressing 32/64 bit registers/memories - // ADDR_LSB = 2 for 32 bits (n downto 2) - // ADDR_LSB = 3 for 64 bits (n downto 3) - localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1; - localparam integer OPT_MEM_ADDR_BITS = 2; - //---------------------------------------------- - //-- Signals for user logic register space example - //------------------------------------------------ - //-- Number of Slave Registers 8 - reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg0; - reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg1; - reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg2; - reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg3; - reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg4; - reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg5; - reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg6; - reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg7; - wire slv_reg_rden; - wire slv_reg_wren; - reg [C_S_AXI_DATA_WIDTH-1:0] reg_data_out; - integer byte_index; - reg aw_en; - - // I/O Connections assignments - - assign S_AXI_AWREADY = axi_awready; - assign S_AXI_WREADY = axi_wready; - assign S_AXI_BRESP = axi_bresp; - assign S_AXI_BVALID = axi_bvalid; - assign S_AXI_ARREADY = axi_arready; - assign S_AXI_RDATA = axi_rdata; - assign S_AXI_RRESP = axi_rresp; - assign S_AXI_RVALID = axi_rvalid; - // Implement axi_awready generation - // axi_awready is asserted for one S_AXI_ACLK clock cycle when both - // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is - // de-asserted when reset is low. - - always @( posedge S_AXI_ACLK ) - begin - if ( S_AXI_ARESETN == 1'b0 ) - begin - axi_awready <= 1'b0; - aw_en <= 1'b1; - end - else - begin - if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en) - begin - // slave is ready to accept write address when - // there is a valid write address and write data - // on the write address and data bus. This design - // expects no outstanding transactions. - axi_awready <= 1'b1; - aw_en <= 1'b0; - end - else if (S_AXI_BREADY && axi_bvalid) - begin - aw_en <= 1'b1; - axi_awready <= 1'b0; - end - else - begin - axi_awready <= 1'b0; - end - end - end - - // Implement axi_awaddr latching - // This process is used to latch the address when both - // S_AXI_AWVALID and S_AXI_WVALID are valid. - - always @( posedge S_AXI_ACLK ) - begin - if ( S_AXI_ARESETN == 1'b0 ) - begin - axi_awaddr <= 0; - end - else - begin - if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en) - begin - // Write Address latching - axi_awaddr <= S_AXI_AWADDR; - end - end - end - - // Implement axi_wready generation - // axi_wready is asserted for one S_AXI_ACLK clock cycle when both - // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is - // de-asserted when reset is low. - - always @( posedge S_AXI_ACLK ) - begin - if ( S_AXI_ARESETN == 1'b0 ) - begin - axi_wready <= 1'b0; - end - else - begin - if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID && aw_en ) - begin - // slave is ready to accept write data when - // there is a valid write address and write data - // on the write address and data bus. This design - // expects no outstanding transactions. - axi_wready <= 1'b1; - end - else - begin - axi_wready <= 1'b0; - end - end - end - - // Implement memory mapped register select and write logic generation - // The write data is accepted and written to memory mapped registers when - // axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to - // select byte enables of slave registers while writing. - // These registers are cleared when reset (active low) is applied. - // Slave register write enable is asserted when valid address and data are available - // and the slave is ready to accept the write address and write data. - assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID; - - always @( posedge S_AXI_ACLK ) - begin - if ( S_AXI_ARESETN == 1'b0 ) - begin - slv_reg0 <= 0; - slv_reg1 <= 0; - slv_reg2 <= 0; - slv_reg3 <= 0; - slv_reg4 <= 0; - slv_reg5 <= 0; - slv_reg6 <= 0; - slv_reg7 <= 0; - end - else begin - if (slv_reg_wren) - begin - case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] ) - 3'h0: - for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) - if ( S_AXI_WSTRB[byte_index] == 1 ) begin - // Respective byte enables are asserted as per write strobes - // Slave register 0 - slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; - end - 3'h1: - for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) - if ( S_AXI_WSTRB[byte_index] == 1 ) begin - // Respective byte enables are asserted as per write strobes - // Slave register 1 - slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; - end - 3'h2: - for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) - if ( S_AXI_WSTRB[byte_index] == 1 ) begin - // Respective byte enables are asserted as per write strobes - // Slave register 2 - slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; - end - 3'h3: - for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) - if ( S_AXI_WSTRB[byte_index] == 1 ) begin - // Respective byte enables are asserted as per write strobes - // Slave register 3 - slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; - end - 3'h4: - for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) - if ( S_AXI_WSTRB[byte_index] == 1 ) begin - // Respective byte enables are asserted as per write strobes - // Slave register 4 - slv_reg4[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; - end - 3'h5: - for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) - if ( S_AXI_WSTRB[byte_index] == 1 ) begin - // Respective byte enables are asserted as per write strobes - // Slave register 5 - slv_reg5[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; - end - 3'h6: - for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) - if ( S_AXI_WSTRB[byte_index] == 1 ) begin - // Respective byte enables are asserted as per write strobes - // Slave register 6 - slv_reg6[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; - end - 3'h7: - for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) - if ( S_AXI_WSTRB[byte_index] == 1 ) begin - // Respective byte enables are asserted as per write strobes - // Slave register 7 - slv_reg7[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; - end - default : begin - slv_reg0 <= slv_reg0; - slv_reg1 <= slv_reg1; - slv_reg2 <= slv_reg2; - slv_reg3 <= slv_reg3; - slv_reg4 <= slv_reg4; - slv_reg5 <= slv_reg5; - slv_reg6 <= slv_reg6; - slv_reg7 <= slv_reg7; - end - endcase - end - end - end - - // Implement write response logic generation - // The write response and response valid signals are asserted by the slave - // when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. - // This marks the acceptance of address and indicates the status of - // write transaction. - - always @( posedge S_AXI_ACLK ) - begin - if ( S_AXI_ARESETN == 1'b0 ) - begin - axi_bvalid <= 0; - axi_bresp <= 2'b0; - end - else - begin - if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID) - begin - // indicates a valid write response is available - axi_bvalid <= 1'b1; - axi_bresp <= 2'b0; // 'OKAY' response - end // work error responses in future - else - begin - if (S_AXI_BREADY && axi_bvalid) - //check if bready is asserted while bvalid is high) - //(there is a possibility that bready is always asserted high) - begin - axi_bvalid <= 1'b0; - end - end - end - end - - // Implement axi_arready generation - // axi_arready is asserted for one S_AXI_ACLK clock cycle when - // S_AXI_ARVALID is asserted. axi_awready is - // de-asserted when reset (active low) is asserted. - // The read address is also latched when S_AXI_ARVALID is - // asserted. axi_araddr is reset to zero on reset assertion. - - always @( posedge S_AXI_ACLK ) - begin - if ( S_AXI_ARESETN == 1'b0 ) - begin - axi_arready <= 1'b0; - axi_araddr <= 32'b0; - end - else - begin - if (~axi_arready && S_AXI_ARVALID) - begin - // indicates that the slave has acceped the valid read address - axi_arready <= 1'b1; - // Read address latching - axi_araddr <= S_AXI_ARADDR; - end - else - begin - axi_arready <= 1'b0; - end - end - end - - // Implement axi_arvalid generation - // axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both - // S_AXI_ARVALID and axi_arready are asserted. The slave registers - // data are available on the axi_rdata bus at this instance. The - // assertion of axi_rvalid marks the validity of read data on the - // bus and axi_rresp indicates the status of read transaction.axi_rvalid - // is deasserted on reset (active low). axi_rresp and axi_rdata are - // cleared to zero on reset (active low). - always @( posedge S_AXI_ACLK ) - begin - if ( S_AXI_ARESETN == 1'b0 ) - begin - axi_rvalid <= 0; - axi_rresp <= 0; - end - else - begin - if (axi_arready && S_AXI_ARVALID && ~axi_rvalid) - begin - // Valid read data is available at the read data bus - axi_rvalid <= 1'b1; - axi_rresp <= 2'b0; // 'OKAY' response - end - else if (axi_rvalid && S_AXI_RREADY) - begin - // Read data is accepted by the master - axi_rvalid <= 1'b0; - end - end - end - - // Implement memory mapped register select and read logic generation - // Slave register read enable is asserted when valid address is available - // and the slave is ready to accept the read address. - assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid; - always @(*) - begin - // Address decoding for reading registers - case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] ) - 3'h0 : reg_data_out <= data_x_out; - 3'h1 : reg_data_out <= data_y_out; - 3'h2 : reg_data_out <= slv_reg2; - 3'h3 : reg_data_out <= slv_reg3; - 3'h4 : reg_data_out <= slv_reg4; - 3'h5 : reg_data_out <= slv_reg5; - 3'h6 : reg_data_out <= slv_reg6; - 3'h7 : reg_data_out <= slv_reg7; - default : reg_data_out <= 0; - endcase - end - - // Output register or memory read data - always @( posedge S_AXI_ACLK ) - begin - if ( S_AXI_ARESETN == 1'b0 ) - begin - axi_rdata <= 0; - end - else - begin - // When there is a valid read address (S_AXI_ARVALID) with - // acceptance of read address by the slave (axi_arready), - // output the read data - if (slv_reg_rden) - begin - axi_rdata <= reg_data_out; // register read data - end - end - end - - // Add user logic here - reg [7:0] sclk_cnt, shift_index; - reg trigger_on_high, trigger_on_low; - - always @(posedge S_AXI_ACLK, negedge S_AXI_ARESETN) begin - if(!S_AXI_ARESETN) begin - sclk_cnt <= 8'b0; - trigger_on_high <= 1'b0; - trigger_on_low <= 1'b0; - shift_index <= 8'b0; - end - else if(pwm_carrier_high | pwm_carrier_low) begin - sclk_cnt <= slv_reg2[7:0]; - trigger_on_high <= slv_reg3[0]; - trigger_on_low <= slv_reg3[1]; - shift_index <= slv_reg4[7:0]; - end - end - - // Synchronize SPI master ADC driver to start with the PWM carrier - wire trigger; - assign trigger = (pwm_carrier_high & trigger_on_high) | (pwm_carrier_low & trigger_on_low); - - // These are used to capture the output of the SPI Master (shift registers) and put - // in the AXI memory-mapped registers (see below) to be read by C driver - wire [17:0] sensor_data_x, sensor_data_y; - - amdc_spi_master iSPI_MASTER( - ///////////////// - // INPUTS - ////////////// - - // From AXI - .clk(S_AXI_ACLK), - .rst_n(S_AXI_ARESETN), - - // PWM-Synchronized Conversion Initiation - .trigger(enable & trigger), - - // From ADCs - .miso_x(miso_x), - .miso_y(miso_y), - - // SCLK frequency parameter configured by C driver - .sclk_cnt(sclk_cnt), - - // How long to delay shift signal (depends on RC filter on adapter board) - .shift_index(shift_index), - - ////////////////// - // OUTPUTS - //////////////// - - // To x and y ADCs - .sclk(sclk), - .cnv(cnv), - - // Out - .sensor_data_x(sensor_data_x), - .sensor_data_y(sensor_data_y), - .done(done), - .debug(debug) - ); - - always @(posedge S_AXI_ACLK, negedge S_AXI_ARESETN) begin - if(!S_AXI_ARESETN) begin - data_x_out <= 32'b0; - data_y_out <= 32'b0; - end - else if(done) begin - data_x_out <= {{14{sensor_data_x[17]}},sensor_data_x}; - data_y_out <= {{14{sensor_data_y[17]}},sensor_data_y}; - end - end - // User logic ends - - endmodule + +`timescale 1 ns / 1 ps + + module amdc_eddy_current_sensor_v2_0_S00_AXI # + ( + // Users to add parameters here + + // User parameters ends + // Do not modify the parameters beyond this line + + // Width of S_AXI data bus + parameter integer C_S_AXI_DATA_WIDTH = 32, + // Width of S_AXI address bus + parameter integer C_S_AXI_ADDR_WIDTH = 5 + ) + ( + // Users to add ports here + input wire miso_x, + input wire miso_y, + input wire enable, + input wire pwm_carrier_high, + input wire pwm_carrier_low, + + output wire sclk, + output wire cnv, + output wire done, + output wire [2:0] debug, + // User ports ends + // Do not modify the ports beyond this line + + // Global Clock Signal + input wire S_AXI_ACLK, + // Global Reset Signal. This Signal is Active LOW + input wire S_AXI_ARESETN, + // Write address (issued by master, acceped by Slave) + input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR, + // Write channel Protection type. This signal indicates the + // privilege and security level of the transaction, and whether + // the transaction is a data access or an instruction access. + input wire [2 : 0] S_AXI_AWPROT, + // Write address valid. This signal indicates that the master signaling + // valid write address and control information. + input wire S_AXI_AWVALID, + // Write address ready. This signal indicates that the slave is ready + // to accept an address and associated control signals. + output wire S_AXI_AWREADY, + // Write data (issued by master, acceped by Slave) + input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA, + // Write strobes. This signal indicates which byte lanes hold + // valid data. There is one write strobe bit for each eight + // bits of the write data bus. + input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB, + // Write valid. This signal indicates that valid write + // data and strobes are available. + input wire S_AXI_WVALID, + // Write ready. This signal indicates that the slave + // can accept the write data. + output wire S_AXI_WREADY, + // Write response. This signal indicates the status + // of the write transaction. + output wire [1 : 0] S_AXI_BRESP, + // Write response valid. This signal indicates that the channel + // is signaling a valid write response. + output wire S_AXI_BVALID, + // Response ready. This signal indicates that the master + // can accept a write response. + input wire S_AXI_BREADY, + // Read address (issued by master, acceped by Slave) + input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR, + // Protection type. This signal indicates the privilege + // and security level of the transaction, and whether the + // transaction is a data access or an instruction access. + input wire [2 : 0] S_AXI_ARPROT, + // Read address valid. This signal indicates that the channel + // is signaling valid read address and control information. + input wire S_AXI_ARVALID, + // Read address ready. This signal indicates that the slave is + // ready to accept an address and associated control signals. + output wire S_AXI_ARREADY, + // Read data (issued by slave) + output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA, + // Read response. This signal indicates the status of the + // read transfer. + output wire [1 : 0] S_AXI_RRESP, + // Read valid. This signal indicates that the channel is + // signaling the required read data. + output wire S_AXI_RVALID, + // Read ready. This signal indicates that the master can + // accept the read data and response information. + input wire S_AXI_RREADY + ); + reg [31:0] data_x_out; + reg [31:0] data_y_out; + + // AXI4LITE signals + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr; + reg axi_awready; + reg axi_wready; + reg [1 : 0] axi_bresp; + reg axi_bvalid; + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr; + reg axi_arready; + reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata; + reg [1 : 0] axi_rresp; + reg axi_rvalid; + + // Example-specific design signals + // local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH + // ADDR_LSB is used for addressing 32/64 bit registers/memories + // ADDR_LSB = 2 for 32 bits (n downto 2) + // ADDR_LSB = 3 for 64 bits (n downto 3) + localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1; + localparam integer OPT_MEM_ADDR_BITS = 2; + //---------------------------------------------- + //-- Signals for user logic register space example + //------------------------------------------------ + //-- Number of Slave Registers 8 + reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg0; + reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg1; + reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg2; + reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg3; + reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg4; + reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg5; + reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg6; + reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg7; + wire slv_reg_rden; + wire slv_reg_wren; + reg [C_S_AXI_DATA_WIDTH-1:0] reg_data_out; + integer byte_index; + reg aw_en; + + // I/O Connections assignments + + assign S_AXI_AWREADY = axi_awready; + assign S_AXI_WREADY = axi_wready; + assign S_AXI_BRESP = axi_bresp; + assign S_AXI_BVALID = axi_bvalid; + assign S_AXI_ARREADY = axi_arready; + assign S_AXI_RDATA = axi_rdata; + assign S_AXI_RRESP = axi_rresp; + assign S_AXI_RVALID = axi_rvalid; + // Implement axi_awready generation + // axi_awready is asserted for one S_AXI_ACLK clock cycle when both + // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is + // de-asserted when reset is low. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_awready <= 1'b0; + aw_en <= 1'b1; + end + else + begin + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en) + begin + // slave is ready to accept write address when + // there is a valid write address and write data + // on the write address and data bus. This design + // expects no outstanding transactions. + axi_awready <= 1'b1; + aw_en <= 1'b0; + end + else if (S_AXI_BREADY && axi_bvalid) + begin + aw_en <= 1'b1; + axi_awready <= 1'b0; + end + else + begin + axi_awready <= 1'b0; + end + end + end + + // Implement axi_awaddr latching + // This process is used to latch the address when both + // S_AXI_AWVALID and S_AXI_WVALID are valid. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_awaddr <= 0; + end + else + begin + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en) + begin + // Write Address latching + axi_awaddr <= S_AXI_AWADDR; + end + end + end + + // Implement axi_wready generation + // axi_wready is asserted for one S_AXI_ACLK clock cycle when both + // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is + // de-asserted when reset is low. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_wready <= 1'b0; + end + else + begin + if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID && aw_en ) + begin + // slave is ready to accept write data when + // there is a valid write address and write data + // on the write address and data bus. This design + // expects no outstanding transactions. + axi_wready <= 1'b1; + end + else + begin + axi_wready <= 1'b0; + end + end + end + + // Implement memory mapped register select and write logic generation + // The write data is accepted and written to memory mapped registers when + // axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to + // select byte enables of slave registers while writing. + // These registers are cleared when reset (active low) is applied. + // Slave register write enable is asserted when valid address and data are available + // and the slave is ready to accept the write address and write data. + assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID; + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + slv_reg0 <= 0; + slv_reg1 <= 0; + slv_reg2 <= 0; + slv_reg3 <= 0; + slv_reg4 <= 0; + slv_reg5 <= 0; + slv_reg6 <= 0; + slv_reg7 <= 0; + end + else begin + if (slv_reg_wren) + begin + case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] ) + 3'h0: + for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) + if ( S_AXI_WSTRB[byte_index] == 1 ) begin + // Respective byte enables are asserted as per write strobes + // Slave register 0 + slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; + end + 3'h1: + for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) + if ( S_AXI_WSTRB[byte_index] == 1 ) begin + // Respective byte enables are asserted as per write strobes + // Slave register 1 + slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; + end + 3'h2: + for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) + if ( S_AXI_WSTRB[byte_index] == 1 ) begin + // Respective byte enables are asserted as per write strobes + // Slave register 2 + slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; + end + 3'h3: + for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) + if ( S_AXI_WSTRB[byte_index] == 1 ) begin + // Respective byte enables are asserted as per write strobes + // Slave register 3 + slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; + end + 3'h4: + for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) + if ( S_AXI_WSTRB[byte_index] == 1 ) begin + // Respective byte enables are asserted as per write strobes + // Slave register 4 + slv_reg4[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; + end + 3'h5: + for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) + if ( S_AXI_WSTRB[byte_index] == 1 ) begin + // Respective byte enables are asserted as per write strobes + // Slave register 5 + slv_reg5[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; + end + 3'h6: + for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) + if ( S_AXI_WSTRB[byte_index] == 1 ) begin + // Respective byte enables are asserted as per write strobes + // Slave register 6 + slv_reg6[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; + end + 3'h7: + for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) + if ( S_AXI_WSTRB[byte_index] == 1 ) begin + // Respective byte enables are asserted as per write strobes + // Slave register 7 + slv_reg7[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; + end + default : begin + slv_reg0 <= slv_reg0; + slv_reg1 <= slv_reg1; + slv_reg2 <= slv_reg2; + slv_reg3 <= slv_reg3; + slv_reg4 <= slv_reg4; + slv_reg5 <= slv_reg5; + slv_reg6 <= slv_reg6; + slv_reg7 <= slv_reg7; + end + endcase + end + end + end + + // Implement write response logic generation + // The write response and response valid signals are asserted by the slave + // when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. + // This marks the acceptance of address and indicates the status of + // write transaction. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_bvalid <= 0; + axi_bresp <= 2'b0; + end + else + begin + if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID) + begin + // indicates a valid write response is available + axi_bvalid <= 1'b1; + axi_bresp <= 2'b0; // 'OKAY' response + end // work error responses in future + else + begin + if (S_AXI_BREADY && axi_bvalid) + //check if bready is asserted while bvalid is high) + //(there is a possibility that bready is always asserted high) + begin + axi_bvalid <= 1'b0; + end + end + end + end + + // Implement axi_arready generation + // axi_arready is asserted for one S_AXI_ACLK clock cycle when + // S_AXI_ARVALID is asserted. axi_awready is + // de-asserted when reset (active low) is asserted. + // The read address is also latched when S_AXI_ARVALID is + // asserted. axi_araddr is reset to zero on reset assertion. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_arready <= 1'b0; + axi_araddr <= 32'b0; + end + else + begin + if (~axi_arready && S_AXI_ARVALID) + begin + // indicates that the slave has acceped the valid read address + axi_arready <= 1'b1; + // Read address latching + axi_araddr <= S_AXI_ARADDR; + end + else + begin + axi_arready <= 1'b0; + end + end + end + + // Implement axi_arvalid generation + // axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both + // S_AXI_ARVALID and axi_arready are asserted. The slave registers + // data are available on the axi_rdata bus at this instance. The + // assertion of axi_rvalid marks the validity of read data on the + // bus and axi_rresp indicates the status of read transaction.axi_rvalid + // is deasserted on reset (active low). axi_rresp and axi_rdata are + // cleared to zero on reset (active low). + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_rvalid <= 0; + axi_rresp <= 0; + end + else + begin + if (axi_arready && S_AXI_ARVALID && ~axi_rvalid) + begin + // Valid read data is available at the read data bus + axi_rvalid <= 1'b1; + axi_rresp <= 2'b0; // 'OKAY' response + end + else if (axi_rvalid && S_AXI_RREADY) + begin + // Read data is accepted by the master + axi_rvalid <= 1'b0; + end + end + end + + // Implement memory mapped register select and read logic generation + // Slave register read enable is asserted when valid address is available + // and the slave is ready to accept the read address. + assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid; + always @(*) + begin + // Address decoding for reading registers + case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] ) + 3'h0 : reg_data_out <= data_x_out; + 3'h1 : reg_data_out <= data_y_out; + 3'h2 : reg_data_out <= slv_reg2; + 3'h3 : reg_data_out <= slv_reg3; + 3'h4 : reg_data_out <= slv_reg4; + 3'h5 : reg_data_out <= slv_reg5; + 3'h6 : reg_data_out <= slv_reg6; + 3'h7 : reg_data_out <= slv_reg7; + default : reg_data_out <= 0; + endcase + end + + // Output register or memory read data + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_rdata <= 0; + end + else + begin + // When there is a valid read address (S_AXI_ARVALID) with + // acceptance of read address by the slave (axi_arready), + // output the read data + if (slv_reg_rden) + begin + axi_rdata <= reg_data_out; // register read data + end + end + end + + // Add user logic here + reg [7:0] sclk_cnt, shift_index; + reg trigger_on_high, trigger_on_low; + + always @(posedge S_AXI_ACLK, negedge S_AXI_ARESETN) begin + if(!S_AXI_ARESETN) begin + sclk_cnt <= 8'b0; + trigger_on_high <= 1'b0; + trigger_on_low <= 1'b0; + shift_index <= 8'b0; + end + else if(pwm_carrier_high | pwm_carrier_low) begin + sclk_cnt <= slv_reg2[7:0]; + trigger_on_high <= slv_reg3[0]; + trigger_on_low <= slv_reg3[1]; + shift_index <= slv_reg4[7:0]; + end + end + + // Synchronize SPI master ADC driver to start with the PWM carrier + wire trigger; + assign trigger = (pwm_carrier_high & trigger_on_high) | (pwm_carrier_low & trigger_on_low); + + // These are used to capture the output of the SPI Master (shift registers) and put + // in the AXI memory-mapped registers (see below) to be read by C driver + wire [17:0] sensor_data_x, sensor_data_y; + + amdc_spi_master iSPI_MASTER( + ///////////////// + // INPUTS + ////////////// + + // From AXI + .clk(S_AXI_ACLK), + .rst_n(S_AXI_ARESETN), + + // PWM-Synchronized Conversion Initiation + .trigger(enable & trigger), + + // From ADCs + .miso_x(miso_x), + .miso_y(miso_y), + + // SCLK frequency parameter configured by C driver + .sclk_cnt(sclk_cnt), + + // How long to delay shift signal (depends on RC filter on adapter board) + .shift_index(shift_index), + + ////////////////// + // OUTPUTS + //////////////// + + // To x and y ADCs + .sclk(sclk), + .cnv(cnv), + + // Out + .sensor_data_x(sensor_data_x), + .sensor_data_y(sensor_data_y), + .done(done), + .debug(debug) + ); + + always @(posedge S_AXI_ACLK, negedge S_AXI_ARESETN) begin + if(!S_AXI_ARESETN) begin + data_x_out <= 32'b0; + data_y_out <= 32'b0; + end + else if(done) begin + data_x_out <= {{14{sensor_data_x[17]}},sensor_data_x}; + data_y_out <= {{14{sensor_data_y[17]}},sensor_data_y}; + end + end + // User logic ends + + endmodule diff --git a/ip_repo/amdc_eddy_current_sensor_2.0/xgui/amdc_eddy_current_sensor_v2_0.tcl b/ip_repo/amdc_eddy_current_sensor_2.0/xgui/amdc_eddy_current_sensor_v2_0.tcl index 44d2eddc..d8bf1744 100644 --- a/ip_repo/amdc_eddy_current_sensor_2.0/xgui/amdc_eddy_current_sensor_v2_0.tcl +++ b/ip_repo/amdc_eddy_current_sensor_2.0/xgui/amdc_eddy_current_sensor_v2_0.tcl @@ -1,62 +1,62 @@ -# Definitional proc to organize widgets for parameters. -proc init_gui { IPINST } { - ipgui::add_param $IPINST -name "Component_Name" - #Adding Page - set Page_0 [ipgui::add_page $IPINST -name "Page 0"] - set C_S00_AXI_DATA_WIDTH [ipgui::add_param $IPINST -name "C_S00_AXI_DATA_WIDTH" -parent ${Page_0} -widget comboBox] - set_property tooltip {Width of S_AXI data bus} ${C_S00_AXI_DATA_WIDTH} - set C_S00_AXI_ADDR_WIDTH [ipgui::add_param $IPINST -name "C_S00_AXI_ADDR_WIDTH" -parent ${Page_0}] - set_property tooltip {Width of S_AXI address bus} ${C_S00_AXI_ADDR_WIDTH} - ipgui::add_param $IPINST -name "C_S00_AXI_BASEADDR" -parent ${Page_0} - ipgui::add_param $IPINST -name "C_S00_AXI_HIGHADDR" -parent ${Page_0} - - -} - -proc update_PARAM_VALUE.C_S00_AXI_DATA_WIDTH { PARAM_VALUE.C_S00_AXI_DATA_WIDTH } { - # Procedure called to update C_S00_AXI_DATA_WIDTH when any of the dependent parameters in the arguments change -} - -proc validate_PARAM_VALUE.C_S00_AXI_DATA_WIDTH { PARAM_VALUE.C_S00_AXI_DATA_WIDTH } { - # Procedure called to validate C_S00_AXI_DATA_WIDTH - return true -} - -proc update_PARAM_VALUE.C_S00_AXI_ADDR_WIDTH { PARAM_VALUE.C_S00_AXI_ADDR_WIDTH } { - # Procedure called to update C_S00_AXI_ADDR_WIDTH when any of the dependent parameters in the arguments change -} - -proc validate_PARAM_VALUE.C_S00_AXI_ADDR_WIDTH { PARAM_VALUE.C_S00_AXI_ADDR_WIDTH } { - # Procedure called to validate C_S00_AXI_ADDR_WIDTH - return true -} - -proc update_PARAM_VALUE.C_S00_AXI_BASEADDR { PARAM_VALUE.C_S00_AXI_BASEADDR } { - # Procedure called to update C_S00_AXI_BASEADDR when any of the dependent parameters in the arguments change -} - -proc validate_PARAM_VALUE.C_S00_AXI_BASEADDR { PARAM_VALUE.C_S00_AXI_BASEADDR } { - # Procedure called to validate C_S00_AXI_BASEADDR - return true -} - -proc update_PARAM_VALUE.C_S00_AXI_HIGHADDR { PARAM_VALUE.C_S00_AXI_HIGHADDR } { - # Procedure called to update C_S00_AXI_HIGHADDR when any of the dependent parameters in the arguments change -} - -proc validate_PARAM_VALUE.C_S00_AXI_HIGHADDR { PARAM_VALUE.C_S00_AXI_HIGHADDR } { - # Procedure called to validate C_S00_AXI_HIGHADDR - return true -} - - -proc update_MODELPARAM_VALUE.C_S00_AXI_DATA_WIDTH { MODELPARAM_VALUE.C_S00_AXI_DATA_WIDTH PARAM_VALUE.C_S00_AXI_DATA_WIDTH } { - # Procedure called to set VHDL generic/Verilog parameter value(s) based on TCL parameter value - set_property value [get_property value ${PARAM_VALUE.C_S00_AXI_DATA_WIDTH}] ${MODELPARAM_VALUE.C_S00_AXI_DATA_WIDTH} -} - -proc update_MODELPARAM_VALUE.C_S00_AXI_ADDR_WIDTH { MODELPARAM_VALUE.C_S00_AXI_ADDR_WIDTH PARAM_VALUE.C_S00_AXI_ADDR_WIDTH } { - # Procedure called to set VHDL generic/Verilog parameter value(s) based on TCL parameter value - set_property value [get_property value ${PARAM_VALUE.C_S00_AXI_ADDR_WIDTH}] ${MODELPARAM_VALUE.C_S00_AXI_ADDR_WIDTH} -} - +# Definitional proc to organize widgets for parameters. +proc init_gui { IPINST } { + ipgui::add_param $IPINST -name "Component_Name" + #Adding Page + set Page_0 [ipgui::add_page $IPINST -name "Page 0"] + set C_S00_AXI_DATA_WIDTH [ipgui::add_param $IPINST -name "C_S00_AXI_DATA_WIDTH" -parent ${Page_0} -widget comboBox] + set_property tooltip {Width of S_AXI data bus} ${C_S00_AXI_DATA_WIDTH} + set C_S00_AXI_ADDR_WIDTH [ipgui::add_param $IPINST -name "C_S00_AXI_ADDR_WIDTH" -parent ${Page_0}] + set_property tooltip {Width of S_AXI address bus} ${C_S00_AXI_ADDR_WIDTH} + ipgui::add_param $IPINST -name "C_S00_AXI_BASEADDR" -parent ${Page_0} + ipgui::add_param $IPINST -name "C_S00_AXI_HIGHADDR" -parent ${Page_0} + + +} + +proc update_PARAM_VALUE.C_S00_AXI_DATA_WIDTH { PARAM_VALUE.C_S00_AXI_DATA_WIDTH } { + # Procedure called to update C_S00_AXI_DATA_WIDTH when any of the dependent parameters in the arguments change +} + +proc validate_PARAM_VALUE.C_S00_AXI_DATA_WIDTH { PARAM_VALUE.C_S00_AXI_DATA_WIDTH } { + # Procedure called to validate C_S00_AXI_DATA_WIDTH + return true +} + +proc update_PARAM_VALUE.C_S00_AXI_ADDR_WIDTH { PARAM_VALUE.C_S00_AXI_ADDR_WIDTH } { + # Procedure called to update C_S00_AXI_ADDR_WIDTH when any of the dependent parameters in the arguments change +} + +proc validate_PARAM_VALUE.C_S00_AXI_ADDR_WIDTH { PARAM_VALUE.C_S00_AXI_ADDR_WIDTH } { + # Procedure called to validate C_S00_AXI_ADDR_WIDTH + return true +} + +proc update_PARAM_VALUE.C_S00_AXI_BASEADDR { PARAM_VALUE.C_S00_AXI_BASEADDR } { + # Procedure called to update C_S00_AXI_BASEADDR when any of the dependent parameters in the arguments change +} + +proc validate_PARAM_VALUE.C_S00_AXI_BASEADDR { PARAM_VALUE.C_S00_AXI_BASEADDR } { + # Procedure called to validate C_S00_AXI_BASEADDR + return true +} + +proc update_PARAM_VALUE.C_S00_AXI_HIGHADDR { PARAM_VALUE.C_S00_AXI_HIGHADDR } { + # Procedure called to update C_S00_AXI_HIGHADDR when any of the dependent parameters in the arguments change +} + +proc validate_PARAM_VALUE.C_S00_AXI_HIGHADDR { PARAM_VALUE.C_S00_AXI_HIGHADDR } { + # Procedure called to validate C_S00_AXI_HIGHADDR + return true +} + + +proc update_MODELPARAM_VALUE.C_S00_AXI_DATA_WIDTH { MODELPARAM_VALUE.C_S00_AXI_DATA_WIDTH PARAM_VALUE.C_S00_AXI_DATA_WIDTH } { + # Procedure called to set VHDL generic/Verilog parameter value(s) based on TCL parameter value + set_property value [get_property value ${PARAM_VALUE.C_S00_AXI_DATA_WIDTH}] ${MODELPARAM_VALUE.C_S00_AXI_DATA_WIDTH} +} + +proc update_MODELPARAM_VALUE.C_S00_AXI_ADDR_WIDTH { MODELPARAM_VALUE.C_S00_AXI_ADDR_WIDTH PARAM_VALUE.C_S00_AXI_ADDR_WIDTH } { + # Procedure called to set VHDL generic/Verilog parameter value(s) based on TCL parameter value + set_property value [get_property value ${PARAM_VALUE.C_S00_AXI_ADDR_WIDTH}] ${MODELPARAM_VALUE.C_S00_AXI_ADDR_WIDTH} +} + diff --git a/scripts/clang-format b/scripts/clang-format old mode 100755 new mode 100644 diff --git a/scripts/format.sh b/scripts/format.sh old mode 100755 new mode 100644 diff --git a/sdk/FreeRTOS-Kernel b/sdk/FreeRTOS-Kernel index c0ce7252..0452603a 160000 --- a/sdk/FreeRTOS-Kernel +++ b/sdk/FreeRTOS-Kernel @@ -1 +1 @@ -Subproject commit c0ce725293bb8cf9b30626a8bba173af33163533 +Subproject commit 0452603a943e13d27e7117f7112c4dd000748705 diff --git a/sdk/basic/.cproject b/sdk/basic/.cproject old mode 100755 new mode 100644 index b7e3c292..c6d14cae --- a/sdk/basic/.cproject +++ b/sdk/basic/.cproject @@ -1,174 +1,174 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/basic/.project b/sdk/basic/.project old mode 100755 new mode 100644 index d69b79ff..b6e2aa0d --- a/sdk/basic/.project +++ b/sdk/basic/.project @@ -1,26 +1,26 @@ - - - basic - Created by SDK v2017.2. amdc_bsp - ps7_cortexa9_0 - - amdc_bsp - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - - org.eclipse.cdt.core.cnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - - + + + basic + Created by SDK v2017.2. amdc_bsp - ps7_cortexa9_0 + + amdc_bsp + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/sdk/basic/control_apps/HBridge_CC.c b/sdk/basic/control_apps/HBridge_CC.c old mode 100755 new mode 100644 index 55c30db9..67669c5d --- a/sdk/basic/control_apps/HBridge_CC.c +++ b/sdk/basic/control_apps/HBridge_CC.c @@ -1,437 +1,437 @@ -/* - * HBridge_CC_8Leg.c - * - * Created on: Jun 27, 2014 - * Author: sever212 - */ -#include "../src/project_include.h" - -#define KP_GAIN 0.452 -#define KiTs_GAIN 0.005 -#define ADC_SCALE 1 //(important to make sure this is recognized as a double and not an int) new: 3 amps per volt, wound around three times gives me a factor of 1 --OLD:3 amps per volt, wound around twice gives me a factor of 3/2 - - - -HB_context HB_Controllers[NUM_HBRIDGE]; -controller_linked_list_item cont_items [NUM_HBRIDGE]; - - -//Logging -u32 HB_H1_d1, HB_H1_d2, HB_H1_error, HB_H1_output, HB_H1_reference, HB_H1_Current, dummy; -u32 HB_H2_d1, HB_H2_d2, HB_H2_error, HB_H2_output, HB_H2_reference, HB_H2_Current; -u32 HB_H3_d1, HB_H3_d2, HB_H3_error, HB_H3_output, HB_H3_reference, HB_H3_Current; -u32 HB_H4_d1, HB_H4_d2, HB_H4_error, HB_H4_output, HB_H4_reference, HB_H4_Current; - -//callback declarations: -static void HB_Input(void *arg, struct controller_context *cnt); -static void HB_Output(void *arg, struct controller_context *cnt); - -static u8 ExampleHB_NeedsInput(void *arg, void *HBContext); -static void ExampleHB_WriteOutput(void *arg, void *HBContext); - - -/***************************** - * Init_VSI_DQ_VSPWM() - * Sets up the controllers memory to default values - * and optionally starts the controllers running. - * The default settings can be overridden by manually - * editing the HB_Controllers structure. - * - *StartAllControllers: if this is set to TRUE, all the - * controllers are registered in control.c and started. - *returns a success code - */ -int Init_HBridge_CC(u8 StartAllControllers) -{ - //pi_house *pi_ptr = HB_Controllers; - int i; - for (i = 0; i= NUM_HBRIDGE) - return INVALID_ARGUMENT; - if (cont_items[i].bRegistered == TRUE) - return INVALID_OPERATION; - - RegisterController(0, &cont_items[i]); - - return SUCCESS; -} - - -/***************************** - * Stop_HBridge_CC_Controller() - * Unregisters the HBridge current controller from control.c. - * - *HB: the HB number to unregister (1 - NUM_HBRIDGE) - *returns a success code - */ -int Stop_HBridge_CC_Controller(u32 HB) -{ - u32 i = HB-1; - if (i >= NUM_HBRIDGE) - return INVALID_ARGUMENT; - if (cont_items[i].bRegistered == TRUE) - UnregisterController(0, &cont_items[i]); - - return SUCCESS; -} - -/***************************** - * HBridge_CC_StopCommand() - * Process an ascii command for stopping the HB controllers - * Stop_HBridge_CC_Controller is called - * - *szCmd: incoming command - *szResponse: the response to the command - *CommDevice: pointer to information about the communication device - * this was received on - */ -int HBridge_CC_StopCommand(const char *szCmd, char *szResponse, void *CommDevice) -{ - int i; - for (i=0; i< NUM_HBRIDGE; i++) - Stop_HBridge_CC_Controller(i+1); - - strcpy(szResponse, "OK"); - return strlen(szResponse); -} - - -/***************************** - * HBridge_CC_StartCommand() - * Process an ascii command for starting HB current controllers - * Init_HBridge_CC_8Leg is called - * - *szCmd: incoming command - *szResponse: the response to the command - *CommDevice: pointer to information about the communication device - * this was received on - */ -int HBridge_CC_StartCommand(const char *szCmd, char *szResponse, void *CommDevice) -{ - Init_HBridge_CC(TRUE); - strcpy(szResponse, "OK"); - return strlen(szResponse); -} - -/***************************** - * HBridge_CC_Command() - * Process an ascii command for setting a reference current - * Syntax: n,val - * n is the Hbridge number (1 - NUM_HBRIDGE), - * val is the current reference value * 128 - * - *szCmd: incoming command - *szResponse: the response to the command - *CommDevice: pointer to information about the communication device - * this was received on - */ -int HBridge_CC_Command(const char * szCmd, char *szResponse, void *CommDevice) -{ - const char *ptr; - u32 hbridge = atoi(szCmd); - u8 bError = FALSE; - if (hbridge < 1 || hbridge > NUM_HBRIDGE) - bError = TRUE; - else - { - for (ptr = szCmd; ptr != &szCmd[strlen(szCmd)-1]; ptr++) - if (*ptr == ',') - break; - ptr++; //advance past the comma - if (ptr >= &szCmd[strlen(szCmd)]) - bError = TRUE; - else - { - double current_ref = ((double) atoi(ptr))/128; - if (HBridge_CC_SetCurrentRef(hbridge, current_ref) == SUCCESS) - strcpy(szResponse, "OK"); - else - bError = TRUE; - } - - } - if (bError) - strcpy(szResponse, "ERROR"); - - return strlen(szResponse); -} - - -/***************************** - * HBridge_CC_SetCurrentRef() - * Set a reference current for an H-Bridge - * - *hbridge: index of the HBridge to set the reference current of - * Should be 1 - NUM_HBRIDGE - *reference: the value of the new reference current - */ -int HBridge_CC_SetCurrentRef(u32 hbridge, double reference) -{ - if (hbridge < 1 || hbridge > NUM_HBRIDGE) - return INVALID_ARGUMENT; - HB_Controllers[hbridge-1].c.reference = reference; - - //logging: - switch(hbridge) - { - case 1: - HB_H1_reference = (s32)(128 * reference); - break; - case 2: - HB_H2_reference = (s32)(128 * reference); - break; - case 3: - HB_H3_reference = (s32)(128 * reference); - break; - case 4: - HB_H4_reference = (s32)(128 * reference); - break; - } - return SUCCESS; -} - - -//Internal function called by control.c before executing a controller -static void HB_Input(void *arg, struct controller_context *cnt) -{ - u32 i=0; - u32 *Herror, *Hcurrent; - Herror = &dummy; - Hcurrent = &dummy; - - for (i= 0; i< NUM_HBRIDGE; i++) - if (&HB_Controllers[i].c.io == cnt) - { - switch(i) - { - case 0: - Herror = &HB_H1_error; - Hcurrent = &HB_H1_Current; - break; - - case 1: - Herror = &HB_H2_error; - Hcurrent = &HB_H2_Current; - break; - - case 2: - Herror = &HB_H3_error; - Hcurrent = &HB_H3_Current; - break; - - case 3: - Herror = &HB_H4_error; - Hcurrent = &HB_H4_Current; - break; - - } - break; //we have our match - } - - if (i < NUM_HBRIDGE) - { - HB_Controllers[i].InputAtTickCount = MainTimerTimerTick; - - //get the input - HB_Controllers[i].get_input(HB_Controllers[i].input_arg, &HB_Controllers[i]); - - //calculate the error and store it - HB_Controllers[i].c.input = HB_Controllers[i].c.reference - HB_Controllers[i].I; - *Herror = (s32) (HB_Controllers[i].c.input*128); - *Hcurrent = (s32) (HB_Controllers[i].I*128); - } - else - ; //should not happen!! -} - -//Internal function called by control.c when an output is ready -static void HB_Output(void *arg, struct controller_context *cnt) -{ - u32 i = 0; - - //logging - u32 *Hd1, *Hd2, *Houtput; - Hd1 = &dummy; - Hd2 = &dummy; - Houtput = &dummy; - - for (i= 0; i< NUM_HBRIDGE; i++) - if (&HB_Controllers[i].c.io == cnt) - { - //logging - switch(i) - { - case 0: - Hd1 = &HB_H1_d1; - Hd2 = &HB_H1_d2; - Houtput = &HB_H1_output; - break; - - case 1: - Hd1 = &HB_H2_d1; - Hd2 = &HB_H2_d2; - Houtput = &HB_H2_output; - break; - - case 2: - Hd1 = &HB_H3_d1; - Hd2 = &HB_H3_d2; - Houtput = &HB_H3_output; - break; - - case 3: - Hd1 = &HB_H4_d1; - Hd2 = &HB_H4_d2; - Houtput = &HB_H4_output; - break; - } - break; - } - - if (i < NUM_HBRIDGE) - { - //safety to avoid roll-over: - if (HB_Controllers[i].c.output > 1.0) - HB_Controllers[i].c.output = 1.0; - if (HB_Controllers[i].c.output < -1.0) - HB_Controllers[i].c.output = -1.0; - - //calculate duty ratios - HB_Controllers[i].d[0] = (unsigned char) 127*(1 + HB_Controllers[i].c.output); - HB_Controllers[i].d[1] = (unsigned char) 127*(1 - HB_Controllers[i].c.output); - - //write them out: - HB_Controllers[i].write_output(HB_Controllers[i].output_arg, &HB_Controllers[i]); - - //logging - *Hd1 = HB_Controllers[i].d[0]; - *Hd2 = HB_Controllers[i].d[1]; - *Houtput = (s32) (HB_Controllers[i].c.output*128); - } - else - ; //should not happen!! -} - -//HB_Controllers[i].get_input = ExampleHB_NeedsInput; -//HB_Controllers[i].write_output = ExampleHB_WriteOutput; - -//return false -static u8 ExampleHB_NeedsInput(void *arg, void *HBContext) -{ - u32 i=0; - u32 adc_num = 0; - struct HB_context *cnt = HBContext; - - for (i= 0; i< NUM_HBRIDGE; i++) - if (&HB_Controllers[i] == cnt) - { - if (i == 0) - adc_num = 4; - else if (i == 1) - adc_num = 5; - else if (i == 2) - adc_num = 6; - else if (i == 3) - adc_num = 1; - break; //we have our match - } - - //measure the current and store it - if (i < NUM_HBRIDGE) - HB_Controllers[i].I = 0.6*ReadADC(adc_num); - else - ; //uh oh! should not get here! - - return FALSE; -} - - -//return false if ABC values set, true if DQ values set -static void ExampleHB_WriteOutput(void *arg, void *HBContext) -{ - u32 legs[2]; - struct HB_context *cnt = HBContext; - int i; - - legs[0] = 0; legs[1] = 0; legs[2] = 0; - for (i= 0; i< NUM_HBRIDGE; i++) - { - if (&HB_Controllers[i] == cnt) - { - if (i == 0) - { legs[0] = 5; legs[1] = 6; } - else if (i == 1) - { legs[0] = 13; legs[1] = 14; } - else if (i == 2) - { legs[0] = 17; legs[1] = 18; } - else if (i == 3) - { legs[0] = 11; legs[1] = 12; } - else - i = NUM_HBRIDGE; //safety, don't write out to other legs. - break; - } - } - - if (i < NUM_HBRIDGE) - { - //write them out: - WriteDutyRatio(legs[0], HB_Controllers[i].d[0]); - WriteDutyRatio(legs[1], HB_Controllers[i].d[1]); - } -} - +/* + * HBridge_CC_8Leg.c + * + * Created on: Jun 27, 2014 + * Author: sever212 + */ +#include "../src/project_include.h" + +#define KP_GAIN 0.452 +#define KiTs_GAIN 0.005 +#define ADC_SCALE 1 //(important to make sure this is recognized as a double and not an int) new: 3 amps per volt, wound around three times gives me a factor of 1 --OLD:3 amps per volt, wound around twice gives me a factor of 3/2 + + + +HB_context HB_Controllers[NUM_HBRIDGE]; +controller_linked_list_item cont_items [NUM_HBRIDGE]; + + +//Logging +u32 HB_H1_d1, HB_H1_d2, HB_H1_error, HB_H1_output, HB_H1_reference, HB_H1_Current, dummy; +u32 HB_H2_d1, HB_H2_d2, HB_H2_error, HB_H2_output, HB_H2_reference, HB_H2_Current; +u32 HB_H3_d1, HB_H3_d2, HB_H3_error, HB_H3_output, HB_H3_reference, HB_H3_Current; +u32 HB_H4_d1, HB_H4_d2, HB_H4_error, HB_H4_output, HB_H4_reference, HB_H4_Current; + +//callback declarations: +static void HB_Input(void *arg, struct controller_context *cnt); +static void HB_Output(void *arg, struct controller_context *cnt); + +static u8 ExampleHB_NeedsInput(void *arg, void *HBContext); +static void ExampleHB_WriteOutput(void *arg, void *HBContext); + + +/***************************** + * Init_VSI_DQ_VSPWM() + * Sets up the controllers memory to default values + * and optionally starts the controllers running. + * The default settings can be overridden by manually + * editing the HB_Controllers structure. + * + *StartAllControllers: if this is set to TRUE, all the + * controllers are registered in control.c and started. + *returns a success code + */ +int Init_HBridge_CC(u8 StartAllControllers) +{ + //pi_house *pi_ptr = HB_Controllers; + int i; + for (i = 0; i= NUM_HBRIDGE) + return INVALID_ARGUMENT; + if (cont_items[i].bRegistered == TRUE) + return INVALID_OPERATION; + + RegisterController(0, &cont_items[i]); + + return SUCCESS; +} + + +/***************************** + * Stop_HBridge_CC_Controller() + * Unregisters the HBridge current controller from control.c. + * + *HB: the HB number to unregister (1 - NUM_HBRIDGE) + *returns a success code + */ +int Stop_HBridge_CC_Controller(u32 HB) +{ + u32 i = HB-1; + if (i >= NUM_HBRIDGE) + return INVALID_ARGUMENT; + if (cont_items[i].bRegistered == TRUE) + UnregisterController(0, &cont_items[i]); + + return SUCCESS; +} + +/***************************** + * HBridge_CC_StopCommand() + * Process an ascii command for stopping the HB controllers + * Stop_HBridge_CC_Controller is called + * + *szCmd: incoming command + *szResponse: the response to the command + *CommDevice: pointer to information about the communication device + * this was received on + */ +int HBridge_CC_StopCommand(const char *szCmd, char *szResponse, void *CommDevice) +{ + int i; + for (i=0; i< NUM_HBRIDGE; i++) + Stop_HBridge_CC_Controller(i+1); + + strcpy(szResponse, "OK"); + return strlen(szResponse); +} + + +/***************************** + * HBridge_CC_StartCommand() + * Process an ascii command for starting HB current controllers + * Init_HBridge_CC_8Leg is called + * + *szCmd: incoming command + *szResponse: the response to the command + *CommDevice: pointer to information about the communication device + * this was received on + */ +int HBridge_CC_StartCommand(const char *szCmd, char *szResponse, void *CommDevice) +{ + Init_HBridge_CC(TRUE); + strcpy(szResponse, "OK"); + return strlen(szResponse); +} + +/***************************** + * HBridge_CC_Command() + * Process an ascii command for setting a reference current + * Syntax: n,val + * n is the Hbridge number (1 - NUM_HBRIDGE), + * val is the current reference value * 128 + * + *szCmd: incoming command + *szResponse: the response to the command + *CommDevice: pointer to information about the communication device + * this was received on + */ +int HBridge_CC_Command(const char * szCmd, char *szResponse, void *CommDevice) +{ + const char *ptr; + u32 hbridge = atoi(szCmd); + u8 bError = FALSE; + if (hbridge < 1 || hbridge > NUM_HBRIDGE) + bError = TRUE; + else + { + for (ptr = szCmd; ptr != &szCmd[strlen(szCmd)-1]; ptr++) + if (*ptr == ',') + break; + ptr++; //advance past the comma + if (ptr >= &szCmd[strlen(szCmd)]) + bError = TRUE; + else + { + double current_ref = ((double) atoi(ptr))/128; + if (HBridge_CC_SetCurrentRef(hbridge, current_ref) == SUCCESS) + strcpy(szResponse, "OK"); + else + bError = TRUE; + } + + } + if (bError) + strcpy(szResponse, "ERROR"); + + return strlen(szResponse); +} + + +/***************************** + * HBridge_CC_SetCurrentRef() + * Set a reference current for an H-Bridge + * + *hbridge: index of the HBridge to set the reference current of + * Should be 1 - NUM_HBRIDGE + *reference: the value of the new reference current + */ +int HBridge_CC_SetCurrentRef(u32 hbridge, double reference) +{ + if (hbridge < 1 || hbridge > NUM_HBRIDGE) + return INVALID_ARGUMENT; + HB_Controllers[hbridge-1].c.reference = reference; + + //logging: + switch(hbridge) + { + case 1: + HB_H1_reference = (s32)(128 * reference); + break; + case 2: + HB_H2_reference = (s32)(128 * reference); + break; + case 3: + HB_H3_reference = (s32)(128 * reference); + break; + case 4: + HB_H4_reference = (s32)(128 * reference); + break; + } + return SUCCESS; +} + + +//Internal function called by control.c before executing a controller +static void HB_Input(void *arg, struct controller_context *cnt) +{ + u32 i=0; + u32 *Herror, *Hcurrent; + Herror = &dummy; + Hcurrent = &dummy; + + for (i= 0; i< NUM_HBRIDGE; i++) + if (&HB_Controllers[i].c.io == cnt) + { + switch(i) + { + case 0: + Herror = &HB_H1_error; + Hcurrent = &HB_H1_Current; + break; + + case 1: + Herror = &HB_H2_error; + Hcurrent = &HB_H2_Current; + break; + + case 2: + Herror = &HB_H3_error; + Hcurrent = &HB_H3_Current; + break; + + case 3: + Herror = &HB_H4_error; + Hcurrent = &HB_H4_Current; + break; + + } + break; //we have our match + } + + if (i < NUM_HBRIDGE) + { + HB_Controllers[i].InputAtTickCount = MainTimerTimerTick; + + //get the input + HB_Controllers[i].get_input(HB_Controllers[i].input_arg, &HB_Controllers[i]); + + //calculate the error and store it + HB_Controllers[i].c.input = HB_Controllers[i].c.reference - HB_Controllers[i].I; + *Herror = (s32) (HB_Controllers[i].c.input*128); + *Hcurrent = (s32) (HB_Controllers[i].I*128); + } + else + ; //should not happen!! +} + +//Internal function called by control.c when an output is ready +static void HB_Output(void *arg, struct controller_context *cnt) +{ + u32 i = 0; + + //logging + u32 *Hd1, *Hd2, *Houtput; + Hd1 = &dummy; + Hd2 = &dummy; + Houtput = &dummy; + + for (i= 0; i< NUM_HBRIDGE; i++) + if (&HB_Controllers[i].c.io == cnt) + { + //logging + switch(i) + { + case 0: + Hd1 = &HB_H1_d1; + Hd2 = &HB_H1_d2; + Houtput = &HB_H1_output; + break; + + case 1: + Hd1 = &HB_H2_d1; + Hd2 = &HB_H2_d2; + Houtput = &HB_H2_output; + break; + + case 2: + Hd1 = &HB_H3_d1; + Hd2 = &HB_H3_d2; + Houtput = &HB_H3_output; + break; + + case 3: + Hd1 = &HB_H4_d1; + Hd2 = &HB_H4_d2; + Houtput = &HB_H4_output; + break; + } + break; + } + + if (i < NUM_HBRIDGE) + { + //safety to avoid roll-over: + if (HB_Controllers[i].c.output > 1.0) + HB_Controllers[i].c.output = 1.0; + if (HB_Controllers[i].c.output < -1.0) + HB_Controllers[i].c.output = -1.0; + + //calculate duty ratios + HB_Controllers[i].d[0] = (unsigned char) 127*(1 + HB_Controllers[i].c.output); + HB_Controllers[i].d[1] = (unsigned char) 127*(1 - HB_Controllers[i].c.output); + + //write them out: + HB_Controllers[i].write_output(HB_Controllers[i].output_arg, &HB_Controllers[i]); + + //logging + *Hd1 = HB_Controllers[i].d[0]; + *Hd2 = HB_Controllers[i].d[1]; + *Houtput = (s32) (HB_Controllers[i].c.output*128); + } + else + ; //should not happen!! +} + +//HB_Controllers[i].get_input = ExampleHB_NeedsInput; +//HB_Controllers[i].write_output = ExampleHB_WriteOutput; + +//return false +static u8 ExampleHB_NeedsInput(void *arg, void *HBContext) +{ + u32 i=0; + u32 adc_num = 0; + struct HB_context *cnt = HBContext; + + for (i= 0; i< NUM_HBRIDGE; i++) + if (&HB_Controllers[i] == cnt) + { + if (i == 0) + adc_num = 4; + else if (i == 1) + adc_num = 5; + else if (i == 2) + adc_num = 6; + else if (i == 3) + adc_num = 1; + break; //we have our match + } + + //measure the current and store it + if (i < NUM_HBRIDGE) + HB_Controllers[i].I = 0.6*ReadADC(adc_num); + else + ; //uh oh! should not get here! + + return FALSE; +} + + +//return false if ABC values set, true if DQ values set +static void ExampleHB_WriteOutput(void *arg, void *HBContext) +{ + u32 legs[2]; + struct HB_context *cnt = HBContext; + int i; + + legs[0] = 0; legs[1] = 0; legs[2] = 0; + for (i= 0; i< NUM_HBRIDGE; i++) + { + if (&HB_Controllers[i] == cnt) + { + if (i == 0) + { legs[0] = 5; legs[1] = 6; } + else if (i == 1) + { legs[0] = 13; legs[1] = 14; } + else if (i == 2) + { legs[0] = 17; legs[1] = 18; } + else if (i == 3) + { legs[0] = 11; legs[1] = 12; } + else + i = NUM_HBRIDGE; //safety, don't write out to other legs. + break; + } + } + + if (i < NUM_HBRIDGE) + { + //write them out: + WriteDutyRatio(legs[0], HB_Controllers[i].d[0]); + WriteDutyRatio(legs[1], HB_Controllers[i].d[1]); + } +} + diff --git a/sdk/basic/control_apps/HBridge_CC.h b/sdk/basic/control_apps/HBridge_CC.h old mode 100755 new mode 100644 index fbaf90e2..d18811d5 --- a/sdk/basic/control_apps/HBridge_CC.h +++ b/sdk/basic/control_apps/HBridge_CC.h @@ -1,30 +1,30 @@ -#ifndef __HBRIDGE_CC_H -#define __HBRIDGE_CC_H - -extern int Init_HBridge_CC(u8 StartAllControllers); -extern int HBridge_CC_StartCommand(const char *szCmd, char *szResponse, void *CommDevice); -extern int Start_HBridge_CC_Controller(u32 HB); -extern int Stop_HBridge_CC_Controller(u32 HB); -extern int HBridge_CC_Command(const char * szCmd, char *szResponse, void *CommDevice); -extern int HBridge_CC_SetCurrentRef(u32 hbridge, double reference); -extern int HBridge_CC_StopCommand(const char *szCmd, char *szResponse, void *CommDevice); - -typedef u8 (*HBridge_input)(void *arg, void *VSIcontext); -typedef void (*Hbridge_output)(void *arg, void *VSIcontext); - -#define NUM_HBRIDGE 6 - -typedef struct HB_context -{ - pi_house c; - u32 InputAtTickCount; //the tick count of the last time the inputs were updated (to avoid unnecessary computation) - double I; - u8 d[2]; //[0] for leg 1, [1] for leg 2 - HBridge_input get_input; - void * input_arg; - Hbridge_output write_output; - void * output_arg; -} HB_context; - -extern HB_context HB_Controllers[NUM_HBRIDGE]; -#endif +#ifndef __HBRIDGE_CC_H +#define __HBRIDGE_CC_H + +extern int Init_HBridge_CC(u8 StartAllControllers); +extern int HBridge_CC_StartCommand(const char *szCmd, char *szResponse, void *CommDevice); +extern int Start_HBridge_CC_Controller(u32 HB); +extern int Stop_HBridge_CC_Controller(u32 HB); +extern int HBridge_CC_Command(const char * szCmd, char *szResponse, void *CommDevice); +extern int HBridge_CC_SetCurrentRef(u32 hbridge, double reference); +extern int HBridge_CC_StopCommand(const char *szCmd, char *szResponse, void *CommDevice); + +typedef u8 (*HBridge_input)(void *arg, void *VSIcontext); +typedef void (*Hbridge_output)(void *arg, void *VSIcontext); + +#define NUM_HBRIDGE 6 + +typedef struct HB_context +{ + pi_house c; + u32 InputAtTickCount; //the tick count of the last time the inputs were updated (to avoid unnecessary computation) + double I; + u8 d[2]; //[0] for leg 1, [1] for leg 2 + HBridge_input get_input; + void * input_arg; + Hbridge_output write_output; + void * output_arg; +} HB_context; + +extern HB_context HB_Controllers[NUM_HBRIDGE]; +#endif diff --git a/sdk/basic/control_apps/PosContTry1.c b/sdk/basic/control_apps/PosContTry1.c old mode 100755 new mode 100644 index f24935a9..434b968a --- a/sdk/basic/control_apps/PosContTry1.c +++ b/sdk/basic/control_apps/PosContTry1.c @@ -1,896 +1,896 @@ -/* - * PosContTry1.c - * - * Created on: Jul 10, 2014 - * Author: sever212 - */ -#include "../src/project_include.h" - -#if defined (USE_VSI_CC) - //(these are all scaled so that we can take sensor inputs in units of mm) - #define KKpf_xo_GAIN 47.905474024799268 //38.9693 //Kxo_forcenorm*Kpf_xo - #define KKiTs_xo_GAIN 0.011041196186847 //0.0075708324 //Kxo_forcenorm*Kif_xo*Ts - //derivative gain for current error: derivative difference EQ: D = kdn*E[n] + kdn1*E[n-1] + kdm1*D[n-1] - #define KKdn_xo_GAIN 398.2600565348860 //349.43217 //Kxo_forcenorm*er_coefs_xo(1) - #define KKdn1_xo_GAIN -398.2600565348860 //-349.43217 //Kxo_forcenorm*er_coefs_xo(2) - #define KKdm1_xo_GAIN 0.909993668824279 //0.905664 //Dcoefs_xo(2) - - #define KKpf_th_GAIN 4.70 //3.45 //Kth_forcenorm*Kpf_th - #define KKiTs_th_GAIN 0.001060151124033 //.000517474016 //Kth_forcenorm*Kif_th*Ts - //derivative gain for current error: derivative difference EQ: D = kdn*E[n] + kdn1*E[n-1] + kdm1*D[n-1] - #define KKdn_th_GAIN 76.670981745634862 //76.2908 //Kth_forcenorm*er_coefs_th(1) - #define KKdn1_th_GAIN -76.670981745634862 //-76.2908 //Kth_forcenorm*er_coefs_th(2) - #define KKdm1_th_GAIN 0.909993668824279 //0.857308 //Dcoefs_th(2) - - - #define CUR_KP_GAIN 0.441786 //Old val (works): 0.9990 //WORKS: 0.499513231920777 // 0.16650441064 //Kpv - #define CUR_KiTs_GAIN 0.014726 //Old val (works): 0.0251 //WORKS: 0.012566370614359 // 0.006283185307180 //Kiv*Ts - - - #define BOT_US_ADC 1 - #define BOT_VS_ADC 2 - #define BOT_WS_ADC 3 - #define TOP_US_ADC 4 - #define TOP_VS_ADC 5 - #define TOP_WS_ADC 6 - - #define BOT_US_LEG 1 - #define BOT_VS_LEG 2 - #define BOT_WS_LEG 3 - #define TOP_US_LEG 4 - #define TOP_VS_LEG 5 - #define TOP_WS_LEG 6 - - - #define BOTX_ADC 7 - #define BOTY_ADC 8 - #define TOPX_ADC 9 - #define TOPY_ADC 10 - - #define BOT_ADC_MM_V 0.201005 //mm/V (1/4.975) for SN1309172-01-01 - #define TOP_ADC_MM_V 0.201491 //mm/V (1/4.963) for SN1207054-01-01 - - #define INV_2RX 2.617801047120 //1/(2*rx) //rx should be in units of m (even though sensors are in units of mm -- because gains were divided by 1000) - - #define MAX_PHASE_CURRENT 3.6 //max that the sensor can read (8 turns --> 0.375 A/V, so max it can read is 3.75A) - - #define CS_ADC_AMP_PER_VOLT 0.375 - - static u8 POS_VSI_Input(void *arg, void *VSIContext); - static void POS_VSI_Output(void *arg, void *VSIContext); -#endif - -#if defined (USE_H_BRIDGE_CC) || defined(USE_H_BRIDGE_DQ_CC) - //(these are all scaled so that we can take sensor inputs in units of mm) - #define KKpf_xo_GAIN 61.669050462043472 //WORKS: 77.938586884587338 //Kxo_forcenorm*Kpf_xo - #define KKiTs_xo_GAIN 0.010458260654729 //0.015141664815228 //Kxo_forcenorm*Kif_xo*Ts - //derivative gain for current error: derivative difference EQ: D = kdn*E[n] + kdn1*E[n-1] + kdm1*D[n-1] - #define KKdn_xo_GAIN 546.4352960041329 //698.86434078013 //Kxo_forcenorm*er_coefs_xo(1) - #define KKdn1_xo_GAIN -546.4352960041329 //-698.8643407801309 //Kxo_forcenorm*er_coefs_xo(2) - #define KKdm1_xo_GAIN 0.917183613124594 //0.905664 //Dcoefs_xo(2) - - #define KKpf_th_GAIN 7.183817503137941 //6.90 //Kth_forcenorm*Kpf_th - #define KKiTs_th_GAIN 0.001101464122195 //0.001034948 //Kth_forcenorm*Kif_th*Ts - //derivative gain for current error: derivative difference EQ: D = kdn*E[n] + kdn1*E[n-1] + kdm1*D[n-1] - #define KKdn_th_GAIN 159.0181780942346 //152.581543975 //Kth_forcenorm*er_coefs_th(1) - #define KKdn1_th_GAIN -159.0181780942346 //-152.581543975 //Kth_forcenorm*er_coefs_th(2) - #define KKdm1_th_GAIN 0.854358985825323 //0.857308 //Dcoefs_th(2) - - - #define CUR_KP_GAIN 0.161 //Works (Lext): 0.3338 //Works (IAS): 0.1047 //0.1665 //Kpv - #define CUR_KiTs_GAIN 0.0210 //Works (Lext): 0.0105 //Works (IAS): 0.02094 //0.006283 //Kiv*Ts - - - #define BOT_US_ADC 1 - #define BOT_VS_ADC 2 - #define BOT_WS_ADC 3 - #define TOP_US_ADC 4 - #define TOP_VS_ADC 5 - #define TOP_WS_ADC 6 - - #define BOT_US_L1 11 - #define BOT_US_L2 12 - #define BOT_VS_L1 15 - #define BOT_VS_L2 16 - #define BOT_WS_L1 19 - #define BOT_WS_L2 20 - #define TOP_US_L1 5 - #define TOP_US_L2 6 - #define TOP_VS_L1 13 - #define TOP_VS_L2 14 - #define TOP_WS_L1 17 - #define TOP_WS_L2 18 - - #define BOTX_ADC 7 - #define BOTY_ADC 8 - #define TOPX_ADC 9 - #define TOPY_ADC 10 - - #define BOT_ADC_MM_V 0.201005 //mm/V (1/4.975) for SN1309172-01-01 - #define TOP_ADC_MM_V 0.201491 //mm/V (1/4.963) for SN1207054-01-01 - - #define INV_2RX 2.617801047120 //1/(2*rx) //rx should be in units of m (even though sensors are in units of mm -- because gains were divided by 1000) - - #define MAX_PHASE_CURRENT 5.8 //max that the sensor can read (5 turns --> 0.6 A/V, so max it can read is 6A) - - #define CS_ADC_AMP_PER_VOLT 0.6 - -#if defined(USE_H_BRIDGE_CC) - static u8 POS_HB_Input(void *arg, void *HBContext); - static void POS_HB_Output(void *arg, void *HBContext); -#endif -#if defined(USE_H_BRIDGE_DQ_CC) - static u8 POS_VSI_Input(void *arg, void *VSIContext); - static void POS_VSI_Output(void *arg, void *VSIContext); -#endif -#endif - - - -static void POS_Input(void *arg, struct controller_context *cnt); -static void POS_Output(void *arg, struct controller_context *cnt); - - - -//Logging: -s32 x0_meas, y0_meas, x0Error, y0Error, thx, thy, thxError, thyError; -s32 Ixt_meas, Iyt_meas, Ixb_meas, Iyb_meas, Ixt_ref, Iyt_ref, Ixb_ref, Iyb_ref; -s32 Ixb_ref_usat, Iyb_ref_usat, Ixt_ref_usat, Iyt_ref_usat; - -#define DEFAULT_X_TOP_REF 0.251 -#define DEFAULT_Y_TOP_REF -0.053 -#define DEFAULT_X_BOT_REF 0.089 -#define DEFAULT_Y_BOT_REF -0.140 - -//double default_ref_pos[4] = {DEFAULT_X_TOP_REF, DEFAULT_Y_TOP_REF, DEFAULT_X_BOT_REF, DEFAULT_Y_BOT_REF}; - -//non-control -- allows x and y, top and bottom currents to be forced to a certain value -double force_ixy_top[2] = {0.0, 0.0}; -double force_ixy_bot[2] = {0.0, 0.0}; -u8 bForceXY_Currents = 0; - -int SaturateDQCurrents(double MaxPhaseCurrent, double *inputDQ, double *outputDQ) -{ - double mc = sqrt(0.6667*(inputDQ[0]*inputDQ[0] + inputDQ[1]*inputDQ[1])); - if (mc > MaxPhaseCurrent) - { - outputDQ[0] = inputDQ[0]/mc*MaxPhaseCurrent; - outputDQ[1] = inputDQ[1]/mc*MaxPhaseCurrent; - } - else - { - outputDQ[0] = inputDQ[0]; - outputDQ[1] = inputDQ[1]; - } - return SUCCESS; -} - -int SaturatePhaseCurrents(double MaxPhaseCurrent, double *inputUVW, double *outputUVW) -{ - int i = 0; - double max_c = inputUVW[0]; - double scale = 1.0; - for (i = 1; i < 3; i++) - { - if (fabs(inputUVW[i]) > fabs(max_c)) - max_c = inputUVW[i]; - } - if (fabs(max_c) > MaxPhaseCurrent) - { - scale = fabs(MaxPhaseCurrent/max_c); - for (i = 0; i < 3; i++) - outputUVW[i] = scale*inputUVW[i]; - } - else - { - for (i = 0; i < 3; i++) - outputUVW[i] = inputUVW[i]; - } - - return SUCCESS; -} - -PosCnt_context PosControllers; -static controller_linked_list_item pos_cont_items [4]; - -int ConvertFromX1X2(double *x1x2, double *x0th) -{ - x0th[0] = 0.5*(x1x2[0] + x1x2[1]); - x0th[1] = INV_2RX*(x1x2[0] - x1x2[1]); - return SUCCESS; -} - -int ConvertFromSumDiff(double *SumDiff, double *OneTwo) -{ - OneTwo[0] = 0.5*(SumDiff[0] + SumDiff[1]); - OneTwo[1] = 0.5*(SumDiff[0] - SumDiff[1]); - return SUCCESS; -} - -/***************************** - * Init_PosContTry1() - * Sets up the controllers memory to default values - * and optionally starts the controllers running. - * The default settings can be overridden by manually - * editing the VSI_DQ_Cur_Controllers structure. - * - *StartAllControllers: this is ignored - *returns a success code - */ -int Init_PosContTry1(u8 StartAllControllers) -{ - struct pid_house *pid; - int i; - - PosControllers.MaxPhaseCurrent = MAX_PHASE_CURRENT; -#if defined(USE_VSI_CC) || defined(USE_H_BRIDGE_DQ_CC) - PosControllers.VSItop = &VSI_DQ_Cur_Controllers[VSI_TOP_INDEX]; - PosControllers.VSIbot = &VSI_DQ_Cur_Controllers[VSI_BOT_INDEX]; -#endif - - - //setup and register PID controllers - for (i = 0; i < 4; i++) - { - if (i < 2) - pid = &PosControllers.x[i]; - else - pid = &PosControllers.y[i-2]; - - //position controller - if ((i == 0) || (i == 2)) - { - pid->pid.kp = KKpf_xo_GAIN; - pid->pid.kits = KKiTs_xo_GAIN; - pid->pid.kdn = KKdn_xo_GAIN; - pid->pid.kdn1 = KKdn1_xo_GAIN; - pid->pid.kdm1 = KKdm1_xo_GAIN; - } - else - { - pid->pid.kp = KKpf_th_GAIN; - pid->pid.kits = KKiTs_th_GAIN; - pid->pid.kdn = KKdn_th_GAIN; - pid->pid.kdn1 = KKdn1_th_GAIN; - pid->pid.kdm1 = KKdm1_th_GAIN; - } - pid->pid.lastInt = 0; - pid->pid.lastErr = 0; - pid->pid.lastD = 0; - pid->pid.plusSat = 2.4495*MAX_PHASE_CURRENT; //2*sqrt(3/2)*Kf*Iph_max - pid->pid.negSat = -2.4495*MAX_PHASE_CURRENT; //-2*sqrt(3/2)*Kf*Iph_max - - //house - pid->reference = 0; - pid->updated = FALSE; - pid->input = 0; - pid->output = 0; - - //IO (controller_context) - pid->io.inputs = &pid->input; - pid->io.outputs = &pid->output; - pid->io.NumInputs = 1; - pid->io.NumOutputs = 1; - pid->io.ClockTime = 5; //uS - pid->io.clockCount = 0; - pid->io.NumClocks = 1; - pid->io.Type = C_PID; - pid->io.Status = C_RUNNING; - - //CTXT (controller_holder) - pid->ctxt.arg_in = (void *)i; - pid->ctxt.arg_out = (void *)i; - pid->ctxt.control_io = &pid->io; - pid->ctxt.controller_info = &pid->pid; - pid->ctxt.input_callback = POS_Input; - pid->ctxt.output_callback = POS_Output; - - //register the controller - pos_cont_items[i].context = &pid->ctxt; - RegisterController(0, &pos_cont_items[i]); - } - - //setup VSI's: -#if defined(USE_VSI_CC) || defined(USE_H_BRIDGE_DQ_CC) - Init_VSI_DQ_VSPWM(FALSE); //set to defaults (but don't register controllers) - for (i = 0; i < 2; i++) - { - u32 vsi_index; - struct VSI_context *VSI; - if (i == 0) - { - VSI = PosControllers.VSIbot; - vsi_index = VSI_BOT_INDEX; - } - else - { - VSI = PosControllers.VSItop; - vsi_index = VSI_TOP_INDEX; -#if defined(VSI_ISOLATED) - VSI->bUseZeroSequence = 0; -#else - VSI->bUseZeroSequence = 1; - VSI->zero.pi.kits = CUR_KiTs_GAIN/2.0; - VSI->zero.pi.kp = CUR_KP_GAIN/2.0; -#endif - } - - VSI->input_arg = (void*) vsi_index; - VSI->output_arg = (void*) vsi_index; - - VSI->d.pi.kits = CUR_KiTs_GAIN; - VSI->d.pi.kp = CUR_KP_GAIN; - VSI->q.pi.kits = CUR_KiTs_GAIN; - VSI->q.pi.kp = CUR_KP_GAIN; - - //callbacks - VSI->get_input = POS_VSI_Input; - VSI->write_output = POS_VSI_Output; - - //start it up - Start_VSI_DQ_SVPWM_Controller(vsi_index+1); - } -#endif -#if defined(USE_H_BRIDGE_CC) - - Init_HBridge_CC(FALSE); //set to defaults (but don't register controllers) - for (i = 0; i < 6; i++) - { - u32 hb_index; - struct HB_context *HB; - - if (i < 3) - { - PosControllers.HBtop[i] = &HB_Controllers[i]; - HB = PosControllers.HBtop[i]; //i = 0: u, i = 1: v, i = 2: w - hb_index = i; - } - else - { - PosControllers.HBbot[i-3] = &HB_Controllers[i]; - HB = PosControllers.HBbot[i-3]; //i = 3: u, i = 4: v, i = 5: w - hb_index = i; - } - - HB->input_arg = (void*) hb_index; - HB->output_arg = (void*) hb_index; - - HB->c.pi.kits = CUR_KiTs_GAIN; - HB->c.pi.kp = CUR_KP_GAIN; - - //callbacks - HB->get_input = POS_HB_Input; - HB->write_output = POS_HB_Output; - - //start it up - Start_HBridge_CC_Controller(hb_index+1); - } -#endif - - //adjust references of position controllers - //x1 is top, x2 is bot - double xs[2] = {DEFAULT_X_TOP_REF, DEFAULT_X_BOT_REF}; - double ys[2] = {DEFAULT_Y_TOP_REF, DEFAULT_Y_BOT_REF}; - double xthx[2]; - double ythy[2]; - ConvertFromX1X2(xs, xthx); - ConvertFromX1X2(ys, ythy); - - PosControllers.x[0].reference = xthx[0]; - PosControllers.x[1].reference = xthx[1]; - - PosControllers.y[0].reference = ythy[0]; - PosControllers.y[1].reference = ythy[1]; - return SUCCESS; -} - - -/***************************** - * Stop_PosContTry1_Controller() - * Unregisters the position controller. Note that this does - * not stop any corresponding current controller - * - *vsi: the VSI number to unregister (1 - VSI_DQ_SVPWM_NUM_VSI) - *returns a success code - */ -int Stop_PosContTry1_Controller(u32 poscnt) -{ - u32 i = poscnt-1; - if (i >= 4) - return INVALID_ARGUMENT; - if (pos_cont_items[2*i].bRegistered == TRUE) - UnregisterController(0, &pos_cont_items[2*i]); - if (pos_cont_items[2*i+1].bRegistered == TRUE) - UnregisterController(0, &pos_cont_items[2*i+1]); - return SUCCESS; -} - -/***************************** - * PosContTry1_StopCommand() - * Process an ascii command for stopping the position controllers - * and any associated current controllers - * - *szCmd: incoming command - *szResponse: the response to the command - *CommDevice: pointer to information about the communication device - * this was received on - */ -int PosContTry1_StopCommand(const char *szCmd, char *szResponse, void *CommDevice) -{ - int i; - for (i=0; i< 4; i++) - { - Stop_PosContTry1_Controller(i+1); - } -#if defined(USE_VSI_CC) || defined(USE_H_BRIDGE_DQ_CC) - Stop_VSI_DQ_SVPWM_Controller(VSI_BOT_INDEX); - Stop_VSI_DQ_SVPWM_Controller(VSI_TOP_INDEX); -#endif -#if defined(USE_H_BRIDGE_CC) - for (i=0; i < 6; i++) - Stop_HBridge_CC_Controller(i); -#endif - - strcpy(szResponse, "OK"); - return strlen(szResponse); -} - - -/***************************** - * PosContTry1_StartCommand() - * Process an ascii command for starting the position controllers - * Init_PosContTry1 is called - * - * Example: CST=1,FORCEI=1 - *szCmd: incoming command - *szResponse: the response to the command - *CommDevice: pointer to information about the communication device - * this was received on - */ -int PosContTry1_StartCommand(const char *szCmd, char *szResponse, void *CommDevice) -{ - - if (strstr(szCmd, "FORCEI")) - { - strcpy(szResponse, "FORCEI=1"); - bForceXY_Currents = TRUE; - } - else - { - bForceXY_Currents = FALSE; - strcpy(szResponse, "OK"); - } - - - Init_PosContTry1(TRUE); - - return strlen(szResponse); -} - -/***************************** - * PosContTry1_Command() - * Process an ascii command for setting a reference position (or current) - * Syntax: n,tb,val - * n is the controller axis (x for x-axis, y for y-axis), - * tb is t for top, b for bottom, - * val is the mm reference (*128) - * - *szCmd: incoming command - *szResponse: the response to the command - *CommDevice: pointer to information about the communication device - * this was received on - */ -int PosContTry1_Command(const char * szCmd, char *szResponse, void *CommDevice) -{ - u8 tb = szCmd[0]; - u8 bError = FALSE; - double ref; - if ((tb != 'b') && (tb != 't') ) - bError = TRUE; - else if (szCmd[1] != ',') - bError = TRUE; - else - { - u8 xy = szCmd[2]; - if ((xy != 'x') && (xy != 'y') ) - bError = TRUE; - else if (szCmd[3] != ',') - bError = TRUE; - else if (szCmd[4] == 0) - bError = TRUE; - else - { - ref = ((double) atoi(&szCmd[4]))/128; - if (bForceXY_Currents) - { - if (tb == 't') - { - if (xy == 'x') - force_ixy_top[0] = ref; - else - force_ixy_top[1] = ref; - } - else - { - if (xy == 'x') - force_ixy_bot[0] = ref; - else - force_ixy_bot[1] = ref; - } - strcpy(szResponse, "OK"); - } - else //not supported yet - bError = TRUE; - } - - } - if (bError) - strcpy(szResponse, "ERROR"); - - return strlen(szResponse); -} - - - - -//Internal function called by control.c before executing a controller -static void POS_Input(void *arg, struct controller_context *cnt) -{ -// u32 i= (u32) arg; - - //calculate the error and store it - if (TimeElapsed10us(PosControllers.InputAtTickCount) > 5) - { - - PosControllers.InputAtTickCount = MainTimerTimerTick; - PosControllers.xs[POS_BOT_INDEX] = BOT_ADC_MM_V*ReadADC(BOTX_ADC); - PosControllers.xs[POS_TOP_INDEX] = TOP_ADC_MM_V*ReadADC(TOPX_ADC); - PosControllers.ys[POS_BOT_INDEX] = BOT_ADC_MM_V*ReadADC(BOTY_ADC); - PosControllers.ys[POS_TOP_INDEX] = TOP_ADC_MM_V*ReadADC(TOPY_ADC); - double x1x2[2] = {PosControllers.xs[POS_TOP_INDEX], PosControllers.xs[POS_BOT_INDEX]}; - double y1y2[2] = {PosControllers.ys[POS_TOP_INDEX], PosControllers.ys[POS_BOT_INDEX]}; - ConvertFromX1X2(x1x2, PosControllers.x_thx); - ConvertFromX1X2(y1y2, PosControllers.y_thy); - - PosControllers.x[0].input = PosControllers.x[0].reference - PosControllers.x_thx[0]; - PosControllers.x[1].input = PosControllers.x[1].reference - PosControllers.x_thx[1]; - PosControllers.y[0].input = PosControllers.y[0].reference - PosControllers.y_thy[0]; - PosControllers.y[1].input = PosControllers.y[1].reference - PosControllers.y_thy[1]; - - //logging - x0_meas = (s32) 128.0*PosControllers.x_thx[0]; - y0_meas = (s32) 128.0*PosControllers.y_thy[0]; - thx = (s32) 128.0*PosControllers.x_thx[1]; - thy = (s32) 128.0*PosControllers.y_thy[1]; - x0Error = (s32) 128.0*PosControllers.x[0].input; - y0Error = (s32) 128.0*PosControllers.y[0].input; - thxError = (s32) 128.0*PosControllers.x[1].input; - thyError = (s32) 128.0*PosControllers.y[1].input; - - } -} - -//Internal function called by control.c when an output is ready -static void POS_Output(void *arg, struct controller_context *cnt) -{ - u32 i= (u32) arg; - - switch (i) - { - case 0: - PosControllers.x[0].updated = TRUE; - break; - - case 1: - PosControllers.x[1].updated = TRUE; - break; - - case 2: - PosControllers.y[0].updated = TRUE; - break; - - case 3: - PosControllers.y[1].updated = TRUE; - break; - - default: - break; - } - - - if ( (PosControllers.x[0].updated == TRUE) && (PosControllers.x[1].updated==TRUE) - && (PosControllers.y[0].updated == TRUE) && (PosControllers.y[1].updated==TRUE)) - { - double current_xy_top[2], current_xy_bot[2], current_12x[2], current_12y[2], current_sumdiff[2]; - //all controller output current references have been updated, - //update the xy current holder taking into account maximum current values - PosControllers.x[0].updated = FALSE; - PosControllers.x[1].updated = FALSE; - PosControllers.y[0].updated = FALSE; - PosControllers.y[1].updated = FALSE; - - //get top bot x currents - current_sumdiff[0] = PosControllers.x[POS_XY0_INDEX].output; - current_sumdiff[1] = PosControllers.x[POS_THXY_INDEX].output; - ConvertFromSumDiff(current_sumdiff, current_12x); - current_xy_top[0] = current_12x[0]; - current_xy_bot[0] = current_12x[1]; //NOT negative because the bottom force is NOT created in the opposite direction - - //get top bot y currents - current_sumdiff[0] = PosControllers.y[POS_XY0_INDEX].output; - current_sumdiff[1] = PosControllers.y[POS_THXY_INDEX].output; - ConvertFromSumDiff(current_sumdiff, current_12y); - current_xy_top[1] = current_12y[0]; - current_xy_bot[1] = current_12y[1]; //NOT negative because the bottom force is NOT created in the opposite direction - - //if we are forcing the currents, override the above calculations - if (bForceXY_Currents) - { - current_xy_top[0] = force_ixy_top[0]; - current_xy_top[1] = force_ixy_top[1]; - current_xy_bot[0] = force_ixy_bot[0]; - current_xy_bot[1] = force_ixy_bot[1]; - } - - //saturate the top bot xy currents -#if defined(USE_VSI_CC) || defined(USE_H_BRIDGE_DQ_CC) - SaturateDQCurrents(PosControllers.MaxPhaseCurrent, current_xy_top, PosControllers.Itop_xy); - SaturateDQCurrents(PosControllers.MaxPhaseCurrent, current_xy_bot, PosControllers.Ibot_xy); -#else - PosControllers.Itop_xy[0] = current_xy_top[0]; PosControllers.Itop_xy[1] = current_xy_top[1]; - PosControllers.Ibot_xy[0] = current_xy_bot[0]; PosControllers.Ibot_xy[1] = current_xy_bot[1]; -#endif - -#if defined(USE_H_BRIDGE_CC) - { - double i_xy0[3], i_uvw[3]; - i_xy0[0] = PosControllers.Itop_xy[0]; - i_xy0[1] = PosControllers.Itop_xy[1]; - i_xy0[2] = 0; - InverseDQ0_Transform(0, i_uvw, i_xy0); - SaturatePhaseCurrents(PosControllers.MaxPhaseCurrent, i_uvw, PosControllers.Itop_uvw_sus); - i_xy0[0] = PosControllers.Ibot_xy[0]; i_xy0[1] = PosControllers.Ibot_xy[1]; i_xy0[2] = 0; - InverseDQ0_Transform(0, i_uvw, i_xy0); - SaturatePhaseCurrents(PosControllers.MaxPhaseCurrent, i_uvw, PosControllers.Ibot_uvw_sus); - } -#endif - - //logging - Ixb_ref_usat = (s32) 128.0*current_xy_bot[0]; - Iyb_ref_usat = (s32) 128.0*current_xy_bot[1]; - Ixt_ref_usat = (s32) 128.0*current_xy_top[0]; - Iyt_ref_usat = (s32) 128.0*current_xy_top[1]; - } -} - - -#if defined(USE_VSI_CC) || defined(USE_H_BRIDGE_DQ_CC) -//update reference and measured currents -//return false if ABC values set, true if DQ values set -static u8 POS_VSI_Input(void *arg, void *VSIContext) -{ - u32 vsi_index = (u32) arg; - u32 adc_num[3]; - struct VSI_context *cnt = VSIContext; - //double meas_abc[3], meas_dq0[3]; - double adc_gain = CS_ADC_AMP_PER_VOLT; - - //MEASURED CURRENTS - if (vsi_index == VSI_BOT_INDEX) - { - adc_num[0] = BOT_US_ADC; adc_num[1] = BOT_VS_ADC; adc_num[2] = BOT_WS_ADC; - } - else - { - adc_num[0] = TOP_US_ADC; adc_num[1] = TOP_VS_ADC; adc_num[2] = TOP_WS_ADC; - } - - cnt->Iabc[0] = adc_gain*ReadADC(adc_num[0]); - cnt->Iabc[1] = adc_gain*ReadADC(adc_num[1]); - cnt->Iabc[2] = adc_gain*ReadADC(adc_num[2]); - cnt->theta_da = 0; - - //REFERENCE DQ CURRENTS - if (vsi_index == VSI_BOT_INDEX) - { -#if defined(USE_H_BRIDGE_DQ_CC) - cnt->d.reference = PosControllers.Ibot_xy[0]; - cnt->q.reference = PosControllers.Ibot_xy[1]; -#endif - -#if defined(USE_VSI_CC) - cnt->d.reference = PosControllers.Ibot_xy[0] - 0.5*PosControllers.TorqueVSI_botIxy[0]; - cnt->q.reference = PosControllers.Ibot_xy[1] - 0.5*PosControllers.TorqueVSI_botIxy[1]; -#endif - //logging - Ixb_ref = (s32) 128.0*PosControllers.Ibot_xy[0]; //PosControllers.Ibot_xy[0] - 0.5*PosControllers.TorqueVSI_topIxy[0]; - Iyb_ref = (s32) 128.0*PosControllers.Ibot_xy[1]; //PosControllers.Ibot_xy[1] - 0.5*PosControllers.TorqueVSI_topIxy[1]; - } - else - { -#if defined(USE_H_BRIDGE_DQ_CC) - cnt->d.reference = PosControllers.Itop_xy[0]; - cnt->q.reference = PosControllers.Itop_xy[1]; -#endif -#if defined(USE_VSI_CC) - cnt->d.reference = PosControllers.Itop_xy[0] - 0.5*PosControllers.TorqueVSI_topIxy[0]; - cnt->q.reference = PosControllers.Itop_xy[1] - 0.5*PosControllers.TorqueVSI_topIxy[1]; -#endif - //logging - Ixt_ref = (s32) 128.0*PosControllers.Itop_xy[0]; - Iyt_ref = (s32) 128.0*PosControllers.Itop_xy[1]; - } - return FALSE; -} - -//write the duty ratio out to the legs -static void POS_VSI_Output(void *arg, void *VSIContext) -{ - u32 vsi_index = (u32) arg; - u32 legs[6]; - u8 duty1, duty2, duty3; - struct VSI_context *cnt = VSIContext; - legs[0] = 0; legs[1] = 0; legs[2] = 0; - int i; - -#if defined(USE_H_BRIDGE_DQ_CC) - if (vsi_index == VSI_BOT_INDEX) - { - legs[0] = BOT_US_L1; legs[1] = BOT_US_L2; - legs[2] = BOT_VS_L1; legs[3] = BOT_VS_L2; - legs[4] = BOT_WS_L1; legs[5] = BOT_WS_L2; - } - else - { - legs[0] = TOP_US_L1; legs[1] = TOP_US_L2; - legs[2] = TOP_VS_L1; legs[3] = TOP_VS_L2; - legs[4] = TOP_WS_L1; legs[5] = TOP_WS_L2; - } - - //convert the modulation indices to duty ratios - for (i = 0; i < 3; i++) - { - double m; - u8 d1, d2; - //safety to avoid roll-over: - if (cnt->mabc[i] > 1.0) - m = 1.0; - else if (cnt->mabc[i] < -1.0) - m = -1.0; - else - m = cnt->mabc[i]; - - - //calculate duty ratios - d1 = (unsigned char) 127*(1 + m); - d2 = (unsigned char) 127*(1 - m); - - //write it out - WriteDutyRatio(legs[i*2], d1); - WriteDutyRatio(legs[i*2+1], d2); - - } -#endif - -#if defined(USE_VSI_CC) - if (vsi_index == VSI_BOT_INDEX) - { - legs[0] = BOT_US_LEG; legs[1] = BOT_VS_LEG; legs[2] = BOT_WS_LEG; - } - else - { - legs[0] = TOP_US_LEG; legs[1] = TOP_VS_LEG; legs[2] = TOP_WS_LEG; - } - //convert the duty ratios - //dtest = 256*(d_com + m_abc[0]); - duty1 = (unsigned char) 256.0*(cnt->dabc[0]); - duty2 = (unsigned char) 256.0*(cnt->dabc[1]); - duty3 = (unsigned char) 256.0*(cnt->dabc[2]); - - //write them out: - WriteDutyRatio(legs[0], duty1); - WriteDutyRatio(legs[1], duty2); - WriteDutyRatio(legs[2], duty3); -#endif -} -#endif - -#if defined(USE_H_BRIDGE_CC) -//update reference and measured currents -//return false if ABC values set, true if DQ values set -static u8 POS_HB_Input(void *arg, void *HBContext) -{ - u32 hb_index = (u32) arg; - u32 adc_num = 0; - struct HB_context *cnt = HBContext; - double adc_gain = CS_ADC_AMP_PER_VOLT; - - //MEASURED CURRENTS - switch(hb_index) - { - case 0: - adc_num = TOP_US_ADC; - break; - case 1: - adc_num = TOP_VS_ADC; - break; - case 2: - adc_num = TOP_WS_ADC; - break; - case 3: - adc_num = BOT_US_ADC; - break; - case 4: - adc_num = BOT_VS_ADC; - break; - case 5: - adc_num = BOT_WS_ADC; - break; - default: - //should not get here! - break; - } - - //update the measured current - cnt->I = adc_gain*ReadADC(adc_num); - - //update reference currents - if (hb_index < 3) - HBridge_CC_SetCurrentRef(hb_index+1, PosControllers.Itop_uvw_sus[hb_index]); - else - HBridge_CC_SetCurrentRef(hb_index+1, PosControllers.Ibot_uvw_sus[hb_index-3]); - - //logging - Ixt_ref = (s32) 128.0*PosControllers.Itop_xy[0]; - Iyt_ref = (s32) 128.0*PosControllers.Itop_xy[1]; - Ixb_ref = (s32) 128.0*PosControllers.Ibot_xy[0]; - Iyb_ref = (s32) 128.0*PosControllers.Ibot_xy[1]; - - return FALSE; -} - -//write the duty ratio out to the legs -static void POS_HB_Output(void *arg, void *HBContext) -{ - u32 hb_index = (u32) arg; - u32 legs[2]; - - struct HB_context *cnt = HBContext; - legs[0] = 0; legs[1] = 0; - - switch(hb_index) - { - case 0: - legs[0] = TOP_US_L1; - legs[1] = TOP_US_L2; - break; - case 1: - legs[0] = TOP_VS_L1; - legs[1] = TOP_VS_L2; - break; - case 2: - legs[0] = TOP_WS_L1; - legs[1] = TOP_WS_L2; - break; - case 3: - legs[0] = BOT_US_L1; - legs[1] = BOT_US_L2; - break; - case 4: - legs[0] = BOT_VS_L1; - legs[1] = BOT_VS_L2; - break; - case 5: - legs[0] = BOT_WS_L1; - legs[1] = BOT_WS_L2; - break; - default: - //should not get here! - break; - } - - //write them out: - WriteDutyRatio(legs[0], cnt->d[0]); - WriteDutyRatio(legs[1], cnt->d[1]); -} -#endif +/* + * PosContTry1.c + * + * Created on: Jul 10, 2014 + * Author: sever212 + */ +#include "../src/project_include.h" + +#if defined (USE_VSI_CC) + //(these are all scaled so that we can take sensor inputs in units of mm) + #define KKpf_xo_GAIN 47.905474024799268 //38.9693 //Kxo_forcenorm*Kpf_xo + #define KKiTs_xo_GAIN 0.011041196186847 //0.0075708324 //Kxo_forcenorm*Kif_xo*Ts + //derivative gain for current error: derivative difference EQ: D = kdn*E[n] + kdn1*E[n-1] + kdm1*D[n-1] + #define KKdn_xo_GAIN 398.2600565348860 //349.43217 //Kxo_forcenorm*er_coefs_xo(1) + #define KKdn1_xo_GAIN -398.2600565348860 //-349.43217 //Kxo_forcenorm*er_coefs_xo(2) + #define KKdm1_xo_GAIN 0.909993668824279 //0.905664 //Dcoefs_xo(2) + + #define KKpf_th_GAIN 4.70 //3.45 //Kth_forcenorm*Kpf_th + #define KKiTs_th_GAIN 0.001060151124033 //.000517474016 //Kth_forcenorm*Kif_th*Ts + //derivative gain for current error: derivative difference EQ: D = kdn*E[n] + kdn1*E[n-1] + kdm1*D[n-1] + #define KKdn_th_GAIN 76.670981745634862 //76.2908 //Kth_forcenorm*er_coefs_th(1) + #define KKdn1_th_GAIN -76.670981745634862 //-76.2908 //Kth_forcenorm*er_coefs_th(2) + #define KKdm1_th_GAIN 0.909993668824279 //0.857308 //Dcoefs_th(2) + + + #define CUR_KP_GAIN 0.441786 //Old val (works): 0.9990 //WORKS: 0.499513231920777 // 0.16650441064 //Kpv + #define CUR_KiTs_GAIN 0.014726 //Old val (works): 0.0251 //WORKS: 0.012566370614359 // 0.006283185307180 //Kiv*Ts + + + #define BOT_US_ADC 1 + #define BOT_VS_ADC 2 + #define BOT_WS_ADC 3 + #define TOP_US_ADC 4 + #define TOP_VS_ADC 5 + #define TOP_WS_ADC 6 + + #define BOT_US_LEG 1 + #define BOT_VS_LEG 2 + #define BOT_WS_LEG 3 + #define TOP_US_LEG 4 + #define TOP_VS_LEG 5 + #define TOP_WS_LEG 6 + + + #define BOTX_ADC 7 + #define BOTY_ADC 8 + #define TOPX_ADC 9 + #define TOPY_ADC 10 + + #define BOT_ADC_MM_V 0.201005 //mm/V (1/4.975) for SN1309172-01-01 + #define TOP_ADC_MM_V 0.201491 //mm/V (1/4.963) for SN1207054-01-01 + + #define INV_2RX 2.617801047120 //1/(2*rx) //rx should be in units of m (even though sensors are in units of mm -- because gains were divided by 1000) + + #define MAX_PHASE_CURRENT 3.6 //max that the sensor can read (8 turns --> 0.375 A/V, so max it can read is 3.75A) + + #define CS_ADC_AMP_PER_VOLT 0.375 + + static u8 POS_VSI_Input(void *arg, void *VSIContext); + static void POS_VSI_Output(void *arg, void *VSIContext); +#endif + +#if defined (USE_H_BRIDGE_CC) || defined(USE_H_BRIDGE_DQ_CC) + //(these are all scaled so that we can take sensor inputs in units of mm) + #define KKpf_xo_GAIN 61.669050462043472 //WORKS: 77.938586884587338 //Kxo_forcenorm*Kpf_xo + #define KKiTs_xo_GAIN 0.010458260654729 //0.015141664815228 //Kxo_forcenorm*Kif_xo*Ts + //derivative gain for current error: derivative difference EQ: D = kdn*E[n] + kdn1*E[n-1] + kdm1*D[n-1] + #define KKdn_xo_GAIN 546.4352960041329 //698.86434078013 //Kxo_forcenorm*er_coefs_xo(1) + #define KKdn1_xo_GAIN -546.4352960041329 //-698.8643407801309 //Kxo_forcenorm*er_coefs_xo(2) + #define KKdm1_xo_GAIN 0.917183613124594 //0.905664 //Dcoefs_xo(2) + + #define KKpf_th_GAIN 7.183817503137941 //6.90 //Kth_forcenorm*Kpf_th + #define KKiTs_th_GAIN 0.001101464122195 //0.001034948 //Kth_forcenorm*Kif_th*Ts + //derivative gain for current error: derivative difference EQ: D = kdn*E[n] + kdn1*E[n-1] + kdm1*D[n-1] + #define KKdn_th_GAIN 159.0181780942346 //152.581543975 //Kth_forcenorm*er_coefs_th(1) + #define KKdn1_th_GAIN -159.0181780942346 //-152.581543975 //Kth_forcenorm*er_coefs_th(2) + #define KKdm1_th_GAIN 0.854358985825323 //0.857308 //Dcoefs_th(2) + + + #define CUR_KP_GAIN 0.161 //Works (Lext): 0.3338 //Works (IAS): 0.1047 //0.1665 //Kpv + #define CUR_KiTs_GAIN 0.0210 //Works (Lext): 0.0105 //Works (IAS): 0.02094 //0.006283 //Kiv*Ts + + + #define BOT_US_ADC 1 + #define BOT_VS_ADC 2 + #define BOT_WS_ADC 3 + #define TOP_US_ADC 4 + #define TOP_VS_ADC 5 + #define TOP_WS_ADC 6 + + #define BOT_US_L1 11 + #define BOT_US_L2 12 + #define BOT_VS_L1 15 + #define BOT_VS_L2 16 + #define BOT_WS_L1 19 + #define BOT_WS_L2 20 + #define TOP_US_L1 5 + #define TOP_US_L2 6 + #define TOP_VS_L1 13 + #define TOP_VS_L2 14 + #define TOP_WS_L1 17 + #define TOP_WS_L2 18 + + #define BOTX_ADC 7 + #define BOTY_ADC 8 + #define TOPX_ADC 9 + #define TOPY_ADC 10 + + #define BOT_ADC_MM_V 0.201005 //mm/V (1/4.975) for SN1309172-01-01 + #define TOP_ADC_MM_V 0.201491 //mm/V (1/4.963) for SN1207054-01-01 + + #define INV_2RX 2.617801047120 //1/(2*rx) //rx should be in units of m (even though sensors are in units of mm -- because gains were divided by 1000) + + #define MAX_PHASE_CURRENT 5.8 //max that the sensor can read (5 turns --> 0.6 A/V, so max it can read is 6A) + + #define CS_ADC_AMP_PER_VOLT 0.6 + +#if defined(USE_H_BRIDGE_CC) + static u8 POS_HB_Input(void *arg, void *HBContext); + static void POS_HB_Output(void *arg, void *HBContext); +#endif +#if defined(USE_H_BRIDGE_DQ_CC) + static u8 POS_VSI_Input(void *arg, void *VSIContext); + static void POS_VSI_Output(void *arg, void *VSIContext); +#endif +#endif + + + +static void POS_Input(void *arg, struct controller_context *cnt); +static void POS_Output(void *arg, struct controller_context *cnt); + + + +//Logging: +s32 x0_meas, y0_meas, x0Error, y0Error, thx, thy, thxError, thyError; +s32 Ixt_meas, Iyt_meas, Ixb_meas, Iyb_meas, Ixt_ref, Iyt_ref, Ixb_ref, Iyb_ref; +s32 Ixb_ref_usat, Iyb_ref_usat, Ixt_ref_usat, Iyt_ref_usat; + +#define DEFAULT_X_TOP_REF 0.251 +#define DEFAULT_Y_TOP_REF -0.053 +#define DEFAULT_X_BOT_REF 0.089 +#define DEFAULT_Y_BOT_REF -0.140 + +//double default_ref_pos[4] = {DEFAULT_X_TOP_REF, DEFAULT_Y_TOP_REF, DEFAULT_X_BOT_REF, DEFAULT_Y_BOT_REF}; + +//non-control -- allows x and y, top and bottom currents to be forced to a certain value +double force_ixy_top[2] = {0.0, 0.0}; +double force_ixy_bot[2] = {0.0, 0.0}; +u8 bForceXY_Currents = 0; + +int SaturateDQCurrents(double MaxPhaseCurrent, double *inputDQ, double *outputDQ) +{ + double mc = sqrt(0.6667*(inputDQ[0]*inputDQ[0] + inputDQ[1]*inputDQ[1])); + if (mc > MaxPhaseCurrent) + { + outputDQ[0] = inputDQ[0]/mc*MaxPhaseCurrent; + outputDQ[1] = inputDQ[1]/mc*MaxPhaseCurrent; + } + else + { + outputDQ[0] = inputDQ[0]; + outputDQ[1] = inputDQ[1]; + } + return SUCCESS; +} + +int SaturatePhaseCurrents(double MaxPhaseCurrent, double *inputUVW, double *outputUVW) +{ + int i = 0; + double max_c = inputUVW[0]; + double scale = 1.0; + for (i = 1; i < 3; i++) + { + if (fabs(inputUVW[i]) > fabs(max_c)) + max_c = inputUVW[i]; + } + if (fabs(max_c) > MaxPhaseCurrent) + { + scale = fabs(MaxPhaseCurrent/max_c); + for (i = 0; i < 3; i++) + outputUVW[i] = scale*inputUVW[i]; + } + else + { + for (i = 0; i < 3; i++) + outputUVW[i] = inputUVW[i]; + } + + return SUCCESS; +} + +PosCnt_context PosControllers; +static controller_linked_list_item pos_cont_items [4]; + +int ConvertFromX1X2(double *x1x2, double *x0th) +{ + x0th[0] = 0.5*(x1x2[0] + x1x2[1]); + x0th[1] = INV_2RX*(x1x2[0] - x1x2[1]); + return SUCCESS; +} + +int ConvertFromSumDiff(double *SumDiff, double *OneTwo) +{ + OneTwo[0] = 0.5*(SumDiff[0] + SumDiff[1]); + OneTwo[1] = 0.5*(SumDiff[0] - SumDiff[1]); + return SUCCESS; +} + +/***************************** + * Init_PosContTry1() + * Sets up the controllers memory to default values + * and optionally starts the controllers running. + * The default settings can be overridden by manually + * editing the VSI_DQ_Cur_Controllers structure. + * + *StartAllControllers: this is ignored + *returns a success code + */ +int Init_PosContTry1(u8 StartAllControllers) +{ + struct pid_house *pid; + int i; + + PosControllers.MaxPhaseCurrent = MAX_PHASE_CURRENT; +#if defined(USE_VSI_CC) || defined(USE_H_BRIDGE_DQ_CC) + PosControllers.VSItop = &VSI_DQ_Cur_Controllers[VSI_TOP_INDEX]; + PosControllers.VSIbot = &VSI_DQ_Cur_Controllers[VSI_BOT_INDEX]; +#endif + + + //setup and register PID controllers + for (i = 0; i < 4; i++) + { + if (i < 2) + pid = &PosControllers.x[i]; + else + pid = &PosControllers.y[i-2]; + + //position controller + if ((i == 0) || (i == 2)) + { + pid->pid.kp = KKpf_xo_GAIN; + pid->pid.kits = KKiTs_xo_GAIN; + pid->pid.kdn = KKdn_xo_GAIN; + pid->pid.kdn1 = KKdn1_xo_GAIN; + pid->pid.kdm1 = KKdm1_xo_GAIN; + } + else + { + pid->pid.kp = KKpf_th_GAIN; + pid->pid.kits = KKiTs_th_GAIN; + pid->pid.kdn = KKdn_th_GAIN; + pid->pid.kdn1 = KKdn1_th_GAIN; + pid->pid.kdm1 = KKdm1_th_GAIN; + } + pid->pid.lastInt = 0; + pid->pid.lastErr = 0; + pid->pid.lastD = 0; + pid->pid.plusSat = 2.4495*MAX_PHASE_CURRENT; //2*sqrt(3/2)*Kf*Iph_max + pid->pid.negSat = -2.4495*MAX_PHASE_CURRENT; //-2*sqrt(3/2)*Kf*Iph_max + + //house + pid->reference = 0; + pid->updated = FALSE; + pid->input = 0; + pid->output = 0; + + //IO (controller_context) + pid->io.inputs = &pid->input; + pid->io.outputs = &pid->output; + pid->io.NumInputs = 1; + pid->io.NumOutputs = 1; + pid->io.ClockTime = 5; //uS + pid->io.clockCount = 0; + pid->io.NumClocks = 1; + pid->io.Type = C_PID; + pid->io.Status = C_RUNNING; + + //CTXT (controller_holder) + pid->ctxt.arg_in = (void *)i; + pid->ctxt.arg_out = (void *)i; + pid->ctxt.control_io = &pid->io; + pid->ctxt.controller_info = &pid->pid; + pid->ctxt.input_callback = POS_Input; + pid->ctxt.output_callback = POS_Output; + + //register the controller + pos_cont_items[i].context = &pid->ctxt; + RegisterController(0, &pos_cont_items[i]); + } + + //setup VSI's: +#if defined(USE_VSI_CC) || defined(USE_H_BRIDGE_DQ_CC) + Init_VSI_DQ_VSPWM(FALSE); //set to defaults (but don't register controllers) + for (i = 0; i < 2; i++) + { + u32 vsi_index; + struct VSI_context *VSI; + if (i == 0) + { + VSI = PosControllers.VSIbot; + vsi_index = VSI_BOT_INDEX; + } + else + { + VSI = PosControllers.VSItop; + vsi_index = VSI_TOP_INDEX; +#if defined(VSI_ISOLATED) + VSI->bUseZeroSequence = 0; +#else + VSI->bUseZeroSequence = 1; + VSI->zero.pi.kits = CUR_KiTs_GAIN/2.0; + VSI->zero.pi.kp = CUR_KP_GAIN/2.0; +#endif + } + + VSI->input_arg = (void*) vsi_index; + VSI->output_arg = (void*) vsi_index; + + VSI->d.pi.kits = CUR_KiTs_GAIN; + VSI->d.pi.kp = CUR_KP_GAIN; + VSI->q.pi.kits = CUR_KiTs_GAIN; + VSI->q.pi.kp = CUR_KP_GAIN; + + //callbacks + VSI->get_input = POS_VSI_Input; + VSI->write_output = POS_VSI_Output; + + //start it up + Start_VSI_DQ_SVPWM_Controller(vsi_index+1); + } +#endif +#if defined(USE_H_BRIDGE_CC) + + Init_HBridge_CC(FALSE); //set to defaults (but don't register controllers) + for (i = 0; i < 6; i++) + { + u32 hb_index; + struct HB_context *HB; + + if (i < 3) + { + PosControllers.HBtop[i] = &HB_Controllers[i]; + HB = PosControllers.HBtop[i]; //i = 0: u, i = 1: v, i = 2: w + hb_index = i; + } + else + { + PosControllers.HBbot[i-3] = &HB_Controllers[i]; + HB = PosControllers.HBbot[i-3]; //i = 3: u, i = 4: v, i = 5: w + hb_index = i; + } + + HB->input_arg = (void*) hb_index; + HB->output_arg = (void*) hb_index; + + HB->c.pi.kits = CUR_KiTs_GAIN; + HB->c.pi.kp = CUR_KP_GAIN; + + //callbacks + HB->get_input = POS_HB_Input; + HB->write_output = POS_HB_Output; + + //start it up + Start_HBridge_CC_Controller(hb_index+1); + } +#endif + + //adjust references of position controllers + //x1 is top, x2 is bot + double xs[2] = {DEFAULT_X_TOP_REF, DEFAULT_X_BOT_REF}; + double ys[2] = {DEFAULT_Y_TOP_REF, DEFAULT_Y_BOT_REF}; + double xthx[2]; + double ythy[2]; + ConvertFromX1X2(xs, xthx); + ConvertFromX1X2(ys, ythy); + + PosControllers.x[0].reference = xthx[0]; + PosControllers.x[1].reference = xthx[1]; + + PosControllers.y[0].reference = ythy[0]; + PosControllers.y[1].reference = ythy[1]; + return SUCCESS; +} + + +/***************************** + * Stop_PosContTry1_Controller() + * Unregisters the position controller. Note that this does + * not stop any corresponding current controller + * + *vsi: the VSI number to unregister (1 - VSI_DQ_SVPWM_NUM_VSI) + *returns a success code + */ +int Stop_PosContTry1_Controller(u32 poscnt) +{ + u32 i = poscnt-1; + if (i >= 4) + return INVALID_ARGUMENT; + if (pos_cont_items[2*i].bRegistered == TRUE) + UnregisterController(0, &pos_cont_items[2*i]); + if (pos_cont_items[2*i+1].bRegistered == TRUE) + UnregisterController(0, &pos_cont_items[2*i+1]); + return SUCCESS; +} + +/***************************** + * PosContTry1_StopCommand() + * Process an ascii command for stopping the position controllers + * and any associated current controllers + * + *szCmd: incoming command + *szResponse: the response to the command + *CommDevice: pointer to information about the communication device + * this was received on + */ +int PosContTry1_StopCommand(const char *szCmd, char *szResponse, void *CommDevice) +{ + int i; + for (i=0; i< 4; i++) + { + Stop_PosContTry1_Controller(i+1); + } +#if defined(USE_VSI_CC) || defined(USE_H_BRIDGE_DQ_CC) + Stop_VSI_DQ_SVPWM_Controller(VSI_BOT_INDEX); + Stop_VSI_DQ_SVPWM_Controller(VSI_TOP_INDEX); +#endif +#if defined(USE_H_BRIDGE_CC) + for (i=0; i < 6; i++) + Stop_HBridge_CC_Controller(i); +#endif + + strcpy(szResponse, "OK"); + return strlen(szResponse); +} + + +/***************************** + * PosContTry1_StartCommand() + * Process an ascii command for starting the position controllers + * Init_PosContTry1 is called + * + * Example: CST=1,FORCEI=1 + *szCmd: incoming command + *szResponse: the response to the command + *CommDevice: pointer to information about the communication device + * this was received on + */ +int PosContTry1_StartCommand(const char *szCmd, char *szResponse, void *CommDevice) +{ + + if (strstr(szCmd, "FORCEI")) + { + strcpy(szResponse, "FORCEI=1"); + bForceXY_Currents = TRUE; + } + else + { + bForceXY_Currents = FALSE; + strcpy(szResponse, "OK"); + } + + + Init_PosContTry1(TRUE); + + return strlen(szResponse); +} + +/***************************** + * PosContTry1_Command() + * Process an ascii command for setting a reference position (or current) + * Syntax: n,tb,val + * n is the controller axis (x for x-axis, y for y-axis), + * tb is t for top, b for bottom, + * val is the mm reference (*128) + * + *szCmd: incoming command + *szResponse: the response to the command + *CommDevice: pointer to information about the communication device + * this was received on + */ +int PosContTry1_Command(const char * szCmd, char *szResponse, void *CommDevice) +{ + u8 tb = szCmd[0]; + u8 bError = FALSE; + double ref; + if ((tb != 'b') && (tb != 't') ) + bError = TRUE; + else if (szCmd[1] != ',') + bError = TRUE; + else + { + u8 xy = szCmd[2]; + if ((xy != 'x') && (xy != 'y') ) + bError = TRUE; + else if (szCmd[3] != ',') + bError = TRUE; + else if (szCmd[4] == 0) + bError = TRUE; + else + { + ref = ((double) atoi(&szCmd[4]))/128; + if (bForceXY_Currents) + { + if (tb == 't') + { + if (xy == 'x') + force_ixy_top[0] = ref; + else + force_ixy_top[1] = ref; + } + else + { + if (xy == 'x') + force_ixy_bot[0] = ref; + else + force_ixy_bot[1] = ref; + } + strcpy(szResponse, "OK"); + } + else //not supported yet + bError = TRUE; + } + + } + if (bError) + strcpy(szResponse, "ERROR"); + + return strlen(szResponse); +} + + + + +//Internal function called by control.c before executing a controller +static void POS_Input(void *arg, struct controller_context *cnt) +{ +// u32 i= (u32) arg; + + //calculate the error and store it + if (TimeElapsed10us(PosControllers.InputAtTickCount) > 5) + { + + PosControllers.InputAtTickCount = MainTimerTimerTick; + PosControllers.xs[POS_BOT_INDEX] = BOT_ADC_MM_V*ReadADC(BOTX_ADC); + PosControllers.xs[POS_TOP_INDEX] = TOP_ADC_MM_V*ReadADC(TOPX_ADC); + PosControllers.ys[POS_BOT_INDEX] = BOT_ADC_MM_V*ReadADC(BOTY_ADC); + PosControllers.ys[POS_TOP_INDEX] = TOP_ADC_MM_V*ReadADC(TOPY_ADC); + double x1x2[2] = {PosControllers.xs[POS_TOP_INDEX], PosControllers.xs[POS_BOT_INDEX]}; + double y1y2[2] = {PosControllers.ys[POS_TOP_INDEX], PosControllers.ys[POS_BOT_INDEX]}; + ConvertFromX1X2(x1x2, PosControllers.x_thx); + ConvertFromX1X2(y1y2, PosControllers.y_thy); + + PosControllers.x[0].input = PosControllers.x[0].reference - PosControllers.x_thx[0]; + PosControllers.x[1].input = PosControllers.x[1].reference - PosControllers.x_thx[1]; + PosControllers.y[0].input = PosControllers.y[0].reference - PosControllers.y_thy[0]; + PosControllers.y[1].input = PosControllers.y[1].reference - PosControllers.y_thy[1]; + + //logging + x0_meas = (s32) 128.0*PosControllers.x_thx[0]; + y0_meas = (s32) 128.0*PosControllers.y_thy[0]; + thx = (s32) 128.0*PosControllers.x_thx[1]; + thy = (s32) 128.0*PosControllers.y_thy[1]; + x0Error = (s32) 128.0*PosControllers.x[0].input; + y0Error = (s32) 128.0*PosControllers.y[0].input; + thxError = (s32) 128.0*PosControllers.x[1].input; + thyError = (s32) 128.0*PosControllers.y[1].input; + + } +} + +//Internal function called by control.c when an output is ready +static void POS_Output(void *arg, struct controller_context *cnt) +{ + u32 i= (u32) arg; + + switch (i) + { + case 0: + PosControllers.x[0].updated = TRUE; + break; + + case 1: + PosControllers.x[1].updated = TRUE; + break; + + case 2: + PosControllers.y[0].updated = TRUE; + break; + + case 3: + PosControllers.y[1].updated = TRUE; + break; + + default: + break; + } + + + if ( (PosControllers.x[0].updated == TRUE) && (PosControllers.x[1].updated==TRUE) + && (PosControllers.y[0].updated == TRUE) && (PosControllers.y[1].updated==TRUE)) + { + double current_xy_top[2], current_xy_bot[2], current_12x[2], current_12y[2], current_sumdiff[2]; + //all controller output current references have been updated, + //update the xy current holder taking into account maximum current values + PosControllers.x[0].updated = FALSE; + PosControllers.x[1].updated = FALSE; + PosControllers.y[0].updated = FALSE; + PosControllers.y[1].updated = FALSE; + + //get top bot x currents + current_sumdiff[0] = PosControllers.x[POS_XY0_INDEX].output; + current_sumdiff[1] = PosControllers.x[POS_THXY_INDEX].output; + ConvertFromSumDiff(current_sumdiff, current_12x); + current_xy_top[0] = current_12x[0]; + current_xy_bot[0] = current_12x[1]; //NOT negative because the bottom force is NOT created in the opposite direction + + //get top bot y currents + current_sumdiff[0] = PosControllers.y[POS_XY0_INDEX].output; + current_sumdiff[1] = PosControllers.y[POS_THXY_INDEX].output; + ConvertFromSumDiff(current_sumdiff, current_12y); + current_xy_top[1] = current_12y[0]; + current_xy_bot[1] = current_12y[1]; //NOT negative because the bottom force is NOT created in the opposite direction + + //if we are forcing the currents, override the above calculations + if (bForceXY_Currents) + { + current_xy_top[0] = force_ixy_top[0]; + current_xy_top[1] = force_ixy_top[1]; + current_xy_bot[0] = force_ixy_bot[0]; + current_xy_bot[1] = force_ixy_bot[1]; + } + + //saturate the top bot xy currents +#if defined(USE_VSI_CC) || defined(USE_H_BRIDGE_DQ_CC) + SaturateDQCurrents(PosControllers.MaxPhaseCurrent, current_xy_top, PosControllers.Itop_xy); + SaturateDQCurrents(PosControllers.MaxPhaseCurrent, current_xy_bot, PosControllers.Ibot_xy); +#else + PosControllers.Itop_xy[0] = current_xy_top[0]; PosControllers.Itop_xy[1] = current_xy_top[1]; + PosControllers.Ibot_xy[0] = current_xy_bot[0]; PosControllers.Ibot_xy[1] = current_xy_bot[1]; +#endif + +#if defined(USE_H_BRIDGE_CC) + { + double i_xy0[3], i_uvw[3]; + i_xy0[0] = PosControllers.Itop_xy[0]; + i_xy0[1] = PosControllers.Itop_xy[1]; + i_xy0[2] = 0; + InverseDQ0_Transform(0, i_uvw, i_xy0); + SaturatePhaseCurrents(PosControllers.MaxPhaseCurrent, i_uvw, PosControllers.Itop_uvw_sus); + i_xy0[0] = PosControllers.Ibot_xy[0]; i_xy0[1] = PosControllers.Ibot_xy[1]; i_xy0[2] = 0; + InverseDQ0_Transform(0, i_uvw, i_xy0); + SaturatePhaseCurrents(PosControllers.MaxPhaseCurrent, i_uvw, PosControllers.Ibot_uvw_sus); + } +#endif + + //logging + Ixb_ref_usat = (s32) 128.0*current_xy_bot[0]; + Iyb_ref_usat = (s32) 128.0*current_xy_bot[1]; + Ixt_ref_usat = (s32) 128.0*current_xy_top[0]; + Iyt_ref_usat = (s32) 128.0*current_xy_top[1]; + } +} + + +#if defined(USE_VSI_CC) || defined(USE_H_BRIDGE_DQ_CC) +//update reference and measured currents +//return false if ABC values set, true if DQ values set +static u8 POS_VSI_Input(void *arg, void *VSIContext) +{ + u32 vsi_index = (u32) arg; + u32 adc_num[3]; + struct VSI_context *cnt = VSIContext; + //double meas_abc[3], meas_dq0[3]; + double adc_gain = CS_ADC_AMP_PER_VOLT; + + //MEASURED CURRENTS + if (vsi_index == VSI_BOT_INDEX) + { + adc_num[0] = BOT_US_ADC; adc_num[1] = BOT_VS_ADC; adc_num[2] = BOT_WS_ADC; + } + else + { + adc_num[0] = TOP_US_ADC; adc_num[1] = TOP_VS_ADC; adc_num[2] = TOP_WS_ADC; + } + + cnt->Iabc[0] = adc_gain*ReadADC(adc_num[0]); + cnt->Iabc[1] = adc_gain*ReadADC(adc_num[1]); + cnt->Iabc[2] = adc_gain*ReadADC(adc_num[2]); + cnt->theta_da = 0; + + //REFERENCE DQ CURRENTS + if (vsi_index == VSI_BOT_INDEX) + { +#if defined(USE_H_BRIDGE_DQ_CC) + cnt->d.reference = PosControllers.Ibot_xy[0]; + cnt->q.reference = PosControllers.Ibot_xy[1]; +#endif + +#if defined(USE_VSI_CC) + cnt->d.reference = PosControllers.Ibot_xy[0] - 0.5*PosControllers.TorqueVSI_botIxy[0]; + cnt->q.reference = PosControllers.Ibot_xy[1] - 0.5*PosControllers.TorqueVSI_botIxy[1]; +#endif + //logging + Ixb_ref = (s32) 128.0*PosControllers.Ibot_xy[0]; //PosControllers.Ibot_xy[0] - 0.5*PosControllers.TorqueVSI_topIxy[0]; + Iyb_ref = (s32) 128.0*PosControllers.Ibot_xy[1]; //PosControllers.Ibot_xy[1] - 0.5*PosControllers.TorqueVSI_topIxy[1]; + } + else + { +#if defined(USE_H_BRIDGE_DQ_CC) + cnt->d.reference = PosControllers.Itop_xy[0]; + cnt->q.reference = PosControllers.Itop_xy[1]; +#endif +#if defined(USE_VSI_CC) + cnt->d.reference = PosControllers.Itop_xy[0] - 0.5*PosControllers.TorqueVSI_topIxy[0]; + cnt->q.reference = PosControllers.Itop_xy[1] - 0.5*PosControllers.TorqueVSI_topIxy[1]; +#endif + //logging + Ixt_ref = (s32) 128.0*PosControllers.Itop_xy[0]; + Iyt_ref = (s32) 128.0*PosControllers.Itop_xy[1]; + } + return FALSE; +} + +//write the duty ratio out to the legs +static void POS_VSI_Output(void *arg, void *VSIContext) +{ + u32 vsi_index = (u32) arg; + u32 legs[6]; + u8 duty1, duty2, duty3; + struct VSI_context *cnt = VSIContext; + legs[0] = 0; legs[1] = 0; legs[2] = 0; + int i; + +#if defined(USE_H_BRIDGE_DQ_CC) + if (vsi_index == VSI_BOT_INDEX) + { + legs[0] = BOT_US_L1; legs[1] = BOT_US_L2; + legs[2] = BOT_VS_L1; legs[3] = BOT_VS_L2; + legs[4] = BOT_WS_L1; legs[5] = BOT_WS_L2; + } + else + { + legs[0] = TOP_US_L1; legs[1] = TOP_US_L2; + legs[2] = TOP_VS_L1; legs[3] = TOP_VS_L2; + legs[4] = TOP_WS_L1; legs[5] = TOP_WS_L2; + } + + //convert the modulation indices to duty ratios + for (i = 0; i < 3; i++) + { + double m; + u8 d1, d2; + //safety to avoid roll-over: + if (cnt->mabc[i] > 1.0) + m = 1.0; + else if (cnt->mabc[i] < -1.0) + m = -1.0; + else + m = cnt->mabc[i]; + + + //calculate duty ratios + d1 = (unsigned char) 127*(1 + m); + d2 = (unsigned char) 127*(1 - m); + + //write it out + WriteDutyRatio(legs[i*2], d1); + WriteDutyRatio(legs[i*2+1], d2); + + } +#endif + +#if defined(USE_VSI_CC) + if (vsi_index == VSI_BOT_INDEX) + { + legs[0] = BOT_US_LEG; legs[1] = BOT_VS_LEG; legs[2] = BOT_WS_LEG; + } + else + { + legs[0] = TOP_US_LEG; legs[1] = TOP_VS_LEG; legs[2] = TOP_WS_LEG; + } + //convert the duty ratios + //dtest = 256*(d_com + m_abc[0]); + duty1 = (unsigned char) 256.0*(cnt->dabc[0]); + duty2 = (unsigned char) 256.0*(cnt->dabc[1]); + duty3 = (unsigned char) 256.0*(cnt->dabc[2]); + + //write them out: + WriteDutyRatio(legs[0], duty1); + WriteDutyRatio(legs[1], duty2); + WriteDutyRatio(legs[2], duty3); +#endif +} +#endif + +#if defined(USE_H_BRIDGE_CC) +//update reference and measured currents +//return false if ABC values set, true if DQ values set +static u8 POS_HB_Input(void *arg, void *HBContext) +{ + u32 hb_index = (u32) arg; + u32 adc_num = 0; + struct HB_context *cnt = HBContext; + double adc_gain = CS_ADC_AMP_PER_VOLT; + + //MEASURED CURRENTS + switch(hb_index) + { + case 0: + adc_num = TOP_US_ADC; + break; + case 1: + adc_num = TOP_VS_ADC; + break; + case 2: + adc_num = TOP_WS_ADC; + break; + case 3: + adc_num = BOT_US_ADC; + break; + case 4: + adc_num = BOT_VS_ADC; + break; + case 5: + adc_num = BOT_WS_ADC; + break; + default: + //should not get here! + break; + } + + //update the measured current + cnt->I = adc_gain*ReadADC(adc_num); + + //update reference currents + if (hb_index < 3) + HBridge_CC_SetCurrentRef(hb_index+1, PosControllers.Itop_uvw_sus[hb_index]); + else + HBridge_CC_SetCurrentRef(hb_index+1, PosControllers.Ibot_uvw_sus[hb_index-3]); + + //logging + Ixt_ref = (s32) 128.0*PosControllers.Itop_xy[0]; + Iyt_ref = (s32) 128.0*PosControllers.Itop_xy[1]; + Ixb_ref = (s32) 128.0*PosControllers.Ibot_xy[0]; + Iyb_ref = (s32) 128.0*PosControllers.Ibot_xy[1]; + + return FALSE; +} + +//write the duty ratio out to the legs +static void POS_HB_Output(void *arg, void *HBContext) +{ + u32 hb_index = (u32) arg; + u32 legs[2]; + + struct HB_context *cnt = HBContext; + legs[0] = 0; legs[1] = 0; + + switch(hb_index) + { + case 0: + legs[0] = TOP_US_L1; + legs[1] = TOP_US_L2; + break; + case 1: + legs[0] = TOP_VS_L1; + legs[1] = TOP_VS_L2; + break; + case 2: + legs[0] = TOP_WS_L1; + legs[1] = TOP_WS_L2; + break; + case 3: + legs[0] = BOT_US_L1; + legs[1] = BOT_US_L2; + break; + case 4: + legs[0] = BOT_VS_L1; + legs[1] = BOT_VS_L2; + break; + case 5: + legs[0] = BOT_WS_L1; + legs[1] = BOT_WS_L2; + break; + default: + //should not get here! + break; + } + + //write them out: + WriteDutyRatio(legs[0], cnt->d[0]); + WriteDutyRatio(legs[1], cnt->d[1]); +} +#endif diff --git a/sdk/basic/control_apps/PosContTry1.h b/sdk/basic/control_apps/PosContTry1.h old mode 100755 new mode 100644 index dbace2b5..6c52edb2 --- a/sdk/basic/control_apps/PosContTry1.h +++ b/sdk/basic/control_apps/PosContTry1.h @@ -1,65 +1,65 @@ -#ifndef __POS_CONT_TRY1_H -#define __POS_CONT_TRY1_H - -//#define USE_H_BRIDGE_CC //uncomment this for HBridge CC (Bridge config) -//#define USE_H_BRIDGE_DQ_CC //uncomment this for using Hbridges controlled by a dq0 controller -#define USE_VSI_CC //uncomment this for VSI CC (Parallel config) -#define VSI_ISOLATED //uncomment this if using isolated VSI's in parallel config - -#define VSI_BOT_INDEX 0 -#define VSI_TOP_INDEX 1 - - -#define POS_BOT_INDEX 0 -#define POS_TOP_INDEX 1 - -#define POS_XY0_INDEX 0 -#define POS_THXY_INDEX 1 - -typedef struct pid_house -{ - pid_controller pid; - controller_context io; - controller_holder ctxt; - double input; - double output; - double reference; - u8 updated; //set to TRUE everytime this controller output is updated, cleared everytime the output is used - //1 to 1 double adc_scale; //3 amps per volt, wound around twice gives me a factor of 3/2 -} pid_house; - -typedef struct PosCntVSI_context -{ - pid_house x[2]; - pid_house y[2]; -#if defined(USE_VSI_CC) || defined(USE_H_BRIDGE_DQ_CC) - struct VSI_context *VSItop; - struct VSI_context *VSIbot; -#endif -#if defined(USE_H_BRIDGE_CC) - struct HB_context *HBtop[3]; - struct HB_context *HBbot[3]; - double Itop_uvw_sus[3]; //reference suspension uvw currents - double Ibot_uvw_sus[3]; //reference suspension uvw currents -#endif - u32 InputAtTickCount; //the tick count of the last time the inputs were updated (to avoid unnecessary dq transformations) - double x_thx[2]; - double y_thy[2]; - double xs[2]; - double ys[2]; - double Itop_xy[2]; - double Ibot_xy[2]; - double MaxPhaseCurrent; - double TorqueVSI_topIxy[2]; - double TorqueVSI_botIxy[2]; -} PosCnt_context; - -extern PosCnt_context PosControllers; - -extern int Init_PosContTry1(u8 StartAllControllers); -extern int Stop_PosContTry1_Controller(u32 poscnt); -extern int PosContTry1_StopCommand(const char *szCmd, char *szResponse, void *CommDevice); -extern int PosContTry1_StartCommand(const char *szCmd, char *szResponse, void *CommDevice); -extern int PosContTry1_Command(const char * szCmd, char *szResponse, void *CommDevice); -#endif //__POS_CONT_TRY1_H - +#ifndef __POS_CONT_TRY1_H +#define __POS_CONT_TRY1_H + +//#define USE_H_BRIDGE_CC //uncomment this for HBridge CC (Bridge config) +//#define USE_H_BRIDGE_DQ_CC //uncomment this for using Hbridges controlled by a dq0 controller +#define USE_VSI_CC //uncomment this for VSI CC (Parallel config) +#define VSI_ISOLATED //uncomment this if using isolated VSI's in parallel config + +#define VSI_BOT_INDEX 0 +#define VSI_TOP_INDEX 1 + + +#define POS_BOT_INDEX 0 +#define POS_TOP_INDEX 1 + +#define POS_XY0_INDEX 0 +#define POS_THXY_INDEX 1 + +typedef struct pid_house +{ + pid_controller pid; + controller_context io; + controller_holder ctxt; + double input; + double output; + double reference; + u8 updated; //set to TRUE everytime this controller output is updated, cleared everytime the output is used + //1 to 1 double adc_scale; //3 amps per volt, wound around twice gives me a factor of 3/2 +} pid_house; + +typedef struct PosCntVSI_context +{ + pid_house x[2]; + pid_house y[2]; +#if defined(USE_VSI_CC) || defined(USE_H_BRIDGE_DQ_CC) + struct VSI_context *VSItop; + struct VSI_context *VSIbot; +#endif +#if defined(USE_H_BRIDGE_CC) + struct HB_context *HBtop[3]; + struct HB_context *HBbot[3]; + double Itop_uvw_sus[3]; //reference suspension uvw currents + double Ibot_uvw_sus[3]; //reference suspension uvw currents +#endif + u32 InputAtTickCount; //the tick count of the last time the inputs were updated (to avoid unnecessary dq transformations) + double x_thx[2]; + double y_thy[2]; + double xs[2]; + double ys[2]; + double Itop_xy[2]; + double Ibot_xy[2]; + double MaxPhaseCurrent; + double TorqueVSI_topIxy[2]; + double TorqueVSI_botIxy[2]; +} PosCnt_context; + +extern PosCnt_context PosControllers; + +extern int Init_PosContTry1(u8 StartAllControllers); +extern int Stop_PosContTry1_Controller(u32 poscnt); +extern int PosContTry1_StopCommand(const char *szCmd, char *szResponse, void *CommDevice); +extern int PosContTry1_StartCommand(const char *szCmd, char *szResponse, void *CommDevice); +extern int PosContTry1_Command(const char * szCmd, char *szResponse, void *CommDevice); +#endif //__POS_CONT_TRY1_H + diff --git a/sdk/basic/control_apps/TorqueVSI.c b/sdk/basic/control_apps/TorqueVSI.c old mode 100755 new mode 100644 index 3fbf43fe..51d27339 --- a/sdk/basic/control_apps/TorqueVSI.c +++ b/sdk/basic/control_apps/TorqueVSI.c @@ -1,481 +1,481 @@ -/* - * TorqueVSI.c - * - * Created on: Jul 17, 2014 - * Author: sever212 - */ - -#include "../src/project_include.h" - - -#define OMEGA_DA_RAMP_RATE 0.001 - -#define DEFAULT_T_SINE_TRIANGLE 1 -#define MAX_PHASE_CURRENT 1 -const u8 TVSI_INDEX[NUM_TVSI] = {2}; - - - -TVSI_context TVSIs[NUM_TVSI]; - -#define IField 1 - -#if defined (USE_VSI_CC) - #define TVSI_KiTs_Q_GAIN 0.001675516 //0.0010053 //0.001675 //0.0032 //0.0063 //Old val (works): 0.0151 //0.0008 //0.005 //Ki_t*Ts/Vbus - #define TVSI_KiTs_D_GAIN 0.001675516 //0.0010053 //0.001675 //0.0032 //0.0063 //0.0151 //0.0008 //0.005 //Ki_t*Ts/Vbus - - #define TVSI_KP_Q_GAIN 0.1590065 //0.09540388 //0.159006 //0.2981 //0.5963 //Old val (works): 1.431 //.076 //0.452 //Kp_t/Vbus - #define TVSI_KP_D_GAIN 0.1590065 //0.09540388 //0.159006 //0.2981 //0.5963 //1.431 //.076 //0.452 //Kp_t/Vbus - - - #define T0_U_ADC 11 - #define T0_V_ADC 12 - - #define T0_U_LEG 11 - #define T0_V_LEG 12 - #define T0_W_LEG 13 - - #define Lq_div_Vbus 0.00002531 //0.000126533 //Lq/Vbus - #define Ld_div_Vbus 0.00002531 //0.000126533 //Ld/Vbus - #define sqrt6_Lfg_div_Vbus 0.00009219 //0.0004609576 //sqrt(6)*Lfg_m/Vbus - -#endif - -#if defined(TVSI_STATIONARY_FRAME) - const u8 TVSI_STATIONARY_INDEX[NUM_TVSI] = {3}; - - #define TVSI_KiTs_X_GAIN TVSI_KiTs_D_GAIN - #define TVSI_KiTs_Y_GAIN TVSI_KiTs_D_GAIN - - #define TVSI_KP_X_GAIN 0 - #define TVSI_KP_Y_GAIN 0 - - static u8 T_VSI_Input_Stationary(void *arg, void *VSIContext); - static void T_VSI_Output_Stationary(void *arg, void *VSIContext); - - //logging - u32 Itx_measured, Ity_measured; - u32 Itx_ref, Ity_ref; - u32 x_out_ref, y_out_ref; - u32 dxy_out_ref, qxy_out_ref; -#endif - -#if defined (USE_H_BRIDGE_CC) || defined(USE_H_BRIDGE_DQ_CC) - //wc = 2*pi*750 - #define TVSI_KiTs_Q_GAIN 0.00837758 //0.0047 //0.0151 //Ki_t*Ts/Vbus - #define TVSI_KiTs_D_GAIN 0.00837758 //0.0047 //0.0151 //Ki_t*Ts/Vbus - - #define TVSI_KP_Q_GAIN 0.7950 //0.13499 //1.431 //Kp_t/Vbus - #define TVSI_KP_D_GAIN 0.7950 //0.13499 //1.431 //Kp_t/Vbus - - #define T0_U_ADC 11 - #define T0_V_ADC 12 - - #define T0_U_LEG 1 - #define T0_V_LEG 2 - #define T0_W_LEG 3 - - #define Lq_div_Vbus 0.000126533 //Lq/Vbus - #define Ld_div_Vbus 0.000126533 //Ld/Vbus - #define sqrt6_Lfg_div_Vbus 0.0004609576 //sqrt(6)*Lfg_m/Vbus -#endif - -s32 OmegaDA_Log = 0; - -static u8 T_VSI_Input(void *arg, void *VSIContext); -static void T_VSI_Output(void *arg, void *VSIContext); - -static double GetTheta_DA(double theta_da, double omega_da, u32 LastTickCNT) -{ - double update_da = 0; - u32 elapsed; - elapsed = TimeElapsed10us(LastTickCNT); - update_da = ((double) omega_da*((double)elapsed)/((double)100000.0)); - theta_da += update_da; - while (theta_da > PI2) - theta_da = theta_da - PI2; - - return theta_da; -} -u32 t_vsi_theta_da; - -/***************************** - * Init_TorqueVSI() - * Sets up the controllers memory to default values - * and optionally starts the controllers running. - * The default settings can be overridden by manually - * editing the VSI_DQ_Cur_Controllers structure. - * - *StartAllControllers: this is ignored - *returns a success code - */ -int Init_TorqueVSI(u8 StartAllControllers) -{ - int i; - -#if defined(USE_H_BRIDGE_CC) - Init_VSI_DQ_VSPWM(FALSE); //We need to init the VSI controllers in the HBridge case because the position controller has not done that. -#endif - - for (i = 0; i < NUM_TVSI; i++) - { - TVSIs[i].MaxPhaseCurrent = MAX_PHASE_CURRENT; - TVSIs[i].InputAtTickCount = MainTimerTimerTick; - TVSIs[i].OmegaDA_Cmd = 0; - TVSIs[i].OmegaDA_Current = 0; - TVSIs[i].VSI = &VSI_DQ_Cur_Controllers[TVSI_INDEX[i]]; - TVSIs[i].VSI->theta_da = 0; - TVSIs[i].Idq_ref[0] = 0; - TVSIs[i].Idq_ref[1] = 0; - - //assume init_vsi_dq_VSPWM has already been called - TVSIs[i].VSI->bSineTriangle = DEFAULT_T_SINE_TRIANGLE; - - //controller gains - TVSIs[i].VSI->d.pi.kits = TVSI_KiTs_D_GAIN; - TVSIs[i].VSI->d.pi.kp = TVSI_KP_D_GAIN; - TVSIs[i].VSI->q.pi.kits = TVSI_KiTs_Q_GAIN; - TVSIs[i].VSI->q.pi.kp = TVSI_KP_Q_GAIN; - - //callbacks - TVSIs[i].VSI->input_arg = (void*) i; - TVSIs[i].VSI->output_arg = (void*) i; - TVSIs[i].VSI->get_input = T_VSI_Input; - TVSIs[i].VSI->write_output = T_VSI_Output; - -#if defined (TVSI_STATIONARY_FRAME) - TVSIs[i].VSI_stationary = &VSI_DQ_Cur_Controllers[TVSI_STATIONARY_INDEX[i]]; - TVSIs[i].VSI_stationary->theta_da = 0; - - //assume init_vsi_dq_VSPWM has already been called - TVSIs[i].VSI_stationary->bSineTriangle = DEFAULT_T_SINE_TRIANGLE; - - //controller gains - TVSIs[i].VSI_stationary->d.pi.kits = TVSI_KiTs_X_GAIN; - TVSIs[i].VSI_stationary->d.pi.kp = TVSI_KP_X_GAIN; - TVSIs[i].VSI_stationary->q.pi.kits = TVSI_KiTs_Y_GAIN; - TVSIs[i].VSI_stationary->q.pi.kp = TVSI_KP_Y_GAIN; - - //callbacks - TVSIs[i].VSI_stationary->input_arg = (void*) i; - TVSIs[i].VSI_stationary->output_arg = (void*) i; - TVSIs[i].VSI_stationary->get_input = T_VSI_Input_Stationary; - TVSIs[i].VSI_stationary->write_output = T_VSI_Output_Stationary; - - Start_VSI_DQ_SVPWM_Controller(TVSI_STATIONARY_INDEX[i]+1); -#endif - - //start up the current controller - Start_VSI_DQ_SVPWM_Controller(TVSI_INDEX[i]+1); - } - return SUCCESS; -} - - -/***************************** - * Stop_TorqueVSI_Controller() - * Unregisters the VSI's belonging to the TVSI controller. - * - *tvsi: the TVSI number to unregister (1 - NUM_TVSI) - *returns a success code - */ -int Stop_TorqueVSI_Controller(u32 tvsi) -{ - u32 i = tvsi-1; - if (i >= NUM_TVSI) - return INVALID_ARGUMENT; - -#if defined(TVSI_STATIONARY_FRAME) - Stop_VSI_DQ_SVPWM_Controller(TVSI_STATIONARY_INDEX[i]+1); -#endif - return Stop_VSI_DQ_SVPWM_Controller(TVSI_INDEX[i]+1); -} - - -/***************************** - * TorqueVSI_StopCommand() - * Process an ascii command for stopping the torque VSI current controllers - * and any associated current controllers - * - *szCmd: incoming command - *szResponse: the response to the command - *CommDevice: pointer to information about the communication device - * this was received on - */ -int TorqueVSI_StopCommand(const char *szCmd, char *szResponse, void *CommDevice) -{ - int i; - for (i=0; i< 4; i++) - { - Stop_TorqueVSI_Controller(i+1); - } - strcpy(szResponse, "OK"); - return strlen(szResponse); -} - - -/***************************** - * TorqueVSI_StartCommand() - * Process an ascii command for starting the torque VSI controllers - * Init_PosContTry1 is called - * - *szCmd: incoming command - *szResponse: the response to the command - *CommDevice: pointer to information about the communication device - * this was received on - */ -int TorqueVSI_StartCommand(const char *szCmd, char *szResponse, void *CommDevice) -{ - - /*if (strstr(szCmd, "FORCEI")) - { - strcpy(szResponse, "FORCEI=1"); - bForceXY_Currents = TRUE; - } - else - { - bForceXY_Currents = FALSE;*/ - strcpy(szResponse, "OK"); - //} - - - Init_TorqueVSI(TRUE); - - return strlen(szResponse); -} - - -/***************************** - * PosContTry1_Command() - * Process an ascii command for setting a reference position (or current) - * Syntax: n,v,val - * n is the controller index (1 or 2), - * v is the variable to set (d for d axis current, q for q axis current, w for reference OmegaDa command) - * val is the value (*128) - * - *szCmd: incoming command - *szResponse: the response to the command - *CommDevice: pointer to information about the communication device - * this was received on - */ -int TorqueVSI_Command(const char * szCmd, char *szResponse, void *CommDevice) -{ - u8 num = atoi(szCmd); - u8 bError = FALSE; - double ref; - if ((num != 1) ) - bError = TRUE; - else if (szCmd[1] != ',') - bError = TRUE; - else - { - u8 v = szCmd[2]; - if ((v != 'd') && (v != 'q') && (v != 'w')) - bError = TRUE; - else if (szCmd[3] != ',') - bError = TRUE; - else if (szCmd[4] == 0) - bError = TRUE; - else - { - ref = ((double) atoi(&szCmd[4]))/128; - if (v == 'd') - { - TVSIs[num-1].Idq_ref[0] = ref; - strcpy(szResponse, "OK"); - } - else if (v == 'q') - { - TVSIs[num-1].Idq_ref[1] = ref; - strcpy(szResponse, "OK"); - } - else if (v == 'w') - { - TVSIs[num-1].OmegaDA_Cmd = ref; - strcpy(szResponse, "OK"); - } - else //not supported yet - bError = TRUE; - } - - } - if (bError) - strcpy(szResponse, "ERROR"); - - return strlen(szResponse); -} - -//update reference and measured currents -//return false if ABC values set, true if DQ values set -static u8 T_VSI_Input(void *arg, void *VSIContext) -{ - u32 t_index = (u32) arg; - u32 adc_num[3]; - struct VSI_context *cnt = VSIContext; - //double meas_abc[3], meas_dq0[3]; - - //MEASURED CURRENTS - if (t_index == 0) - { - adc_num[0] = T0_U_ADC; adc_num[1] = T0_V_ADC; - adc_num[2] = 0; //use a+b+c =0 - } - else - { - ; //adc_num[0] = TOP_US_ADC; adc_num[1] = TOP_VS_ADC; adc_num[2] = TOP_WS_ADC; //should not get here! - } - - cnt->Iabc[0] = 0.6*ReadADC(adc_num[0]); - cnt->Iabc[1] = 0.6*ReadADC(adc_num[1]); - cnt->Iabc[2] = -cnt->Iabc[0] -cnt->Iabc[1]; //ReadADC(adc_num[2]); -#if defined (USE_VSI_CC) && !defined(VSI_ISOLATED) - cnt->Iabc[2] = cnt->Iabc[2] - (PosControllers.VSItop->Iabc[0] + PosControllers.VSItop->Iabc[1] + PosControllers.VSItop->Iabc[2]); -#endif - - cnt->theta_da = GetTheta_DA(cnt->theta_da, TVSIs[t_index].OmegaDA_Current, TVSIs[t_index].InputAtTickCount); - DQ0_Transform(cnt->theta_da, cnt->Iabc, cnt->Idq0); - - //compensation terms: - cnt->dqComp[0] = 0; //-TVSIs[t_index].OmegaDA_Current*Lq_div_Vbus*cnt->Idq0[1]; - cnt->dqComp[1] = 0; //TVSIs[t_index].OmegaDA_Current*(Ld_div_Vbus*cnt->Idq0[0] + sqrt6_Lfg_div_Vbus*IField); - -#if defined (TVSI_STATIONARY_FRAME) - //add the stationary frame terms as additional compensation - { - //cnt->dqComp[0] += TVSIs[t_index].VSI_stationary->d.output*cos(cnt->theta_da) + TVSIs[t_index].VSI_stationary->q.output*sin(cnt->theta_da); - //cnt->dqComp[1] += TVSIs[t_index].VSI_stationary->q.output*cos(cnt->theta_da) - TVSIs[t_index].VSI_stationary->d.output*sin(cnt->theta_da); - double new_dq0[3], old_dq0[3], test_uvw[3], alt_dq0[3]; - old_dq0[0] = TVSIs[t_index].VSI_stationary->d.output; - old_dq0[1] = TVSIs[t_index].VSI_stationary->q.output; - old_dq0[2] = 0; - ChangeDQ_ReferenceFrame(new_dq0, cnt->theta_da, old_dq0, 0.0); - cnt->dqComp[0] = cnt->dqComp[0] + new_dq0[0]; - cnt->dqComp[1] = cnt->dqComp[1] + new_dq0[1]; - - //debugging - //InverseDQ0_Transform(0.0, test_uvw, old_dq0); - //DQ0_Transform(cnt->theta_da, test_uvw, alt_dq0); - - //logging - /*x_out_ref = (s32)(128.0*old_dq0[0]); - y_out_ref = (s32)(128.0*old_dq0[1]); - dxy_out_ref = (s32)(128.0*(alt_dq0[0] - new_dq0[0])); //(s32)(128.0*new_dq0[0]); - qxy_out_ref = (s32)(128.0*(alt_dq0[1] - new_dq0[1])); //(s32)(128.0*new_dq0[1]);*/ - - } -#endif - - //acceleration - if (TVSIs[t_index].OmegaDA_Cmd != TVSIs[t_index].OmegaDA_Current) - { - if (TVSIs[t_index].OmegaDA_Cmd > TVSIs[t_index].OmegaDA_Current) - { - TVSIs[t_index].OmegaDA_Current += OMEGA_DA_RAMP_RATE*TimeElapsed10us(TVSIs[t_index].InputAtTickCount); - if (TVSIs[t_index].OmegaDA_Current > TVSIs[t_index].OmegaDA_Cmd) - TVSIs[t_index].OmegaDA_Current = TVSIs[t_index].OmegaDA_Cmd; - } - else if (TVSIs[t_index].OmegaDA_Cmd < TVSIs[t_index].OmegaDA_Current) - { - TVSIs[t_index].OmegaDA_Current -= OMEGA_DA_RAMP_RATE*TimeElapsed10us(TVSIs[t_index].InputAtTickCount); - if (TVSIs[t_index].OmegaDA_Current < TVSIs[t_index].OmegaDA_Cmd) - TVSIs[t_index].OmegaDA_Current = TVSIs[t_index].OmegaDA_Cmd; - } - } - - //should limit the reference currents, but for now don't worry about it: - cnt->d.reference = TVSIs[t_index].Idq_ref[0]; - cnt->q.reference = TVSIs[t_index].Idq_ref[1]; - -#if defined(USE_VSI_CC) - //inform the position controller what we are up to - { - double new_dq0[3], old_dq0[3]; - old_dq0[0] = cnt->d.reference; - old_dq0[1] = cnt->q.reference; - old_dq0[2] = 0; - //PosControllers.TorqueVSI_topIxy[0] = cnt->d.reference*cos(cnt->theta_da) - cnt->q.reference*sin(cnt->theta_da); - //PosControllers.TorqueVSI_topIxy[1] = cnt->q.reference*cos(cnt->theta_da) + cnt->d.reference*sin(cnt->theta_da); - ChangeDQ_ReferenceFrame(new_dq0, 0.0, old_dq0, cnt->theta_da); - PosControllers.TorqueVSI_topIxy[0] = new_dq0[0]; - PosControllers.TorqueVSI_topIxy[1] = new_dq0[1]; - } -#endif - - //update the tick count: - TVSIs[t_index].InputAtTickCount = MainTimerTimerTick; - - //logging - if (t_index == 0) - OmegaDA_Log = (s32)(128.0*TVSIs[t_index].OmegaDA_Current); - return TRUE; -} - -//write the duty ratio out to the legs -static void T_VSI_Output(void *arg, void *VSIContext) -{ - u32 tvsi_index = (u32) arg; - u32 legs[3]; - u8 duty1, duty2, duty3; - struct VSI_context *cnt = VSIContext; - legs[0] = 0; legs[1] = 0; legs[2] = 0; - - if (tvsi_index == 0) - { - legs[0] = T0_U_LEG; legs[1] = T0_V_LEG; legs[2] = T0_W_LEG; - } - else - { - ; //should not get here legs[0] = TOP_US_LEG; legs[1] = TOP_VS_LEG; legs[2] = TOP_WS_LEG; - } - - - //convert the duty ratios - //dtest = 256*(d_com + m_abc[0]); - duty1 = (unsigned char) 256.0*(cnt->dabc[0]); - duty2 = (unsigned char) 256.0*(cnt->dabc[1]); - duty3 = (unsigned char) 256.0*(cnt->dabc[2]); - - //write them out: - WriteDutyRatio(legs[0], duty1); - WriteDutyRatio(legs[1], duty2); - WriteDutyRatio(legs[2], duty3); -} - -#if defined(TVSI_STATIONARY_FRAME) -//update reference and measured currents -//return false if ABC values set, true if DQ values set -static u8 T_VSI_Input_Stationary(void *arg, void *VSIContext) -{ - u32 t_index = (u32) arg; - struct VSI_context *cnt = VSIContext; - double new_dq0[3], old_dq0[3]; - - //use the measured VSI currents (transform them into the stationary reference frame) - ChangeDQ_ReferenceFrame(TVSIs[t_index].VSI_stationary->Idq0, 0.0, TVSIs[t_index].VSI->Idq0, TVSIs[t_index].VSI->theta_da); - - //the reference currents also need to be brought over from the other frame - old_dq0[0] = TVSIs[t_index].VSI->d.reference; - old_dq0[1] = TVSIs[t_index].VSI->q.reference; - old_dq0[2] = 0; - ChangeDQ_ReferenceFrame(new_dq0, 0.0, old_dq0, TVSIs[t_index].VSI->theta_da); - - cnt->d.reference = new_dq0[0]; - cnt->q.reference = new_dq0[1]; - - //logging: - /*Itx_measured = (s32)(128.0*TVSIs[t_index].VSI_stationary->Idq0[0]); - Ity_measured = (s32)(128.0*TVSIs[t_index].VSI_stationary->Idq0[1]); - Itx_ref = (s32)(128.0*TVSIs[t_index].VSI_stationary->d.reference); - Ity_ref = (s32)(128.0*TVSIs[t_index].VSI_stationary->q.reference);*/ - - return TRUE; -} - -//normally would write the duty ratio out to the legs, but don't do anything, let the other output function handle all of this. -static void T_VSI_Output_Stationary(void *arg, void *VSIContext) -{ - -} - -#endif - +/* + * TorqueVSI.c + * + * Created on: Jul 17, 2014 + * Author: sever212 + */ + +#include "../src/project_include.h" + + +#define OMEGA_DA_RAMP_RATE 0.001 + +#define DEFAULT_T_SINE_TRIANGLE 1 +#define MAX_PHASE_CURRENT 1 +const u8 TVSI_INDEX[NUM_TVSI] = {2}; + + + +TVSI_context TVSIs[NUM_TVSI]; + +#define IField 1 + +#if defined (USE_VSI_CC) + #define TVSI_KiTs_Q_GAIN 0.001675516 //0.0010053 //0.001675 //0.0032 //0.0063 //Old val (works): 0.0151 //0.0008 //0.005 //Ki_t*Ts/Vbus + #define TVSI_KiTs_D_GAIN 0.001675516 //0.0010053 //0.001675 //0.0032 //0.0063 //0.0151 //0.0008 //0.005 //Ki_t*Ts/Vbus + + #define TVSI_KP_Q_GAIN 0.1590065 //0.09540388 //0.159006 //0.2981 //0.5963 //Old val (works): 1.431 //.076 //0.452 //Kp_t/Vbus + #define TVSI_KP_D_GAIN 0.1590065 //0.09540388 //0.159006 //0.2981 //0.5963 //1.431 //.076 //0.452 //Kp_t/Vbus + + + #define T0_U_ADC 11 + #define T0_V_ADC 12 + + #define T0_U_LEG 11 + #define T0_V_LEG 12 + #define T0_W_LEG 13 + + #define Lq_div_Vbus 0.00002531 //0.000126533 //Lq/Vbus + #define Ld_div_Vbus 0.00002531 //0.000126533 //Ld/Vbus + #define sqrt6_Lfg_div_Vbus 0.00009219 //0.0004609576 //sqrt(6)*Lfg_m/Vbus + +#endif + +#if defined(TVSI_STATIONARY_FRAME) + const u8 TVSI_STATIONARY_INDEX[NUM_TVSI] = {3}; + + #define TVSI_KiTs_X_GAIN TVSI_KiTs_D_GAIN + #define TVSI_KiTs_Y_GAIN TVSI_KiTs_D_GAIN + + #define TVSI_KP_X_GAIN 0 + #define TVSI_KP_Y_GAIN 0 + + static u8 T_VSI_Input_Stationary(void *arg, void *VSIContext); + static void T_VSI_Output_Stationary(void *arg, void *VSIContext); + + //logging + u32 Itx_measured, Ity_measured; + u32 Itx_ref, Ity_ref; + u32 x_out_ref, y_out_ref; + u32 dxy_out_ref, qxy_out_ref; +#endif + +#if defined (USE_H_BRIDGE_CC) || defined(USE_H_BRIDGE_DQ_CC) + //wc = 2*pi*750 + #define TVSI_KiTs_Q_GAIN 0.00837758 //0.0047 //0.0151 //Ki_t*Ts/Vbus + #define TVSI_KiTs_D_GAIN 0.00837758 //0.0047 //0.0151 //Ki_t*Ts/Vbus + + #define TVSI_KP_Q_GAIN 0.7950 //0.13499 //1.431 //Kp_t/Vbus + #define TVSI_KP_D_GAIN 0.7950 //0.13499 //1.431 //Kp_t/Vbus + + #define T0_U_ADC 11 + #define T0_V_ADC 12 + + #define T0_U_LEG 1 + #define T0_V_LEG 2 + #define T0_W_LEG 3 + + #define Lq_div_Vbus 0.000126533 //Lq/Vbus + #define Ld_div_Vbus 0.000126533 //Ld/Vbus + #define sqrt6_Lfg_div_Vbus 0.0004609576 //sqrt(6)*Lfg_m/Vbus +#endif + +s32 OmegaDA_Log = 0; + +static u8 T_VSI_Input(void *arg, void *VSIContext); +static void T_VSI_Output(void *arg, void *VSIContext); + +static double GetTheta_DA(double theta_da, double omega_da, u32 LastTickCNT) +{ + double update_da = 0; + u32 elapsed; + elapsed = TimeElapsed10us(LastTickCNT); + update_da = ((double) omega_da*((double)elapsed)/((double)100000.0)); + theta_da += update_da; + while (theta_da > PI2) + theta_da = theta_da - PI2; + + return theta_da; +} +u32 t_vsi_theta_da; + +/***************************** + * Init_TorqueVSI() + * Sets up the controllers memory to default values + * and optionally starts the controllers running. + * The default settings can be overridden by manually + * editing the VSI_DQ_Cur_Controllers structure. + * + *StartAllControllers: this is ignored + *returns a success code + */ +int Init_TorqueVSI(u8 StartAllControllers) +{ + int i; + +#if defined(USE_H_BRIDGE_CC) + Init_VSI_DQ_VSPWM(FALSE); //We need to init the VSI controllers in the HBridge case because the position controller has not done that. +#endif + + for (i = 0; i < NUM_TVSI; i++) + { + TVSIs[i].MaxPhaseCurrent = MAX_PHASE_CURRENT; + TVSIs[i].InputAtTickCount = MainTimerTimerTick; + TVSIs[i].OmegaDA_Cmd = 0; + TVSIs[i].OmegaDA_Current = 0; + TVSIs[i].VSI = &VSI_DQ_Cur_Controllers[TVSI_INDEX[i]]; + TVSIs[i].VSI->theta_da = 0; + TVSIs[i].Idq_ref[0] = 0; + TVSIs[i].Idq_ref[1] = 0; + + //assume init_vsi_dq_VSPWM has already been called + TVSIs[i].VSI->bSineTriangle = DEFAULT_T_SINE_TRIANGLE; + + //controller gains + TVSIs[i].VSI->d.pi.kits = TVSI_KiTs_D_GAIN; + TVSIs[i].VSI->d.pi.kp = TVSI_KP_D_GAIN; + TVSIs[i].VSI->q.pi.kits = TVSI_KiTs_Q_GAIN; + TVSIs[i].VSI->q.pi.kp = TVSI_KP_Q_GAIN; + + //callbacks + TVSIs[i].VSI->input_arg = (void*) i; + TVSIs[i].VSI->output_arg = (void*) i; + TVSIs[i].VSI->get_input = T_VSI_Input; + TVSIs[i].VSI->write_output = T_VSI_Output; + +#if defined (TVSI_STATIONARY_FRAME) + TVSIs[i].VSI_stationary = &VSI_DQ_Cur_Controllers[TVSI_STATIONARY_INDEX[i]]; + TVSIs[i].VSI_stationary->theta_da = 0; + + //assume init_vsi_dq_VSPWM has already been called + TVSIs[i].VSI_stationary->bSineTriangle = DEFAULT_T_SINE_TRIANGLE; + + //controller gains + TVSIs[i].VSI_stationary->d.pi.kits = TVSI_KiTs_X_GAIN; + TVSIs[i].VSI_stationary->d.pi.kp = TVSI_KP_X_GAIN; + TVSIs[i].VSI_stationary->q.pi.kits = TVSI_KiTs_Y_GAIN; + TVSIs[i].VSI_stationary->q.pi.kp = TVSI_KP_Y_GAIN; + + //callbacks + TVSIs[i].VSI_stationary->input_arg = (void*) i; + TVSIs[i].VSI_stationary->output_arg = (void*) i; + TVSIs[i].VSI_stationary->get_input = T_VSI_Input_Stationary; + TVSIs[i].VSI_stationary->write_output = T_VSI_Output_Stationary; + + Start_VSI_DQ_SVPWM_Controller(TVSI_STATIONARY_INDEX[i]+1); +#endif + + //start up the current controller + Start_VSI_DQ_SVPWM_Controller(TVSI_INDEX[i]+1); + } + return SUCCESS; +} + + +/***************************** + * Stop_TorqueVSI_Controller() + * Unregisters the VSI's belonging to the TVSI controller. + * + *tvsi: the TVSI number to unregister (1 - NUM_TVSI) + *returns a success code + */ +int Stop_TorqueVSI_Controller(u32 tvsi) +{ + u32 i = tvsi-1; + if (i >= NUM_TVSI) + return INVALID_ARGUMENT; + +#if defined(TVSI_STATIONARY_FRAME) + Stop_VSI_DQ_SVPWM_Controller(TVSI_STATIONARY_INDEX[i]+1); +#endif + return Stop_VSI_DQ_SVPWM_Controller(TVSI_INDEX[i]+1); +} + + +/***************************** + * TorqueVSI_StopCommand() + * Process an ascii command for stopping the torque VSI current controllers + * and any associated current controllers + * + *szCmd: incoming command + *szResponse: the response to the command + *CommDevice: pointer to information about the communication device + * this was received on + */ +int TorqueVSI_StopCommand(const char *szCmd, char *szResponse, void *CommDevice) +{ + int i; + for (i=0; i< 4; i++) + { + Stop_TorqueVSI_Controller(i+1); + } + strcpy(szResponse, "OK"); + return strlen(szResponse); +} + + +/***************************** + * TorqueVSI_StartCommand() + * Process an ascii command for starting the torque VSI controllers + * Init_PosContTry1 is called + * + *szCmd: incoming command + *szResponse: the response to the command + *CommDevice: pointer to information about the communication device + * this was received on + */ +int TorqueVSI_StartCommand(const char *szCmd, char *szResponse, void *CommDevice) +{ + + /*if (strstr(szCmd, "FORCEI")) + { + strcpy(szResponse, "FORCEI=1"); + bForceXY_Currents = TRUE; + } + else + { + bForceXY_Currents = FALSE;*/ + strcpy(szResponse, "OK"); + //} + + + Init_TorqueVSI(TRUE); + + return strlen(szResponse); +} + + +/***************************** + * PosContTry1_Command() + * Process an ascii command for setting a reference position (or current) + * Syntax: n,v,val + * n is the controller index (1 or 2), + * v is the variable to set (d for d axis current, q for q axis current, w for reference OmegaDa command) + * val is the value (*128) + * + *szCmd: incoming command + *szResponse: the response to the command + *CommDevice: pointer to information about the communication device + * this was received on + */ +int TorqueVSI_Command(const char * szCmd, char *szResponse, void *CommDevice) +{ + u8 num = atoi(szCmd); + u8 bError = FALSE; + double ref; + if ((num != 1) ) + bError = TRUE; + else if (szCmd[1] != ',') + bError = TRUE; + else + { + u8 v = szCmd[2]; + if ((v != 'd') && (v != 'q') && (v != 'w')) + bError = TRUE; + else if (szCmd[3] != ',') + bError = TRUE; + else if (szCmd[4] == 0) + bError = TRUE; + else + { + ref = ((double) atoi(&szCmd[4]))/128; + if (v == 'd') + { + TVSIs[num-1].Idq_ref[0] = ref; + strcpy(szResponse, "OK"); + } + else if (v == 'q') + { + TVSIs[num-1].Idq_ref[1] = ref; + strcpy(szResponse, "OK"); + } + else if (v == 'w') + { + TVSIs[num-1].OmegaDA_Cmd = ref; + strcpy(szResponse, "OK"); + } + else //not supported yet + bError = TRUE; + } + + } + if (bError) + strcpy(szResponse, "ERROR"); + + return strlen(szResponse); +} + +//update reference and measured currents +//return false if ABC values set, true if DQ values set +static u8 T_VSI_Input(void *arg, void *VSIContext) +{ + u32 t_index = (u32) arg; + u32 adc_num[3]; + struct VSI_context *cnt = VSIContext; + //double meas_abc[3], meas_dq0[3]; + + //MEASURED CURRENTS + if (t_index == 0) + { + adc_num[0] = T0_U_ADC; adc_num[1] = T0_V_ADC; + adc_num[2] = 0; //use a+b+c =0 + } + else + { + ; //adc_num[0] = TOP_US_ADC; adc_num[1] = TOP_VS_ADC; adc_num[2] = TOP_WS_ADC; //should not get here! + } + + cnt->Iabc[0] = 0.6*ReadADC(adc_num[0]); + cnt->Iabc[1] = 0.6*ReadADC(adc_num[1]); + cnt->Iabc[2] = -cnt->Iabc[0] -cnt->Iabc[1]; //ReadADC(adc_num[2]); +#if defined (USE_VSI_CC) && !defined(VSI_ISOLATED) + cnt->Iabc[2] = cnt->Iabc[2] - (PosControllers.VSItop->Iabc[0] + PosControllers.VSItop->Iabc[1] + PosControllers.VSItop->Iabc[2]); +#endif + + cnt->theta_da = GetTheta_DA(cnt->theta_da, TVSIs[t_index].OmegaDA_Current, TVSIs[t_index].InputAtTickCount); + DQ0_Transform(cnt->theta_da, cnt->Iabc, cnt->Idq0); + + //compensation terms: + cnt->dqComp[0] = 0; //-TVSIs[t_index].OmegaDA_Current*Lq_div_Vbus*cnt->Idq0[1]; + cnt->dqComp[1] = 0; //TVSIs[t_index].OmegaDA_Current*(Ld_div_Vbus*cnt->Idq0[0] + sqrt6_Lfg_div_Vbus*IField); + +#if defined (TVSI_STATIONARY_FRAME) + //add the stationary frame terms as additional compensation + { + //cnt->dqComp[0] += TVSIs[t_index].VSI_stationary->d.output*cos(cnt->theta_da) + TVSIs[t_index].VSI_stationary->q.output*sin(cnt->theta_da); + //cnt->dqComp[1] += TVSIs[t_index].VSI_stationary->q.output*cos(cnt->theta_da) - TVSIs[t_index].VSI_stationary->d.output*sin(cnt->theta_da); + double new_dq0[3], old_dq0[3], test_uvw[3], alt_dq0[3]; + old_dq0[0] = TVSIs[t_index].VSI_stationary->d.output; + old_dq0[1] = TVSIs[t_index].VSI_stationary->q.output; + old_dq0[2] = 0; + ChangeDQ_ReferenceFrame(new_dq0, cnt->theta_da, old_dq0, 0.0); + cnt->dqComp[0] = cnt->dqComp[0] + new_dq0[0]; + cnt->dqComp[1] = cnt->dqComp[1] + new_dq0[1]; + + //debugging + //InverseDQ0_Transform(0.0, test_uvw, old_dq0); + //DQ0_Transform(cnt->theta_da, test_uvw, alt_dq0); + + //logging + /*x_out_ref = (s32)(128.0*old_dq0[0]); + y_out_ref = (s32)(128.0*old_dq0[1]); + dxy_out_ref = (s32)(128.0*(alt_dq0[0] - new_dq0[0])); //(s32)(128.0*new_dq0[0]); + qxy_out_ref = (s32)(128.0*(alt_dq0[1] - new_dq0[1])); //(s32)(128.0*new_dq0[1]);*/ + + } +#endif + + //acceleration + if (TVSIs[t_index].OmegaDA_Cmd != TVSIs[t_index].OmegaDA_Current) + { + if (TVSIs[t_index].OmegaDA_Cmd > TVSIs[t_index].OmegaDA_Current) + { + TVSIs[t_index].OmegaDA_Current += OMEGA_DA_RAMP_RATE*TimeElapsed10us(TVSIs[t_index].InputAtTickCount); + if (TVSIs[t_index].OmegaDA_Current > TVSIs[t_index].OmegaDA_Cmd) + TVSIs[t_index].OmegaDA_Current = TVSIs[t_index].OmegaDA_Cmd; + } + else if (TVSIs[t_index].OmegaDA_Cmd < TVSIs[t_index].OmegaDA_Current) + { + TVSIs[t_index].OmegaDA_Current -= OMEGA_DA_RAMP_RATE*TimeElapsed10us(TVSIs[t_index].InputAtTickCount); + if (TVSIs[t_index].OmegaDA_Current < TVSIs[t_index].OmegaDA_Cmd) + TVSIs[t_index].OmegaDA_Current = TVSIs[t_index].OmegaDA_Cmd; + } + } + + //should limit the reference currents, but for now don't worry about it: + cnt->d.reference = TVSIs[t_index].Idq_ref[0]; + cnt->q.reference = TVSIs[t_index].Idq_ref[1]; + +#if defined(USE_VSI_CC) + //inform the position controller what we are up to + { + double new_dq0[3], old_dq0[3]; + old_dq0[0] = cnt->d.reference; + old_dq0[1] = cnt->q.reference; + old_dq0[2] = 0; + //PosControllers.TorqueVSI_topIxy[0] = cnt->d.reference*cos(cnt->theta_da) - cnt->q.reference*sin(cnt->theta_da); + //PosControllers.TorqueVSI_topIxy[1] = cnt->q.reference*cos(cnt->theta_da) + cnt->d.reference*sin(cnt->theta_da); + ChangeDQ_ReferenceFrame(new_dq0, 0.0, old_dq0, cnt->theta_da); + PosControllers.TorqueVSI_topIxy[0] = new_dq0[0]; + PosControllers.TorqueVSI_topIxy[1] = new_dq0[1]; + } +#endif + + //update the tick count: + TVSIs[t_index].InputAtTickCount = MainTimerTimerTick; + + //logging + if (t_index == 0) + OmegaDA_Log = (s32)(128.0*TVSIs[t_index].OmegaDA_Current); + return TRUE; +} + +//write the duty ratio out to the legs +static void T_VSI_Output(void *arg, void *VSIContext) +{ + u32 tvsi_index = (u32) arg; + u32 legs[3]; + u8 duty1, duty2, duty3; + struct VSI_context *cnt = VSIContext; + legs[0] = 0; legs[1] = 0; legs[2] = 0; + + if (tvsi_index == 0) + { + legs[0] = T0_U_LEG; legs[1] = T0_V_LEG; legs[2] = T0_W_LEG; + } + else + { + ; //should not get here legs[0] = TOP_US_LEG; legs[1] = TOP_VS_LEG; legs[2] = TOP_WS_LEG; + } + + + //convert the duty ratios + //dtest = 256*(d_com + m_abc[0]); + duty1 = (unsigned char) 256.0*(cnt->dabc[0]); + duty2 = (unsigned char) 256.0*(cnt->dabc[1]); + duty3 = (unsigned char) 256.0*(cnt->dabc[2]); + + //write them out: + WriteDutyRatio(legs[0], duty1); + WriteDutyRatio(legs[1], duty2); + WriteDutyRatio(legs[2], duty3); +} + +#if defined(TVSI_STATIONARY_FRAME) +//update reference and measured currents +//return false if ABC values set, true if DQ values set +static u8 T_VSI_Input_Stationary(void *arg, void *VSIContext) +{ + u32 t_index = (u32) arg; + struct VSI_context *cnt = VSIContext; + double new_dq0[3], old_dq0[3]; + + //use the measured VSI currents (transform them into the stationary reference frame) + ChangeDQ_ReferenceFrame(TVSIs[t_index].VSI_stationary->Idq0, 0.0, TVSIs[t_index].VSI->Idq0, TVSIs[t_index].VSI->theta_da); + + //the reference currents also need to be brought over from the other frame + old_dq0[0] = TVSIs[t_index].VSI->d.reference; + old_dq0[1] = TVSIs[t_index].VSI->q.reference; + old_dq0[2] = 0; + ChangeDQ_ReferenceFrame(new_dq0, 0.0, old_dq0, TVSIs[t_index].VSI->theta_da); + + cnt->d.reference = new_dq0[0]; + cnt->q.reference = new_dq0[1]; + + //logging: + /*Itx_measured = (s32)(128.0*TVSIs[t_index].VSI_stationary->Idq0[0]); + Ity_measured = (s32)(128.0*TVSIs[t_index].VSI_stationary->Idq0[1]); + Itx_ref = (s32)(128.0*TVSIs[t_index].VSI_stationary->d.reference); + Ity_ref = (s32)(128.0*TVSIs[t_index].VSI_stationary->q.reference);*/ + + return TRUE; +} + +//normally would write the duty ratio out to the legs, but don't do anything, let the other output function handle all of this. +static void T_VSI_Output_Stationary(void *arg, void *VSIContext) +{ + +} + +#endif + diff --git a/sdk/basic/control_apps/TorqueVSI.h b/sdk/basic/control_apps/TorqueVSI.h old mode 100755 new mode 100644 index cd96c07f..9fee225e --- a/sdk/basic/control_apps/TorqueVSI.h +++ b/sdk/basic/control_apps/TorqueVSI.h @@ -1,28 +1,28 @@ -#ifndef __TORQUE_VSI_H -#define __TORQUE_VSI_H - -#define NUM_TVSI 1 - -#if defined (USE_VSI_CC) -//#define TVSI_STATIONARY_FRAME //comment this out to turn off the torque stationary frame controller -#endif - -typedef struct TVSI_context -{ - struct VSI_context *VSI; -#if defined (TVSI_STATIONARY_FRAME) - struct VSI_context *VSI_stationary; -#endif - u32 InputAtTickCount; //the tick count of the last time the inputs were updated (to avoid unnecessary dq transformations) - double OmegaDA_Cmd; - double OmegaDA_Current; - double MaxPhaseCurrent; - double Idq_ref[2]; -} TVSI_context; - -extern int Init_TorqueVSI(u8 StartAllControllers); -extern int Stop_TorqueVSI_Controller(u32 tvsi); -extern int TorqueVSI_StopCommand(const char *szCmd, char *szResponse, void *CommDevice); -extern int TorqueVSI_StartCommand(const char *szCmd, char *szResponse, void *CommDevice); -extern int TorqueVSI_Command(const char * szCmd, char *szResponse, void *CommDevice); -#endif //__TORQUE_VSI_H +#ifndef __TORQUE_VSI_H +#define __TORQUE_VSI_H + +#define NUM_TVSI 1 + +#if defined (USE_VSI_CC) +//#define TVSI_STATIONARY_FRAME //comment this out to turn off the torque stationary frame controller +#endif + +typedef struct TVSI_context +{ + struct VSI_context *VSI; +#if defined (TVSI_STATIONARY_FRAME) + struct VSI_context *VSI_stationary; +#endif + u32 InputAtTickCount; //the tick count of the last time the inputs were updated (to avoid unnecessary dq transformations) + double OmegaDA_Cmd; + double OmegaDA_Current; + double MaxPhaseCurrent; + double Idq_ref[2]; +} TVSI_context; + +extern int Init_TorqueVSI(u8 StartAllControllers); +extern int Stop_TorqueVSI_Controller(u32 tvsi); +extern int TorqueVSI_StopCommand(const char *szCmd, char *szResponse, void *CommDevice); +extern int TorqueVSI_StartCommand(const char *szCmd, char *szResponse, void *CommDevice); +extern int TorqueVSI_Command(const char * szCmd, char *szResponse, void *CommDevice); +#endif //__TORQUE_VSI_H diff --git a/sdk/basic/control_apps/VSI_DQ_SVPWM.c b/sdk/basic/control_apps/VSI_DQ_SVPWM.c old mode 100755 new mode 100644 index 6d07b67a..c50fd806 --- a/sdk/basic/control_apps/VSI_DQ_SVPWM.c +++ b/sdk/basic/control_apps/VSI_DQ_SVPWM.c @@ -1,683 +1,683 @@ -/* - * VSI_DQ_SVPWM.c - * - * Created on: Jun 30, 2014 - * Author: sever212 - */ - -#include "../src/project_include.h" -//#include - - -#define KiTs_Q_GAIN 0.005 -#define KiTs_D_GAIN 0.005 - -#define KP_Q_GAIN 0.452 -#define KP_D_GAIN 0.452 - -#define DEFAULT_SINE_TRIANGLE 1 //0 for SVPWM, 1 for SINE TRIANGLE - - -//assumes the dq voltages are a fraction of the dc bus voltage -int SaturateDQ0Voltages(double *inputDQ, double *outputDQ, u8 bSineTriangle) -{ - double ml, ml_0, a; - if (bSineTriangle) - { - ml = 1.632993161855452*sqrt(inputDQ[0]*inputDQ[0] + inputDQ[1]*inputDQ[1]); - ml_0 = 0.816496580927726*fabs(inputDQ[2]); - a = 0.816496580927726; - } - else - { - ml = sqrt(2.0*(inputDQ[0]*inputDQ[0] + inputDQ[1]*inputDQ[1])); - ml_0 = 0.707106781186548*fabs(inputDQ[2]); - a = 0.707106781186548; - } - - if (ml > 1.0) //case 1: limit d and q, no zero sequence - { - outputDQ[0] = inputDQ[0]/ml; - outputDQ[1] = inputDQ[1]/ml; - outputDQ[2] = 0; //Zero seq reference set to 0 - } - else if (ml + ml_0 > 1.0) //case 2: no limit on d and q, limit zero sequence - { - outputDQ[0] = inputDQ[0]; - outputDQ[1] = inputDQ[1]; - if (inputDQ[2] > 0.0) - outputDQ[2] = (1.0-ml)/a; - else - outputDQ[2] = -(1.0-ml)/a; - } - else //case 3: no limits. - { - outputDQ[0] = inputDQ[0]; - outputDQ[1] = inputDQ[1]; - outputDQ[2] = inputDQ[2]; - - } - return SUCCESS; -} - -//assumes the dq voltages are a fraction of the dc bus voltage -int SaturateDQVoltages(double *inputDQ, double *outputDQ, u8 bSineTriangle) -{ - double ml; - if (bSineTriangle) - ml = 1.632993161855452*sqrt(inputDQ[0]*inputDQ[0] + inputDQ[1]*inputDQ[1]); - else - ml = sqrt(2.0*(inputDQ[0]*inputDQ[0] + inputDQ[1]*inputDQ[1])); - - if (ml > 1.0) - { - outputDQ[0] = inputDQ[0]/ml; - outputDQ[1] = inputDQ[1]/ml; - } - else - { - outputDQ[0] = inputDQ[0]; - outputDQ[1] = inputDQ[1]; - } - return SUCCESS; -} - -int DQ0_Transform(double theta_da, double *abc, double *dq0) -{ - dq0[0] = DQK*(cos(theta_da)*abc[0] +cos(theta_da - PI23)*abc[1] +cos(theta_da + PI23)*abc[2]); - dq0[1] = -DQK*(sin(theta_da)*abc[0] +sin(theta_da - PI23)*abc[1] +sin(theta_da + PI23)*abc[2]); - dq0[2] = DQK*( abc[0] +abc[1] +abc[2]); - return SUCCESS; -} - -int InverseDQ0_Transform(double theta_da, double *abc, double *dq0) -{ - abc[0] = DQK*(cos(theta_da)*dq0[0] -sin(theta_da)*dq0[1] +0.5*dq0[2]); - abc[1] = DQK*(cos(theta_da - PI23)*dq0[0] -sin(theta_da - PI23)*dq0[1] +0.5*dq0[2]); - abc[2] = DQK*(cos(theta_da + PI23)*dq0[0] -sin(theta_da + PI23)*dq0[1] +0.5*dq0[2]); - return SUCCESS; -} - -double GetMid(double m1, double m2, double m3) -{ - if ( (m2 >= m1) && (m1 >= m3) ) - return m1; - if ( (m3 >= m1) && (m1 >= m2) ) - return m1; - if ( (m1 >= m2) && (m2 >= m3)) - return m2; - if ( (m3 >= m2) && (m2 >= m1)) - return m2; - if ( (m1 >= m3) && (m3 >= m2) ) - return m3; - if ( (m2 >= m3) && (m3 >= m1)) - return m3; - return m1; //should never get here! -} - -//change the reference frame of a dq0 value. -int ChangeDQ_ReferenceFrame(double *new_dq0, double new_theta_da, double *old_dq0, double old_theta_da) -{ - double theta = old_theta_da - new_theta_da; - - new_dq0[0] = old_dq0[0]*cos(theta) - old_dq0[1]*sin(theta); - new_dq0[1] = old_dq0[0]*sin(theta) + old_dq0[1]*cos(theta); - new_dq0[2] = old_dq0[2]; - - return SUCCESS; -} - -#define OUTPUT_FREQ 120.0 //Hz -//#define THETA_DA GetTheta_DA() /*0.0 //212 //*/ //((double) 2.0*PI*OUTPUT_FREQ*((double)MainTimerTimerTick)/((double)100000.0)) - - -double GetTheta_DA() -{ - static double theta_da = 0; - double update_da = 0; - static u32 LastTickCNT = 0; - u32 elapsed; - elapsed = TimeElapsed10us(LastTickCNT); - LastTickCNT = MainTimerTimerTick; - update_da = ((double) 2.0*PI*OUTPUT_FREQ*((double)elapsed)/((double)100000.0)); - theta_da += update_da; - while (theta_da > PI2) - theta_da = theta_da - PI2; - - return theta_da; -} - -u32 vsi_theta_da; - - -static u8 ExampleVSI_NeedsInput(void *arg, void *VSIContext); -static void ExampleVSI_WriteOutput(void *arg, void *VSIContext); - -VSI_context VSI_DQ_Cur_Controllers[VSI_DQ_SVPWM_NUM_VSI]; -static controller_linked_list_item cont_items [3*VSI_DQ_SVPWM_NUM_VSI]; - -//callbacks: -static void VSI_Input(void *arg, struct controller_context *cnt); -static void VSI_Output(void *arg, struct controller_context *cnt); - -//logging: -u32 VSI_V1_da, VSI_V1_db, VSI_V1_dc; -s32 VSI_V1_d_error, VSI_V1_q_error, VSI_V1_d_current, VSI_V1_q_current; - - -//non-control -- allows d and q voltages to be forced to a certain value (fraction of dc bus) -double force_vd[VSI_DQ_SVPWM_NUM_VSI]; -double force_vq[VSI_DQ_SVPWM_NUM_VSI]; -u8 bForceDQ_Voltages = 0; - -/***************************** - * Init_VSI_DQ_VSPWM() - * Sets up the controllers memory to default values - * and optionally starts the controllers running. - * The default settings can be overridden by manually - * editing the VSI_DQ_Cur_Controllers structure. - * - *StartAllControllers: if this is set to TRUE, all the - * controllers are registered in control.c and started. - *returns a success code - */ -int Init_VSI_DQ_VSPWM(u8 StartAllControllers) -{ - //pi_house *pi_ptr = HB_Controllers; - int i; - for (i = 0; i= VSI_DQ_SVPWM_NUM_VSI) - return INVALID_ARGUMENT; - if (cont_items[3*i].bRegistered == TRUE) - return INVALID_OPERATION; - if (cont_items[3*i+1].bRegistered == TRUE) - return INVALID_OPERATION; - if (VSI_DQ_Cur_Controllers[i].bUseZeroSequence) - if (cont_items[3*i+2].bRegistered == TRUE) - return INVALID_OPERATION; - - RegisterController(0, &cont_items[3*i]); - RegisterController(0, &cont_items[3*i+1]); - - if (VSI_DQ_Cur_Controllers[i].bUseZeroSequence) - RegisterController(0, &cont_items[3*i+2]); - - return SUCCESS; -} - -/***************************** - * Stop_VSI_DQ_SVPWM_Controller() - * Unregisters the VSI d and q current controllers from control.c. - * - *vsi: the VSI number to unregister (1 - VSI_DQ_SVPWM_NUM_VSI) - *returns a success code - */ -int Stop_VSI_DQ_SVPWM_Controller(u32 vsi) -{ - u32 i = vsi-1; - if (i >= VSI_DQ_SVPWM_NUM_VSI) - return INVALID_ARGUMENT; - if (cont_items[2*i].bRegistered == TRUE) - UnregisterController(0, &cont_items[3*i]); - if (cont_items[2*i+1].bRegistered == TRUE) - UnregisterController(0, &cont_items[3*i+1]); - if (cont_items[3*i+2].bRegistered == TRUE) - UnregisterController(0, &cont_items[3*i+2]); - - return SUCCESS; -} - -/***************************** - * VSI_DQ_VSPW_StopCommand() - * Process an ascii command for starting VSI controllers - * Init_VSI_DQ_VSPWM is called - * - *szCmd: incoming command - *szResponse: the response to the command - *CommDevice: pointer to information about the communication device - * this was received on - */ -int VSI_DQ_VSPW_StopCommand(const char *szCmd, char *szResponse, void *CommDevice) -{ - int i; - for (i=0; i< VSI_DQ_SVPWM_NUM_VSI; i++) - { - Stop_VSI_DQ_SVPWM_Controller(i+1); - } - - strcpy(szResponse, "OK"); - return strlen(szResponse); -} - -/***************************** - * VSI_DQ_VSPW_StartCommand() - * Process an ascii command for starting VSI controllers - * Init_VSI_DQ_VSPWM is called - * - *szCmd: incoming command - *szResponse: the response to the command - *CommDevice: pointer to information about the communication device - * this was received on - */ -int VSI_DQ_VSPW_StartCommand(const char *szCmd, char *szResponse, void *CommDevice) -{ - if (strstr(szCmd, "FORCEVDQ")) - { - strcpy(szResponse, "FORCEVDQ=1"); - bForceDQ_Voltages = TRUE; - } - else - { - bForceDQ_Voltages = FALSE; - strcpy(szResponse, "OK"); - } - - Init_VSI_DQ_VSPWM(TRUE); - - return strlen(szResponse); -} - -/***************************** - * VSI_DQ_VSPW_Command() - * Process an ascii command for setting a reference current - * Syntax: n,r,val - * n is the Vbridge number (1 - VSI_DQ_SVPWM_NUM_VSI), - * r is d for direct axis or q for quadrature axis, - * val is the current reference value * 128 - * - *szCmd: incoming command - *szResponse: the response to the command - *CommDevice: pointer to information about the communication device - * this was received on - */ -int VSI_DQ_VSPW_Command(const char * szCmd, char *szResponse, void *CommDevice) -{ - const char *ptr; - u32 vsi = atoi(szCmd); - u8 bError = FALSE, bD = FALSE; - if (vsi < 1 || vsi > VSI_DQ_SVPWM_NUM_VSI) - bError = TRUE; - else - { - for (ptr = szCmd; ptr != &szCmd[strlen(szCmd)-1]; ptr++) - if (*ptr == ',') - break; - ptr++; //advance past the comma - if ( (ptr >= &szCmd[strlen(szCmd)]) || (ptr[1] != ',') || ((*ptr != 'd') && (*ptr != 'q')) ) - bError = TRUE; - else - { - double current_ref; - if (ptr[0] == 'd') - bD = TRUE; - - ptr = &ptr[2]; - current_ref = ((double) atoi(ptr))/128; - if (bForceDQ_Voltages == TRUE) - { - if (bD) - force_vd[vsi-1] = current_ref; - else - force_vq[vsi-1] = current_ref; - - strcpy(szResponse, "OK"); - } - else - { - if (VSI_DQ_VSPW_SetCurrentRef(vsi, bD, current_ref) == SUCCESS) - strcpy(szResponse, "OK"); - else - bError = TRUE; - } - } - - } - if (bError) - strcpy(szResponse, "ERROR"); - - return strlen(szResponse); -} - - -/***************************** - * VSI_DQ_VSPW_SetCurrentRef() - * Set a d or q axis reference current - * - * - *vsi: index of the VSI to set the reference current of - *bDaxis: 1 if setting a d-axis quantity, otherwise 0 for q - *reference: the value of the new reference current - */ -int VSI_DQ_VSPW_SetCurrentRef(u32 vsi, u8 bDaxis, double reference) -{ - if (vsi < 1 || vsi > VSI_DQ_SVPWM_NUM_VSI) - return INVALID_ARGUMENT; - if (bDaxis) - VSI_DQ_Cur_Controllers[vsi-1].d.reference = reference; - else - VSI_DQ_Cur_Controllers[vsi-1].q.reference = reference; - - return SUCCESS; -} - -//Internal function called by control.c before executing a controller -static void VSI_Input(void *arg, struct controller_context *cnt) -{ - u32 i=0; - - for (i= 0; i< VSI_DQ_SVPWM_NUM_VSI; i++) - { - if (&VSI_DQ_Cur_Controllers[i].d.io == cnt) - break; - else if (&VSI_DQ_Cur_Controllers[i].q.io == cnt) - break; - else if (&VSI_DQ_Cur_Controllers[i].zero.io == cnt) - break; - - } - - //calculate the error and store it - if (TimeElapsed10us(VSI_DQ_Cur_Controllers[i].InputAtTickCount) > 3) - { - - VSI_DQ_Cur_Controllers[i].InputAtTickCount = MainTimerTimerTick; - - if (!VSI_DQ_Cur_Controllers[i].get_input(VSI_DQ_Cur_Controllers[i].input_arg, &VSI_DQ_Cur_Controllers[i])) - DQ0_Transform(VSI_DQ_Cur_Controllers[i].theta_da, VSI_DQ_Cur_Controllers[i].Iabc, VSI_DQ_Cur_Controllers[i].Idq0); - - VSI_DQ_Cur_Controllers[i].d.input = VSI_DQ_Cur_Controllers[i].d.reference - VSI_DQ_Cur_Controllers[i].Idq0[0]; - VSI_DQ_Cur_Controllers[i].q.input = VSI_DQ_Cur_Controllers[i].q.reference - VSI_DQ_Cur_Controllers[i].Idq0[1]; - //if a zero sequence current controller: - if (VSI_DQ_Cur_Controllers[i].bUseZeroSequence) - VSI_DQ_Cur_Controllers[i].zero.input = VSI_DQ_Cur_Controllers[i].zero.reference - VSI_DQ_Cur_Controllers[i].Idq0[2]; - - //logging: - if (i == 0) - { - VSI_V1_d_error = (s32) (VSI_DQ_Cur_Controllers[i].d.input*128.0); - VSI_V1_q_error = (s32) (VSI_DQ_Cur_Controllers[i].q.input*128.0); - VSI_V1_d_current = (s32) (VSI_DQ_Cur_Controllers[i].Idq0[0]*128.0); - VSI_V1_q_current = (s32) (VSI_DQ_Cur_Controllers[i].Idq0[1]*128.0); - vsi_theta_da = (u32) VSI_DQ_Cur_Controllers[i].theta_da*128.0; - } - - } -} - -//Internal function called by control.c when an output is ready -static void VSI_Output(void *arg, struct controller_context *cnt) -{ - u32 i = 0, n = 0; - double m_dq0[3], mid_m, d_com; - for (i= 0; i< VSI_DQ_SVPWM_NUM_VSI; i++) - { - if (&VSI_DQ_Cur_Controllers[i].d.io == cnt) - { - VSI_DQ_Cur_Controllers[i].d.updated = TRUE; - break; - } - else if (&VSI_DQ_Cur_Controllers[i].q.io == cnt) - { - VSI_DQ_Cur_Controllers[i].q.updated = TRUE; - break; - } - else if (&VSI_DQ_Cur_Controllers[i].zero.io == cnt) - { - VSI_DQ_Cur_Controllers[i].zero.updated = TRUE; - break; - } - } - - if ( (VSI_DQ_Cur_Controllers[i].d.updated == TRUE) && (VSI_DQ_Cur_Controllers[i].q.updated==TRUE) && (VSI_DQ_Cur_Controllers[i].zero.updated==TRUE || (!VSI_DQ_Cur_Controllers[i].bUseZeroSequence))) - { - double dq_raw[3], dq_saturated[3]; - //both d and q have been updated, do the inverse dq transform and write out the duty ratios - - VSI_DQ_Cur_Controllers[i].d.updated = FALSE; - VSI_DQ_Cur_Controllers[i].q.updated = FALSE; - VSI_DQ_Cur_Controllers[i].zero.updated = FALSE; - - //first saturate the outputs: - if (bForceDQ_Voltages == FALSE) - { - dq_raw[0] = VSI_DQ_Cur_Controllers[i].d.output + VSI_DQ_Cur_Controllers[i].dqComp[0]; - dq_raw[1] = VSI_DQ_Cur_Controllers[i].q.output + VSI_DQ_Cur_Controllers[i].dqComp[1]; - if (VSI_DQ_Cur_Controllers[i].bUseZeroSequence) - dq_raw[2] = VSI_DQ_Cur_Controllers[i].zero.output; - } - else - { - //allow to operate VSI open loop - dq_raw[0] = force_vd[i]; - dq_raw[1] = force_vq[i]; - dq_raw[2] = 0; - } - - if (VSI_DQ_Cur_Controllers[i].bUseZeroSequence) - SaturateDQ0Voltages(dq_raw, dq_saturated, VSI_DQ_Cur_Controllers[i].bSineTriangle); - else - SaturateDQVoltages(dq_raw, dq_saturated, VSI_DQ_Cur_Controllers[i].bSineTriangle); - - //dq modulation indices - m_dq0[0] = dq_saturated[0]; - m_dq0[1] = dq_saturated[1]; - if (VSI_DQ_Cur_Controllers[i].bUseZeroSequence) - m_dq0[2] = dq_saturated[2]; - else - m_dq0[2] = 0; - - //abc modulation indices - InverseDQ0_Transform(VSI_DQ_Cur_Controllers[i].theta_da, VSI_DQ_Cur_Controllers[i].mabc, m_dq0); - - //mid modulation indices (for SVPWM) - if (VSI_DQ_Cur_Controllers[i].bSineTriangle) - d_com = 0.5; - else - { - mid_m = GetMid(VSI_DQ_Cur_Controllers[i].mabc[0], VSI_DQ_Cur_Controllers[i].mabc[1], VSI_DQ_Cur_Controllers[i].mabc[2]); - d_com = 0.5*(1+mid_m); - } - - //calculate duty ratios - //dtest = 256*(d_com + m_abc[0]); - VSI_DQ_Cur_Controllers[i].dabc[0] = d_com + VSI_DQ_Cur_Controllers[i].mabc[0]; - VSI_DQ_Cur_Controllers[i].dabc[1] = d_com + VSI_DQ_Cur_Controllers[i].mabc[1]; - VSI_DQ_Cur_Controllers[i].dabc[2] = d_com + VSI_DQ_Cur_Controllers[i].mabc[2]; - - for (n = 0; n < 3; n++) //SAFETY make sure we don't wrap around - { - if (VSI_DQ_Cur_Controllers[i].dabc[n] > 1.0) - VSI_DQ_Cur_Controllers[i].dabc[n] = 1.0; - else if (VSI_DQ_Cur_Controllers[i].dabc[n] < -1.0) - VSI_DQ_Cur_Controllers[i].dabc[n] = -1.0; - } - - //write them out: - VSI_DQ_Cur_Controllers[i].write_output(VSI_DQ_Cur_Controllers[i].output_arg, &VSI_DQ_Cur_Controllers[i]); - - } -} - -//return false if ABC values set, true if DQ values set -static u8 ExampleVSI_NeedsInput(void *arg, void *VSIContext) -{ - u32 i=0; - u32 adc_num[3]; - struct VSI_context *cnt = VSIContext; - //double meas_abc[3], meas_dq0[3]; - adc_num[0] = 4; adc_num[1] = 5; adc_num[2] = 6; - - for (i= 0; i< VSI_DQ_SVPWM_NUM_VSI; i++) - { - if (&VSI_DQ_Cur_Controllers[i] == cnt) - { - if (i == 0) - { - adc_num[0] = 1; adc_num[1] = 2; adc_num[2] = 3; - /*Verror = &VSI_V1_d_error; - Vcurrent = &VSI_V1_d_current;*/ - //bD = TRUE; - } - break; - } - } - - cnt->Iabc[0] = ReadADC(adc_num[0]); - cnt->Iabc[1] = ReadADC(adc_num[1]); - cnt->Iabc[2] = ReadADC(adc_num[2]); - cnt->theta_da = GetTheta_DA(); - - return FALSE; -} - -//return false if ABC values set, true if DQ values set -static void ExampleVSI_WriteOutput(void *arg, void *VSIContext) -{ - u32 legs[3]; - u8 duty1, duty2, duty3; - struct VSI_context *cnt = VSIContext; - int i; - legs[0] = 0; legs[1] = 0; legs[2] = 0; - for (i= 0; i< VSI_DQ_SVPWM_NUM_VSI; i++) - { - if (&VSI_DQ_Cur_Controllers[i] == cnt) - { - if (i == 0) - legs[0] = 1; legs[1] = 2; legs[2] = 3; - break; - } - } - - if (i==0) - { - //convert the duty ratios - //dtest = 256*(d_com + m_abc[0]); - duty1 = (unsigned char) 256.0*(cnt->dabc[0]); - duty2 = (unsigned char) 256.0*(cnt->dabc[1]); - duty3 = (unsigned char) 256.0*(cnt->dabc[2]); - - //write them out: - WriteDutyRatio(legs[0], duty1); - WriteDutyRatio(legs[1], duty2); - WriteDutyRatio(legs[2], duty3); - - //logging - VSI_V1_da = duty1; - VSI_V1_db = duty2; - VSI_V1_dc = duty3; - - } -} - +/* + * VSI_DQ_SVPWM.c + * + * Created on: Jun 30, 2014 + * Author: sever212 + */ + +#include "../src/project_include.h" +//#include + + +#define KiTs_Q_GAIN 0.005 +#define KiTs_D_GAIN 0.005 + +#define KP_Q_GAIN 0.452 +#define KP_D_GAIN 0.452 + +#define DEFAULT_SINE_TRIANGLE 1 //0 for SVPWM, 1 for SINE TRIANGLE + + +//assumes the dq voltages are a fraction of the dc bus voltage +int SaturateDQ0Voltages(double *inputDQ, double *outputDQ, u8 bSineTriangle) +{ + double ml, ml_0, a; + if (bSineTriangle) + { + ml = 1.632993161855452*sqrt(inputDQ[0]*inputDQ[0] + inputDQ[1]*inputDQ[1]); + ml_0 = 0.816496580927726*fabs(inputDQ[2]); + a = 0.816496580927726; + } + else + { + ml = sqrt(2.0*(inputDQ[0]*inputDQ[0] + inputDQ[1]*inputDQ[1])); + ml_0 = 0.707106781186548*fabs(inputDQ[2]); + a = 0.707106781186548; + } + + if (ml > 1.0) //case 1: limit d and q, no zero sequence + { + outputDQ[0] = inputDQ[0]/ml; + outputDQ[1] = inputDQ[1]/ml; + outputDQ[2] = 0; //Zero seq reference set to 0 + } + else if (ml + ml_0 > 1.0) //case 2: no limit on d and q, limit zero sequence + { + outputDQ[0] = inputDQ[0]; + outputDQ[1] = inputDQ[1]; + if (inputDQ[2] > 0.0) + outputDQ[2] = (1.0-ml)/a; + else + outputDQ[2] = -(1.0-ml)/a; + } + else //case 3: no limits. + { + outputDQ[0] = inputDQ[0]; + outputDQ[1] = inputDQ[1]; + outputDQ[2] = inputDQ[2]; + + } + return SUCCESS; +} + +//assumes the dq voltages are a fraction of the dc bus voltage +int SaturateDQVoltages(double *inputDQ, double *outputDQ, u8 bSineTriangle) +{ + double ml; + if (bSineTriangle) + ml = 1.632993161855452*sqrt(inputDQ[0]*inputDQ[0] + inputDQ[1]*inputDQ[1]); + else + ml = sqrt(2.0*(inputDQ[0]*inputDQ[0] + inputDQ[1]*inputDQ[1])); + + if (ml > 1.0) + { + outputDQ[0] = inputDQ[0]/ml; + outputDQ[1] = inputDQ[1]/ml; + } + else + { + outputDQ[0] = inputDQ[0]; + outputDQ[1] = inputDQ[1]; + } + return SUCCESS; +} + +int DQ0_Transform(double theta_da, double *abc, double *dq0) +{ + dq0[0] = DQK*(cos(theta_da)*abc[0] +cos(theta_da - PI23)*abc[1] +cos(theta_da + PI23)*abc[2]); + dq0[1] = -DQK*(sin(theta_da)*abc[0] +sin(theta_da - PI23)*abc[1] +sin(theta_da + PI23)*abc[2]); + dq0[2] = DQK*( abc[0] +abc[1] +abc[2]); + return SUCCESS; +} + +int InverseDQ0_Transform(double theta_da, double *abc, double *dq0) +{ + abc[0] = DQK*(cos(theta_da)*dq0[0] -sin(theta_da)*dq0[1] +0.5*dq0[2]); + abc[1] = DQK*(cos(theta_da - PI23)*dq0[0] -sin(theta_da - PI23)*dq0[1] +0.5*dq0[2]); + abc[2] = DQK*(cos(theta_da + PI23)*dq0[0] -sin(theta_da + PI23)*dq0[1] +0.5*dq0[2]); + return SUCCESS; +} + +double GetMid(double m1, double m2, double m3) +{ + if ( (m2 >= m1) && (m1 >= m3) ) + return m1; + if ( (m3 >= m1) && (m1 >= m2) ) + return m1; + if ( (m1 >= m2) && (m2 >= m3)) + return m2; + if ( (m3 >= m2) && (m2 >= m1)) + return m2; + if ( (m1 >= m3) && (m3 >= m2) ) + return m3; + if ( (m2 >= m3) && (m3 >= m1)) + return m3; + return m1; //should never get here! +} + +//change the reference frame of a dq0 value. +int ChangeDQ_ReferenceFrame(double *new_dq0, double new_theta_da, double *old_dq0, double old_theta_da) +{ + double theta = old_theta_da - new_theta_da; + + new_dq0[0] = old_dq0[0]*cos(theta) - old_dq0[1]*sin(theta); + new_dq0[1] = old_dq0[0]*sin(theta) + old_dq0[1]*cos(theta); + new_dq0[2] = old_dq0[2]; + + return SUCCESS; +} + +#define OUTPUT_FREQ 120.0 //Hz +//#define THETA_DA GetTheta_DA() /*0.0 //212 //*/ //((double) 2.0*PI*OUTPUT_FREQ*((double)MainTimerTimerTick)/((double)100000.0)) + + +double GetTheta_DA() +{ + static double theta_da = 0; + double update_da = 0; + static u32 LastTickCNT = 0; + u32 elapsed; + elapsed = TimeElapsed10us(LastTickCNT); + LastTickCNT = MainTimerTimerTick; + update_da = ((double) 2.0*PI*OUTPUT_FREQ*((double)elapsed)/((double)100000.0)); + theta_da += update_da; + while (theta_da > PI2) + theta_da = theta_da - PI2; + + return theta_da; +} + +u32 vsi_theta_da; + + +static u8 ExampleVSI_NeedsInput(void *arg, void *VSIContext); +static void ExampleVSI_WriteOutput(void *arg, void *VSIContext); + +VSI_context VSI_DQ_Cur_Controllers[VSI_DQ_SVPWM_NUM_VSI]; +static controller_linked_list_item cont_items [3*VSI_DQ_SVPWM_NUM_VSI]; + +//callbacks: +static void VSI_Input(void *arg, struct controller_context *cnt); +static void VSI_Output(void *arg, struct controller_context *cnt); + +//logging: +u32 VSI_V1_da, VSI_V1_db, VSI_V1_dc; +s32 VSI_V1_d_error, VSI_V1_q_error, VSI_V1_d_current, VSI_V1_q_current; + + +//non-control -- allows d and q voltages to be forced to a certain value (fraction of dc bus) +double force_vd[VSI_DQ_SVPWM_NUM_VSI]; +double force_vq[VSI_DQ_SVPWM_NUM_VSI]; +u8 bForceDQ_Voltages = 0; + +/***************************** + * Init_VSI_DQ_VSPWM() + * Sets up the controllers memory to default values + * and optionally starts the controllers running. + * The default settings can be overridden by manually + * editing the VSI_DQ_Cur_Controllers structure. + * + *StartAllControllers: if this is set to TRUE, all the + * controllers are registered in control.c and started. + *returns a success code + */ +int Init_VSI_DQ_VSPWM(u8 StartAllControllers) +{ + //pi_house *pi_ptr = HB_Controllers; + int i; + for (i = 0; i= VSI_DQ_SVPWM_NUM_VSI) + return INVALID_ARGUMENT; + if (cont_items[3*i].bRegistered == TRUE) + return INVALID_OPERATION; + if (cont_items[3*i+1].bRegistered == TRUE) + return INVALID_OPERATION; + if (VSI_DQ_Cur_Controllers[i].bUseZeroSequence) + if (cont_items[3*i+2].bRegistered == TRUE) + return INVALID_OPERATION; + + RegisterController(0, &cont_items[3*i]); + RegisterController(0, &cont_items[3*i+1]); + + if (VSI_DQ_Cur_Controllers[i].bUseZeroSequence) + RegisterController(0, &cont_items[3*i+2]); + + return SUCCESS; +} + +/***************************** + * Stop_VSI_DQ_SVPWM_Controller() + * Unregisters the VSI d and q current controllers from control.c. + * + *vsi: the VSI number to unregister (1 - VSI_DQ_SVPWM_NUM_VSI) + *returns a success code + */ +int Stop_VSI_DQ_SVPWM_Controller(u32 vsi) +{ + u32 i = vsi-1; + if (i >= VSI_DQ_SVPWM_NUM_VSI) + return INVALID_ARGUMENT; + if (cont_items[2*i].bRegistered == TRUE) + UnregisterController(0, &cont_items[3*i]); + if (cont_items[2*i+1].bRegistered == TRUE) + UnregisterController(0, &cont_items[3*i+1]); + if (cont_items[3*i+2].bRegistered == TRUE) + UnregisterController(0, &cont_items[3*i+2]); + + return SUCCESS; +} + +/***************************** + * VSI_DQ_VSPW_StopCommand() + * Process an ascii command for starting VSI controllers + * Init_VSI_DQ_VSPWM is called + * + *szCmd: incoming command + *szResponse: the response to the command + *CommDevice: pointer to information about the communication device + * this was received on + */ +int VSI_DQ_VSPW_StopCommand(const char *szCmd, char *szResponse, void *CommDevice) +{ + int i; + for (i=0; i< VSI_DQ_SVPWM_NUM_VSI; i++) + { + Stop_VSI_DQ_SVPWM_Controller(i+1); + } + + strcpy(szResponse, "OK"); + return strlen(szResponse); +} + +/***************************** + * VSI_DQ_VSPW_StartCommand() + * Process an ascii command for starting VSI controllers + * Init_VSI_DQ_VSPWM is called + * + *szCmd: incoming command + *szResponse: the response to the command + *CommDevice: pointer to information about the communication device + * this was received on + */ +int VSI_DQ_VSPW_StartCommand(const char *szCmd, char *szResponse, void *CommDevice) +{ + if (strstr(szCmd, "FORCEVDQ")) + { + strcpy(szResponse, "FORCEVDQ=1"); + bForceDQ_Voltages = TRUE; + } + else + { + bForceDQ_Voltages = FALSE; + strcpy(szResponse, "OK"); + } + + Init_VSI_DQ_VSPWM(TRUE); + + return strlen(szResponse); +} + +/***************************** + * VSI_DQ_VSPW_Command() + * Process an ascii command for setting a reference current + * Syntax: n,r,val + * n is the Vbridge number (1 - VSI_DQ_SVPWM_NUM_VSI), + * r is d for direct axis or q for quadrature axis, + * val is the current reference value * 128 + * + *szCmd: incoming command + *szResponse: the response to the command + *CommDevice: pointer to information about the communication device + * this was received on + */ +int VSI_DQ_VSPW_Command(const char * szCmd, char *szResponse, void *CommDevice) +{ + const char *ptr; + u32 vsi = atoi(szCmd); + u8 bError = FALSE, bD = FALSE; + if (vsi < 1 || vsi > VSI_DQ_SVPWM_NUM_VSI) + bError = TRUE; + else + { + for (ptr = szCmd; ptr != &szCmd[strlen(szCmd)-1]; ptr++) + if (*ptr == ',') + break; + ptr++; //advance past the comma + if ( (ptr >= &szCmd[strlen(szCmd)]) || (ptr[1] != ',') || ((*ptr != 'd') && (*ptr != 'q')) ) + bError = TRUE; + else + { + double current_ref; + if (ptr[0] == 'd') + bD = TRUE; + + ptr = &ptr[2]; + current_ref = ((double) atoi(ptr))/128; + if (bForceDQ_Voltages == TRUE) + { + if (bD) + force_vd[vsi-1] = current_ref; + else + force_vq[vsi-1] = current_ref; + + strcpy(szResponse, "OK"); + } + else + { + if (VSI_DQ_VSPW_SetCurrentRef(vsi, bD, current_ref) == SUCCESS) + strcpy(szResponse, "OK"); + else + bError = TRUE; + } + } + + } + if (bError) + strcpy(szResponse, "ERROR"); + + return strlen(szResponse); +} + + +/***************************** + * VSI_DQ_VSPW_SetCurrentRef() + * Set a d or q axis reference current + * + * + *vsi: index of the VSI to set the reference current of + *bDaxis: 1 if setting a d-axis quantity, otherwise 0 for q + *reference: the value of the new reference current + */ +int VSI_DQ_VSPW_SetCurrentRef(u32 vsi, u8 bDaxis, double reference) +{ + if (vsi < 1 || vsi > VSI_DQ_SVPWM_NUM_VSI) + return INVALID_ARGUMENT; + if (bDaxis) + VSI_DQ_Cur_Controllers[vsi-1].d.reference = reference; + else + VSI_DQ_Cur_Controllers[vsi-1].q.reference = reference; + + return SUCCESS; +} + +//Internal function called by control.c before executing a controller +static void VSI_Input(void *arg, struct controller_context *cnt) +{ + u32 i=0; + + for (i= 0; i< VSI_DQ_SVPWM_NUM_VSI; i++) + { + if (&VSI_DQ_Cur_Controllers[i].d.io == cnt) + break; + else if (&VSI_DQ_Cur_Controllers[i].q.io == cnt) + break; + else if (&VSI_DQ_Cur_Controllers[i].zero.io == cnt) + break; + + } + + //calculate the error and store it + if (TimeElapsed10us(VSI_DQ_Cur_Controllers[i].InputAtTickCount) > 3) + { + + VSI_DQ_Cur_Controllers[i].InputAtTickCount = MainTimerTimerTick; + + if (!VSI_DQ_Cur_Controllers[i].get_input(VSI_DQ_Cur_Controllers[i].input_arg, &VSI_DQ_Cur_Controllers[i])) + DQ0_Transform(VSI_DQ_Cur_Controllers[i].theta_da, VSI_DQ_Cur_Controllers[i].Iabc, VSI_DQ_Cur_Controllers[i].Idq0); + + VSI_DQ_Cur_Controllers[i].d.input = VSI_DQ_Cur_Controllers[i].d.reference - VSI_DQ_Cur_Controllers[i].Idq0[0]; + VSI_DQ_Cur_Controllers[i].q.input = VSI_DQ_Cur_Controllers[i].q.reference - VSI_DQ_Cur_Controllers[i].Idq0[1]; + //if a zero sequence current controller: + if (VSI_DQ_Cur_Controllers[i].bUseZeroSequence) + VSI_DQ_Cur_Controllers[i].zero.input = VSI_DQ_Cur_Controllers[i].zero.reference - VSI_DQ_Cur_Controllers[i].Idq0[2]; + + //logging: + if (i == 0) + { + VSI_V1_d_error = (s32) (VSI_DQ_Cur_Controllers[i].d.input*128.0); + VSI_V1_q_error = (s32) (VSI_DQ_Cur_Controllers[i].q.input*128.0); + VSI_V1_d_current = (s32) (VSI_DQ_Cur_Controllers[i].Idq0[0]*128.0); + VSI_V1_q_current = (s32) (VSI_DQ_Cur_Controllers[i].Idq0[1]*128.0); + vsi_theta_da = (u32) VSI_DQ_Cur_Controllers[i].theta_da*128.0; + } + + } +} + +//Internal function called by control.c when an output is ready +static void VSI_Output(void *arg, struct controller_context *cnt) +{ + u32 i = 0, n = 0; + double m_dq0[3], mid_m, d_com; + for (i= 0; i< VSI_DQ_SVPWM_NUM_VSI; i++) + { + if (&VSI_DQ_Cur_Controllers[i].d.io == cnt) + { + VSI_DQ_Cur_Controllers[i].d.updated = TRUE; + break; + } + else if (&VSI_DQ_Cur_Controllers[i].q.io == cnt) + { + VSI_DQ_Cur_Controllers[i].q.updated = TRUE; + break; + } + else if (&VSI_DQ_Cur_Controllers[i].zero.io == cnt) + { + VSI_DQ_Cur_Controllers[i].zero.updated = TRUE; + break; + } + } + + if ( (VSI_DQ_Cur_Controllers[i].d.updated == TRUE) && (VSI_DQ_Cur_Controllers[i].q.updated==TRUE) && (VSI_DQ_Cur_Controllers[i].zero.updated==TRUE || (!VSI_DQ_Cur_Controllers[i].bUseZeroSequence))) + { + double dq_raw[3], dq_saturated[3]; + //both d and q have been updated, do the inverse dq transform and write out the duty ratios + + VSI_DQ_Cur_Controllers[i].d.updated = FALSE; + VSI_DQ_Cur_Controllers[i].q.updated = FALSE; + VSI_DQ_Cur_Controllers[i].zero.updated = FALSE; + + //first saturate the outputs: + if (bForceDQ_Voltages == FALSE) + { + dq_raw[0] = VSI_DQ_Cur_Controllers[i].d.output + VSI_DQ_Cur_Controllers[i].dqComp[0]; + dq_raw[1] = VSI_DQ_Cur_Controllers[i].q.output + VSI_DQ_Cur_Controllers[i].dqComp[1]; + if (VSI_DQ_Cur_Controllers[i].bUseZeroSequence) + dq_raw[2] = VSI_DQ_Cur_Controllers[i].zero.output; + } + else + { + //allow to operate VSI open loop + dq_raw[0] = force_vd[i]; + dq_raw[1] = force_vq[i]; + dq_raw[2] = 0; + } + + if (VSI_DQ_Cur_Controllers[i].bUseZeroSequence) + SaturateDQ0Voltages(dq_raw, dq_saturated, VSI_DQ_Cur_Controllers[i].bSineTriangle); + else + SaturateDQVoltages(dq_raw, dq_saturated, VSI_DQ_Cur_Controllers[i].bSineTriangle); + + //dq modulation indices + m_dq0[0] = dq_saturated[0]; + m_dq0[1] = dq_saturated[1]; + if (VSI_DQ_Cur_Controllers[i].bUseZeroSequence) + m_dq0[2] = dq_saturated[2]; + else + m_dq0[2] = 0; + + //abc modulation indices + InverseDQ0_Transform(VSI_DQ_Cur_Controllers[i].theta_da, VSI_DQ_Cur_Controllers[i].mabc, m_dq0); + + //mid modulation indices (for SVPWM) + if (VSI_DQ_Cur_Controllers[i].bSineTriangle) + d_com = 0.5; + else + { + mid_m = GetMid(VSI_DQ_Cur_Controllers[i].mabc[0], VSI_DQ_Cur_Controllers[i].mabc[1], VSI_DQ_Cur_Controllers[i].mabc[2]); + d_com = 0.5*(1+mid_m); + } + + //calculate duty ratios + //dtest = 256*(d_com + m_abc[0]); + VSI_DQ_Cur_Controllers[i].dabc[0] = d_com + VSI_DQ_Cur_Controllers[i].mabc[0]; + VSI_DQ_Cur_Controllers[i].dabc[1] = d_com + VSI_DQ_Cur_Controllers[i].mabc[1]; + VSI_DQ_Cur_Controllers[i].dabc[2] = d_com + VSI_DQ_Cur_Controllers[i].mabc[2]; + + for (n = 0; n < 3; n++) //SAFETY make sure we don't wrap around + { + if (VSI_DQ_Cur_Controllers[i].dabc[n] > 1.0) + VSI_DQ_Cur_Controllers[i].dabc[n] = 1.0; + else if (VSI_DQ_Cur_Controllers[i].dabc[n] < -1.0) + VSI_DQ_Cur_Controllers[i].dabc[n] = -1.0; + } + + //write them out: + VSI_DQ_Cur_Controllers[i].write_output(VSI_DQ_Cur_Controllers[i].output_arg, &VSI_DQ_Cur_Controllers[i]); + + } +} + +//return false if ABC values set, true if DQ values set +static u8 ExampleVSI_NeedsInput(void *arg, void *VSIContext) +{ + u32 i=0; + u32 adc_num[3]; + struct VSI_context *cnt = VSIContext; + //double meas_abc[3], meas_dq0[3]; + adc_num[0] = 4; adc_num[1] = 5; adc_num[2] = 6; + + for (i= 0; i< VSI_DQ_SVPWM_NUM_VSI; i++) + { + if (&VSI_DQ_Cur_Controllers[i] == cnt) + { + if (i == 0) + { + adc_num[0] = 1; adc_num[1] = 2; adc_num[2] = 3; + /*Verror = &VSI_V1_d_error; + Vcurrent = &VSI_V1_d_current;*/ + //bD = TRUE; + } + break; + } + } + + cnt->Iabc[0] = ReadADC(adc_num[0]); + cnt->Iabc[1] = ReadADC(adc_num[1]); + cnt->Iabc[2] = ReadADC(adc_num[2]); + cnt->theta_da = GetTheta_DA(); + + return FALSE; +} + +//return false if ABC values set, true if DQ values set +static void ExampleVSI_WriteOutput(void *arg, void *VSIContext) +{ + u32 legs[3]; + u8 duty1, duty2, duty3; + struct VSI_context *cnt = VSIContext; + int i; + legs[0] = 0; legs[1] = 0; legs[2] = 0; + for (i= 0; i< VSI_DQ_SVPWM_NUM_VSI; i++) + { + if (&VSI_DQ_Cur_Controllers[i] == cnt) + { + if (i == 0) + legs[0] = 1; legs[1] = 2; legs[2] = 3; + break; + } + } + + if (i==0) + { + //convert the duty ratios + //dtest = 256*(d_com + m_abc[0]); + duty1 = (unsigned char) 256.0*(cnt->dabc[0]); + duty2 = (unsigned char) 256.0*(cnt->dabc[1]); + duty3 = (unsigned char) 256.0*(cnt->dabc[2]); + + //write them out: + WriteDutyRatio(legs[0], duty1); + WriteDutyRatio(legs[1], duty2); + WriteDutyRatio(legs[2], duty3); + + //logging + VSI_V1_da = duty1; + VSI_V1_db = duty2; + VSI_V1_dc = duty3; + + } +} + diff --git a/sdk/basic/control_apps/VSI_DQ_SVPWM.h b/sdk/basic/control_apps/VSI_DQ_SVPWM.h old mode 100755 new mode 100644 index 66d2437d..655c7418 --- a/sdk/basic/control_apps/VSI_DQ_SVPWM.h +++ b/sdk/basic/control_apps/VSI_DQ_SVPWM.h @@ -1,65 +1,65 @@ -#ifndef __VSI_DQ_SVPWM_H -#define __VSI_DQ_SVPWM_H - - -#define PI 3.14159265 -#define PI2 6.283185307179586 -#define PI23 2.094395102393195 -#define DQK 0.816496580927726 - -#define VSI_DQ_SVPWM_NUM_VSI 5 - -typedef struct pi_house -{ - pi_controller pi; - controller_context io; - controller_holder ctxt; - double input; - double output; - double reference; - u8 updated; //set to TRUE everytime this controller output is updated, cleared everytime the output is used - //1 to 1 double adc_scale; //3 amps per volt, wound around twice gives me a factor of 3/2 -} pi_house; - -typedef u8 (*VSI_DQ_SVPWM_input)(void *arg, void *VSIcontext); -typedef void (*VSI_DQ_SVPWM_output)(void *arg, void *VSIcontext); - -typedef struct VSI_context -{ - pi_house d; - pi_house q; - pi_house zero; - u32 InputAtTickCount; //the tick count of the last time the inputs were updated (to avoid unnecessary dq transformations) - double Iabc[3]; - double Idq0[3]; - double dabc[3]; - double mabc[3]; //the 3 output modulation indices - double dqComp[2]; //compensation d and q terms. These are added to the controller outputs before saturating the result. - double theta_da; - u8 bUseZeroSequence; //set to 1 to use a zero sequence controller, otherwise 0 - VSI_DQ_SVPWM_input get_input; - void * input_arg; - VSI_DQ_SVPWM_output write_output; - void * output_arg; - u8 bSineTriangle; //0 for CSVPWM, 1 for SineTriangle -} VSI_context; - - - - -//move these to a library: -int ChangeDQ_ReferenceFrame(double *new_dq0, double new_theta_da, double *old_dq0, double old_theta_da); -int SaturateDQVoltages(double *inputDQ, double *outputDQ, u8 bSineTriangle); -extern int DQ0_Transform(double theta_da, double *abc, double *dq0); -extern int InverseDQ0_Transform(double theta_da, double *abc, double *dq0); - -extern int Start_VSI_DQ_SVPWM_Controller(u32 vsi); -extern int Stop_VSI_DQ_SVPWM_Controller(u32 vsi); -extern int Init_VSI_DQ_VSPWM(u8 StartAllControllers); -extern int VSI_DQ_VSPW_StopCommand(const char *szCmd, char *szResponse, void *CommDevice); -extern int VSI_DQ_VSPW_StartCommand(const char *szCmd, char *szResponse, void *CommDevice); -extern int VSI_DQ_VSPW_Command(const char * szCmd, char *szResponse, void *CommDevice); -extern int VSI_DQ_VSPW_SetCurrentRef(u32 vsi, u8 bDaxis, double reference); - -extern VSI_context VSI_DQ_Cur_Controllers[VSI_DQ_SVPWM_NUM_VSI]; -#endif +#ifndef __VSI_DQ_SVPWM_H +#define __VSI_DQ_SVPWM_H + + +#define PI 3.14159265 +#define PI2 6.283185307179586 +#define PI23 2.094395102393195 +#define DQK 0.816496580927726 + +#define VSI_DQ_SVPWM_NUM_VSI 5 + +typedef struct pi_house +{ + pi_controller pi; + controller_context io; + controller_holder ctxt; + double input; + double output; + double reference; + u8 updated; //set to TRUE everytime this controller output is updated, cleared everytime the output is used + //1 to 1 double adc_scale; //3 amps per volt, wound around twice gives me a factor of 3/2 +} pi_house; + +typedef u8 (*VSI_DQ_SVPWM_input)(void *arg, void *VSIcontext); +typedef void (*VSI_DQ_SVPWM_output)(void *arg, void *VSIcontext); + +typedef struct VSI_context +{ + pi_house d; + pi_house q; + pi_house zero; + u32 InputAtTickCount; //the tick count of the last time the inputs were updated (to avoid unnecessary dq transformations) + double Iabc[3]; + double Idq0[3]; + double dabc[3]; + double mabc[3]; //the 3 output modulation indices + double dqComp[2]; //compensation d and q terms. These are added to the controller outputs before saturating the result. + double theta_da; + u8 bUseZeroSequence; //set to 1 to use a zero sequence controller, otherwise 0 + VSI_DQ_SVPWM_input get_input; + void * input_arg; + VSI_DQ_SVPWM_output write_output; + void * output_arg; + u8 bSineTriangle; //0 for CSVPWM, 1 for SineTriangle +} VSI_context; + + + + +//move these to a library: +int ChangeDQ_ReferenceFrame(double *new_dq0, double new_theta_da, double *old_dq0, double old_theta_da); +int SaturateDQVoltages(double *inputDQ, double *outputDQ, u8 bSineTriangle); +extern int DQ0_Transform(double theta_da, double *abc, double *dq0); +extern int InverseDQ0_Transform(double theta_da, double *abc, double *dq0); + +extern int Start_VSI_DQ_SVPWM_Controller(u32 vsi); +extern int Stop_VSI_DQ_SVPWM_Controller(u32 vsi); +extern int Init_VSI_DQ_VSPWM(u8 StartAllControllers); +extern int VSI_DQ_VSPW_StopCommand(const char *szCmd, char *szResponse, void *CommDevice); +extern int VSI_DQ_VSPW_StartCommand(const char *szCmd, char *szResponse, void *CommDevice); +extern int VSI_DQ_VSPW_Command(const char * szCmd, char *szResponse, void *CommDevice); +extern int VSI_DQ_VSPW_SetCurrentRef(u32 vsi, u8 bDaxis, double reference); + +extern VSI_context VSI_DQ_Cur_Controllers[VSI_DQ_SVPWM_NUM_VSI]; +#endif diff --git a/sdk/basic/src/ControlApp.c b/sdk/basic/src/ControlApp.c old mode 100755 new mode 100644 index 678bc33c..fd55993e --- a/sdk/basic/src/ControlApp.c +++ b/sdk/basic/src/ControlApp.c @@ -1,165 +1,165 @@ -/* - * ControlApp.c - * - * This file houses the control application - * Created on: Jun 24, 2014 - * Author: sever212 - */ - -#include "project_include.h" - -typedef struct c_pi_house -{ - pi_controller pi; - controller_context io; - controller_holder ctxt; - double input; - double output; - double reference; - double adc_scale; //3 amps per volt, wound around twice gives me a factor of 3/2 -} c_pi_house; - -c_pi_house PI_Controllers[NUM_PI_CONTROLLERS]; -controller_linked_list_item cont_items [NUM_PI_CONTROLLERS]; - -//Logging -u32 Leg1_d1; -u32 Leg1_d2; -s32 Leg1_error; -s32 Leg1_output; -s32 Leg1_reference = 0; -s32 Leg1_ADC; -s32 Leg1_Current; - -static void HBridgeCurrent_Input(void *arg, struct controller_context *cnt); -static void HBridgeCurrent_Output(void *arg, struct controller_context *cnt); - -//#define HB8L -//#define VSI_DQ_SVPWM -#define PARALLEL_SUSPENSION - -int ControlStopAppCommand(const char *szCmd, char *szResponse, void *CommDevice) -{ -#if defined(HB8L) - return HBridge_CC_8Leg_StopCommand(szCmd, szResponse, CommDevice); -#elif defined(VSI_DQ_SVPWM) - return VSI_DQ_VSPW_StopCommand(szCmd, szResponse, CommDevice); -#elif defined (PARALLEL_SUSPENSION) - return PosContTry1_StopCommand(szCmd, szResponse, CommDevice); -#else - int i; - for (i = 0; i< NUM_PI_CONTROLLERS; i++) - UnregisterPIController(0, &cont_items[i]); - - strcpy(szResponse, "OK"); - return strlen(szResponse); -#endif -} - -int ControlStartAppCommand(const char *szCmd, char *szResponse, void *CommDevice) -{ -#if defined(HB8L) - return HBridge_CC_8Leg_StartCommand(szCmd, szResponse, CommDevice); -#elif defined(VSI_DQ_SVPWM) - return VSI_DQ_VSPW_StartCommand(szCmd, szResponse, CommDevice); -#elif defined (PARALLEL_SUSPENSION) - return PosContTry1_StartCommand(szCmd, szResponse, CommDevice); -#else - InitControlApp(); - strcpy(szResponse, "OK"); - return strlen(szResponse); -#endif -} - -int ControlAppCommand(const char * szCmd, char *szResponse, void *CommDevice) -{ -#if defined(HB8L) - return HBridge_CC_8Leg_Command(szCmd, szResponse, CommDevice); -#elif defined (VSI_DQ_SVPWM) - return VSI_DQ_VSPW_Command(szCmd, szResponse, CommDevice); -#elif defined (PARALLEL_SUSPENSION) - return PosContTry1_Command(szCmd, szResponse, CommDevice); -#else - s32 current = atoi(szCmd); - s32 *L1R = &Leg1_reference; - PI_Controllers[0].reference = ((double) current)/128; - strcpy(szResponse, "OK"); - *L1R = current; - return strlen(szResponse); -#endif -} - -#if !defined(HB8L) && !defined(VSI_DQ_SVPWM) && !defined(PARALLEL_SUSPENSION) -int InitControlApp() -{ - /*int i; - for(i = 0; i -#include -#include "commands.h" -#include "main.h" -#include "project_settings.h" -#include "Log.h" - - - - -//log_entry TheLog[MAX_LOG_VARS]; -log_entry TheLog[MAX_LOG_VARS]; - - -static inline int ProtectLog(u32 LogIndex) -{ - return 1; //Protection not needed since we aren't allowing overruns EnterProtection(); -} - -static inline int UnprotectLog(u32 LogIndex, int State) -{ - return 1; //protection not needed since we aren't allowing overruns LeaveProtection(State); -} -/***************************** - * InitLog() - * Call this to initialize the log. - * - */ -int InitLog() -{ - int i; - for (i = 0; i < MAX_LOG_VARS; i++) - { - int protect = ProtectLog(i); - TheLog[i].InPos = 0; - TheLog[i].OutPos = 0; - TheLog[i].Settings = 0; - TheLog[i].Flags = 0; - TheLog[i].VarToLog = 0; - TheLog[i].LogStatus = L_IDLE; - UnprotectLog(i, protect); - } - - return SUCCESS; -} - -/***************************** - * ReadFromLog() - * Call this to read data from the log - * - * output: where the data is copied to - * LogIndex: which log to read from (0 to MAX_LOG_VARS-1) - * Index: zero-based index in the log to start reading from - * Length: The maximum length that can be written to output (in bytes) - * ---NOTE: since everything is 32 bit aligned, length must be - * divisible by 4 - * - * Returns number of bytes read (if positive) - * Error code (if negative) - */ -int ReadFromLog(unsigned char *output, u32 LogIndex, u32 Length) -{ - u32 avail, in, out; - int protect; - if (LogIndex >= MAX_LOG_VARS) - return INVALID_ARGUMENT; - if ( (TheLog[LogIndex].LogStatus != L_DONE) && (TheLog[LogIndex].LogStatus != L_LOGGING) ) - return INVALID_OPERATION; - if (Length % 4 != 0) - return INVALID_ARGUMENT; //must by 32bit aligned - - protect = ProtectLog(LogIndex); - //set up internal variables and adjust length - avail = LogDataAvail(LogIndex); //in u32 (for bytes multiply by 4) - in = TheLog[LogIndex].InPos; - out = TheLog[LogIndex].OutPos; - if (Length > avail*4) - Length = avail*4; - - //Okay, now read it out - if (out + Length/4 < LOG_LENGTH) - { - memcpy(output, &TheLog[LogIndex].LogEntry[out], Length); - TheLog[LogIndex].OutPos += Length/4; - } - else if (out > in) - { - u32 lenTop = 4*(LOG_LENGTH - out); //number of bytes - u32 lenBot = Length - lenTop; //number of bytes - memcpy(output, &TheLog[LogIndex].LogEntry[out], lenTop); - memcpy(&output[lenTop], TheLog[LogIndex].LogEntry, lenBot); - TheLog[LogIndex].OutPos = lenBot/4; - } - - UnprotectLog(LogIndex, protect); - return Length; -} - -/***************************** - * DetermineMostFullLog() - * Call this to determine which log has the most data and find out how many - * bytes can be read. - * - * LogIndex: set to the log that has the most data (0 to MAX_LOG_VARS-1) - * - * Returns number of bytes available (if positive) - * Error code (if negative) - */ -int DetermineMostFullLog(u32 *LogIndex) -{ - int i; - u32 max_avail = 0, cur_avail = 0; - for (i = 0; i < MAX_LOG_VARS; i++) - { - cur_avail = LogDataAvail(i); - if (cur_avail > max_avail) - { - max_avail = cur_avail; - *LogIndex = i; - } - } - return max_avail; -} - -/***************************** - * ReadFromMostFullLog() - * Call this to read data from the log that has the most data ready - * to be read out. - * - * output: where the data is copied to - * LogIndex: set to the log that was read from (0 to MAX_LOG_VARS-1) - * Length: The maximum length that can be written to output (in bytes) - * ---NOTE: since everything is 32 bit aligned, length must be - * divisible by 4 - * - * Returns number of bytes read (if positive) - * Error code (if negative) - */ -int ReadFromMostFullLog(unsigned char *output, u32 *LogIndex, u32 Length) -{ - int i; - u32 max_entry = 0, max_avail = 0, cur_avail = 0; - for (i = 0; i < MAX_LOG_VARS; i++) - { - cur_avail = LogDataAvail(i); - if (cur_avail > max_avail) - { - max_avail = cur_avail; - max_entry = i; - *LogIndex = i; - } - } - if (max_avail > 0) - return ReadFromLog(output, max_entry, Length); - else - return 0; -} - -/***************************** - * ReadLogFlags() - * Call this to read a log's flags. Doing so - * clears the flags - * - * *flags: pointer to where the flags should be written to - * LogIndex: which log to read from (0 to MAX_LOG_VARS-1) - * - * Returns number of bytes read (if positive) - * Error code (if negative) - */ -int ReadLogFlags(u32 *flags, u32 LogIndex) -{ - - if (LogIndex >= MAX_LOG_VARS) - return INVALID_ARGUMENT; - *flags = TheLog[LogIndex].Flags; - TheLog[LogIndex].Flags = 0; - return SUCCESS; -} - -/***************************** - * LogDataAvail() - * Determine how many u32 values can be read from the log - * (the number of bytes is 4 * this) - * - * LogIndex: Which log the caller is inquiring about - * Returns: number of u32's available - */ -u32 inline LogDataAvail(u32 LogIndex) -{ - u32 in, out; - int protect; - - if (LogIndex >= MAX_LOG_VARS) - return 0; - protect = ProtectLog(LogIndex); - in = TheLog[LogIndex].InPos; - out = TheLog[LogIndex].OutPos; - UnprotectLog(LogIndex, protect); - if (in >= out) - return in - out; - else - return LOG_LENGTH - (out - in); -} - -/***************************** - * LogInputSpaceAvail() - * Determine how many u32 values can be stored in the log - * (the number of bytes is 4 * this) - * - * LogIndex: Which log the caller is inquiring about - * Returns: number of u32's available - */ -static inline u32 LogInputSpaceAvail(u32 LogIndex) -{ - u32 in, out; - if (LogIndex >= MAX_LOG_VARS) - return 0; - in = TheLog[LogIndex].InPos; - out = TheLog[LogIndex].OutPos; - - if (out > in) - return (out - in) - 1; - else - return (LOG_LENGTH - (in - out)) - 1; -} - -/***************************** - * SetupLogVariable() - * Call this prepare a variable for logging - * - * LogIndex: Which index in the log to use (0 to MAX_LOG_VARS-1) - * Variable: Pointer to the variable to log - * Returns: Success code - */ -int SetupLogVariable(u32 LogIndex, u32 *Variable, u32 Settings) -{ - if (LogIndex >= MAX_LOG_VARS) - return INVALID_ARGUMENT; - - else - { - TheLog[LogIndex].InPos = 0; - TheLog[LogIndex].OutPos = 0; - TheLog[LogIndex].Settings = Settings; - TheLog[LogIndex].Flags = 0; - TheLog[LogIndex].VarToLog = Variable; - TheLog[LogIndex].LogStatus = L_READY; - } - return SUCCESS; -} - -/***************************** - * StartLogging() - * Call this to start the data logging - * - * Returns: Success code - */ -int StartLogging() -{ - int i; - for (i = 0; i < MAX_LOG_VARS; i++) - { - if (TheLog[i].LogStatus == L_READY) - TheLog[i].LogStatus = L_LOGGING; - } - - return SUCCESS; -} - -/***************************** - * StopAllLogging() - * Call this to stop all data logging. Anything - * in progress will be marked as done. - * - * Returns: Success code - */ -int StopAllLogging() -{ - int i; - for (i = 0; i < MAX_LOG_VARS; i++) - { - if (TheLog[i].LogStatus == L_LOGGING) - TheLog[i].LogStatus = L_DONE; - } - - return SUCCESS; -} - -/***************************** - * DoLogging() - * Call this at fixed intervals to handle logging of variables (move to DMA??) - * - * Returns: Success code - */ -int DoLogging() -{ - int i; - for (i = 0; i < MAX_LOG_VARS; i++) - { - if (TheLog[i].LogStatus == L_LOGGING) - { - //basic case: we have space: - if ( LogInputSpaceAvail(i) ) - TheLog[i].LogEntry[TheLog[i].InPos++] = *TheLog[i].VarToLog; - else if (TheLog[i].Settings & FIFO_RUN_ONCE) //just run once - TheLog[i].LogStatus = L_DONE; - else if ( !(TheLog[i].Settings & FIFO_PREVENT_OVERRUN) ) //just write over - { - //if we don't write over, than there is no need to protect the fifo! - TheLog[i].Flags |= FIFO_OVERRUN_OCCURED; - /* - TheLog[i].OutPos++; - TheLog[i].OutPos %= LOG_LENGTH; - TheLog[i].LogEntry[TheLog[i].InPos++] = *TheLog[i].VarToLog;*/ - } - - /*if (TheLog[i].Flags != 0) - TheLog[i].Flags = TheLog[i].Flags; - if (TheLog[i].InPos >= LOG_LENGTH) - TheLog[i].InPos = TheLog[i].InPos;*/ - - //adjust indices: - TheLog[i].InPos %= LOG_LENGTH; - } - } - - return SUCCESS; -} +/* + * Log.c + * + * Created on: Jun 6, 2014 + * Author: sever212 + */ + + +#include "xparameters.h" +#include "xil_exception.h" +#include "xil_printf.h" +#include +#include +#include "commands.h" +#include "main.h" +#include "project_settings.h" +#include "Log.h" + + + + +//log_entry TheLog[MAX_LOG_VARS]; +log_entry TheLog[MAX_LOG_VARS]; + + +static inline int ProtectLog(u32 LogIndex) +{ + return 1; //Protection not needed since we aren't allowing overruns EnterProtection(); +} + +static inline int UnprotectLog(u32 LogIndex, int State) +{ + return 1; //protection not needed since we aren't allowing overruns LeaveProtection(State); +} +/***************************** + * InitLog() + * Call this to initialize the log. + * + */ +int InitLog() +{ + int i; + for (i = 0; i < MAX_LOG_VARS; i++) + { + int protect = ProtectLog(i); + TheLog[i].InPos = 0; + TheLog[i].OutPos = 0; + TheLog[i].Settings = 0; + TheLog[i].Flags = 0; + TheLog[i].VarToLog = 0; + TheLog[i].LogStatus = L_IDLE; + UnprotectLog(i, protect); + } + + return SUCCESS; +} + +/***************************** + * ReadFromLog() + * Call this to read data from the log + * + * output: where the data is copied to + * LogIndex: which log to read from (0 to MAX_LOG_VARS-1) + * Index: zero-based index in the log to start reading from + * Length: The maximum length that can be written to output (in bytes) + * ---NOTE: since everything is 32 bit aligned, length must be + * divisible by 4 + * + * Returns number of bytes read (if positive) + * Error code (if negative) + */ +int ReadFromLog(unsigned char *output, u32 LogIndex, u32 Length) +{ + u32 avail, in, out; + int protect; + if (LogIndex >= MAX_LOG_VARS) + return INVALID_ARGUMENT; + if ( (TheLog[LogIndex].LogStatus != L_DONE) && (TheLog[LogIndex].LogStatus != L_LOGGING) ) + return INVALID_OPERATION; + if (Length % 4 != 0) + return INVALID_ARGUMENT; //must by 32bit aligned + + protect = ProtectLog(LogIndex); + //set up internal variables and adjust length + avail = LogDataAvail(LogIndex); //in u32 (for bytes multiply by 4) + in = TheLog[LogIndex].InPos; + out = TheLog[LogIndex].OutPos; + if (Length > avail*4) + Length = avail*4; + + //Okay, now read it out + if (out + Length/4 < LOG_LENGTH) + { + memcpy(output, &TheLog[LogIndex].LogEntry[out], Length); + TheLog[LogIndex].OutPos += Length/4; + } + else if (out > in) + { + u32 lenTop = 4*(LOG_LENGTH - out); //number of bytes + u32 lenBot = Length - lenTop; //number of bytes + memcpy(output, &TheLog[LogIndex].LogEntry[out], lenTop); + memcpy(&output[lenTop], TheLog[LogIndex].LogEntry, lenBot); + TheLog[LogIndex].OutPos = lenBot/4; + } + + UnprotectLog(LogIndex, protect); + return Length; +} + +/***************************** + * DetermineMostFullLog() + * Call this to determine which log has the most data and find out how many + * bytes can be read. + * + * LogIndex: set to the log that has the most data (0 to MAX_LOG_VARS-1) + * + * Returns number of bytes available (if positive) + * Error code (if negative) + */ +int DetermineMostFullLog(u32 *LogIndex) +{ + int i; + u32 max_avail = 0, cur_avail = 0; + for (i = 0; i < MAX_LOG_VARS; i++) + { + cur_avail = LogDataAvail(i); + if (cur_avail > max_avail) + { + max_avail = cur_avail; + *LogIndex = i; + } + } + return max_avail; +} + +/***************************** + * ReadFromMostFullLog() + * Call this to read data from the log that has the most data ready + * to be read out. + * + * output: where the data is copied to + * LogIndex: set to the log that was read from (0 to MAX_LOG_VARS-1) + * Length: The maximum length that can be written to output (in bytes) + * ---NOTE: since everything is 32 bit aligned, length must be + * divisible by 4 + * + * Returns number of bytes read (if positive) + * Error code (if negative) + */ +int ReadFromMostFullLog(unsigned char *output, u32 *LogIndex, u32 Length) +{ + int i; + u32 max_entry = 0, max_avail = 0, cur_avail = 0; + for (i = 0; i < MAX_LOG_VARS; i++) + { + cur_avail = LogDataAvail(i); + if (cur_avail > max_avail) + { + max_avail = cur_avail; + max_entry = i; + *LogIndex = i; + } + } + if (max_avail > 0) + return ReadFromLog(output, max_entry, Length); + else + return 0; +} + +/***************************** + * ReadLogFlags() + * Call this to read a log's flags. Doing so + * clears the flags + * + * *flags: pointer to where the flags should be written to + * LogIndex: which log to read from (0 to MAX_LOG_VARS-1) + * + * Returns number of bytes read (if positive) + * Error code (if negative) + */ +int ReadLogFlags(u32 *flags, u32 LogIndex) +{ + + if (LogIndex >= MAX_LOG_VARS) + return INVALID_ARGUMENT; + *flags = TheLog[LogIndex].Flags; + TheLog[LogIndex].Flags = 0; + return SUCCESS; +} + +/***************************** + * LogDataAvail() + * Determine how many u32 values can be read from the log + * (the number of bytes is 4 * this) + * + * LogIndex: Which log the caller is inquiring about + * Returns: number of u32's available + */ +u32 inline LogDataAvail(u32 LogIndex) +{ + u32 in, out; + int protect; + + if (LogIndex >= MAX_LOG_VARS) + return 0; + protect = ProtectLog(LogIndex); + in = TheLog[LogIndex].InPos; + out = TheLog[LogIndex].OutPos; + UnprotectLog(LogIndex, protect); + if (in >= out) + return in - out; + else + return LOG_LENGTH - (out - in); +} + +/***************************** + * LogInputSpaceAvail() + * Determine how many u32 values can be stored in the log + * (the number of bytes is 4 * this) + * + * LogIndex: Which log the caller is inquiring about + * Returns: number of u32's available + */ +static inline u32 LogInputSpaceAvail(u32 LogIndex) +{ + u32 in, out; + if (LogIndex >= MAX_LOG_VARS) + return 0; + in = TheLog[LogIndex].InPos; + out = TheLog[LogIndex].OutPos; + + if (out > in) + return (out - in) - 1; + else + return (LOG_LENGTH - (in - out)) - 1; +} + +/***************************** + * SetupLogVariable() + * Call this prepare a variable for logging + * + * LogIndex: Which index in the log to use (0 to MAX_LOG_VARS-1) + * Variable: Pointer to the variable to log + * Returns: Success code + */ +int SetupLogVariable(u32 LogIndex, u32 *Variable, u32 Settings) +{ + if (LogIndex >= MAX_LOG_VARS) + return INVALID_ARGUMENT; + + else + { + TheLog[LogIndex].InPos = 0; + TheLog[LogIndex].OutPos = 0; + TheLog[LogIndex].Settings = Settings; + TheLog[LogIndex].Flags = 0; + TheLog[LogIndex].VarToLog = Variable; + TheLog[LogIndex].LogStatus = L_READY; + } + return SUCCESS; +} + +/***************************** + * StartLogging() + * Call this to start the data logging + * + * Returns: Success code + */ +int StartLogging() +{ + int i; + for (i = 0; i < MAX_LOG_VARS; i++) + { + if (TheLog[i].LogStatus == L_READY) + TheLog[i].LogStatus = L_LOGGING; + } + + return SUCCESS; +} + +/***************************** + * StopAllLogging() + * Call this to stop all data logging. Anything + * in progress will be marked as done. + * + * Returns: Success code + */ +int StopAllLogging() +{ + int i; + for (i = 0; i < MAX_LOG_VARS; i++) + { + if (TheLog[i].LogStatus == L_LOGGING) + TheLog[i].LogStatus = L_DONE; + } + + return SUCCESS; +} + +/***************************** + * DoLogging() + * Call this at fixed intervals to handle logging of variables (move to DMA??) + * + * Returns: Success code + */ +int DoLogging() +{ + int i; + for (i = 0; i < MAX_LOG_VARS; i++) + { + if (TheLog[i].LogStatus == L_LOGGING) + { + //basic case: we have space: + if ( LogInputSpaceAvail(i) ) + TheLog[i].LogEntry[TheLog[i].InPos++] = *TheLog[i].VarToLog; + else if (TheLog[i].Settings & FIFO_RUN_ONCE) //just run once + TheLog[i].LogStatus = L_DONE; + else if ( !(TheLog[i].Settings & FIFO_PREVENT_OVERRUN) ) //just write over + { + //if we don't write over, than there is no need to protect the fifo! + TheLog[i].Flags |= FIFO_OVERRUN_OCCURED; + /* + TheLog[i].OutPos++; + TheLog[i].OutPos %= LOG_LENGTH; + TheLog[i].LogEntry[TheLog[i].InPos++] = *TheLog[i].VarToLog;*/ + } + + /*if (TheLog[i].Flags != 0) + TheLog[i].Flags = TheLog[i].Flags; + if (TheLog[i].InPos >= LOG_LENGTH) + TheLog[i].InPos = TheLog[i].InPos;*/ + + //adjust indices: + TheLog[i].InPos %= LOG_LENGTH; + } + } + + return SUCCESS; +} diff --git a/sdk/basic/src/Log.h b/sdk/basic/src/Log.h old mode 100755 new mode 100644 index 389ea65b..80a22b07 --- a/sdk/basic/src/Log.h +++ b/sdk/basic/src/Log.h @@ -1,40 +1,40 @@ - -#ifndef __LOG_H -#define __LOG_H - -#define MAX_LOG_VARS 14 -#define LOG_LENGTH (100000 + 1) //+1 is for empty position of circular buffer - -typedef enum {L_IDLE, L_READY, L_LOGGING, L_DONE} LogStatus_t; - -//FIFO settings: -#define FIFO_PREVENT_OVERRUN 1 //set this to prevent the log from overwriting old data (error will be flagged) -#define FIFO_RUN_ONCE 2 //set this to let the log fill up once and then stop - -// FIFO flags: -#define FIFO_OVERRUN_OCCURED 1 - -typedef struct log_entry { - u32 LogEntry[LOG_LENGTH]; - u32 InPos; - u32 OutPos; - u32 Settings; - u32 Flags; - u32 *VarToLog; - LogStatus_t LogStatus; -} log_entry; - - -extern int InitLog(); -extern int ReadFromLog(unsigned char *output, u32 LogIndex, u32 Length); -extern int DetermineMostFullLog(u32 *LogIndex); -extern int ReadFromMostFullLog(unsigned char *output, u32 *LogIndex, u32 Length); -extern int ReadLogFlags(u32 *flags, u32 LogIndex); -extern u32 LogDataAvail(u32 LogIndex); -extern int SetupLogVariable(u32 LogIndex, u32 *Variable, u32 Settings); -extern int StartLogging(); -extern int StopAllLogging(); -extern int DoLogging(); - -#endif //__LOG_H - + +#ifndef __LOG_H +#define __LOG_H + +#define MAX_LOG_VARS 14 +#define LOG_LENGTH (100000 + 1) //+1 is for empty position of circular buffer + +typedef enum {L_IDLE, L_READY, L_LOGGING, L_DONE} LogStatus_t; + +//FIFO settings: +#define FIFO_PREVENT_OVERRUN 1 //set this to prevent the log from overwriting old data (error will be flagged) +#define FIFO_RUN_ONCE 2 //set this to let the log fill up once and then stop + +// FIFO flags: +#define FIFO_OVERRUN_OCCURED 1 + +typedef struct log_entry { + u32 LogEntry[LOG_LENGTH]; + u32 InPos; + u32 OutPos; + u32 Settings; + u32 Flags; + u32 *VarToLog; + LogStatus_t LogStatus; +} log_entry; + + +extern int InitLog(); +extern int ReadFromLog(unsigned char *output, u32 LogIndex, u32 Length); +extern int DetermineMostFullLog(u32 *LogIndex); +extern int ReadFromMostFullLog(unsigned char *output, u32 *LogIndex, u32 Length); +extern int ReadLogFlags(u32 *flags, u32 LogIndex); +extern u32 LogDataAvail(u32 LogIndex); +extern int SetupLogVariable(u32 LogIndex, u32 *Variable, u32 Settings); +extern int StartLogging(); +extern int StopAllLogging(); +extern int DoLogging(); + +#endif //__LOG_H + diff --git a/sdk/basic/src/README.txt b/sdk/basic/src/README.txt old mode 100755 new mode 100644 diff --git a/sdk/basic/src/axi_timer.c b/sdk/basic/src/axi_timer.c old mode 100755 new mode 100644 index ed28262f..600538f7 --- a/sdk/basic/src/axi_timer.c +++ b/sdk/basic/src/axi_timer.c @@ -1,159 +1,159 @@ -/* - * control_timer.c - * - * Created on: Jun 23, 2014 - * Author: sever212 - */ - -#include "project_include.h" - - - -static int AXI_TimerSetupIntrSystem(XScuGic *IntcInstancePtr, - XTmrCtr *TimerInstancePtr, u16 TimerIntrId, u8 priority); -/*static int Init_AXI_Timer(XScuGic* IntcInstancePtr, XTmrCtr* TmrCtrInstancePtr, - u16 DeviceId, u16 IntrId, u8 TmrCtrNumber, - XTmrCtr_Handler InterruptHandler, u8 IntrPriority, u32 ResetValue);*/ - - -/*****************************************************************************/ -/** - * It initializes a timer counter and then sets it up in - * compare mode with auto reload such that a periodic interrupt is generated. - * - * This function uses interrupt driven mode of the timer counter. - * - * @param IntcInstancePtr is a pointer to the Interrupt Controller - * driver Instance - * @param TmrCtrInstancePtr is a pointer to the XTmrCtr driver Instance - * @param DeviceId is the XPAR__DEVICE_ID value from - * xparameters.h - * @param IntrId is XPAR___INTERRUPT_INTR - * value from xparameters.h - * @param TmrCtrNumber is the number of the timer to which this - * handler is associated with. - * - * @return XST_SUCCESS if the Test is successful, otherwise XST_FAILURE - * - * @note This function contains an infinite loop such that if interrupts - * are not working it may never return. - * - *****************************************************************************/ -int Init_AXI_Timer(XScuGic* IntcInstancePtr, XTmrCtr* TmrCtrInstancePtr, - u16 DeviceId, u16 IntrId, u8 TmrCtrNumber, - XTmrCtr_Handler InterruptHandler, u8 IntrPriority, u32 ResetValue) { - int Status; - - /* - * Initialize the timer counter so that it's ready to use, - * specify the device ID that is generated in xparameters.h - */ - Status = XTmrCtr_Initialize(TmrCtrInstancePtr, DeviceId); - if (Status != XST_SUCCESS) { - return XST_FAILURE; - } - - /* - * Perform a self-test to ensure that the hardware was built - * correctly, use the 1st timer in the device (0) - */ - Status = XTmrCtr_SelfTest(TmrCtrInstancePtr, TmrCtrNumber); - if (Status != XST_SUCCESS) { - return XST_FAILURE; - } - - /* - * Connect the timer counter to the interrupt subsystem such that - * interrupts can occur. This function is application specific. - */ - Status = AXI_TimerSetupIntrSystem(IntcInstancePtr, TmrCtrInstancePtr, - IntrId, IntrPriority); - if (Status != XST_SUCCESS) { - return XST_FAILURE; - } - - /* - * Setup the handler for the timer counter that will be called from the - * interrupt context when the timer expires, specify a pointer to the - * timer counter driver instance as the callback reference so the handler - * is able to access the instance data - */ - XTmrCtr_SetHandler(TmrCtrInstancePtr, InterruptHandler, TmrCtrInstancePtr); - - /* - * Enable the interrupt of the timer counter so interrupts will occur - * and use auto reload mode such that the timer counter will reload - * itself automatically and continue repeatedly, without this option - * it would expire once only - */ - XTmrCtr_SetOptions(TmrCtrInstancePtr, TmrCtrNumber, - XTC_INT_MODE_OPTION | XTC_AUTO_RELOAD_OPTION); - - /* - * Set a reset value for the timer counter such that it will expire - * eariler than letting it roll over from 0, the reset value is loaded - * into the timer counter when it is started - */ - XTmrCtr_SetResetValue(TmrCtrInstancePtr, TmrCtrNumber, ResetValue); - - /* - * Start the timer counter such that it's incrementing by default, - * then wait for it to timeout a number of times - */ - XTmrCtr_Start(TmrCtrInstancePtr, TmrCtrNumber); - - return XST_SUCCESS; -} - -/*****************************************************************************/ -/** - * - * This function sets up the interrupt system such that interrupts can occur - * for the device. - * - * @param IntcInstancePtr is a pointer to the instance of XScuGic driver. - * @param TimerInstancePtr is a pointer to the instance of XScuTimer - * driver. - * @param TimerIntrId is the Interrupt Id of the XScuTimer device. - * @param InterruptHandler is the function to handle the interrupts - * @param priority is the priority for the interrupts (0 is highest - * priority, 0xF8 (248) is lowest. - * - * @return XST_SUCCESS if successful, otherwise XST_FAILURE. - * - * @note None. - * - ******************************************************************************/ -static int AXI_TimerSetupIntrSystem(XScuGic *IntcInstancePtr, - XTmrCtr *TimerInstancePtr, u16 TimerIntrId, u8 priority) { - int Status; - - /* - * Connect the device driver handler that will be called when an - * interrupt for the device occurs, the handler defined above performs - * the specific interrupt processing for the device. - */ - XScuGic_SetPriorityTriggerType(IntcInstancePtr, TimerIntrId, /*0xA8*/ priority /*0xA0*/, 0x3); - - Status = XScuGic_Connect(IntcInstancePtr, TimerIntrId, - (XInterruptHandler) XTmrCtr_InterruptHandler, - (void *) TimerInstancePtr); - if (Status != XST_SUCCESS) { - return Status; - } - - /* - * Enable the interrupt for the device. - */ - XScuGic_Enable(IntcInstancePtr, TimerIntrId); - - /* - * Enable the timer interrupts for timer mode. - */ - //should I do this?? XScuTimer_EnableInterrupt(TimerInstancePtr); - - return XST_SUCCESS; -} - - - +/* + * control_timer.c + * + * Created on: Jun 23, 2014 + * Author: sever212 + */ + +#include "project_include.h" + + + +static int AXI_TimerSetupIntrSystem(XScuGic *IntcInstancePtr, + XTmrCtr *TimerInstancePtr, u16 TimerIntrId, u8 priority); +/*static int Init_AXI_Timer(XScuGic* IntcInstancePtr, XTmrCtr* TmrCtrInstancePtr, + u16 DeviceId, u16 IntrId, u8 TmrCtrNumber, + XTmrCtr_Handler InterruptHandler, u8 IntrPriority, u32 ResetValue);*/ + + +/*****************************************************************************/ +/** + * It initializes a timer counter and then sets it up in + * compare mode with auto reload such that a periodic interrupt is generated. + * + * This function uses interrupt driven mode of the timer counter. + * + * @param IntcInstancePtr is a pointer to the Interrupt Controller + * driver Instance + * @param TmrCtrInstancePtr is a pointer to the XTmrCtr driver Instance + * @param DeviceId is the XPAR__DEVICE_ID value from + * xparameters.h + * @param IntrId is XPAR___INTERRUPT_INTR + * value from xparameters.h + * @param TmrCtrNumber is the number of the timer to which this + * handler is associated with. + * + * @return XST_SUCCESS if the Test is successful, otherwise XST_FAILURE + * + * @note This function contains an infinite loop such that if interrupts + * are not working it may never return. + * + *****************************************************************************/ +int Init_AXI_Timer(XScuGic* IntcInstancePtr, XTmrCtr* TmrCtrInstancePtr, + u16 DeviceId, u16 IntrId, u8 TmrCtrNumber, + XTmrCtr_Handler InterruptHandler, u8 IntrPriority, u32 ResetValue) { + int Status; + + /* + * Initialize the timer counter so that it's ready to use, + * specify the device ID that is generated in xparameters.h + */ + Status = XTmrCtr_Initialize(TmrCtrInstancePtr, DeviceId); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Perform a self-test to ensure that the hardware was built + * correctly, use the 1st timer in the device (0) + */ + Status = XTmrCtr_SelfTest(TmrCtrInstancePtr, TmrCtrNumber); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Connect the timer counter to the interrupt subsystem such that + * interrupts can occur. This function is application specific. + */ + Status = AXI_TimerSetupIntrSystem(IntcInstancePtr, TmrCtrInstancePtr, + IntrId, IntrPriority); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setup the handler for the timer counter that will be called from the + * interrupt context when the timer expires, specify a pointer to the + * timer counter driver instance as the callback reference so the handler + * is able to access the instance data + */ + XTmrCtr_SetHandler(TmrCtrInstancePtr, InterruptHandler, TmrCtrInstancePtr); + + /* + * Enable the interrupt of the timer counter so interrupts will occur + * and use auto reload mode such that the timer counter will reload + * itself automatically and continue repeatedly, without this option + * it would expire once only + */ + XTmrCtr_SetOptions(TmrCtrInstancePtr, TmrCtrNumber, + XTC_INT_MODE_OPTION | XTC_AUTO_RELOAD_OPTION); + + /* + * Set a reset value for the timer counter such that it will expire + * eariler than letting it roll over from 0, the reset value is loaded + * into the timer counter when it is started + */ + XTmrCtr_SetResetValue(TmrCtrInstancePtr, TmrCtrNumber, ResetValue); + + /* + * Start the timer counter such that it's incrementing by default, + * then wait for it to timeout a number of times + */ + XTmrCtr_Start(TmrCtrInstancePtr, TmrCtrNumber); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** + * + * This function sets up the interrupt system such that interrupts can occur + * for the device. + * + * @param IntcInstancePtr is a pointer to the instance of XScuGic driver. + * @param TimerInstancePtr is a pointer to the instance of XScuTimer + * driver. + * @param TimerIntrId is the Interrupt Id of the XScuTimer device. + * @param InterruptHandler is the function to handle the interrupts + * @param priority is the priority for the interrupts (0 is highest + * priority, 0xF8 (248) is lowest. + * + * @return XST_SUCCESS if successful, otherwise XST_FAILURE. + * + * @note None. + * + ******************************************************************************/ +static int AXI_TimerSetupIntrSystem(XScuGic *IntcInstancePtr, + XTmrCtr *TimerInstancePtr, u16 TimerIntrId, u8 priority) { + int Status; + + /* + * Connect the device driver handler that will be called when an + * interrupt for the device occurs, the handler defined above performs + * the specific interrupt processing for the device. + */ + XScuGic_SetPriorityTriggerType(IntcInstancePtr, TimerIntrId, /*0xA8*/ priority /*0xA0*/, 0x3); + + Status = XScuGic_Connect(IntcInstancePtr, TimerIntrId, + (XInterruptHandler) XTmrCtr_InterruptHandler, + (void *) TimerInstancePtr); + if (Status != XST_SUCCESS) { + return Status; + } + + /* + * Enable the interrupt for the device. + */ + XScuGic_Enable(IntcInstancePtr, TimerIntrId); + + /* + * Enable the timer interrupts for timer mode. + */ + //should I do this?? XScuTimer_EnableInterrupt(TimerInstancePtr); + + return XST_SUCCESS; +} + + + diff --git a/sdk/basic/src/axi_timer.h b/sdk/basic/src/axi_timer.h old mode 100755 new mode 100644 index 00099088..7986271e --- a/sdk/basic/src/axi_timer.h +++ b/sdk/basic/src/axi_timer.h @@ -1,12 +1,12 @@ -#ifndef __AXI_TIMER_H -#define __AXI_TIMER_H -extern volatile u32 ControlTimer0_TickCount; -extern volatile u32 ControlTimer1_TickCount; -#include "xparameters.h" - - - -extern int Init_AXI_Timer(XScuGic* IntcInstancePtr, XTmrCtr* TmrCtrInstancePtr, - u16 DeviceId, u16 IntrId, u8 TmrCtrNumber, - XTmrCtr_Handler InterruptHandler, u8 IntrPriority, u32 ResetValue); -#endif //__AXI_TIMER_H +#ifndef __AXI_TIMER_H +#define __AXI_TIMER_H +extern volatile u32 ControlTimer0_TickCount; +extern volatile u32 ControlTimer1_TickCount; +#include "xparameters.h" + + + +extern int Init_AXI_Timer(XScuGic* IntcInstancePtr, XTmrCtr* TmrCtrInstancePtr, + u16 DeviceId, u16 IntrId, u8 TmrCtrNumber, + XTmrCtr_Handler InterruptHandler, u8 IntrPriority, u32 ResetValue); +#endif //__AXI_TIMER_H diff --git a/sdk/basic/src/commands.c b/sdk/basic/src/commands.c old mode 100755 new mode 100644 index a9175e4d..ad8dde62 --- a/sdk/basic/src/commands.c +++ b/sdk/basic/src/commands.c @@ -1,1538 +1,1538 @@ - -#if 0 -#include "xparameters.h" -#include "xil_exception.h" -#include "xil_printf.h" -#include -#include -#include -#include "commands.h" -#include "main.h" -#include "project_settings.h" -#include "log.h" -#include "prog_timer.h" -#endif - -#include "project_include.h" - -#include "../bsp/bsp.h" - -/***************************** - * MakeMostFullLFR() - * Populate an LFR response from the most-full log - * - * - * Response: LFR=sqn_num,index,flags,length,binary_data - * **The response length will be different from the - * ** command length if the end of the log is reached - * **binary_data is byte-for-byte what is in the log. - * **sqn_num is a sequence number that starts at 1 (reset when LFS is received) - * and increments with each LFR - * --> only 100us errors are but response is padded to 10 fields - *szResponse: the response - *uiMaxLength: the maximum length of the binary_data field (must be divisible by 4) - */ -int MakeMostFullLFR(char *szResponse, u32 uiMaxLength, u32 *SQnum) -{ - u32 uiLogIndex = 0, uiFlags = 0; - int iStatus1 = ReadFromMostFullLog((unsigned char*) szResponse, &uiLogIndex, uiMaxLength); - int iStatus2 = ReadLogFlags(&uiFlags, uiLogIndex); - if ( (iStatus1 < 0) || (iStatus2 < 0)) - return -1; - else if (iStatus1 == 0) - return 0; - else - { - char szTemp[64]; - if (uiFlags != 0) - uiFlags = uiFlags; //breakpoint - sprintf(szTemp, "LFR=%d,%d,%d,%d,", (int) *SQnum, (int) uiLogIndex, (int) uiFlags, (int) iStatus1); - *SQnum = *SQnum + 1; - memmove(&szResponse[strlen(szTemp)], szResponse, iStatus1); - memcpy(szResponse, szTemp, strlen(szTemp)); - return strlen(szTemp) + iStatus1; - } -} - -//Streaming FIFO -u32 StreamFIFO_SqnNum = 0; -void *StreamFIFOComm = 0; -u32 StreamFIFO_MaxPacket = 0; //maximum LFR binary data field size in bytes -char bPrimeStreamFIFO = FALSE; //set this to true if the streaming FIFO needs to be loaded from the main loop (instead of the callback) - -int ReloadStreamFIFO(void * comm) -{ - int retVal = 0; - int status; - err_t err; - if (comm > 0) - { - unsigned char ucSendAnother; - char SendDataBuff[MAX_SEND_PACKET_SIZE]; - do - { - u32 tcp_space_avail = tcp_sndbuf((struct tcp_pcb *)comm); - u32 uiMaxLen = ((u32)(tcp_space_avail/4) * 4)-64; //-64 is to account for the header - status = 0; - ucSendAnother = 0; - if (uiMaxLen > StreamFIFO_MaxPacket) - uiMaxLen = StreamFIFO_MaxPacket; - if (uiMaxLen > 0) - status = MakeMostFullLFR(&SendDataBuff[2], uiMaxLen, &StreamFIFO_SqnNum); - - if (status > 0) - { - u32 dummy; - status += 4; //for \n\r - SendDataBuff[0] = '\n'; SendDataBuff[1] = '\r'; - SendDataBuff[status-2] = '\n'; SendDataBuff[status-1] = '\r'; - if ( (tcp_space_avail - status >= MAX_SEND_PACKET_SIZE) && (DetermineMostFullLog(&dummy) >= MAX_SEND_PACKET_SIZE/4 )) //if we have at least a half packet that we can send - ucSendAnother = 2; - - err = tcp_write(comm, SendDataBuff, status, 1+ ucSendAnother); - if (err != ERR_OK) - status = 0; //break point - retVal += status; - } - - } while(ucSendAnother > 0 ); - } - return retVal; -} - -//internal functions -static int CmdBMK(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdCFG(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdCNT(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdCST(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdCTT(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdHBA(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdHBV(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdLFH(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdLM(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdLFR(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdLFS(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdLS(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdPRE(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdReadADC(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdWD(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdTRE(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdTRT(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdTCE(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdVSL(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdVSI(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdFSW(const char * szCmd, char *szResponse, void *CommDevice); -static int CmdDEA(const char * szCmd, char *szResponse, void *CommDevice); - -typedef struct command_table_entry { - char *szCmd; - char *szDescription; - int (*cmd_function)(const char *, char *, void *); -} command_table_entry; - -#define NUM_CMD 22 -command_table_entry command_table[NUM_CMD] = { - {"BMK", "Benchmark the PI controller logic", CmdBMK}, - {"CFG", "CFG=d: Write setting d to configuration register (d = 0 to 255)", CmdCFG}, - {"CNT", "CNT=n,cmd: Send the control application a message", CmdCNT}, - {"CST", "CST=n,cmd: Start control application n with startup command cmd", CmdCST}, - {"CTT", "CTT=n,cmd: Terminate control application n with command cmd", CmdCTT}, - {"HBA", "HBV=l1,l2,V,omega: Make an H-bridge from legs l1 and l2, output V (0-100), with omega (=int*128)", CmdHBA}, - {"HBV", "HBV=l1,l2,V: Make an H-bridge from legs l1 and l2 and output V (0-100)", CmdHBV}, - {"LFH", "Stop logging and hault sending unsolicited LFRs", CmdLFH}, - {"LFR", "Read a log output", CmdLFR}, - {"LFS", "Start logging and stream FIFO outputs (unsolicited LFRs sent until LFH recv'd)", CmdLFS}, - {"LM", "Log a memory address", CmdLM}, - {"LS", "Start logging", CmdLS}, - {"PRE", "PRE=toDev,fromDev: Read PECB data bus error count", CmdPRE}, - {"RADC", "Read ADC converter output", CmdReadADC}, - {"TCE", "Clear timing errors", CmdTCE}, - {"TRE", "Read timing errors", CmdTRE}, - {"TRT", "Read timer ticks", CmdTRT}, - {"WD", "WDn=d: Write d duty cycle register n (0 for off)", CmdWD}, - {"VSL", "VSL=l1,l2,l3: Set output legs for VSI", CmdVSL}, - {"VSI", "VSI=V,freq(,ramptime): Set V (percent output voltage, 0-100), with freq (Hz). Optional ramp time (ms)", CmdVSI}, - {"FSW", "FSW=frequency: Set PWM switching frequency (100Hz to 4MHz)", CmdFSW}, - {"DEA", "DEA=ns: Set PWM dead time in ns (25ns to ...)", CmdDEA} - }; - - - - - -/***************************** - * CmdLR() - * Handle the LR command. Read portion of the log. - * LR=index,start,length - * - * (must have already send LM commands to setup the log) - * - * Response: LR=index,start,length,binary_data - * **The response length will be different from the - * ** command length if the end of the log is reached - * **binary_data is byte-for-byte what is in the log. - * --> only 100us errors are but response is padded to 10 fields - *szCmd: the command - *szResponse: the response - */ -#if 0 -static int CmdLR(const char * szCmd, char *szResponse, void *CommDevice) -{ - const char *szNum = &szCmd[3]; - char bError = 0; - int retVal = 0; - u32 uiLogIndex, uiStart, uiLength; - - //get the log index number - uiLogIndex = atoi(szNum); - - if ( uiLogIndex >= MAX_LOG_VARS ) - bError = 1; - else - { -//get the number of bytes to read - int i; - for (i = 0; i < strlen(szCmd); i++) - if (szCmd[i] == ',') - { - szNum = &szCmd[i+1]; - break; - } - if (i == strlen(szCmd)) - bError = 1; - else - { - uiStart = atoi(szNum); - - for (i++; i < strlen(szCmd); i++) - if (szCmd[i] == ',') - { - szNum = &szCmd[i+1]; - break; - } - if (i == strlen(szCmd)) - bError = 1; - else - { - int iStatus; - uiLength = atoi(szNum); - iStatus = ReadFromLog((unsigned char*) szResponse, uiLogIndex, uiStart, uiLength); - if (iStatus < 0) - bError = 1; - else - { - char szTemp[64]; - sprintf(szTemp, "LR=%d,%d,%d,", (int) uiLogIndex, (int) uiStart, (int) iStatus); - memmove(&szResponse[strlen(szTemp)], szResponse, iStatus); - memcpy(szResponse, szTemp, strlen(szTemp)); - retVal = strlen(szTemp) + iStatus; - } - } - - } - } - if (bError) - { - strcat(szResponse, "ERROR"); - retVal = strlen(szResponse); - } - - return retVal; -} -#endif -/***************************** - * CmdLLR() - * Handle the LFR command. Read portion of the log. - * LFR=index,length - * - * (must have already send LM commands to setup the log) - * - * Response: LFR=sqn_num, index,flags,length,binary_data - * **The response length will be different from the - * ** command length if the end of the log is reached - * **binary_data is byte-for-byte what is in the log. - * --> only 100us errors are but response is padded to 10 fields - * **sqn_num is always 1 - *szCmd: the command - *szResponse: the response - */ -static int CmdLFR(const char * szCmd, char *szResponse, void *CommDevice) -{ - const char *szNum = &szCmd[4]; - char bError = 0; - int retVal = 0; - int iStatus1, iStatus2; - u32 uiLogIndex, uiLength, uiFlags; - - //get the log index number - uiLogIndex = atoi(szNum); - - if ( uiLogIndex >= MAX_LOG_VARS ) - bError = 1; - else - { -//get the number of bytes to read - int i; - for (i = 0; i < strlen(szCmd); i++) - if (szCmd[i] == ',') - { - szNum = &szCmd[i+1]; - break; - } - if (i == strlen(szCmd)) - bError = 1; - else - { - uiLength = atoi(szNum); - - iStatus1 = ReadFromLog((unsigned char*) szResponse, uiLogIndex, uiLength); - iStatus2 = ReadLogFlags(&uiFlags, uiLogIndex); - if ( (iStatus1 < 0) || (iStatus2 < 0)) - bError = 1; - else - { - char szTemp[64]; - sprintf(szTemp, "LFR=1,%d,%d,%d,", (int) uiLogIndex, (int) uiFlags, (int) iStatus1); - memmove(&szResponse[strlen(szTemp)], szResponse, iStatus1); - memcpy(szResponse, szTemp, strlen(szTemp)); - retVal = strlen(szTemp) + iStatus1; - } - } - } - if (bError) - { - strcat(szResponse, "ERROR"); - retVal = strlen(szResponse); - } - - return retVal; -} - - -/***************************** - * CmdBMK() - * Benchmark a PI controller - * BMK - * - * (must have already send LM commands to setup the log) - * - * Response: BMK=num - * number of time the PI controller was called in 1 second. - *szCmd: the command - *szResponse: the response - */ -static int CmdBMK(const char * szCmd, char *szResponse, void *CommDevice) -{ - u32 started = MainTimerTimerTick; - u32 count = 0; - double input; - double output; - double abc[3], dq0[3]; - pi_controller cont; - controller_context io; - controller_holder ctxt; - io.ClockTime = 10; - io.NumClocks = 1; - cont.kits = 10.315; - cont.kp = 1.42; - cont.plusSat = 5.12; - cont.negSat = -100.91; - cont.lastInt = 0; - io.inputs = &input; - io.outputs = &output; - io.NumInputs = 1; - io.NumOutputs = 1; - io.Status = C_RUNNING; - ctxt.control_io = &io; - ctxt.controller_info = &cont; - while (MainTimerTimerTick - started < 100000) - { - /*input += 0.1; - if (input > cont.plusSat + 0.5) - input = cont.negSat; - RunPI_Controller(&ctxt);*/ - abc[0] = count/1000.0; - abc[1] = (double) MainTimerTimerTick/100000.0; - abc[2] = 3*abc[0]; - DQ0_Transform(((double) MainTimerTimerTick)/100000.0, abc, dq0); - count++; - } - - sprintf(szResponse, "BMK=%d", (int) count); - return strlen(szResponse); -} - - -/***************************** - * CmdLS() - * Handle the LS command. Start logging. - * LS - * - * (must have already send LM commands to setup the log) - * - * Response: OK - * --> only 100us errors are but response is padded to 10 fields - *szCmd: the command - *szResponse: the response - */ -static int CmdLS(const char * szCmd, char *szResponse, void *CommDevice) -{ - if (StartLogging() == SUCCESS) - strcat(szResponse, "OK"); - else - strcat(szResponse, "ERROR"); - - return strlen(szResponse); -} - -/***************************** - * CmdLFS() - * Handle the LFS command. Start logging and start sending unsolicited - * LFRs. - * LFS=max_packet_size (in bytes) - * - * (must have already sent LM commands to setup the log) - * - * Response: OK - *szCmd: the command - *szResponse: the response - */ -static int CmdLFS(const char * szCmd, char *szResponse, void *CommDevice) -{ - const char *szNum = &szCmd[4]; - u32 tempLen = 0; - - //get the log index number - tempLen = atoi(szNum); - - if ( (StartLogging() == SUCCESS) && (tempLen > 0) && (tempLen % 4 == 0)) - { - strcat(szResponse, "OK"); - StreamFIFO_SqnNum = 1; - StreamFIFO_MaxPacket = tempLen; - StreamFIFOComm = CommDevice; - bPrimeStreamFIFO = TRUE; - } - else - strcat(szResponse, "ERROR"); - - return strlen(szResponse); -} - -/***************************** - * CmdLFH() - * Handle the LFH command. Hault sending unsolicited LFRs - * LFH - * - * - * Response: OK - * --> only 100us errors are but response is padded to 10 fields - *szCmd: the command - *szResponse: the response - */ -static int CmdLFH(const char * szCmd, char *szResponse, void *CommDevice) -{ - StreamFIFOComm = 0; - bPrimeStreamFIFO = FALSE; - - StopAllLogging(); - strcat(szResponse, "OK"); - - return strlen(szResponse); -} - - - - -/***************************** - * CmdLM() - * Handle the LM command. Log a memory address - * LM=index,address,settings - * index: log file index (0 to MAX_LOG_VARS-1) - * Response: OK - * --> only 100us errors are but response is padded to 10 fields - *szCmd: the command - *szResponse: the response - */ -static int CmdLM(const char * szCmd, char *szResponse, void *CommDevice) -{ - const char *szNum = &szCmd[3]; - char bError = 0; - u32 uiLogIndex, uiAddr, uiSettings; - - //get the log index number - uiLogIndex = atoi(szNum); - - if ( uiLogIndex >= MAX_LOG_VARS ) - bError = 1; - else - { -//get the memory address - int i; - for (i = 0; i < strlen(szCmd); i++) - if (szCmd[i] == ',') - { - szNum = &szCmd[i+1]; - break; - } - if (i == strlen(szCmd)) - bError = 1; - else - { - uiAddr = atoi(szNum); - for (i++; i < strlen(szCmd); i++) - if (szCmd[i] == ',') - { - szNum = &szCmd[i+1]; - break; - } - if (i == strlen(szCmd)) - bError = 1; - else - { - uiSettings = atoi(szNum); - - if (SetupLogVariable(uiLogIndex, (u32 *) uiAddr, uiSettings) != SUCCESS) - bError = 1; - else - strcat(szResponse, "OK"); - } - } - } - if (bError) - strcat(szResponse, "ERROR"); - - return strlen(szResponse); -} - - -unsigned char HBA_bEnabled = 0; -u32 HBA_uiLeg1, HBA_uiLeg2; -double HBA_dbVPercent, HBA_dbOmega, HBA_dbTheta; - -/***************************** - * CmdHBA() - * Handle the 100uS tick for the ac HBridge function. - */ -void HBA_100usTick() -{ - //generate ac for Hbridge - if (HBA_bEnabled){ - u8 duty1, duty2; - double update_da = ((double) HBA_dbOmega/( (double) 10000)); - double dbVPercent; - HBA_dbTheta += update_da; - if (HBA_dbTheta > 6.283185307179586) - HBA_dbTheta -= 6.283185307179586; - - dbVPercent = HBA_dbVPercent*cos(HBA_dbTheta); - - duty1 = (unsigned char) 127*(1 + dbVPercent); - duty2 = (unsigned char) 127*(1 - dbVPercent); - - WriteDutyRatio(HBA_uiLeg1, duty1); - WriteDutyRatio(HBA_uiLeg2, duty2); - } -} - - -// Ramps between `current` and `setpoint` values assuming Fs = 10kHz -// Updates `current` as it ramps. -// -// `ramprate` is in (units of `current`) / sec -// 0 implies no ramp -// -// -// Returns delta in Ts for theta update -// -double omega_ramp_fcn(double *current, double *setpoint, double ramprate) -{ - double ret; - - if (ramprate != 0 && *current != *setpoint) { - // Ramping - double dir = (*setpoint > *current) ? 1 : -1; - double del = ramprate / 10000.0; - - *current += (dir * del); - ret = *current / 10000.0; - - // Check if done ramping - if ((dir == 1) && (*current > *setpoint)) *current = *setpoint; - if ((dir == -1) && (*current < *setpoint)) *current = *setpoint; - } else { - // Not ramping - ret = *setpoint / 10000.0; - } - - return ret; -} - -uint8_t VSI_enabled = 0; -uint8_t VSI_leg1; -uint8_t VSI_leg2; -uint8_t VSI_leg3; -double VSI_Vpercent = 0; -double VSI_omega = 0; -double theta = 0; - -double VSI_omega_ramp = 0; -double VSI_old_Vpercent = 0; -double VSI_old_omega = 0; - -double VSI_R; -double VSI_V0; - -/***************************** - * CmdVSI() - * Handle the 100uS tick for the VSI function. - */ -void VSI_100usTick(void) -{ - if (VSI_enabled) { -// uint8_t duty1, duty2, duty3; - - // Calculate `da` - double update_da = omega_ramp_fcn(&VSI_old_omega, &VSI_omega, VSI_omega_ramp); - - // Calculate dv - // ramp(&VSI_old_Vpercent, &VSI_Vpercent, 0.1); - - theta += update_da; - if (theta > 6.283185307179586) - theta -= 6.283185307179586; - - double v = (VSI_R * VSI_old_omega) + VSI_V0; - - double percent1 = v*cos(theta); - double percent2 = v*cos(theta - PI23); - double percent3 = v*cos(theta + PI23); - -// duty1 = (unsigned char) 127*(1 + percent1); -// duty2 = (unsigned char) 127*(1 + percent2); -// duty3 = (unsigned char) 127*(1 + percent3); - - pwm_set_duty(VSI_leg1 - 1, (1 + percent1) / 2.0); - pwm_set_duty(VSI_leg2 - 1, (1 + percent2) / 2.0); - pwm_set_duty(VSI_leg3 - 1, (1 + percent3) / 2.0); - -// WriteDutyRatio(VSI_leg1, duty1); -// WriteDutyRatio(VSI_leg2, duty2); -// WriteDutyRatio(VSI_leg3, duty3); - } else { - WriteDutyRatio(VSI_leg1, 0); - WriteDutyRatio(VSI_leg2, 0); - WriteDutyRatio(VSI_leg3, 0); - } -} - - -/***************************** - * CmdHBA() - * Handle the HBA command. Make an HBridge from two legs and - * output the specified voltage as a sine wave varying from 0 - * to the peak value specified - * HBV=leg1,leg2,voltage,omega - * leg1: number of leg 1 (1 to NUM_LEGS) - * leg2: number of leg 2 (1 to NUM_LEGS) - * voltage: percent of bus voltage (0 to 100) - * omega: 0 to 2*pi*10000, specified as an integer which must - * be divided by 128 - * Response: OK - *szCmd: the command - *szResponse: the response - */ -static int CmdHBA(const char * szCmd, char *szResponse, void *CommDevice) -{ - const char *szNum = &szCmd[4]; - char bError = 0; - u32 uiLeg1, uiLeg2, uiVoltagePercent; - -//get the leg 1 number - uiLeg1 = atoi(szNum); - - if ( (uiLeg1 > NUM_LEGS) || (uiLeg1 == 0) ) - bError = 1; - else - { -//get the leg 2 number - int i; - for (i = 0; i < strlen(szCmd); i++) - if (szCmd[i] == ',') - { - szNum = &szCmd[i+1]; - break; - } - if (i == strlen(szCmd)) - bError = 1; - else - { - uiLeg2 = atoi(szNum); - if ( (uiLeg2 > NUM_LEGS) || (uiLeg2 == 0) ) - bError = 1; - else - { - for (i++; i < strlen(szCmd); i++) - if (szCmd[i] == ',') - { - szNum = &szCmd[i+1]; - break; - } - if (i == strlen(szCmd)) - bError = 1; - else - { - double dbVPercent; - uiVoltagePercent = atoi(szNum); - dbVPercent = ((double) uiVoltagePercent)/100; - - for (i++; i < strlen(szCmd); i++) - if (szCmd[i] == ',') - { - szNum = &szCmd[i+1]; - break; - } - if (i == strlen(szCmd)) - bError = 1; - else - { - HBA_dbOmega = ((double) atoi(szNum)) / ((double) 128); - HBA_dbVPercent = dbVPercent; - HBA_uiLeg1 = uiLeg1; - HBA_uiLeg2 = uiLeg2; - HBA_bEnabled = 1; - strcat(szResponse, "OK"); - } - } - } - } - } - if (bError) - strcat(szResponse, "ERROR"); - - return strlen(szResponse); -} - -/***************************** - * CmdHBV() - * Handle the HBV command. Make an HBridge from two legs and - * output the specified voltage - * HBV=leg1,leg2,voltage - * leg1: number of leg 1 (1 to NUM_LEGS) - * leg2: number of leg 2 (1 to NUM_LEGS) - * voltage: percent of bus voltage (0 to 100) - * Response: OK - *szCmd: the command - *szResponse: the response - */ -static int CmdHBV(const char * szCmd, char *szResponse, void *CommDevice) -{ - const char *szNum = &szCmd[4]; - char bError = 0; - u32 uiLeg1, uiLeg2, uiVoltagePercent; - -//get the leg 1 number - uiLeg1 = atoi(szNum); - - if ( (uiLeg1 > NUM_LEGS) || (uiLeg1 == 0) ) - bError = 1; - else - { -//get the leg 2 number - int i; - for (i = 0; i < strlen(szCmd); i++) - if (szCmd[i] == ',') - { - szNum = &szCmd[i+1]; - break; - } - if (i == strlen(szCmd)) - bError = 1; - else - { - uiLeg2 = atoi(szNum); - if ( (uiLeg2 > NUM_LEGS) || (uiLeg2 == 0) ) - bError = 1; - else - { - for (i++; i < strlen(szCmd); i++) - if (szCmd[i] == ',') - { - szNum = &szCmd[i+1]; - break; - } - if (i == strlen(szCmd)) - bError = 1; - else - { - double dbVPercent; - u8 duty1, duty2; - uiVoltagePercent = atoi(szNum); - dbVPercent = ((double) uiVoltagePercent)/100; - duty1 = (unsigned char) 127*(1 + dbVPercent); - duty2 = (unsigned char) 127*(1 - dbVPercent); - - WriteDutyRatio(uiLeg1, duty1); - WriteDutyRatio(uiLeg2, duty2); - strcat(szResponse, "OK"); - } - } - } - } - if (bError) - strcat(szResponse, "ERROR"); - - return strlen(szResponse); -} - - -/***************************** - * CmdReadADC() - * Handle the RADC command - * RADCn - n is adc number (1 - 12) - * Response: RADCn=xx.xxxxV - *szCmd: the command - *szResponse: the response - */ -static int CmdReadADC(const char * szCmd, char *szResponse, void *CommDevice) -{ - const char *szADCnum = &szCmd[4]; - double dbADC = 0; - u32 uiADCnum = atoi(szADCnum); - if ( (uiADCnum > 0) && (uiADCnum < 13) ) - { - dbADC = ReadADC(uiADCnum); - sprintf(szResponse, "ADC%d=%2.4fV", (int)uiADCnum,dbADC); //reads +-10V, accurate to 0.0049V - } - else - strcpy(szResponse, "ERROR"); - - return strlen(szResponse); -} - -/***************************** - * CmdTCE() - * Handle the TCE command. Clear timing errors. - * RTE - * Response: OK - * --> only 100us errors are but response is padded to 10 fields - *szCmd: the command - *szResponse: the response - */ -static int CmdTCE(const char * szCmd, char *szResponse, void *CommDevice) -{ - Timing10usErrorCount = 0; - Timing100usErrorCount = 0; - ControlTimer0ErrorCount = 0; - ControlTimer1ErrorCount = 0; - strcpy(szResponse, "OK"); - - return strlen(szResponse); -} - - -/***************************** - * CmdTRT() - * Handle the TRT command. Read timing ticks. - * RTE - * Response: TRT=main,control0,control1,,,,,,, - * --> only first 3 are defined but response is padded to 10 fields - *szCmd: the command - *szResponse: the response - */ -static int CmdTRT(const char * szCmd, char *szResponse, void *CommDevice) -{ - /*u32 TimerCount1 = XTmrCtr_ReadReg(0x42800000, - TIMER_CNTR_0, XTC_TCR_OFFSET);*/ - - sprintf(szResponse, "TRT=%d,%d,%d,,,,,,,", (int) MainTimerTimerTick, (int) ControlTimer0_TickCount, (int) ControlTimer1_TickCount); - - return strlen(szResponse); -} - -/***************************** - * CmdPRE() - * Handle the PRE command. Read PECB databus errors. - * RTE - * Response: PRE=ToPECB,FromPECB - *szCmd: the command - *szResponse: the response - */ -static int CmdPRE(const char * szCmd, char *szResponse, void *CommDevice) -{ - /*u32 TimerCount1 = XTmrCtr_ReadReg(0x42800000, - TIMER_CNTR_0, XTC_TCR_OFFSET);*/ - u32 ec_to_dev, ec_from_dev; - ec_to_dev = PECB[ER_CNT] & 0xFFFF; - ec_from_dev = (PECB[ER_CNT] >> 16) & 0xFFFF; - sprintf(szResponse, "TRE=%d,%d,%d,%d", (int) ec_to_dev, (int) ec_from_dev, (int) PECB[ER_CNT-1], (int) PECB[ER_CNT-2]); - - return strlen(szResponse); -} - - -/***************************** - * CmdTRE() - * Handle the TRE command. Read timing errors. - * RTE - * Response: TRE=10us,100us,,,,,,,, - * --> only 10us, 100us errors are but response is padded to 10 fields - *szCmd: the command - *szResponse: the response - */ -static int CmdTRE(const char * szCmd, char *szResponse, void *CommDevice) -{ - /*u32 TimerCount1 = XTmrCtr_ReadReg(0x42800000, - TIMER_CNTR_0, XTC_TCR_OFFSET);*/ - - sprintf(szResponse, "TRE=%d,%d,%d,%d,,,,,,", (int) Timing10usErrorCount, (int) Timing100usErrorCount, (int) ControlTimer0ErrorCount, (int) ControlTimer1ErrorCount); - - return strlen(szResponse); -} - - -/***************************** - * CmdCFG() - * Handle the CFG command. Write setting to config register. - * CFG=d - * --> d: (0 to 255) - *szCmd: the command - *szResponse: the response - */ -static int CmdCFG(const char * szCmd, char *szResponse, void *CommDevice) -{ - const char *szNum = &szCmd[4]; - char bError = 0; - u32 uiValue; - if ( (szNum[0] < 0x30) || (szNum[0] > 0x39) ) - bError = 1; - else - { -//get the value - uiValue = atoi(szNum); - WriteConfigRegister((u8) uiValue); - sprintf(szResponse, "OK"); - } - if (bError) - strcpy(szResponse, "ERROR"); - - return strlen(szResponse); -} - - -/***************************** - * CmdWD() - * Handle the WD command. Write duty ratio. - * WDn=d - * --> n: duty ratio register to write to - * --> d: (0 to 255) - *szCmd: the command - *szResponse: the response - */ -static int CmdWD(const char * szCmd, char *szResponse, void *CommDevice) -{ - const char *szNum = &szCmd[2]; - char bError = 0; - u32 uiLeg, uiValue; - if ( (szNum[0] < 0x31) ) - bError = 1; - else - { -//get the leg number - uiLeg = atoi(szNum); - - if ( (uiLeg < 1) || (uiLeg > NUM_LEGS) ) - bError = 1; - else - { -//get new duty ratio - int i; - for (i = 0; i < strlen(szCmd); i++) - if (szCmd[i] == '=') - { - szNum = &szCmd[i+1]; - break; - } - if (i == strlen(szCmd)) - bError = 1; - else - { - uiValue = atoi(szNum); - if (uiValue > 255) - bError = 1; - else - { - WriteDutyRatio(uiLeg, (unsigned char) uiValue); - sprintf(szResponse, "OK"); - } - } - } - } - if (bError) - strcpy(szResponse, "ERROR"); - - return strlen(szResponse); -} - - -/***************************** - * CmdCNT() - * Handle the CNT command. Send a control application a command. - * CNT=d,CMD - * --> n: which control application to send the command to (number) - * --> CMD: The command to send - *szCmd: the command - *szResponse: the response - */ -static int CmdCNT(const char * szCmd, char *szResponse, void *CommDevice) -{ - const char *szAppCMD = &szCmd[4]; - - u32 uiApp; - { -//get the control application to send to - uiApp = atoi(szAppCMD); - - if ( uiApp >= 1) //|| (uiLeg > NUM_LEGS) ) - { -//get new duty ratio - int i; - for (i = 0; i < strlen(szCmd); i++) - if (szCmd[i] == ',') - { - szAppCMD = &szCmd[i+1]; - break; - } - if (i != strlen(szCmd)) - { - if (uiApp == 1) - return ControlAppCommand(szAppCMD, szResponse, CommDevice); - else if (uiApp == 2) - return TorqueVSI_Command(szAppCMD, szResponse, CommDevice); - } - } - } - strcpy(szResponse, "ERROR"); - - return strlen(szResponse); -} - - -/***************************** - * CmdCTT() - * Handle the CTT command. Start a control application with a command. - * CTT=n,CMD - * --> n: which control application to start (number) - * --> CMD: The start command to send - *szCmd: the command - *szResponse: the response - */ -static int CmdCTT(const char * szCmd, char *szResponse, void *CommDevice) -{ - const char *szAppCMD = &szCmd[4]; - - u32 uiApp; - { -//get the control application to send to - uiApp = atoi(szAppCMD); - - if ( uiApp >= 1) //|| (uiLeg > NUM_LEGS) ) - { -//get new duty ratio - int i; - for (i = 0; i < strlen(szCmd); i++) - if (szCmd[i] == ',') - { - szAppCMD = &szCmd[i+1]; - break; - } - if (i != strlen(szCmd)) - { - if (uiApp == 1) - return ControlStopAppCommand(szAppCMD, szResponse, CommDevice); - else if (uiApp == 2) - return TorqueVSI_StopCommand(szAppCMD, szResponse, CommDevice); - } - } - } - strcpy(szResponse, "ERROR"); - - return strlen(szResponse); -} - -/***************************** - * CmdCST() - * Handle the CST command. Start a control application with a command. - * CST=n,CMD - * --> n: which control application to start (number) - * --> CMD: The start command to send - *szCmd: the command - *szResponse: the response - */ -static int CmdCST(const char * szCmd, char *szResponse, void *CommDevice) -{ - const char *szAppCMD = &szCmd[4]; - - u32 uiApp; - { -//get the control application to send to - uiApp = atoi(szAppCMD); - - if ( uiApp >= 1) //|| (uiLeg > NUM_LEGS) ) - { -//get new duty ratio - int i; - for (i = 0; i < strlen(szCmd); i++) - if (szCmd[i] == ',') - { - szAppCMD = &szCmd[i+1]; - break; - } - if (i != strlen(szCmd)) - { - if (uiApp == 1) - return ControlStartAppCommand(szAppCMD, szResponse, CommDevice); - else if (uiApp == 2) - return TorqueVSI_StartCommand(szAppCMD, szResponse, CommDevice); - } - } - } - strcpy(szResponse, "ERROR"); - - return strlen(szResponse); -} - -/***************************** - * CmdVSL() - * Handle the VSL command. - * - * VSL=leg1,leg2,leg3 - * - * leg1: number of leg 1 (1 to NUM_LEGS) - * leg2: number of leg 2 (1 to NUM_LEGS) - * leg3: number of leg 3 (1 to NUM_LEGS) - * - * Response: OK - * - *szCmd: the command - *szResponse: the response - */ - -static char bufferVSL[128]; -static int CmdVSL(const char * szCmd, char *szResponse, void *CommDevice) -{ - char *p; - int i = 0; - - // Create copy of cmd for parsing - memset(bufferVSL, 0, 128); - strcpy(bufferVSL, szCmd); - - // Parse out tokens - int iLeg1 = 0; - int iLeg2 = 0; - int iLeg3 = 0; - - p = strtok(bufferVSL, "=,"); - while (p != NULL) { - // Use current token... - switch (i) { - case 0: - // Ignore 'VSL' - break; - case 1: - iLeg1 = atoi(p); - break; - case 2: - iLeg2 = atoi(p); - break; - case 3: - iLeg3 = atoi(p); - break; - default: - // This is an error! - // Force error below - iLeg1 = 0; - iLeg2 = 1; - iLeg3 = 1; - break; - } - - // Get next token - p = strtok(NULL, "=,"); - i++; - } - - // Check if all 0 => disable VSI - if (iLeg1 == 0 && iLeg2 == 0 && iLeg3 == 0) { - VSI_enabled = 0; - strcat(szResponse, "OK"); - return strlen(szResponse); - } - - // Check if errors in leg numbers - int bError = 0; - if (iLeg1 <= 0 || iLeg1 > NUM_LEGS) bError = 1; - if (iLeg2 <= 0 || iLeg2 > NUM_LEGS) bError = 1; - if (iLeg3 <= 0 || iLeg3 > NUM_LEGS) bError = 1; - - if (bError) { - strcat(szResponse, "ERROR"); - return strlen(szResponse); - } - - // Set legs for VSI - VSI_leg1 = iLeg1; - VSI_leg2 = iLeg2; - VSI_leg3 = iLeg3; - - // Enable VSI - VSI_enabled = 1; - - strcat(szResponse, "OK"); - return strlen(szResponse); -} - - -/***************************** - * CmdVSI() - * Handle the VSI command. - * - * VSI=voltage,freq(,ramp) - * - * voltage: peak voltage output percent of Vbus (0 to 100) - * freq: frequency of output (Hz) - * ramptime: (optional) duration of ramping (ms) - * - * Response: OK - * - *szCmd: the command - *szResponse: the response - */ - -static char bufferVSI[128]; -static int CmdVSI(const char * szCmd, char *szResponse, void *CommDevice) -{ - char *p; - int i = 0; - - // Create copy of cmd for parsing - memset(bufferVSI, 0, 128); - strcpy(bufferVSI, szCmd); - - // Parse out tokens - int iVoltagePercent = 0; - int iHz = 0; - int iRamptime = 0; - - p = strtok(bufferVSI, "=,"); - while (p != NULL) { - // Use current token... - switch (i) { - case 0: - // Ignore 'VSI' - break; - case 1: - iVoltagePercent = atoi(p); - break; - case 2: - iHz = atoi(p); - break; - case 3: - iRamptime = atoi(p); - break; - default: - // This is an error! - // Force error below - iHz = 0; - break; - } - - // Get next token - p = strtok(NULL, "=,"); - i++; - } - - // Check for errors while parsing -// if (iHz == 0 || iVoltagePercent == 0) { -// strcat(szResponse, "ERROR"); -// return strlen(szResponse); -// } - - // Convert voltage percent input to double percentage - VSI_old_Vpercent = VSI_Vpercent; - VSI_Vpercent = iVoltagePercent / 100.0; - if (VSI_Vpercent > 100) VSI_Vpercent = 100.0; - if (VSI_Vpercent < 0) VSI_Vpercent = 0.0; - - - // Convert freq input to rad/sec - VSI_old_omega = VSI_omega; - VSI_omega = 2 * PI * iHz; - - if (iRamptime > 0) { - VSI_omega_ramp = abs(VSI_old_omega - VSI_omega) / (iRamptime / 1000.0); // (rad/sec) / sec - } else { - VSI_omega_ramp = 0; - } - - - if (VSI_omega != VSI_old_omega) { - // There is delta freq requested - VSI_R = (VSI_Vpercent - VSI_old_Vpercent) / (VSI_omega - VSI_old_omega); - VSI_V0 = VSI_Vpercent - (VSI_R * VSI_omega); - } else { - // Instaneous voltage change - VSI_R = 0; - VSI_V0 = VSI_Vpercent; - } - - strcat(szResponse, "OK"); - return strlen(szResponse); -} - -static char bufferFSW[128]; -static int CmdFSW(const char * szCmd, char *szResponse, void *CommDevice) -{ - char *p; - int i = 0; - - // Create copy of cmd for parsing - memset(bufferFSW, 0, 128); - strcpy(bufferFSW, szCmd); - - // Parse out tokens - int iHz = 0; - - p = strtok(bufferFSW, "=,"); - while (p != NULL) { - // Use current token... - switch (i) { - case 0: - // Ignore 'FSW' - break; - case 1: - iHz = atoi(p); - break; - default: - // This is an error! - // Force error below - iHz = 0; - break; - } - - // Get next token - p = strtok(NULL, "=,"); - i++; - } - - // Check for errors while parsing - if (iHz < 100 || iHz > 4000000) { - strcat(szResponse, "ERROR"); - return strlen(szResponse); - } - - // do work - pwm_set_switching_freq((double) iHz); - - strcat(szResponse, "OK"); - return strlen(szResponse); -} - - - -static char bufferDEA[128]; -static int CmdDEA(const char * szCmd, char *szResponse, void *CommDevice) -{ - char *p; - int i = 0; - - // Create copy of cmd for parsing - memset(bufferDEA, 0, 128); - strcpy(bufferDEA, szCmd); - - // Parse out tokens - int iNs = 0; - - p = strtok(bufferDEA, "=,"); - while (p != NULL) { - // Use current token... - switch (i) { - case 0: - // Ignore 'DEA' - break; - case 1: - iNs = atoi(p); - break; - default: - // This is an error! - // Force error below - iNs = 0; - break; - } - - // Get next token - p = strtok(NULL, "=,"); - i++; - } - - // Check for errors while parsing - if (iNs < 25 || iNs > 1e9) { - strcat(szResponse, "ERROR"); - return strlen(szResponse); - } - - // do work - pwm_set_deadtime_ns(iNs); - - strcat(szResponse, "OK"); - return strlen(szResponse); -} - - - - - - - -//call this with the CR removed -//load the response into szResponse -int CommandParser(const char * szCmd, char *szResponse, void *CommDevice) -{ - char szTemp[256]; - int retVal = 0; - //read ADC - int i; - char bFoundCmd = 0; - szResponse[0] = 0; //put a leading null in to prevent any issues - for (i = 0; i 0) - { - szSendCmd[newLen++] = '\r'; - szSendCmd[newLen++] = '\n'; - outLen += newLen + 2; - } - } - else if (cRcvd[0] != '\n') //ignore line feeds - { - szRcvCmd[*state] = cRcvd[0]; - *state += 1; - szRcvCmd[*state] = 0; //always null terminate - - //strcat(szRcvCmd, cRcvd); - } - } - return outLen; -} + +#if 0 +#include "xparameters.h" +#include "xil_exception.h" +#include "xil_printf.h" +#include +#include +#include +#include "commands.h" +#include "main.h" +#include "project_settings.h" +#include "log.h" +#include "prog_timer.h" +#endif + +#include "project_include.h" + +#include "../bsp/bsp.h" + +/***************************** + * MakeMostFullLFR() + * Populate an LFR response from the most-full log + * + * + * Response: LFR=sqn_num,index,flags,length,binary_data + * **The response length will be different from the + * ** command length if the end of the log is reached + * **binary_data is byte-for-byte what is in the log. + * **sqn_num is a sequence number that starts at 1 (reset when LFS is received) + * and increments with each LFR + * --> only 100us errors are but response is padded to 10 fields + *szResponse: the response + *uiMaxLength: the maximum length of the binary_data field (must be divisible by 4) + */ +int MakeMostFullLFR(char *szResponse, u32 uiMaxLength, u32 *SQnum) +{ + u32 uiLogIndex = 0, uiFlags = 0; + int iStatus1 = ReadFromMostFullLog((unsigned char*) szResponse, &uiLogIndex, uiMaxLength); + int iStatus2 = ReadLogFlags(&uiFlags, uiLogIndex); + if ( (iStatus1 < 0) || (iStatus2 < 0)) + return -1; + else if (iStatus1 == 0) + return 0; + else + { + char szTemp[64]; + if (uiFlags != 0) + uiFlags = uiFlags; //breakpoint + sprintf(szTemp, "LFR=%d,%d,%d,%d,", (int) *SQnum, (int) uiLogIndex, (int) uiFlags, (int) iStatus1); + *SQnum = *SQnum + 1; + memmove(&szResponse[strlen(szTemp)], szResponse, iStatus1); + memcpy(szResponse, szTemp, strlen(szTemp)); + return strlen(szTemp) + iStatus1; + } +} + +//Streaming FIFO +u32 StreamFIFO_SqnNum = 0; +void *StreamFIFOComm = 0; +u32 StreamFIFO_MaxPacket = 0; //maximum LFR binary data field size in bytes +char bPrimeStreamFIFO = FALSE; //set this to true if the streaming FIFO needs to be loaded from the main loop (instead of the callback) + +int ReloadStreamFIFO(void * comm) +{ + int retVal = 0; + int status; + err_t err; + if (comm > 0) + { + unsigned char ucSendAnother; + char SendDataBuff[MAX_SEND_PACKET_SIZE]; + do + { + u32 tcp_space_avail = tcp_sndbuf((struct tcp_pcb *)comm); + u32 uiMaxLen = ((u32)(tcp_space_avail/4) * 4)-64; //-64 is to account for the header + status = 0; + ucSendAnother = 0; + if (uiMaxLen > StreamFIFO_MaxPacket) + uiMaxLen = StreamFIFO_MaxPacket; + if (uiMaxLen > 0) + status = MakeMostFullLFR(&SendDataBuff[2], uiMaxLen, &StreamFIFO_SqnNum); + + if (status > 0) + { + u32 dummy; + status += 4; //for \n\r + SendDataBuff[0] = '\n'; SendDataBuff[1] = '\r'; + SendDataBuff[status-2] = '\n'; SendDataBuff[status-1] = '\r'; + if ( (tcp_space_avail - status >= MAX_SEND_PACKET_SIZE) && (DetermineMostFullLog(&dummy) >= MAX_SEND_PACKET_SIZE/4 )) //if we have at least a half packet that we can send + ucSendAnother = 2; + + err = tcp_write(comm, SendDataBuff, status, 1+ ucSendAnother); + if (err != ERR_OK) + status = 0; //break point + retVal += status; + } + + } while(ucSendAnother > 0 ); + } + return retVal; +} + +//internal functions +static int CmdBMK(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdCFG(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdCNT(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdCST(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdCTT(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdHBA(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdHBV(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdLFH(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdLM(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdLFR(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdLFS(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdLS(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdPRE(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdReadADC(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdWD(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdTRE(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdTRT(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdTCE(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdVSL(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdVSI(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdFSW(const char * szCmd, char *szResponse, void *CommDevice); +static int CmdDEA(const char * szCmd, char *szResponse, void *CommDevice); + +typedef struct command_table_entry { + char *szCmd; + char *szDescription; + int (*cmd_function)(const char *, char *, void *); +} command_table_entry; + +#define NUM_CMD 22 +command_table_entry command_table[NUM_CMD] = { + {"BMK", "Benchmark the PI controller logic", CmdBMK}, + {"CFG", "CFG=d: Write setting d to configuration register (d = 0 to 255)", CmdCFG}, + {"CNT", "CNT=n,cmd: Send the control application a message", CmdCNT}, + {"CST", "CST=n,cmd: Start control application n with startup command cmd", CmdCST}, + {"CTT", "CTT=n,cmd: Terminate control application n with command cmd", CmdCTT}, + {"HBA", "HBV=l1,l2,V,omega: Make an H-bridge from legs l1 and l2, output V (0-100), with omega (=int*128)", CmdHBA}, + {"HBV", "HBV=l1,l2,V: Make an H-bridge from legs l1 and l2 and output V (0-100)", CmdHBV}, + {"LFH", "Stop logging and hault sending unsolicited LFRs", CmdLFH}, + {"LFR", "Read a log output", CmdLFR}, + {"LFS", "Start logging and stream FIFO outputs (unsolicited LFRs sent until LFH recv'd)", CmdLFS}, + {"LM", "Log a memory address", CmdLM}, + {"LS", "Start logging", CmdLS}, + {"PRE", "PRE=toDev,fromDev: Read PECB data bus error count", CmdPRE}, + {"RADC", "Read ADC converter output", CmdReadADC}, + {"TCE", "Clear timing errors", CmdTCE}, + {"TRE", "Read timing errors", CmdTRE}, + {"TRT", "Read timer ticks", CmdTRT}, + {"WD", "WDn=d: Write d duty cycle register n (0 for off)", CmdWD}, + {"VSL", "VSL=l1,l2,l3: Set output legs for VSI", CmdVSL}, + {"VSI", "VSI=V,freq(,ramptime): Set V (percent output voltage, 0-100), with freq (Hz). Optional ramp time (ms)", CmdVSI}, + {"FSW", "FSW=frequency: Set PWM switching frequency (100Hz to 4MHz)", CmdFSW}, + {"DEA", "DEA=ns: Set PWM dead time in ns (25ns to ...)", CmdDEA} + }; + + + + + +/***************************** + * CmdLR() + * Handle the LR command. Read portion of the log. + * LR=index,start,length + * + * (must have already send LM commands to setup the log) + * + * Response: LR=index,start,length,binary_data + * **The response length will be different from the + * ** command length if the end of the log is reached + * **binary_data is byte-for-byte what is in the log. + * --> only 100us errors are but response is padded to 10 fields + *szCmd: the command + *szResponse: the response + */ +#if 0 +static int CmdLR(const char * szCmd, char *szResponse, void *CommDevice) +{ + const char *szNum = &szCmd[3]; + char bError = 0; + int retVal = 0; + u32 uiLogIndex, uiStart, uiLength; + + //get the log index number + uiLogIndex = atoi(szNum); + + if ( uiLogIndex >= MAX_LOG_VARS ) + bError = 1; + else + { +//get the number of bytes to read + int i; + for (i = 0; i < strlen(szCmd); i++) + if (szCmd[i] == ',') + { + szNum = &szCmd[i+1]; + break; + } + if (i == strlen(szCmd)) + bError = 1; + else + { + uiStart = atoi(szNum); + + for (i++; i < strlen(szCmd); i++) + if (szCmd[i] == ',') + { + szNum = &szCmd[i+1]; + break; + } + if (i == strlen(szCmd)) + bError = 1; + else + { + int iStatus; + uiLength = atoi(szNum); + iStatus = ReadFromLog((unsigned char*) szResponse, uiLogIndex, uiStart, uiLength); + if (iStatus < 0) + bError = 1; + else + { + char szTemp[64]; + sprintf(szTemp, "LR=%d,%d,%d,", (int) uiLogIndex, (int) uiStart, (int) iStatus); + memmove(&szResponse[strlen(szTemp)], szResponse, iStatus); + memcpy(szResponse, szTemp, strlen(szTemp)); + retVal = strlen(szTemp) + iStatus; + } + } + + } + } + if (bError) + { + strcat(szResponse, "ERROR"); + retVal = strlen(szResponse); + } + + return retVal; +} +#endif +/***************************** + * CmdLLR() + * Handle the LFR command. Read portion of the log. + * LFR=index,length + * + * (must have already send LM commands to setup the log) + * + * Response: LFR=sqn_num, index,flags,length,binary_data + * **The response length will be different from the + * ** command length if the end of the log is reached + * **binary_data is byte-for-byte what is in the log. + * --> only 100us errors are but response is padded to 10 fields + * **sqn_num is always 1 + *szCmd: the command + *szResponse: the response + */ +static int CmdLFR(const char * szCmd, char *szResponse, void *CommDevice) +{ + const char *szNum = &szCmd[4]; + char bError = 0; + int retVal = 0; + int iStatus1, iStatus2; + u32 uiLogIndex, uiLength, uiFlags; + + //get the log index number + uiLogIndex = atoi(szNum); + + if ( uiLogIndex >= MAX_LOG_VARS ) + bError = 1; + else + { +//get the number of bytes to read + int i; + for (i = 0; i < strlen(szCmd); i++) + if (szCmd[i] == ',') + { + szNum = &szCmd[i+1]; + break; + } + if (i == strlen(szCmd)) + bError = 1; + else + { + uiLength = atoi(szNum); + + iStatus1 = ReadFromLog((unsigned char*) szResponse, uiLogIndex, uiLength); + iStatus2 = ReadLogFlags(&uiFlags, uiLogIndex); + if ( (iStatus1 < 0) || (iStatus2 < 0)) + bError = 1; + else + { + char szTemp[64]; + sprintf(szTemp, "LFR=1,%d,%d,%d,", (int) uiLogIndex, (int) uiFlags, (int) iStatus1); + memmove(&szResponse[strlen(szTemp)], szResponse, iStatus1); + memcpy(szResponse, szTemp, strlen(szTemp)); + retVal = strlen(szTemp) + iStatus1; + } + } + } + if (bError) + { + strcat(szResponse, "ERROR"); + retVal = strlen(szResponse); + } + + return retVal; +} + + +/***************************** + * CmdBMK() + * Benchmark a PI controller + * BMK + * + * (must have already send LM commands to setup the log) + * + * Response: BMK=num + * number of time the PI controller was called in 1 second. + *szCmd: the command + *szResponse: the response + */ +static int CmdBMK(const char * szCmd, char *szResponse, void *CommDevice) +{ + u32 started = MainTimerTimerTick; + u32 count = 0; + double input; + double output; + double abc[3], dq0[3]; + pi_controller cont; + controller_context io; + controller_holder ctxt; + io.ClockTime = 10; + io.NumClocks = 1; + cont.kits = 10.315; + cont.kp = 1.42; + cont.plusSat = 5.12; + cont.negSat = -100.91; + cont.lastInt = 0; + io.inputs = &input; + io.outputs = &output; + io.NumInputs = 1; + io.NumOutputs = 1; + io.Status = C_RUNNING; + ctxt.control_io = &io; + ctxt.controller_info = &cont; + while (MainTimerTimerTick - started < 100000) + { + /*input += 0.1; + if (input > cont.plusSat + 0.5) + input = cont.negSat; + RunPI_Controller(&ctxt);*/ + abc[0] = count/1000.0; + abc[1] = (double) MainTimerTimerTick/100000.0; + abc[2] = 3*abc[0]; + DQ0_Transform(((double) MainTimerTimerTick)/100000.0, abc, dq0); + count++; + } + + sprintf(szResponse, "BMK=%d", (int) count); + return strlen(szResponse); +} + + +/***************************** + * CmdLS() + * Handle the LS command. Start logging. + * LS + * + * (must have already send LM commands to setup the log) + * + * Response: OK + * --> only 100us errors are but response is padded to 10 fields + *szCmd: the command + *szResponse: the response + */ +static int CmdLS(const char * szCmd, char *szResponse, void *CommDevice) +{ + if (StartLogging() == SUCCESS) + strcat(szResponse, "OK"); + else + strcat(szResponse, "ERROR"); + + return strlen(szResponse); +} + +/***************************** + * CmdLFS() + * Handle the LFS command. Start logging and start sending unsolicited + * LFRs. + * LFS=max_packet_size (in bytes) + * + * (must have already sent LM commands to setup the log) + * + * Response: OK + *szCmd: the command + *szResponse: the response + */ +static int CmdLFS(const char * szCmd, char *szResponse, void *CommDevice) +{ + const char *szNum = &szCmd[4]; + u32 tempLen = 0; + + //get the log index number + tempLen = atoi(szNum); + + if ( (StartLogging() == SUCCESS) && (tempLen > 0) && (tempLen % 4 == 0)) + { + strcat(szResponse, "OK"); + StreamFIFO_SqnNum = 1; + StreamFIFO_MaxPacket = tempLen; + StreamFIFOComm = CommDevice; + bPrimeStreamFIFO = TRUE; + } + else + strcat(szResponse, "ERROR"); + + return strlen(szResponse); +} + +/***************************** + * CmdLFH() + * Handle the LFH command. Hault sending unsolicited LFRs + * LFH + * + * + * Response: OK + * --> only 100us errors are but response is padded to 10 fields + *szCmd: the command + *szResponse: the response + */ +static int CmdLFH(const char * szCmd, char *szResponse, void *CommDevice) +{ + StreamFIFOComm = 0; + bPrimeStreamFIFO = FALSE; + + StopAllLogging(); + strcat(szResponse, "OK"); + + return strlen(szResponse); +} + + + + +/***************************** + * CmdLM() + * Handle the LM command. Log a memory address + * LM=index,address,settings + * index: log file index (0 to MAX_LOG_VARS-1) + * Response: OK + * --> only 100us errors are but response is padded to 10 fields + *szCmd: the command + *szResponse: the response + */ +static int CmdLM(const char * szCmd, char *szResponse, void *CommDevice) +{ + const char *szNum = &szCmd[3]; + char bError = 0; + u32 uiLogIndex, uiAddr, uiSettings; + + //get the log index number + uiLogIndex = atoi(szNum); + + if ( uiLogIndex >= MAX_LOG_VARS ) + bError = 1; + else + { +//get the memory address + int i; + for (i = 0; i < strlen(szCmd); i++) + if (szCmd[i] == ',') + { + szNum = &szCmd[i+1]; + break; + } + if (i == strlen(szCmd)) + bError = 1; + else + { + uiAddr = atoi(szNum); + for (i++; i < strlen(szCmd); i++) + if (szCmd[i] == ',') + { + szNum = &szCmd[i+1]; + break; + } + if (i == strlen(szCmd)) + bError = 1; + else + { + uiSettings = atoi(szNum); + + if (SetupLogVariable(uiLogIndex, (u32 *) uiAddr, uiSettings) != SUCCESS) + bError = 1; + else + strcat(szResponse, "OK"); + } + } + } + if (bError) + strcat(szResponse, "ERROR"); + + return strlen(szResponse); +} + + +unsigned char HBA_bEnabled = 0; +u32 HBA_uiLeg1, HBA_uiLeg2; +double HBA_dbVPercent, HBA_dbOmega, HBA_dbTheta; + +/***************************** + * CmdHBA() + * Handle the 100uS tick for the ac HBridge function. + */ +void HBA_100usTick() +{ + //generate ac for Hbridge + if (HBA_bEnabled){ + u8 duty1, duty2; + double update_da = ((double) HBA_dbOmega/( (double) 10000)); + double dbVPercent; + HBA_dbTheta += update_da; + if (HBA_dbTheta > 6.283185307179586) + HBA_dbTheta -= 6.283185307179586; + + dbVPercent = HBA_dbVPercent*cos(HBA_dbTheta); + + duty1 = (unsigned char) 127*(1 + dbVPercent); + duty2 = (unsigned char) 127*(1 - dbVPercent); + + WriteDutyRatio(HBA_uiLeg1, duty1); + WriteDutyRatio(HBA_uiLeg2, duty2); + } +} + + +// Ramps between `current` and `setpoint` values assuming Fs = 10kHz +// Updates `current` as it ramps. +// +// `ramprate` is in (units of `current`) / sec +// 0 implies no ramp +// +// +// Returns delta in Ts for theta update +// +double omega_ramp_fcn(double *current, double *setpoint, double ramprate) +{ + double ret; + + if (ramprate != 0 && *current != *setpoint) { + // Ramping + double dir = (*setpoint > *current) ? 1 : -1; + double del = ramprate / 10000.0; + + *current += (dir * del); + ret = *current / 10000.0; + + // Check if done ramping + if ((dir == 1) && (*current > *setpoint)) *current = *setpoint; + if ((dir == -1) && (*current < *setpoint)) *current = *setpoint; + } else { + // Not ramping + ret = *setpoint / 10000.0; + } + + return ret; +} + +uint8_t VSI_enabled = 0; +uint8_t VSI_leg1; +uint8_t VSI_leg2; +uint8_t VSI_leg3; +double VSI_Vpercent = 0; +double VSI_omega = 0; +double theta = 0; + +double VSI_omega_ramp = 0; +double VSI_old_Vpercent = 0; +double VSI_old_omega = 0; + +double VSI_R; +double VSI_V0; + +/***************************** + * CmdVSI() + * Handle the 100uS tick for the VSI function. + */ +void VSI_100usTick(void) +{ + if (VSI_enabled) { +// uint8_t duty1, duty2, duty3; + + // Calculate `da` + double update_da = omega_ramp_fcn(&VSI_old_omega, &VSI_omega, VSI_omega_ramp); + + // Calculate dv + // ramp(&VSI_old_Vpercent, &VSI_Vpercent, 0.1); + + theta += update_da; + if (theta > 6.283185307179586) + theta -= 6.283185307179586; + + double v = (VSI_R * VSI_old_omega) + VSI_V0; + + double percent1 = v*cos(theta); + double percent2 = v*cos(theta - PI23); + double percent3 = v*cos(theta + PI23); + +// duty1 = (unsigned char) 127*(1 + percent1); +// duty2 = (unsigned char) 127*(1 + percent2); +// duty3 = (unsigned char) 127*(1 + percent3); + + pwm_set_duty(VSI_leg1 - 1, (1 + percent1) / 2.0); + pwm_set_duty(VSI_leg2 - 1, (1 + percent2) / 2.0); + pwm_set_duty(VSI_leg3 - 1, (1 + percent3) / 2.0); + +// WriteDutyRatio(VSI_leg1, duty1); +// WriteDutyRatio(VSI_leg2, duty2); +// WriteDutyRatio(VSI_leg3, duty3); + } else { + WriteDutyRatio(VSI_leg1, 0); + WriteDutyRatio(VSI_leg2, 0); + WriteDutyRatio(VSI_leg3, 0); + } +} + + +/***************************** + * CmdHBA() + * Handle the HBA command. Make an HBridge from two legs and + * output the specified voltage as a sine wave varying from 0 + * to the peak value specified + * HBV=leg1,leg2,voltage,omega + * leg1: number of leg 1 (1 to NUM_LEGS) + * leg2: number of leg 2 (1 to NUM_LEGS) + * voltage: percent of bus voltage (0 to 100) + * omega: 0 to 2*pi*10000, specified as an integer which must + * be divided by 128 + * Response: OK + *szCmd: the command + *szResponse: the response + */ +static int CmdHBA(const char * szCmd, char *szResponse, void *CommDevice) +{ + const char *szNum = &szCmd[4]; + char bError = 0; + u32 uiLeg1, uiLeg2, uiVoltagePercent; + +//get the leg 1 number + uiLeg1 = atoi(szNum); + + if ( (uiLeg1 > NUM_LEGS) || (uiLeg1 == 0) ) + bError = 1; + else + { +//get the leg 2 number + int i; + for (i = 0; i < strlen(szCmd); i++) + if (szCmd[i] == ',') + { + szNum = &szCmd[i+1]; + break; + } + if (i == strlen(szCmd)) + bError = 1; + else + { + uiLeg2 = atoi(szNum); + if ( (uiLeg2 > NUM_LEGS) || (uiLeg2 == 0) ) + bError = 1; + else + { + for (i++; i < strlen(szCmd); i++) + if (szCmd[i] == ',') + { + szNum = &szCmd[i+1]; + break; + } + if (i == strlen(szCmd)) + bError = 1; + else + { + double dbVPercent; + uiVoltagePercent = atoi(szNum); + dbVPercent = ((double) uiVoltagePercent)/100; + + for (i++; i < strlen(szCmd); i++) + if (szCmd[i] == ',') + { + szNum = &szCmd[i+1]; + break; + } + if (i == strlen(szCmd)) + bError = 1; + else + { + HBA_dbOmega = ((double) atoi(szNum)) / ((double) 128); + HBA_dbVPercent = dbVPercent; + HBA_uiLeg1 = uiLeg1; + HBA_uiLeg2 = uiLeg2; + HBA_bEnabled = 1; + strcat(szResponse, "OK"); + } + } + } + } + } + if (bError) + strcat(szResponse, "ERROR"); + + return strlen(szResponse); +} + +/***************************** + * CmdHBV() + * Handle the HBV command. Make an HBridge from two legs and + * output the specified voltage + * HBV=leg1,leg2,voltage + * leg1: number of leg 1 (1 to NUM_LEGS) + * leg2: number of leg 2 (1 to NUM_LEGS) + * voltage: percent of bus voltage (0 to 100) + * Response: OK + *szCmd: the command + *szResponse: the response + */ +static int CmdHBV(const char * szCmd, char *szResponse, void *CommDevice) +{ + const char *szNum = &szCmd[4]; + char bError = 0; + u32 uiLeg1, uiLeg2, uiVoltagePercent; + +//get the leg 1 number + uiLeg1 = atoi(szNum); + + if ( (uiLeg1 > NUM_LEGS) || (uiLeg1 == 0) ) + bError = 1; + else + { +//get the leg 2 number + int i; + for (i = 0; i < strlen(szCmd); i++) + if (szCmd[i] == ',') + { + szNum = &szCmd[i+1]; + break; + } + if (i == strlen(szCmd)) + bError = 1; + else + { + uiLeg2 = atoi(szNum); + if ( (uiLeg2 > NUM_LEGS) || (uiLeg2 == 0) ) + bError = 1; + else + { + for (i++; i < strlen(szCmd); i++) + if (szCmd[i] == ',') + { + szNum = &szCmd[i+1]; + break; + } + if (i == strlen(szCmd)) + bError = 1; + else + { + double dbVPercent; + u8 duty1, duty2; + uiVoltagePercent = atoi(szNum); + dbVPercent = ((double) uiVoltagePercent)/100; + duty1 = (unsigned char) 127*(1 + dbVPercent); + duty2 = (unsigned char) 127*(1 - dbVPercent); + + WriteDutyRatio(uiLeg1, duty1); + WriteDutyRatio(uiLeg2, duty2); + strcat(szResponse, "OK"); + } + } + } + } + if (bError) + strcat(szResponse, "ERROR"); + + return strlen(szResponse); +} + + +/***************************** + * CmdReadADC() + * Handle the RADC command + * RADCn - n is adc number (1 - 12) + * Response: RADCn=xx.xxxxV + *szCmd: the command + *szResponse: the response + */ +static int CmdReadADC(const char * szCmd, char *szResponse, void *CommDevice) +{ + const char *szADCnum = &szCmd[4]; + double dbADC = 0; + u32 uiADCnum = atoi(szADCnum); + if ( (uiADCnum > 0) && (uiADCnum < 13) ) + { + dbADC = ReadADC(uiADCnum); + sprintf(szResponse, "ADC%d=%2.4fV", (int)uiADCnum,dbADC); //reads +-10V, accurate to 0.0049V + } + else + strcpy(szResponse, "ERROR"); + + return strlen(szResponse); +} + +/***************************** + * CmdTCE() + * Handle the TCE command. Clear timing errors. + * RTE + * Response: OK + * --> only 100us errors are but response is padded to 10 fields + *szCmd: the command + *szResponse: the response + */ +static int CmdTCE(const char * szCmd, char *szResponse, void *CommDevice) +{ + Timing10usErrorCount = 0; + Timing100usErrorCount = 0; + ControlTimer0ErrorCount = 0; + ControlTimer1ErrorCount = 0; + strcpy(szResponse, "OK"); + + return strlen(szResponse); +} + + +/***************************** + * CmdTRT() + * Handle the TRT command. Read timing ticks. + * RTE + * Response: TRT=main,control0,control1,,,,,,, + * --> only first 3 are defined but response is padded to 10 fields + *szCmd: the command + *szResponse: the response + */ +static int CmdTRT(const char * szCmd, char *szResponse, void *CommDevice) +{ + /*u32 TimerCount1 = XTmrCtr_ReadReg(0x42800000, + TIMER_CNTR_0, XTC_TCR_OFFSET);*/ + + sprintf(szResponse, "TRT=%d,%d,%d,,,,,,,", (int) MainTimerTimerTick, (int) ControlTimer0_TickCount, (int) ControlTimer1_TickCount); + + return strlen(szResponse); +} + +/***************************** + * CmdPRE() + * Handle the PRE command. Read PECB databus errors. + * RTE + * Response: PRE=ToPECB,FromPECB + *szCmd: the command + *szResponse: the response + */ +static int CmdPRE(const char * szCmd, char *szResponse, void *CommDevice) +{ + /*u32 TimerCount1 = XTmrCtr_ReadReg(0x42800000, + TIMER_CNTR_0, XTC_TCR_OFFSET);*/ + u32 ec_to_dev, ec_from_dev; + ec_to_dev = PECB[ER_CNT] & 0xFFFF; + ec_from_dev = (PECB[ER_CNT] >> 16) & 0xFFFF; + sprintf(szResponse, "TRE=%d,%d,%d,%d", (int) ec_to_dev, (int) ec_from_dev, (int) PECB[ER_CNT-1], (int) PECB[ER_CNT-2]); + + return strlen(szResponse); +} + + +/***************************** + * CmdTRE() + * Handle the TRE command. Read timing errors. + * RTE + * Response: TRE=10us,100us,,,,,,,, + * --> only 10us, 100us errors are but response is padded to 10 fields + *szCmd: the command + *szResponse: the response + */ +static int CmdTRE(const char * szCmd, char *szResponse, void *CommDevice) +{ + /*u32 TimerCount1 = XTmrCtr_ReadReg(0x42800000, + TIMER_CNTR_0, XTC_TCR_OFFSET);*/ + + sprintf(szResponse, "TRE=%d,%d,%d,%d,,,,,,", (int) Timing10usErrorCount, (int) Timing100usErrorCount, (int) ControlTimer0ErrorCount, (int) ControlTimer1ErrorCount); + + return strlen(szResponse); +} + + +/***************************** + * CmdCFG() + * Handle the CFG command. Write setting to config register. + * CFG=d + * --> d: (0 to 255) + *szCmd: the command + *szResponse: the response + */ +static int CmdCFG(const char * szCmd, char *szResponse, void *CommDevice) +{ + const char *szNum = &szCmd[4]; + char bError = 0; + u32 uiValue; + if ( (szNum[0] < 0x30) || (szNum[0] > 0x39) ) + bError = 1; + else + { +//get the value + uiValue = atoi(szNum); + WriteConfigRegister((u8) uiValue); + sprintf(szResponse, "OK"); + } + if (bError) + strcpy(szResponse, "ERROR"); + + return strlen(szResponse); +} + + +/***************************** + * CmdWD() + * Handle the WD command. Write duty ratio. + * WDn=d + * --> n: duty ratio register to write to + * --> d: (0 to 255) + *szCmd: the command + *szResponse: the response + */ +static int CmdWD(const char * szCmd, char *szResponse, void *CommDevice) +{ + const char *szNum = &szCmd[2]; + char bError = 0; + u32 uiLeg, uiValue; + if ( (szNum[0] < 0x31) ) + bError = 1; + else + { +//get the leg number + uiLeg = atoi(szNum); + + if ( (uiLeg < 1) || (uiLeg > NUM_LEGS) ) + bError = 1; + else + { +//get new duty ratio + int i; + for (i = 0; i < strlen(szCmd); i++) + if (szCmd[i] == '=') + { + szNum = &szCmd[i+1]; + break; + } + if (i == strlen(szCmd)) + bError = 1; + else + { + uiValue = atoi(szNum); + if (uiValue > 255) + bError = 1; + else + { + WriteDutyRatio(uiLeg, (unsigned char) uiValue); + sprintf(szResponse, "OK"); + } + } + } + } + if (bError) + strcpy(szResponse, "ERROR"); + + return strlen(szResponse); +} + + +/***************************** + * CmdCNT() + * Handle the CNT command. Send a control application a command. + * CNT=d,CMD + * --> n: which control application to send the command to (number) + * --> CMD: The command to send + *szCmd: the command + *szResponse: the response + */ +static int CmdCNT(const char * szCmd, char *szResponse, void *CommDevice) +{ + const char *szAppCMD = &szCmd[4]; + + u32 uiApp; + { +//get the control application to send to + uiApp = atoi(szAppCMD); + + if ( uiApp >= 1) //|| (uiLeg > NUM_LEGS) ) + { +//get new duty ratio + int i; + for (i = 0; i < strlen(szCmd); i++) + if (szCmd[i] == ',') + { + szAppCMD = &szCmd[i+1]; + break; + } + if (i != strlen(szCmd)) + { + if (uiApp == 1) + return ControlAppCommand(szAppCMD, szResponse, CommDevice); + else if (uiApp == 2) + return TorqueVSI_Command(szAppCMD, szResponse, CommDevice); + } + } + } + strcpy(szResponse, "ERROR"); + + return strlen(szResponse); +} + + +/***************************** + * CmdCTT() + * Handle the CTT command. Start a control application with a command. + * CTT=n,CMD + * --> n: which control application to start (number) + * --> CMD: The start command to send + *szCmd: the command + *szResponse: the response + */ +static int CmdCTT(const char * szCmd, char *szResponse, void *CommDevice) +{ + const char *szAppCMD = &szCmd[4]; + + u32 uiApp; + { +//get the control application to send to + uiApp = atoi(szAppCMD); + + if ( uiApp >= 1) //|| (uiLeg > NUM_LEGS) ) + { +//get new duty ratio + int i; + for (i = 0; i < strlen(szCmd); i++) + if (szCmd[i] == ',') + { + szAppCMD = &szCmd[i+1]; + break; + } + if (i != strlen(szCmd)) + { + if (uiApp == 1) + return ControlStopAppCommand(szAppCMD, szResponse, CommDevice); + else if (uiApp == 2) + return TorqueVSI_StopCommand(szAppCMD, szResponse, CommDevice); + } + } + } + strcpy(szResponse, "ERROR"); + + return strlen(szResponse); +} + +/***************************** + * CmdCST() + * Handle the CST command. Start a control application with a command. + * CST=n,CMD + * --> n: which control application to start (number) + * --> CMD: The start command to send + *szCmd: the command + *szResponse: the response + */ +static int CmdCST(const char * szCmd, char *szResponse, void *CommDevice) +{ + const char *szAppCMD = &szCmd[4]; + + u32 uiApp; + { +//get the control application to send to + uiApp = atoi(szAppCMD); + + if ( uiApp >= 1) //|| (uiLeg > NUM_LEGS) ) + { +//get new duty ratio + int i; + for (i = 0; i < strlen(szCmd); i++) + if (szCmd[i] == ',') + { + szAppCMD = &szCmd[i+1]; + break; + } + if (i != strlen(szCmd)) + { + if (uiApp == 1) + return ControlStartAppCommand(szAppCMD, szResponse, CommDevice); + else if (uiApp == 2) + return TorqueVSI_StartCommand(szAppCMD, szResponse, CommDevice); + } + } + } + strcpy(szResponse, "ERROR"); + + return strlen(szResponse); +} + +/***************************** + * CmdVSL() + * Handle the VSL command. + * + * VSL=leg1,leg2,leg3 + * + * leg1: number of leg 1 (1 to NUM_LEGS) + * leg2: number of leg 2 (1 to NUM_LEGS) + * leg3: number of leg 3 (1 to NUM_LEGS) + * + * Response: OK + * + *szCmd: the command + *szResponse: the response + */ + +static char bufferVSL[128]; +static int CmdVSL(const char * szCmd, char *szResponse, void *CommDevice) +{ + char *p; + int i = 0; + + // Create copy of cmd for parsing + memset(bufferVSL, 0, 128); + strcpy(bufferVSL, szCmd); + + // Parse out tokens + int iLeg1 = 0; + int iLeg2 = 0; + int iLeg3 = 0; + + p = strtok(bufferVSL, "=,"); + while (p != NULL) { + // Use current token... + switch (i) { + case 0: + // Ignore 'VSL' + break; + case 1: + iLeg1 = atoi(p); + break; + case 2: + iLeg2 = atoi(p); + break; + case 3: + iLeg3 = atoi(p); + break; + default: + // This is an error! + // Force error below + iLeg1 = 0; + iLeg2 = 1; + iLeg3 = 1; + break; + } + + // Get next token + p = strtok(NULL, "=,"); + i++; + } + + // Check if all 0 => disable VSI + if (iLeg1 == 0 && iLeg2 == 0 && iLeg3 == 0) { + VSI_enabled = 0; + strcat(szResponse, "OK"); + return strlen(szResponse); + } + + // Check if errors in leg numbers + int bError = 0; + if (iLeg1 <= 0 || iLeg1 > NUM_LEGS) bError = 1; + if (iLeg2 <= 0 || iLeg2 > NUM_LEGS) bError = 1; + if (iLeg3 <= 0 || iLeg3 > NUM_LEGS) bError = 1; + + if (bError) { + strcat(szResponse, "ERROR"); + return strlen(szResponse); + } + + // Set legs for VSI + VSI_leg1 = iLeg1; + VSI_leg2 = iLeg2; + VSI_leg3 = iLeg3; + + // Enable VSI + VSI_enabled = 1; + + strcat(szResponse, "OK"); + return strlen(szResponse); +} + + +/***************************** + * CmdVSI() + * Handle the VSI command. + * + * VSI=voltage,freq(,ramp) + * + * voltage: peak voltage output percent of Vbus (0 to 100) + * freq: frequency of output (Hz) + * ramptime: (optional) duration of ramping (ms) + * + * Response: OK + * + *szCmd: the command + *szResponse: the response + */ + +static char bufferVSI[128]; +static int CmdVSI(const char * szCmd, char *szResponse, void *CommDevice) +{ + char *p; + int i = 0; + + // Create copy of cmd for parsing + memset(bufferVSI, 0, 128); + strcpy(bufferVSI, szCmd); + + // Parse out tokens + int iVoltagePercent = 0; + int iHz = 0; + int iRamptime = 0; + + p = strtok(bufferVSI, "=,"); + while (p != NULL) { + // Use current token... + switch (i) { + case 0: + // Ignore 'VSI' + break; + case 1: + iVoltagePercent = atoi(p); + break; + case 2: + iHz = atoi(p); + break; + case 3: + iRamptime = atoi(p); + break; + default: + // This is an error! + // Force error below + iHz = 0; + break; + } + + // Get next token + p = strtok(NULL, "=,"); + i++; + } + + // Check for errors while parsing +// if (iHz == 0 || iVoltagePercent == 0) { +// strcat(szResponse, "ERROR"); +// return strlen(szResponse); +// } + + // Convert voltage percent input to double percentage + VSI_old_Vpercent = VSI_Vpercent; + VSI_Vpercent = iVoltagePercent / 100.0; + if (VSI_Vpercent > 100) VSI_Vpercent = 100.0; + if (VSI_Vpercent < 0) VSI_Vpercent = 0.0; + + + // Convert freq input to rad/sec + VSI_old_omega = VSI_omega; + VSI_omega = 2 * PI * iHz; + + if (iRamptime > 0) { + VSI_omega_ramp = abs(VSI_old_omega - VSI_omega) / (iRamptime / 1000.0); // (rad/sec) / sec + } else { + VSI_omega_ramp = 0; + } + + + if (VSI_omega != VSI_old_omega) { + // There is delta freq requested + VSI_R = (VSI_Vpercent - VSI_old_Vpercent) / (VSI_omega - VSI_old_omega); + VSI_V0 = VSI_Vpercent - (VSI_R * VSI_omega); + } else { + // Instaneous voltage change + VSI_R = 0; + VSI_V0 = VSI_Vpercent; + } + + strcat(szResponse, "OK"); + return strlen(szResponse); +} + +static char bufferFSW[128]; +static int CmdFSW(const char * szCmd, char *szResponse, void *CommDevice) +{ + char *p; + int i = 0; + + // Create copy of cmd for parsing + memset(bufferFSW, 0, 128); + strcpy(bufferFSW, szCmd); + + // Parse out tokens + int iHz = 0; + + p = strtok(bufferFSW, "=,"); + while (p != NULL) { + // Use current token... + switch (i) { + case 0: + // Ignore 'FSW' + break; + case 1: + iHz = atoi(p); + break; + default: + // This is an error! + // Force error below + iHz = 0; + break; + } + + // Get next token + p = strtok(NULL, "=,"); + i++; + } + + // Check for errors while parsing + if (iHz < 100 || iHz > 4000000) { + strcat(szResponse, "ERROR"); + return strlen(szResponse); + } + + // do work + pwm_set_switching_freq((double) iHz); + + strcat(szResponse, "OK"); + return strlen(szResponse); +} + + + +static char bufferDEA[128]; +static int CmdDEA(const char * szCmd, char *szResponse, void *CommDevice) +{ + char *p; + int i = 0; + + // Create copy of cmd for parsing + memset(bufferDEA, 0, 128); + strcpy(bufferDEA, szCmd); + + // Parse out tokens + int iNs = 0; + + p = strtok(bufferDEA, "=,"); + while (p != NULL) { + // Use current token... + switch (i) { + case 0: + // Ignore 'DEA' + break; + case 1: + iNs = atoi(p); + break; + default: + // This is an error! + // Force error below + iNs = 0; + break; + } + + // Get next token + p = strtok(NULL, "=,"); + i++; + } + + // Check for errors while parsing + if (iNs < 25 || iNs > 1e9) { + strcat(szResponse, "ERROR"); + return strlen(szResponse); + } + + // do work + pwm_set_deadtime_ns(iNs); + + strcat(szResponse, "OK"); + return strlen(szResponse); +} + + + + + + + +//call this with the CR removed +//load the response into szResponse +int CommandParser(const char * szCmd, char *szResponse, void *CommDevice) +{ + char szTemp[256]; + int retVal = 0; + //read ADC + int i; + char bFoundCmd = 0; + szResponse[0] = 0; //put a leading null in to prevent any issues + for (i = 0; i 0) + { + szSendCmd[newLen++] = '\r'; + szSendCmd[newLen++] = '\n'; + outLen += newLen + 2; + } + } + else if (cRcvd[0] != '\n') //ignore line feeds + { + szRcvCmd[*state] = cRcvd[0]; + *state += 1; + szRcvCmd[*state] = 0; //always null terminate + + //strcat(szRcvCmd, cRcvd); + } + } + return outLen; +} diff --git a/sdk/basic/src/commands.h b/sdk/basic/src/commands.h old mode 100755 new mode 100644 index bdd47529..3c6cdd5e --- a/sdk/basic/src/commands.h +++ b/sdk/basic/src/commands.h @@ -1,20 +1,20 @@ -#ifndef __COMMANDS_H -#define __COMMANDS_H - -extern void *StreamFIFOComm; -extern u32 StreamFIFO_MaxPacket; -extern char bPrimeStreamFIFO; //set this to true if the streaming FIFO needs to be loaded from the main loop (instead of the callback) - -extern int MakeMostFullLFR(char *szResponse, u32 uiMaxLength, u32 *SQnum); -extern int ReloadStreamFIFO(void * comm); - -extern int CommandParser(const char * szCmd, char *szResponse, void *CommDevice); -extern u32 HandleCommandsUart(char *szRcvCmd, u32 state); - -extern u32 HandleCommandsGeneral(char *szOutData, char *szRcvCmd, char *szNewData, u32 NewDataLength, u32 *state, void *ComDevice); - -extern void HBA_100usTick(); -extern void VSI_100usTick(void); -#endif //__COMMANDS_H - - +#ifndef __COMMANDS_H +#define __COMMANDS_H + +extern void *StreamFIFOComm; +extern u32 StreamFIFO_MaxPacket; +extern char bPrimeStreamFIFO; //set this to true if the streaming FIFO needs to be loaded from the main loop (instead of the callback) + +extern int MakeMostFullLFR(char *szResponse, u32 uiMaxLength, u32 *SQnum); +extern int ReloadStreamFIFO(void * comm); + +extern int CommandParser(const char * szCmd, char *szResponse, void *CommDevice); +extern u32 HandleCommandsUart(char *szRcvCmd, u32 state); + +extern u32 HandleCommandsGeneral(char *szOutData, char *szRcvCmd, char *szNewData, u32 NewDataLength, u32 *state, void *ComDevice); + +extern void HBA_100usTick(); +extern void VSI_100usTick(void); +#endif //__COMMANDS_H + + diff --git a/sdk/basic/src/control.c b/sdk/basic/src/control.c old mode 100755 new mode 100644 index e3970197..d4bacbdd --- a/sdk/basic/src/control.c +++ b/sdk/basic/src/control.c @@ -1,340 +1,340 @@ -/* - * control.c - * - * Created on: Jun 24, 2014 - * Author: sever212 - */ - -#include "project_include.h" - -/*4294947296 for 10kHz*/ -/*4294957296 for 20kHz*/ -#define TIMER0_TICK_FREQ 20000 -#define TIMER0_RESET_VAL ((0xFFFFFFFF-XPAR_CONTROL_TIMER_0_CLOCK_FREQ_HZ/TIMER0_TICK_FREQ) + 1) //4294957296 //32bit counter, 100MHz clock, time = (0x1_0000_0000-RESET_VALUE)/200e6 --> RESET_VALUE = 4294967296 - time*200e6 - //I don't know why the clock is 200MHz, maybe it is clocked from the AXI clock? - -#define TIMER1_TICK_FREQ 1000 -#define TIMER1_RESET_VAL ((0xFFFFFFFF-XPAR_CONTROL_TIMER_1_CLOCK_FREQ_HZ/TIMER1_TICK_FREQ) + 1) //4294957296 //32bit counter, 100MHz clock, time = (0x1_0000_0000-RESET_VALUE)/200e6 --> RESET_VALUE = 4294967296 - time*200e6 - //I don't know why the clock is 200MHz, maybe it is clocked from the AXI clock? - - -#define AXI_TIMER0_PRIORITY 0xA8 //0xF8 is lowest priority, 0 is highest: READ THIS: actually if the priority's upper nibble is F, it doesn't work at all! -#define AXI_TIMER1_PRIORITY 0xA9 //0xF8 is lowest priority, 0 is highest: READ THIS: actually if the priority's upper nibble is F, it doesn't work at all! - - -#define TMRCTR0_INTERRUPT_ID 61 //I don't know why, but it won't recognize these XPAR_FABRIC_AXI_TIMER_0_INTERRUPT_INTR -#define TMRCTR1_INTERRUPT_ID 62 //XPAR_FABRIC_AXI_TIMER_1_INTERRUPT_INTR - -#define TMRCTR0_DEVICE_ID XPAR_TMRCTR_0_DEVICE_ID -#define TMRCTR1_DEVICE_ID XPAR_TMRCTR_1_DEVICE_ID - -#define TIMER_CNTR_0 0 -#define TIMER_CNTR_1 0 - -XTmrCtr TmrCtrInstance0; -XTmrCtr TmrCtrInstance1; -static void ControlTimer0_ISR(void *CallBackRef, u8 TmrCtrNumber); -static void ControlTimer1_ISR(void *CallBackRef, u8 TmrCtrNumber); -volatile u32 ControlTimer0_TickCount = 0; -volatile u32 ControlTimer1_TickCount = 0; - -volatile u32 ControlTimer0ErrorCount = 0; -volatile u32 ControlTimer1ErrorCount = 0; - -struct controller_linked_list_item *C0s = 0; //list of the PI controllers for controller 0 -//struct controller_linked_list_item *C0_PIDs = 0; //list of the PI controllers for controller 0 -struct controller_linked_list_item *C1s = 0; //list of the PI controllers for controller 0 -//struct controller_linked_list_item *C1_PIDs = 0; //list of the PI controllers for controller 0 - -/************************TIMERS************************/ -static int InitControlTimers(XScuGic* IntcInstancePtr) -{ - XTmrCtr *TmrCtrInstance0Ptr = &TmrCtrInstance0; - XTmrCtr *TmrCtrInstance1Ptr = &TmrCtrInstance1; - int Status; - - Status = Init_AXI_Timer(IntcInstancePtr, - TmrCtrInstance0Ptr, TMRCTR0_DEVICE_ID, TMRCTR0_INTERRUPT_ID, - TIMER_CNTR_0, ControlTimer0_ISR, AXI_TIMER0_PRIORITY, TIMER0_RESET_VAL); - if (Status != XST_SUCCESS) { - return XST_FAILURE; - } - - /*return Init_AXI_Timer(IntcInstancePtr, - TmrCtrInstance1Ptr, TMRCTR1_DEVICE_ID, TMRCTR1_INTERRUPT_ID, - TIMER_CNTR_1, ControlTimer1_ISR, AXI_TIMER1_PRIORITY, TIMER1_RESET_VAL);*/ - return XST_SUCCESS; - -} - -static void ServiceControllers(struct controller_linked_list_item *cnts) -{ - while(cnts) - { - struct controller_context *basic_cnt = cnts->context->control_io; - if (++(basic_cnt->clockCount) >= basic_cnt->NumClocks) - { - basic_cnt->clockCount = 0; - - //input callback - cnts->context->input_callback(cnts->context->arg_in, basic_cnt); - - //run the controller - switch(basic_cnt->Type) - { - case C_PI: - RunPI_Controller(cnts->context); - break; - case C_PID: - RunPID_Controller (cnts->context); - default: - //UNSUPPORTED! - break; - } - - //output callback - cnts->context->output_callback(cnts->context->arg_out, basic_cnt); - } - cnts = cnts->next; - //basic_cnt = ((struct pi_controller *)cnts->controller)->controller; - } -} - -u32 starve = 0; -volatile unsigned char currentlyInISR = 0; -u32 LastMainTickCount = 0; -static void ControlTimer0_ISR(void *CallBackRef, u8 TmrCtrNumber) { - XTmrCtr *InstancePtr = (XTmrCtr *)CallBackRef; - u32 ControlStatusReg = XTmrCtr_ReadReg(InstancePtr->BaseAddress, - TmrCtrNumber, XTC_TCSR_OFFSET); - //clear the interrupt - XTmrCtr_WriteReg(InstancePtr->BaseAddress, - TmrCtrNumber, - XTC_TCSR_OFFSET, - ControlStatusReg | - XTC_CSR_INT_OCCURED_MASK); - if (currentlyInISR) - ControlTimer0ErrorCount++; - else - { - - u32 startMainTicks = MainTimerTimerTick; - if (TimeElapsed10us(LastMainTickCount) > 6) - ControlTimer0ErrorCount++; - - LastMainTickCount = startMainTicks; - //u32 i; - ControlTimer0_TickCount++; - - currentlyInISR = 1; - Xil_EnableNestedInterrupts(); - - //do PIs: - ServiceControllers(C0s); - - /* - for (i=0; i 5) - { - ControlTimer0ErrorCount++; - starve = 0; - } - currentlyInISR = 0; - Xil_DisableNestedInterrupts(); - } -} - -static void ControlTimer1_ISR(void *CallBackRef, u8 TmrCtrNumber) { - - u32 startMainTicks = MainTimerTimerTick; - ControlTimer1_TickCount++; - //if (ControlTimer0_Count % 100000 == 0) - /*if (ControlTimer1_TickCount == 10000 ) - { - ControlTimer1_TickCount = 0; - print("10 second tick - CISR1\r\n"); - }*/ - if (TimeElapsed10us(startMainTicks) >= 10) - ControlTimer1ErrorCount++; -} -/*****************************************************/ - -static double SaturationBlock(double in, double sat_up, double sat_lower) -{ - if (in > sat_up) - in = sat_up; - else if (in < sat_lower) - in = sat_lower; - return in; -} - -static double BasicIntegrator(double in, double last, double sat_up, double sat_lower) -{ - return SaturationBlock(in + last, sat_up, sat_lower); -} - -int InitControllers(XScuGic* IntcInstancePtr) -{ - int Status = InitControlTimers(IntcInstancePtr); - - if (Status != XST_SUCCESS) { - return XST_FAILURE; - } - - return XST_SUCCESS; -} - -void RemoveLinkedListItem(struct controller_linked_list_item **list, struct controller_linked_list_item *item) -{ - if (*list) - { - struct controller_linked_list_item *head = *list; - while ( (head != item) && (head->next) ) - head = head->next; - - //okay, we either found our item or it isnt here: - if (head == item) - { - if (head->prev) - head->prev->next = item->next; - if (head->next) - head->next->prev = item->prev; - //update where the list points to - if (head == *list) - *list = head->next; - } - item->prev = 0; - item->next = 0; - item->bRegistered = FALSE; - } -} - -void AddLinkedListItem(struct controller_linked_list_item **list, struct controller_linked_list_item *item) -{ - if (*list) - { - struct controller_linked_list_item *head = *list; - while (head->next) - head = head->next; - - //okay, at the end - head->next = item; - item->prev = head; - item->next = 0; - } - else - { - *list = item; - (*list)->next = 0; - (*list)->prev = 0; - } - item->bRegistered = TRUE; -} - -int UnregisterController(int contNum, struct controller_linked_list_item *cnt) -{ - if (contNum == 0) - RemoveLinkedListItem(&C0s, cnt); - else if (contNum == 1) - RemoveLinkedListItem(&C1s, cnt); - else - return XST_FAILURE; - - return XST_SUCCESS; -} - -int RegisterController(int contNum, struct controller_linked_list_item *cnt) -{ - if (contNum == 0) - AddLinkedListItem(&C0s, cnt); - else if (contNum == 1) - AddLinkedListItem(&C1s, cnt); - else - return XST_FAILURE; - - return XST_SUCCESS; -} - -/***************************** - * RunPI_Controller() - * Do the computation for a pi controller - * - * - * - *pi: the pi controller context - */ -void RunPI_Controller (controller_holder* ctxt) -{ - struct pi_controller *pi = ctxt->controller_info; - struct controller_context *cont_io = ctxt->control_io; - double error = *cont_io->inputs; - double p = pi->kp*error; - //double kiTs = pi->ki* ((double)(cont_io->NumClocks*cont_io->ClockTime))*0.000001; - double i_in = pi->kits*error; - pi->lastInt = BasicIntegrator(i_in, pi->lastInt, pi->plusSat, pi->negSat); - *(cont_io->outputs) = pi->lastInt + p; //don't saturate output, just prevent windup //SaturationBlock(pi->lastInt + p, pi->plusSat, pi->negSat); - - //check for NaN (conditions with NaN are always false) - if (pi->lastInt != pi->lastInt) - pi->lastInt = 0; -} - -s32 PID_D, PID_I, PID_P, PID_LastD, PID_Err, PID_out; -/***************************** - * RunPID_Controller() - * Do the computation for our custom pid controller - * - * - * - *ctxt: the controller context - */ -void RunPID_Controller (controller_holder* ctxt) -{ - static int i = 0; - struct pid_controller *pid = ctxt->controller_info; - struct controller_context *cont_io = ctxt->control_io; - double error = *cont_io->inputs; - double p = pid->kp*error; - double i_in = pid->kits*error; - double d = pid->kdn*error + pid->kdn1*pid->lastErr + pid->kdm1*pid->lastD; - pid->lastInt = BasicIntegrator(i_in, pid->lastInt, pid->plusSat, pid->negSat); - pid->lastD = SaturationBlock(d, pid->plusSat, pid->negSat); //saturate to prevent windup - pid->lastErr = error; - - *(cont_io->outputs) = pid->lastInt + p + d; //don't saturate output, just prevent windup //SaturationBlock(pid->lastInt + p + d, pid->plusSat, pid->negSat); - //*(cont_io->outputs) = SaturationBlock(pid->lastInt + p + d, 10.0*pid->plusSat, 10.0*pid->negSat); - - //check for NaN (conditions with NaN are always false) - if (pid->lastInt != pid->lastInt) - pid->lastInt = 0; - if (pid->lastD != pid->lastD) - pid->lastD = 0; - if (pid->lastErr != pid->lastErr) - pid->lastErr = 0; - - //logging - if (i == 0) - { - PID_D = (s32) (128*d); - PID_I = (s32) (128*(pid->lastInt)); - PID_P = (s32) (128*p); - PID_LastD = (s32) (128*(pid->lastD)); - PID_Err = (s32) (512*(error)); - PID_out = (s32) (128*(*(cont_io->outputs))); - } - i++; - if (i == 4) - i = 0; -} - - +/* + * control.c + * + * Created on: Jun 24, 2014 + * Author: sever212 + */ + +#include "project_include.h" + +/*4294947296 for 10kHz*/ +/*4294957296 for 20kHz*/ +#define TIMER0_TICK_FREQ 20000 +#define TIMER0_RESET_VAL ((0xFFFFFFFF-XPAR_CONTROL_TIMER_0_CLOCK_FREQ_HZ/TIMER0_TICK_FREQ) + 1) //4294957296 //32bit counter, 100MHz clock, time = (0x1_0000_0000-RESET_VALUE)/200e6 --> RESET_VALUE = 4294967296 - time*200e6 + //I don't know why the clock is 200MHz, maybe it is clocked from the AXI clock? + +#define TIMER1_TICK_FREQ 1000 +#define TIMER1_RESET_VAL ((0xFFFFFFFF-XPAR_CONTROL_TIMER_1_CLOCK_FREQ_HZ/TIMER1_TICK_FREQ) + 1) //4294957296 //32bit counter, 100MHz clock, time = (0x1_0000_0000-RESET_VALUE)/200e6 --> RESET_VALUE = 4294967296 - time*200e6 + //I don't know why the clock is 200MHz, maybe it is clocked from the AXI clock? + + +#define AXI_TIMER0_PRIORITY 0xA8 //0xF8 is lowest priority, 0 is highest: READ THIS: actually if the priority's upper nibble is F, it doesn't work at all! +#define AXI_TIMER1_PRIORITY 0xA9 //0xF8 is lowest priority, 0 is highest: READ THIS: actually if the priority's upper nibble is F, it doesn't work at all! + + +#define TMRCTR0_INTERRUPT_ID 61 //I don't know why, but it won't recognize these XPAR_FABRIC_AXI_TIMER_0_INTERRUPT_INTR +#define TMRCTR1_INTERRUPT_ID 62 //XPAR_FABRIC_AXI_TIMER_1_INTERRUPT_INTR + +#define TMRCTR0_DEVICE_ID XPAR_TMRCTR_0_DEVICE_ID +#define TMRCTR1_DEVICE_ID XPAR_TMRCTR_1_DEVICE_ID + +#define TIMER_CNTR_0 0 +#define TIMER_CNTR_1 0 + +XTmrCtr TmrCtrInstance0; +XTmrCtr TmrCtrInstance1; +static void ControlTimer0_ISR(void *CallBackRef, u8 TmrCtrNumber); +static void ControlTimer1_ISR(void *CallBackRef, u8 TmrCtrNumber); +volatile u32 ControlTimer0_TickCount = 0; +volatile u32 ControlTimer1_TickCount = 0; + +volatile u32 ControlTimer0ErrorCount = 0; +volatile u32 ControlTimer1ErrorCount = 0; + +struct controller_linked_list_item *C0s = 0; //list of the PI controllers for controller 0 +//struct controller_linked_list_item *C0_PIDs = 0; //list of the PI controllers for controller 0 +struct controller_linked_list_item *C1s = 0; //list of the PI controllers for controller 0 +//struct controller_linked_list_item *C1_PIDs = 0; //list of the PI controllers for controller 0 + +/************************TIMERS************************/ +static int InitControlTimers(XScuGic* IntcInstancePtr) +{ + XTmrCtr *TmrCtrInstance0Ptr = &TmrCtrInstance0; + XTmrCtr *TmrCtrInstance1Ptr = &TmrCtrInstance1; + int Status; + + Status = Init_AXI_Timer(IntcInstancePtr, + TmrCtrInstance0Ptr, TMRCTR0_DEVICE_ID, TMRCTR0_INTERRUPT_ID, + TIMER_CNTR_0, ControlTimer0_ISR, AXI_TIMER0_PRIORITY, TIMER0_RESET_VAL); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /*return Init_AXI_Timer(IntcInstancePtr, + TmrCtrInstance1Ptr, TMRCTR1_DEVICE_ID, TMRCTR1_INTERRUPT_ID, + TIMER_CNTR_1, ControlTimer1_ISR, AXI_TIMER1_PRIORITY, TIMER1_RESET_VAL);*/ + return XST_SUCCESS; + +} + +static void ServiceControllers(struct controller_linked_list_item *cnts) +{ + while(cnts) + { + struct controller_context *basic_cnt = cnts->context->control_io; + if (++(basic_cnt->clockCount) >= basic_cnt->NumClocks) + { + basic_cnt->clockCount = 0; + + //input callback + cnts->context->input_callback(cnts->context->arg_in, basic_cnt); + + //run the controller + switch(basic_cnt->Type) + { + case C_PI: + RunPI_Controller(cnts->context); + break; + case C_PID: + RunPID_Controller (cnts->context); + default: + //UNSUPPORTED! + break; + } + + //output callback + cnts->context->output_callback(cnts->context->arg_out, basic_cnt); + } + cnts = cnts->next; + //basic_cnt = ((struct pi_controller *)cnts->controller)->controller; + } +} + +u32 starve = 0; +volatile unsigned char currentlyInISR = 0; +u32 LastMainTickCount = 0; +static void ControlTimer0_ISR(void *CallBackRef, u8 TmrCtrNumber) { + XTmrCtr *InstancePtr = (XTmrCtr *)CallBackRef; + u32 ControlStatusReg = XTmrCtr_ReadReg(InstancePtr->BaseAddress, + TmrCtrNumber, XTC_TCSR_OFFSET); + //clear the interrupt + XTmrCtr_WriteReg(InstancePtr->BaseAddress, + TmrCtrNumber, + XTC_TCSR_OFFSET, + ControlStatusReg | + XTC_CSR_INT_OCCURED_MASK); + if (currentlyInISR) + ControlTimer0ErrorCount++; + else + { + + u32 startMainTicks = MainTimerTimerTick; + if (TimeElapsed10us(LastMainTickCount) > 6) + ControlTimer0ErrorCount++; + + LastMainTickCount = startMainTicks; + //u32 i; + ControlTimer0_TickCount++; + + currentlyInISR = 1; + Xil_EnableNestedInterrupts(); + + //do PIs: + ServiceControllers(C0s); + + /* + for (i=0; i 5) + { + ControlTimer0ErrorCount++; + starve = 0; + } + currentlyInISR = 0; + Xil_DisableNestedInterrupts(); + } +} + +static void ControlTimer1_ISR(void *CallBackRef, u8 TmrCtrNumber) { + + u32 startMainTicks = MainTimerTimerTick; + ControlTimer1_TickCount++; + //if (ControlTimer0_Count % 100000 == 0) + /*if (ControlTimer1_TickCount == 10000 ) + { + ControlTimer1_TickCount = 0; + print("10 second tick - CISR1\r\n"); + }*/ + if (TimeElapsed10us(startMainTicks) >= 10) + ControlTimer1ErrorCount++; +} +/*****************************************************/ + +static double SaturationBlock(double in, double sat_up, double sat_lower) +{ + if (in > sat_up) + in = sat_up; + else if (in < sat_lower) + in = sat_lower; + return in; +} + +static double BasicIntegrator(double in, double last, double sat_up, double sat_lower) +{ + return SaturationBlock(in + last, sat_up, sat_lower); +} + +int InitControllers(XScuGic* IntcInstancePtr) +{ + int Status = InitControlTimers(IntcInstancePtr); + + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +void RemoveLinkedListItem(struct controller_linked_list_item **list, struct controller_linked_list_item *item) +{ + if (*list) + { + struct controller_linked_list_item *head = *list; + while ( (head != item) && (head->next) ) + head = head->next; + + //okay, we either found our item or it isnt here: + if (head == item) + { + if (head->prev) + head->prev->next = item->next; + if (head->next) + head->next->prev = item->prev; + //update where the list points to + if (head == *list) + *list = head->next; + } + item->prev = 0; + item->next = 0; + item->bRegistered = FALSE; + } +} + +void AddLinkedListItem(struct controller_linked_list_item **list, struct controller_linked_list_item *item) +{ + if (*list) + { + struct controller_linked_list_item *head = *list; + while (head->next) + head = head->next; + + //okay, at the end + head->next = item; + item->prev = head; + item->next = 0; + } + else + { + *list = item; + (*list)->next = 0; + (*list)->prev = 0; + } + item->bRegistered = TRUE; +} + +int UnregisterController(int contNum, struct controller_linked_list_item *cnt) +{ + if (contNum == 0) + RemoveLinkedListItem(&C0s, cnt); + else if (contNum == 1) + RemoveLinkedListItem(&C1s, cnt); + else + return XST_FAILURE; + + return XST_SUCCESS; +} + +int RegisterController(int contNum, struct controller_linked_list_item *cnt) +{ + if (contNum == 0) + AddLinkedListItem(&C0s, cnt); + else if (contNum == 1) + AddLinkedListItem(&C1s, cnt); + else + return XST_FAILURE; + + return XST_SUCCESS; +} + +/***************************** + * RunPI_Controller() + * Do the computation for a pi controller + * + * + * + *pi: the pi controller context + */ +void RunPI_Controller (controller_holder* ctxt) +{ + struct pi_controller *pi = ctxt->controller_info; + struct controller_context *cont_io = ctxt->control_io; + double error = *cont_io->inputs; + double p = pi->kp*error; + //double kiTs = pi->ki* ((double)(cont_io->NumClocks*cont_io->ClockTime))*0.000001; + double i_in = pi->kits*error; + pi->lastInt = BasicIntegrator(i_in, pi->lastInt, pi->plusSat, pi->negSat); + *(cont_io->outputs) = pi->lastInt + p; //don't saturate output, just prevent windup //SaturationBlock(pi->lastInt + p, pi->plusSat, pi->negSat); + + //check for NaN (conditions with NaN are always false) + if (pi->lastInt != pi->lastInt) + pi->lastInt = 0; +} + +s32 PID_D, PID_I, PID_P, PID_LastD, PID_Err, PID_out; +/***************************** + * RunPID_Controller() + * Do the computation for our custom pid controller + * + * + * + *ctxt: the controller context + */ +void RunPID_Controller (controller_holder* ctxt) +{ + static int i = 0; + struct pid_controller *pid = ctxt->controller_info; + struct controller_context *cont_io = ctxt->control_io; + double error = *cont_io->inputs; + double p = pid->kp*error; + double i_in = pid->kits*error; + double d = pid->kdn*error + pid->kdn1*pid->lastErr + pid->kdm1*pid->lastD; + pid->lastInt = BasicIntegrator(i_in, pid->lastInt, pid->plusSat, pid->negSat); + pid->lastD = SaturationBlock(d, pid->plusSat, pid->negSat); //saturate to prevent windup + pid->lastErr = error; + + *(cont_io->outputs) = pid->lastInt + p + d; //don't saturate output, just prevent windup //SaturationBlock(pid->lastInt + p + d, pid->plusSat, pid->negSat); + //*(cont_io->outputs) = SaturationBlock(pid->lastInt + p + d, 10.0*pid->plusSat, 10.0*pid->negSat); + + //check for NaN (conditions with NaN are always false) + if (pid->lastInt != pid->lastInt) + pid->lastInt = 0; + if (pid->lastD != pid->lastD) + pid->lastD = 0; + if (pid->lastErr != pid->lastErr) + pid->lastErr = 0; + + //logging + if (i == 0) + { + PID_D = (s32) (128*d); + PID_I = (s32) (128*(pid->lastInt)); + PID_P = (s32) (128*p); + PID_LastD = (s32) (128*(pid->lastD)); + PID_Err = (s32) (512*(error)); + PID_out = (s32) (128*(*(cont_io->outputs))); + } + i++; + if (i == 4) + i = 0; +} + + diff --git a/sdk/basic/src/control.h b/sdk/basic/src/control.h old mode 100755 new mode 100644 index d677acf4..f6916370 --- a/sdk/basic/src/control.h +++ b/sdk/basic/src/control.h @@ -1,77 +1,77 @@ -/* - * control.h - * - * Created on: Jun 24, 2014 - * Author: sever212 - */ - -#ifndef CONTROL_H_ -#define CONTROL_H_ - -typedef enum {C_IDLE, C_READY, C_RUNNING} controller_status; -typedef enum {C_PI, C_PID} controller_type; - -typedef struct controller_context{ - double *inputs; //reference - measured value of quantity being controlled - double *outputs; //output of the pi controller - u32 NumInputs; //number of inputs - u32 NumOutputs; //number of outputs - controller_status Status; //the status of the controller - u32 NumClocks; //run this controller every NumClocks count (1 for every time) - u32 ClockTime; //duration (in microseconds) of a clock edge - u32 clockCount; //current clock count - controller_type Type; //the type of controller (PI, PID) -} controller_context; - -typedef void (*get_controller_inputs)(void *arg, struct controller_context *cnt); -typedef void (*take_controller_output)(void *arg, struct controller_context *cnt); - -typedef struct pid_controller{ - double kp; //proportional gain - double kits; //integral gain * sample time - double kdn; //derivative gain for current error: derivative difference EQ: D = kdn*E[n] + kdn1*E[n-1] + kdm1*D[n-1] - double kdn1; //derivative gain for previous error - double kdm1; //derivative gain for previous derivative - double lastInt; //value of last integral - double lastErr; //value of the last error - double lastD; //value of the last derivative output - double plusSat; //positive integral saturation limit - double negSat; //negative integral saturation limit -} pid_controller; - -typedef struct pi_controller{ - double kp; //proportional gain - double kits; //integral gain * sample time - double lastInt; //value of last integral - double plusSat; //positive integral saturation limit - double negSat; //negative integral saturation limit -} pi_controller; - -typedef struct controller_holder{ - void *controller_info; //specific to the type of controller - struct controller_context *control_io; //the io of the controller (general to all controllers) - get_controller_inputs input_callback; //function to call to get measured and reference values - take_controller_output output_callback; //function to call to take the controller output - void *arg_in; //argument to pass input_callback when called - void *arg_out; //argument to pass output_callback when called -} controller_holder; - -typedef struct controller_linked_list_item -{ - struct controller_holder *context; - struct controller_linked_list_item *next; - struct controller_linked_list_item *prev; - u8 bRegistered; //set to true when added to the list, false when removed -} controller_linked_list_item; - -extern volatile u32 ControlTimer0ErrorCount; -extern volatile u32 ControlTimer1ErrorCount; - -extern int InitControllers(XScuGic* IntcInstancePtr); -//extern int InitControlTimers(XScuGic* IntcInstancePtr); -extern void RunPI_Controller (controller_holder* ctxt); -extern void RunPID_Controller (controller_holder* ctxt); -extern int UnregisterController(int contNum, struct controller_linked_list_item *cnt); -extern int RegisterController(int contNum, struct controller_linked_list_item *cnt); - -#endif /* CONTROL_H_ */ +/* + * control.h + * + * Created on: Jun 24, 2014 + * Author: sever212 + */ + +#ifndef CONTROL_H_ +#define CONTROL_H_ + +typedef enum {C_IDLE, C_READY, C_RUNNING} controller_status; +typedef enum {C_PI, C_PID} controller_type; + +typedef struct controller_context{ + double *inputs; //reference - measured value of quantity being controlled + double *outputs; //output of the pi controller + u32 NumInputs; //number of inputs + u32 NumOutputs; //number of outputs + controller_status Status; //the status of the controller + u32 NumClocks; //run this controller every NumClocks count (1 for every time) + u32 ClockTime; //duration (in microseconds) of a clock edge + u32 clockCount; //current clock count + controller_type Type; //the type of controller (PI, PID) +} controller_context; + +typedef void (*get_controller_inputs)(void *arg, struct controller_context *cnt); +typedef void (*take_controller_output)(void *arg, struct controller_context *cnt); + +typedef struct pid_controller{ + double kp; //proportional gain + double kits; //integral gain * sample time + double kdn; //derivative gain for current error: derivative difference EQ: D = kdn*E[n] + kdn1*E[n-1] + kdm1*D[n-1] + double kdn1; //derivative gain for previous error + double kdm1; //derivative gain for previous derivative + double lastInt; //value of last integral + double lastErr; //value of the last error + double lastD; //value of the last derivative output + double plusSat; //positive integral saturation limit + double negSat; //negative integral saturation limit +} pid_controller; + +typedef struct pi_controller{ + double kp; //proportional gain + double kits; //integral gain * sample time + double lastInt; //value of last integral + double plusSat; //positive integral saturation limit + double negSat; //negative integral saturation limit +} pi_controller; + +typedef struct controller_holder{ + void *controller_info; //specific to the type of controller + struct controller_context *control_io; //the io of the controller (general to all controllers) + get_controller_inputs input_callback; //function to call to get measured and reference values + take_controller_output output_callback; //function to call to take the controller output + void *arg_in; //argument to pass input_callback when called + void *arg_out; //argument to pass output_callback when called +} controller_holder; + +typedef struct controller_linked_list_item +{ + struct controller_holder *context; + struct controller_linked_list_item *next; + struct controller_linked_list_item *prev; + u8 bRegistered; //set to true when added to the list, false when removed +} controller_linked_list_item; + +extern volatile u32 ControlTimer0ErrorCount; +extern volatile u32 ControlTimer1ErrorCount; + +extern int InitControllers(XScuGic* IntcInstancePtr); +//extern int InitControlTimers(XScuGic* IntcInstancePtr); +extern void RunPI_Controller (controller_holder* ctxt); +extern void RunPID_Controller (controller_holder* ctxt); +extern int UnregisterController(int contNum, struct controller_linked_list_item *cnt); +extern int RegisterController(int contNum, struct controller_linked_list_item *cnt); + +#endif /* CONTROL_H_ */ diff --git a/sdk/basic/src/io_pecb.c b/sdk/basic/src/io_pecb.c old mode 100755 new mode 100644 index 9621406d..a87737fd --- a/sdk/basic/src/io_pecb.c +++ b/sdk/basic/src/io_pecb.c @@ -1,115 +1,115 @@ -/* - * io_pecb.c - * - * Created on: Jun 25, 2014 - * Author: sever212 - */ - -#include "project_include.h" - -volatile u32 *PECB; -volatile u32 *LEDs; - -/***************************** - * ReadADC() - * Call this function to read in the ADC voltage - * - * reads +-10V, accurate to 0.0049V - *uiADCnum: the ADC to use (between 1 and 12) - */ -double ReadADC(u32 uiADCnum) -{ - float v; - analog_getf(uiADCnum, &v); - return v; - -// signed int iADC = 0; -// double dbADCval = 0, dbTemp; -// -// if ( (uiADCnum > 0) && (uiADCnum < 13) ) -// iADC = PECB[uiADCnum-1]; -// dbTemp = iADC; -// dbADCval = (dbTemp / 0x7FF) * 10; -// return dbADCval; -} - -/*void WriteDutyFraction(u32 Leg, float frac) -{ - unsigned char value = (unsigned char) (frac*256); - PECB[Leg-1] = value; -}*/ - -/***************************** - * WriteDutyRatio() - * Call this function to write a duty ratio out to - * a single leg. The value should be between 0 and 255 - * as where 255 is always on and 0 is always off - * - * Leg: 1 - ?? - * value: fractional duty ratio between 0 and 255 - * - */ -void WriteDutyRatio(u32 Leg, unsigned char value) -{ - pwm_set_duty_raw(Leg-1, value); - -// PECB[Leg-1] = value; - -} - -/***************************** - * WriteConfigRegister() - * Call this function to write a setting to the PECB config - * register. - * - * value: value between 0 and 255 - * - */ -void WriteConfigRegister(u8 value) -{ - PECB[NUM_LEGS] = value; -} - -/***************************** - * InitPECB_IO() - * Call this function to start setting up the - * PECB IO. After approximately 0.5 seconds have - * passed, call FinishInitPECB_IO() to finish - * the initialization - * - */ -int InitPECB_IO() -{ - u32 i; - LEDs = (u32 *) 0x41200000; - PECB = (u32 *) 0x43c00000; - - //turn all of the PECB legs on. - //this is to get the leg's dc/dc converters up and running properly - //in accordance with the email from sever212@umn.edu on Dec. 10, 2014 - //will turn all the legs off later, in FinishInitPECB_IO() - for (i = 0; i < NUM_LEGS; i++) - WriteDutyRatio(i+1, 255); - - return XST_SUCCESS; -} - -/***************************** - * FinishInitPECB_IO() - * Call this function approximately 0.5 seconds - * after calling InitPECB_IO() to finish the - * initialization. - * - */ -int FinishInitPECB_IO() -{ - u32 i; - //turn all of the legs off - for (i = 0; i < NUM_LEGS; i++) - WriteDutyRatio(i+1, 0); -} - -void WriteToZB_LEDs(u32 LED_value) -{ - *LEDs = LED_value; -} +/* + * io_pecb.c + * + * Created on: Jun 25, 2014 + * Author: sever212 + */ + +#include "project_include.h" + +volatile u32 *PECB; +volatile u32 *LEDs; + +/***************************** + * ReadADC() + * Call this function to read in the ADC voltage + * + * reads +-10V, accurate to 0.0049V + *uiADCnum: the ADC to use (between 1 and 12) + */ +double ReadADC(u32 uiADCnum) +{ + float v; + analog_getf(uiADCnum, &v); + return v; + +// signed int iADC = 0; +// double dbADCval = 0, dbTemp; +// +// if ( (uiADCnum > 0) && (uiADCnum < 13) ) +// iADC = PECB[uiADCnum-1]; +// dbTemp = iADC; +// dbADCval = (dbTemp / 0x7FF) * 10; +// return dbADCval; +} + +/*void WriteDutyFraction(u32 Leg, float frac) +{ + unsigned char value = (unsigned char) (frac*256); + PECB[Leg-1] = value; +}*/ + +/***************************** + * WriteDutyRatio() + * Call this function to write a duty ratio out to + * a single leg. The value should be between 0 and 255 + * as where 255 is always on and 0 is always off + * + * Leg: 1 - ?? + * value: fractional duty ratio between 0 and 255 + * + */ +void WriteDutyRatio(u32 Leg, unsigned char value) +{ + pwm_set_duty_raw(Leg-1, value); + +// PECB[Leg-1] = value; + +} + +/***************************** + * WriteConfigRegister() + * Call this function to write a setting to the PECB config + * register. + * + * value: value between 0 and 255 + * + */ +void WriteConfigRegister(u8 value) +{ + PECB[NUM_LEGS] = value; +} + +/***************************** + * InitPECB_IO() + * Call this function to start setting up the + * PECB IO. After approximately 0.5 seconds have + * passed, call FinishInitPECB_IO() to finish + * the initialization + * + */ +int InitPECB_IO() +{ + u32 i; + LEDs = (u32 *) 0x41200000; + PECB = (u32 *) 0x43c00000; + + //turn all of the PECB legs on. + //this is to get the leg's dc/dc converters up and running properly + //in accordance with the email from sever212@umn.edu on Dec. 10, 2014 + //will turn all the legs off later, in FinishInitPECB_IO() + for (i = 0; i < NUM_LEGS; i++) + WriteDutyRatio(i+1, 255); + + return XST_SUCCESS; +} + +/***************************** + * FinishInitPECB_IO() + * Call this function approximately 0.5 seconds + * after calling InitPECB_IO() to finish the + * initialization. + * + */ +int FinishInitPECB_IO() +{ + u32 i; + //turn all of the legs off + for (i = 0; i < NUM_LEGS; i++) + WriteDutyRatio(i+1, 0); +} + +void WriteToZB_LEDs(u32 LED_value) +{ + *LEDs = LED_value; +} diff --git a/sdk/basic/src/io_pecb.h b/sdk/basic/src/io_pecb.h old mode 100755 new mode 100644 index 64a101ca..d1128e53 --- a/sdk/basic/src/io_pecb.h +++ b/sdk/basic/src/io_pecb.h @@ -1,19 +1,19 @@ -#ifndef __PECB_IO_H -#define __PECB_IO_H - -//custom PL stuff -#define ER_CNT 31 -#define CONTROL 31 -#define WR_REG0 0 -#define RD_REG0 0 - - - -//extern void WriteDutyFraction(u32 Leg, float frac); -extern void WriteConfigRegister(u8 value); -extern void WriteDutyRatio(u32 Leg, unsigned char value); -extern double ReadADC(u32 uiADCnum); -extern int InitPECB_IO(); -extern int FinishInitPECB_IO(); -extern void WriteToZB_LEDs(u32 LED_value); -#endif +#ifndef __PECB_IO_H +#define __PECB_IO_H + +//custom PL stuff +#define ER_CNT 31 +#define CONTROL 31 +#define WR_REG0 0 +#define RD_REG0 0 + + + +//extern void WriteDutyFraction(u32 Leg, float frac); +extern void WriteConfigRegister(u8 value); +extern void WriteDutyRatio(u32 Leg, unsigned char value); +extern double ReadADC(u32 uiADCnum); +extern int InitPECB_IO(); +extern int FinishInitPECB_IO(); +extern void WriteToZB_LEDs(u32 LED_value); +#endif diff --git a/sdk/basic/src/lscript.ld b/sdk/basic/src/lscript.ld old mode 100755 new mode 100644 diff --git a/sdk/basic/src/lwip_glue.c b/sdk/basic/src/lwip_glue.c old mode 100755 new mode 100644 index d96507c0..f817848d --- a/sdk/basic/src/lwip_glue.c +++ b/sdk/basic/src/lwip_glue.c @@ -1,361 +1,361 @@ -/* - * lwip_glue.c - * - * Created on: Jun 13, 2014 - * Author: sever212 - */ -#ifdef __arm__ -#if 0 -#include "xparameters.h" -#include "xparameters_ps.h" /* defines XPAR values */ -#include "xil_cache.h" -#include "xscugic.h" -#include "xscutimer.h" -#include "lwip/tcp.h" -#include "lwip/tcp_impl.h" -#include "xil_printf.h" -#include "platform_config.h" -#include "netif/xadapter.h" -#endif -#include "project_include.h" - -#define RESET_RX_CNTR_LIMIT 400 - -static int ResetRxCntr = 0; -volatile char bEnableEthTimer = FALSE; -static struct netif server_netif; -struct netif *echo_netif; - -char bEth250ms = FALSE; - -typedef struct lwip_comm_glue { - char szRcvCmdEth[4096]; - void *socket; - u32 CmdHndlStateEth; -} lwip_comm_glue; - - -lwip_comm_glue EthComm[MAX_BASE_SOCKETS]; - -/***************************** - * init_tcpip_comm_data() - * Set up the communication data structures. - * Call on power up. - */ -static void init_tcpip_comm_data() -{ - int i; - for (i = 0; i < MAX_BASE_SOCKETS; i++) - { - EthComm[i].socket = 0; - EthComm[i].CmdHndlStateEth = 0; - } -} - -/***************************** - * get_tcpip_comm_data() - * Get a pointer to the receive data and the receive state for - * this socket. - * - * socket: unique pointer to the socket (doesn't need to point - * to the socket, just needs to be unique to the socket) - * data: returned pointer to the data - * state: returned pointer to the state - * - * Returns a status code: NOT_FOUND or SUCCESS - */ -static int get_tcpip_comm_data(void *socket, char **data, u32 **state) -{ - int retVal = NOT_FOUND; - int i; - int protect = EnterProtection(); - for (i = 0; i < MAX_BASE_SOCKETS; i++) - { - if (EthComm[i].socket == socket) - { - *data = EthComm[i].szRcvCmdEth; - *state = &EthComm[i].CmdHndlStateEth; - retVal = SUCCESS; - break; - } - } - LeaveProtection(protect); - return retVal; -} - -/***************************** - * put_tcpip_comm_data() - * Call this upon the connection of a new socket to setup a data - * structure for it. - * - * socket: unique pointer to the socket (doesn't need to point - * to the socket, just needs to be unique to the socket) - * - * Returns a status code: OVERFLOW (if no space) or SUCCESS - */ -static int put_tcpip_comm_data(void *socket) -{ - int retVal = OVERFLOW; - int i; - int protect = EnterProtection(); - for (i = 0; i < MAX_BASE_SOCKETS; i++) - { - if ((EthComm[i].socket == 0) || (EthComm[i].socket == socket)) - { - EthComm[i].socket = socket; - EthComm[i].CmdHndlStateEth = 0; - retVal = SUCCESS; - break; - } - } - LeaveProtection(protect); - return retVal; -} - -/***************************** - * remove_tcpip_comm_data() - * Call this upon the disconnection of a socket to free up - * the memory used for its data structure - * - * socket: unique pointer to the socket (doesn't need to point - * to the socket, just needs to be unique to the socket) - * - * Returns a status code: NOT_FOUND or SUCCESS - */ -static int remove_tcpip_comm_data(void *socket) -{ - int retVal = NOT_FOUND; - int i; - int protect = EnterProtection(); - for (i = 0; i < MAX_BASE_SOCKETS; i++) - { - if (EthComm[i].socket == socket) - { - EthComm[i].socket = 0; - EthComm[i].CmdHndlStateEth = 0; - retVal = SUCCESS; - break; - } - } - LeaveProtection(protect); - return retVal; -} - - - -void lwip_timer_callback() -{ - /* we need to call tcp_fasttmr & tcp_slowtmr at intervals specified - * by lwIP. It is not important that the timing is absoluetly accurate. - */ - static int odd = 1; - - odd = !odd; -#ifndef USE_SOFTETH_ON_ZYNQ - ResetRxCntr++; -#endif - tcp_fasttmr(); - if (odd) { - tcp_slowtmr(); - } - - /* For providing an SW alternative for the SI #692601. Under heavy - * Rx traffic if at some point the Rx path becomes unresponsive, the - * following API call will ensures a SW reset of the Rx path. The - * API xemacpsif_resetrx_on_no_rxdata is called every 100 milliseconds. - * This ensures that if the above HW bug is hit, in the worst case, - * the Rx path cannot become unresponsive for more than 100 - * milliseconds. - */ -#ifndef USE_SOFTETH_ON_ZYNQ - if (ResetRxCntr >= RESET_RX_CNTR_LIMIT) { - xemacpsif_resetrx_on_no_rxdata(echo_netif); - ResetRxCntr = 0; - } -#endif -} - - -void -print_ip(char *msg, struct ip_addr *ip) -{ - print(msg); - xil_printf("%d.%d.%d.%d\n\r", ip4_addr1(ip), ip4_addr2(ip), - ip4_addr3(ip), ip4_addr4(ip)); -} - -void -print_ip_settings(struct ip_addr *ip, struct ip_addr *mask, struct ip_addr *gw) -{ - - print_ip("Board IP: ", ip); - print_ip("Netmask : ", mask); - print_ip("Gateway : ", gw); -} - - -int SetupLWIP() -{ - struct ip_addr ipaddr, netmask, gw; - - /* the mac address of the board. this should be unique per board */ - unsigned char mac_ethernet_address[] = - { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 }; - - echo_netif = &server_netif; - - /* initliaze IP addresses to be used */ - IP4_ADDR(&ipaddr, 192, 168, 1, 10); - IP4_ADDR(&netmask, 255, 255, 255, 0); - IP4_ADDR(&gw, 192, 168, 1, 1); - - print_ip_settings(&ipaddr, &netmask, &gw); - - lwip_init(); - - /* Add network interface to the netif_list, and set it as default */ - if (!xemac_add(echo_netif, &ipaddr, &netmask, - &gw, mac_ethernet_address, - PLATFORM_EMAC_BASEADDR)) { - xil_printf("Error adding N/W interface\n\r"); - return -1; - } - netif_set_default(echo_netif); - - bEnableEthTimer = TRUE; - - /* specify that the network if is up */ - netif_set_up(echo_netif); - - /*Setup the application's comm data memory*/ - init_tcpip_comm_data(); - return XST_SUCCESS; -} - -//for now lump all ethernet commands together: - -void tcpip_disconnect_callback(void *arg, err_t err) -{ - remove_tcpip_comm_data(arg); - //if we are streaming out this port, stop the streaming. - if (StreamFIFOComm == arg) - StreamFIFOComm = 0; -} - -err_t recv_callback(void *arg, struct tcp_pcb *tpcb, - struct pbuf *p, err_t err) -{ - char szOutDataEth[8192]; - int status; - char *szRcvCmdEth; - u32 *CmdHndlStateEth; - - status = get_tcpip_comm_data(arg, &szRcvCmdEth, &CmdHndlStateEth); - /* do not read the packet if we are not in ESTABLISHED state */ - /* Also, abort connection if unable to find the comm data*/ - if ((!p) || (status != SUCCESS)) { - tcp_close(tpcb); - tcp_recv(tpcb, NULL); - remove_tcpip_comm_data(tpcb); - return ERR_OK; - } - u32 outLen = HandleCommandsGeneral(szOutDataEth, szRcvCmdEth, p->payload, p->len, CmdHndlStateEth, arg); - /* indicate that the packet has been received */ - tcp_recved(tpcb, p->len); - - - /* echo back the payload */ - /* in this case, we assume that the payload is < TCP_SND_BUF */ - if (outLen > 0) - { - if (tcp_sndbuf(tpcb) > outLen) { //(tcp_sndbuf(tpcb) > p->len) { - err = tcp_write(tpcb, szOutDataEth, outLen, 1); - } else - xil_printf("no space in tcp_sndbuf\n\r"); - } - /* free the received pbuf */ - pbuf_free(p); - - return ERR_OK; -} - -err_t sent_callback(void *arg, struct tcp_pcb *pcb, unsigned short len) -{ - //if streaming data, send data - if (StreamFIFOComm == pcb) - { - if (ReloadStreamFIFO(pcb) > 0) - bPrimeStreamFIFO = FALSE; - else - bPrimeStreamFIFO = TRUE; - } - return ERR_OK; -} - -err_t accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err) -{ - static int connection = 1; - - put_tcpip_comm_data(newpcb); - - /* set the receive callback for this connection */ - tcp_recv(newpcb, recv_callback); - - /* just use an integer number indicating the connection id as the - callback argument */ - tcp_arg(newpcb, /*(void*)connection*/ newpcb); - - //eric added: - tcp_sent(newpcb, sent_callback); - - tcp_err(newpcb, tcpip_disconnect_callback); - /* increment for subsequent accepted connections */ - connection++; - - return ERR_OK; -} - - -int start_tcpip() -{ - struct tcp_pcb *pcb; - err_t err; - unsigned port = 7; - - /* create new TCP PCB structure */ - pcb = tcp_new(); - if (!pcb) { - xil_printf("Error creating PCB. Out of Memory\n\r"); - return -1; - } - - pcb->so_options |= SOF_KEEPALIVE; //ELS added to try to get sockets to detect a disconnect - - /* bind to specified @port */ - err = tcp_bind(pcb, IP_ADDR_ANY, port); - if (err != ERR_OK) { - xil_printf("Unable to bind to port %d: err = %d\n\r", port, err); - return -2; - } - - /* we do not need any arguments to callback functions */ - tcp_arg(pcb, NULL); - - /* listen for connections */ - pcb = tcp_listen(pcb); - if (!pcb) { - xil_printf("Out of memory while tcp_listen\n\r"); - return -3; - } - - /* specify callback to use for incoming connections */ - tcp_accept(pcb, accept_callback); - - xil_printf("TCP echo server started @ port %d\n\r", port); - - return XST_SUCCESS; -} - - -#endif - +/* + * lwip_glue.c + * + * Created on: Jun 13, 2014 + * Author: sever212 + */ +#ifdef __arm__ +#if 0 +#include "xparameters.h" +#include "xparameters_ps.h" /* defines XPAR values */ +#include "xil_cache.h" +#include "xscugic.h" +#include "xscutimer.h" +#include "lwip/tcp.h" +#include "lwip/tcp_impl.h" +#include "xil_printf.h" +#include "platform_config.h" +#include "netif/xadapter.h" +#endif +#include "project_include.h" + +#define RESET_RX_CNTR_LIMIT 400 + +static int ResetRxCntr = 0; +volatile char bEnableEthTimer = FALSE; +static struct netif server_netif; +struct netif *echo_netif; + +char bEth250ms = FALSE; + +typedef struct lwip_comm_glue { + char szRcvCmdEth[4096]; + void *socket; + u32 CmdHndlStateEth; +} lwip_comm_glue; + + +lwip_comm_glue EthComm[MAX_BASE_SOCKETS]; + +/***************************** + * init_tcpip_comm_data() + * Set up the communication data structures. + * Call on power up. + */ +static void init_tcpip_comm_data() +{ + int i; + for (i = 0; i < MAX_BASE_SOCKETS; i++) + { + EthComm[i].socket = 0; + EthComm[i].CmdHndlStateEth = 0; + } +} + +/***************************** + * get_tcpip_comm_data() + * Get a pointer to the receive data and the receive state for + * this socket. + * + * socket: unique pointer to the socket (doesn't need to point + * to the socket, just needs to be unique to the socket) + * data: returned pointer to the data + * state: returned pointer to the state + * + * Returns a status code: NOT_FOUND or SUCCESS + */ +static int get_tcpip_comm_data(void *socket, char **data, u32 **state) +{ + int retVal = NOT_FOUND; + int i; + int protect = EnterProtection(); + for (i = 0; i < MAX_BASE_SOCKETS; i++) + { + if (EthComm[i].socket == socket) + { + *data = EthComm[i].szRcvCmdEth; + *state = &EthComm[i].CmdHndlStateEth; + retVal = SUCCESS; + break; + } + } + LeaveProtection(protect); + return retVal; +} + +/***************************** + * put_tcpip_comm_data() + * Call this upon the connection of a new socket to setup a data + * structure for it. + * + * socket: unique pointer to the socket (doesn't need to point + * to the socket, just needs to be unique to the socket) + * + * Returns a status code: OVERFLOW (if no space) or SUCCESS + */ +static int put_tcpip_comm_data(void *socket) +{ + int retVal = OVERFLOW; + int i; + int protect = EnterProtection(); + for (i = 0; i < MAX_BASE_SOCKETS; i++) + { + if ((EthComm[i].socket == 0) || (EthComm[i].socket == socket)) + { + EthComm[i].socket = socket; + EthComm[i].CmdHndlStateEth = 0; + retVal = SUCCESS; + break; + } + } + LeaveProtection(protect); + return retVal; +} + +/***************************** + * remove_tcpip_comm_data() + * Call this upon the disconnection of a socket to free up + * the memory used for its data structure + * + * socket: unique pointer to the socket (doesn't need to point + * to the socket, just needs to be unique to the socket) + * + * Returns a status code: NOT_FOUND or SUCCESS + */ +static int remove_tcpip_comm_data(void *socket) +{ + int retVal = NOT_FOUND; + int i; + int protect = EnterProtection(); + for (i = 0; i < MAX_BASE_SOCKETS; i++) + { + if (EthComm[i].socket == socket) + { + EthComm[i].socket = 0; + EthComm[i].CmdHndlStateEth = 0; + retVal = SUCCESS; + break; + } + } + LeaveProtection(protect); + return retVal; +} + + + +void lwip_timer_callback() +{ + /* we need to call tcp_fasttmr & tcp_slowtmr at intervals specified + * by lwIP. It is not important that the timing is absoluetly accurate. + */ + static int odd = 1; + + odd = !odd; +#ifndef USE_SOFTETH_ON_ZYNQ + ResetRxCntr++; +#endif + tcp_fasttmr(); + if (odd) { + tcp_slowtmr(); + } + + /* For providing an SW alternative for the SI #692601. Under heavy + * Rx traffic if at some point the Rx path becomes unresponsive, the + * following API call will ensures a SW reset of the Rx path. The + * API xemacpsif_resetrx_on_no_rxdata is called every 100 milliseconds. + * This ensures that if the above HW bug is hit, in the worst case, + * the Rx path cannot become unresponsive for more than 100 + * milliseconds. + */ +#ifndef USE_SOFTETH_ON_ZYNQ + if (ResetRxCntr >= RESET_RX_CNTR_LIMIT) { + xemacpsif_resetrx_on_no_rxdata(echo_netif); + ResetRxCntr = 0; + } +#endif +} + + +void +print_ip(char *msg, struct ip_addr *ip) +{ + print(msg); + xil_printf("%d.%d.%d.%d\n\r", ip4_addr1(ip), ip4_addr2(ip), + ip4_addr3(ip), ip4_addr4(ip)); +} + +void +print_ip_settings(struct ip_addr *ip, struct ip_addr *mask, struct ip_addr *gw) +{ + + print_ip("Board IP: ", ip); + print_ip("Netmask : ", mask); + print_ip("Gateway : ", gw); +} + + +int SetupLWIP() +{ + struct ip_addr ipaddr, netmask, gw; + + /* the mac address of the board. this should be unique per board */ + unsigned char mac_ethernet_address[] = + { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 }; + + echo_netif = &server_netif; + + /* initliaze IP addresses to be used */ + IP4_ADDR(&ipaddr, 192, 168, 1, 10); + IP4_ADDR(&netmask, 255, 255, 255, 0); + IP4_ADDR(&gw, 192, 168, 1, 1); + + print_ip_settings(&ipaddr, &netmask, &gw); + + lwip_init(); + + /* Add network interface to the netif_list, and set it as default */ + if (!xemac_add(echo_netif, &ipaddr, &netmask, + &gw, mac_ethernet_address, + PLATFORM_EMAC_BASEADDR)) { + xil_printf("Error adding N/W interface\n\r"); + return -1; + } + netif_set_default(echo_netif); + + bEnableEthTimer = TRUE; + + /* specify that the network if is up */ + netif_set_up(echo_netif); + + /*Setup the application's comm data memory*/ + init_tcpip_comm_data(); + return XST_SUCCESS; +} + +//for now lump all ethernet commands together: + +void tcpip_disconnect_callback(void *arg, err_t err) +{ + remove_tcpip_comm_data(arg); + //if we are streaming out this port, stop the streaming. + if (StreamFIFOComm == arg) + StreamFIFOComm = 0; +} + +err_t recv_callback(void *arg, struct tcp_pcb *tpcb, + struct pbuf *p, err_t err) +{ + char szOutDataEth[8192]; + int status; + char *szRcvCmdEth; + u32 *CmdHndlStateEth; + + status = get_tcpip_comm_data(arg, &szRcvCmdEth, &CmdHndlStateEth); + /* do not read the packet if we are not in ESTABLISHED state */ + /* Also, abort connection if unable to find the comm data*/ + if ((!p) || (status != SUCCESS)) { + tcp_close(tpcb); + tcp_recv(tpcb, NULL); + remove_tcpip_comm_data(tpcb); + return ERR_OK; + } + u32 outLen = HandleCommandsGeneral(szOutDataEth, szRcvCmdEth, p->payload, p->len, CmdHndlStateEth, arg); + /* indicate that the packet has been received */ + tcp_recved(tpcb, p->len); + + + /* echo back the payload */ + /* in this case, we assume that the payload is < TCP_SND_BUF */ + if (outLen > 0) + { + if (tcp_sndbuf(tpcb) > outLen) { //(tcp_sndbuf(tpcb) > p->len) { + err = tcp_write(tpcb, szOutDataEth, outLen, 1); + } else + xil_printf("no space in tcp_sndbuf\n\r"); + } + /* free the received pbuf */ + pbuf_free(p); + + return ERR_OK; +} + +err_t sent_callback(void *arg, struct tcp_pcb *pcb, unsigned short len) +{ + //if streaming data, send data + if (StreamFIFOComm == pcb) + { + if (ReloadStreamFIFO(pcb) > 0) + bPrimeStreamFIFO = FALSE; + else + bPrimeStreamFIFO = TRUE; + } + return ERR_OK; +} + +err_t accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err) +{ + static int connection = 1; + + put_tcpip_comm_data(newpcb); + + /* set the receive callback for this connection */ + tcp_recv(newpcb, recv_callback); + + /* just use an integer number indicating the connection id as the + callback argument */ + tcp_arg(newpcb, /*(void*)connection*/ newpcb); + + //eric added: + tcp_sent(newpcb, sent_callback); + + tcp_err(newpcb, tcpip_disconnect_callback); + /* increment for subsequent accepted connections */ + connection++; + + return ERR_OK; +} + + +int start_tcpip() +{ + struct tcp_pcb *pcb; + err_t err; + unsigned port = 7; + + /* create new TCP PCB structure */ + pcb = tcp_new(); + if (!pcb) { + xil_printf("Error creating PCB. Out of Memory\n\r"); + return -1; + } + + pcb->so_options |= SOF_KEEPALIVE; //ELS added to try to get sockets to detect a disconnect + + /* bind to specified @port */ + err = tcp_bind(pcb, IP_ADDR_ANY, port); + if (err != ERR_OK) { + xil_printf("Unable to bind to port %d: err = %d\n\r", port, err); + return -2; + } + + /* we do not need any arguments to callback functions */ + tcp_arg(pcb, NULL); + + /* listen for connections */ + pcb = tcp_listen(pcb); + if (!pcb) { + xil_printf("Out of memory while tcp_listen\n\r"); + return -3; + } + + /* specify callback to use for incoming connections */ + tcp_accept(pcb, accept_callback); + + xil_printf("TCP echo server started @ port %d\n\r", port); + + return XST_SUCCESS; +} + + +#endif + diff --git a/sdk/basic/src/lwip_glue.h b/sdk/basic/src/lwip_glue.h old mode 100755 new mode 100644 index c6721178..6238e30f --- a/sdk/basic/src/lwip_glue.h +++ b/sdk/basic/src/lwip_glue.h @@ -1,12 +1,12 @@ - -#ifndef __LWIP_GLUE_H -#define __LWIP_GLUE_H -extern void lwip_timer_callback(); -extern int SetupLWIP(); -extern int start_tcpip(); - -extern volatile char bEnableEthTimer; -extern struct netif *echo_netif; -extern char bEth250ms; - -#endif //__LWIP_GLUE_H + +#ifndef __LWIP_GLUE_H +#define __LWIP_GLUE_H +extern void lwip_timer_callback(); +extern int SetupLWIP(); +extern int start_tcpip(); + +extern volatile char bEnableEthTimer; +extern struct netif *echo_netif; +extern char bEth250ms; + +#endif //__LWIP_GLUE_H diff --git a/sdk/basic/src/main.c b/sdk/basic/src/main.c old mode 100755 new mode 100644 index 1f78c13a..c437dfbd --- a/sdk/basic/src/main.c +++ b/sdk/basic/src/main.c @@ -1,436 +1,436 @@ -/* - * Copyright (c) 2009-2012 Xilinx, Inc. All rights reserved. - * - * Xilinx, Inc. - * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A - * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS - * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR - * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION - * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE - * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. - * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO - * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO - * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE - * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -/* - * helloworld.c: simple test application - * - * This application configures UART 16550 to baud rate 9600. - * PS7 UART (Zynq) is not initialized by this application, since - * bootrom/bsp configures it to baud rate 115200 - * - * ------------------------------------------------ - * | UART TYPE BAUD RATE | - * ------------------------------------------------ - * uartns550 9600 - * uartlite Configurable only in HW design - * ps7_uart 115200 (configured by bootrom/bsp) - */ - -//#include -#if 0 -#include "platform.h" -#include "xparameters.h" -#include "netif/xadapter.h" -#include "xgpio.h" -#include "xscutimer.h" -#include "xscugic.h" -#include "xil_exception.h" -#include "xil_printf.h" -#include "xuartps_hw.h" -#include -#include "commands.h" -#include "Log.h" -#include "prog_timer.h" -#endif -#include "project_include.h" -/************************** Constant Definitions *****************************/ -/* - * The following constant maps to the name of the hardware instances that - * were created in the EDK XPS system. - */ - -//#define GPIO_EXAMPLE_DEVICE_ID XPAR_AXI_GPIO_0_DEVICE_ID -//#define LED_CHANNEL 1 -//#define BUTTON_CHANNEL 2 -#define INTC_DEVICE_ID XPAR_PS7_SCUGIC_0_DEVICE_ID -//#define INTC_GPIO_INTERRUPT_ID XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR -#define INTC XScuGic -#define INTC_HANDLER XScuGic_InterruptHandler -//#define BUTTON_INTERRUPT XGPIO_IR_CH2_MASK -//#define INTENSITY_STEP 110000 - -//Internal functions -//int SetupGPIO_Interrupt(XScuGic *IntcInstancePtr); -int SetupInterruptSystem(XScuGic *IntcInstancePtr); -//void GpioIsr(void *InstancePtr); -void HandleTimer100usTick(); -// /void CommandParser(const char * szCmd, char *szResponse); -//void HandleCommands(); -//void UpdateLEDs(); - -/* missing declaration in lwIP */ -void lwip_init(); - -////GPIO -//XGpio Gpio; /* The Instance of the GPIO Driver */ -//u32 count = 0; - -//Interrupts -XScuGic IntcInstance; /* Interrupt Controller Instance */ - - -//UART stuff -char szRcvCmdUart[4096]; - -//timer stuff: -/*static int SetupTimer(XScuGic *IntcInstancePtr, XScuTimer * TimerInstancePtr, - u16 TimerDeviceId, u16 TimerIntrId);*/ - -XScuTimer TimerInstance; /* Cortex A9 Scu Private Timer Instance */ - -volatile u32 Timer10ms; - -u32 Timing100usErrorCount = 0; - -u32 bTimer = 0; - -u32 ConvertCharToByte(u32 i) { - u32 res = i; - if (res <= 0x39) - res -= 0x30; - else if (res <= 'F') - res -= 55; - else if (res <= 'f') - res -= 87; - - return res; -} - -char TimerDisabled = TRUE; -int EnterProtection() { - if (!TimerDisabled) - { - XScuGic_Disable(&IntcInstance, TIMER_IRPT_INTR); - TimerDisabled = TRUE; - return TRUE; - } - else - return FALSE; -} - -int LeaveProtection(int State) { - if (State) - { - XScuGic_Enable(&IntcInstance, TIMER_IRPT_INTR); - TimerDisabled = FALSE; - } - return State; -} - - extern void outbyte(char c); - int main() { - u32 HandleCommandState = 0; - u32 counter; - u32 ec_to_dev, ec_from_dev; //, failure; - int Status; - - init_platform(); - - bsp_init(); - - InitPECB_IO(); - InitLog(); - - /* - * Setup the interrupts such that interrupt processing can occur. - * If an error occurs then exit - */ -//ISR - print("Setting up the interrupts... "); - Status = SetupInterruptSystem(&IntcInstance); - if (Status != XST_SUCCESS) - return XST_FAILURE; - print("Success!\n\r"); - -//TIMER - print("Setting up the timer..."); - Status = SetupTimer(&IntcInstance, &TimerInstance, TIMER_DEVICE_ID, - TIMER_IRPT_INTR); - if (Status != XST_SUCCESS) - return XST_FAILURE; - print("Success!\n\r"); - TimerDisabled = FALSE; - -////GPIO -// print("Setting up the GPIO..."); -// Status = XGpio_Initialize(&Gpio, GPIO_EXAMPLE_DEVICE_ID); -// if (Status != XST_SUCCESS) -// return XST_FAILURE; -// print("Success!\n\r"); - -////GPIO ISR -// print("Setting up the GPIO Interrupt..."); -// Status = SetupGPIO_Interrupt(&IntcInstance); -// if (Status != XST_SUCCESS) -// return XST_FAILURE; -// print("Success!\n\r"); - -//CONTROL - print("Setting up the controllers..."); - Status = InitControllers(&IntcInstance); - if (Status != XST_SUCCESS) - return XST_FAILURE; - print("Success!\n\r"); - -//CONTROL app - /*print("Initializing the control application..."); - Status = InitControlApp(); - if (Status != XST_SUCCESS) - return XST_FAILURE; - print("Success!\n\r");*/ - -//CLEAR PECB error count - print("Clearing PECB error count..."); - PECB[CONTROL] = 1; - for (counter = 0; counter < 0xFFFF; counter++) - ; - PECB[CONTROL] = 0; - - ec_to_dev = PECB[ER_CNT] & 0xFFFF; - ec_from_dev = (PECB[ER_CNT] >> 16) & 0xFFFF; - if (ec_to_dev + ec_from_dev == 0) - print("Success!\r\n"); - else - printf("Uh oh... found %d errors!\r\n", - (unsigned int) (ec_to_dev + ec_from_dev)); - -//PECB self-test -#if 0 - print("PECB self test..."); - for (counter = 0; counter < 12; counter++) - PECB[WR_REG0+counter] = 0x03 + counter; - - for (counter = 0; counter < 0xFFFF; counter++) - ; - - failure = 0; - - for (counter = 0; counter < 12; counter++) - if (PECB[RD_REG0+counter] != 0x03 + counter) - { - failure = 1; - printf("\r\nPECB Self-Test Failure: Register %X reads %08X, expected %08X", (unsigned int)counter, (unsigned int)PECB[RD_REG0+counter], (unsigned int) (0x03+counter)); - } - - if (failure == 0) - printf("Success!\r\n"); - else - printf("\r\n"); -#endif - print("Setting up ethernet and lwip..."); - if (SetupLWIP() == XST_SUCCESS) - printf("Success!\r\n"); - else - printf("Failure\r\n"); - - print("Setting up listening sockets..."); - if (start_tcpip() == XST_SUCCESS) - printf("Success!\r\n"); - else - printf("Failure\r\n"); - - //so we have two options to address the IO -- either directly with its address (0x41200000) - //or via XGpio functions. - - //Option 1: - //print("Writing to LEDs directly: 0x24\n\r"); - - //*LEDs = 0x24; - - print("Completing the initialization of the PECB interface..."); - FinishInitPECB_IO(); - - print("Enter a command followed by CR\n\r"); - while (1) { - xemacif_input(echo_netif); - - HandleCommandState = HandleCommandsUart(szRcvCmdUart, - HandleCommandState); - - if (bTimer100usTick) - HandleTimer100usTick(); - - if (bPrimeStreamFIFO) - { - if (ReloadStreamFIFO(StreamFIFOComm) > 0) - bPrimeStreamFIFO = FALSE; - } - - if (bEth250ms) - { - bEth250ms = FALSE; - lwip_timer_callback(); - } - } - - return 0; - } - - void HandleTimer100usTick() { - static u32 countTo10ms; - - //Clear this immediately so we can make sure the function doesn't take more than 100us - bTimer100usTick = 0; - - //code every 10ms - if (++countTo10ms) { - countTo10ms = 0; -// UpdateLEDs(); - } - - HBA_100usTick(); - VSI_100usTick(); - - if (bTimer100usTick) - Timing100usErrorCount++; - } - -// void UpdateLEDs() -// { -// u32 ec_to_dev, ec_from_dev; -// ec_to_dev = PECB[ER_CNT] & 0xFFFF; -// ec_from_dev = (PECB[ER_CNT] >> 16) & 0xFFFF; -// WriteToZB_LEDs(ec_to_dev + ec_from_dev); -// } - - - - -// void GpioIsr(void *InstancePtr) { -// u32 Buttons; -// -// XGpio *GpioPtr = (XGpio *) InstancePtr; -// -// // Disable the interrupt -// XGpio_InterruptDisable(GpioPtr, BUTTON_INTERRUPT); -// -// // There should not be any other interrupts occuring other than the the button changes -// if ((XGpio_InterruptGetStatus(GpioPtr) & BUTTON_INTERRUPT) -// != BUTTON_INTERRUPT) { -// return; -// } -// -// // Read state of push buttons and determine which ones changed -// // states from the previous interrupt. Save a copy of the buttons -// // for the next interrupt -// -// Buttons = XGpio_DiscreteRead(&Gpio, BUTTON_CHANNEL); -// -// if (Buttons == 1 && (count < 0xFF)) { -// u32 counter; -// count++; -// PECB[CONTROL] = 1; -// fprintf(stdout, "Clearing the error count\n"); -// for (counter = 0; counter < 0xFFFF; counter++) -// ; -// PECB[CONTROL] = 0; -// fprintf(stdout, "Error count cleared, now reads: %d\n", -// (int) PECB[ER_CNT]); -// } -// -// if (Buttons == 2 && (count < 0xFF)) { -// count++; -// } -// -// if (Buttons == 4 && (count >= 1)) { -// count--; -// } -// -// if (Buttons == 8 && (count >= 1)) { -// count--; -// } -// -// if (Buttons == 16) { -// count = 0; -// } -// -// //fprintf(stdout,"Count : %X\n",(int)count); -// -// //XGpio_DiscreteWrite(&Gpio, LED_CHANNEL, count); -// -// // Clear the interrupt such that it is no longer pending in the GPIO -// (void) XGpio_InterruptClear(GpioPtr, BUTTON_INTERRUPT); -// -// // Enable the interrupt -// XGpio_InterruptEnable(GpioPtr, BUTTON_INTERRUPT); -// -// } - - /*******************************************************************************/ - /* S E T U P I N T E R R U P T S Y S T E M */ - /*******************************************************************************/ - int SetupInterruptSystem(XScuGic *IntcInstancePtr) { - int Result; - - XScuGic_Config *IntcConfig; - - // Initialize the interrupt controller driver so that it is ready to use. - - IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);//ELS -- this is misleading! there is only one XScuGic device (0) - if (NULL == IntcConfig) { - return XST_FAILURE; - } - - Result = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, - IntcConfig->CpuBaseAddress); - if (Result != XST_SUCCESS) { - return XST_FAILURE; - } - - // Initialize the exception table and register the interrupt - // controller handler with the exception table - - Xil_ExceptionInit(); - - Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, - (Xil_ExceptionHandler) INTC_HANDLER, IntcInstancePtr); - - // Enable non-critical exceptions - - Xil_ExceptionEnable(); - - return XST_SUCCESS; - } - -// int SetupGPIO_Interrupt(XScuGic *IntcInstancePtr) { -// int Result; -// XScuGic_SetPriorityTriggerType(IntcInstancePtr, INTC_GPIO_INTERRUPT_ID, -// 0xA0, 0x3); -// -// // Connect the interrupt handler that will be called when an -// // interrupt occurs for the device. -// -// Result = XScuGic_Connect(IntcInstancePtr, INTC_GPIO_INTERRUPT_ID, -// (Xil_ExceptionHandler) GpioIsr, &Gpio); -// if (Result != XST_SUCCESS) { -// return Result; -// } -// -// // Enable the interrupt for the GPIO device. -// -// XScuGic_Enable(IntcInstancePtr, INTC_GPIO_INTERRUPT_ID); -// -// // Enable the GPIO channel interrupts so that push button can be -// // detected and enable interrupts for the GPIO device -// -// XGpio_InterruptEnable(&Gpio, BUTTON_INTERRUPT); -// XGpio_InterruptGlobalEnable(&Gpio); -// -// return XST_SUCCESS; -// } - +/* + * Copyright (c) 2009-2012 Xilinx, Inc. All rights reserved. + * + * Xilinx, Inc. + * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A + * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS + * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR + * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION + * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE + * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. + * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO + * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO + * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE + * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +/* + * helloworld.c: simple test application + * + * This application configures UART 16550 to baud rate 9600. + * PS7 UART (Zynq) is not initialized by this application, since + * bootrom/bsp configures it to baud rate 115200 + * + * ------------------------------------------------ + * | UART TYPE BAUD RATE | + * ------------------------------------------------ + * uartns550 9600 + * uartlite Configurable only in HW design + * ps7_uart 115200 (configured by bootrom/bsp) + */ + +//#include +#if 0 +#include "platform.h" +#include "xparameters.h" +#include "netif/xadapter.h" +#include "xgpio.h" +#include "xscutimer.h" +#include "xscugic.h" +#include "xil_exception.h" +#include "xil_printf.h" +#include "xuartps_hw.h" +#include +#include "commands.h" +#include "Log.h" +#include "prog_timer.h" +#endif +#include "project_include.h" +/************************** Constant Definitions *****************************/ +/* + * The following constant maps to the name of the hardware instances that + * were created in the EDK XPS system. + */ + +//#define GPIO_EXAMPLE_DEVICE_ID XPAR_AXI_GPIO_0_DEVICE_ID +//#define LED_CHANNEL 1 +//#define BUTTON_CHANNEL 2 +#define INTC_DEVICE_ID XPAR_PS7_SCUGIC_0_DEVICE_ID +//#define INTC_GPIO_INTERRUPT_ID XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR +#define INTC XScuGic +#define INTC_HANDLER XScuGic_InterruptHandler +//#define BUTTON_INTERRUPT XGPIO_IR_CH2_MASK +//#define INTENSITY_STEP 110000 + +//Internal functions +//int SetupGPIO_Interrupt(XScuGic *IntcInstancePtr); +int SetupInterruptSystem(XScuGic *IntcInstancePtr); +//void GpioIsr(void *InstancePtr); +void HandleTimer100usTick(); +// /void CommandParser(const char * szCmd, char *szResponse); +//void HandleCommands(); +//void UpdateLEDs(); + +/* missing declaration in lwIP */ +void lwip_init(); + +////GPIO +//XGpio Gpio; /* The Instance of the GPIO Driver */ +//u32 count = 0; + +//Interrupts +XScuGic IntcInstance; /* Interrupt Controller Instance */ + + +//UART stuff +char szRcvCmdUart[4096]; + +//timer stuff: +/*static int SetupTimer(XScuGic *IntcInstancePtr, XScuTimer * TimerInstancePtr, + u16 TimerDeviceId, u16 TimerIntrId);*/ + +XScuTimer TimerInstance; /* Cortex A9 Scu Private Timer Instance */ + +volatile u32 Timer10ms; + +u32 Timing100usErrorCount = 0; + +u32 bTimer = 0; + +u32 ConvertCharToByte(u32 i) { + u32 res = i; + if (res <= 0x39) + res -= 0x30; + else if (res <= 'F') + res -= 55; + else if (res <= 'f') + res -= 87; + + return res; +} + +char TimerDisabled = TRUE; +int EnterProtection() { + if (!TimerDisabled) + { + XScuGic_Disable(&IntcInstance, TIMER_IRPT_INTR); + TimerDisabled = TRUE; + return TRUE; + } + else + return FALSE; +} + +int LeaveProtection(int State) { + if (State) + { + XScuGic_Enable(&IntcInstance, TIMER_IRPT_INTR); + TimerDisabled = FALSE; + } + return State; +} + + extern void outbyte(char c); + int main() { + u32 HandleCommandState = 0; + u32 counter; + u32 ec_to_dev, ec_from_dev; //, failure; + int Status; + + init_platform(); + + bsp_init(); + + InitPECB_IO(); + InitLog(); + + /* + * Setup the interrupts such that interrupt processing can occur. + * If an error occurs then exit + */ +//ISR + print("Setting up the interrupts... "); + Status = SetupInterruptSystem(&IntcInstance); + if (Status != XST_SUCCESS) + return XST_FAILURE; + print("Success!\n\r"); + +//TIMER + print("Setting up the timer..."); + Status = SetupTimer(&IntcInstance, &TimerInstance, TIMER_DEVICE_ID, + TIMER_IRPT_INTR); + if (Status != XST_SUCCESS) + return XST_FAILURE; + print("Success!\n\r"); + TimerDisabled = FALSE; + +////GPIO +// print("Setting up the GPIO..."); +// Status = XGpio_Initialize(&Gpio, GPIO_EXAMPLE_DEVICE_ID); +// if (Status != XST_SUCCESS) +// return XST_FAILURE; +// print("Success!\n\r"); + +////GPIO ISR +// print("Setting up the GPIO Interrupt..."); +// Status = SetupGPIO_Interrupt(&IntcInstance); +// if (Status != XST_SUCCESS) +// return XST_FAILURE; +// print("Success!\n\r"); + +//CONTROL + print("Setting up the controllers..."); + Status = InitControllers(&IntcInstance); + if (Status != XST_SUCCESS) + return XST_FAILURE; + print("Success!\n\r"); + +//CONTROL app + /*print("Initializing the control application..."); + Status = InitControlApp(); + if (Status != XST_SUCCESS) + return XST_FAILURE; + print("Success!\n\r");*/ + +//CLEAR PECB error count + print("Clearing PECB error count..."); + PECB[CONTROL] = 1; + for (counter = 0; counter < 0xFFFF; counter++) + ; + PECB[CONTROL] = 0; + + ec_to_dev = PECB[ER_CNT] & 0xFFFF; + ec_from_dev = (PECB[ER_CNT] >> 16) & 0xFFFF; + if (ec_to_dev + ec_from_dev == 0) + print("Success!\r\n"); + else + printf("Uh oh... found %d errors!\r\n", + (unsigned int) (ec_to_dev + ec_from_dev)); + +//PECB self-test +#if 0 + print("PECB self test..."); + for (counter = 0; counter < 12; counter++) + PECB[WR_REG0+counter] = 0x03 + counter; + + for (counter = 0; counter < 0xFFFF; counter++) + ; + + failure = 0; + + for (counter = 0; counter < 12; counter++) + if (PECB[RD_REG0+counter] != 0x03 + counter) + { + failure = 1; + printf("\r\nPECB Self-Test Failure: Register %X reads %08X, expected %08X", (unsigned int)counter, (unsigned int)PECB[RD_REG0+counter], (unsigned int) (0x03+counter)); + } + + if (failure == 0) + printf("Success!\r\n"); + else + printf("\r\n"); +#endif + print("Setting up ethernet and lwip..."); + if (SetupLWIP() == XST_SUCCESS) + printf("Success!\r\n"); + else + printf("Failure\r\n"); + + print("Setting up listening sockets..."); + if (start_tcpip() == XST_SUCCESS) + printf("Success!\r\n"); + else + printf("Failure\r\n"); + + //so we have two options to address the IO -- either directly with its address (0x41200000) + //or via XGpio functions. + + //Option 1: + //print("Writing to LEDs directly: 0x24\n\r"); + + //*LEDs = 0x24; + + print("Completing the initialization of the PECB interface..."); + FinishInitPECB_IO(); + + print("Enter a command followed by CR\n\r"); + while (1) { + xemacif_input(echo_netif); + + HandleCommandState = HandleCommandsUart(szRcvCmdUart, + HandleCommandState); + + if (bTimer100usTick) + HandleTimer100usTick(); + + if (bPrimeStreamFIFO) + { + if (ReloadStreamFIFO(StreamFIFOComm) > 0) + bPrimeStreamFIFO = FALSE; + } + + if (bEth250ms) + { + bEth250ms = FALSE; + lwip_timer_callback(); + } + } + + return 0; + } + + void HandleTimer100usTick() { + static u32 countTo10ms; + + //Clear this immediately so we can make sure the function doesn't take more than 100us + bTimer100usTick = 0; + + //code every 10ms + if (++countTo10ms) { + countTo10ms = 0; +// UpdateLEDs(); + } + + HBA_100usTick(); + VSI_100usTick(); + + if (bTimer100usTick) + Timing100usErrorCount++; + } + +// void UpdateLEDs() +// { +// u32 ec_to_dev, ec_from_dev; +// ec_to_dev = PECB[ER_CNT] & 0xFFFF; +// ec_from_dev = (PECB[ER_CNT] >> 16) & 0xFFFF; +// WriteToZB_LEDs(ec_to_dev + ec_from_dev); +// } + + + + +// void GpioIsr(void *InstancePtr) { +// u32 Buttons; +// +// XGpio *GpioPtr = (XGpio *) InstancePtr; +// +// // Disable the interrupt +// XGpio_InterruptDisable(GpioPtr, BUTTON_INTERRUPT); +// +// // There should not be any other interrupts occuring other than the the button changes +// if ((XGpio_InterruptGetStatus(GpioPtr) & BUTTON_INTERRUPT) +// != BUTTON_INTERRUPT) { +// return; +// } +// +// // Read state of push buttons and determine which ones changed +// // states from the previous interrupt. Save a copy of the buttons +// // for the next interrupt +// +// Buttons = XGpio_DiscreteRead(&Gpio, BUTTON_CHANNEL); +// +// if (Buttons == 1 && (count < 0xFF)) { +// u32 counter; +// count++; +// PECB[CONTROL] = 1; +// fprintf(stdout, "Clearing the error count\n"); +// for (counter = 0; counter < 0xFFFF; counter++) +// ; +// PECB[CONTROL] = 0; +// fprintf(stdout, "Error count cleared, now reads: %d\n", +// (int) PECB[ER_CNT]); +// } +// +// if (Buttons == 2 && (count < 0xFF)) { +// count++; +// } +// +// if (Buttons == 4 && (count >= 1)) { +// count--; +// } +// +// if (Buttons == 8 && (count >= 1)) { +// count--; +// } +// +// if (Buttons == 16) { +// count = 0; +// } +// +// //fprintf(stdout,"Count : %X\n",(int)count); +// +// //XGpio_DiscreteWrite(&Gpio, LED_CHANNEL, count); +// +// // Clear the interrupt such that it is no longer pending in the GPIO +// (void) XGpio_InterruptClear(GpioPtr, BUTTON_INTERRUPT); +// +// // Enable the interrupt +// XGpio_InterruptEnable(GpioPtr, BUTTON_INTERRUPT); +// +// } + + /*******************************************************************************/ + /* S E T U P I N T E R R U P T S Y S T E M */ + /*******************************************************************************/ + int SetupInterruptSystem(XScuGic *IntcInstancePtr) { + int Result; + + XScuGic_Config *IntcConfig; + + // Initialize the interrupt controller driver so that it is ready to use. + + IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);//ELS -- this is misleading! there is only one XScuGic device (0) + if (NULL == IntcConfig) { + return XST_FAILURE; + } + + Result = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, + IntcConfig->CpuBaseAddress); + if (Result != XST_SUCCESS) { + return XST_FAILURE; + } + + // Initialize the exception table and register the interrupt + // controller handler with the exception table + + Xil_ExceptionInit(); + + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler) INTC_HANDLER, IntcInstancePtr); + + // Enable non-critical exceptions + + Xil_ExceptionEnable(); + + return XST_SUCCESS; + } + +// int SetupGPIO_Interrupt(XScuGic *IntcInstancePtr) { +// int Result; +// XScuGic_SetPriorityTriggerType(IntcInstancePtr, INTC_GPIO_INTERRUPT_ID, +// 0xA0, 0x3); +// +// // Connect the interrupt handler that will be called when an +// // interrupt occurs for the device. +// +// Result = XScuGic_Connect(IntcInstancePtr, INTC_GPIO_INTERRUPT_ID, +// (Xil_ExceptionHandler) GpioIsr, &Gpio); +// if (Result != XST_SUCCESS) { +// return Result; +// } +// +// // Enable the interrupt for the GPIO device. +// +// XScuGic_Enable(IntcInstancePtr, INTC_GPIO_INTERRUPT_ID); +// +// // Enable the GPIO channel interrupts so that push button can be +// // detected and enable interrupts for the GPIO device +// +// XGpio_InterruptEnable(&Gpio, BUTTON_INTERRUPT); +// XGpio_InterruptGlobalEnable(&Gpio); +// +// return XST_SUCCESS; +// } + diff --git a/sdk/basic/src/main.h b/sdk/basic/src/main.h old mode 100755 new mode 100644 index 026a8f9b..2d53ce98 --- a/sdk/basic/src/main.h +++ b/sdk/basic/src/main.h @@ -1,9 +1,9 @@ -#ifndef __MAIN_H -#define __MAIN_H - -extern volatile u32* PECB; -extern u32 Timing100usErrorCount; - -extern int EnterProtection(); -extern int LeaveProtection(int State); -#endif //__MAIN_H +#ifndef __MAIN_H +#define __MAIN_H + +extern volatile u32* PECB; +extern u32 Timing100usErrorCount; + +extern int EnterProtection(); +extern int LeaveProtection(int State); +#endif //__MAIN_H diff --git a/sdk/basic/src/platform.c b/sdk/basic/src/platform.c old mode 100755 new mode 100644 diff --git a/sdk/basic/src/platform.h b/sdk/basic/src/platform.h old mode 100755 new mode 100644 diff --git a/sdk/basic/src/platform_config.h b/sdk/basic/src/platform_config.h old mode 100755 new mode 100644 index 58441bd3..83f0f8f5 --- a/sdk/basic/src/platform_config.h +++ b/sdk/basic/src/platform_config.h @@ -1,12 +1,12 @@ -#ifndef __PLATFORM_CONFIG_H_ -#define __PLATFORM_CONFIG_H_ - -#define STDOUT_IS_PS7_UART -#define UART_DEVICE_ID 0 -#ifdef __PPC__ -#define CACHEABLE_REGION_MASK 0xf0000001 -#endif - -#define PLATFORM_EMAC_BASEADDR XPAR_XEMACPS_0_BASEADDR - -#endif +#ifndef __PLATFORM_CONFIG_H_ +#define __PLATFORM_CONFIG_H_ + +#define STDOUT_IS_PS7_UART +#define UART_DEVICE_ID 0 +#ifdef __PPC__ +#define CACHEABLE_REGION_MASK 0xf0000001 +#endif + +#define PLATFORM_EMAC_BASEADDR XPAR_XEMACPS_0_BASEADDR + +#endif diff --git a/sdk/basic/src/prog_timer.c b/sdk/basic/src/prog_timer.c old mode 100755 new mode 100644 index dc382f84..7aca545c --- a/sdk/basic/src/prog_timer.c +++ b/sdk/basic/src/prog_timer.c @@ -1,262 +1,262 @@ -/* - * timer.c - * - * Created on: Jun 13, 2014 - * Author: sever212 - */ -#if 0 -#include "platform.h" -#include "xparameters.h" -#include "netif/xadapter.h" -#include "xgpio.h" -#include "xscutimer.h" -#include "xscugic.h" -#include "xil_exception.h" -#include "xil_printf.h" -#include "xuartps_hw.h" -#include -#include "commands.h" -#include "Log.h" -#include "prog_timer.h" -#include "lwip_glue.h" -#endif -#include "project_include.h" - -static void TimerIntrHandler(void *CallBackRef); -static int TimerSetupIntrSystem(XScuGic *IntcInstancePtr, - XScuTimer *TimerInstancePtr, u16 TimerIntrId); -//static void TimerDisableIntrSystem(XScuGic *IntcInstancePtr, u16 TimerIntrId); - -volatile u32 MainTimerTimerTick; -volatile char bTimer100usTick = 0; -volatile u32 Timing10usErrorCount = 0; - -int SetupTimer(XScuGic *IntcInstancePtr, XScuTimer * TimerInstancePtr, - u16 TimerDeviceId, u16 TimerIntrId) -{ - int Status; - //int Timer10ms = 0; - XScuTimer_Config *ConfigPtr; - - /* - * Initialize the Scu Private Timer driver. - */ - ConfigPtr = XScuTimer_LookupConfig(TimerDeviceId); - - /* - * This is where the virtual address would be used, this example - * uses physical address. - */ - Status = XScuTimer_CfgInitialize(TimerInstancePtr, ConfigPtr, - ConfigPtr->BaseAddr); - if (Status != XST_SUCCESS) { - return XST_FAILURE; - } - - /* - * Perform a self-test to ensure that the hardware was built correctly. - */ - Status = XScuTimer_SelfTest(TimerInstancePtr); - if (Status != XST_SUCCESS) { - return XST_FAILURE; - } - - /* - * Connect the device to interrupt subsystem so that interrupts - * can occur. - */ - Status = TimerSetupIntrSystem(IntcInstancePtr, - TimerInstancePtr, TimerIntrId); - if (Status != XST_SUCCESS) { - return XST_FAILURE; - } - - /* - * Enable Auto reload mode. - */ - XScuTimer_EnableAutoReload(TimerInstancePtr); - - /* - * Load the timer counter register. - */ - XScuTimer_LoadTimer(TimerInstancePtr, TIMER_LOAD_VALUE); - - /* - * Start the timer counter and then wait for it - * to timeout a number of times. - */ - XScuTimer_Start(TimerInstancePtr); - - return XST_SUCCESS; -} - - - -/***************************** - * TimeElapsed10us() - * Return the time elapsed since old in units of 10us - * - * - * old: an old timer tick value - */ -u32 TimeElapsed10us(u32 old) -{ - if (MainTimerTimerTick >= old) - return (MainTimerTimerTick - old); - else - return (0xFFFFFFFF - (old - MainTimerTimerTick)) + 1; -} - -/*****************************************************************************/ -/** -* -* This function sets up the interrupt system such that interrupts can occur -* for the device. -* -* @param IntcInstancePtr is a pointer to the instance of XScuGic driver. -* @param TimerInstancePtr is a pointer to the instance of XScuTimer -* driver. -* @param TimerIntrId is the Interrupt Id of the XScuTimer device. -* -* @return XST_SUCCESS if successful, otherwise XST_FAILURE. -* -* @note None. -* -******************************************************************************/ -static int TimerSetupIntrSystem(XScuGic *IntcInstancePtr, - XScuTimer *TimerInstancePtr, u16 TimerIntrId) -{ - int Status; - - XScuGic_SetPriorityTriggerType(IntcInstancePtr, TimerIntrId, /*0xA8*/ 0 /*0xA0*/, 0x3); - - /* - * Connect the device driver handler that will be called when an - * interrupt for the device occurs, the handler defined above performs - * the specific interrupt processing for the device. - */ - Status = XScuGic_Connect(IntcInstancePtr, TimerIntrId, - (Xil_ExceptionHandler)TimerIntrHandler, - (void *)TimerInstancePtr); - if (Status != XST_SUCCESS) { - return Status; - } - - /* - * Enable the interrupt for the device. - */ - XScuGic_Enable(IntcInstancePtr, TimerIntrId); - - /* - * Enable the timer interrupts for timer mode. - */ - XScuTimer_EnableInterrupt(TimerInstancePtr); - - - return XST_SUCCESS; -} - -/*****************************************************************************/ -/** -* -* This function is the Interrupt handler for the Timer interrupt of the -* Timer device. It is called on the expiration of the timer counter in -* interrupt context. -* -* @param CallBackRef is a pointer to the callback function. -* -* @return None. -* -* @note None. -* -******************************************************************************/ -static void TimerIntrHandler(void *CallBackRef) -{ - - XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef; - //static u32 local1us = 0; - static u32 tickTo10Counter = 0, tickTo1msCounter = 0; - static u32 Eth_1ms = 0; - /* - * Check if the timer counter has expired, checking is not necessary - * since that's the reason this function is executed, this just shows - * how the callback reference can be used as a pointer to the instance - * of the timer counter that expired, increment a shared variable so - * the main thread of execution can see the timer expired. - */ - if (XScuTimer_IsExpired(TimerInstancePtr)) { - XScuTimer_ClearInterruptStatus(TimerInstancePtr); - - MainTimerTimerTick++; - //local1us += 10; - - if (++tickTo10Counter > 9) - { - //every 100 us code - - bTimer100usTick = 1; - tickTo10Counter = 0; - - if (++tickTo1msCounter > 9) - { - //every 1ms code - - if ( (++Eth_1ms > 249) && (bEnableEthTimer == TRUE) ) - { - Eth_1ms = 0; - - //Ethernet stuff needs to be dealt with every 250ms - bEth250ms = TRUE; - } - } - - } - - DoLogging(); - - /*if (Timer10ms == 500) - { - Timer10ms = 0; - if (bTimer) - print("5 seconds elapsed\r\n"); - } - if (local1us >= 1000) - { - local1us = 0; - }*/ - - /*TimerExpired++; - if (TimerExpired == 3) { - XScuTimer_DisableAutoReload(TimerInstancePtr); - }*/ - - if (XScuTimer_IsExpired(TimerInstancePtr)) - Timing10usErrorCount++; - } - -} - -/*****************************************************************************/ -/** -* -* This function disables the interrupts that occur for the device. -* -* @param IntcInstancePtr is the pointer to the instance of XScuGic -* driver. -* @param TimerIntrId is the Interrupt Id for the device. -* -* @return None. -* -* @note None. -* -******************************************************************************/ -//#if 0 -void TimerDisableIntrSystem(XScuGic *IntcInstancePtr, u16 TimerIntrId) -{ - /* - * Disconnect and disable the interrupt for the Timer. - */ - XScuGic_Disconnect(IntcInstancePtr, TimerIntrId); -} -//#endif - +/* + * timer.c + * + * Created on: Jun 13, 2014 + * Author: sever212 + */ +#if 0 +#include "platform.h" +#include "xparameters.h" +#include "netif/xadapter.h" +#include "xgpio.h" +#include "xscutimer.h" +#include "xscugic.h" +#include "xil_exception.h" +#include "xil_printf.h" +#include "xuartps_hw.h" +#include +#include "commands.h" +#include "Log.h" +#include "prog_timer.h" +#include "lwip_glue.h" +#endif +#include "project_include.h" + +static void TimerIntrHandler(void *CallBackRef); +static int TimerSetupIntrSystem(XScuGic *IntcInstancePtr, + XScuTimer *TimerInstancePtr, u16 TimerIntrId); +//static void TimerDisableIntrSystem(XScuGic *IntcInstancePtr, u16 TimerIntrId); + +volatile u32 MainTimerTimerTick; +volatile char bTimer100usTick = 0; +volatile u32 Timing10usErrorCount = 0; + +int SetupTimer(XScuGic *IntcInstancePtr, XScuTimer * TimerInstancePtr, + u16 TimerDeviceId, u16 TimerIntrId) +{ + int Status; + //int Timer10ms = 0; + XScuTimer_Config *ConfigPtr; + + /* + * Initialize the Scu Private Timer driver. + */ + ConfigPtr = XScuTimer_LookupConfig(TimerDeviceId); + + /* + * This is where the virtual address would be used, this example + * uses physical address. + */ + Status = XScuTimer_CfgInitialize(TimerInstancePtr, ConfigPtr, + ConfigPtr->BaseAddr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Perform a self-test to ensure that the hardware was built correctly. + */ + Status = XScuTimer_SelfTest(TimerInstancePtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Connect the device to interrupt subsystem so that interrupts + * can occur. + */ + Status = TimerSetupIntrSystem(IntcInstancePtr, + TimerInstancePtr, TimerIntrId); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable Auto reload mode. + */ + XScuTimer_EnableAutoReload(TimerInstancePtr); + + /* + * Load the timer counter register. + */ + XScuTimer_LoadTimer(TimerInstancePtr, TIMER_LOAD_VALUE); + + /* + * Start the timer counter and then wait for it + * to timeout a number of times. + */ + XScuTimer_Start(TimerInstancePtr); + + return XST_SUCCESS; +} + + + +/***************************** + * TimeElapsed10us() + * Return the time elapsed since old in units of 10us + * + * + * old: an old timer tick value + */ +u32 TimeElapsed10us(u32 old) +{ + if (MainTimerTimerTick >= old) + return (MainTimerTimerTick - old); + else + return (0xFFFFFFFF - (old - MainTimerTimerTick)) + 1; +} + +/*****************************************************************************/ +/** +* +* This function sets up the interrupt system such that interrupts can occur +* for the device. +* +* @param IntcInstancePtr is a pointer to the instance of XScuGic driver. +* @param TimerInstancePtr is a pointer to the instance of XScuTimer +* driver. +* @param TimerIntrId is the Interrupt Id of the XScuTimer device. +* +* @return XST_SUCCESS if successful, otherwise XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +static int TimerSetupIntrSystem(XScuGic *IntcInstancePtr, + XScuTimer *TimerInstancePtr, u16 TimerIntrId) +{ + int Status; + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, TimerIntrId, /*0xA8*/ 0 /*0xA0*/, 0x3); + + /* + * Connect the device driver handler that will be called when an + * interrupt for the device occurs, the handler defined above performs + * the specific interrupt processing for the device. + */ + Status = XScuGic_Connect(IntcInstancePtr, TimerIntrId, + (Xil_ExceptionHandler)TimerIntrHandler, + (void *)TimerInstancePtr); + if (Status != XST_SUCCESS) { + return Status; + } + + /* + * Enable the interrupt for the device. + */ + XScuGic_Enable(IntcInstancePtr, TimerIntrId); + + /* + * Enable the timer interrupts for timer mode. + */ + XScuTimer_EnableInterrupt(TimerInstancePtr); + + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function is the Interrupt handler for the Timer interrupt of the +* Timer device. It is called on the expiration of the timer counter in +* interrupt context. +* +* @param CallBackRef is a pointer to the callback function. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void TimerIntrHandler(void *CallBackRef) +{ + + XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef; + //static u32 local1us = 0; + static u32 tickTo10Counter = 0, tickTo1msCounter = 0; + static u32 Eth_1ms = 0; + /* + * Check if the timer counter has expired, checking is not necessary + * since that's the reason this function is executed, this just shows + * how the callback reference can be used as a pointer to the instance + * of the timer counter that expired, increment a shared variable so + * the main thread of execution can see the timer expired. + */ + if (XScuTimer_IsExpired(TimerInstancePtr)) { + XScuTimer_ClearInterruptStatus(TimerInstancePtr); + + MainTimerTimerTick++; + //local1us += 10; + + if (++tickTo10Counter > 9) + { + //every 100 us code + + bTimer100usTick = 1; + tickTo10Counter = 0; + + if (++tickTo1msCounter > 9) + { + //every 1ms code + + if ( (++Eth_1ms > 249) && (bEnableEthTimer == TRUE) ) + { + Eth_1ms = 0; + + //Ethernet stuff needs to be dealt with every 250ms + bEth250ms = TRUE; + } + } + + } + + DoLogging(); + + /*if (Timer10ms == 500) + { + Timer10ms = 0; + if (bTimer) + print("5 seconds elapsed\r\n"); + } + if (local1us >= 1000) + { + local1us = 0; + }*/ + + /*TimerExpired++; + if (TimerExpired == 3) { + XScuTimer_DisableAutoReload(TimerInstancePtr); + }*/ + + if (XScuTimer_IsExpired(TimerInstancePtr)) + Timing10usErrorCount++; + } + +} + +/*****************************************************************************/ +/** +* +* This function disables the interrupts that occur for the device. +* +* @param IntcInstancePtr is the pointer to the instance of XScuGic +* driver. +* @param TimerIntrId is the Interrupt Id for the device. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +//#if 0 +void TimerDisableIntrSystem(XScuGic *IntcInstancePtr, u16 TimerIntrId) +{ + /* + * Disconnect and disable the interrupt for the Timer. + */ + XScuGic_Disconnect(IntcInstancePtr, TimerIntrId); +} +//#endif + diff --git a/sdk/basic/src/prog_timer.h b/sdk/basic/src/prog_timer.h old mode 100755 new mode 100644 index 4c34a479..49a8899b --- a/sdk/basic/src/prog_timer.h +++ b/sdk/basic/src/prog_timer.h @@ -1,22 +1,22 @@ - -#ifndef __PROG_TIMER_H -#define __PROG_TIMER_H -#include "xscutimer.h" -#include "xscugic.h" - -#define TIMER_DEVICE_ID XPAR_XSCUTIMER_0_DEVICE_ID -#define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR -#define TIMER_INTERVAL 10 //value in us -#define TIMER_LOAD_VALUE (TIMER_INTERVAL*666.66666667)/2 //0xFFFF // = timerInterval*ClockFreq/2 - - -extern volatile u32 MainTimerTimerTick; -extern volatile char bTimer100usTick; -extern volatile u32 Timing10usErrorCount; - - -extern int SetupTimer(XScuGic *IntcInstancePtr, XScuTimer * TimerInstancePtr, - u16 TimerDeviceId, u16 TimerIntrId); -extern u32 TimeElapsed10us(u32 old); -extern void TimerDisableIntrSystem(XScuGic *IntcInstancePtr, u16 TimerIntrId); -#endif //__PROG_TIMER_H + +#ifndef __PROG_TIMER_H +#define __PROG_TIMER_H +#include "xscutimer.h" +#include "xscugic.h" + +#define TIMER_DEVICE_ID XPAR_XSCUTIMER_0_DEVICE_ID +#define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR +#define TIMER_INTERVAL 10 //value in us +#define TIMER_LOAD_VALUE (TIMER_INTERVAL*666.66666667)/2 //0xFFFF // = timerInterval*ClockFreq/2 + + +extern volatile u32 MainTimerTimerTick; +extern volatile char bTimer100usTick; +extern volatile u32 Timing10usErrorCount; + + +extern int SetupTimer(XScuGic *IntcInstancePtr, XScuTimer * TimerInstancePtr, + u16 TimerDeviceId, u16 TimerIntrId); +extern u32 TimeElapsed10us(u32 old); +extern void TimerDisableIntrSystem(XScuGic *IntcInstancePtr, u16 TimerIntrId); +#endif //__PROG_TIMER_H diff --git a/sdk/basic/src/project_include.h b/sdk/basic/src/project_include.h old mode 100755 new mode 100644 index f3183d26..d244d1e5 --- a/sdk/basic/src/project_include.h +++ b/sdk/basic/src/project_include.h @@ -1,49 +1,49 @@ -#ifndef __PROJECT_INCLUDE_H -#define __PROJECT_INCLUDE_H -#include -#include -#include -#include - -#include "platform.h" -#include "xparameters.h" -#include "xparameters_ps.h" /* defines XPAR values */ -#include "xil_cache.h" -#include "netif/xadapter.h" -// #include "xgpio.h" -#include "xscutimer.h" -#include "xscugic.h" -#include "xil_exception.h" -#include "xil_printf.h" -#include "xuartps_hw.h" -#include "xtmrctr.h" - -//LWIP -#include "lwip/tcp.h" -#include "lwip/tcp_impl.h" -#include "lwip/init.h" - -#include "platform_config.h" -#include "project_settings.h" -#include "commands.h" -#include "main.h" -#include "log.h" -#include "prog_timer.h" -#include "axi_timer.h" -#include "lwip_glue.h" -#include "control.h" -#include "io_pecb.h" - -#include "../bsp/bsp.h" - -//Control applications (maybe make this conditional) -#include "../control_apps/VSI_DQ_SVPWM.h" -#include "../control_apps/HBridge_CC.h" -#include "../control_apps/PosContTry1.h" -#include "../control_apps/TorqueVSI.h" -#include "ControlApp.h" - - - -#endif //__PROJECT_INCLUDE_H - +#ifndef __PROJECT_INCLUDE_H +#define __PROJECT_INCLUDE_H +#include +#include +#include +#include + +#include "platform.h" +#include "xparameters.h" +#include "xparameters_ps.h" /* defines XPAR values */ +#include "xil_cache.h" +#include "netif/xadapter.h" +// #include "xgpio.h" +#include "xscutimer.h" +#include "xscugic.h" +#include "xil_exception.h" +#include "xil_printf.h" +#include "xuartps_hw.h" +#include "xtmrctr.h" + +//LWIP +#include "lwip/tcp.h" +#include "lwip/tcp_impl.h" +#include "lwip/init.h" + +#include "platform_config.h" +#include "project_settings.h" +#include "commands.h" +#include "main.h" +#include "log.h" +#include "prog_timer.h" +#include "axi_timer.h" +#include "lwip_glue.h" +#include "control.h" +#include "io_pecb.h" + +#include "../bsp/bsp.h" + +//Control applications (maybe make this conditional) +#include "../control_apps/VSI_DQ_SVPWM.h" +#include "../control_apps/HBridge_CC.h" +#include "../control_apps/PosContTry1.h" +#include "../control_apps/TorqueVSI.h" +#include "ControlApp.h" + + + +#endif //__PROJECT_INCLUDE_H + diff --git a/sdk/basic/src/project_settings.h b/sdk/basic/src/project_settings.h old mode 100755 new mode 100644 index 44b3a56f..89beb03f --- a/sdk/basic/src/project_settings.h +++ b/sdk/basic/src/project_settings.h @@ -1,22 +1,22 @@ -#ifndef __PROJECT_SETTINGS_H -#define __PROJECT_SETTINGS_H - -#define NUM_ADCS 12 -#define NUM_LEGS 20 - -//communications -#define MAX_BASE_SOCKETS 5 -#define MAX_SEND_PACKET_SIZE (2*8192) - -#define TRUE 1 -#define FALSE 0 - -//general status codes -#define SUCCESS 1 -#define INVALID_ARGUMENT -2 -#define INVALID_OPERATION -3 -#define NOT_FOUND -4 -#define OVERFLOW -5 - -#endif //__PROJECT_SETTINGS_H - +#ifndef __PROJECT_SETTINGS_H +#define __PROJECT_SETTINGS_H + +#define NUM_ADCS 12 +#define NUM_LEGS 20 + +//communications +#define MAX_BASE_SOCKETS 5 +#define MAX_SEND_PACKET_SIZE (2*8192) + +#define TRUE 1 +#define FALSE 0 + +//general status codes +#define SUCCESS 1 +#define INVALID_ARGUMENT -2 +#define INVALID_OPERATION -3 +#define NOT_FOUND -4 +#define OVERFLOW -5 + +#endif //__PROJECT_SETTINGS_H + diff --git a/sdk/freertos_app_cpu0/.cproject b/sdk/freertos_app_cpu0/.cproject index 12744bde..192e8a67 100644 --- a/sdk/freertos_app_cpu0/.cproject +++ b/sdk/freertos_app_cpu0/.cproject @@ -1,198 +1,260 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/freertos_app_cpu0/.project b/sdk/freertos_app_cpu0/.project index 23ac0f12..f945779c 100644 --- a/sdk/freertos_app_cpu0/.project +++ b/sdk/freertos_app_cpu0/.project @@ -1,38 +1,38 @@ - - - freertos_app_cpu0 - Created by SDK v2019.1. amdc_freertos_bsp_cpu0 - ps7_cortexa9_0 - - amdc_freertos_bsp_cpu0 - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - - org.eclipse.cdt.core.cnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - - - - FreeRTOS-Kernel - 2 - S:/School/WEMPEC/firmware-rtos-e/sdk/FreeRTOS-Kernel - - - shared - 2 - S:/School/WEMPEC/firmware-rtos-e/sdk/shared - - - + + + freertos_app_cpu0 + Created by SDK v2019.1. amdc_freertos_bsp_cpu0 - ps7_cortexa9_0 + + amdc_freertos_bsp_cpu0 + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + FreeRTOS-Kernel + 2 + C:/Users/srich008/Information/v2-staging/sdk/FreeRTOS-Kernel + + + shared + 2 + C:/Users/srich008/Information/gitMistakes/freertos-singlecore/sdk/shared + + + diff --git a/sdk/freertos_app_cpu0/src/FreeRTOSConfig.h b/sdk/freertos_app_cpu0/src/FreeRTOSConfig.h index b92d6969..5f69cf13 100644 --- a/sdk/freertos_app_cpu0/src/FreeRTOSConfig.h +++ b/sdk/freertos_app_cpu0/src/FreeRTOSConfig.h @@ -1,247 +1,249 @@ -/* README!!! - * - * This configuration is copied from the FreeRTOS v10.1.1 - * based example project for the Zynq 7000 platform (for - * compatibility). However, you can add to it. - * - * Another example configuration file is available at - * "sdk/FreeRTOS-Kernel/examples/sample_configuration/FreeRTOSConfig.h" - * Because that example is in the submodule, it may update - * from time-to-time when the submodule is updated. - */ - -/* - * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * http://www.FreeRTOS.org - * http://aws.amazon.com/freertos - * - * 1 tab == 4 spaces! - */ - -#ifndef FREERTOS_CONFIG_H -#define FREERTOS_CONFIG_H - -#include "xparameters.h" - -/*----------------------------------------------------------- - * Application specific definitions. - * - * These definitions should be adjusted for your particular hardware and - * application requirements. - * - * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE - * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. - * - * See http://www.freertos.org/a00110.html - *----------------------------------------------------------*/ - -/* - * The FreeRTOS Cortex-A port implements a full interrupt nesting model. - * - * Interrupts that are assigned a priority at or below - * configMAX_API_CALL_INTERRUPT_PRIORITY (which counter-intuitively in the ARM - * generic interrupt controller [GIC] means a priority that has a numerical - * value above configMAX_API_CALL_INTERRUPT_PRIORITY) can call FreeRTOS safe API - * functions and will nest. - * - * Interrupts that are assigned a priority above - * configMAX_API_CALL_INTERRUPT_PRIORITY (which in the GIC means a numerical - * value below configMAX_API_CALL_INTERRUPT_PRIORITY) cannot call any FreeRTOS - * API functions, will nest, and will not be masked by FreeRTOS critical - * sections (although it is necessary for interrupts to be globally disabled - * extremely briefly as the interrupt mask is updated in the GIC). - * - * FreeRTOS functions that can be called from an interrupt are those that end in - * "FromISR". FreeRTOS maintains a separate interrupt safe API to enable - * interrupt entry to be shorter, faster, simpler and smaller. - * - * The Zynq implements 256 unique interrupt priorities. For the purpose of - * setting configMAX_API_CALL_INTERRUPT_PRIORITY 255 represents the lowest - * priority. - */ -#define configMAX_API_CALL_INTERRUPT_PRIORITY 18 - -#define configCPU_CLOCK_HZ 100000000UL -#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 -#define configUSE_TICKLESS_IDLE 0 -#define configTICK_RATE_HZ ((TickType_t) 1000) -#define configPERIPHERAL_CLOCK_HZ (33333000UL) -#define configUSE_PREEMPTION 1 -#define configUSE_IDLE_HOOK 0 // TODO: For low-power, set 1 and implement vApplicationIdleHook() -#define configUSE_TICK_HOOK 0 // TODO: Set as 1 if we want to run function every tick -#define configMAX_PRIORITIES (7) -#define configTOTAL_HEAP_SIZE (125 * 1024) -#define configMAX_TASK_NAME_LEN (10) -#define configUSE_TRACE_FACILITY 1 -#define configUSE_16_BIT_TICKS 0 -#define configIDLE_SHOULD_YIELD 1 -#define configUSE_MUTEXES 1 -#define configQUEUE_REGISTRY_SIZE 8 -#define configCHECK_FOR_STACK_OVERFLOW 0 -#define configUSE_RECURSIVE_MUTEXES 1 -#define configUSE_MALLOC_FAILED_HOOK 0 -#define configUSE_APPLICATION_TASK_TAG 0 -#define configUSE_COUNTING_SEMAPHORES 1 -#define configUSE_QUEUE_SETS 1 -#define configSUPPORT_DYNAMIC_ALLOCATION 1 -#define configSUPPORT_STATIC_ALLOCATION 1 - -/* AMDC ADDITION: Need to specify this callback config so we can create message buffers with callbacks - * This is done for Inter-Core Communication (src/sys/icc.c) */ -#define configUSE_SB_COMPLETED_CALLBACK 1 - -/* Include the query-heap CLI command to query the free heap space. */ -#define configINCLUDE_QUERY_HEAP_COMMAND 1 - -/* Co-routine definitions. */ -#define configUSE_CO_ROUTINES 0 -#define configMAX_CO_ROUTINE_PRIORITIES (2) - -/* Software timer definitions. */ -#define configUSE_TIMERS 1 -#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) -#define configTIMER_QUEUE_LENGTH 5 -#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) - -/* If configUSE_TASK_FPU_SUPPORT is set to 1 (or undefined) then each task will -be created without an FPU context, and a task must call vTaskUsesFPU() before -making use of any FPU registers. If configUSE_TASK_FPU_SUPPORT is set to 2 then -tasks are created with an FPU context by default, and calling vTaskUsesFPU() has -no effect. */ -#define configUSE_TASK_FPU_SUPPORT 2 -#define configMINIMAL_STACK_SIZE ((unsigned short) 250) // Large since all tasks have FPU context - -/* Set the following definitions to 1 to include the API function, or zero -to exclude the API function. */ -#define INCLUDE_vTaskPrioritySet 1 -#define INCLUDE_uxTaskPriorityGet 1 -#define INCLUDE_vTaskDelete 1 -#define INCLUDE_vTaskCleanUpResources 1 -#define INCLUDE_vTaskSuspend 1 -#define INCLUDE_vTaskDelayUntil 1 -#define INCLUDE_vTaskDelay 1 -#define INCLUDE_xTimerPendFunctionCall 1 -#define INCLUDE_eTaskGetState 1 -#define INCLUDE_xTaskAbortDelay 1 -#define INCLUDE_xTaskGetTaskHandle 1 -#define INCLUDE_xTaskGetHandle 1 -#define INCLUDE_xSemaphoreGetMutexHolder 1 - -/* This demo makes use of one or more example stats formatting functions. These -format the raw data provided by the uxTaskGetSystemState() function in to human -readable ASCII form. See the notes in the implementation of vTaskList() within -FreeRTOS/Source/tasks.c for limitations. */ -#define configUSE_STATS_FORMATTING_FUNCTIONS 0 - -/* The private watchdog is used to generate run time stats. */ -/* -#include "xscuwdt.h" -extern XScuWdt xWatchDogInstance; -extern void vInitialiseTimerForRunTimeStats( void ); -#define configGENERATE_RUN_TIME_STATS 1 -#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vInitialiseTimerForRunTimeStats() -#define portGET_RUN_TIME_COUNTER_VALUE() ( ( 0xffffffffUL - XScuWdt_ReadReg( xWatchDogInstance.Config.BaseAddr, -XSCUWDT_COUNTER_OFFSET ) ) >> 1 ) -*/ - -/* The size of the global output buffer that is available for use when there -are multiple command interpreters running at once (for example, one on a UART -and one on TCP/IP). This is done to prevent an output buffer being defined by -each implementation - which would waste RAM. In this case, there is only one -command interpreter running. */ -#define configCOMMAND_INT_MAX_OUTPUT_SIZE 2096 - -/* Normal assert() semantics without relying on the provision of an assert.h -header file. */ -void vAssertCalled(const char *pcFile, unsigned long ulLine); - -// Original Implementation -//#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ); - -#define configASSERT(x) \ - if ((x) == 0) \ - while (1) \ - ; - -/* If configTASK_RETURN_ADDRESS is not defined then a task that attempts to -return from its implementing function will end up in a "task exit error" -function - which contains a call to configASSERT(). However this can give GCC -some problems when it tries to unwind the stack, as the exit error function has -nothing to return to. To avoid this define configTASK_RETURN_ADDRESS to 0. */ -#define configTASK_RETURN_ADDRESS NULL - -/****** Hardware specific settings. *******************************************/ - -/* - * The application must provide a function that configures a peripheral to - * create the FreeRTOS tick interrupt, then define configSETUP_TICK_INTERRUPT() - * in FreeRTOSConfig.h to call the function. This file contains a function - * that is suitable for use on the Zynq MPU. FreeRTOS_Tick_Handler() must - * be installed as the peripheral's interrupt handler. - */ -void vConfigureTickInterrupt(void); -#define configSETUP_TICK_INTERRUPT() vConfigureTickInterrupt() - -void vClearTickInterrupt(void); -#define configCLEAR_TICK_INTERRUPT() vClearTickInterrupt() - -/* The following constant describe the hardware, and are correct for the -Zynq MPU. */ -#define configINTERRUPT_CONTROLLER_BASE_ADDRESS (XPAR_PS7_SCUGIC_0_DIST_BASEADDR) -#define configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET (-0xf00) -#define configUNIQUE_INTERRUPT_PRIORITIES 32 - -/****** Network configuration settings - only used when the lwIP example is -built. See the page that documents this demo on the http://www.FreeRTOS.org -website for more information. ***********************************************/ - -/* The priority for the task that unblocked by the MAC interrupt to process -received packets. */ -#define configMAC_INPUT_TASK_PRIORITY (configMAX_PRIORITIES - 1) - -/* The priority of the task that runs the lwIP stack. */ -#define configLWIP_TASK_PRIORITY (configMAX_PRIORITIES - 2) - -/* The priority of the task that uses lwIP sockets to provide a simple command -line interface. */ -#define configCLI_TASK_PRIORITY (tskIDLE_PRIORITY) - -/* MAC address configuration. */ -#define configMAC_ADDR0 0x00 -#define configMAC_ADDR1 0x13 -#define configMAC_ADDR2 0x14 -#define configMAC_ADDR3 0x15 -#define configMAC_ADDR4 0x15 -#define configMAC_ADDR5 0x16 - -/* IP address configuration. */ -#define configIP_ADDR0 172 -#define configIP_ADDR1 25 -#define configIP_ADDR2 218 -#define configIP_ADDR3 200 - -/* Netmask configuration. */ -#define configNET_MASK0 255 -#define configNET_MASK1 255 -#define configNET_MASK2 255 -#define configNET_MASK3 0 - -#endif /* FREERTOS_CONFIG_H */ +/* README!!! + * + * This configuration is copied from the FreeRTOS v10.1.1 + * based example project for the Zynq 7000 platform (for + * compatibility). However, you can add to it. + * + * Another example configuration file is available at + * "sdk/FreeRTOS-Kernel/examples/sample_configuration/FreeRTOSConfig.h" + * Because that example is in the submodule, it may update + * from time-to-time when the submodule is updated. + */ + +/* + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +#include "xparameters.h" + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html + *----------------------------------------------------------*/ + +/* + * The FreeRTOS Cortex-A port implements a full interrupt nesting model. + * + * Interrupts that are assigned a priority at or below + * configMAX_API_CALL_INTERRUPT_PRIORITY (which counter-intuitively in the ARM + * generic interrupt controller [GIC] means a priority that has a numerical + * value above configMAX_API_CALL_INTERRUPT_PRIORITY) can call FreeRTOS safe API + * functions and will nest. + * + * Interrupts that are assigned a priority above + * configMAX_API_CALL_INTERRUPT_PRIORITY (which in the GIC means a numerical + * value below configMAX_API_CALL_INTERRUPT_PRIORITY) cannot call any FreeRTOS + * API functions, will nest, and will not be masked by FreeRTOS critical + * sections (although it is necessary for interrupts to be globally disabled + * extremely briefly as the interrupt mask is updated in the GIC). + * + * FreeRTOS functions that can be called from an interrupt are those that end in + * "FromISR". FreeRTOS maintains a separate interrupt safe API to enable + * interrupt entry to be shorter, faster, simpler and smaller. + * + * The Zynq implements 256 unique interrupt priorities. For the purpose of + * setting configMAX_API_CALL_INTERRUPT_PRIORITY 255 represents the lowest + * priority. + */ +#define configMAX_API_CALL_INTERRUPT_PRIORITY 18 + +#define configCPU_CLOCK_HZ 100000000UL +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configUSE_TICKLESS_IDLE 0 +#define configTICK_RATE_HZ ((TickType_t) 10000) +#define configPERIPHERAL_CLOCK_HZ (33333000UL) +#define configUSE_PREEMPTION 1 +#define configUSE_IDLE_HOOK 0 // TODO: For low-power, set 1 and implement vApplicationIdleHook() +#define configUSE_TICK_HOOK 0 // TODO: Set as 1 if we want to run function every tick +#define configMAX_PRIORITIES (7) +#define configTOTAL_HEAP_SIZE (125 * 1024) +#define configMAX_TASK_NAME_LEN (10) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 8 +#define configCHECK_FOR_STACK_OVERFLOW 0 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_QUEUE_SETS 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* AMDC ADDITION: Need to specify this callback config so we can create message buffers with callbacks + * This is done for Inter-Core Communication (src/sys/icc.c) */ +#define configUSE_SB_COMPLETED_CALLBACK 1 + +/* Include the query-heap CLI command to query the free heap space. */ +#define configINCLUDE_QUERY_HEAP_COMMAND 1 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES (2) + +/* Software timer definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) + +/* If configUSE_TASK_FPU_SUPPORT is set to 1 (or undefined) then each task will +be created without an FPU context, and a task must call vTaskUsesFPU() before +making use of any FPU registers. If configUSE_TASK_FPU_SUPPORT is set to 2 then +tasks are created with an FPU context by default, and calling vTaskUsesFPU() has +no effect. */ +#define configUSE_TASK_FPU_SUPPORT 2 +#define configMINIMAL_STACK_SIZE ((unsigned short) 250) // Large since all tasks have FPU context + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xTaskAbortDelay 1 +#define INCLUDE_xTaskGetTaskHandle 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_xSemaphoreGetMutexHolder 1 + +/* This demo makes use of one or more example stats formatting functions. These +format the raw data provided by the uxTaskGetSystemState() function in to human +readable ASCII form. See the notes in the implementation of vTaskList() within +FreeRTOS/Source/tasks.c for limitations. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* A separate timer is used to generate run time stats. */ +#include "xscuwdt.h" +extern XScuWdt xTimerStats; +extern void vInitialiseTimerForRunTimeStats(void); +#define configGENERATE_RUN_TIME_STATS 1 +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vInitialiseTimerForRunTimeStats() +#define portGET_RUN_TIME_COUNTER_VALUE() ((0xffffffffUL - XScuWdt_ReadReg(xTimerStats.Config.BaseAddr, XSCUWDT_COUNTER_OFFSET)) >> 1) + + +/* The size of the global output buffer that is available for use when there +are multiple command interpreters running at once (for example, one on a UART +and one on TCP/IP). This is done to prevent an output buffer being defined by +each implementation - which would waste RAM. In this case, there is only one +command interpreter running. */ +#define configCOMMAND_INT_MAX_OUTPUT_SIZE 2096 + +/* Normal assert() semantics without relying on the provision of an assert.h +header file. */ +void vAssertCalled(const char *pcFile, unsigned long ulLine); + +// Original Implementation +//#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ); + +#define configASSERT(x) \ + if ((x) == 0) \ + while (1) \ + ; + +/* If configTASK_RETURN_ADDRESS is not defined then a task that attempts to +return from its implementing function will end up in a "task exit error" +function - which contains a call to configASSERT(). However this can give GCC +some problems when it tries to unwind the stack, as the exit error function has +nothing to return to. To avoid this define configTASK_RETURN_ADDRESS to 0. */ +#define configTASK_RETURN_ADDRESS NULL + +/****** Hardware specific settings. *******************************************/ + +/* + * The application must provide a function that configures a peripheral to + * create the FreeRTOS tick interrupt, then define configSETUP_TICK_INTERRUPT() + * in FreeRTOSConfig.h to call the function. This file contains a function + * that is suitable for use on the Zynq MPU. FreeRTOS_Tick_Handler() must + * be installed as the peripheral's interrupt handler. + */ +void vConfigureTickInterrupt(void); +#define configSETUP_TICK_INTERRUPT() vConfigureTickInterrupt() + +void vClearTickInterrupt(void); +#define configCLEAR_TICK_INTERRUPT() vClearTickInterrupt() + +/* The following constant describe the hardware, and are correct for the +Zynq MPU. */ +#define configINTERRUPT_CONTROLLER_BASE_ADDRESS (XPAR_PS7_SCUGIC_0_DIST_BASEADDR) +#define configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET (-0xf00) +#define configUNIQUE_INTERRUPT_PRIORITIES 32 + +/****** Network configuration settings - only used when the lwIP example is +built. See the page that documents this demo on the http://www.FreeRTOS.org +website for more information. ***********************************************/ + +/* The priority for the task that unblocked by the MAC interrupt to process +received packets. */ +#define configMAC_INPUT_TASK_PRIORITY (configMAX_PRIORITIES - 1) + +/* The priority of the task that runs the lwIP stack. */ +#define configLWIP_TASK_PRIORITY (configMAX_PRIORITIES - 2) + +/* The priority of the task that uses lwIP sockets to provide a simple command +line interface. */ +#define configCLI_TASK_PRIORITY (tskIDLE_PRIORITY) + +/* MAC address configuration. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x13 +#define configMAC_ADDR2 0x14 +#define configMAC_ADDR3 0x15 +#define configMAC_ADDR4 0x15 +#define configMAC_ADDR5 0x16 + +/* IP address configuration. */ +#define configIP_ADDR0 172 +#define configIP_ADDR1 25 +#define configIP_ADDR2 218 +#define configIP_ADDR3 200 + +/* Netmask configuration. */ +#define configNET_MASK0 255 +#define configNET_MASK1 255 +#define configNET_MASK2 255 +#define configNET_MASK3 0 + +/* MS to tick macros */ +#define pdMS_TO_TICKS(xTimeInMs) ((TickType_t) (((xTimeInMs) * (uint64_t) configTICK_RATE_HZ) / (uint64_t) 1000U)) +#define pdTICKS_TO_MS(xTimeInTicks) (((xTimeInTicks) * (uint64_t) 1000U) / (double) configTICK_RATE_HZ) + +#endif /* FREERTOS_CONFIG_H */ diff --git a/sdk/freertos_app_cpu0/src/Xilinx.spec b/sdk/freertos_app_cpu0/src/Xilinx.spec index 9c27dcad..8eea3774 100644 --- a/sdk/freertos_app_cpu0/src/Xilinx.spec +++ b/sdk/freertos_app_cpu0/src/Xilinx.spec @@ -1,2 +1,2 @@ -*startfile: -crti%O%s crtbegin%O%s +*startfile: +crti%O%s crtbegin%O%s diff --git a/sdk/freertos_app_cpu0/src/main.c b/sdk/freertos_app_cpu0/src/main.c index 9a77b434..2d827942 100644 --- a/sdk/freertos_app_cpu0/src/main.c +++ b/sdk/freertos_app_cpu0/src/main.c @@ -40,24 +40,22 @@ #include "xil_printf.h" #include "xparameters.h" /* Firmware includes */ -#include "sys/icc.h" +//#include "sys/icc.h" #include "sys/intr.h" /* Begin User Includes */ #include "drv/led.h" +#include "drv/pwm.h" +#include "drv/uart.h" +#include "sys/serial.h" +#include "sys/commands.h" +#include "sys/cmd/cmd_counter.h" +#include "sys/cmd/cmd_hw.h" +#include "usr/user_apps.h" /* End User Includes */ -#define TIMER_ID 1 -#define DELAY_10_SECONDS 10000UL #define DELAY_1_SECOND 1000UL -#define TIMER_CHECK_THRESHOLD 9 -/*-----------------------------------------------------------*/ - -/* The Tx and Rx tasks as described at the top of this file. */ -static void prvTxTask(void *pvParameters); -static void prvRxTask(void *pvParameters); -static void prvBlinkyTask(void *pvParameters); -static void vTimerCallback(TimerHandle_t pxTimer); +#define INTC_HANDLER XScuGic_InterruptHandler /*-----------------------------------------------------------*/ /* This project has configSUPPORT_STATIC_ALLOCATION set to 1 (for Inter-Core Communication) so @@ -91,50 +89,12 @@ extern void vPortInstallFreeRTOSVectorTable(void); #define QUEUE_LENGTH 10 #define ITEM_SIZE sizeof(uint32_t) -static TaskHandle_t xTxTaskHandle; -static TaskHandle_t xRxTaskHandle; -static TaskHandle_t xBlinkyTaskHandle; -static QueueHandle_t xQueue = NULL; -static TimerHandle_t xTimer = NULL; - -char HWstring[32] = "CPU0 - Hello World"; -long RxtaskCntr = 0; - -uint8_t message_status = 0; -// 0 - sending messages -// 1 - complete, success -// 2 - complete, failure - int main(void) { // Both CPUs: Disable cache on OCM // S=b1 TEX=b100 AP=b11, Domain=b1111, C=b0, B=b0 Xil_SetTlbAttributes(0xFFFF0000, 0x14de2); -#if 1 - // CPU0 ONLY: - // This code is required to start CPU1 from CPU0 during boot. - // - // This only applies when booting from flash via the FSBL. - // During development with JTAG loading, these low-level - // calls in this #if block are not needed! However, we'll - // keep them here since it doesn't affect performance... - - // Write starting base address for CPU1 PC. - // It will look for this address upon waking up - static const uintptr_t CPU1_START_ADDR = 0xFFFFFFF0; - static const uint32_t CPU1_BASE_ADDR = 0x20080000; - Xil_Out32(CPU1_START_ADDR, CPU1_BASE_ADDR); - - // Waits until write has finished - // DMB = Data Memory Barrier - dmb(); - - // Wake up CPU1 by sending the SEV command - // SEV = Set Event, which causes CPU1 to wake up and jump to CPU1_BASE_ADDR - __asm__("sev"); -#endif - Xil_ExceptionInit(); intr_init(); icc_init(); @@ -143,60 +103,27 @@ int main(void) /////////////////////////// // BEGIN USER CODE HERE // ///////////////////////// + /* initialise hardware */ led_init(); + uart_init(); + pwm_init(); + serial_init(); + commands_init(); + + /* command sets */ + cmd_counter_register(); + cmd_hw_register(); - const TickType_t x10seconds = pdMS_TO_TICKS(DELAY_10_SECONDS); - - xil_printf("CPU0 - Hello from FreeRTOS example main()!\r\n"); - - /* Create the three tasks */ - xTaskCreate(prvTxTask, /* The function that implements the task. */ - (const char *) "CPU0_Tx", /* Text name for the task, provided to assist debugging only. */ - configMINIMAL_STACK_SIZE, /* The stack allocated to the task. */ - NULL, /* The task parameter is not used, so set to NULL. */ - tskIDLE_PRIORITY, /* The task runs at the idle priority. */ - &xTxTaskHandle); - - xTaskCreate(prvRxTask, /* The function that implements the task. */ - (const char *) "CPU0_Rx", /* Text name for the task, provided to assist debugging only. */ - configMINIMAL_STACK_SIZE, - NULL, - tskIDLE_PRIORITY + 1, - &xRxTaskHandle); - - // Create additional blinky task - CPU0 only - xTaskCreate(prvBlinkyTask, - (const char *) "CPU0_Blinky", - configMINIMAL_STACK_SIZE, - NULL, - tskIDLE_PRIORITY, - &xBlinkyTaskHandle); - - /* Create the queue used by the tasks. The Rx task has a higher priority - than the Tx task, so will preempt the Tx task and remove values from the - queue as soon as the Tx task writes to the queue - therefore the queue can - never have more than one item in it. */ - xQueue = xQueueCreate(1, sizeof(HWstring)); - - /* Check the queue was created. */ - configASSERT(xQueue); - - /* Create a timer with a timer expiry of 10 seconds. The timer would expire - after 10 seconds and the timer call back would get called. In the timer call back - checks are done to ensure that the tasks have been running properly till then. - The tasks are deleted in the timer call back and a message is printed to convey that - the example has run successfully. - The timer expiry is set to 10 seconds and the timer set to not auto reload. */ - xTimer = xTimerCreate((const char *) "CPU0_Timer", x10seconds, pdFALSE, (void *) TIMER_ID, vTimerCallback); - - /* Check the timer was created. */ - configASSERT(xTimer); - - /* start the timer with a block time of 0 ticks. This means as soon - as the schedule starts the timer will start running and will expire after - 10 seconds */ - xTimerStart(xTimer, 0); + /* user apps */ + user_apps_init(); + + xil_printf("CPU0 - Hello, World!!!\r\n"); +// xil_printf("1 millisecond is %d ticks\n", pdMS_TO_TICKS(1)); +// xil_printf("0.1 milliseconds is %d ticks\n", pdMS_TO_TICKS(0.1)); +// +// xil_printf("10 ticks is %d milliseconds\n", pdTICKS_TO_MS(10)); +// xil_printf("1 ticks is %d microseconds\n", (int) (pdTICKS_TO_MS(1) * 1000)); ///////////////////////// // END USER CODE HERE // @@ -211,150 +138,7 @@ int main(void) to be created. See the memory management section on the FreeRTOS web site for more details. */ for (;;) { - } -} - -/*-----------------------------------------------------------*/ -static void prvTxTask(void *pvParameters) -{ - const TickType_t x1second = pdMS_TO_TICKS(DELAY_1_SECOND); - - for (;;) { - if (message_status > 0) { - // Cannot delete tasks created using heap_1 implementation, so instead we suspend immediately if done - vTaskSuspend(NULL); - } else { - /* Delay for 1 second. */ - vTaskDelay(x1second); - - /* Send the next value on the queue. The queue should always be - empty at this point so a block time of 0 is used. */ - // xQueueSend(xQueue, /* The queue being written to. */ - // HWstring, /* The address of the data being sent. */ - // 0UL); /* The block time. */ - - xil_printf("DEBUG: CPU 0 about to attempt send\r\n"); - - // Send a message to the other core - size_t bytes_sent = xMessageBufferSend(xCPU0to1MessageBuffer, HWstring, sizeof(HWstring), 0UL); - - xil_printf("DEBUG: CPU0 sent %d bytes to ICC buffer\r\n", bytes_sent); - - if (bytes_sent == 0) { - xil_printf("ERROR: CPU 0 failed to write to ICC buffer\r\n"); - } - } - } -} - -/*-----------------------------------------------------------*/ -static void prvRxTask(void *pvParameters) -{ - char Rcvdstring[32] = ""; - - for (;;) { - if (message_status > 0) { - // Cannot delete tasks created using heap_1 implementation, so instead we suspend immediately if done - vTaskSuspend(NULL); - } else { - - // /* Block to wait for data arriving on the queue. */ - // xQueueReceive(xQueue, /* The queue being read. */ - // Rcvdstring, /* Data is read into this address. */ - // portMAX_DELAY); /* Wait without a timeout for data. */ - - xil_printf("DEBUG: CPU 0 about to attempt rcv\r\n"); - - size_t bytes_rcvd = xMessageBufferReceive(xCPU1to0MessageBuffer, Rcvdstring, 32, portMAX_DELAY); - - xil_printf("DEBUG: CPU0 rcvd %d bytes from ICC buffer\r\n", bytes_rcvd); - - if (bytes_rcvd == 0) { - xil_printf("CPU 0 failed to receive from ICC buffer\r\n"); - } else { - /* Print the received data. */ - xil_printf("CPU0 - Rx task received string from CPU1 Tx: %s\r\n", Rcvdstring); - RxtaskCntr++; - } - } - } -} - -/*-----------------------------------------------------------*/ -static void prvBlinkyTask(void *pvParameters) -{ - const TickType_t x250ms = pdMS_TO_TICKS(DELAY_1_SECOND / 4); - uint8_t led_offset = 0; - - for (;;) { - if (message_status == 0) { - // If not complete, cycle yellow every 250ms - vTaskDelay(x250ms); - - led_set_color(0 + led_offset, LED_COLOR_YELLOW); - led_set_color(1 + led_offset, LED_COLOR_BLACK); - led_set_color(2 + led_offset, LED_COLOR_BLACK); - led_set_color(3 + led_offset, LED_COLOR_BLACK); - - led_offset = (led_offset + 1) % 4; - } else if (message_status == 1) { - // If complete, flash all green every 250ms - vTaskDelay(x250ms); - - led_set_color(LED0, LED_COLOR_BLACK); - led_set_color(LED1, LED_COLOR_BLACK); - led_set_color(LED2, LED_COLOR_BLACK); - led_set_color(LED3, LED_COLOR_BLACK); - - vTaskDelay(x250ms); - - led_set_color(LED0, LED_COLOR_GREEN); - led_set_color(LED1, LED_COLOR_GREEN); - led_set_color(LED2, LED_COLOR_GREEN); - led_set_color(LED3, LED_COLOR_GREEN); - } else { - // message_status must be 2, meaning failure - // flash all red every 250ms - vTaskDelay(x250ms); - - led_set_color(LED0, LED_COLOR_BLACK); - led_set_color(LED1, LED_COLOR_BLACK); - led_set_color(LED2, LED_COLOR_BLACK); - led_set_color(LED3, LED_COLOR_BLACK); - - vTaskDelay(x250ms); - - led_set_color(LED0, LED_COLOR_RED); - led_set_color(LED1, LED_COLOR_RED); - led_set_color(LED2, LED_COLOR_RED); - led_set_color(LED3, LED_COLOR_RED); - } - } -} - -/*-----------------------------------------------------------*/ -static void vTimerCallback(TimerHandle_t pxTimer) -{ - long lTimerId; - configASSERT(pxTimer); - - lTimerId = (long) pvTimerGetTimerID(pxTimer); - - if (lTimerId != TIMER_ID) { - xil_printf("CPU0 - FreeRTOS Hello World Example FAILED"); - } - - /* If the RxtaskCntr is updated every time the Rx task is called. The - Rx task is called every time the Tx task sends a message. The Tx task - sends a message every 1 second. - The timer expires after 10 seconds. We expect the RxtaskCntr to at least - have a value of 9 (TIMER_CHECK_THRESHOLD) when the timer expires. */ - if (RxtaskCntr >= TIMER_CHECK_THRESHOLD) { - message_status = 1; - xil_printf("CPU0 - FreeRTOS Hello World Example PASSED\r\n"); - } else { - message_status = 2; - xil_printf("CPU0 - FreeRTOS Hello World Example FAILED\r\n"); + xil_printf("IF YOU'RE READING THIS THEN A TERRIBLE ERROR HAS OCCURRED!\n"); } } @@ -410,3 +194,39 @@ void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, * configMINIMAL_STACK_SIZE is specified in words, not bytes. */ *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; } + +/*******************************************************************************/ +/* S E T U P I N T E R R U P T S Y S T E M */ +/*******************************************************************************/ +int SetupInterruptSystem(XScuGic *IntcInstancePtr) { + int Result; + + XScuGic_Config *IntcConfig; + + // Initialize the interrupt controller driver so that it is ready to use. + + IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);//ELS -- this is misleading! there is only one XScuGic device (0) + if (NULL == IntcConfig) { + return XST_FAILURE; + } + + Result = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, + IntcConfig->CpuBaseAddress); + if (Result != XST_SUCCESS) { + return XST_FAILURE; + } + + // Initialize the exception table and register the interrupt + // controller handler with the exception table + + Xil_ExceptionInit(); + + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler) INTC_HANDLER, IntcInstancePtr); + + // Enable non-critical exceptions + + Xil_ExceptionEnable(); + + return XST_SUCCESS; +} diff --git a/sdk/freertos_app_cpu0/src/usr/blink/README.md b/sdk/freertos_app_cpu0/src/usr/blink/README.md new file mode 100644 index 00000000..286e9351 --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/blink/README.md @@ -0,0 +1,41 @@ +# Blink Application + +This is a minimal application which shows how to use both commands and tasks. + +## Usage + +Follow the guide to load this application onto AMDC hardware. Connect to the UART serial port via your PC (115200 baud). + +Once started, the RGB LED should begin cycling colors. The start-up messages should appear on the serial terminal. The list of available commands will appear. Try issuing the `blink hello ` command. + +View the source code for the following files to learn how the application is implemented. + +## Files + +The application directory structure contains the minimal set of files to have a functioning app with a single command and task. All application files live in the application directory (`usr/blink/`). + +``` +blink/ +|-- cmd/ +| |-- cmd_blink.c +| |-- cmd_blink.h +|-- app_blink.c +|-- app_blink.h +|-- task_blink.c +|-- task_blink.h +``` + +### [`app_blink.c`](app_blink.c) + +- Every application needs a top-level app file. +- This is called for app initialization during start-up. +- Users define what this app init function does. + +### [`task_blink.c`](task_blink.c) + +- This task cycles through the red, green, and blue LED colors at 1Hz. + +### [`cmd/cmd_blink.c`](cmd/cmd_blink.c) + +- This command echos the user-supplied name back to the terminal. +- Be careful, not all names are welcome! diff --git a/sdk/freertos_app_cpu0/src/usr/blink/app_blink.c b/sdk/freertos_app_cpu0/src/usr/blink/app_blink.c new file mode 100644 index 00000000..e0c6d054 --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/blink/app_blink.c @@ -0,0 +1,19 @@ +#ifdef APP_BLINK + +#include "usr/blink/app_blink.h" +#include "usr/blink/cmd/cmd_blink.h" +#include "usr/blink/task_blink.h" +#include "usr/blink/task_vsi.h" + +void app_blink_init(void) +{ + // Register "blink" command with system + cmd_blink_register(); + + // Initialize blink task with system + task_blink_init(); + + task_vsi_init(); +} + +#endif // APP_BLINK diff --git a/sdk/freertos_app_cpu0/src/usr/blink/app_blink.h b/sdk/freertos_app_cpu0/src/usr/blink/app_blink.h new file mode 100644 index 00000000..cabaaa63 --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/blink/app_blink.h @@ -0,0 +1,6 @@ +#ifndef APP_BLINK_H +#define APP_BLINK_H + +void app_blink_init(void); + +#endif // APP_BLINK_H diff --git a/sdk/freertos_app_cpu0/src/usr/blink/cmd/cmd_blink.c b/sdk/freertos_app_cpu0/src/usr/blink/cmd/cmd_blink.c new file mode 100644 index 00000000..c4109ef8 --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/blink/cmd/cmd_blink.c @@ -0,0 +1,140 @@ +#ifdef APP_BLINK + +#include "usr/blink/cmd/cmd_blink.h" +#include "sys/commands.h" +#include "sys/debug.h" +#include "sys/defines.h" +#include "sys/util.h" +#include "usr/blink/task_blink.h" +#include +#include + +// Stores command entry for command system module +static command_entry_t cmd_entry; + +// Defines help content displayed for this command +// when user types "help" at command prompt +static command_help_t cmd_help[] = { + { "hello ", "Print hello to screen" }, + { "init", "Start task" }, + { "deinit", "Stop task" }, + { "stats print", "Print stats" }, + { "stats reset", "Reset stats" }, +}; + +void cmd_blink_register(void) +{ + // Populate the command entry block + // + // Here is where you define the base command string: "blink" + // and what function is called to handle command + commands_cmd_init(&cmd_entry, "blink", "Blink application commands", cmd_help, ARRAY_SIZE(cmd_help), cmd_blink); + + // Register the command with the system + commands_cmd_register(&cmd_entry); +} + +int cmd_blink(int argc, char **argv) +{ + // This function is called every time the user types "blink" + // followed by a space and any number of characters. + // + // Example user input: blink foo 123 + // + // It is up to the application developer to handle this + // incoming command in a manner that reflects this command's + // help message, as to not confuse the user. + // + // The arguments passed into this function (argc & argv) + // follow standard C convention for main() programs called + // via command line interface (CLI). + // + // 'argc' is the number of CLI arguments, including the base command + // For above example: argc = 3 + // + // 'argv' is an array of char strings which contain the CLI arguments + // For above example: + // - argv[0] => "blink" + // - argv[1] => "foo" + // - argv[2] => "123" + // + // NOTE: The system constrains user CLI input to ensure responsive + // behavior for arbitrary commands. This involves limiting individual + // command argument length as well as the total number of arguments + // (this is defined in sys/commands.c) + + // Handle 'hello' sub-command + // + // First, verify correct number of arguments (2) + // Second, verify second argument is "hello" + if (argc == 3 && strcmp("hello", argv[1]) == 0) { + // Perform desired action for command... + + // Fun example: hello message based on name + if (strcmp("nathan", argv[2]) == 0) { + // Wow, happy to talk to Nathan! + debug_printf("Welcome, sir Nathan!!!\r\n"); + debug_print("\r\n"); + + // Indicate success, but hide SUCCESS message + return CMD_SUCCESS_QUIET; + + } else if (strcmp("fred", argv[2]) == 0) { + // We don't want to talk to Fred... :( + // Treat this case as an invalid command input from user + return CMD_INVALID_ARGUMENTS; + + } else { + // Normal hello for anyone else + debug_printf("Hello, %s\r\n", argv[2]); + debug_print("\r\n"); + + // Indicate success, but hide SUCCESS message + return CMD_SUCCESS_QUIET; + } + + // If user typed a valid command, return SUCCESS + return CMD_SUCCESS; + } + + if (argc == 2 && strcmp("init", argv[1]) == 0) { + if (task_blink_init() != SUCCESS) { + return CMD_FAILURE; + } + + return CMD_SUCCESS; + } + + if (argc == 2 && strcmp("deinit", argv[1]) == 0) { + if (task_blink_deinit() != SUCCESS) { + return CMD_FAILURE; + } + + return CMD_SUCCESS; + } + + if (argc >= 2 && strcmp("stats", argv[1]) == 0) { + if (argc == 3 && strcmp("print", argv[2]) == 0) { + task_blink_stats_print(); + return CMD_SUCCESS; + } + + if (argc == 3 && strcmp("reset", argv[2]) == 0) { + task_blink_stats_reset(); + return CMD_SUCCESS; + } + } + + // At any point, if an error is detected in given input command, + // simply return an error code (defined in sys/defines.h) + // + // The return statement below is used to catch all user input which + // didn't match the if statements above. In general, to handle commands, + // assume they are invalid. Only after checking if each argument is + // valid should you trust them. + // + // Common error return values are: FAILURE, INVALID_ARGUMENTS + return CMD_INVALID_ARGUMENTS; +} + +#endif // APP_BLINK diff --git a/sdk/freertos_app_cpu0/src/usr/blink/cmd/cmd_blink.h b/sdk/freertos_app_cpu0/src/usr/blink/cmd/cmd_blink.h new file mode 100644 index 00000000..62716a81 --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/blink/cmd/cmd_blink.h @@ -0,0 +1,11 @@ +#ifndef CMD_BLINK_H +#define CMD_BLINK_H + +// Called in app init function to register command with system +void cmd_blink_register(void); + +// Function called when user types "blink" command into command prompt +// i.e., this is the blink command handler function +int cmd_blink(int argc, char **argv); + +#endif // CMD_BLINK_H diff --git a/sdk/freertos_app_cpu0/src/usr/blink/task_blink.c b/sdk/freertos_app_cpu0/src/usr/blink/task_blink.c new file mode 100644 index 00000000..2a84c892 --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/blink/task_blink.c @@ -0,0 +1,92 @@ +#ifdef APP_BLINK + +/* FreeRTOS includes */ +#include "FreeRTOS.h" +#include "task.h" +/* other includes */ +#include "usr/blink/task_blink.h" +#include "drv/led.h" +#include "sys/defines.h" +#include + +// Hold LED animation state +static uint8_t led_pos = 0; +static uint8_t led_color_idx = 0; +#define NUM_LED_COLORS (7) +static led_color_t led_colors[NUM_LED_COLORS] = { + LED_COLOR_RED, // + LED_COLOR_GREEN, // + LED_COLOR_BLUE, // + LED_COLOR_YELLOW, // + LED_COLOR_CYAN, // + LED_COLOR_MAGENTA, // + LED_COLOR_WHITE, // +}; + +// Scheduler TCB which holds task "context" +static TaskHandle_t tcb; +static uint8_t taskExists = 0; // extra data to ensure tasks don't get duplicated or double free'd + +int task_blink_init(void) +{ + if (taskExists) { + return FAILURE; + } + // Fill TCB with parameters + xTaskCreate(task_blink, (const char *) "blink", configMINIMAL_STACK_SIZE, + NULL, tskIDLE_PRIORITY, &tcb); + taskExists = 1; + return SUCCESS; +} + +int task_blink_deinit(void) +{ + if (taskExists == 0) { + return FAILURE; + } + // Turn off all LEDs + for (uint8_t i = 0; i < NUM_LEDS; i++) { + led_set_color(i, LED_COLOR_BLACK); + } + + // Reset state + led_pos = 0; + led_color_idx = 0; + + // Unregister task with scheduler + vTaskDelete(tcb); + taskExists = 0; + return SUCCESS; +} + +void task_blink(void *arg) +{ + for (;;) { + vTaskDelay(TASK_BLINK_INTERVAL_TICKS); + for (uint8_t i = 0; i < NUM_LEDS; i++) { + led_set_color(i, led_pos == i ? led_colors[led_color_idx] : LED_COLOR_BLACK); + } + + if (++led_pos == NUM_LEDS) { + led_pos = 0; + + if (++led_color_idx >= NUM_LED_COLORS) { + led_color_idx = 0; + } + } + } +} + +void task_blink_stats_print(void) +{ + char statsBuffer[configSTATS_BUFFER_MAX_LENGTH]; + vTaskGetRunTimeStats(statsBuffer); + xil_printf("%s\n", statsBuffer); +} + +void task_blink_stats_reset(void) +{ + /* currently does nothing */ +} + +#endif // APP_BLINK diff --git a/sdk/freertos_app_cpu0/src/usr/blink/task_blink.h b/sdk/freertos_app_cpu0/src/usr/blink/task_blink.h new file mode 100644 index 00000000..f1e78872 --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/blink/task_blink.h @@ -0,0 +1,34 @@ +#ifndef TASK_BLINK_H +#define TASK_BLINK_H + +/* FreeRTOS includes */ +#include "FreeRTOS.h" +#include "task.h" + +// Frequency that this task is called (in Hz) +// +// Must be less than or equal to scheduler updates per second +// This value is defined in sys/scheduler.h and defaults to 10kHz. +// Note that it can be overridden via usr/user_config.h +#define TASK_BLINK_UPDATES_PER_SEC (5) + +// Microseconds interval between when task is called +// +// This is what scheduler actually uses to run task, +// but is generated via define above +#define TASK_BLINK_INTERVAL_TICKS (pdMS_TO_TICKS(1000.0 / TASK_BLINK_UPDATES_PER_SEC)) + +// Called in app init function to set up task (or via command) +int task_blink_init(void); +int task_blink_deinit(void); + +// Callback function which scheduler calls periodically +void task_blink(void *arg); + +// Print the statistics gathered by the scheduler +void task_blink_stats_print(void); + +// Reset the statistics gathered by the scheduler +void task_blink_stats_reset(void); + +#endif // TASK_BLINK_H diff --git a/sdk/freertos_app_cpu0/src/usr/blink/task_vsi.c b/sdk/freertos_app_cpu0/src/usr/blink/task_vsi.c new file mode 100644 index 00000000..e6e7bbe7 --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/blink/task_vsi.c @@ -0,0 +1,55 @@ +#ifdef APP_BLINK +/* FreeRTOS includes */ +#include "FreeRTOS.h" +#include "task.h" +/* other includes */ +#include "usr/blink/task_vsi.h" +#include "drv/led.h" +#include "sys/defines.h" +#include +#include + +// Scheduler TCB which holds task "context" +static TaskHandle_t tcb; + +// Example logging variables for testing +int LOG_task_vsi_runs = 0; +double LOG_vsi_a = 0; +float LOG_vsi_b = 0; +int LOG_vsi_c = 0; + +static double Ts = 1.0 / 10000.0; // [sec] +static double theta = 0.0; // [rad] +static double omega = 10.0; // [rad/s] +static double Do = 0.75; // [--] + +void task_vsi_init(void) +{ + // Fill TCB with parameters + xTaskCreate(task_vsi, (const char *) "vsi", configMINIMAL_STACK_SIZE, + NULL, tskIDLE_PRIORITY, &tcb); +} + +void task_vsi(void *arg) +{ + for (;;) { + vTaskDelay(TASK_VSI_INTERVAL_TICKS); + LOG_task_vsi_runs += 1; + + // Update theta + theta += (Ts * omega); + theta = fmod(theta, 2.0 * M_PI); // Wrap to 2*pi + + // Calculate desired duty ratios + double vsi_a = Do * cos(theta); + double vsi_b = Do * cos(theta + 2.0 * M_PI / 3.0); + double vsi_c = Do * cos(theta + 4.0 * M_PI / 3.0); + + // Update logging variables + LOG_vsi_a = (double) (10e3 * vsi_a); + LOG_vsi_b = (float) (10e3 * vsi_b); + LOG_vsi_c = (int) (10e3 * vsi_c); + } +} + +#endif // APP_BLINK diff --git a/sdk/freertos_app_cpu0/src/usr/blink/task_vsi.h b/sdk/freertos_app_cpu0/src/usr/blink/task_vsi.h new file mode 100644 index 00000000..eeaf396f --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/blink/task_vsi.h @@ -0,0 +1,15 @@ +#ifndef TASK_VSI_H +#define TASK_VSI_H + +/* FreeRTOS includes */ +#include "FreeRTOS.h" +#include "task.h" + +#define TASK_VSI_UPDATES_PER_SEC (10000) +#define TASK_VSI_INTERVAL_TICKS (pdMS_TO_TICKS(1000.0 / TASK_VSI_UPDATES_PER_SEC)) + +void task_vsi_init(void); + +void task_vsi(void *arg); + +#endif // TASK_VSI_H diff --git a/sdk/freertos_app_cpu0/src/usr/game/app_game.c b/sdk/freertos_app_cpu0/src/usr/game/app_game.c new file mode 100644 index 00000000..2eec8e98 --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/game/app_game.c @@ -0,0 +1,16 @@ +#ifdef APP_GAME + +#include "usr/game/app_game.h" +#include "usr/game/cmd/cmd_game.h" +#include "usr/game/task_game.h" + +void app_game_init(void) +{ + // Register "game" command with system + cmd_game_register(); + + // Initialize game task with system + task_game_init(); +} + +#endif // APP_GAME diff --git a/sdk/freertos_app_cpu0/src/usr/game/app_game.h b/sdk/freertos_app_cpu0/src/usr/game/app_game.h new file mode 100644 index 00000000..1aee03ad --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/game/app_game.h @@ -0,0 +1,6 @@ +#ifndef APP_GAME_H +#define APP_GAME_H + +void app_game_init(void); + +#endif // APP_GAME_H diff --git a/sdk/freertos_app_cpu0/src/usr/game/cmd/cmd_game.c b/sdk/freertos_app_cpu0/src/usr/game/cmd/cmd_game.c new file mode 100644 index 00000000..c5d5daed --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/game/cmd/cmd_game.c @@ -0,0 +1,106 @@ +#ifdef APP_GAME +#include "cmd_game.h" +#include "usr/game/task_game.h" +#include "sys/commands.h" +#include "sys/debug.h" +#include "sys/defines.h" +#include "sys/util.h" +#include +#include + +static command_entry_t cmd_entry1; +static command_entry_t cmd_entry2; +static command_entry_t cmd_entry3; +static command_entry_t cmd_entry4; +static command_entry_t cmd_entryRestart; + +static command_help_t cmd_help1[] = { + { "1", "Send when LED 1 is on" } +}; + +static command_help_t cmd_help2[] = { + { "2", "Send when LED 2 is on" } +}; + +static command_help_t cmd_help3[] = { + { "3", "Send when LED 3 is on" } +}; + +static command_help_t cmd_help4[] = { + { "4", "Send when LED 4 is on" } +}; + +static command_help_t cmd_helpRestart[] = { + { "r", "Send to restart the game" } +}; + +void cmd_game_register(void) +{ + // Populate the command entry block + commands_cmd_init(&cmd_entry1, "1", "Game 1 command", cmd_help1, ARRAY_SIZE(cmd_help1), cmd_game1); + commands_cmd_init(&cmd_entry2, "2", "Game 2 command", cmd_help2, ARRAY_SIZE(cmd_help2), cmd_game2); + commands_cmd_init(&cmd_entry3, "3", "Game 3 command", cmd_help3, ARRAY_SIZE(cmd_help3), cmd_game3); + commands_cmd_init(&cmd_entry4, "4", "Game 4 command", cmd_help4, ARRAY_SIZE(cmd_help4), cmd_game4); + commands_cmd_init(&cmd_entryRestart, "r", "Restart command", cmd_helpRestart, ARRAY_SIZE(cmd_helpRestart), cmd_gameRestart); + + // Register the command + commands_cmd_register(&cmd_entry1); + commands_cmd_register(&cmd_entry2); + commands_cmd_register(&cmd_entry3); + commands_cmd_register(&cmd_entry4); + commands_cmd_register(&cmd_entryRestart); +} + +int cmd_game1(int argc, char **argv) { + if (getGameLedOn() == 1) { + while (getGameLedOn() == 1) { + setGameLedOn(randomInt(1, 4)); + } + incrementGameScore(); + return CMD_SUCCESS; + } + decrementGameScore(); + return CMD_FAILURE; +} + +int cmd_game2(int argc, char **argv) { + if (getGameLedOn() == 2) { + while (getGameLedOn() == 2) { + setGameLedOn(randomInt(1, 4)); + } + incrementGameScore(); + return CMD_SUCCESS; + } + decrementGameScore(); + return CMD_FAILURE; +} + +int cmd_game3(int argc, char **argv) { + if (getGameLedOn() == 3) { + while (getGameLedOn() == 3) { + setGameLedOn(randomInt(1, 4)); + } + incrementGameScore(); + return CMD_SUCCESS; + } + decrementGameScore(); + return CMD_FAILURE; +} + +int cmd_game4(int argc, char **argv) { + if (getGameLedOn() == 4) { + while (getGameLedOn() == 4) { + setGameLedOn(randomInt(1, 4)); + } + incrementGameScore(); + return CMD_SUCCESS; + } + decrementGameScore(); + return CMD_FAILURE; +} + +int cmd_gameRestart(int argc, char **argv) { + reset_game(); + return CMD_SUCCESS; +} +#endif // APP_GAME diff --git a/sdk/freertos_app_cpu0/src/usr/game/cmd/cmd_game.h b/sdk/freertos_app_cpu0/src/usr/game/cmd/cmd_game.h new file mode 100644 index 00000000..dc7b5466 --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/game/cmd/cmd_game.h @@ -0,0 +1,12 @@ +#ifndef CMD_GAME_H +#define CMD_GAME_H + +void cmd_game_register(void); + +int cmd_game1(int argc, char **argv); +int cmd_game2(int argc, char **argv); +int cmd_game3(int argc, char **argv); +int cmd_game4(int argc, char **argv); +int cmd_gameRestart(int argc, char **argv); + +#endif // CMD_GAME_H diff --git a/sdk/freertos_app_cpu0/src/usr/game/task_game.c b/sdk/freertos_app_cpu0/src/usr/game/task_game.c new file mode 100644 index 00000000..ceddef56 --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/game/task_game.c @@ -0,0 +1,146 @@ +#ifdef APP_GAME + +/* FreeRTOS includes */ +#include "FreeRTOS.h" +#include "task.h" +/* Xilinx includes. */ +#include "xil_printf.h" +/* other includes */ +#include "sys/defines.h" +#include "usr/game/task_game.h" +#include "drv/led.h" +#include +#include + +/* from: https://www.quora.com/Can-we-get-a-random-number-without-using-rand-in-C-C-and-Python */ +int randCustom() { + static int next = 3251 ; // Anything you like here - but not + // 0000, 0100, 2500, 3792, 7600, + // 0540, 2916, 5030 or 3009. + next = ((next * next) / 100) % 10000; + return next ; +} + +int randomInt(int lowerBound, int upperBound) { // random integer between lower and upper bound (inclusive) + return randCustom() % (upperBound + 1 - lowerBound) + lowerBound; +} + +int gameScore = 0; + +void incrementGameScore() { + gameScore++; +} + +void decrementGameScore() { + gameScore--; +} + +uint8_t game_led_on = 1; + +uint8_t getGameLedOn() { + return game_led_on; +} + +void setGameLedOn(uint8_t setTo) { + if (!game_started()) { + start_game(); + } + led_set_color(game_led_on - 1, LED_COLOR_BLACK); + led_set_color(setTo - 1, LED_COLOR_GREEN); + game_led_on = setTo; +} + +// Hold LED animation state +static uint8_t led_pos = 0; +static uint8_t led_color_idx = 0; +// Scheduler TCB which holds task "context" +static TaskHandle_t tcb; +static uint8_t taskExists = 0; // extra data to ensure tasks don't get duplicated or double free'd + +int task_game_init(void) +{ + if (taskExists) { + return FAILURE; + } + // Turn off all LEDs + for (uint8_t i = 1; i < NUM_LEDS; i++) { + led_set_color(i, LED_COLOR_BLACK); + } + // Turn on first LED to RED + led_set_color(0, LED_COLOR_RED); + + // Command parse task (UART) + xTaskCreate(task_game, (const char *) "game", configMINIMAL_STACK_SIZE, + NULL, tskIDLE_PRIORITY, &tcb); + taskExists = 1; + return SUCCESS; +} + +int task_game_deinit(void) +{ + if (taskExists == 0) { + return FAILURE; + } + // Turn off all LEDs + for (uint8_t i = 0; i < NUM_LEDS; i++) { + led_set_color(i, LED_COLOR_BLACK); + } + + // Reset state + led_pos = 0; + led_color_idx = 0; + vTaskDelete(tcb); + taskExists = 0; + return SUCCESS; +} + +int callbackIter = -2; +int secondsLeft = 30; + +void start_game() { + callbackIter = 0; + secondsLeft = 30; +} + +void reset_game() { + // Turn off all LEDs + for (uint8_t i = 1; i < NUM_LEDS; i++) { + led_set_color(i, LED_COLOR_BLACK); + } + // Turn on first LED to RED + led_set_color(0, LED_COLOR_RED); + callbackIter = -2; + gameScore = 0; + game_led_on = 1; +} + +int game_started() { + if (callbackIter == -2) { + return 0; + } + return 1; +} + +void task_game(void *arg) +{ + for (;;) { + vTaskDelay(TASK_GAME_INTERVAL_TICKS); + if (callbackIter >= 0) { + callbackIter++; + if (callbackIter % 5 == 0) { + xil_printf("%d seconds left\n", secondsLeft); + secondsLeft--; + } + if (callbackIter > 150) { + game_led_on = 0; + for (uint8_t i = 0; i < NUM_LEDS; i++) { + led_set_color(i, LED_COLOR_BLACK); + } + callbackIter = -1; + xil_printf("Time's up! Score: %d\n", gameScore); + } + } + } +} + +#endif // APP_GAME diff --git a/sdk/freertos_app_cpu0/src/usr/game/task_game.h b/sdk/freertos_app_cpu0/src/usr/game/task_game.h new file mode 100644 index 00000000..49f7d0e1 --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/game/task_game.h @@ -0,0 +1,48 @@ +#ifndef TASK_GAME_H +#define TASK_GAME_H + +/* FreeRTOS includes */ +#include "FreeRTOS.h" +#include "task.h" + +// Frequency that this task is called (in Hz) +// +// Must be less than or equal to scheduler updates per second +// This value is defined in sys/scheduler.h and defaults to 10kHz. +// Note that it can be overridden via usr/user_config.h +#define TASK_GAME_UPDATES_PER_SEC (5) + +// Microseconds interval between when task is called +// +// This is what scheduler actually uses to run task, +// but is generated via define above +#define TASK_GAME_INTERVAL_TICKS (pdMS_TO_TICKS(1000.0 / TASK_GAME_UPDATES_PER_SEC)) + +void incrementGameScore(); +void decrementGameScore(); + +uint8_t getGameLedOn(); +void setGameLedOn(uint8_t setTo); +int randomInt(int lowerBound, int upperBound); + +// Called in app init function to set up task (or via command) +int task_game_init(void); +int task_game_deinit(void); + +// start the game timer +void start_game(); +void reset_game(); + +// returns 1 if the game is already started and 0 otherwise +int game_started(); + +// Callback function which scheduler calls periodically +void task_game(void *arg); + +// Print the statistics gathered by the scheduler +void task_game_stats_print(void); + +// Reset the statistics gathered by the scheduler +void task_game_stats_reset(void); + +#endif // TASK_GAME_H diff --git a/sdk/freertos_app_cpu0/src/usr/user_apps.c b/sdk/freertos_app_cpu0/src/usr/user_apps.c new file mode 100644 index 00000000..2bea0f19 --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/user_apps.c @@ -0,0 +1,68 @@ +#include "usr/user_apps.h" + +// Adding applications: +// +// To add a new application, create a block +// like the other example(s) below which +// conditionally includes the app's header file. +// +// Also, conditionally call the app's init function. + +#ifdef APP_PCBTEST +#include "usr/pcbtest/app_pcbtest.h" +#endif + +#ifdef APP_BLINK +#include "usr/blink/app_blink.h" +#endif + +#ifdef APP_GAME +#include "usr/game/app_game.h" +#endif + +#ifdef APP_MATH +#include "usr/math/app_math.h" +#endif + +#ifdef APP_BETA_LABS +#include "usr/beta_labs/app_beta_labs.h" +#endif + +#ifdef APP_DEMO +#include "usr/demo/app_demo.h" +#endif + +#ifdef APP_DAC +#include "usr/dac/app_dac.h" +#endif + +void user_apps_init(void) +{ +#ifdef APP_PCBTEST + app_pcbtest_init(); +#endif + +#ifdef APP_BLINK + app_blink_init(); +#endif + +#ifdef APP_GAME + app_game_init(); +#endif + +#ifdef APP_MATH + app_math_init(); +#endif + +#ifdef APP_BETA_LABS + app_beta_labs_init(); +#endif + +#ifdef APP_DEMO + app_demo_init(); +#endif + +#ifdef APP_DAC + app_dac_init(); +#endif +} diff --git a/sdk/freertos_app_cpu0/src/usr/user_apps.h b/sdk/freertos_app_cpu0/src/usr/user_apps.h new file mode 100644 index 00000000..1564485c --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/user_apps.h @@ -0,0 +1,6 @@ +#ifndef USER_APPS_H +#define USER_APPS_H + +void user_apps_init(void); + +#endif // USER_APPS_H diff --git a/sdk/freertos_app_cpu0/src/usr/user_config.h b/sdk/freertos_app_cpu0/src/usr/user_config.h new file mode 100644 index 00000000..6f448c47 --- /dev/null +++ b/sdk/freertos_app_cpu0/src/usr/user_config.h @@ -0,0 +1,45 @@ +#ifndef USER_CONFIG_H +#define USER_CONFIG_H + +#include "drv/hardware_targets.h" + +// This file is used to override system defines and conditionally enable +// various system-level firmware features. + +// Specify hardware revision (i.e. REV E, REV F, etc) +#define USER_CONFIG_HARDWARE_TARGET (AMDC_REV_F) + +// Enable task statistic collection by default +// NOTE: The user can still go and enable the stats themselves if this is set to 0! +// set to 1 for enabled, 0 for disabled +#define USER_CONFIG_ENABLE_TASK_STATISTICS_BY_DEFAULT (0) + +// Enable the watchdog timer +// set to 1 for enabled, 0 for disabled +#define USER_CONFIG_ENABLE_WATCHDOG (0) + +// Enable logging functionality +// set to 1 for enabled, 0 for disabled +#define USER_CONFIG_ENABLE_LOGGING (0) + +// Override default number of available logging variables +// when defined, this takes precedence over system default of 32 +//#define USER_CONFIG_LOGGING_MAX_NUM_VARIABLES (150) + +// Override default logging sample depth per variable +// when defined, this takes precedence over system default of 100k +//#define USER_CONFIG_LOGGING_SAMPLE_DEPTH_PER_VARIABLE (50000) + +// Enable injection functionality +// set to 1 for enabled, 0 for disabled +#define USER_CONFIG_ENABLE_INJECTION (0) + +// Enable SensorCard platform motherboard support +// set to 1 for enabled, 0 for disabled +#define USER_CONFIG_ENABLE_MOTHERBOARD_SUPPORT (0) + +// Enable SensorCard platform motherboard auto request new ADC sample data +// set to 1 for enabled, 0 for disabled +#define USER_CONFIG_ENABLE_MOTHERBOARD_AUTO_TX (0) + +#endif // USER_CONFIG_H diff --git a/sdk/freertos_app_cpu1/.cproject b/sdk/freertos_app_cpu1/.cproject index f04ca3b5..a51eb941 100644 --- a/sdk/freertos_app_cpu1/.cproject +++ b/sdk/freertos_app_cpu1/.cproject @@ -1,197 +1,277 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/freertos_app_cpu1/.project b/sdk/freertos_app_cpu1/.project index 0e6c64d2..cb5c2c83 100644 --- a/sdk/freertos_app_cpu1/.project +++ b/sdk/freertos_app_cpu1/.project @@ -1,38 +1,43 @@ - - - freertos_app_cpu1 - Created by SDK v2019.1. amdc_freertos_bsp_cpu1 - ps7_cortexa9_1 - - amdc_freertos_bsp_cpu1 - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - - org.eclipse.cdt.core.cnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - - - - FreeRTOS-Kernel - 2 - S:/School/WEMPEC/firmware-rtos-e/sdk/FreeRTOS-Kernel - - - shared - 2 - S:/School/WEMPEC/firmware-rtos-e/sdk/shared - - - + + + freertos_app_cpu1 + Created by SDK v2019.1. amdc_freertos_bsp_cpu1 - ps7_cortexa9_1 + + amdc_bsp_cpu1 + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + FreeRTOS-Kernel + 2 + C:/Users/srich008/Information/v2-staging/sdk/FreeRTOS-Kernel + + + MemMang + 2 + C:/Users/srich008/Information/v2-staging/sdk/FreeRTOS-Kernel/portable/MemMang + + + shared + 2 + C:/Users/srich008/Information/v2-staging/sdk/shared + + + diff --git a/sdk/freertos_app_cpu1/src/FreeRTOSConfig.h b/sdk/freertos_app_cpu1/src/FreeRTOSConfig.h index b92d6969..94d03f1f 100644 --- a/sdk/freertos_app_cpu1/src/FreeRTOSConfig.h +++ b/sdk/freertos_app_cpu1/src/FreeRTOSConfig.h @@ -1,247 +1,247 @@ -/* README!!! - * - * This configuration is copied from the FreeRTOS v10.1.1 - * based example project for the Zynq 7000 platform (for - * compatibility). However, you can add to it. - * - * Another example configuration file is available at - * "sdk/FreeRTOS-Kernel/examples/sample_configuration/FreeRTOSConfig.h" - * Because that example is in the submodule, it may update - * from time-to-time when the submodule is updated. - */ - -/* - * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * http://www.FreeRTOS.org - * http://aws.amazon.com/freertos - * - * 1 tab == 4 spaces! - */ - -#ifndef FREERTOS_CONFIG_H -#define FREERTOS_CONFIG_H - -#include "xparameters.h" - -/*----------------------------------------------------------- - * Application specific definitions. - * - * These definitions should be adjusted for your particular hardware and - * application requirements. - * - * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE - * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. - * - * See http://www.freertos.org/a00110.html - *----------------------------------------------------------*/ - -/* - * The FreeRTOS Cortex-A port implements a full interrupt nesting model. - * - * Interrupts that are assigned a priority at or below - * configMAX_API_CALL_INTERRUPT_PRIORITY (which counter-intuitively in the ARM - * generic interrupt controller [GIC] means a priority that has a numerical - * value above configMAX_API_CALL_INTERRUPT_PRIORITY) can call FreeRTOS safe API - * functions and will nest. - * - * Interrupts that are assigned a priority above - * configMAX_API_CALL_INTERRUPT_PRIORITY (which in the GIC means a numerical - * value below configMAX_API_CALL_INTERRUPT_PRIORITY) cannot call any FreeRTOS - * API functions, will nest, and will not be masked by FreeRTOS critical - * sections (although it is necessary for interrupts to be globally disabled - * extremely briefly as the interrupt mask is updated in the GIC). - * - * FreeRTOS functions that can be called from an interrupt are those that end in - * "FromISR". FreeRTOS maintains a separate interrupt safe API to enable - * interrupt entry to be shorter, faster, simpler and smaller. - * - * The Zynq implements 256 unique interrupt priorities. For the purpose of - * setting configMAX_API_CALL_INTERRUPT_PRIORITY 255 represents the lowest - * priority. - */ -#define configMAX_API_CALL_INTERRUPT_PRIORITY 18 - -#define configCPU_CLOCK_HZ 100000000UL -#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 -#define configUSE_TICKLESS_IDLE 0 -#define configTICK_RATE_HZ ((TickType_t) 1000) -#define configPERIPHERAL_CLOCK_HZ (33333000UL) -#define configUSE_PREEMPTION 1 -#define configUSE_IDLE_HOOK 0 // TODO: For low-power, set 1 and implement vApplicationIdleHook() -#define configUSE_TICK_HOOK 0 // TODO: Set as 1 if we want to run function every tick -#define configMAX_PRIORITIES (7) -#define configTOTAL_HEAP_SIZE (125 * 1024) -#define configMAX_TASK_NAME_LEN (10) -#define configUSE_TRACE_FACILITY 1 -#define configUSE_16_BIT_TICKS 0 -#define configIDLE_SHOULD_YIELD 1 -#define configUSE_MUTEXES 1 -#define configQUEUE_REGISTRY_SIZE 8 -#define configCHECK_FOR_STACK_OVERFLOW 0 -#define configUSE_RECURSIVE_MUTEXES 1 -#define configUSE_MALLOC_FAILED_HOOK 0 -#define configUSE_APPLICATION_TASK_TAG 0 -#define configUSE_COUNTING_SEMAPHORES 1 -#define configUSE_QUEUE_SETS 1 -#define configSUPPORT_DYNAMIC_ALLOCATION 1 -#define configSUPPORT_STATIC_ALLOCATION 1 - -/* AMDC ADDITION: Need to specify this callback config so we can create message buffers with callbacks - * This is done for Inter-Core Communication (src/sys/icc.c) */ -#define configUSE_SB_COMPLETED_CALLBACK 1 - -/* Include the query-heap CLI command to query the free heap space. */ -#define configINCLUDE_QUERY_HEAP_COMMAND 1 - -/* Co-routine definitions. */ -#define configUSE_CO_ROUTINES 0 -#define configMAX_CO_ROUTINE_PRIORITIES (2) - -/* Software timer definitions. */ -#define configUSE_TIMERS 1 -#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) -#define configTIMER_QUEUE_LENGTH 5 -#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) - -/* If configUSE_TASK_FPU_SUPPORT is set to 1 (or undefined) then each task will -be created without an FPU context, and a task must call vTaskUsesFPU() before -making use of any FPU registers. If configUSE_TASK_FPU_SUPPORT is set to 2 then -tasks are created with an FPU context by default, and calling vTaskUsesFPU() has -no effect. */ -#define configUSE_TASK_FPU_SUPPORT 2 -#define configMINIMAL_STACK_SIZE ((unsigned short) 250) // Large since all tasks have FPU context - -/* Set the following definitions to 1 to include the API function, or zero -to exclude the API function. */ -#define INCLUDE_vTaskPrioritySet 1 -#define INCLUDE_uxTaskPriorityGet 1 -#define INCLUDE_vTaskDelete 1 -#define INCLUDE_vTaskCleanUpResources 1 -#define INCLUDE_vTaskSuspend 1 -#define INCLUDE_vTaskDelayUntil 1 -#define INCLUDE_vTaskDelay 1 -#define INCLUDE_xTimerPendFunctionCall 1 -#define INCLUDE_eTaskGetState 1 -#define INCLUDE_xTaskAbortDelay 1 -#define INCLUDE_xTaskGetTaskHandle 1 -#define INCLUDE_xTaskGetHandle 1 -#define INCLUDE_xSemaphoreGetMutexHolder 1 - -/* This demo makes use of one or more example stats formatting functions. These -format the raw data provided by the uxTaskGetSystemState() function in to human -readable ASCII form. See the notes in the implementation of vTaskList() within -FreeRTOS/Source/tasks.c for limitations. */ -#define configUSE_STATS_FORMATTING_FUNCTIONS 0 - -/* The private watchdog is used to generate run time stats. */ -/* -#include "xscuwdt.h" -extern XScuWdt xWatchDogInstance; -extern void vInitialiseTimerForRunTimeStats( void ); -#define configGENERATE_RUN_TIME_STATS 1 -#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vInitialiseTimerForRunTimeStats() -#define portGET_RUN_TIME_COUNTER_VALUE() ( ( 0xffffffffUL - XScuWdt_ReadReg( xWatchDogInstance.Config.BaseAddr, -XSCUWDT_COUNTER_OFFSET ) ) >> 1 ) -*/ - -/* The size of the global output buffer that is available for use when there -are multiple command interpreters running at once (for example, one on a UART -and one on TCP/IP). This is done to prevent an output buffer being defined by -each implementation - which would waste RAM. In this case, there is only one -command interpreter running. */ -#define configCOMMAND_INT_MAX_OUTPUT_SIZE 2096 - -/* Normal assert() semantics without relying on the provision of an assert.h -header file. */ -void vAssertCalled(const char *pcFile, unsigned long ulLine); - -// Original Implementation -//#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ); - -#define configASSERT(x) \ - if ((x) == 0) \ - while (1) \ - ; - -/* If configTASK_RETURN_ADDRESS is not defined then a task that attempts to -return from its implementing function will end up in a "task exit error" -function - which contains a call to configASSERT(). However this can give GCC -some problems when it tries to unwind the stack, as the exit error function has -nothing to return to. To avoid this define configTASK_RETURN_ADDRESS to 0. */ -#define configTASK_RETURN_ADDRESS NULL - -/****** Hardware specific settings. *******************************************/ - -/* - * The application must provide a function that configures a peripheral to - * create the FreeRTOS tick interrupt, then define configSETUP_TICK_INTERRUPT() - * in FreeRTOSConfig.h to call the function. This file contains a function - * that is suitable for use on the Zynq MPU. FreeRTOS_Tick_Handler() must - * be installed as the peripheral's interrupt handler. - */ -void vConfigureTickInterrupt(void); -#define configSETUP_TICK_INTERRUPT() vConfigureTickInterrupt() - -void vClearTickInterrupt(void); -#define configCLEAR_TICK_INTERRUPT() vClearTickInterrupt() - -/* The following constant describe the hardware, and are correct for the -Zynq MPU. */ -#define configINTERRUPT_CONTROLLER_BASE_ADDRESS (XPAR_PS7_SCUGIC_0_DIST_BASEADDR) -#define configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET (-0xf00) -#define configUNIQUE_INTERRUPT_PRIORITIES 32 - -/****** Network configuration settings - only used when the lwIP example is -built. See the page that documents this demo on the http://www.FreeRTOS.org -website for more information. ***********************************************/ - -/* The priority for the task that unblocked by the MAC interrupt to process -received packets. */ -#define configMAC_INPUT_TASK_PRIORITY (configMAX_PRIORITIES - 1) - -/* The priority of the task that runs the lwIP stack. */ -#define configLWIP_TASK_PRIORITY (configMAX_PRIORITIES - 2) - -/* The priority of the task that uses lwIP sockets to provide a simple command -line interface. */ -#define configCLI_TASK_PRIORITY (tskIDLE_PRIORITY) - -/* MAC address configuration. */ -#define configMAC_ADDR0 0x00 -#define configMAC_ADDR1 0x13 -#define configMAC_ADDR2 0x14 -#define configMAC_ADDR3 0x15 -#define configMAC_ADDR4 0x15 -#define configMAC_ADDR5 0x16 - -/* IP address configuration. */ -#define configIP_ADDR0 172 -#define configIP_ADDR1 25 -#define configIP_ADDR2 218 -#define configIP_ADDR3 200 - -/* Netmask configuration. */ -#define configNET_MASK0 255 -#define configNET_MASK1 255 -#define configNET_MASK2 255 -#define configNET_MASK3 0 - -#endif /* FREERTOS_CONFIG_H */ +/* README!!! + * + * This configuration is copied from the FreeRTOS v10.1.1 + * based example project for the Zynq 7000 platform (for + * compatibility). However, you can add to it. + * + * Another example configuration file is available at + * "sdk/FreeRTOS-Kernel/examples/sample_configuration/FreeRTOSConfig.h" + * Because that example is in the submodule, it may update + * from time-to-time when the submodule is updated. + */ + +/* + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +#include "xparameters.h" + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html + *----------------------------------------------------------*/ + +/* + * The FreeRTOS Cortex-A port implements a full interrupt nesting model. + * + * Interrupts that are assigned a priority at or below + * configMAX_API_CALL_INTERRUPT_PRIORITY (which counter-intuitively in the ARM + * generic interrupt controller [GIC] means a priority that has a numerical + * value above configMAX_API_CALL_INTERRUPT_PRIORITY) can call FreeRTOS safe API + * functions and will nest. + * + * Interrupts that are assigned a priority above + * configMAX_API_CALL_INTERRUPT_PRIORITY (which in the GIC means a numerical + * value below configMAX_API_CALL_INTERRUPT_PRIORITY) cannot call any FreeRTOS + * API functions, will nest, and will not be masked by FreeRTOS critical + * sections (although it is necessary for interrupts to be globally disabled + * extremely briefly as the interrupt mask is updated in the GIC). + * + * FreeRTOS functions that can be called from an interrupt are those that end in + * "FromISR". FreeRTOS maintains a separate interrupt safe API to enable + * interrupt entry to be shorter, faster, simpler and smaller. + * + * The Zynq implements 256 unique interrupt priorities. For the purpose of + * setting configMAX_API_CALL_INTERRUPT_PRIORITY 255 represents the lowest + * priority. + */ +#define configMAX_API_CALL_INTERRUPT_PRIORITY 18 + +#define configCPU_CLOCK_HZ 100000000UL +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configUSE_TICKLESS_IDLE 0 +#define configTICK_RATE_HZ ((TickType_t) 1000) +#define configPERIPHERAL_CLOCK_HZ (33333000UL) +#define configUSE_PREEMPTION 1 +#define configUSE_IDLE_HOOK 0 // TODO: For low-power, set 1 and implement vApplicationIdleHook() +#define configUSE_TICK_HOOK 0 // TODO: Set as 1 if we want to run function every tick +#define configMAX_PRIORITIES (7) +#define configTOTAL_HEAP_SIZE (125 * 1024) +#define configMAX_TASK_NAME_LEN (10) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 8 +#define configCHECK_FOR_STACK_OVERFLOW 0 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_QUEUE_SETS 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* AMDC ADDITION: Need to specify this callback config so we can create message buffers with callbacks + * This is done for Inter-Core Communication (src/sys/icc.c) */ +#define configUSE_SB_COMPLETED_CALLBACK 1 + +/* Include the query-heap CLI command to query the free heap space. */ +#define configINCLUDE_QUERY_HEAP_COMMAND 1 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES (2) + +/* Software timer definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) + +/* If configUSE_TASK_FPU_SUPPORT is set to 1 (or undefined) then each task will +be created without an FPU context, and a task must call vTaskUsesFPU() before +making use of any FPU registers. If configUSE_TASK_FPU_SUPPORT is set to 2 then +tasks are created with an FPU context by default, and calling vTaskUsesFPU() has +no effect. */ +#define configUSE_TASK_FPU_SUPPORT 2 +#define configMINIMAL_STACK_SIZE ((unsigned short) 250) // Large since all tasks have FPU context + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xTaskAbortDelay 1 +#define INCLUDE_xTaskGetTaskHandle 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_xSemaphoreGetMutexHolder 1 + +/* This demo makes use of one or more example stats formatting functions. These +format the raw data provided by the uxTaskGetSystemState() function in to human +readable ASCII form. See the notes in the implementation of vTaskList() within +FreeRTOS/Source/tasks.c for limitations. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 + +/* The private watchdog is used to generate run time stats. */ +/* +#include "xscuwdt.h" +extern XScuWdt xWatchDogInstance; +extern void vInitialiseTimerForRunTimeStats( void ); +#define configGENERATE_RUN_TIME_STATS 1 +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vInitialiseTimerForRunTimeStats() +#define portGET_RUN_TIME_COUNTER_VALUE() ( ( 0xffffffffUL - XScuWdt_ReadReg( xWatchDogInstance.Config.BaseAddr, +XSCUWDT_COUNTER_OFFSET ) ) >> 1 ) +*/ + +/* The size of the global output buffer that is available for use when there +are multiple command interpreters running at once (for example, one on a UART +and one on TCP/IP). This is done to prevent an output buffer being defined by +each implementation - which would waste RAM. In this case, there is only one +command interpreter running. */ +#define configCOMMAND_INT_MAX_OUTPUT_SIZE 2096 + +/* Normal assert() semantics without relying on the provision of an assert.h +header file. */ +void vAssertCalled(const char *pcFile, unsigned long ulLine); + +// Original Implementation +//#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ); + +#define configASSERT(x) \ + if ((x) == 0) \ + while (1) \ + ; + +/* If configTASK_RETURN_ADDRESS is not defined then a task that attempts to +return from its implementing function will end up in a "task exit error" +function - which contains a call to configASSERT(). However this can give GCC +some problems when it tries to unwind the stack, as the exit error function has +nothing to return to. To avoid this define configTASK_RETURN_ADDRESS to 0. */ +#define configTASK_RETURN_ADDRESS NULL + +/****** Hardware specific settings. *******************************************/ + +/* + * The application must provide a function that configures a peripheral to + * create the FreeRTOS tick interrupt, then define configSETUP_TICK_INTERRUPT() + * in FreeRTOSConfig.h to call the function. This file contains a function + * that is suitable for use on the Zynq MPU. FreeRTOS_Tick_Handler() must + * be installed as the peripheral's interrupt handler. + */ +void vConfigureTickInterrupt(void); +#define configSETUP_TICK_INTERRUPT() vConfigureTickInterrupt() + +void vClearTickInterrupt(void); +#define configCLEAR_TICK_INTERRUPT() vClearTickInterrupt() + +/* The following constant describe the hardware, and are correct for the +Zynq MPU. */ +#define configINTERRUPT_CONTROLLER_BASE_ADDRESS (XPAR_PS7_SCUGIC_0_DIST_BASEADDR) +#define configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET (-0xf00) +#define configUNIQUE_INTERRUPT_PRIORITIES 32 + +/****** Network configuration settings - only used when the lwIP example is +built. See the page that documents this demo on the http://www.FreeRTOS.org +website for more information. ***********************************************/ + +/* The priority for the task that unblocked by the MAC interrupt to process +received packets. */ +#define configMAC_INPUT_TASK_PRIORITY (configMAX_PRIORITIES - 1) + +/* The priority of the task that runs the lwIP stack. */ +#define configLWIP_TASK_PRIORITY (configMAX_PRIORITIES - 2) + +/* The priority of the task that uses lwIP sockets to provide a simple command +line interface. */ +#define configCLI_TASK_PRIORITY (tskIDLE_PRIORITY) + +/* MAC address configuration. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x13 +#define configMAC_ADDR2 0x14 +#define configMAC_ADDR3 0x15 +#define configMAC_ADDR4 0x15 +#define configMAC_ADDR5 0x16 + +/* IP address configuration. */ +#define configIP_ADDR0 172 +#define configIP_ADDR1 25 +#define configIP_ADDR2 218 +#define configIP_ADDR3 200 + +/* Netmask configuration. */ +#define configNET_MASK0 255 +#define configNET_MASK1 255 +#define configNET_MASK2 255 +#define configNET_MASK3 0 + +#endif /* FREERTOS_CONFIG_H */ diff --git a/sdk/freertos_app_cpu1/src/Xilinx.spec b/sdk/freertos_app_cpu1/src/Xilinx.spec index 9c27dcad..8eea3774 100644 --- a/sdk/freertos_app_cpu1/src/Xilinx.spec +++ b/sdk/freertos_app_cpu1/src/Xilinx.spec @@ -1,2 +1,2 @@ -*startfile: -crti%O%s crtbegin%O%s +*startfile: +crti%O%s crtbegin%O%s diff --git a/sdk/freertos_app_cpu1/src/main.c b/sdk/freertos_app_cpu1/src/main.c index 3565a044..96b92f0b 100644 --- a/sdk/freertos_app_cpu1/src/main.c +++ b/sdk/freertos_app_cpu1/src/main.c @@ -39,7 +39,7 @@ #include "xil_mmu.h" #include "xil_printf.h" #include "xparameters.h" -/* Firmware includes */ +/* Firmware includes. */ #include "sys/icc.h" #include "sys/intr.h" diff --git a/sdk/shared/FreeRTOS_tick_config.c b/sdk/shared/FreeRTOS_tick_config.c index 8ed8452d..b231f163 100644 --- a/sdk/shared/FreeRTOS_tick_config.c +++ b/sdk/shared/FreeRTOS_tick_config.c @@ -1,138 +1,138 @@ -/* - * FreeRTOS Kernel V10.1.1 - * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * http://www.FreeRTOS.org - * http://aws.amazon.com/freertos - * - * 1 tab == 4 spaces! - */ - -/* FreeRTOS includes. */ -#include "FreeRTOS.h" -#include "task.h" - -/* Xilinx includes. */ -#include "xscugic.h" -#include "xscutimer.h" - -#define XSCUTIMER_CLOCK_HZ (XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ / 2UL) - -static XScuTimer xTimer; -XScuGic xInterruptController; /* Interrupt controller instance */ - -/* - * The application must provide a function that configures a peripheral to - * create the FreeRTOS tick interrupt, then define configSETUP_TICK_INTERRUPT() - * in FreeRTOSConfig.h to call the function. This file contains a function - * that is suitable for use on the Zynq SoC. - */ -void vConfigureTickInterrupt(void) -{ - BaseType_t xStatus; - extern void FreeRTOS_Tick_Handler(void); - XScuTimer_Config *pxTimerConfig; - XScuGic_Config *pxGICConfig; - const uint8_t ucRisingEdge = 3; - - /* This function is called with the IRQ interrupt disabled, and the IRQ - interrupt should be left disabled. It is enabled automatically when the - scheduler is started. */ - - /* Ensure XScuGic_CfgInitialize() has been called. In this demo it has - already been called from prvSetupHardware() in main(). */ - pxGICConfig = XScuGic_LookupConfig(XPAR_SCUGIC_SINGLE_DEVICE_ID); - xStatus = XScuGic_CfgInitialize(&xInterruptController, pxGICConfig, pxGICConfig->CpuBaseAddress); - configASSERT(xStatus == XST_SUCCESS); - (void) xStatus; /* Remove compiler warning if configASSERT() is not defined. */ - - /* The priority must be the lowest possible. */ - XScuGic_SetPriorityTriggerType(&xInterruptController, - XPAR_SCUTIMER_INTR, - portLOWEST_USABLE_INTERRUPT_PRIORITY << portPRIORITY_SHIFT, - ucRisingEdge); - - /* Install the FreeRTOS tick handler. */ - xStatus = XScuGic_Connect( - &xInterruptController, XPAR_SCUTIMER_INTR, (Xil_ExceptionHandler) FreeRTOS_Tick_Handler, (void *) &xTimer); - configASSERT(xStatus == XST_SUCCESS); - (void) xStatus; /* Remove compiler warning if configASSERT() is not defined. */ - - /* Initialise the timer. */ - pxTimerConfig = XScuTimer_LookupConfig(XPAR_SCUTIMER_DEVICE_ID); - xStatus = XScuTimer_CfgInitialize(&xTimer, pxTimerConfig, pxTimerConfig->BaseAddr); - configASSERT(xStatus == XST_SUCCESS); - (void) xStatus; /* Remove compiler warning if configASSERT() is not defined. */ - - /* Enable Auto reload mode. */ - XScuTimer_EnableAutoReload(&xTimer); - - /* Ensure there is no prescale. */ - XScuTimer_SetPrescaler(&xTimer, 0); - - /* Load the timer counter register. */ - XScuTimer_LoadTimer(&xTimer, XSCUTIMER_CLOCK_HZ / configTICK_RATE_HZ); - - /* Start the timer counter and then wait for it to timeout a number of - times. */ - XScuTimer_Start(&xTimer); - - /* Enable the interrupt for the xTimer in the interrupt controller. */ - XScuGic_Enable(&xInterruptController, XPAR_SCUTIMER_INTR); - - /* Enable the interrupt in the xTimer itself. */ - vClearTickInterrupt(); - XScuTimer_EnableInterrupt(&xTimer); -} -/*-----------------------------------------------------------*/ - -void vClearTickInterrupt(void) -{ - XScuTimer_ClearInterruptStatus(&xTimer); -} -/*-----------------------------------------------------------*/ - -/* This is the callback function which is called by the FreeRTOS Cortex-A port -layer in response to an interrupt. If the function is called -vApplicationFPUSafeIRQHandler() then it is called after the floating point -registers have been saved. If the function is called vApplicationIRQHandler() -then it will be called without first having saved the FPU registers. See -http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html for -more information */ -void vApplicationFPUSafeIRQHandler(uint32_t ulICCIAR) -{ - extern const XScuGic_Config XScuGic_ConfigTable[]; - static const XScuGic_VectorTableEntry *pxVectorTable - = XScuGic_ConfigTable[XPAR_SCUGIC_SINGLE_DEVICE_ID].HandlerTable; - uint32_t ulInterruptID; - const XScuGic_VectorTableEntry *pxVectorEntry; - - /* Re-enable interrupts. */ - __asm("cpsie i"); - - /* The ID of the interrupt is obtained by bitwise anding the ICCIAR value - with 0x3FF. */ - ulInterruptID = ulICCIAR & 0x3FFUL; - if (ulInterruptID < XSCUGIC_MAX_NUM_INTR_INPUTS) { - /* Call the function installed in the array of installed handler functions. */ - pxVectorEntry = &(pxVectorTable[ulInterruptID]); - pxVectorEntry->Handler(pxVectorEntry->CallBackRef); - } -} +/* + * FreeRTOS Kernel V10.1.1 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Xilinx includes. */ +#include "xscugic.h" +#include "xscutimer.h" + +#define XSCUTIMER_CLOCK_HZ (XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ / 2UL) + +static XScuTimer xTimer; +XScuGic xInterruptController; /* Interrupt controller instance */ + +/* + * The application must provide a function that configures a peripheral to + * create the FreeRTOS tick interrupt, then define configSETUP_TICK_INTERRUPT() + * in FreeRTOSConfig.h to call the function. This file contains a function + * that is suitable for use on the Zynq SoC. + */ +void vConfigureTickInterrupt(void) +{ + BaseType_t xStatus; + extern void FreeRTOS_Tick_Handler(void); + XScuTimer_Config *pxTimerConfig; + XScuGic_Config *pxGICConfig; + const uint8_t ucRisingEdge = 3; + + /* This function is called with the IRQ interrupt disabled, and the IRQ + interrupt should be left disabled. It is enabled automatically when the + scheduler is started. */ + + /* Ensure XScuGic_CfgInitialize() has been called. In this demo it has + already been called from prvSetupHardware() in main(). */ + pxGICConfig = XScuGic_LookupConfig(XPAR_SCUGIC_SINGLE_DEVICE_ID); + xStatus = XScuGic_CfgInitialize(&xInterruptController, pxGICConfig, pxGICConfig->CpuBaseAddress); + configASSERT(xStatus == XST_SUCCESS); + (void) xStatus; /* Remove compiler warning if configASSERT() is not defined. */ + + /* The priority must be the lowest possible. */ + XScuGic_SetPriorityTriggerType(&xInterruptController, + XPAR_SCUTIMER_INTR, + portLOWEST_USABLE_INTERRUPT_PRIORITY << portPRIORITY_SHIFT, + ucRisingEdge); + + /* Install the FreeRTOS tick handler. */ + xStatus = XScuGic_Connect( + &xInterruptController, XPAR_SCUTIMER_INTR, (Xil_ExceptionHandler) FreeRTOS_Tick_Handler, (void *) &xTimer); + configASSERT(xStatus == XST_SUCCESS); + (void) xStatus; /* Remove compiler warning if configASSERT() is not defined. */ + + /* Initialise the timer. */ + pxTimerConfig = XScuTimer_LookupConfig(XPAR_SCUTIMER_DEVICE_ID); + xStatus = XScuTimer_CfgInitialize(&xTimer, pxTimerConfig, pxTimerConfig->BaseAddr); + configASSERT(xStatus == XST_SUCCESS); + (void) xStatus; /* Remove compiler warning if configASSERT() is not defined. */ + + /* Enable Auto reload mode. */ + XScuTimer_EnableAutoReload(&xTimer); + + /* Ensure there is no prescale. */ + XScuTimer_SetPrescaler(&xTimer, 0); + + /* Load the timer counter register. */ + XScuTimer_LoadTimer(&xTimer, XSCUTIMER_CLOCK_HZ / configTICK_RATE_HZ); + + /* Start the timer counter and then wait for it to timeout a number of + times. */ + XScuTimer_Start(&xTimer); + + /* Enable the interrupt for the xTimer in the interrupt controller. */ + XScuGic_Enable(&xInterruptController, XPAR_SCUTIMER_INTR); + + /* Enable the interrupt in the xTimer itself. */ + vClearTickInterrupt(); + XScuTimer_EnableInterrupt(&xTimer); +} +/*-----------------------------------------------------------*/ + +void vClearTickInterrupt(void) +{ + XScuTimer_ClearInterruptStatus(&xTimer); +} +/*-----------------------------------------------------------*/ + +/* This is the callback function which is called by the FreeRTOS Cortex-A port +layer in response to an interrupt. If the function is called +vApplicationFPUSafeIRQHandler() then it is called after the floating point +registers have been saved. If the function is called vApplicationIRQHandler() +then it will be called without first having saved the FPU registers. See +http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html for +more information */ +void vApplicationFPUSafeIRQHandler(uint32_t ulICCIAR) +{ + extern const XScuGic_Config XScuGic_ConfigTable[]; + static const XScuGic_VectorTableEntry *pxVectorTable + = XScuGic_ConfigTable[XPAR_SCUGIC_SINGLE_DEVICE_ID].HandlerTable; + uint32_t ulInterruptID; + const XScuGic_VectorTableEntry *pxVectorEntry; + + /* Re-enable interrupts. */ + __asm("cpsie i"); + + /* The ID of the interrupt is obtained by bitwise anding the ICCIAR value + with 0x3FF. */ + ulInterruptID = ulICCIAR & 0x3FFUL; + if (ulInterruptID < XSCUGIC_MAX_NUM_INTR_INPUTS) { + /* Call the function installed in the array of installed handler functions. */ + pxVectorEntry = &(pxVectorTable[ulInterruptID]); + pxVectorEntry->Handler(pxVectorEntry->CallBackRef); + } +} diff --git a/sdk/shared/README.md b/sdk/shared/README.md index acf8ca46..49cda056 100644 --- a/sdk/shared/README.md +++ b/sdk/shared/README.md @@ -1,30 +1,30 @@ -# Shared Code Folder - -This folder (`AMDC-Firmware/sdk/shared`) contains source code shared by both CPU applications in the v2, FreeRTOS-based firmware. - -Shared code includes system-level source code for inter-core communication, interrupts, etc, as well as the [FreeRTOS-Kernel](https://github.com/FreeRTOS/FreeRTOS-Kernel) source code, which is available in `AMDC-Firmware/sdk/FreeRTOS-Kernel` as a [Git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules). - -### Differentiating code between CPUs - -If you need to include or run slightly different code on CPU 0 and CPU 1 in a shared source file, it can be done using the `#if` directive like so: - -```c -#include xparameters.h // Must be included to gain access to the XPAR_CPU_ID definition -#include foo.h -#include bar.h - -// Code to be included on both CPUs - -#if XPAR_CPU_ID == 0 - -// Code for CPU 0 only - -#elif XPAR_CPU_ID == 1 - -// Code for CPU 1 only - -#endif - -// More code to be included on both CPUs - -``` +# Shared Code Folder + +This folder (`AMDC-Firmware/sdk/shared`) contains source code shared by both CPU applications in the v2, FreeRTOS-based firmware. + +Shared code includes system-level source code for inter-core communication, interrupts, etc, as well as the [FreeRTOS-Kernel](https://github.com/FreeRTOS/FreeRTOS-Kernel) source code, which is available in `AMDC-Firmware/sdk/FreeRTOS-Kernel` as a [Git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules). + +### Differentiating code between CPUs + +If you need to include or run slightly different code on CPU 0 and CPU 1 in a shared source file, it can be done using the `#if` directive like so: + +```c +#include xparameters.h // Must be included to gain access to the XPAR_CPU_ID definition +#include foo.h +#include bar.h + +// Code to be included on both CPUs + +#if XPAR_CPU_ID == 0 + +// Code for CPU 0 only + +#elif XPAR_CPU_ID == 1 + +// Code for CPU 1 only + +#endif + +// More code to be included on both CPUs + +``` diff --git a/sdk/shared/drv/analog.c b/sdk/shared/drv/analog.c new file mode 100644 index 00000000..e0b9ea26 --- /dev/null +++ b/sdk/shared/drv/analog.c @@ -0,0 +1,103 @@ +#include "drv/analog.h" +#include "drv/analog_defs.h" +#include "sys/defines.h" +#include + +static volatile uint32_t *m_adc; + +void analog_init(uint32_t base_addr) +{ + // Store base address for IP + m_adc = (volatile uint32_t *) base_addr; + + // Set SCK to 50MHz (200MHz / 4) + analog_set_clkdiv(ANALOG_CLKDIV4); + + // Set PWM sync to both high and low of triangle carrier + bool sync_to_carrier_high = true; + bool sync_to_carrier_low = true; + analog_set_pwm_sync(sync_to_carrier_high, sync_to_carrier_low); +} + +int analog_set_clkdiv(analog_clkdiv_e div) +{ + // Make sure the divisor is valid + if (!analog_is_valid_clkdiv(div)) { + return FAILURE; + } + + // Read in CONTROL register + uint32_t reg = m_adc[ANALOG_DEFS_OFFSET_CONTROL / 4]; + + // Clear lower 2 bits + reg &= ~ANALOG_DEFS_CONTROL_CLKDIV_MASK; + + // Set lower 2 bits + reg |= (div & ANALOG_DEFS_CONTROL_CLKDIV_MASK); + + // Write out CONTROL register + m_adc[ANALOG_DEFS_OFFSET_CONTROL / 4] = reg; + + return SUCCESS; +} + +void analog_get_clkdiv(analog_clkdiv_e *out_div) +{ + // Read in CONTROL register + uint32_t reg = m_adc[ANALOG_DEFS_OFFSET_CONTROL / 4]; + + // Make sure we only look at lower 2 bits + uint32_t value = reg & ANALOG_DEFS_CONTROL_CLKDIV_MASK; + + *out_div = value; +} + +int analog_getf(analog_channel_e channel, float *out_value) +{ + // Read raw binary value from ADC + int16_t val; + if (analog_geti(channel, &val) != SUCCESS) { + return FAILURE; + } + + // Conversion from raw bits to voltage + *out_value = (float) (val) / 400.0; + + return SUCCESS; +} + +int analog_geti(analog_channel_e channel, int16_t *out_value) +{ + // Make sure channel in valid + if (!analog_is_valid_channel(channel)) { + return FAILURE; + } + + // Read in ADC data register + uint32_t reg = m_adc[channel]; + + *out_value = (int16_t) reg; + + return SUCCESS; +} + +void analog_set_pwm_sync(bool sync_to_carrier_high, bool sync_to_carrier_low) +{ + // Read in CONTROL register + uint32_t reg = m_adc[ANALOG_DEFS_OFFSET_CONTROL / 4]; + + if (sync_to_carrier_high) { + reg |= (1 << ANALOG_DEFS_CONTROL_PWM_SYNC_HIGH_SHIFT); + } else { + reg &= ~(1 << ANALOG_DEFS_CONTROL_PWM_SYNC_HIGH_SHIFT); + } + + if (sync_to_carrier_low) { + reg |= (1 << ANALOG_DEFS_CONTROL_PWM_SYNC_LOW_SHIFT); + } else { + reg &= ~(1 << ANALOG_DEFS_CONTROL_PWM_SYNC_LOW_SHIFT); + } + + // Write out CONTROL register + m_adc[ANALOG_DEFS_OFFSET_CONTROL / 4] = reg; +} diff --git a/sdk/shared/drv/analog.h b/sdk/shared/drv/analog.h new file mode 100644 index 00000000..0958f5ef --- /dev/null +++ b/sdk/shared/drv/analog.h @@ -0,0 +1,68 @@ +#ifndef ANALOG_H +#define ANALOG_H + +#include "drv/hardware_targets.h" +#include "usr/user_config.h" +#include +#include + +// From Vivado build output +#include "xparameters.h" + +#define ANALOG_BASE_ADDR (XPAR_AMDC_ADC_0_S00_AXI_BASEADDR) + +typedef enum { + // Keep first channel index at 0! + ANALOG_IN1 = 0, + ANALOG_IN2, + ANALOG_IN3, + ANALOG_IN4, + ANALOG_IN5, + ANALOG_IN6, + ANALOG_IN7, + ANALOG_IN8, + + // Keep this as last entry! + ANALOG_NUM_CHANNELS, +} analog_channel_e; + +typedef enum { + ANALOG_CLKDIV2 = 0, + ANALOG_CLKDIV4, + ANALOG_CLKDIV8, + ANALOG_CLKDIV16, +} analog_clkdiv_e; + +static inline bool analog_is_valid_channel(analog_channel_e channel) +{ + if (channel >= ANALOG_IN1 && channel < ANALOG_NUM_CHANNELS) { + return true; + } + + return false; +} + +static inline bool analog_is_valid_clkdiv(analog_clkdiv_e div) +{ + if (div == ANALOG_CLKDIV2 || div == ANALOG_CLKDIV4 || div == ANALOG_CLKDIV8 || div == ANALOG_CLKDIV16) { + return true; + } + + return false; +} + +void analog_init(uint32_t base_addr); + +int analog_set_clkdiv(analog_clkdiv_e div); +void analog_get_clkdiv(analog_clkdiv_e *out_div); + +int analog_getf(analog_channel_e channel, float *out_value); +int analog_geti(analog_channel_e channel, int16_t *out_value); + +void analog_set_pwm_sync(bool sync_to_carrier_high, bool sync_to_carrier_low); + +// TODO(NP): Implement digital low-pass filtering in FPGA, +// then, implement C driver which looks like this: +// void analog_set_filter(analog_channel_e channel, ...); + +#endif // ANALOG_H diff --git a/sdk/shared/drv/analog_defs.h b/sdk/shared/drv/analog_defs.h new file mode 100644 index 00000000..6715b951 --- /dev/null +++ b/sdk/shared/drv/analog_defs.h @@ -0,0 +1,42 @@ +#ifndef ANALOG_DEFS_H +#define ANALOG_DEFS_H + +#include "drv/hardware_targets.h" +#include "usr/user_config.h" + +// =============== +// Number of slave registers in this IP +// =============== +#define ANALOG_DEFS_NUM_SLAVE_REGS (10) + +// =============== +// Offsets for the relevant slave registers (in bytes). +// Separated by 4 bytes since each register is 32 bits. +// =============== +#define ANALOG_DEFS_OFFSET_CHANNEL1 (0 * 4) +#define ANALOG_DEFS_OFFSET_CHANNEL2 (1 * 4) +#define ANALOG_DEFS_OFFSET_CHANNEL3 (2 * 4) +#define ANALOG_DEFS_OFFSET_CHANNEL4 (3 * 4) +#define ANALOG_DEFS_OFFSET_CHANNEL5 (4 * 4) +#define ANALOG_DEFS_OFFSET_CHANNEL6 (5 * 4) +#define ANALOG_DEFS_OFFSET_CHANNEL7 (6 * 4) +#define ANALOG_DEFS_OFFSET_CHANNEL8 (7 * 4) +#define ANALOG_DEFS_OFFSET_CONTROL (8 * 4) +#define ANALOG_DEFS_OFFSET_UNUSED1 (9 * 4) + +// =============== +// CONTROL register +// =============== +#define ANALOG_DEFS_CONTROL_CLKDIV_WIDTH (2) // in bits +#define ANALOG_DEFS_CONTROL_CLKDIV_SHIFT (0) // up from reg[0] +#define ANALOG_DEFS_CONTROL_CLKDIV_MASK (0x3) + +#define ANALOG_DEFS_CONTROL_PWM_SYNC_HIGH_WIDTH (1) // in bits +#define ANALOG_DEFS_CONTROL_PWM_SYNC_HIGH_SHIFT (2) // up from reg[0] +#define ANALOG_DEFS_CONTROL_PWM_SYNC_HIGH_MASK (0x1) + +#define ANALOG_DEFS_CONTROL_PWM_SYNC_LOW_WIDTH (1) // in bits +#define ANALOG_DEFS_CONTROL_PWM_SYNC_LOW_SHIFT (3) // up from reg[0] +#define ANALOG_DEFS_CONTROL_PWM_SYNC_LOW_MASK (0x1) + +#endif // ANALOG_DEFS_H diff --git a/sdk/shared/drv/bsp.c b/sdk/shared/drv/bsp.c new file mode 100644 index 00000000..a88a8828 --- /dev/null +++ b/sdk/shared/drv/bsp.c @@ -0,0 +1,95 @@ +#include "drv/hardware_targets.h" +#include "usr/user_config.h" + +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_D) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) \ + || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) +// Ensure a valid hardware target is specified +// NOTE: this firmware only supports REV D hardware onward +#else +#error "ERROR: Hardware target not specified correctly in user_config.h" +// If you have this error, please define USER_CONFIG_HARDWARE_TARGET in your usr/user_config.h file! +#endif + +#include "drv/analog.h" +#include "drv/bsp.h" +#include "drv/cpu_timer.h" +#include "drv/dac.h" +#include "drv/eddy_current_sensor.h" +#include "drv/encoder.h" +#include "drv/fpga_timer.h" +#include "drv/gp3io_mux.h" +#include "drv/gpio_mux.h" +#include "drv/led.h" +#include "drv/pwm.h" +#include "drv/sts_mux.h" +#include "drv/timer.h" +#include "drv/uart.h" +#include "sys/cmd/cmd_hw.h" +#include "sys/defines.h" +#include + +void bsp_init(void) +{ + if (uart_init() != SUCCESS) { + printf("ERROR: UART init failed!\n"); + while (1) { + }; + } + + // Busy loop to wait for UART to warm up... :) + volatile int i; + for (i = 0; i < 10e6; i++) { + asm("nop"); + } + + // Print welcome message to user + printf("Advanced Motor Drive Controller\n"); + + switch (USER_CONFIG_HARDWARE_TARGET) { + case AMDC_REV_D: + printf("Hardware Target: REV D\n"); + break; + + case AMDC_REV_E: + printf("Hardware Target: REV E\n"); + break; + + case AMDC_REV_F: + printf("Hardware Target: REV F\n"); + break; + + default: + printf("ERROR: Unknown AMDC hardware revision\n"); + while (1) { + } + } + + printf("(C) Severson Research Group\n"); + printf("--------------------------------\n"); + printf("\n"); + + printf("BSP:\tInitializing...\n"); + + encoder_init(); + analog_init(ANALOG_BASE_ADDR); + pwm_init(); + + fpga_timer_init(); + cpu_timer_init(); + led_init(); + sts_mux_init(); + dac_init(); + eddy_current_sensor_init(); + +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_D) + gpio_mux_init(); +#elif (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + gp3io_mux_init(); +#endif + +#if USER_CONFIG_ENABLE_WATCHDOG == 1 + watchdog_init(); +#endif + + cmd_hw_register(); +} diff --git a/sdk/shared/drv/bsp.h b/sdk/shared/drv/bsp.h new file mode 100644 index 00000000..debd2685 --- /dev/null +++ b/sdk/shared/drv/bsp.h @@ -0,0 +1,6 @@ +#ifndef BSP_H +#define BSP_H + +void bsp_init(void); + +#endif // BSP_H diff --git a/sdk/shared/drv/cpu_timer.c b/sdk/shared/drv/cpu_timer.c new file mode 100644 index 00000000..89f524bd --- /dev/null +++ b/sdk/shared/drv/cpu_timer.c @@ -0,0 +1,69 @@ +#include "drv/cpu_timer.h" +#include "sys/defines.h" +//#include "xparameters.h" +//#include "xtmrctr.h" + +// Code from StackOverflow post: +// https://stackoverflow.com/questions/3247373/3250835#3250835 + +static inline void init_perfcounters(int32_t do_reset, int32_t enable_divider); + +static const double CPU_CLOCK_FREQ_MHZ = 666.666; +static const double CPU_CLOCK_FREQ_HZ = CPU_CLOCK_FREQ_MHZ * 1e6; + +void cpu_timer_init(void) +{ + /* enable user-mode access to the performance counter*/ + asm("MCR p15, 0, %0, C9, C14, 0\n\t" ::"r"(1)); + + /* disable counter overflow interrupts (just in case)*/ + asm("MCR p15, 0, %0, C9, C14, 2\n\t" ::"r"(0x8000000f)); + + init_perfcounters(1, 0); +} + +uint32_t cpu_timer_now(void) +{ + uint32_t value; + // Read CCNT Register + asm volatile("MRC p15, 0, %0, c9, c13, 0\t\n" : "=r"(value)); + return value; +} + +double cpu_timer_ticks_to_usec(uint32_t ticks) +{ + double usec = (double) ticks / CPU_CLOCK_FREQ_MHZ; + return usec; +} + +double cpu_timer_ticks_to_sec(uint32_t ticks) +{ + double sec = (double) ticks / CPU_CLOCK_FREQ_HZ; + return sec; +} + +static inline void init_perfcounters(int32_t do_reset, int32_t enable_divider) +{ + // in general enable all counters (including cycle counter) + int32_t value = 1; + + // peform reset: + if (do_reset) { + value |= 2; // reset all counters to zero. + value |= 4; // reset cycle counter to zero. + } + + if (enable_divider) + value |= 8; // enable "by 64" divider for CCNT. + + value |= 16; + + // program the performance-counter control-register: + asm volatile("MCR p15, 0, %0, c9, c12, 0\t\n" ::"r"(value)); + + // enable all counters: + asm volatile("MCR p15, 0, %0, c9, c12, 1\t\n" ::"r"(0x8000000f)); + + // clear overflows: + asm volatile("MCR p15, 0, %0, c9, c12, 3\t\n" ::"r"(0x8000000f)); +} diff --git a/sdk/shared/drv/cpu_timer.h b/sdk/shared/drv/cpu_timer.h new file mode 100644 index 00000000..9b98904d --- /dev/null +++ b/sdk/shared/drv/cpu_timer.h @@ -0,0 +1,17 @@ +#ifndef CPU_TIMER_H +#define CPU_TIMER_H + +#include + +void cpu_timer_init(void); + +// Return the current time in CPU clock cycles (666.666 MHZ clock) +uint32_t cpu_timer_now(void); + +// Convert CPU clock ticks to usec +double cpu_timer_ticks_to_usec(uint32_t ticks); + +// Convert CPU clock ticks to sec +double cpu_timer_ticks_to_sec(uint32_t ticks); + +#endif // CPU_TIMER_H diff --git a/sdk/shared/drv/dac.c b/sdk/shared/drv/dac.c new file mode 100644 index 00000000..f4d02afe --- /dev/null +++ b/sdk/shared/drv/dac.c @@ -0,0 +1,46 @@ +#include "drv/dac.h" +#include "xil_io.h" +#include +#include + +#define DAC_BASE_ADDR (0x43C60000) + +void dac_init(void) +{ + printf("DAC:\tInitializing...\n"); + + // Default Reference divider and each channel Gain to 2/2 + dac_set_raw(DAC_REG_GAIN, 0x000401FF); + + // Default all channels to be synchronously triggered + dac_set_raw(DAC_REG_SYNC, 0x0002FFFF); + + // Default all channel values to 0V (redundant to power on reset) + dac_set_broadcast(0); +} + +void dac_set_voltage(uint8_t ch, double voltage) +{ + double range = 20; + uint32_t value = (voltage + 10) * DAC_MAX_CODE / range; + + dac_set_raw(ch + 0x8, (ch + 0x8) << 16 | (value << 4 & 0xFFF0)); +} + +void dac_set_broadcast(double voltage) +{ + double range = 20; + uint32_t value = (voltage + 10) * DAC_MAX_CODE / range; + + dac_set_raw(0x6, (0x6) << 16 | (value << 4 & 0xFFF0)); +} + +void dac_set_trigger(void) +{ + Xil_Out32(DAC_BASE_ADDR + (DAC_REG_TRIGGER * sizeof(uint32_t)), 0x00000010); +} + +void dac_set_raw(dac_reg_t reg, uint32_t value) +{ + Xil_Out32(DAC_BASE_ADDR + (reg * sizeof(uint32_t)), value); +} diff --git a/sdk/shared/drv/dac.h b/sdk/shared/drv/dac.h new file mode 100644 index 00000000..c80b634c --- /dev/null +++ b/sdk/shared/drv/dac.h @@ -0,0 +1,34 @@ +#ifndef DAC_H +#define DAC_H + +#include + +typedef enum { + DAC_REG_SYNC = 2, + DAC_REG_CONFIG = 3, + DAC_REG_GAIN = 4, + DAC_REG_TRIGGER = 5, + DAC_REG_BRDCAST = 6, + DAC_REG_DAC0 = 8, + DAC_REG_DAC1 = 9, + DAC_REG_DAC2 = 10, + DAC_REG_DAC3 = 11, + DAC_REG_DAC4 = 12, + DAC_REG_DAC5 = 13, + DAC_REG_DAC6 = 14, + DAC_REG_DAC7 = 15, +} dac_reg_t; + +#define DAC_MAX_CODE (4095) + +void dac_init(void); + +void dac_set_voltage(uint8_t ch, double voltage); + +void dac_set_broadcast(double voltage); + +void dac_set_trigger(void); + +void dac_set_raw(dac_reg_t reg, uint32_t value); + +#endif // DAC_H diff --git a/sdk/shared/drv/docs/DAC-Expansion-Board.md b/sdk/shared/drv/docs/DAC-Expansion-Board.md new file mode 100644 index 00000000..0418b8ad --- /dev/null +++ b/sdk/shared/drv/docs/DAC-Expansion-Board.md @@ -0,0 +1,50 @@ +# DAC Expansion Board Driver + +This driver is used to control and configure the DAC expansion board Rev B IP core in the FPGA through the AXI4-Lite interface. + +## Files +All files for the inverter status mux driver are in the driver directory ([`common/drv/`](/sdk/bare/common/drv/)). + +``` +drv/ +|-- dac.c +|-- dac.h +``` + +## Enabling the DAC Drivers + +Several configuration need to be made to enable the DAC driver. The first configuration occurs in the [sts_mux.h](Status-Mux.md) file. The DAC IP core needs to be mapped to the desired Inverter Port for operation. By default the DAC IP core is connected to `STS_MUX_DEVICE1`. The desired port (`INVERTER_PORTn`) must be set to `STS_MUX_DEVICE1`. Lastly the direction of the Status lines A, B, and C must be configured as outputs. The `STS_MUX_X_DIR` macros must be set to `STS_MUX_OUTPUT` in the [sts_mux.h](Status-Mux.md) file, and the hardware must be configured as well. + +## Configuring the DAC +### Functions +```C +void dac_init(void) +``` + +This function initializes the DAC expansion board to +/- 10V output range with all channels synchronously triggering. + +```C +void dac_set_raw(dac_reg_t reg, uint32_t value) +``` + +This function initiates a SPI transmission to the given register. Calling this function can be thought of as transmitting the given value directly to the given register in DAC IC on the expansion board. + +## Driving the DAC +### Functions +```C +void dac_set_voltage(uint8_t ch, double voltage) +``` + +This function converts the given voltage into a hex code used by the DAC IC on the expansion board for setting the desired voltage. Calling this function will initiate a SPI transmission to the channel register on the DAC IC. + +```C +void dac_set_broadcast(double voltage) +``` + +This function converts the given voltage into a hex code used by the DAC IC on the expansion board for setting the desired voltages on all broadcast enabled channels simultaneously. + +```C +void dac_set_trigger(void) +``` + +This function initiates a trigger event on the DAC IC. All synchronous enabled channels will update their outputs with the current register value. diff --git a/sdk/shared/drv/docs/Eddy-Current-Sensor.md b/sdk/shared/drv/docs/Eddy-Current-Sensor.md new file mode 100644 index 00000000..6b95196c --- /dev/null +++ b/sdk/shared/drv/docs/Eddy-Current-Sensor.md @@ -0,0 +1,129 @@ +# Eddy Current Sensor Driver + +This driver is used to control and configure the AMDC eddy current sensor IP core in the FPGA through the AXI4-Lite interface. + +## Files +All files for the eddy current sensor driver are in the driver directory ([`common/drv/`](/sdk/bare/common/drv/)). + +``` +drv/ +|-- eddy_current_sensor.c +|-- eddy_current_sensor.h +``` + +## Configuring the AMDC + +The [GPIO mux](GPIO_Mux.md) is used to map IP cores to the physical GPIO (IsoSPI) ports. It must be configured to map the `eddy_current_sensor_1.0` IP core to the intended GPIO port. The following function can be used to configure the GPIO port mapping: + +```C +void gpio_mux_set_device(port, device); +``` + +By default the `eddy_current_sensor_1.0` IP core is connected to device 1 in the FPGA firmware. The example below would configure the GPIO mux to map the IP core to port 1. + +```C +gpio_mux_set_device(1, 1); +``` + +## Driving the Eddy Current Sensor +### Functions +```C +void eddy_current_sensor_init(void) +``` + +This function is called by the BSP and initializes the eddy_current_sensor sample rate to 20kHz to match the AMDC callback frequency. + +```C +void eddy_current_sensor_enable(void) +``` + +This function enables SPI transmissions to the eddy current sensor. SPI transmission will occur continuously until the drivers are disabled + +```C +void eddy_current_sensor_disable(void) +``` + +This function disables SPI transmissions to the eddy current sensor. + +```C +void eddy_current_sensor_set_sample_rate(double sample_rate) +``` + +This function sets frequency of the SPI clock and conversion signal to match the given sample_rate parameter in Hz. The SPI clock is 25 times greater than the sample rate. + +```C +void eddy_current_sensor_set_divider(uint8_t divider) +``` + +This function sets the IP register used to modulate the SPI frequency. + +```C +double eddy_current_sensor_read_x_voltage(void) +``` + +This function reads the X data from the IP data register. The returned data is sign extended 2's compliment 18-bit data. + +```C +double eddy_current_sensor_read_y_voltage(void) +``` + +This function reads the Y data from the IP data register. The returned data is sign extended 2's compliment 18-bit data. + +## Example Code + +The desired sampling rate for the eddy current sensor should be set in the users initialization of their C drivers. The sampling rate ranges from 2KSps to 500KSps. The sensor data can be read from an existing callback function or one can be created and registered with FreeRTOS. The following code is a simple example of a scheduled callback function that reads the sensors positional data: + +```C +/////////////////////////////////// +// In my_driver.c +/////////////////////////////////// + +void my_driver_init() { + + // Set the sample rate of the eddy current sensor to 40KSps (1MHz SPI clock) + eddy_current_sensor_set_sample_rate(40000); + + // Initializes a task to read the eddy current sensor data + task_eddy_current_sensor_init(); + + + // More Initialization code... + + return; +} + + +/////////////////////////////////// +// In task_eddy_current_sensor.c +////////////////////////////////// + +// Scheduler TCB which holds task "context" +static task_control_block_t tcb; + +int task_eddy_current_sensor_init(void) +{ + if (scheduler_tcb_is_registered(&tcb)) { + return FAILURE; + } + + // Fill TCB with parameters + scheduler_tcb_init(&tcb, task_eddy_current_sensor_callback, NULL, "eddy_current", TASK_DAC_INTERVAL_USEC); + + // Register task with scheduler + return scheduler_tcb_register(&tcb); +} + +void task_eddy_current_sensor_callback(void *arg) +{ + + // Read X and Y positional data as voltage + double voltage_x = eddy_current_sensor_read_x_voltage(); + double voltage_y = eddy_current_sensor_read_y_voltage(); + + + // Use the positional data + my_bearing_control_function(voltage_x, voltage_y); + + return; +} +``` \ No newline at end of file diff --git a/sdk/shared/drv/docs/GPIO-Mux.md b/sdk/shared/drv/docs/GPIO-Mux.md new file mode 100644 index 00000000..68fc7502 --- /dev/null +++ b/sdk/shared/drv/docs/GPIO-Mux.md @@ -0,0 +1,46 @@ +# Inverter GPIO Mux Driver + +This driver is used to control and configure the GPIO mux IP core in the FPGA through the AXI4-Lite interface. + +## Files +All files for the GPIO mux driver are in the driver directory ([`/sdk/app_cpu1/common/drv/`](/sdk/app_cpu1/common/drv/)). + +``` +drv/ +|-- gpio_mux.c +|-- gpio_mux.h +``` +## Default Connections and Operation + +The mux IP can be connected to one of eight different IP drivers + +## Configuring the Mux + +The following functions are used to configuring the GPIO mux IP. The `gpio_mux_init()` function is called upon initialization of the AMDC and sets the GPIO mux into a default state defined by the macros as described below. The `gpio_mux_set_device()` function is the intended way of configuring the GPIO mux IP. The function must be called by the user app. During runtime, the CLI commands can be used to configure the mux. + +### Functions + +`gpio_mux_init(void)` + +Initializes the GPIO mux with default configurations. Each IsoSPI port is mapped to the device drivers defined in its respective macro in `gpio_mux.h`. + + +`void gpio_mux_set_device(port, device);` + +Remaps the GPIO lines on the specified IsoSPI port to the specified device driver. Each register corresponding to the IsoSPI port are written to via the AXI4-Lite interface with the device address (1-4). + +### CLI Commands + +The GPIO mux can be configured at runtime using commands entered in the command line interface. The command follows the form `hw mux gpio ` where `` and `` specify which device driver is connected to which IsoSPI port. + +### Macros + +The following macros are used to configure which device driver each IsoSPI port is mapped to upon initialization. + +Each port is set to the `GPIO_MUX_UNUSED` macro by default which disables the GPIO lines on the port by holding the lines to logic low. Each port can be mapped to a specific driver IP core upon initialization of the AMDC by setting the port macro to one of the devices (`GPIO_MUX_DEVICE1` - `GPIO_MUX_DEVICE4`) + +```C +#define GPIO_PORT1 GPIO_MUX_UNUSED + +#define GPIO_PORT2 GPIO_MUX_UNUSED +``` diff --git a/sdk/shared/drv/docs/README.md b/sdk/shared/drv/docs/README.md new file mode 100644 index 00000000..8273451f --- /dev/null +++ b/sdk/shared/drv/docs/README.md @@ -0,0 +1,21 @@ +# AMDC Drivers + +This folder houses the documentation of the drivers for the bare framework on the AMDC platform. + +## AMDC REV D Drivers + +### [`DAC-Expansion-Board`](DAC-Expansion-Board.md) + +This driver is responsible for driving the DAC expansion board Rev B. + +### [`Status-Mux`](Status-Mux.md) + +This driver is responsible for configuring the inverter status mux IP core. + +### [`GPIO-Mux`](GPIO-Mux.md) + +This driver is responsible for configuring the IsoSPI GPIO mux IP core. + +### [`Eddy-Current-Sensor`](Eddy-Current-Sensor.md) + +This driver is responsible for configuring and reading data from the Eddy Current Sensor IP core. \ No newline at end of file diff --git a/sdk/shared/drv/docs/Status-Mux.md b/sdk/shared/drv/docs/Status-Mux.md new file mode 100644 index 00000000..8a0691ef --- /dev/null +++ b/sdk/shared/drv/docs/Status-Mux.md @@ -0,0 +1,68 @@ +# Inverter Status Mux Driver + +This driver is used to control and configure the inverter status mux IP core in the FPGA through the AXI4-Lite interface. + +## Files +All files for the inverter status mux driver are in the driver directory ([`common/drv/`](/sdk/bare/common/drv/)). + +``` +drv/ +|-- sts_mux.c +|-- sts_mux.h +``` +## Default Connections and Operation + +The mux IP can be connected to 8 different IP drivers + +## Configuring the Mux +### Macros + +The following macros are used to configure which device driver each inverter port is mapped to upon initialization and the direction of each status line. + +Each port is set to the `STS_MUX_UNUSED` macro by default which maps the port status lines directly to the inverter IP core. Each port can be mapped to a specific driver IP core by setting the port macro to one of the devices (`STS_MUX_DEVICE1` - `STS_MUX_DEVICE8`) + +```C +#define INVERTER_PORT1 STS_MUX_UNUSED + +#define INVERTER_PORT2 STS_MUX_UNUSED + +#define INVERTER_PORT3 STS_MUX_UNUSED + +#define INVERTER_PORT4 STS_MUX_UNUSED + +#define INVERTER_PORT5 STS_MUX_UNUSED + +#define INVERTER_PORT6 STS_MUX_UNUSED + +#define INVERTER_PORT7 STS_MUX_UNUSED + +#define INVERTER_PORT8 STS_MUX_UNUSED +``` + +The status lines are set to the default directions described in the [AMDC Hardware](https://github.com/Severson-Group/AMDC-Hardware/blob/develop/docs/PowerStack.md) documentation. Status A is an Output and Status B, C, and D are inputs. + +```C +#define STS_MUX_A_DIR STS_MUX_OUTPUT + +#define STS_MUX_B_DIR STS_MUX_INPUT + +#define STS_MUX_C_DIR STS_MUX_INPUT + +#define STS_MUX_D_DIR STS_MUX_INPUT +``` +### Functions +`sts_mux_init(void)` + +Initializes the inverter status mux with default configurations. All status A lines are configured as outputs and all status B, C, and D lines are configured as inputs. Each inverter port in mapped to the device defined in its respective macro in `sts_mux.h`. + +`void sts_mux_set_line(port, device, line);` + +Remaps a single status line. The register corresponding to the specified port and line is written to via the AXI4-Lite interface with the device address (1-8). + +`void sts_mux_set_device(port, device);` + +Remaps all the status lines on the given port to the device. Each register corresponding to the status lines are written to via the AXI4-Lite interface with the device address (1-8). + +`void sts_mux_set_output(line, bool);` + +Configures all of the given lines (A, B, C or D) to be outputs if the bool is true or inputs if the bool is false. diff --git a/sdk/shared/drv/eddy_current_sensor.c b/sdk/shared/drv/eddy_current_sensor.c new file mode 100644 index 00000000..908ae8a0 --- /dev/null +++ b/sdk/shared/drv/eddy_current_sensor.c @@ -0,0 +1,148 @@ +#include "drv/eddy_current_sensor.h" +#include "usr/user_config.h" +#include "xil_io.h" +#include +#include +#include + +void eddy_current_sensor_init(void) +{ + printf("EDDY CURRENT SENSOR:\tInitializing...\n"); + + // Default PWM carrier frequency for AMDC is 100 kHz + // To trigger on both the peak and valley of the PWM carrier (200 kHz), SCLK needs to be quite fast. + // The default SCLK frequency of 5 MHz allows us to fit a conversion cycle into the 5us interval. + eddy_current_sensor_trigger_on_pwm_both(EDDY_CURRENT_SENSOR_1_BASE_ADDR); + eddy_current_sensor_set_timing(EDDY_CURRENT_SENSOR_1_BASE_ADDR, + EDDY_CURRENT_SENSOR_DEFAULT_SCLK_FREQ_KHZ, + EDDY_CURRENT_SENSOR_DEFAULT_PROP_DELAY_NS); + +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + eddy_current_sensor_trigger_on_pwm_both(EDDY_CURRENT_SENSOR_2_BASE_ADDR); + eddy_current_sensor_trigger_on_pwm_both(EDDY_CURRENT_SENSOR_3_BASE_ADDR); + eddy_current_sensor_trigger_on_pwm_both(EDDY_CURRENT_SENSOR_4_BASE_ADDR); + eddy_current_sensor_set_timing(EDDY_CURRENT_SENSOR_2_BASE_ADDR, + EDDY_CURRENT_SENSOR_DEFAULT_SCLK_FREQ_KHZ, + EDDY_CURRENT_SENSOR_DEFAULT_PROP_DELAY_NS); + eddy_current_sensor_set_timing(EDDY_CURRENT_SENSOR_3_BASE_ADDR, + EDDY_CURRENT_SENSOR_DEFAULT_SCLK_FREQ_KHZ, + EDDY_CURRENT_SENSOR_DEFAULT_PROP_DELAY_NS); + eddy_current_sensor_set_timing(EDDY_CURRENT_SENSOR_4_BASE_ADDR, + EDDY_CURRENT_SENSOR_DEFAULT_SCLK_FREQ_KHZ, + EDDY_CURRENT_SENSOR_DEFAULT_PROP_DELAY_NS); +#endif +} + +void eddy_current_sensor_trigger_on_pwm_high(uint32_t base_addr) +{ + // Get the current value of the config register and set the pwm_high trigger bit + uint32_t config_reg_address = base_addr + (3 * sizeof(uint32_t)); + Xil_Out32(config_reg_address, (Xil_In32(config_reg_address) | 0x1)); +} + +void eddy_current_sensor_trigger_on_pwm_low(uint32_t base_addr) +{ + // Get the current value of the config register and set the pwm_low trigger bit + uint32_t config_reg_address = base_addr + (3 * sizeof(uint32_t)); + Xil_Out32(config_reg_address, (Xil_In32(config_reg_address) | 0x2)); +} + +void eddy_current_sensor_trigger_on_pwm_both(uint32_t base_addr) +{ + // Get the current value of the config register and set both the pwm_high and pwm_low trigger bits + uint32_t config_reg_address = base_addr + (3 * sizeof(uint32_t)); + Xil_Out32(config_reg_address, (Xil_In32(config_reg_address) | 0x3)); +} + +void eddy_current_sensor_trigger_on_pwm_clear(uint32_t base_addr) +{ + // Get the current value of the config register and clear both the pwm_high and pwm_low trigger bits + uint32_t config_reg_address = base_addr + (3 * sizeof(uint32_t)); + Xil_Out32(config_reg_address, (Xil_In32(config_reg_address) & ~0x3)); +} + +void eddy_current_sensor_set_timing(uint32_t base_addr, uint32_t sclk_freq_khz, uint32_t propogation_delay_ns) +{ + // 5 MHz is max SCLK frequency (weird behaviour beyond 5 MHz) + // This is still sufficiently fast to complete at a sampling frequency of 200 kHz + if (sclk_freq_khz > 5000) { + sclk_freq_khz = 5000; + } + + // 500 kHz is min frequency (slower frequencies won't complete in a PWM carrier cycle) + if (sclk_freq_khz < 500) { + sclk_freq_khz = 500; + } + + // This is period in ns for one half of the sclk period + // We want half a period since sclk_cnt is the number of FPGA CLK cycles to wait before toggling SCLK + uint32_t sclk_half_period_ns = (1000000 / sclk_freq_khz) / 2; + + uint32_t fpga_period_ns = 1000 / FPGA_CLK_FREQ_MHZ; + + uint32_t sclk_cnt = sclk_half_period_ns / fpga_period_ns; + + Xil_Out32(base_addr + (2 * sizeof(uint32_t)), sclk_cnt); + + // SHIFT delayer + // Why is this needed? The Kaman adapter board's filtering introduces a significant + // propogation delay into the system. On the FPGA side, the SCLK signal + // being generated will fall, which is when we would like to sample the MISO line. + // However, the fall of SCLK will take a while to propogate through the adapter + // board (270ns for example) and then the valid data on the MISO lines will take a + // while (again, 270ns for example) to propogate back. In the example, this is + // a total round-trip propogation delay of 540ns. The actual delay depends on the + // RC filters used on the Kaman adapter board. + // + // This code takes the ONE-WAY propogation delay in nanoseconds of the Kaman adapter + // board's filtering, doubles it for the round-trip propogation delay, and then + // adds half of the user-requested SCLK period so that the shifting occurs halfway + // through when the bit is valid. See the amdc_spi_master.v for details on how + // the shift signal is propogated through a shift register and then the appropriate delay + // is selected by the shift_index value calculated below. + uint32_t delay_time = 2 * propogation_delay_ns; + + uint32_t shift_index = delay_time / fpga_period_ns; + + // 255 is an FPGA-imposed limit, as the SHIFT_INDEX register field is only 8-bit + if (shift_index > 255) { + shift_index = 255; + } + + Xil_Out32(base_addr + (4 * sizeof(uint32_t)), shift_index); +} + +static double bits_to_voltage(uint32_t data) +{ + bool is_negative = 0x20000 & data; + + // Convert 2's compliment to positive data + if (is_negative) { + data = ~data; + data += 1; + } + + // Convert data to voltage (+/-5V) + double resolution = 0.00003814697; // 5V / 2^17 + double voltage = (0x1FFFF & data) * resolution; // 17-bit data + + if (is_negative) { + voltage = -voltage; + } + + return voltage; +} + +double eddy_current_sensor_read_x_voltage(uint32_t base_addr) +{ + uint32_t x_data = Xil_In32(base_addr); + + return bits_to_voltage(x_data); +} + +double eddy_current_sensor_read_y_voltage(uint32_t base_addr) +{ + uint32_t y_data = Xil_In32(base_addr + (1 * sizeof(uint32_t))); + + return bits_to_voltage(y_data); +} diff --git a/sdk/shared/drv/eddy_current_sensor.h b/sdk/shared/drv/eddy_current_sensor.h new file mode 100644 index 00000000..9e1d8d85 --- /dev/null +++ b/sdk/shared/drv/eddy_current_sensor.h @@ -0,0 +1,41 @@ +#ifndef EDDY_CURRENT_SENSOR_H +#define EDDY_CURRENT_SENSOR_H + +#include "drv/hardware_targets.h" +#include "usr/user_config.h" +#include +#include + +#include "xparameters.h" + +#define FPGA_CLK_FREQ_MHZ (200) + +#define EDDY_CURRENT_SENSOR_DEFAULT_SCLK_FREQ_KHZ (5000) +#define EDDY_CURRENT_SENSOR_DEFAULT_PROP_DELAY_NS (10) + +#if USER_CONFIG_HARDWARE_TARGET == AMDC_REV_D +#define EDDY_CURRENT_SENSOR_MAX_IP_CORES (XPAR_AMDC_EDDY_CURRENT_SENSOR_NUM_INSTANCES) +#define EDDY_CURRENT_SENSOR_1_BASE_ADDR (XPAR_AMDC_EDDY_CURRENT_SE_0_S00_AXI_BASEADDR) +#endif + +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) +#define EDDY_CURRENT_SENSOR_MAX_IP_CORES (XPAR_AMDC_EDDY_CURRENT_SENSOR_NUM_INSTANCES) +#define EDDY_CURRENT_SENSOR_1_BASE_ADDR (XPAR_HIER_GPIO_0_AMDC_EDDY_CURRENT_SE_0_S00_AXI_BASEADDR) +#define EDDY_CURRENT_SENSOR_2_BASE_ADDR (XPAR_HIER_GPIO_1_AMDC_EDDY_CURRENT_SE_0_S00_AXI_BASEADDR) +#define EDDY_CURRENT_SENSOR_3_BASE_ADDR (XPAR_HIER_GPIO_2_AMDC_EDDY_CURRENT_SE_0_S00_AXI_BASEADDR) +#define EDDY_CURRENT_SENSOR_4_BASE_ADDR (XPAR_HIER_GPIO_3_AMDC_EDDY_CURRENT_SE_0_S00_AXI_BASEADDR) +#endif + +void eddy_current_sensor_init(void); + +void eddy_current_sensor_trigger_on_pwm_high(uint32_t base_addr); +void eddy_current_sensor_trigger_on_pwm_low(uint32_t base_addr); +void eddy_current_sensor_trigger_on_pwm_both(uint32_t base_addr); +void eddy_current_sensor_trigger_on_pwm_clear(uint32_t base_addr); + +void eddy_current_sensor_set_timing(uint32_t base_addr, uint32_t sclk_freq_khz, uint32_t propogation_delay_ns); + +double eddy_current_sensor_read_x_voltage(uint32_t base_addr); +double eddy_current_sensor_read_y_voltage(uint32_t base_addr); + +#endif // EDDY_CURRENT_SENSOR_H diff --git a/sdk/shared/drv/encoder.c b/sdk/shared/drv/encoder.c new file mode 100644 index 00000000..dafaf53f --- /dev/null +++ b/sdk/shared/drv/encoder.c @@ -0,0 +1,107 @@ +/* FreeRTOS includes */ +#include "FreeRTOS.h" +#include "task.h" +/* other includes */ +#include "drv/encoder.h" +#include "sys/defines.h" +#include "xil_io.h" + +#define ENCODER_BASE_ADDR (0x43C10000) + +void encoder_init(void) +{ + printf("ENC:\tInitializing...\n"); + encoder_set_pulses_per_rev_bits(ENCODER_PULSES_PER_REV_BITS); +} + +void encoder_set_pulses_per_rev_bits(uint32_t bits) +{ + printf("ENC:\tSetting pulses per rev bits = %ld...\n", bits); + encoder_set_pulses_per_rev(1 << bits); +} + +void encoder_set_pulses_per_rev(uint32_t pulses) +{ + printf("ENC:\tSetting pulses per rev = %ld...\n", pulses); + + Xil_Out32(ENCODER_BASE_ADDR + 2 * sizeof(uint32_t), pulses); +} + +void encoder_get_steps(int32_t *steps) +{ + *steps = Xil_In32(ENCODER_BASE_ADDR + 2 * sizeof(uint32_t)); +} + +void encoder_get_steps_instantaneous(int32_t *steps) +{ + *steps = Xil_In32(ENCODER_BASE_ADDR); +} + +void encoder_get_position(uint32_t *position) +{ + *position = Xil_In32(ENCODER_BASE_ADDR + 3 * sizeof(uint32_t)); +} + +void encoder_get_position_instantaneous(uint32_t *position) +{ + *position = Xil_In32(ENCODER_BASE_ADDR + 1 * sizeof(uint32_t)); +} + +// **************** +// State Machine which finds z pulse +// **************** + +typedef enum sm_states_e { + WAIT_UNTIL_Z, + REMOVE_TASK, +} sm_states_e; + +typedef struct sm_ctx_t { + sm_states_e state; + double vPercent; + double theta; + double theta_delta; + int counter; + TaskHandle_t tcb; +} sm_ctx_t; + +#define SM_UPDATES_PER_SEC (10000) +#define SM_INTERVAL_TICKS (pdMS_TO_TICKS(1000.0 / SM_UPDATES_PER_SEC)) + +static sm_ctx_t ctxG; + +static void _find_z(void *arg) +{ + sm_ctx_t *ctx = &ctxG; + for (;;) { + vTaskDelay(SM_INTERVAL_TICKS); + switch (ctx->state) { + case WAIT_UNTIL_Z: + { + uint32_t pos; + encoder_get_position(&pos); + if (pos != -1) { + ctx->state = REMOVE_TASK; + } + + break; + } + + case REMOVE_TASK: + { + vTaskDelete(ctx->tcb); + break; + } + } + } +} + +void encoder_find_z(void) +{ + // Initialize the state machine context + ctxG.state = WAIT_UNTIL_Z; + + // Initialize the state machine callback tcb + xTaskCreate(_find_z, (const char *) "find_z", configMINIMAL_STACK_SIZE, + NULL, configMAX_PRIORITIES - 1, &ctxG.tcb); +} diff --git a/sdk/shared/drv/encoder.h b/sdk/shared/drv/encoder.h new file mode 100644 index 00000000..9aaa6080 --- /dev/null +++ b/sdk/shared/drv/encoder.h @@ -0,0 +1,20 @@ +#ifndef ENCODER_H +#define ENCODER_H + +#include + +#define ENCODER_PULSES_PER_REV_BITS (14) +#define ENCODER_PULSES_PER_REV (1 << ENCODER_PULSES_PER_REV_BITS) + +void encoder_init(void); + +void encoder_set_pulses_per_rev_bits(uint32_t bits); +void encoder_set_pulses_per_rev(uint32_t pulses); +void encoder_get_steps(int32_t *steps); +void encoder_get_steps_instantaneous(int32_t *steps); +void encoder_get_position(uint32_t *position); +void encoder_get_position_instantaneous(uint32_t *position); + +void encoder_find_z(void); + +#endif // ENCODER_H diff --git a/sdk/shared/drv/fpga_timer.c b/sdk/shared/drv/fpga_timer.c new file mode 100644 index 00000000..b07d78e2 --- /dev/null +++ b/sdk/shared/drv/fpga_timer.c @@ -0,0 +1,51 @@ +#include "drv/fpga_timer.h" +#include "sys/defines.h" +#include "usr/user_config.h" +#include "xparameters.h" +#include "xtmrctr.h" +#include + +#if USER_CONFIG_HARDWARE_TARGET == AMDC_REV_D +#define TMR_DEVICE_ID XPAR_CONTROL_TIMER_1_DEVICE_ID +#endif + +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) +#define TMR_DEVICE_ID XPAR_HIER_TIMERS_CONTROL_TIMER_1_DEVICE_ID +#endif + +static XTmrCtr timer; + +void fpga_timer_init(void) +{ + int xStatus = XTmrCtr_Initialize(&timer, TMR_DEVICE_ID); + if (xStatus != XST_SUCCESS) { + HANG; + } + + // Configure timer to count up and auto-restart when it hits max value + XTmrCtr_SetOptions(&timer, 0, XTC_AUTO_RELOAD_OPTION); + + // Reset timer to value of 0 + XTmrCtr_SetResetValue(&timer, 0, 0); + + XTmrCtr_Start(&timer, 0); +} + +uint32_t fpga_timer_now(void) +{ + return XTmrCtr_GetValue(&timer, 0); +} + +double fpga_timer_ticks_to_usec(uint32_t ticks) +{ + // FPGA clock is 200MHz on AMDC + double usec = (double) ticks / 200; + return usec; +} + +double fpga_timer_ticks_to_sec(uint32_t ticks) +{ + // FPGA clock is 200MHz on AMDC + double sec = (double) ticks / 200e6; + return sec; +} diff --git a/sdk/shared/drv/fpga_timer.h b/sdk/shared/drv/fpga_timer.h new file mode 100644 index 00000000..7ad2bddf --- /dev/null +++ b/sdk/shared/drv/fpga_timer.h @@ -0,0 +1,17 @@ +#ifndef FPGA_TIMER_H +#define FPGA_TIMER_H + +#include + +void fpga_timer_init(void); + +// Return the current time in FPGA clock cycles (200MHz clock) +uint32_t fpga_timer_now(void); + +// Convert FPGA clock ticks to usec +double fpga_timer_ticks_to_usec(uint32_t ticks); + +// Convert FPGA clock ticks to sec +double fpga_timer_ticks_to_sec(uint32_t ticks); + +#endif // FPGA_TIMER_H diff --git a/sdk/shared/drv/gp3io_mux.c b/sdk/shared/drv/gp3io_mux.c new file mode 100644 index 00000000..2b056540 --- /dev/null +++ b/sdk/shared/drv/gp3io_mux.c @@ -0,0 +1,25 @@ +#include "usr/user_config.h" +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + +#include "drv/gp3io_mux.h" +#include "xil_io.h" +#include +#include + +void gp3io_mux_init(void) +{ + printf("GP3IO LINES:\tInitializing...\n"); + + // Default all GP3IO muxes to unused, i.e. disconnected + gp3io_mux_set_device(GP3IO_MUX_1_BASE_ADDR, GP3IO_MUX_UNUSED); + gp3io_mux_set_device(GP3IO_MUX_2_BASE_ADDR, GP3IO_MUX_UNUSED); + gp3io_mux_set_device(GP3IO_MUX_3_BASE_ADDR, GP3IO_MUX_UNUSED); + gp3io_mux_set_device(GP3IO_MUX_4_BASE_ADDR, GP3IO_MUX_UNUSED); +} + +void gp3io_mux_set_device(uint32_t base_addr, gp3io_mux_device_t device) +{ + Xil_Out32(base_addr, device); +} + +#endif // USER_CONFIG_HARDWARE_TARGET diff --git a/sdk/shared/drv/gp3io_mux.h b/sdk/shared/drv/gp3io_mux.h new file mode 100644 index 00000000..a9df3a9d --- /dev/null +++ b/sdk/shared/drv/gp3io_mux.h @@ -0,0 +1,39 @@ +#include "usr/user_config.h" +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + +#ifndef GP3IO_MUX_H +#define GP3IO_MUX_H + +#include "xparameters.h" +#include +#include + +#define GP3IO_MUX_1_BASE_ADDR (XPAR_HIER_GPIO_0_AMDC_GP3IO_MUX_0_S00_AXI_BASEADDR) +#define GP3IO_MUX_2_BASE_ADDR (XPAR_HIER_GPIO_1_AMDC_GP3IO_MUX_0_S00_AXI_BASEADDR) +#define GP3IO_MUX_3_BASE_ADDR (XPAR_HIER_GPIO_2_AMDC_GP3IO_MUX_0_S00_AXI_BASEADDR) +#define GP3IO_MUX_4_BASE_ADDR (XPAR_HIER_GPIO_3_AMDC_GP3IO_MUX_0_S00_AXI_BASEADDR) +#define GP3IO_MUX_5_BASE_ADDR (XPAR_HIER_GPIO_4_AMDC_GP3IO_MUX_0_S00_AXI_BASEADDR) +#define GP3IO_MUX_6_BASE_ADDR (XPAR_HIER_GPIO_5_AMDC_GP3IO_MUX_0_S00_AXI_BASEADDR) +#define GP3IO_MUX_7_BASE_ADDR (XPAR_HIER_GPIO_6_AMDC_GP3IO_MUX_0_S00_AXI_BASEADDR) +#define GP3IO_MUX_8_BASE_ADDR (XPAR_HIER_GPIO_7_AMDC_GP3IO_MUX_0_S00_AXI_BASEADDR) + +typedef enum { + GP3IO_MUX_UNUSED = 0, + GP3IO_MUX_DEVICE1 = 1, + GP3IO_MUX_DEVICE2 = 2, + GP3IO_MUX_DEVICE3 = 3, + GP3IO_MUX_DEVICE4 = 4, + GP3IO_MUX_DEVICE5 = 5, + GP3IO_MUX_DEVICE6 = 6, + GP3IO_MUX_DEVICE7 = 7, + GP3IO_MUX_DEVICE8 = 8 +} gp3io_mux_device_t; + +#define GP3IO_MUX_DEVICE_COUNT 8 + +void gp3io_mux_init(void); +void gp3io_mux_set_device(uint32_t base_addr, gp3io_mux_device_t device); + +#endif // GP3IO_MUX_H + +#endif // USER_CONFIG_HARDWARE_TARGET diff --git a/sdk/shared/drv/gpio_direct.c b/sdk/shared/drv/gpio_direct.c new file mode 100644 index 00000000..9a74bd95 --- /dev/null +++ b/sdk/shared/drv/gpio_direct.c @@ -0,0 +1,146 @@ +#include "drv/gpio_direct.h" +#include "usr/user_config.h" +#include "xil_io.h" +#include + +/* GPIO DIRECT REGISTERS + +AMDC REV E: + +Ports are 1-4 +Pins are 1-3 (both IN and OUT) + +Each GPIO port has two registers, an IN and an OUT. + +Reg 0 (BASE_ADDR) is the IN register, and Reg 1 (BASE_ADDR + 4) is the OUT register. + +For each register, the 3 least-significant bits are pin 1, pin 2, and pin 3. + + + +AMDC REV D: + +Ports are 1-2 +Pins are 1-2 (both IN and OUT) + +Each GPIO port has two registers, an IN and an OUT. + +Reg 0 (BASE_ADDR) is the IN register, and Reg 1 (BASE_ADDR + 4) is the OUT register. + +For each register, the 2 least-significant bits are pin 1 and pin 2. + + + +Note that for each GPIO port, the IN and OUT pins are different electric connections on the GPIO port. +i.e. Port 1 has both pin 1 IN and pin 1 OUT. + +*/ + +void gpio_direct_init() +{ + // Set all WRITE pins to LOW + gpio_direct_write(GPIO_DIRECT_PORT1, GPIO_DIRECT_PIN1, GPIO_DIRECT_LOW); + gpio_direct_write(GPIO_DIRECT_PORT1, GPIO_DIRECT_PIN2, GPIO_DIRECT_LOW); + gpio_direct_write(GPIO_DIRECT_PORT2, GPIO_DIRECT_PIN1, GPIO_DIRECT_LOW); + gpio_direct_write(GPIO_DIRECT_PORT2, GPIO_DIRECT_PIN2, GPIO_DIRECT_LOW); +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + gpio_direct_write(GPIO_DIRECT_PORT1, GPIO_DIRECT_PIN3, GPIO_DIRECT_LOW); + gpio_direct_write(GPIO_DIRECT_PORT2, GPIO_DIRECT_PIN3, GPIO_DIRECT_LOW); + gpio_direct_write(GPIO_DIRECT_PORT3, GPIO_DIRECT_PIN1, GPIO_DIRECT_LOW); + gpio_direct_write(GPIO_DIRECT_PORT3, GPIO_DIRECT_PIN2, GPIO_DIRECT_LOW); + gpio_direct_write(GPIO_DIRECT_PORT3, GPIO_DIRECT_PIN3, GPIO_DIRECT_LOW); + gpio_direct_write(GPIO_DIRECT_PORT4, GPIO_DIRECT_PIN1, GPIO_DIRECT_LOW); + gpio_direct_write(GPIO_DIRECT_PORT4, GPIO_DIRECT_PIN2, GPIO_DIRECT_LOW); + gpio_direct_write(GPIO_DIRECT_PORT4, GPIO_DIRECT_PIN3, GPIO_DIRECT_LOW); +#endif +} + +gpio_direct_level_t gpio_direct_read(gpio_direct_port_t port, gpio_direct_pin_t pin) +{ + uint32_t base_addr = 0; + + switch (port) { + case GPIO_DIRECT_PORT1: + base_addr = GPIO1_DIRECT_BASE_ADDR; + break; + case GPIO_DIRECT_PORT2: + base_addr = GPIO2_DIRECT_BASE_ADDR; + break; +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + case GPIO_DIRECT_PORT3: + base_addr = GPIO3_DIRECT_BASE_ADDR; + break; + case GPIO_DIRECT_PORT4: + base_addr = GPIO4_DIRECT_BASE_ADDR; + break; +#endif + } + + if (Xil_In32(base_addr) & (1 << pin)) + return GPIO_DIRECT_HIGH; + else + return GPIO_DIRECT_LOW; +} + +void gpio_direct_write(gpio_direct_port_t port, gpio_direct_pin_t pin, gpio_direct_level_t level) +{ + // Get current register value using Xil_In, + // then set the correct bit if write level is HIGH or clear the correct bit if write level is LOW + uint32_t current = 0; + uint32_t base_addr = 0; + + switch (port) { + case GPIO_DIRECT_PORT1: + base_addr = GPIO1_DIRECT_BASE_ADDR; + break; + case GPIO_DIRECT_PORT2: + base_addr = GPIO2_DIRECT_BASE_ADDR; + break; +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + case GPIO_DIRECT_PORT3: + base_addr = GPIO3_DIRECT_BASE_ADDR; + break; + case GPIO_DIRECT_PORT4: + base_addr = GPIO4_DIRECT_BASE_ADDR; + break; +#endif + } + + // Read the WRITE register, change only desired bit, write back out below + // The desired port's WRITE register is the second register in the IP block + // Therefore it is at the port's base_addr + sizeof(uint32_t) + current = Xil_In32(base_addr + sizeof(uint32_t)); + + if (level) { + // SET + Xil_Out32(base_addr + sizeof(uint32_t), current | (1 << pin)); + } else { + // CLEAR + Xil_Out32(base_addr + sizeof(uint32_t), current & ~(1 << pin)); + } +} + +void gpio_direct_toggle(gpio_direct_port_t port, gpio_direct_pin_t pin) +{ + uint32_t base_addr = 0; + + switch (port) { + case GPIO_DIRECT_PORT1: + base_addr = GPIO1_DIRECT_BASE_ADDR; + break; + case GPIO_DIRECT_PORT2: + base_addr = GPIO2_DIRECT_BASE_ADDR; + break; +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + case GPIO_DIRECT_PORT3: + base_addr = GPIO3_DIRECT_BASE_ADDR; + break; + case GPIO_DIRECT_PORT4: + base_addr = GPIO4_DIRECT_BASE_ADDR; + break; +#endif + } + + // Get current register value using Xil_In, then toggle the desired bit + Xil_Out32(base_addr + sizeof(uint32_t), Xil_In32(base_addr + sizeof(uint32_t)) ^ (1 << pin)); +} diff --git a/sdk/shared/drv/gpio_direct.h b/sdk/shared/drv/gpio_direct.h new file mode 100644 index 00000000..40e47b04 --- /dev/null +++ b/sdk/shared/drv/gpio_direct.h @@ -0,0 +1,50 @@ +#ifndef GPIO_DIRECT_H +#define GPIO_DIRECT_H + +#include "usr/user_config.h" +#include "xparameters.h" +#include + +#if USER_CONFIG_HARDWARE_TARGET == AMDC_REV_D + +#define GPIO1_DIRECT_BASE_ADDR (XPAR_AMDC_GPIO_DIRECT_0_S00_AXI_BASEADDR) +#define GPIO2_DIRECT_BASE_ADDR (XPAR_AMDC_GPIO_DIRECT_1_S00_AXI_BASEADDR) + +#endif // ifdef HARDWARE_TARGET REV_D + +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + +#define GPIO1_DIRECT_BASE_ADDR (XPAR_HIER_GPIO_0_AMDC_GPIO_DIRECT_0_S00_AXI_BASEADDR) +#define GPIO2_DIRECT_BASE_ADDR (XPAR_HIER_GPIO_1_AMDC_GPIO_DIRECT_0_S00_AXI_BASEADDR) +#define GPIO3_DIRECT_BASE_ADDR (XPAR_HIER_GPIO_2_AMDC_GPIO_DIRECT_0_S00_AXI_BASEADDR) +#define GPIO4_DIRECT_BASE_ADDR (XPAR_HIER_GPIO_3_AMDC_GPIO_DIRECT_0_S00_AXI_BASEADDR) + +#endif // ifdef HARDWARE_TARGET REV_E + +// These port and pin enumerations MUST BE the specified numbers below + +typedef enum { + GPIO_DIRECT_PORT1 = 0, + GPIO_DIRECT_PORT2 = 1, +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + GPIO_DIRECT_PORT3 = 2, + GPIO_DIRECT_PORT4 = 3 +#endif +} gpio_direct_port_t; + +typedef enum { + GPIO_DIRECT_PIN1 = 0, + GPIO_DIRECT_PIN2 = 1, +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + GPIO_DIRECT_PIN3 = 2 +#endif +} gpio_direct_pin_t; + +typedef enum { GPIO_DIRECT_LOW = 0, GPIO_DIRECT_HIGH = 1 } gpio_direct_level_t; + +void gpio_direct_init(); +gpio_direct_level_t gpio_direct_read(gpio_direct_port_t port, gpio_direct_pin_t pin); +void gpio_direct_write(gpio_direct_port_t port, gpio_direct_pin_t pin, gpio_direct_level_t level); +void gpio_direct_toggle(gpio_direct_port_t port, gpio_direct_pin_t pin); + +#endif // GPIO_DIRECT_H diff --git a/sdk/shared/drv/gpio_mux.c b/sdk/shared/drv/gpio_mux.c new file mode 100644 index 00000000..df25c604 --- /dev/null +++ b/sdk/shared/drv/gpio_mux.c @@ -0,0 +1,30 @@ +#include "usr/user_config.h" +#if USER_CONFIG_HARDWARE_TARGET == AMDC_REV_D + +#include "drv/gpio_mux.h" +#include "xil_io.h" +#include +#include + +#define GPIO_MUX_BASE_ADDR (XPAR_AMDC_GPIO_MUX_0_S00_AXI_BASEADDR) + +static int ports[] = { GPIO_PORT1, GPIO_PORT2 }; + +void gpio_mux_init(void) +{ + printf("GPIO LINES:\tInitializing...\n"); + + for (int i = 0; i < 2; i++) { + if (ports[i]) { + // Map the port status lines to the corresponding device defined in the header file + gpio_mux_set_device(i, ports[i]); + } + } +} + +void gpio_mux_set_device(uint8_t port, gpio_mux_device_t device) +{ + Xil_Out32(GPIO_MUX_BASE_ADDR + (port * sizeof(uint32_t)), device); +} + +#endif // USER_CONFIG_HARDWARE_TARGET diff --git a/sdk/shared/drv/gpio_mux.h b/sdk/shared/drv/gpio_mux.h new file mode 100644 index 00000000..984b1bf9 --- /dev/null +++ b/sdk/shared/drv/gpio_mux.h @@ -0,0 +1,33 @@ +#include "usr/user_config.h" +#if USER_CONFIG_HARDWARE_TARGET == AMDC_REV_D + +#ifndef GPIO_MUX_H +#define GPIO_MUX_H + +#include +#include + +typedef enum { + GPIO_MUX_UNUSED = 0, + GPIO_MUX_DEVICE1 = 1, + GPIO_MUX_DEVICE2 = 2, + GPIO_MUX_DEVICE3 = 3, + GPIO_MUX_DEVICE4 = 4, + GPIO_MUX_DEVICE5 = 5, + GPIO_MUX_DEVICE6 = 6, + GPIO_MUX_DEVICE7 = 7, + GPIO_MUX_DEVICE8 = 8 +} gpio_mux_device_t; + +#define GPIO_PORT1 GPIO_MUX_UNUSED +#define GPIO_PORT2 GPIO_MUX_UNUSED + +#define GPIO_MUX_DEVICE_COUNT 8 + +void gpio_mux_init(void); + +void gpio_mux_set_device(uint8_t, gpio_mux_device_t); + +#endif // GPIO_MUX_H + +#endif // USER_CONFIG_HARDWARE_TARGET diff --git a/sdk/shared/drv/hardware_targets.h b/sdk/shared/drv/hardware_targets.h new file mode 100644 index 00000000..d4d3e6c0 --- /dev/null +++ b/sdk/shared/drv/hardware_targets.h @@ -0,0 +1,12 @@ +#ifndef HARDWARE_TARGETS_H +#define HARDWARE_TARGETS_H + +// This file holds the defines for all possible hardware targets. + +// As the AMDC platform matures, the supported hardware targets will change. + +#define AMDC_REV_D (4) +#define AMDC_REV_E (5) +#define AMDC_REV_F (6) + +#endif // HARDWARE_TARGETS_H diff --git a/sdk/shared/drv/ild1420.c b/sdk/shared/drv/ild1420.c new file mode 100644 index 00000000..f7cdc6da --- /dev/null +++ b/sdk/shared/drv/ild1420.c @@ -0,0 +1,25 @@ +#include "drv/ild1420.h" +#include "xil_io.h" +#include + +// IP base addresses per mapping in Vivado +static const uint32_t addr_mapping[ILD1420_NUM_SENSORS] = { + 0x43CA0000, + 0x43CB0000, + 0x43CC0000, + 0x43CD0000, +}; + +ild1420_packet_t ild1420_get_latest_packet(ild1420_sensor_t sensor) +{ + // Read the raw output of the first slave register in the FPGA + uint32_t reg = Xil_In32(addr_mapping[sensor]); + + // Parse the raw output into our data + ild1420_packet_t ret; + ret.distance = reg & 0x0000FFFF; + ret.error = (reg >> 16) & 0x3; + ret.fresh = (reg >> 18) & 0x1; + + return ret; +} diff --git a/sdk/shared/drv/ild1420.h b/sdk/shared/drv/ild1420.h new file mode 100644 index 00000000..e1222689 --- /dev/null +++ b/sdk/shared/drv/ild1420.h @@ -0,0 +1,39 @@ +#ifndef ILD1420_H +#define ILD1420_H + +#include + +typedef enum { + // Keep starting at 0 + ILD1420_SENSOR1 = 0, + ILD1420_SENSOR2 = 1, + ILD1420_SENSOR3 = 2, + ILD1420_SENSOR4 = 3, + + // Keep at end + ILD1420_NUM_SENSORS +} ild1420_sensor_t; + +typedef struct ild1420_packet_t { + // 16-bit raw data from the sensor + uint16_t distance; + + // 2-bit raw error code from sensor + uint8_t error; + + // 1 if data was received in the last 300us, 0 if stale + uint8_t fresh; +} ild1420_packet_t; + +// User calls this function to receive the latest +// packet from the ILD1420 sensor. The FPGA is constantly +// listening for data and parsing it. The last valid +// packet is returned, which may be OLD! Use the "fresh" +// bit to determine recency. +// +// NOTE: the C code does NOT have to initialize this driver, +// because the FPGA takes care of aligning its acquisitions +// to the UART data stream. +ild1420_packet_t ild1420_get_latest_packet(ild1420_sensor_t sensor); + +#endif // ILD1420_H diff --git a/sdk/shared/drv/motherboard.c b/sdk/shared/drv/motherboard.c new file mode 100644 index 00000000..80f46382 --- /dev/null +++ b/sdk/shared/drv/motherboard.c @@ -0,0 +1,122 @@ +#include "usr/user_config.h" + +#if (USER_CONFIG_ENABLE_MOTHERBOARD_SUPPORT == 1) + +#include "drv/motherboard.h" +#include "drv/motherboard_defs.h" +#include "sys/cmd/cmd_mb.h" +#include "sys/commands.h" +#include "sys/defines.h" +#include "sys/util.h" +#include +#include + +void motherboard_init(void) +{ + cmd_mb_register(); + +#if USER_CONFIG_ENABLE_MOTHERBOARD_AUTO_TX == 1 + bool auto_tx = true; +#else + bool auto_tx = false +#endif + + motherboard_set_adc_sampling(MOTHERBOARD_1_BASE_ADDR, auto_tx); +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + motherboard_set_adc_sampling(MOTHERBOARD_2_BASE_ADDR, auto_tx); + motherboard_set_adc_sampling(MOTHERBOARD_3_BASE_ADDR, auto_tx); + motherboard_set_adc_sampling(MOTHERBOARD_4_BASE_ADDR, auto_tx); +#endif +} + +void motherboard_set_adc_sampling(uint32_t base_addr, bool enable) +{ + // Create base address for IP + volatile uint32_t *m_motherboard = (volatile uint32_t *) base_addr; + + // Read register from FPGA + uint32_t reg = m_motherboard[MOTHERBOARD_DEFS_OFFSET_CONTROL / 4]; + + // Clear bit + BITCLEAR(reg, MOTHERBOARD_DEFS_CONTROL_SYNC_ADC_EN_SHIFT); + + // Set new bits based on user enable flag + if (enable) { + BITSET(reg, MOTHERBOARD_DEFS_CONTROL_SYNC_ADC_EN_SHIFT); + } + + // Write register to FPGA + m_motherboard[MOTHERBOARD_DEFS_OFFSET_CONTROL / 4] = reg; +} + +void motherboard_request_new_data(uint32_t base_addr) +{ + // Create base address for IP + volatile uint32_t *m_motherboard = (volatile uint32_t *) base_addr; + + // Read register from FPGA + uint32_t reg = m_motherboard[MOTHERBOARD_DEFS_OFFSET_CONTROL / 4]; + + // Toggle the bit + BITFLIP(reg, MOTHERBOARD_DEFS_CONTROL_SYNC_TX_SHIFT); + + // Write register to FPGA + m_motherboard[MOTHERBOARD_DEFS_OFFSET_CONTROL / 4] = reg; +} + +int motherboard_get_data(uint32_t base_addr, mb_channel_e channel, int32_t *out) +{ + // Create base address for IP + volatile uint32_t *m_motherboard = (volatile uint32_t *) base_addr; + + if (!motherboard_is_valid_channel(channel)) { + return FAILURE; + } else { + *out = (int32_t) m_motherboard[channel]; + return SUCCESS; + } +} + +void motherboard_print_samples(uint32_t base_addr) +{ + // Create base address for IP + volatile uint32_t *m_motherboard = (volatile uint32_t *) base_addr; + + for (int i = 0; i < 8; i++) { + uint32_t val = m_motherboard[i]; + cmd_resp_printf("%i: %04X\r\n", i, val); + } +} + +void motherboard_print_counters(uint32_t base_addr) +{ + // Create base address for IP + volatile uint32_t *m_motherboard = (volatile uint32_t *) base_addr; + + cmd_resp_printf("V: %08X\r\n", m_motherboard[MOTHERBOARD_DEFS_OFFSET_COUNT_VALID / 4]); + cmd_resp_printf("C: %08X\r\n", m_motherboard[MOTHERBOARD_DEFS_OFFSET_COUNT_CORRUPT / 4]); + cmd_resp_printf("T: %08X\r\n", m_motherboard[MOTHERBOARD_DEFS_OFFSET_COUNT_TIMEOUT / 4]); +} + +void motherboard_get_counters(uint32_t base_addr, uint32_t *V, uint32_t *C, uint32_t *T) +{ + // Create base address for IP + volatile uint32_t *m_motherboard = (volatile uint32_t *) base_addr; + + // Read V counter if user requested it + if (V != NULL) { + *V = m_motherboard[MOTHERBOARD_DEFS_OFFSET_COUNT_VALID / 4]; + } + + // Read C counter if user requested it + if (C != NULL) { + *C = m_motherboard[MOTHERBOARD_DEFS_OFFSET_COUNT_CORRUPT / 4]; + } + + // Read T counter if user requested it + if (T != NULL) { + *T = m_motherboard[MOTHERBOARD_DEFS_OFFSET_COUNT_TIMEOUT / 4]; + } +} + +#endif // USER_CONFIG_ENABLE_MOTHERBOARD_SUPPORT diff --git a/sdk/shared/drv/motherboard.h b/sdk/shared/drv/motherboard.h new file mode 100644 index 00000000..1459711c --- /dev/null +++ b/sdk/shared/drv/motherboard.h @@ -0,0 +1,88 @@ +#ifndef MOTHERBOARD_H +#define MOTHERBOARD_H + +#include "drv/hardware_targets.h" +#include "usr/user_config.h" +#include +#include + +#include "xparameters.h" + +#if USER_CONFIG_HARDWARE_TARGET == AMDC_REV_D +#define MOTHERBOARD_MAX_IP_CORES (XPAR_AMDC_MOTHERBOARD_NUM_INSTANCES) +#define MOTHERBOARD_1_BASE_ADDR (XPAR_HIER_AMDS_AMDC_MOTHERBOARD_0_S00_AXI_BASEADDR) +#endif + +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) +#define MOTHERBOARD_MAX_IP_CORES (XPAR_AMDC_MOTHERBOARD_NUM_INSTANCES) +#define MOTHERBOARD_1_BASE_ADDR (XPAR_HIER_GPIO_0_HIER_AMDS_0_AMDC_MOTHERBOARD_0_S00_AXI_BASEADDR) +#define MOTHERBOARD_2_BASE_ADDR (XPAR_HIER_GPIO_1_HIER_AMDS_0_AMDC_MOTHERBOARD_0_S00_AXI_BASEADDR) +#define MOTHERBOARD_3_BASE_ADDR (XPAR_HIER_GPIO_2_HIER_AMDS_0_AMDC_MOTHERBOARD_0_S00_AXI_BASEADDR) +#define MOTHERBOARD_4_BASE_ADDR (XPAR_HIER_GPIO_3_HIER_AMDS_0_AMDC_MOTHERBOARD_0_S00_AXI_BASEADDR) +#endif + +typedef enum { + // Keep first channel index at 0! + MB_IN1 = 0, + MB_IN2, + MB_IN3, + MB_IN4, + MB_IN5, + MB_IN6, + MB_IN7, + MB_IN8, + + // Keep this as last entry! + MB_NUM_CHANNELS, +} mb_channel_e; + +static inline bool motherboard_is_valid_channel(mb_channel_e channel) +{ + if (channel >= MB_IN1 && channel < MB_NUM_CHANNELS) { + return true; + } + + return false; +} + +static inline bool motherboard_is_valid_idx(int idx) +{ + if (idx >= 0 && idx < MOTHERBOARD_MAX_IP_CORES) { + return true; + } + + return false; +} + +static inline uint32_t motherboard_idx_to_base_addr(int idx) +{ + switch (idx) { + case 0: + return MOTHERBOARD_1_BASE_ADDR; + +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + case 1: + return MOTHERBOARD_2_BASE_ADDR; + case 2: + return MOTHERBOARD_3_BASE_ADDR; + case 3: + return MOTHERBOARD_4_BASE_ADDR; +#endif + + default: + return 0; + } +} + +void motherboard_init(void); + +void motherboard_set_adc_sampling(uint32_t base_addr, bool enable); +void motherboard_request_new_data(uint32_t base_addr); + +int motherboard_get_data(uint32_t base_addr, mb_channel_e channel, int32_t *out); + +void motherboard_print_samples(uint32_t base_addr); +void motherboard_print_counters(uint32_t base_addr); +void motherboard_get_counters(uint32_t base_addr, uint32_t *V, uint32_t *C, uint32_t *T); + +#endif // MOTHERBOARD_H diff --git a/sdk/shared/drv/motherboard_defs.h b/sdk/shared/drv/motherboard_defs.h new file mode 100644 index 00000000..232c5364 --- /dev/null +++ b/sdk/shared/drv/motherboard_defs.h @@ -0,0 +1,41 @@ +#ifndef MOTHERBOARD_DEFS_H +#define MOTHERBOARD_DEFS_H + +// =============== +// Number of slave registers in this IP +// =============== +#define MOTHERBOARD_DEFS_NUM_SLAVE_REGS (16) + +// =============== +// Offsets for the relevant slave registers (in bytes). +// Separated by 4 bytes since each register is 32 bits. +// =============== +#define MOTHERBOARD_DEFS_OFFSET_ADC_CH1 (0 * 4) +#define MOTHERBOARD_DEFS_OFFSET_ADC_CH2 (1 * 4) +#define MOTHERBOARD_DEFS_OFFSET_ADC_CH3 (2 * 4) +#define MOTHERBOARD_DEFS_OFFSET_ADC_CH4 (3 * 4) +#define MOTHERBOARD_DEFS_OFFSET_ADC_CH5 (4 * 4) +#define MOTHERBOARD_DEFS_OFFSET_ADC_CH6 (5 * 4) +#define MOTHERBOARD_DEFS_OFFSET_ADC_CH7 (6 * 4) +#define MOTHERBOARD_DEFS_OFFSET_ADC_CH8 (7 * 4) +#define MOTHERBOARD_DEFS_OFFSET_CONTROL (8 * 4) +#define MOTHERBOARD_DEFS_OFFSET_STATUS (9 * 4) +#define MOTHERBOARD_DEFS_OFFSET_COUNT_VALID (10 * 4) +#define MOTHERBOARD_DEFS_OFFSET_COUNT_CORRUPT (11 * 4) +#define MOTHERBOARD_DEFS_OFFSET_COUNT_TIMEOUT (12 * 4) +#define MOTHERBOARD_DEFS_OFFSET_UNUSED5 (13 * 4) +#define MOTHERBOARD_DEFS_OFFSET_UNUSED6 (14 * 4) +#define MOTHERBOARD_DEFS_OFFSET_UNUSED7 (15 * 4) + +// =============== +// CONTROL register +// =============== +#define MOTHERBOARD_DEFS_CONTROL_SYNC_ADC_EN_WIDTH (1) // in bits +#define MOTHERBOARD_DEFS_CONTROL_SYNC_ADC_EN_SHIFT (0) // up from reg[0] +#define MOTHERBOARD_DEFS_CONTROL_SYNC_ADC_EN_MASK (0x1) + +#define MOTHERBOARD_DEFS_CONTROL_SYNC_TX_WIDTH (1) // in bits +#define MOTHERBOARD_DEFS_CONTROL_SYNC_TX_SHIFT (1) // up from reg[0] +#define MOTHERBOARD_DEFS_CONTROL_SYNC_TX_MASK (0x1) + +#endif // MOTHERBOARD_DEFS_H diff --git a/sdk/shared/drv/pwm.c b/sdk/shared/drv/pwm.c new file mode 100644 index 00000000..c2ec2669 --- /dev/null +++ b/sdk/shared/drv/pwm.c @@ -0,0 +1,338 @@ +#include "drv/pwm.h" +#include "drv/hardware_targets.h" +#include "sys/defines.h" +#include "usr/user_config.h" +#include "xgpiops.h" +#include "xil_io.h" +#include +#include + +#define PWM_BASE_ADDR (0x43C20000) +#define PWM_MUX_BASE_ADDR (0x43C40000) + +static int pwm_set_carrier_divisor(uint8_t divisor); +static int pwm_set_carrier_max(uint16_t max); +static int pwm_set_duty_raw(pwm_channel_e channel, uint16_t value); + +// Store current state of FPGA registers +static uint8_t carrier_divisor; +static uint16_t carrier_max; +static uint16_t deadtime; + +// Store current state of user params +static uint16_t now_deadtime; +static double now_fsw; + +// switching_freq = (200e6 / divisor) / (2*carrier_max) +// or +// carrier_max = ((200e6 / divisor) / (switching_freq)) / 2 + +static XGpioPs Gpio; +static const uint32_t pin_PS_DRIVE_EN_MIO = 44; + +static void setup_pin_PS_DRIVE_EN(void) +{ + int Status; + XGpioPs_Config *GPIOConfigPtr; + + // GPIO Initialization + GPIOConfigPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID); + Status = XGpioPs_CfgInitialize(&Gpio, GPIOConfigPtr, GPIOConfigPtr->BaseAddr); + if (Status != XST_SUCCESS) { + // Just hang here if error... + while (1) { + } + } + + // Set the PS_DRIVE_EN MIO pin as an output + XGpioPs_SetDirectionPin(&Gpio, pin_PS_DRIVE_EN_MIO, 1); + + // Start the pin as off + XGpioPs_WritePin(&Gpio, pin_PS_DRIVE_EN_MIO, 0); + + // Enable the PS_DRIVE_EN MIO pin + XGpioPs_SetOutputEnablePin(&Gpio, pin_PS_DRIVE_EN_MIO, 1); +} + +void pwm_init(void) +{ + printf("PWM:\tInitializing...\n"); + + setup_pin_PS_DRIVE_EN(); + + // Default to no switching (all PWM outputs are logic LOW) + // Opens all switches... + pwm_disable(); + + pwm_toggle_reset(); + + pwm_set_switching_freq(PWM_DEFAULT_SWITCHING_FREQ_HZ); + pwm_set_deadtime_ns(PWM_DEFAULT_DEADTIME_NS); + + // Initialize all PWMs to 50% duty output. + // Since PWM is disabled, this has no effect now, + // but if user enables PWM without updating registers, + // 50% will appear at outputs. + pwm_set_all_duty_midscale(); + + // Initialize the PWM mux block in the FPGA to basic pass-through + uint32_t mux_config_data[48]; + for (int i = 0; i < 48; i++) { + mux_config_data[i] = i; + } + pwm_mux_set_all_pins(mux_config_data); +} + +void pwm_set_all_duty_midscale(void) +{ + for (int i = 0; i < PWM_NUM_CHANNELS; i++) { + pwm_set_duty(i, 0.5); + } +} + +void pwm_toggle_reset(void) +{ + // Toggles RST on all inverter outputs for 1 ms + pwm_set_all_rst(0xFF); + for (int i = 0; i < 83250; i++) { + asm("nop"); + } + pwm_set_all_rst(0x00); + for (int i = 0; i < 83250; i++) { + asm("nop"); + } + pwm_set_all_rst(0xFF); +} + +void pwm_set_all_rst(uint8_t rst) +{ + uint32_t value = 0; + value |= (uint32_t) rst; + + // Offset 27 is rst output reg + Xil_Out32(PWM_BASE_ADDR + (27 * sizeof(uint32_t)), value); +} + +// Hardware disabling of PWM was added to REV E hardware +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + +static bool is_pwm_enable_hw_enabled = false; + +int pwm_enable_hw(bool en) +{ + int err = FAILURE; + + if (en) { + if (!is_pwm_enable_hw_enabled) { + XGpioPs_WritePin(&Gpio, pin_PS_DRIVE_EN_MIO, 1); + is_pwm_enable_hw_enabled = true; + err = SUCCESS; + } + } else { + if (is_pwm_enable_hw_enabled) { + XGpioPs_WritePin(&Gpio, pin_PS_DRIVE_EN_MIO, 0); + is_pwm_enable_hw_enabled = false; + err = SUCCESS; + } + } + + return err; +} + +#endif + +int pwm_enable(void) +{ + if (pwm_is_enabled()) { + return FAILURE; + } + + // Write to slave reg 31 LSB to enable PWM switching + Xil_Out32(PWM_BASE_ADDR + (31 * sizeof(uint32_t)), 0x00000001); + + return SUCCESS; +} + +int pwm_disable(void) +{ + if (!pwm_is_enabled()) { + return FAILURE; + } + + // Write to slave reg 31 LSB to enable PWM switching + Xil_Out32(PWM_BASE_ADDR + (31 * sizeof(uint32_t)), 0x00000000); + + return SUCCESS; +} + +bool pwm_is_enabled(void) +{ + uint32_t reg31 = Xil_In32(PWM_BASE_ADDR + (31 * sizeof(uint32_t))); + + // LSB of reg 31 is enable bit for PWM + return reg31 & 0x00000001; +} + +int pwm_set_switching_freq(double freq_hz) +{ + // Only allow PWM configuration changes when switching is off + if (pwm_is_enabled()) { + return FAILURE; + } + + // Based on FPGA, freq_hz can be in range: 1526Hz ... ~100MHz + // For sanity, we limit this to: 2kHz to 2MHz + if (freq_hz < PWM_MIN_SWITCHING_FREQ_HZ || freq_hz > PWM_MAX_SWITCHING_FREQ_HZ) { + return FAILURE; + } + + // Always set carrier_divisor to 0... anything else reduces resolution! + pwm_set_carrier_divisor(0); + + // Calculate what the carrier_max should be to achieve the right switching freq + carrier_max = (uint16_t)(((200e6 / (carrier_divisor + 1)) / (freq_hz)) / 2); + pwm_set_carrier_max(carrier_max); + + // Store current freq so we can access later + now_fsw = freq_hz; + + return SUCCESS; +} + +int pwm_set_deadtime_ns(uint16_t time_ns) +{ + // Only allow PWM configuration changes when switching is off + if (pwm_is_enabled()) { + return FAILURE; + } + + // FPGA only supports deadtime reg value from 5 to 2^16 - 1 (naturally supported using uint16_t) + // Deadtime in ns is just reg value * 5. So, minimum deadtime is 25ns. + + // Ensure requested deadtime is >= 25 ns + if (time_ns < PWM_MIN_DEADTIME_NS) { + // Throw error so user knows this didn't work! + return FAILURE; + } + + // Convert time in ns to FPGA clock cycles + deadtime = time_ns / 5; + + // NOTE: FPGA enforces minimum register value of 5 + // This should help prevent shoot-through events. + + // Write to slave reg 26 to set deadtime value + Xil_Out32(PWM_BASE_ADDR + (26 * sizeof(uint32_t)), deadtime); + + // Store current deadtime so we can access later + now_deadtime = time_ns; + + return SUCCESS; +} + +double pwm_get_switching_freq(void) +{ + return now_fsw; +} + +uint16_t pwm_get_deadtime_ns(void) +{ + return now_deadtime; +} + +int pwm_set_duty(pwm_channel_e channel, double duty) +{ + if (!pwm_is_valid_channel(channel)) { + return FAILURE; + } + + if (duty >= 1.0) { + pwm_set_duty_raw(channel, carrier_max); + } else if (duty <= 0.0) { + pwm_set_duty_raw(channel, 0); + } else { + pwm_set_duty_raw(channel, duty * carrier_max); + } + + return SUCCESS; +} + +static int pwm_set_duty_raw(pwm_channel_e channel, uint16_t value) +{ + if (!pwm_is_valid_channel(channel)) { + return FAILURE; + } + + // Write to offset 0 to control PWM 0 + Xil_Out32(PWM_BASE_ADDR + (channel * sizeof(uint32_t)), value); + + return SUCCESS; +} + +static int pwm_set_carrier_divisor(uint8_t divisor) +{ + // Only allow PWM configuration changes when switching is off + if (pwm_is_enabled()) { + return FAILURE; + } + + // FPGA only supports divisor from 0 to 255 (naturally supported using uint8_t) + + carrier_divisor = divisor; + + // Write to slave reg 24 to set triangle carrier clk divisor + Xil_Out32(PWM_BASE_ADDR + (24 * sizeof(uint32_t)), divisor); + + return SUCCESS; +} + +static int pwm_set_carrier_max(uint16_t max) +{ + // Only allow PWM configuration changes when switching is off + if (pwm_is_enabled()) { + return FAILURE; + } + + // FPGA only supports carrier max from 0 to 2^16 - 1 (naturally supported using uint16_t) + + carrier_max = max; + + // Write to slave reg 25 to set triangle carrier max value + Xil_Out32(PWM_BASE_ADDR + (25 * sizeof(uint32_t)), max); + + // Since we updated carrier max value, reset PWMs to new 50% + pwm_set_all_duty_midscale(); + + return SUCCESS; +} + +// NOTE: we assume config is an array of length >= 48 +int pwm_mux_set_all_pins(uint32_t *config) +{ + // Only allow PWM configuration changes when switching is off + if (pwm_is_enabled()) { + return FAILURE; + } + + for (int i = 0; i < (PWM_NUM_CHANNELS * 2); i++) { + Xil_Out32(PWM_MUX_BASE_ADDR + (i * sizeof(uint32_t)), config[i]); + } + + return SUCCESS; +} + +int pwm_mux_set_one_pin(uint32_t pwm_pin_idx, uint32_t config) +{ + // Only allow PWM configuration changes when switching is off + if (pwm_is_enabled()) { + return FAILURE; + } + + if (pwm_pin_idx < 0 || pwm_pin_idx >= 48) { + return FAILURE; + } + + Xil_Out32(PWM_MUX_BASE_ADDR + (pwm_pin_idx * sizeof(uint32_t)), config); + + return SUCCESS; +} diff --git a/sdk/shared/drv/pwm.h b/sdk/shared/drv/pwm.h new file mode 100644 index 00000000..c45ce8df --- /dev/null +++ b/sdk/shared/drv/pwm.h @@ -0,0 +1,85 @@ +#ifndef PWM_H +#define PWM_H + +#include "drv/hardware_targets.h" +#include "usr/user_config.h" +#include +#include + +#define PWM_DEFAULT_SWITCHING_FREQ_HZ (100000.0) +#define PWM_DEFAULT_DEADTIME_NS (100.0) + +#define PWM_MAX_SWITCHING_FREQ_HZ (2e6) +#define PWM_MIN_SWITCHING_FREQ_HZ (2e3) + +#define PWM_MAX_DEADTIME_NS ((1 << 16) - 1) +#define PWM_MIN_DEADTIME_NS (25) + +typedef enum { + // Keep first channel index at 0! + PWM_OUT1 = 0, + PWM_OUT2, + PWM_OUT3, + PWM_OUT4, + PWM_OUT5, + PWM_OUT6, + PWM_OUT7, + PWM_OUT8, + PWM_OUT9, + PWM_OUT10, + PWM_OUT11, + PWM_OUT12, + PWM_OUT13, + PWM_OUT14, + PWM_OUT15, + PWM_OUT16, + PWM_OUT17, + PWM_OUT18, + PWM_OUT19, + PWM_OUT20, + PWM_OUT21, + PWM_OUT22, + PWM_OUT23, + PWM_OUT24, + + // Keep this as last entry! + PWM_NUM_CHANNELS, +} pwm_channel_e; + +static inline bool pwm_is_valid_channel(pwm_channel_e channel) +{ + if (channel >= PWM_OUT1 && channel < PWM_NUM_CHANNELS) { + return true; + } + + return false; +} + +void pwm_init(void); + +void pwm_toggle_reset(void); +void pwm_set_all_rst(uint8_t rst); + +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) +int pwm_enable_hw(bool en); +#endif + +int pwm_enable(void); +int pwm_disable(void); +bool pwm_is_enabled(void); + +int pwm_set_switching_freq(double freq_hz); +int pwm_set_deadtime_ns(uint16_t deadtime); + +double pwm_get_switching_freq(void); +uint16_t pwm_get_deadtime_ns(void); + +int pwm_set_duty(pwm_channel_e channel, double duty); + +void pwm_set_all_duty_midscale(void); + +// Mux for PWM output pins +int pwm_mux_set_all_pins(uint32_t *config); +int pwm_mux_set_one_pin(uint32_t pwm_pin_idx, uint32_t config); + +#endif // PWM_H diff --git a/sdk/shared/drv/sts_mux.c b/sdk/shared/drv/sts_mux.c new file mode 100644 index 00000000..7d2fd736 --- /dev/null +++ b/sdk/shared/drv/sts_mux.c @@ -0,0 +1,48 @@ +#include "drv/sts_mux.h" +#include "xil_io.h" +#include +#include + +#define STS_MUX_BASE_ADDR (0x43C50000) + +static int ports[] = { + INVERTER_PORT1, INVERTER_PORT2, INVERTER_PORT3, INVERTER_PORT4, + INVERTER_PORT5, INVERTER_PORT6, INVERTER_PORT7, INVERTER_PORT8, +}; + +void sts_mux_init(void) +{ + printf("STATUS LINES:\tInitializing...\n"); + + // Set status line direction according to direction defined by the macros in the header file + sts_mux_set_output(STS_MUX_A, STS_MUX_A_DIR); + sts_mux_set_output(STS_MUX_B, STS_MUX_B_DIR); + sts_mux_set_output(STS_MUX_C, STS_MUX_C_DIR); + sts_mux_set_output(STS_MUX_D, STS_MUX_D_DIR); + + for (int i = 0; i < 8; i++) { + if (ports[i]) { + // Map the port status lines to the corresponding device defined in the header file + sts_mux_set_device(i, ports[i]); + } + } +} + +void sts_mux_set_line(uint8_t port, sts_mux_device_t device, sts_mux_line_t line) +{ + Xil_Out32(STS_MUX_BASE_ADDR + ((port + (line * 8)) * sizeof(uint32_t)), device); +} + +void sts_mux_set_output(sts_mux_line_t line, bool output) +{ + int dir = output ? 1 : 0; + Xil_Out32(STS_MUX_BASE_ADDR + ((32 + line) * sizeof(uint32_t)), dir); +} + +void sts_mux_set_device(uint8_t port, sts_mux_device_t device) +{ + sts_mux_set_line(port, device, STS_MUX_A); + sts_mux_set_line(port, device, STS_MUX_B); + sts_mux_set_line(port, device, STS_MUX_C); + sts_mux_set_line(port, device, STS_MUX_D); +} diff --git a/sdk/shared/drv/sts_mux.h b/sdk/shared/drv/sts_mux.h new file mode 100644 index 00000000..ed7394b6 --- /dev/null +++ b/sdk/shared/drv/sts_mux.h @@ -0,0 +1,52 @@ +#ifndef STS_MUX_H +#define STS_MUX_H + +#include +#include + +typedef enum { + STS_MUX_UNUSED = 0, + STS_MUX_DEVICE1 = 1, // DAC expansion board by default + STS_MUX_DEVICE2 = 2, + STS_MUX_DEVICE3 = 3, + STS_MUX_DEVICE4 = 4, + STS_MUX_DEVICE5 = 5, + STS_MUX_DEVICE6 = 6, + STS_MUX_DEVICE7 = 7, + STS_MUX_DEVICE8 = 8 +} sts_mux_device_t; + +#define STS_MUX_OUTPUT true +#define STS_MUX_INPUT false + +typedef enum { STS_MUX_A, STS_MUX_B, STS_MUX_C, STS_MUX_D } sts_mux_line_t; + +// These macros are used to map the connected devices in the FPGA IP to the desired port on the +// AMDC. All ports are re-mapped to the defined device in the init function. The +// STS_MUX_UNUSED enum maps the port to the default connections from the inverter IP + +#define INVERTER_PORT1 STS_MUX_UNUSED +#define INVERTER_PORT2 STS_MUX_UNUSED +#define INVERTER_PORT3 STS_MUX_UNUSED +#define INVERTER_PORT4 STS_MUX_UNUSED +#define INVERTER_PORT5 STS_MUX_UNUSED +#define INVERTER_PORT6 STS_MUX_UNUSED +#define INVERTER_PORT7 STS_MUX_UNUSED +#define INVERTER_PORT8 STS_MUX_UNUSED + +// These macros are used to configure the direction of the status lines in the FPGA IP + +#define STS_MUX_A_DIR STS_MUX_OUTPUT +#define STS_MUX_B_DIR STS_MUX_INPUT +#define STS_MUX_C_DIR STS_MUX_INPUT +#define STS_MUX_D_DIR STS_MUX_INPUT + +void sts_mux_init(void); + +void sts_mux_set_line(uint8_t, sts_mux_device_t, sts_mux_line_t); + +void sts_mux_set_device(uint8_t, sts_mux_device_t); + +void sts_mux_set_output(sts_mux_line_t, bool); + +#endif // STS_MUX_H diff --git a/sdk/shared/drv/timer.c b/sdk/shared/drv/timer.c new file mode 100644 index 00000000..ede8b669 --- /dev/null +++ b/sdk/shared/drv/timer.c @@ -0,0 +1,154 @@ +#include "drv/timer.h" +#include "xparameters.h" +#include "xscugic.h" +#include "xscutimer.h" + +#include +#include +#include + +#define TIMER_DEVICE_ID XPAR_XSCUTIMER_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR + +// Per ARM Cortex-A9 MPCore Technical Reference Manual, Section 4.1.1 (page 63) +// +// PERIOD = ((PRESCALER_VALUE + 1) * (LOAD_VALUE + 1)) / CLK_FREQ +// +// Rearranging leads to: +// LOAD_VALUE = ((PERIOD * CLK_FREQ) / (PRESCALER_VALUE + 1)) - 1 +// +// or, in practical units: +// LOAD_VALUE = ((PERIOD_USEC * CLK_FREQ_MHZ) / (PRESCALER_VALUE + 1)) - 1 +// +// In the Xilinx Zynq-7000: +// CLK_FREQ = 666.666/2 = 333.333 MHz +// PRESCALER_VALUE = 0 (???) +// +// Thus: +// LOAD_VALUE = (PERIOD_USEC * CLK_FREQ_MHZ) - 1 +// +#define TIMER_LOAD_VALUE(period_usec) ((period_usec * 333.333) - 1) + +// Cortex A9 Scu Private Timer Instance +static XScuTimer TimerInstance; + +// Interrupt Controller Instance +static XScuGic IntcInstance; + +static void fatalError(char *str) +{ + printf("ERROR: %s\n", str); + while (1) { + } +} + +static int +SetupIntrSystem(timer_handler_t timer_isr, XScuGic *IntcInstancePtr, XScuTimer *TimerInstancePtr, u16 TimerIntrId); + +void timer_init(timer_handler_t timer_isr, uint32_t timer_period_usec) +{ + int Status; + XScuTimer_Config *ConfigPtr; + + // Initialize the Scu Private Timer driver + ConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID); + + // This is where the virtual address would be used, this example uses physical address + Status = XScuTimer_CfgInitialize(&TimerInstance, ConfigPtr, ConfigPtr->BaseAddr); + if (Status != XST_SUCCESS) { + fatalError("Error 1"); + return; + } + + // Perform a self-test to ensure that the hardware was built correctly + Status = XScuTimer_SelfTest(&TimerInstance); + if (Status != XST_SUCCESS) { + fatalError("Error 2"); + return; + } + + // Connect the device to interrupt subsystem so that interrupts can occur + Status = SetupIntrSystem(timer_isr, &IntcInstance, &TimerInstance, TIMER_IRPT_INTR); + if (Status != XST_SUCCESS) { + fatalError("Error 3"); + return; + } + + // Enable Auto reload mode + XScuTimer_EnableAutoReload(&TimerInstance); + + // Load the timer counter register + XScuTimer_LoadTimer(&TimerInstance, TIMER_LOAD_VALUE(timer_period_usec)); + + // Start the timer counter + XScuTimer_Start(&TimerInstance); +} + +static int +SetupIntrSystem(timer_handler_t timer_isr, XScuGic *IntcInstancePtr, XScuTimer *TimerInstancePtr, u16 TimerIntrId) +{ + int Status; + + XScuGic_Config *IntcConfig; + + /* + * Initialize the interrupt controller driver so that it is ready to + * use. + */ + IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); + if (NULL == IntcConfig) { + return XST_FAILURE; + } + + Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + Xil_ExceptionInit(); + + /* + * Connect the interrupt controller interrupt handler to the hardware + * interrupt handling logic in the processor. + */ + Xil_ExceptionRegisterHandler( + XIL_EXCEPTION_ID_IRQ_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, IntcInstancePtr); + + /* + * Connect the device driver handler that will be called when an + * interrupt for the device occurs, the handler defined above performs + * the specific interrupt processing for the device. + */ + Status = XScuGic_Connect(IntcInstancePtr, TimerIntrId, (Xil_ExceptionHandler) timer_isr, (void *) TimerInstancePtr); + if (Status != XST_SUCCESS) { + return Status; + } + + /* + * Enable the interrupt for the device. + */ + XScuGic_Enable(IntcInstancePtr, TimerIntrId); + + /* + * Enable the timer interrupts for timer mode. + */ + XScuTimer_EnableInterrupt(TimerInstancePtr); + + /* + * Enable interrupts in the Processor. + */ + Xil_ExceptionEnable(); + + return XST_SUCCESS; +} + +void timer_clear_interrupt(void) +{ + XScuTimer_ClearInterruptStatus(&TimerInstance); +} + +bool timer_is_expired(void) +{ + return XScuTimer_IsExpired(&TimerInstance); +} diff --git a/sdk/shared/drv/timer.h b/sdk/shared/drv/timer.h new file mode 100644 index 00000000..33caf382 --- /dev/null +++ b/sdk/shared/drv/timer.h @@ -0,0 +1,14 @@ +#ifndef TIMER_H +#define TIMER_H + +#include +#include + +typedef void (*timer_handler_t)(void *arg); + +void timer_init(timer_handler_t timer_isr, uint32_t timer_period_usec); + +void timer_clear_interrupt(void); +bool timer_is_expired(void); + +#endif // TIMER_H diff --git a/sdk/shared/drv/timer_stats.c b/sdk/shared/drv/timer_stats.c new file mode 100644 index 00000000..e0b62443 --- /dev/null +++ b/sdk/shared/drv/timer_stats.c @@ -0,0 +1,50 @@ +#include "drv/timer_stats.h" +#include "xparameters.h" +#include "xscugic.h" +#include "xscutimer.h" + +/* timer.h also uses TIMER_0_DEVICE_ID, meaning that it probably can't coexist with this timer. This should be changed (or they should be merged) */ +#define TIMER_DEVICE_ID XPAR_XSCUTIMER_0_DEVICE_ID +#define TIMER_LOAD_VALUE(period_usec) ((period_usec * 333.333) - 1) + +XScuTimer xTimerStats; + +// Cortex A9 Scu Private Timer Instance + +static void fatalError(char *str) +{ + xil_printf("TIMER ERROR: %s\n", str); + while (1) { + } +} + +void vInitialiseTimerForRunTimeStats() { + int Status; + XScuTimer_Config *ConfigPtr; + + // Initialize the Scu Private Timer driver + ConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID); + + // This is where the virtual address would be used, this example uses physical address + Status = XScuTimer_CfgInitialize(&xTimerStats, ConfigPtr, ConfigPtr->BaseAddr); + if (Status != XST_SUCCESS) { + fatalError("Error 1"); + return; + } + + // Perform a self-test to ensure that the hardware was built correctly + Status = XScuTimer_SelfTest(&xTimerStats); + if (Status != XST_SUCCESS) { + fatalError("Error 2"); + return; + } + + // Enable Auto reload mode + XScuTimer_EnableAutoReload(&xTimerStats); + + // Load the timer counter register + XScuTimer_LoadTimer(&xTimerStats, TIMER_LOAD_VALUE(TIMER_STATS_USEC)); + + // Start the timer counter + XScuTimer_Start(&xTimerStats); +} diff --git a/sdk/shared/drv/timer_stats.h b/sdk/shared/drv/timer_stats.h new file mode 100644 index 00000000..db46d268 --- /dev/null +++ b/sdk/shared/drv/timer_stats.h @@ -0,0 +1,17 @@ +/* + * timer_stats.h + * + * Created on: Jul 11, 2024 + * Author: Ryan Srichai + * Notes: The timer described in + * https://www.freertos.org/rtos-run-time-stats.html + */ + +#ifndef DRV_TIMER_STATS_H_ +#define DRV_TIMER_STATS_H_ + +#define TIMER_STATS_USEC 10 // timer is 10x faster than FreeRTOS tick rate (which is set to 10000 ticks a second). This stats timer runs at 100KHz + +void vInitialiseTimerForRunTimeStats(); + +#endif /* DRV_TIMER_STATS_H_ */ diff --git a/sdk/shared/drv/uart.c b/sdk/shared/drv/uart.c new file mode 100644 index 00000000..58784b5b --- /dev/null +++ b/sdk/shared/drv/uart.c @@ -0,0 +1,115 @@ +#include "uart.h" +#include "sys/defines.h" +#include "xparameters.h" +#include "xuartps.h" +#include + +#define UART_DEVICE_ID XPAR_XUARTPS_0_DEVICE_ID + +#define TEST_BUFFER_SIZE (26) + +// Instance of the UART Device +XUartPs UartPs; + +// The following buffers are used in this example to send +// and receive data with the UART. +static u8 SendBuffer[TEST_BUFFER_SIZE]; // Buffer for Transmitting Data +static u8 RecvBuffer[TEST_BUFFER_SIZE]; // Buffer for Receiving Data + +// The following counters are used to determine when the entire +// buffer has been sent and received. +volatile int TotalReceivedCount; +volatile int TotalSentCount; +int TotalErrorCount; + +int uart_init(void) +{ + XUartPs *UartInstPtr = &UartPs; + u16 DeviceId = UART_DEVICE_ID; + + u32 LoopCount = 0; + unsigned int SentCount; + unsigned int ReceivedCount; + + int Status; + XUartPs_Config *Config; + int Index; + + /* + * Initialize the UART driver so that it's ready to use + * Look up the configuration in the config table, then initialize it. + */ + Config = XUartPs_LookupConfig(DeviceId); + if (NULL == Config) { + return FAILURE; + } + + Status = XUartPs_CfgInitialize(UartInstPtr, Config, Config->BaseAddress); + if (Status != XST_SUCCESS) { + return FAILURE; + } + + /* Check hardware build */ + Status = XUartPs_SelfTest(UartInstPtr); + if (Status != XST_SUCCESS) { + return FAILURE; + } + + /* Use local loopback mode. */ + XUartPs_SetOperMode(UartInstPtr, XUARTPS_OPER_MODE_LOCAL_LOOP); + + /* + * Initialize the send buffer bytes with a pattern and zero out + * the receive buffer. + */ + for (Index = 0; Index < TEST_BUFFER_SIZE; Index++) { + SendBuffer[Index] = (Index % 26) + 'A'; + RecvBuffer[Index] = 0; + } + + /* Block sending the buffer. */ + SentCount = XUartPs_Send(UartInstPtr, SendBuffer, TEST_BUFFER_SIZE); + if (SentCount != TEST_BUFFER_SIZE) { + return FAILURE; + } + + /* + * Wait while the UART is sending the data so that we are guaranteed + * to get the data the 1st time we call receive, otherwise this function + * may enter receive before the data has arrived + */ + while (XUartPs_IsSending(UartInstPtr)) { + LoopCount++; + } + + /* Block receiving the buffer. */ + ReceivedCount = 0; + while (ReceivedCount < TEST_BUFFER_SIZE) { + ReceivedCount += XUartPs_Recv(UartInstPtr, &RecvBuffer[ReceivedCount], (TEST_BUFFER_SIZE - ReceivedCount)); + } + + /* + * Check the receive buffer against the send buffer and verify the + * data was correctly received + */ + for (Index = 0; Index < TEST_BUFFER_SIZE; Index++) { + if (SendBuffer[Index] != RecvBuffer[Index]) { + return FAILURE; + } + } + + /* Restore to normal mode. */ + XUartPs_SetOperMode(UartInstPtr, XUARTPS_OPER_MODE_NORMAL); + + return SUCCESS; +} + +int uart_send(char *msg, int len) +{ + return XUartPs_Send(&UartPs, (uint8_t *) msg, len); +} + +int uart_recv(char *msg, int len) +{ + return XUartPs_Recv(&UartPs, (uint8_t *) msg, len); +} diff --git a/sdk/shared/drv/uart.h b/sdk/shared/drv/uart.h new file mode 100644 index 00000000..d63a6332 --- /dev/null +++ b/sdk/shared/drv/uart.h @@ -0,0 +1,14 @@ +#ifndef UART_H +#define UART_H + +#include + +#define UART_RX_FIFO_LENGTH (64) +#define UART_TX_FIFO_LENGTH (64) + +int uart_init(void); + +int uart_send(char *msg, int len); +int uart_recv(char *msg, int len); + +#endif // UART_H diff --git a/sdk/shared/drv/watchdog.c b/sdk/shared/drv/watchdog.c new file mode 100644 index 00000000..7dcb81c5 --- /dev/null +++ b/sdk/shared/drv/watchdog.c @@ -0,0 +1,40 @@ +#include "drv/watchdog.h" +#include "xparameters.h" +#include "xscuwdt.h" + +// Private watchdog defines +#define WDT_DEVICE_ID (XPAR_SCUWDT_0_DEVICE_ID) +#define INTC_DEVICE_ID (XPAR_SCUGIC_SINGLE_DEVICE_ID) +#define WDT_IRPT_INTR (XPAR_SCUWDT_INTR) +#define WDT_LOAD_VALUE (0xFFFFFFFF) // seems to be about 10 seconds + +XScuWdt WdtInstance; + +void watchdog_init(void) +{ + int Status; + XScuWdt_Config *ConfigPtr; + + // Initialize the SCU Private Wdt driver so that it is ready to use. + ConfigPtr = XScuWdt_LookupConfig(WDT_DEVICE_ID); + Status = XScuWdt_CfgInitialize(&WdtInstance, ConfigPtr, ConfigPtr->BaseAddr); + if (Status != XST_SUCCESS) { + // Hang if error... + while (1) { + } + } + + // Put the watchdog timer in watchdog mode. + XScuWdt_SetWdMode(&WdtInstance); + + // Load the watchdog counter register. + XScuWdt_LoadWdt(&WdtInstance, WDT_LOAD_VALUE); + + // Start the ScuWdt device. + XScuWdt_Start(&WdtInstance); +} + +void watchdog_reset(void) +{ + XScuWdt_RestartWdt(&WdtInstance); +} diff --git a/sdk/shared/drv/watchdog.h b/sdk/shared/drv/watchdog.h new file mode 100644 index 00000000..62474d7a --- /dev/null +++ b/sdk/shared/drv/watchdog.h @@ -0,0 +1,9 @@ +#ifndef WATCHDOG_H +#define WATCHDOG_H + +/* this might not do anything anymore (because no scheduler), but you know what they say. We'll let sleeping dogs lie */ + +void watchdog_init(void); +void watchdog_reset(void); + +#endif // WATCHDOG_H diff --git a/sdk/shared/platform_config.h b/sdk/shared/platform_config.h index 3e9b7f18..eda2e2eb 100644 --- a/sdk/shared/platform_config.h +++ b/sdk/shared/platform_config.h @@ -1,6 +1,6 @@ -#ifndef __PLATFORM_CONFIG_H_ -#define __PLATFORM_CONFIG_H_ - -#define STDOUT_IS_PS7_UART -#define UART_DEVICE_ID 0 -#endif +#ifndef __PLATFORM_CONFIG_H_ +#define __PLATFORM_CONFIG_H_ + +#define STDOUT_IS_PS7_UART +#define UART_DEVICE_ID 0 +#endif diff --git a/sdk/shared/sys/cmd/cmd_counter.c b/sdk/shared/sys/cmd/cmd_counter.c new file mode 100644 index 00000000..82ac0d34 --- /dev/null +++ b/sdk/shared/sys/cmd/cmd_counter.c @@ -0,0 +1,54 @@ +#include "sys/cmd/cmd_counter.h" +#include "sys/commands.h" +#include "sys/defines.h" +#include "sys/util.h" +#include +#include +#include + +static command_entry_t cmd_entry; + +static command_help_t cmd_help[] = { + { "inc", "Increment CNT reg" }, + { "dec", "Decrement CNT reg" }, + { "clr", "Clear CNT reg" }, + { "get", "Get CNT reg" }, +}; + +void cmd_counter_register(void) +{ + // Populate the command entry block + commands_cmd_init( + &cmd_entry, "counter", "Counter reg related commands", cmd_help, ARRAY_SIZE(cmd_help), cmd_counter); + + // Register the command + commands_cmd_register(&cmd_entry); +} + +static int CNT = 0; + +// Handles the 'counter' command and all sub-commands +int cmd_counter(int argc, char **argv) +{ + if (argc == 2 && STREQ("inc", argv[1])) { + CNT++; + return CMD_SUCCESS; + } + + if (argc == 2 && STREQ("dec", argv[1])) { + CNT--; + return CMD_SUCCESS; + } + + if (argc == 2 && STREQ("clr", argv[1])) { + CNT = 0; + return CMD_SUCCESS; + } + + if (argc == 2 && STREQ("get", argv[1])) { + cmd_resp_printf("CNT = %d\r\n", CNT); + return CMD_SUCCESS; + } + + return CMD_INVALID_ARGUMENTS; +} diff --git a/sdk/shared/sys/cmd/cmd_counter.h b/sdk/shared/sys/cmd/cmd_counter.h new file mode 100644 index 00000000..a9fa6f16 --- /dev/null +++ b/sdk/shared/sys/cmd/cmd_counter.h @@ -0,0 +1,8 @@ +#ifndef CMD_COUNTER_H +#define CMD_COUNTER_H + +void cmd_counter_register(void); + +int cmd_counter(int argc, char **argv); + +#endif // CMD_COUNTER_H diff --git a/sdk/shared/sys/cmd/cmd_help.c b/sdk/shared/sys/cmd/cmd_help.c new file mode 100644 index 00000000..03793982 --- /dev/null +++ b/sdk/shared/sys/cmd/cmd_help.c @@ -0,0 +1,29 @@ +#include "cmd_help.h" +#include "sys/commands.h" +#include +#include + +static command_entry_t cmd_entry; + +void cmd_help_register(void) +{ + // Populate the command entry block + commands_cmd_init(&cmd_entry, "help", "Display this help message", NULL, 0, cmd_help); + + // Register the command + commands_cmd_register(&cmd_entry); +} + +// +// Handles the 'help' command +// +int cmd_help(int argc, char **argv) +{ + if (argc > 1) { + return CMD_INVALID_ARGUMENTS; + } + + commands_display_help(); + + return CMD_SUCCESS_QUIET; +} diff --git a/sdk/shared/sys/cmd/cmd_help.h b/sdk/shared/sys/cmd/cmd_help.h new file mode 100644 index 00000000..130a1a93 --- /dev/null +++ b/sdk/shared/sys/cmd/cmd_help.h @@ -0,0 +1,8 @@ +#ifndef CMD_HELP_H +#define CMD_HELP_H + +void cmd_help_register(void); + +int cmd_help(int argc, char **argv); + +#endif // CMD_HELP_H diff --git a/sdk/shared/sys/cmd/cmd_hw.c b/sdk/shared/sys/cmd/cmd_hw.c new file mode 100644 index 00000000..a32b8242 --- /dev/null +++ b/sdk/shared/sys/cmd/cmd_hw.c @@ -0,0 +1,495 @@ +#include "sys/cmd/cmd_hw.h" +#include "drv/analog.h" +#include "drv/cpu_timer.h" +#include "drv/eddy_current_sensor.h" +#include "drv/encoder.h" +#include "drv/fpga_timer.h" +#include "drv/gp3io_mux.h" +#include "drv/gpio_direct.h" +#include "drv/gpio_mux.h" +#include "drv/ild1420.h" +#include "drv/led.h" +#include "drv/pwm.h" +#include "drv/sts_mux.h" +#include "sys/commands.h" +#include "sys/debug.h" +#include "sys/defines.h" +#include "sys/util.h" +#include "usr/user_config.h" + +#include +#include +#include + +static command_entry_t cmd_entry; + +static command_help_t cmd_help[] = { + { "pwm ", "Turn on/off PWM switching" }, + { "pwm sw ", "Set the PWM switching characteristics" }, + { "pwm duty ", "Set a duty ratio" }, + { "anlg read ", "Read voltage on ADC channel" }, + { "ild read", "Read the latest packet from ILD1420 sensor" }, + { "enc steps", "Read encoder steps from power-up" }, + { "enc pos", "Read encoder position" }, + { "enc init", "Turn on blue LED until Z pulse found" }, + { "timer now", "Read value from hardware timer" }, + { "led set ", "Set LED color (color is 0..255)" }, + { "mux ", "Map the device driver in the FPGA to the hardware port" }, + { "mux list", "List the device drivers available in the FPGA to the hardware port" }, + { "gpio ", "Read and write digital voltages directly to GPIO pins" }, + { "eddy trigger ", + "Trigger the eddy current sensor to sample on the PWM carrier's peak, valley, or both" }, + { "eddy timing ", + "The desired SCLK frequency (kHz) and one-way delay of the adapter board (ns)" }, +}; + +void cmd_hw_register(void) +{ + // Populate the command entry block + commands_cmd_init(&cmd_entry, "hw", "Hardware related commands", cmd_help, ARRAY_SIZE(cmd_help), cmd_hw); + + // Register the command + commands_cmd_register(&cmd_entry); +} + +// Handles the 'hw' command and all sub-commands +int cmd_hw(int argc, char **argv) +{ + // Handle 'pwm' sub-command + if (argc >= 2 && STREQ("pwm", argv[1])) { + if (argc == 3 && STREQ("on", argv[2])) { +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + // Turn on PWM hardware before enabling + // so that the first cycle has correct duty + pwm_enable_hw(true); +#endif + + if (pwm_enable() != SUCCESS) { + return CMD_FAILURE; + } + + return CMD_SUCCESS; + } + + if (argc == 3 && STREQ("off", argv[2])) { + if (pwm_disable() != SUCCESS) { + return CMD_FAILURE; + } + +#if (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + // Turn off PWM hardware after disabling + // so that the last cycle has correct duty + pwm_enable_hw(false); +#endif + + return CMD_SUCCESS; + } + + if (argc == 5 && STREQ("sw", argv[2])) { + // Parse out switching freq arg + double fsw = strtod(argv[3], NULL); + if (fsw > 2e6 || fsw < 2e3) { + return CMD_INVALID_ARGUMENTS; + } + + // Parse out dead time arg + int dt = atoi(argv[4]); + if (dt > 5000 || dt < 25) { + return CMD_INVALID_ARGUMENTS; + } + + if (pwm_set_deadtime_ns(dt) != SUCCESS) { + return CMD_FAILURE; + } + + if (pwm_set_switching_freq(fsw) != SUCCESS) { + return CMD_FAILURE; + } + + return CMD_SUCCESS; + } + + if (argc == 5 && STREQ("duty", argv[2])) { + // Parse out switching pwm_idx arg + int pwm_idx = atoi(argv[3]); + + if (!pwm_is_valid_channel(pwm_idx)) { + return CMD_INVALID_ARGUMENTS; + } + + // Parse out percent arg + double percent = strtod(argv[4], NULL); + if (percent > 1.0 || percent < 0.0) { + return CMD_INVALID_ARGUMENTS; + } + + pwm_set_duty(pwm_idx, percent); + + return CMD_SUCCESS; + } + } + + // Handle 'anlg' sub-command + if (argc >= 2 && STREQ("anlg", argv[1])) { + if (argc == 4 && STREQ("read", argv[2])) { + // Parse out analog channel arg + int anlg_idx = atoi(argv[3]); + + if (!analog_is_valid_channel(anlg_idx)) { + return CMD_INVALID_ARGUMENTS; + } + + float out_volts; + analog_getf(anlg_idx, &out_volts); + + cmd_resp_printf("%fV\r\n", out_volts); + + return SUCCESS; + } + } + + // Handle 'ild' sub-command + // hw ild read + if (argc == 4 && strcmp("ild", argv[1]) == 0) { + if (strcmp("read", argv[2]) == 0) { + int sensor = atoi(argv[3]); + + if (sensor < 0 || sensor >= ILD1420_NUM_SENSORS) + return CMD_INVALID_ARGUMENTS; + + ild1420_packet_t packet = ild1420_get_latest_packet(sensor); + cmd_resp_printf("dist: %x\r\n", packet.distance); + cmd_resp_printf("err: %X\r\n", packet.error); + cmd_resp_printf("fresh: %X\r\n", packet.fresh); + + return CMD_SUCCESS; + } + } + + // Handle 'enc' sub-command + if (argc >= 2 && STREQ("enc", argv[1])) { + if (argc == 3 && STREQ("steps", argv[2])) { + int32_t steps; + encoder_get_steps(&steps); + + cmd_resp_printf("steps: %ld\r\n", steps); + + return CMD_SUCCESS; + } + + if (argc == 3 && STREQ("pos", argv[2])) { + uint32_t position; + encoder_get_position(&position); + + cmd_resp_printf("pos: %ld\r\n", position); + + return CMD_SUCCESS; + } + + if (argc == 3 && STREQ("init", argv[2])) { + encoder_find_z(); + + return CMD_SUCCESS; + } + } + + // Handle 'eddy' sub-command + if (argc >= 5 && STREQ("eddy", argv[1])) { + + int32_t port = atoi(argv[3]); + uint32_t base_addr = 0; + +#if USER_CONFIG_HARDWARE_TARGET == AMDC_REV_D + if (port < 1 || port > 2) + return CMD_INVALID_ARGUMENTS; + else + base_addr = EDDY_CURRENT_SENSOR_1_BASE_ADDR; + +#elif (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + if (port == 1) + base_addr = EDDY_CURRENT_SENSOR_1_BASE_ADDR; + else if (port == 2) + base_addr = EDDY_CURRENT_SENSOR_2_BASE_ADDR; + else if (port == 3) + base_addr = EDDY_CURRENT_SENSOR_3_BASE_ADDR; + else if (port == 4) + base_addr = EDDY_CURRENT_SENSOR_4_BASE_ADDR; + else + return CMD_INVALID_ARGUMENTS; +#endif + + // hw eddy trigger + if (argc == 5 && STREQ("trigger", argv[2])) { + eddy_current_sensor_trigger_on_pwm_clear(base_addr); + + if (STREQ("HIGH", argv[4])) + eddy_current_sensor_trigger_on_pwm_high(base_addr); + else if (STREQ("LOW", argv[4])) + eddy_current_sensor_trigger_on_pwm_low(base_addr); + else if (STREQ("BOTH", argv[4])) + eddy_current_sensor_trigger_on_pwm_both(base_addr); + else + return CMD_INVALID_ARGUMENTS; + + return CMD_SUCCESS; + } + + // hw eddy timing sclk_freq_khz prop_delay_ns + if (argc == 6 && STREQ("timing", argv[2])) { + + uint32_t sclk_freq_khz = (uint32_t) atoi(argv[4]); + uint32_t propogation_delay_ns = (uint32_t) atoi(argv[5]); + + eddy_current_sensor_set_timing(base_addr, sclk_freq_khz, propogation_delay_ns); + + return CMD_SUCCESS; + } + } + + // Handle 'timer' sub-command + if (argc >= 2 && STREQ("timer", argv[1])) { + if (argc == 4 && STREQ("fpga", argv[2]) && STREQ("now", argv[3])) { + uint32_t counts1 = fpga_timer_now(); + uint32_t counts2 = fpga_timer_now(); + + cmd_resp_printf("counts1: %lu\r\n", counts1); + cmd_resp_printf("counts2: %lu\r\n", counts2); + cmd_resp_printf("time delta = %8.3f ns\r\n", 1e3 * fpga_timer_ticks_to_usec(counts2 - counts1)); + + return CMD_SUCCESS; + } + + if (argc == 4 && STREQ("cpu", argv[2]) && STREQ("now", argv[3])) { + uint32_t counts1 = cpu_timer_now(); + uint32_t counts2 = cpu_timer_now(); + + cmd_resp_printf("counts1: %lu\r\n", counts1); + cmd_resp_printf("counts2: %lu\r\n", counts2); + cmd_resp_printf("time delta = %8.3f ns\r\n", 1e3 * cpu_timer_ticks_to_usec(counts2 - counts1)); + + return CMD_SUCCESS; + } + } + + // Handle 'led' sub-command + // hw led set + if (argc >= 2 && STREQ("led", argv[1])) { + if (argc == 7 && STREQ("set", argv[2])) { + int led_idx = atoi(argv[3]); + if (led_idx < 0 || led_idx >= NUM_LEDS) + return CMD_INVALID_ARGUMENTS; + + int r = atoi(argv[4]); + int g = atoi(argv[5]); + int b = atoi(argv[6]); + + if (r < 0 || r > 255) + return CMD_INVALID_ARGUMENTS; + if (g < 0 || g > 255) + return CMD_INVALID_ARGUMENTS; + if (b < 0 || b > 255) + return CMD_INVALID_ARGUMENTS; + + led_set_color_bytes(led_idx, r, g, b); + + return CMD_SUCCESS; + } + } + + // Handle 'gpio' sub-command + // hw gpio read + // hw gpio write + // hw gpio toggle + if (argc >= 5 && STREQ("gpio", argv[1])) { + + // NOTE: + // Users should enter ports and pins that are 1-indexed + // However, the functions in gpio_direct.c require 0-indexed + // arguments. That is why we subtract 1 from the user cmd input + uint8_t gpio_port = atoi(argv[3]); + uint8_t pin = atoi(argv[4]); + +#if USER_CONFIG_HARDWARE_TARGET == AMDC_REV_D + if (gpio_port < 1 || gpio_port > 2) + return CMD_INVALID_ARGUMENTS; + + if (pin < 1 || pin > 2) + return CMD_INVALID_ARGUMENTS; + +#elif (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + if (gpio_port < 1 || gpio_port > 4) + return CMD_INVALID_ARGUMENTS; + + if (pin < 1 || pin > 3) + return CMD_INVALID_ARGUMENTS; +#endif + + if (argc == 5 && STREQ("read", argv[2])) { + + gpio_direct_level_t level = gpio_direct_read(gpio_port - 1, pin - 1); + + if (level == GPIO_DIRECT_HIGH) { + cmd_resp_print("Read Result: HIGH\r\n"); + } else if (level == GPIO_DIRECT_LOW) { + cmd_resp_print("Read Result: LOW\r\n"); + } + + return CMD_SUCCESS; + } // end if "read" + + if (argc == 6 && STREQ("write", argv[2])) { + + char *level = argv[5]; + + if (STREQ("HIGH", level)) { + gpio_direct_write(gpio_port - 1, pin - 1, 1); + } else if (STREQ("LOW", level)) { + gpio_direct_write(gpio_port - 1, pin - 1, 0); + } else { + return CMD_INVALID_ARGUMENTS; + } + + return CMD_SUCCESS; + } // end if "write" + + if (argc == 5 && STREQ("toggle", argv[2])) { + + gpio_direct_toggle(gpio_port - 1, pin - 1); + + return CMD_SUCCESS; + } // end if "write" + + } // end if "gpio" sub-command + + // Handle 'mux' sub-command + // mux gpio + if (argc >= 2 && STREQ("mux", argv[1])) { + if (argc == 5 && STREQ("gpio", argv[2])) { + int gpio_port = atoi(argv[3]); + int device = atoi(argv[4]); + +#if USER_CONFIG_HARDWARE_TARGET == AMDC_REV_D + if (device < 0 || device > GPIO_MUX_DEVICE_COUNT) { + return CMD_INVALID_ARGUMENTS; + } + + if (gpio_port < 1 || gpio_port > 2) { + return CMD_INVALID_ARGUMENTS; + } + + gpio_mux_set_device(gpio_port - 1, device); + +#elif (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + if (device < 0 || device > GP3IO_MUX_DEVICE_COUNT) { + return CMD_INVALID_ARGUMENTS; + } + + if (gpio_port < 1 || gpio_port > 4) { + return CMD_INVALID_ARGUMENTS; + } + + switch (gpio_port) { + case 1: + gp3io_mux_set_device(GP3IO_MUX_1_BASE_ADDR, device); + break; + case 2: + gp3io_mux_set_device(GP3IO_MUX_2_BASE_ADDR, device); + break; + case 3: + gp3io_mux_set_device(GP3IO_MUX_3_BASE_ADDR, device); + break; + case 4: + gp3io_mux_set_device(GP3IO_MUX_4_BASE_ADDR, device); + break; + default: + return CMD_INVALID_ARGUMENTS; + break; + } + +#endif // USER_CONFIG_HARDWARE_TARGET + + return CMD_SUCCESS; + } else if (argc == 4 && STREQ("gpio", argv[2]) && STREQ("list", argv[3])) { + /* MAINTAINER NOTE: + * These device listings come from the Vivado Block Design files, + * amdc_revd.bd and amdc_reve.bd, + * and should be kept in sync. + */ +#if USER_CONFIG_HARDWARE_TARGET == AMDC_REV_D + cmd_resp_print("AMDC REV D gpio device numbers:\r\n"); + cmd_resp_print("1. Eddy Current Sensor\r\n"); + cmd_resp_print("2. AMDS\r\n"); + cmd_resp_print("3. ILD1420 Proximity Sensor 1\r\n"); + cmd_resp_print("4. ILD1420 Proximity Sensor 2\r\n"); + cmd_resp_print("5. GPIO Direct (Port 1)\r\n"); + cmd_resp_print("6. GPIO Direct (Port 2)\r\n"); + cmd_resp_print("7. UNUSED\r\n"); + cmd_resp_print("8. UNUSED\r\n"); + return CMD_SUCCESS; + +#elif (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + cmd_resp_print("AMDC REV E & REV F gpio device numbers:\r\n"); + cmd_resp_print("1. AMDS\r\n"); + cmd_resp_print("2. Eddy Current Sensor\r\n"); + cmd_resp_print("3. ILD1420 Proximity Sensor\r\n"); + cmd_resp_print("4. GPIO Direct\r\n"); + cmd_resp_print("5. UNUSED\r\n"); + cmd_resp_print("6. UNUSED\r\n"); + cmd_resp_print("7. UNUSED\r\n"); + cmd_resp_print("8. UNUSED\r\n"); + return CMD_SUCCESS; + +#endif // USER_CONFIG_HARDWARE_TARGET for hw mux gpio list + } + + if (argc == 5 && STREQ("sts", argv[2])) { + int sts_port = atoi(argv[3]); + int device = atoi(argv[4]); + + if (sts_port < 1 || sts_port > 8) + return CMD_INVALID_ARGUMENTS; + if (device < 0 || device > 8) + return CMD_INVALID_ARGUMENTS; + + sts_mux_set_device(sts_port - 1, device); + + return CMD_SUCCESS; + } else if (argc == 4 && STREQ("sts", argv[2]) && STREQ("list", argv[3])) { +#if USER_CONFIG_HARDWARE_TARGET == AMDC_REV_D + cmd_resp_print("AMDC REV D sts device numbers:\r\n"); + // TODO: FILL IN BELOW AND REMOVE NEXT LINE + cmd_resp_print("Please check the block design by opening hw/amdc_revd.bd in Vivado.\r\n"); + /* + cmd_resp_print("1. \r\n"); + cmd_resp_print("2. \r\n"); + cmd_resp_print("3. \r\n"); + cmd_resp_print("4. \r\n"); + cmd_resp_print("5. \r\n"); + cmd_resp_print("6. \r\n"); + cmd_resp_print("7. \r\n"); + cmd_resp_print("8. \r\n"); + return CMD_SUCCESS; + */ + +#elif (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_E) || (USER_CONFIG_HARDWARE_TARGET == AMDC_REV_F) + cmd_resp_print("AMDC REV E & REV F sts device numbers:\r\n"); + // TODO: FILL IN BELOW AND REMOVE NEXT LINE + cmd_resp_print("Please check the block design by opening hw/amdc_reve.bd in Vivado.\r\n"); + /* + cmd_resp_print("1. \r\n"); + cmd_resp_print("2. \r\n"); + cmd_resp_print("3. \r\n"); + cmd_resp_print("4. \r\n"); + cmd_resp_print("5. \r\n"); + cmd_resp_print("6. \r\n"); + cmd_resp_print("7. \r\n"); + cmd_resp_print("8. \r\n"); + return CMD_SUCCESS; + */ + +#endif // USER_CONFIG_HARDWARE_TARGET for hw mux sts list + } + } + + return CMD_INVALID_ARGUMENTS; +} diff --git a/sdk/shared/sys/cmd/cmd_hw.h b/sdk/shared/sys/cmd/cmd_hw.h new file mode 100644 index 00000000..d657e7dc --- /dev/null +++ b/sdk/shared/sys/cmd/cmd_hw.h @@ -0,0 +1,8 @@ +#ifndef CMD_HW_H +#define CMD_HW_H + +void cmd_hw_register(void); + +int cmd_hw(int argc, char **argv); + +#endif // CMD_HW_H diff --git a/sdk/shared/sys/commands.c b/sdk/shared/sys/commands.c new file mode 100644 index 00000000..3528e2b5 --- /dev/null +++ b/sdk/shared/sys/commands.c @@ -0,0 +1,586 @@ +/* FreeRTOS includes */ +#include "FreeRTOS.h" +#include "task.h" +/* other includes */ +#include "sys/commands.h" +// #include "drv/encoder.h" +#include "drv/uart.h" +#include "sys/cmd/cmd_help.h" +#include "sys/debug.h" +#include "sys/defines.h" +#include "sys/icc.h" + #include "sys/icc_tx.h" +// #include "sys/log.h" +#include "sys/serial.h" +#include "sys/util.h" +#include +#include +#include +#include + +#define RECV_BUFFER_LENGTH (4 * 1024) + +typedef enum cmd_parsing_state_e { + BEGIN = 0, + LOOKING_FOR_SPACE, + LOOKING_FOR_CHAR, +} cmd_parsing_state_e; + +#define CMD_MAX_ARGC (16) // # of args accepted +#define CMD_MAX_ARG_LENGTH (32) // max chars of any arg +typedef struct pending_cmd_t { + int argc; + char *argv[CMD_MAX_ARGC]; + + // Used by parser to keep track of how + // long the argument is. If too long, + // throws an error! + int curr_arg_length; + + // Error flag set by parser task + int err; + + // Set to 1 to indicate ready to execute, + // 0 means not valid + int ready; +} pending_cmd_t; + +// Note, this must be >= 2. +// +// We always need a buffer to be filling while we +// execute the previous command +// +#define MAX_PENDING_CMDS (8) + +typedef struct { + cmd_parsing_state_e state; + + // Store parsed cmds + pending_cmd_t pending_cmds[MAX_PENDING_CMDS]; + int pending_cmd_write_idx; + int pending_cmd_read_idx; + + // Store rx chars + char recv_buffer[RECV_BUFFER_LENGTH]; + int recv_buffer_idx; +} sm_parse_ascii_cmd_ctx_t; + +static sm_parse_ascii_cmd_ctx_t ctx_uart; +static sm_parse_ascii_cmd_ctx_t ctx_eth; + +static int _command_handler(int argc, char **argv); + +static void commands_uart(void *arg); +static void commands_eth(void *arg); +static void parse_commands(void *arg); + +// Head of linked list of commands +static command_entry_t *cmds = NULL; + +static TaskHandle_t tcb_uart; +static uint8_t uartTaskExists = 0; // extra data to ensure tasks don't get duplicated or double free'd +static TaskHandle_t tcb_eth; +static uint8_t ethTaskExists = 0; // extra data to ensure tasks don't get duplicated or double free'd + +// The command response data should either go out UART or ETH, +// depending on the command source. Therefore, we'll define +// global general command response functions which users will +// use for their cmd response. This "commands" module will +// update these functions to target the correct stream. + +typedef enum cmd_src_e { + CMD_SRC_UART = 0, + CMD_SRC_ETH, +} cmd_src_e; + +static cmd_src_e current_cmd_source = CMD_SRC_UART; + +void cmd_resp_write(char *msg, int len) +{ + if (current_cmd_source == CMD_SRC_UART) { + serial_write(msg, len); + } else { + for (int i = 0; i < len; i++) { + icc_tx_append_char_to_fifo(msg[i]); + } + } +} + +void cmd_resp_print(char *msg) +{ + if (current_cmd_source == CMD_SRC_UART) { + debug_print(msg); + } else { + cmd_resp_write(msg, strlen(msg)); + } +} + +#define PRINTF_BUFFER_LENGTH (1024) +static char buffer[PRINTF_BUFFER_LENGTH] = { 0 }; +void cmd_resp_printf(const char *format, ...) +{ + va_list vargs; + va_start(vargs, format); + vsnprintf(buffer, PRINTF_BUFFER_LENGTH, format, vargs); + cmd_resp_print(buffer); + va_end(vargs); +} + +void commands_init(void) +{ + printf("CMD:\tInitializing command tasks...\n"); + // Command parse & exec task (UART) + if (uartTaskExists == 0) { + xTaskCreate(commands_uart, (const char *) "command_uart", configMINIMAL_STACK_SIZE, + NULL, tskIDLE_PRIORITY, &tcb_uart); + uartTaskExists = 1; + } + + // Command parse task (ETH) + if (ethTaskExists == 0) { + xTaskCreate(commands_eth, (const char *) "command_eth", configMINIMAL_STACK_SIZE, + NULL, tskIDLE_PRIORITY, &tcb_eth); + ethTaskExists = 1; + } + + cmd_help_register(); +} + +// Set if we should echo back characters to sender: +// - 0: when EXECUTING the pending command +// - 1: when PROCESSING the incoming chars +// +// Both have pros and cons... For slow comms, we want +// to echo AS the chars come in since the user is likely +// using a UART terminal and wants to see a response to +// their inputs. +// +// For fast comms (i.e. Ethernet), we should only echo +// when the command is executed since the host could send +// a burst of multiple command strings in short time, +// before we have time to actually run the command. +// +// We will choose when PROCESSING the incoming chars and +// limit the command through-put from the host to: +// <= 1 command string per 100 usec time slice +// This will ensure we process the pending command before +// the next set of chars appears. +#define ECHO_BACK_WHEN_PROCESSING_INCOMING_CHARS (1) + +static void _create_pending_cmds(sm_parse_ascii_cmd_ctx_t *ctx, char *buffer, int length) +{ + // Get current pending cmd slot + pending_cmd_t *p = &ctx->pending_cmds[ctx->pending_cmd_write_idx]; + + for (int i = 0; i < length; i++) { + char c = buffer[i]; + + if (ctx->state != BEGIN && (c == '\n' || c == '\r')) { + // End of a command! + + // Set error flag if this arg was too long + if (p->curr_arg_length > CMD_MAX_ARG_LENGTH) { + p->err = CMD_INPUT_TOO_LONG; + } + + // Put a NULL at the end of the last cmd arg + // (replaces a \r or \n, so nbd + buffer[i] = 0; + +#if ECHO_BACK_WHEN_PROCESSING_INCOMING_CHARS == 1 + // Make console go to beginning of next line + if (ctx == &ctx_uart) { + debug_print("\r\n"); + } else { + icc_tx_append_char_to_fifo('\r'); + icc_tx_append_char_to_fifo('\n'); + } +#endif + + p->ready = 1; + + // Update current pending cmd slot + if (++ctx->pending_cmd_write_idx >= MAX_PENDING_CMDS) { + ctx->pending_cmd_write_idx = 0; + } + p = &ctx->pending_cmds[ctx->pending_cmd_write_idx]; + p->ready = 0; + + // Move on to next char, which starts + // next command sequence + ctx->state = BEGIN; + continue; + } + +#if ECHO_BACK_WHEN_PROCESSING_INCOMING_CHARS == 1 + // Echo character back to host + if (ctx == &ctx_uart) { + serial_write(&c, 1); + } else { + icc_tx_append_char_to_fifo(c); + } +#endif + + // Process incoming char `c` + switch (ctx->state) { + case BEGIN: + if (!isspace(c)) { + // Populate first argument + p->argc = 1; + p->argv[0] = &buffer[i]; + p->err = CMD_SUCCESS; // Assume the parsing will work! + p->curr_arg_length = 1; + ctx->state = LOOKING_FOR_SPACE; + } + break; + + case LOOKING_FOR_SPACE: + if (c != ' ') { + p->curr_arg_length++; + } + + if (c == ' ') { + // End of chars for the arg + + // Set error flag if this arg was too long + if (p->curr_arg_length > CMD_MAX_ARG_LENGTH) { + p->err = CMD_INPUT_TOO_LONG; + } + + // Put NULL at end of arg (replaces ' ') + buffer[i] = 0; + + ctx->state = LOOKING_FOR_CHAR; + } + break; + + case LOOKING_FOR_CHAR: + if (c != ' ') { + p->argv[p->argc] = &buffer[i]; + p->argc++; + + // Check if argc too big! + if (p->argc > CMD_MAX_ARGC) { + p->err = CMD_INPUT_TOO_LONG; + + // Put argc back to zero... + // NOTE: this ensure no buffer overruns, + // but, screws up previous args. + // This is okay as we are going to + // throw away this pending cmd! + p->argc = 0; + } + + p->curr_arg_length = 1; + ctx->state = LOOKING_FOR_SPACE; + } + break; + + default: + // Impossible! + HANG; + break; + } + } +} + +static void commands_uart(void *arg) +{ + sm_parse_ascii_cmd_ctx_t *ctx = &ctx_uart; + for (;;) { + vTaskDelay(COMMANDS_INTERVAL_TICKS); + + // Read in bounded chunk of new chars + // + // NOTE: careful not to try and read too much! + // would cause a buffer overrun! + // + int try_to_read = MIN(UART_RX_FIFO_LENGTH, RECV_BUFFER_LENGTH - ctx->recv_buffer_idx); + int num_bytes = uart_recv(&ctx->recv_buffer[ctx->recv_buffer_idx], try_to_read); + + // Run state machine to create pending cmds to execute + _create_pending_cmds(ctx, &ctx->recv_buffer[ctx->recv_buffer_idx], num_bytes); + + // Move along in recv buffer + ctx->recv_buffer_idx += num_bytes; + if (ctx->recv_buffer_idx >= RECV_BUFFER_LENGTH) { + ctx->recv_buffer_idx = 0; + } + parse_commands(ctx); + } +} + +static void commands_eth(void *arg) +{ + sm_parse_ascii_cmd_ctx_t *ctx = &ctx_eth; + + static const int MAX_NUM_BYTES_TO_TRY = 128; + for (;;) { + vTaskDelay(COMMANDS_INTERVAL_TICKS); + // Try to pull out the oldest MAX_NUM_BYTES_TO_TRY bytes from the shared FIFO from CPU0 + // + // If there are less than MAX_NUM_BYTES_TO_TRY bytes in the FIFO, this code will simply + // pull out everything and return. + for (int i = 0; i < MAX_NUM_BYTES_TO_TRY; i++) { + // Check if there are any bytes in the FIFO + if (ICC_CPU0to1_CH0__GET_ProduceCount - ICC_CPU0to1_CH0__GET_ConsumeCount == 0) { + // Shared buffer is empty + break; + } + + // Read the oldest byte available + uint8_t *sharedBuffer = ICC_CPU0to1_CH0__BufferBaseAddr; + uint8_t c = sharedBuffer[ICC_CPU0to1_CH0__GET_ConsumeCount % ICC_BUFFER_SIZE]; + + // Increment the consume count + ICC_CPU0to1_CH0__SET_ConsumeCount(ICC_CPU0to1_CH0__GET_ConsumeCount + 1); + + // ===================== + // Process incoming char + // ===================== + + char c_char = (char) c; + + // Push the new byte into the rx buffer + ctx->recv_buffer[ctx->recv_buffer_idx] = c_char; + + // Run state machine to create pending cmds to execute + _create_pending_cmds(ctx, &ctx->recv_buffer[ctx->recv_buffer_idx], 1); + + // Move along in recv buffer + ctx->recv_buffer_idx += 1; + if (ctx->recv_buffer_idx >= RECV_BUFFER_LENGTH) { + ctx->recv_buffer_idx = 0; + } + } + parse_commands(ctx); + } +} + +static void parse_commands(void *arg) +{ + sm_parse_ascii_cmd_ctx_t *ctx = (sm_parse_ascii_cmd_ctx_t *) arg; + + // Get current pending cmd slot + pending_cmd_t *p = &ctx->pending_cmds[ctx->pending_cmd_read_idx]; + + if (p->ready) { + // Run me! + + // Change current cmd source + if (ctx == &ctx_uart) { + current_cmd_source = CMD_SRC_UART; + } else if (ctx == &ctx_eth) { + current_cmd_source = CMD_SRC_ETH; + } else { + // unreachable + } + +#if ECHO_BACK_WHEN_PROCESSING_INCOMING_CHARS == 0 + // Echo back command to sender + for (int i = 0; i < p->argc; i++) { + cmd_resp_printf("%s", p->argv[i]); + + if (i + 1 < p->argc) { + cmd_resp_print(" "); + } + } + cmd_resp_print("\r\n"); +#endif + + // Don't run a cmd that has errors + int err = p->err; + if (err == CMD_SUCCESS) { + err = _command_handler(p->argc, p->argv); + } + + // Display command status to user + switch (err) { + case CMD_SUCCESS_QUIET: + // Don't print anything + break; + + case CMD_SUCCESS: + cmd_resp_printf("SUCCESS\r\n\n"); + break; + + case CMD_FAILURE: + cmd_resp_printf("FAILURE\r\n\n"); + break; + + case CMD_INVALID_ARGUMENTS: + cmd_resp_printf("INVALID ARGUMENTS\r\n\n"); + break; + + case CMD_INPUT_TOO_LONG: + cmd_resp_printf("INPUT TOO LONG\r\n\n"); + break; + + case CMD_UNKNOWN_CMD: + cmd_resp_printf("UNKNOWN CMD\r\n\n"); + break; + + default: + cmd_resp_printf("UNKNOWN ERROR\r\n\n"); + break; + } + + p->ready = 0; + + // Update READ index + if (++ctx->pending_cmd_read_idx >= MAX_PENDING_CMDS) { + ctx->pending_cmd_read_idx = 0; + } + } +} + +void commands_cmd_init(command_entry_t *cmd_entry, + const char *cmd, + const char *desc, + command_help_t *help, + int num_help_cmds, + int (*cmd_function)(int, char **)) +{ + cmd_entry->cmd = cmd; + cmd_entry->desc = desc; + cmd_entry->help = help; + cmd_entry->num_help_cmds = num_help_cmds; + cmd_entry->cmd_function = cmd_function; + cmd_entry->next = NULL; +} + +void commands_cmd_register(command_entry_t *cmd_entry) +{ + // Base case: there are no tasks in linked list + if (cmds == NULL) { + cmds = cmd_entry; + cmds->next = NULL; + return; + } + + // Find end of list + command_entry_t *curr = cmds; + while (curr->next != NULL) + curr = curr->next; + + // Append new cmd to end of list + curr->next = cmd_entry; + cmd_entry->next = NULL; +} + +void commands_start_msg(void) +{ + cmd_resp_printf("\r\n"); + commands_display_help(); +} + +// _command_handler +// +// Takes `argc` and `argv` and finds +// the command function to call. +// +int _command_handler(int argc, char **argv) +{ + command_entry_t *c = cmds; + + while (c != NULL) { + if (strcmp(argv[0], c->cmd) == 0) { + // Found command to run! + return c->cmd_function(argc, argv); + } + + c = c->next; + } + + return CMD_UNKNOWN_CMD; +} + +// ***************** +// State Machine +// which outputs +// the help messages +// ***************** + +typedef enum sm_states_e { TITLE1 = 1, TITLE2, TITLE3, CMD_HEADER, SUB_CMD, REMOVE_TASK } sm_states_e; + +typedef struct sm_ctx_t { + sm_states_e state; + command_entry_t *curr; + int sub_cmd_idx; + TaskHandle_t tcb; +} sm_ctx_t; + +static sm_ctx_t ctxG; + +#define SM_UPDATES_PER_SEC (10000) +#define SM_INTERVAL_TICKS (pdMS_TO_TICKS(1000.0 / SM_UPDATES_PER_SEC)) + +void help_state_machine(void *arg) +{ + sm_ctx_t *ctx = &ctxG; + for (;;) { + vTaskDelay(SM_INTERVAL_TICKS); + switch (ctx->state) { + case TITLE1: + cmd_resp_printf("\r\n"); + + ctx->curr = cmds; + ctx->state = TITLE2; + break; + + case TITLE2: + cmd_resp_printf("Available commands:\r\n"); + ctx->state = TITLE3; + break; + + case TITLE3: + cmd_resp_printf("-------------------\r\n"); + ctx->state = CMD_HEADER; + break; + + case CMD_HEADER: + if (ctx->curr == NULL) { + // DONE! + cmd_resp_printf("\r\n"); + ctx->state = REMOVE_TASK; + } else { + cmd_resp_printf("%s -- %s\r\n", ctx->curr->cmd, ctx->curr->desc); + ctx->sub_cmd_idx = 0; + ctx->state = SUB_CMD; + } + break; + + case SUB_CMD: + if (ctx->sub_cmd_idx >= ctx->curr->num_help_cmds) { + ctx->curr = ctx->curr->next; + ctx->state = CMD_HEADER; + } else { + command_help_t *h = &ctx->curr->help[ctx->sub_cmd_idx++]; + cmd_resp_printf("\t%s -- %s\r\n", h->subcmd, h->desc); + } + break; + + case REMOVE_TASK: + cmd_resp_printf("SUCCESS\r\n\n"); + vTaskDelete(ctx->tcb); + break; + + default: + // Can't happen + HANG; + break; + } + } +} + +void commands_display_help(void) +{ + // Initialize the state machine context + ctxG.state = TITLE1; + ctxG.curr = cmds; + ctxG.sub_cmd_idx = 0; + + // Initialize the state machine callback tcb (with high priority) + xTaskCreate(help_state_machine, (const char *) "command_help", configMINIMAL_STACK_SIZE, + NULL, configMAX_PRIORITIES - 1, &ctxG.tcb); +} diff --git a/sdk/shared/sys/commands.h b/sdk/shared/sys/commands.h new file mode 100644 index 00000000..65bd4852 --- /dev/null +++ b/sdk/shared/sys/commands.h @@ -0,0 +1,61 @@ +#ifndef COMMANDS_H +#define COMMANDS_H + +#define COMMANDS_UPDATES_PER_SEC (10000) +#define COMMANDS_INTERVAL_TICKS (pdMS_TO_TICKS(1000.0 / COMMANDS_UPDATES_PER_SEC)) + +// Supported command handler return codes +// +// NOTE: all commands must return a valid response to the host. +// Only use the resp: "SUCCESS_QUIET" if you will output a valid +// response later in your handler. +// +// For example, "help" and "log dump" work this way. +// +#define CMD_SUCCESS (0) +#define CMD_FAILURE (1) +#define CMD_SUCCESS_QUIET (2) +#define CMD_INVALID_ARGUMENTS (3) +#define CMD_INPUT_TOO_LONG (4) +#define CMD_UNKNOWN_CMD (5) + +// Forward declarations +typedef struct command_entry_t command_entry_t; +typedef struct command_help_t command_help_t; + +typedef struct command_entry_t { + const char *cmd; + const char *desc; + command_help_t *help; + int num_help_cmds; + int (*cmd_function)(int, char **); + + // Pointer to next cmd; set this to NULL in user code. + // When cmd is registered, this will form a linked list. + command_entry_t *next; +} command_entry_t; + +typedef struct command_help_t { + const char *subcmd; + const char *desc; +} command_help_t; + +// Use these functions to output data for a cmd response: +void cmd_resp_write(char *msg, int len); +void cmd_resp_print(char *msg); +void cmd_resp_printf(const char *format, ...); + +void commands_init(void); + +void commands_cmd_init(command_entry_t *cmd_entry, + const char *cmd, + const char *desc, + command_help_t *help, + int num_help_cmds, + int (*cmd_function)(int, char **)); +void commands_cmd_register(command_entry_t *cmd_entry); + +void commands_start_msg(void); +void commands_display_help(void); + +#endif // COMMANDS_H diff --git a/sdk/shared/sys/debug.c b/sdk/shared/sys/debug.c new file mode 100644 index 00000000..3054f8ff --- /dev/null +++ b/sdk/shared/sys/debug.c @@ -0,0 +1,24 @@ +#include "sys/debug.h" +#include "sys/serial.h" +#include +#include +#include + +#define BUFFER_LENGTH (1024) +static char buffer[BUFFER_LENGTH] = { 0 }; + +void debug_print(char *msg) +{ + serial_write(msg, strlen(msg)); +} + +void debug_printf(const char *format, ...) +{ + va_list vargs; + va_start(vargs, format); + + vsnprintf(buffer, BUFFER_LENGTH, format, vargs); + debug_print(buffer); + + va_end(vargs); +} diff --git a/sdk/shared/sys/debug.h b/sdk/shared/sys/debug.h new file mode 100644 index 00000000..85d4b235 --- /dev/null +++ b/sdk/shared/sys/debug.h @@ -0,0 +1,7 @@ +#ifndef DEBUG_H +#define DEBUG_H + +void debug_print(char *msg); +void debug_printf(const char *msg, ...); + +#endif // DEBUG_H diff --git a/sdk/shared/sys/defines.h b/sdk/shared/sys/defines.h new file mode 100644 index 00000000..36228b3e --- /dev/null +++ b/sdk/shared/sys/defines.h @@ -0,0 +1,28 @@ +#ifndef DEFINES_H +#define DEFINES_H + +#include + +#define UNUSED(x) (void) (x) + +#define HANG \ + printf("HANG!!!\n"); \ + while (1) + +#define SUCCESS (0) +#define FAILURE (1) + +#define PI (3.141592653589793238463) // pi +#define PI23 (2.094395102393195492308) // 2*pi/3 +#define PI2 (6.283185307179586476925) // 2*pi + +#define SQRT23 (0.816496580927726032732) // sqrt(2/3) +#define SQRT2 (1.414213562373095048802) // sqrt(2) +#define SQRT3 (1.732050807568877293528) // sqrt(3) + +#define DEG_TO_RAD(deg) (deg * PI / 180.0) +#define RAD_TO_DEG(rad) (rad * 180.0 / PI) +#define RPM_TO_RAD_PER_SEC(rpm) (rpm * PI2 / 60.0) +#define RAD_PER_SEC_TO_RPM(rps) (rps * 60.0 / PI2) + +#endif // DEFINES_H diff --git a/sdk/shared/sys/icc.c b/sdk/shared/sys/icc.c index 2673a593..b6b662d8 100644 --- a/sdk/shared/sys/icc.c +++ b/sdk/shared/sys/icc.c @@ -1,91 +1,91 @@ -#include "icc.h" - -/////////////////////////////////////////////////////// -// THIS IS A SHARED FILE, SO IT IS ALWAYS -// IN SYNC IN BOTH CPU0 AND CPU1 -// -// If you need to differentiate something between -// CPUs, use "#if XPAR_CPU_ID == ?" -/////////////////////////////////////////////////////// - -void icc_init(uint32_t cpu_num) -{ -#if XPAR_CPU_ID == 0 - // ONLY CPU 0 INITIALIZES THE MESSAGE BUFFERS - - /* Create two message buffers for inter-core communication that use the callback - * functions below as send and receive completed callback functions. */ - xCPU0to1MessageBuffer = xMessageBufferCreateStaticWithCallback(ICC_BUFFER_SIZE - 1, - ICC_CPU0to1_BufferSpaceAddr, - ICC_CPU0to1_BufferStructAddr, - vCPU0to1SendCallback, - vCPU0to1ReceiveCallback); - - xCPU1to0MessageBuffer = xMessageBufferCreateStaticWithCallback(ICC_BUFFER_SIZE - 1, - ICC_CPU1to0_BufferSpaceAddr, - ICC_CPU1to0_BufferStructAddr, - vCPU1to0SendCallback, - vCPU1to0ReceiveCallback); -#endif -} - -/* From FreeRTOS: - * Insert code into callback which is invoked when a message is written to the message buffer. - * This is useful when a message buffer is used to pass messages between - * cores on a multicore processor. In that scenario, this callback - * can be implemented to generate an interrupt in the other CPU core, - * and the interrupt's service routine can then use the - * xMessageBufferSendCompletedFromISR() API function to check, and if - * necessary unblock, a task that was waiting for message. */ - -/* !! IMPORTANT !! - * These callback functions must ALL exist in BOTH CPUs for the above Message Buffer creations - * to work. HOWEVER, the callbacks only have to DO SOMETHING in the relevant CPU - * For example, the behavior of the 0 to 1 Send Callback must be implemented in CPU 0, since - * CPU 0 needs to send an interrupt to CPU 1 when it sends to the buffer. But CPU 1 will never - * send to the 0 to 1 buffer, so in CPU 1 this callback doesn't need to DO ANYTHING except exist. - * - Patrick */ - -void vCPU0to1SendCallback(MessageBufferHandle_t xMessageBuffer, - BaseType_t xIsInsideISR, - BaseType_t *const pxHigherPriorityTaskWoken) -{ -#if XPAR_CPU_ID == 0 - xil_printf("DEBUG: CPU 0 to 1 Send Callback reached\r\n"); - // In CPU 0, this callback should send an interrupt to CPU 1's Rx task - XScuGic_SoftwareIntr(&InterruptController, INTC_0TO1_SEND_INTERRUPT_ID, CPU1_ID); -#endif -} - -void vCPU1to0ReceiveCallback(MessageBufferHandle_t xMessageBuffer, - BaseType_t xIsInsideISR, - BaseType_t *const pxHigherPriorityTaskWoken) -{ -#if XPAR_CPU_ID == 0 - xil_printf("DEBUG: CPU 1 to 0 Receive Callback reached\r\n"); - // In CPU 0, this callback should send an interrupt to CPU 1's Tx task - XScuGic_SoftwareIntr(&InterruptController, INTC_1TO0_RCVE_INTERRUPT_ID, CPU1_ID); -#endif -} - -void vCPU1to0SendCallback(MessageBufferHandle_t xMessageBuffer, - BaseType_t xIsInsideISR, - BaseType_t *const pxHigherPriorityTaskWoken) -{ -#if XPAR_CPU_ID == 1 - xil_printf("DEBUG: CPU 1 to 0 Send Callback reached\r\n"); - // In CPU 1, this callback should send an interrupt to CPU 0's Rx task - XScuGic_SoftwareIntr(&InterruptController, INTC_1TO0_SEND_INTERRUPT_ID, CPU0_ID); -#endif -} - -void vCPU0to1ReceiveCallback(MessageBufferHandle_t xMessageBuffer, - BaseType_t xIsInsideISR, - BaseType_t *const pxHigherPriorityTaskWoken) -{ -#if XPAR_CPU_ID == 1 - xil_printf("DEBUG: CPU 0 to 1 Receive Callback reached\r\n"); - // In CPU 1, this callback should send an interrupt to CPU 0's Tx task - XScuGic_SoftwareIntr(&InterruptController, INTC_0TO1_RCVE_INTERRUPT_ID, CPU0_ID); -#endif -} +#include "icc.h" + +/////////////////////////////////////////////////////// +// THIS IS A SHARED FILE, SO IT IS ALWAYS +// IN SYNC IN BOTH CPU0 AND CPU1 +// +// If you need to differentiate something between +// CPUs, use "#if XPAR_CPU_ID == ?" +/////////////////////////////////////////////////////// + +void icc_init(uint32_t cpu_num) +{ +#if XPAR_CPU_ID == 0 + // ONLY CPU 0 INITIALIZES THE MESSAGE BUFFERS + + /* Create two message buffers for inter-core communication that use the callback + * functions below as send and receive completed callback functions. */ + xCPU0to1MessageBuffer = xMessageBufferCreateStaticWithCallback(ICC_BUFFER_SIZE - 1, + ICC_CPU0to1_BufferSpaceAddr, + ICC_CPU0to1_BufferStructAddr, + vCPU0to1SendCallback, + vCPU0to1ReceiveCallback); + + xCPU1to0MessageBuffer = xMessageBufferCreateStaticWithCallback(ICC_BUFFER_SIZE - 1, + ICC_CPU1to0_BufferSpaceAddr, + ICC_CPU1to0_BufferStructAddr, + vCPU1to0SendCallback, + vCPU1to0ReceiveCallback); +#endif +} + +/* From FreeRTOS: + * Insert code into callback which is invoked when a message is written to the message buffer. + * This is useful when a message buffer is used to pass messages between + * cores on a multicore processor. In that scenario, this callback + * can be implemented to generate an interrupt in the other CPU core, + * and the interrupt's service routine can then use the + * xMessageBufferSendCompletedFromISR() API function to check, and if + * necessary unblock, a task that was waiting for message. */ + +/* !! IMPORTANT !! + * These callback functions must ALL exist in BOTH CPUs for the above Message Buffer creations + * to work. HOWEVER, the callbacks only have to DO SOMETHING in the relevant CPU + * For example, the behavior of the 0 to 1 Send Callback must be implemented in CPU 0, since + * CPU 0 needs to send an interrupt to CPU 1 when it sends to the buffer. But CPU 1 will never + * send to the 0 to 1 buffer, so in CPU 1 this callback doesn't need to DO ANYTHING except exist. + * - Patrick */ + +void vCPU0to1SendCallback(MessageBufferHandle_t xMessageBuffer, + BaseType_t xIsInsideISR, + BaseType_t *const pxHigherPriorityTaskWoken) +{ +#if XPAR_CPU_ID == 0 + xil_printf("DEBUG: CPU 0 to 1 Send Callback reached\r\n"); + // In CPU 0, this callback should send an interrupt to CPU 1's Rx task + XScuGic_SoftwareIntr(&InterruptController, INTC_0TO1_SEND_INTERRUPT_ID, CPU1_ID); +#endif +} + +void vCPU1to0ReceiveCallback(MessageBufferHandle_t xMessageBuffer, + BaseType_t xIsInsideISR, + BaseType_t *const pxHigherPriorityTaskWoken) +{ +#if XPAR_CPU_ID == 0 + xil_printf("DEBUG: CPU 1 to 0 Receive Callback reached\r\n"); + // In CPU 0, this callback should send an interrupt to CPU 1's Tx task + XScuGic_SoftwareIntr(&InterruptController, INTC_1TO0_RCVE_INTERRUPT_ID, CPU1_ID); +#endif +} + +void vCPU1to0SendCallback(MessageBufferHandle_t xMessageBuffer, + BaseType_t xIsInsideISR, + BaseType_t *const pxHigherPriorityTaskWoken) +{ +#if XPAR_CPU_ID == 1 + xil_printf("DEBUG: CPU 1 to 0 Send Callback reached\r\n"); + // In CPU 1, this callback should send an interrupt to CPU 0's Rx task + XScuGic_SoftwareIntr(&InterruptController, INTC_1TO0_SEND_INTERRUPT_ID, CPU0_ID); +#endif +} + +void vCPU0to1ReceiveCallback(MessageBufferHandle_t xMessageBuffer, + BaseType_t xIsInsideISR, + BaseType_t *const pxHigherPriorityTaskWoken) +{ +#if XPAR_CPU_ID == 1 + xil_printf("DEBUG: CPU 0 to 1 Receive Callback reached\r\n"); + // In CPU 1, this callback should send an interrupt to CPU 0's Tx task + XScuGic_SoftwareIntr(&InterruptController, INTC_0TO1_RCVE_INTERRUPT_ID, CPU0_ID); +#endif +} diff --git a/sdk/shared/sys/icc.h b/sdk/shared/sys/icc.h index c8d82879..2d88a445 100644 --- a/sdk/shared/sys/icc.h +++ b/sdk/shared/sys/icc.h @@ -1,89 +1,168 @@ -#ifndef ICC_H -#define ICC_H - -#include "FreeRTOS.h" -#include "intr.h" -#include "message_buffer.h" -#include "xil_printf.h" -#include - -/////////////////////////////////////////////////////// -// THIS IS A SHARED FILE, SO IT IS ALWAYS -// IN SYNC IN BOTH CPU0 AND CPU1 -// -// If you need to differentiate something between -// CPUs, use "#if XPAR_CPU_ID == ?" -/////////////////////////////////////////////////////// - -// ======================== -// Inter-Core Communication -// ======================== -// -// This module implements communication between the two cores, CPU0 and CPU1. -// CPU0 acts as the master and initializes all shared memory spaces. -// -// In the OCM, we implement two FreeRTOS Message Buffers: one from CPU0 to CPU1, -// and one from CPU1 to CPU0. Each FIFO and associated data are used to build a -// simple producer-consumer system. -// -// This implementation is known to be thread (dual-core) safe. -// -// For more details and pseudo code, see these resources: -// https://www.freertos.org/RTOS-message-buffer-API.html -// https://www.freertos.org/2020/02/simple-multicore-core-to-core-communication-using-freertos-message-buffers.html - -// Per Zynq-7000 TRM Ch. 4: System Addresses (page 106), the initial mapping -// of OCM is split between low addresses and high addresses in 64 KB chunks. -// -// We will pick to use the highest 64 KB chunk as our base address: -#define OCM_BASE_ADDR (0xFFFF0000) -#define ICC_BUFFER_STRUCT_SIZE (sizeof(StaticMessageBuffer_t)) -#define ICC_BUFFER_SIZE (4 * 1024) -#define ICC_HANDLE_SIZE (sizeof(MessageBufferHandle_t)) - - -/* Define the pointers to the two structs (that store the metadata) and two message spaces (that hold the messages) in shared memory. - * The ICC_BUFFER_SIZE Should be one more than the value passed in the xBufferSizeBytes parameter. - * The two structs will be located back-to-back right at the base addr of the shared OCM, followed thereafter by the actual message buffers. */ -#define ICC_CPU0to1_BufferStructAddr ((uint8_t *) (OCM_BASE_ADDR + (0 * ICC_BUFFER_STRUCT_SIZE))) -#define ICC_CPU1to0_BufferStructAddr ((uint8_t *) (OCM_BASE_ADDR + (1 * ICC_BUFFER_STRUCT_SIZE))) - -#define ICC_CPU0to1_BufferSpaceAddr ((uint8_t *) (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (0 * ICC_BUFFER_SIZE))) -#define ICC_CPU1to0_BufferSpaceAddr ((uint8_t *) (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (1 * ICC_BUFFER_SIZE))) - - -/* These memory spaces are used to transfer the Message Buffer Handles from CPU0 (who does the initialization work, and gets the handles - * from the xMessageBufferCreateStaticWithCallback function) to CPU1 (who doesn't initialize anything and gets the handles from CPU0, via - * these drop-zones) */ -#define ICC_CPU0to1_HandleDropzoneAddr (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (2 * ICC_BUFFER_SIZE) + (0 * ICC_HANDLE_SIZE))) -#define ICC_CPU1to0_HandleDropzoneAddr (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (2 * ICC_BUFFER_SIZE) + (1 * ICC_HANDLE_SIZE))) - -#define ICC_getCPU0to1Handle (*((MessageBufferHandle_t *) ICC_CPU0to1_HandleDropzoneAddr)) -#define ICC_setCPU0to1Handle(handle) (*((MessageBufferHandle_t *) ICC_CPU0to1_HandleDropzoneAddr) = handle) -#define ICC_getCPU1to0Handle (*((MessageBufferHandle_t *) ICC_CPU1to0_HandleDropzoneAddr)) -#define ICC_setCPU1to0Handle(handle) (*((MessageBufferHandle_t *) ICC_CPU1to0_HandleDropzoneAddr) = handle) - - - -/* These are the handles for the Message Buffers that need to be used by other tasks - * In reality, the handle is just the pointer to the message buffer struct (its memory address) - * These should end up being the addresses computed above */ -MessageBufferHandle_t xCPU0to1MessageBuffer; -MessageBufferHandle_t xCPU1to0MessageBuffer; - - -void icc_init(); -void vCPU0to1SendCallback(MessageBufferHandle_t xMessageBuffer, - BaseType_t xIsInsideISR, - BaseType_t *const pxHigherPriorityTaskWoken); -void vCPU0to1ReceiveCallback(MessageBufferHandle_t xMessageBuffer, - BaseType_t xIsInsideISR, - BaseType_t *const pxHigherPriorityTaskWoken); -void vCPU1to0SendCallback(MessageBufferHandle_t xMessageBuffer, - BaseType_t xIsInsideISR, - BaseType_t *const pxHigherPriorityTaskWoken); -void vCPU1to0ReceiveCallback(MessageBufferHandle_t xMessageBuffer, - BaseType_t xIsInsideISR, - BaseType_t *const pxHigherPriorityTaskWoken); - -#endif /* ICC_H */ +#ifndef ICC_H +#define ICC_H + +#include "FreeRTOS.h" +#include "intr.h" +#include "message_buffer.h" +#include "xil_printf.h" +#include + +/////////////////////////////////////////////////////// +// THIS IS A SHARED FILE, SO IT IS ALWAYS +// IN SYNC IN BOTH CPU0 AND CPU1 +// +// If you need to differentiate something between +// CPUs, use "#if XPAR_CPU_ID == ?" +/////////////////////////////////////////////////////// + +// ======================== +// Inter-Core Communication +// ======================== +// +// This module implements communication between the two cores, CPU0 and CPU1. +// CPU0 acts as the master and initializes all shared memory spaces. +// +// In the OCM, we implement two FreeRTOS Message Buffers: one from CPU0 to CPU1, +// and one from CPU1 to CPU0. Each FIFO and associated data are used to build a +// simple producer-consumer system. +// +// This implementation is known to be thread (dual-core) safe. +// +// For more details and pseudo code, see these resources: +// https://www.freertos.org/RTOS-message-buffer-API.html +// https://www.freertos.org/2020/02/simple-multicore-core-to-core-communication-using-freertos-message-buffers.html + +// Per Zynq-7000 TRM Ch. 4: System Addresses (page 106), the initial mapping +// of OCM is split between low addresses and high addresses in 64 KB chunks. +// +// We will pick to use the highest 64 KB chunk as our base address: +#define OCM_BASE_ADDR (0xFFFF0000) +#define ICC_BUFFER_STRUCT_SIZE (sizeof(StaticMessageBuffer_t)) +#define ICC_BUFFER_SIZE (4 * 1024) +#define ICC_HANDLE_SIZE (sizeof(MessageBufferHandle_t)) + + +/* Define the pointers to the two structs (that store the metadata) and two message spaces (that hold the messages) in shared memory. + * The ICC_BUFFER_SIZE Should be one more than the value passed in the xBufferSizeBytes parameter. + * The two structs will be located back-to-back right at the base addr of the shared OCM, followed thereafter by the actual message buffers. */ +#define ICC_CPU0to1_BufferStructAddr ((uint8_t *) (OCM_BASE_ADDR + (0 * ICC_BUFFER_STRUCT_SIZE))) +#define ICC_CPU1to0_BufferStructAddr ((uint8_t *) (OCM_BASE_ADDR + (1 * ICC_BUFFER_STRUCT_SIZE))) + +#define ICC_CPU0to1_BufferSpaceAddr ((uint8_t *) (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (0 * ICC_BUFFER_SIZE))) +#define ICC_CPU1to0_BufferSpaceAddr ((uint8_t *) (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (1 * ICC_BUFFER_SIZE))) + +// =============================== +// CH0: the ascii_cmd socket +// =============================== + +#define ICC_CPU0to1_CH0__BufferBaseAddr ((uint8_t *) (OCM_BASE_ADDR + 1024 + (0 * ICC_BUFFER_SIZE))) +#define ICC_CPU1to0_CH0__BufferBaseAddr ((uint8_t *) (OCM_BASE_ADDR + 1024 + (1 * ICC_BUFFER_SIZE))) + +#define ICC_CPU0to1_CH0__GET_ProduceCount (*((uint32_t *) (OCM_BASE_ADDR + 0))) +#define ICC_CPU0to1_CH0__SET_ProduceCount(x) (*((uint32_t *) (OCM_BASE_ADDR + 0)) = x) +#define ICC_CPU0to1_CH0__GET_ConsumeCount (*((uint32_t *) (OCM_BASE_ADDR + 4))) +#define ICC_CPU0to1_CH0__SET_ConsumeCount(x) (*((uint32_t *) (OCM_BASE_ADDR + 4)) = x) + +#define ICC_CPU1to0_CH0__GET_ProduceCount (*((uint32_t *) (OCM_BASE_ADDR + 8))) +#define ICC_CPU1to0_CH0__SET_ProduceCount(x) (*((uint32_t *) (OCM_BASE_ADDR + 8)) = x) +#define ICC_CPU1to0_CH0__GET_ConsumeCount (*((uint32_t *) (OCM_BASE_ADDR + 12))) +#define ICC_CPU1to0_CH0__SET_ConsumeCount(x) (*((uint32_t *) (OCM_BASE_ADDR + 12)) = x) + +#define ICC_CPU1to0_CH0__IsBufferFull \ + (ICC_CPU1to0_CH0__GET_ProduceCount - ICC_CPU1to0_CH0__GET_ConsumeCount == ICC_BUFFER_SIZE) +#define ICC_CPU1to0_CH0__IsBufferEmpty (ICC_CPU1to0_CH0__GET_ProduceCount - ICC_CPU1to0_CH0__GET_ConsumeCount == 0) + +#define ICC_CPU0to1_CH0__IsBufferFull \ + (ICC_CPU0to1_CH0__GET_ProduceCount - ICC_CPU0to1_CH0__GET_ConsumeCount == ICC_BUFFER_SIZE) +#define ICC_CPU0to1_CH0__IsBufferEmpty (ICC_CPU0to1_CH0__GET_ProduceCount - ICC_CPU0to1_CH0__GET_ConsumeCount == 0) + +// ==================== +// FIFOs for log variable streaming +// Data only flows from CPU1 to CPU0 for logging +// +// CH1 to 4 are for log streams +// ==================== + +#define ICC_CPU1to0_CH1__BufferBaseAddr ((uint8_t *) (OCM_BASE_ADDR + 1024 + (2 * ICC_BUFFER_SIZE))) +#define ICC_CPU1to0_CH2__BufferBaseAddr ((uint8_t *) (OCM_BASE_ADDR + 1024 + (3 * ICC_BUFFER_SIZE))) +#define ICC_CPU1to0_CH3__BufferBaseAddr ((uint8_t *) (OCM_BASE_ADDR + 1024 + (4 * ICC_BUFFER_SIZE))) +#define ICC_CPU1to0_CH4__BufferBaseAddr ((uint8_t *) (OCM_BASE_ADDR + 1024 + (5 * ICC_BUFFER_SIZE))) + +#define ICC_CPU1to0_CH1__GET_ProduceCount (*((uint32_t *) (OCM_BASE_ADDR + 16))) +#define ICC_CPU1to0_CH1__SET_ProduceCount(x) (*((uint32_t *) (OCM_BASE_ADDR + 16)) = x) +#define ICC_CPU1to0_CH1__GET_ConsumeCount (*((uint32_t *) (OCM_BASE_ADDR + 20))) +#define ICC_CPU1to0_CH1__SET_ConsumeCount(x) (*((uint32_t *) (OCM_BASE_ADDR + 20)) = x) + +#define ICC_CPU1to0_CH2__GET_ProduceCount (*((uint32_t *) (OCM_BASE_ADDR + 24))) +#define ICC_CPU1to0_CH2__SET_ProduceCount(x) (*((uint32_t *) (OCM_BASE_ADDR + 24)) = x) +#define ICC_CPU1to0_CH2__GET_ConsumeCount (*((uint32_t *) (OCM_BASE_ADDR + 28))) +#define ICC_CPU1to0_CH2__SET_ConsumeCount(x) (*((uint32_t *) (OCM_BASE_ADDR + 28)) = x) + +#define ICC_CPU1to0_CH3__GET_ProduceCount (*((uint32_t *) (OCM_BASE_ADDR + 32))) +#define ICC_CPU1to0_CH3__SET_ProduceCount(x) (*((uint32_t *) (OCM_BASE_ADDR + 32)) = x) +#define ICC_CPU1to0_CH3__GET_ConsumeCount (*((uint32_t *) (OCM_BASE_ADDR + 36))) +#define ICC_CPU1to0_CH3__SET_ConsumeCount(x) (*((uint32_t *) (OCM_BASE_ADDR + 36)) = x) + +#define ICC_CPU1to0_CH4__GET_ProduceCount (*((uint32_t *) (OCM_BASE_ADDR + 40))) +#define ICC_CPU1to0_CH4__SET_ProduceCount(x) (*((uint32_t *) (OCM_BASE_ADDR + 40)) = x) +#define ICC_CPU1to0_CH4__GET_ConsumeCount (*((uint32_t *) (OCM_BASE_ADDR + 44))) +#define ICC_CPU1to0_CH4__SET_ConsumeCount(x) (*((uint32_t *) (OCM_BASE_ADDR + 44)) = x) + +#define ICC_CPU1to0_CH1__IsBufferFull \ + (ICC_CPU1to0_CH1__GET_ProduceCount - ICC_CPU1to0_CH1__GET_ConsumeCount == ICC_BUFFER_SIZE) +#define ICC_CPU1to0_CH1__IsBufferEmpty (ICC_CPU1to0_CH1__GET_ProduceCount - ICC_CPU1to0_CH1__GET_ConsumeCount == 0) +#define ICC_CPU1to0_CH2__IsBufferFull \ + (ICC_CPU1to0_CH2__GET_ProduceCount - ICC_CPU1to0_CH2__GET_ConsumeCount == ICC_BUFFER_SIZE) +#define ICC_CPU1to0_CH2__IsBufferEmpty (ICC_CPU1to0_CH2__GET_ProduceCount - ICC_CPU1to0_CH2__GET_ConsumeCount == 0) +#define ICC_CPU1to0_CH3__IsBufferFull \ + (ICC_CPU1to0_CH3__GET_ProduceCount - ICC_CPU1to0_CH3__GET_ConsumeCount == ICC_BUFFER_SIZE) +#define ICC_CPU1to0_CH3__IsBufferEmpty (ICC_CPU1to0_CH3__GET_ProduceCount - ICC_CPU1to0_CH3__GET_ConsumeCount == 0) +#define ICC_CPU1to0_CH4__IsBufferFull \ + (ICC_CPU1to0_CH4__GET_ProduceCount - ICC_CPU1to0_CH4__GET_ConsumeCount == ICC_BUFFER_SIZE) +#define ICC_CPU1to0_CH4__IsBufferEmpty (ICC_CPU1to0_CH4__GET_ProduceCount - ICC_CPU1to0_CH4__GET_ConsumeCount == 0) + +#define ICC_CPU1to0_CH1__INC_ProduceCount (ICC_CPU1to0_CH1__SET_ProduceCount(ICC_CPU1to0_CH1__GET_ProduceCount + 1)) +#define ICC_CPU1to0_CH2__INC_ProduceCount (ICC_CPU1to0_CH2__SET_ProduceCount(ICC_CPU1to0_CH2__GET_ProduceCount + 1)) +#define ICC_CPU1to0_CH3__INC_ProduceCount (ICC_CPU1to0_CH3__SET_ProduceCount(ICC_CPU1to0_CH3__GET_ProduceCount + 1)) +#define ICC_CPU1to0_CH4__INC_ProduceCount (ICC_CPU1to0_CH4__SET_ProduceCount(ICC_CPU1to0_CH4__GET_ProduceCount + 1)) + +#define ICC_CPU1to0_CH1__INC_ConsumeCount (ICC_CPU1to0_CH1__SET_ConsumeCount(ICC_CPU1to0_CH1__GET_ConsumeCount + 1)) +#define ICC_CPU1to0_CH2__INC_ConsumeCount (ICC_CPU1to0_CH2__SET_ConsumeCount(ICC_CPU1to0_CH2__GET_ConsumeCount + 1)) +#define ICC_CPU1to0_CH3__INC_ConsumeCount (ICC_CPU1to0_CH3__SET_ConsumeCount(ICC_CPU1to0_CH3__GET_ConsumeCount + 1)) +#define ICC_CPU1to0_CH4__INC_ConsumeCount (ICC_CPU1to0_CH4__SET_ConsumeCount(ICC_CPU1to0_CH4__GET_ConsumeCount + 1)) + +/* These memory spaces are used to transfer the Message Buffer Handles from CPU0 (who does the initialization work, and gets the handles + * from the xMessageBufferCreateStaticWithCallback function) to CPU1 (who doesn't initialize anything and gets the handles from CPU0, via + * these drop-zones) */ +#define ICC_CPU0to1_HandleDropzoneAddr (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (2 * ICC_BUFFER_SIZE) + (0 * ICC_HANDLE_SIZE))) +#define ICC_CPU1to0_HandleDropzoneAddr (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (2 * ICC_BUFFER_SIZE) + (1 * ICC_HANDLE_SIZE))) + +#define ICC_getCPU0to1Handle (*((MessageBufferHandle_t *) ICC_CPU0to1_HandleDropzoneAddr)) +#define ICC_setCPU0to1Handle(handle) (*((MessageBufferHandle_t *) ICC_CPU0to1_HandleDropzoneAddr) = handle) +#define ICC_getCPU1to0Handle (*((MessageBufferHandle_t *) ICC_CPU1to0_HandleDropzoneAddr)) +#define ICC_setCPU1to0Handle(handle) (*((MessageBufferHandle_t *) ICC_CPU1to0_HandleDropzoneAddr) = handle) + + + +/* These are the handles for the Message Buffers that need to be used by other tasks + * In reality, the handle is just the pointer to the message buffer struct (its memory address) + * These should end up being the addresses computed above */ +MessageBufferHandle_t xCPU0to1MessageBuffer; +MessageBufferHandle_t xCPU1to0MessageBuffer; + + +void icc_init(); +void vCPU0to1SendCallback(MessageBufferHandle_t xMessageBuffer, + BaseType_t xIsInsideISR, + BaseType_t *const pxHigherPriorityTaskWoken); +void vCPU0to1ReceiveCallback(MessageBufferHandle_t xMessageBuffer, + BaseType_t xIsInsideISR, + BaseType_t *const pxHigherPriorityTaskWoken); +void vCPU1to0SendCallback(MessageBufferHandle_t xMessageBuffer, + BaseType_t xIsInsideISR, + BaseType_t *const pxHigherPriorityTaskWoken); +void vCPU1to0ReceiveCallback(MessageBufferHandle_t xMessageBuffer, + BaseType_t xIsInsideISR, + BaseType_t *const pxHigherPriorityTaskWoken); + +#endif /* ICC_H */ diff --git a/sdk/shared/sys/icc_tx.c b/sdk/shared/sys/icc_tx.c new file mode 100644 index 00000000..8ce170e6 --- /dev/null +++ b/sdk/shared/sys/icc_tx.c @@ -0,0 +1,225 @@ +/* FreeRTOS includes */ +#include "FreeRTOS.h" +#include "task.h" +/* other includes */ +#include "sys/icc_tx.h" +#include "sys/icc.h" +#include "xil_io.h" +#include + +#define TASK_ICC_TX_UPDATES_PER_SEC (10000) +#define TASK_ICC_TX_INTERVAL_TICKS (pdMS_TO_TICKS(1000.0 / TASK_ICC_TX_UPDATES_PER_SEC)) + +// Scheduler TCB which holds task "context" +static TaskHandle_t tcb; +static uint8_t taskExists = 0; // extra data to ensure tasks don't get duplicated or double free'd + +#define BUFFER_LENGTH (10 * 1024) +static uint8_t send_buffer[BUFFER_LENGTH] = { 0 }; +static uint32_t idx_writing = 0; +static uint32_t idx_reading = 0; +static uint32_t num_in_buffer = 0; + +static inline char _pop(void) +{ + char ret = send_buffer[idx_reading]; + if (++idx_reading >= BUFFER_LENGTH) { + idx_reading = 0; + } + + num_in_buffer -= 1; + + return ret; +} + +int task_icc_tx_get_buffer_space_available(void) +{ + return BUFFER_LENGTH - num_in_buffer; +} + +static inline void _push(char c) +{ + send_buffer[idx_writing] = c; + if (++idx_writing >= BUFFER_LENGTH) { + idx_writing = 0; + } + + num_in_buffer += 1; +} + +static void task_icc_tx(void *arg) +{ + // Try to give all our ringbuf TCP/IP data to CPU0 + // + // Bounded up to MAX_NUM_BYTES_TO_TRY bytes + // + // If we ever find that the ICC shared FIFO gets full, + // we'll just stop and wait until next time. + + static const int MAX_NUM_BYTES_TO_TRY = 256; + + int num_sent = 0; + + while (num_in_buffer > 0) { + if (ICC_CPU1to0_CH0__GET_ProduceCount - ICC_CPU1to0_CH0__GET_ConsumeCount == ICC_BUFFER_SIZE) { + // Shared buffer is full + // Return and try again in the next time slice + return; + } + + // Write one byte to the sharedBuffer BEFORE incrementing produceCount + uint8_t *sharedBuffer = ICC_CPU1to0_CH0__BufferBaseAddr; + char c = _pop(); + sharedBuffer[ICC_CPU1to0_CH0__GET_ProduceCount % ICC_BUFFER_SIZE] = c; + + // Memory barrier required here to ensure update of the sharedBuffer is + // visible to the other core before the update of produceCount + // + // Nathan thinks we don't actually have to do this since we turned off + // caching on the OCM, so the write should flush immediately, but, + // I might be wrong and it could be stuck in some pipeline... + // Just to be safe, we'll insert a DMB instruction. + dmb(); + + // Increment produce count + ICC_CPU1to0_CH0__SET_ProduceCount(ICC_CPU1to0_CH0__GET_ProduceCount + 1); + + num_sent++; + if (num_sent > MAX_NUM_BYTES_TO_TRY) { + // We sent enough during this time slice! + // Stop now. + return; + } + } +} + +void icc_tx_init(void) +{ + if (taskExists) { + return; + } + // Fill TCB with parameters + xTaskCreate(task_icc_tx, (const char *) "icc_tx", configMINIMAL_STACK_SIZE, + NULL, tskIDLE_PRIORITY, &tcb); + taskExists = 1; +} + +void icc_tx_append_char_to_fifo(char c) +{ + _push(c); +} + +void icc_tx_log_stream(int socket_id, int var_slot, uint32_t ts, uint32_t data) +{ + // Create packet of data to send to host + // + // Packet format: HEADER, VAR_SLOT, TS, DATA, FOOTER + // where each entry is 32 bits + // + // Total packet length: 5*4 = 20 bytes + // + // HEADER = 0x11111111 + // FOOTER = 0x22222222 + + static const int packet_len = 20; + uint8_t bytes_to_send[20] = { 0 }; + + uint32_t *ptr_header = (uint32_t *) &bytes_to_send[0]; + uint32_t *ptr_var_slot = (uint32_t *) &bytes_to_send[4]; + uint32_t *ptr_ts = (uint32_t *) &bytes_to_send[8]; + uint32_t *ptr_data = (uint32_t *) &bytes_to_send[12]; + uint32_t *ptr_footer = (uint32_t *) &bytes_to_send[16]; + + *ptr_header = 0x11111111; + *ptr_var_slot = var_slot; + *ptr_ts = ts; + *ptr_data = data; + *ptr_footer = 0x22222222; + + for (int i = 0; i < packet_len; i++) { + uint8_t d = bytes_to_send[i]; + + int buffer_full = 0; + switch (socket_id) { + case 1: + buffer_full = ICC_CPU1to0_CH1__IsBufferFull; + break; + case 2: + buffer_full = ICC_CPU1to0_CH2__IsBufferFull; + break; + case 3: + buffer_full = ICC_CPU1to0_CH3__IsBufferFull; + break; + case 4: + buffer_full = ICC_CPU1to0_CH4__IsBufferFull; + break; + default: + // Invalid socket + // Return from function and fail silently + return; + } + + if (buffer_full) { + // Shared buffer is full + + // This is a silent error and will cause dropped data! + // For testing, print Q to UART terminal... + xil_printf("Q"); + return; + } + + // Write one byte to the sharedBuffer BEFORE incrementing produceCount + uint8_t *sharedBuffer; + switch (socket_id) { + case 1: + sharedBuffer = ICC_CPU1to0_CH1__BufferBaseAddr; + sharedBuffer[ICC_CPU1to0_CH1__GET_ProduceCount % ICC_BUFFER_SIZE] = d; + break; + case 2: + sharedBuffer = ICC_CPU1to0_CH2__BufferBaseAddr; + sharedBuffer[ICC_CPU1to0_CH2__GET_ProduceCount % ICC_BUFFER_SIZE] = d; + break; + case 3: + sharedBuffer = ICC_CPU1to0_CH3__BufferBaseAddr; + sharedBuffer[ICC_CPU1to0_CH3__GET_ProduceCount % ICC_BUFFER_SIZE] = d; + break; + case 4: + sharedBuffer = ICC_CPU1to0_CH4__BufferBaseAddr; + sharedBuffer[ICC_CPU1to0_CH4__GET_ProduceCount % ICC_BUFFER_SIZE] = d; + break; + default: + // Not a valid socket... + // Just silently ignore for now + break; + } + + // Memory barrier required here to ensure update of the sharedBuffer is + // visible to the other core before the update of produceCount + // + // Nathan thinks we don't actually have to do this since we turned off + // caching on the OCM, so the write should flush immediately, but, + // I might be wrong and it could be stuck in some pipeline... + // Just to be safe, we'll insert a DMB instruction. + dmb(); + + // Increment produce count + switch (socket_id) { + case 1: + ICC_CPU1to0_CH1__INC_ProduceCount; + break; + case 2: + ICC_CPU1to0_CH2__INC_ProduceCount; + break; + case 3: + ICC_CPU1to0_CH3__INC_ProduceCount; + break; + case 4: + ICC_CPU1to0_CH4__INC_ProduceCount; + break; + default: + // Not a valid socket... + // Just silently ignore for now + break; + } + } +} diff --git a/sdk/shared/sys/icc_tx.h b/sdk/shared/sys/icc_tx.h new file mode 100644 index 00000000..10060173 --- /dev/null +++ b/sdk/shared/sys/icc_tx.h @@ -0,0 +1,13 @@ +#ifndef ICC_TX_H +#define ICC_TX_H + +#include + +void icc_tx_init(void); + +void icc_tx_append_char_to_fifo(char c); +int task_icc_tx_get_buffer_space_available(void); + +void icc_tx_log_stream(int socket_id, int var_slot, uint32_t ts, uint32_t data); + +#endif // ICC_TX_H diff --git a/sdk/shared/sys/intr.c b/sdk/shared/sys/intr.c index 253dcbbc..990b647d 100644 --- a/sdk/shared/sys/intr.c +++ b/sdk/shared/sys/intr.c @@ -1,114 +1,114 @@ -#include "intr.h" - -/////////////////////////////////////////////////////// -// THIS IS A SHARED FILE, SO IT IS ALWAYS -// IN SYNC IN BOTH CPU0 AND CPU1 -// -// If you need to differentiate something between -// CPUs, use "#if XPAR_CPU_ID == ?" -/////////////////////////////////////////////////////// - -/* The functions in this file are responsible for setting up the - * Xilinx Generic Interrupt Controller (GIC). - * - * Interrupts are needed for Inter-Core Communication, specifically - * the ability to trigger an interrupt in the receiving CPU after a - * message is placed into an empty ICC Message Buffer, - * OR - * the ability to trigger an interrupt in the sending CPU after a - * message is removed from a full ICC Message Buffer - * - * See sys/icc.c for more info. - */ - -int intr_init() -{ - int Status = XST_FAILURE; - - XScuGic_Config *IntcConfig; - - IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); - XScuGic_CfgInitialize(&InterruptController, IntcConfig, IntcConfig->CpuBaseAddress); - - /* - * Perform a self-test to ensure that the hardware was built - * correctly - */ - Status = XScuGic_SelfTest(&InterruptController); - if (Status != XST_SUCCESS) { - return XST_FAILURE; - } - - // Initialize the interrupt controller - Xil_ExceptionRegisterHandler( - XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, &InterruptController); - Xil_ExceptionEnable(); - -#if XPAR_CPU_ID == 0 - // Connect the given interrupt with its handler - XScuGic_Connect(&InterruptController, INTC_1TO0_SEND_INTERRUPT_ID, (Xil_ExceptionHandler) CPU0WakeRxHandler, NULL); - XScuGic_Connect(&InterruptController, INTC_0TO1_RCVE_INTERRUPT_ID, (Xil_ExceptionHandler) CPU0WakeTxHandler, NULL); - -#elif XPAR_CPU_ID == 1 - // Connect the given interrupt with its handler - XScuGic_Connect(&InterruptController, INTC_0TO1_SEND_INTERRUPT_ID, (Xil_ExceptionHandler) CPU1WakeRxHandler, NULL); - XScuGic_Connect(&InterruptController, INTC_1TO0_RCVE_INTERRUPT_ID, (Xil_ExceptionHandler) CPU1WakeTxHandler, NULL); -#endif - - /* - // Enable the interrupt for the second CPU core - XScuGic_SetPriorityTriggerType(&InterruptController, INTC_INTERRUPT_ID, 0xA0, 3); // Set priority and trigger type - XScuGic_Enable(&InterruptController, INTC_INTERRUPT_ID); - - // Enable the interrupt for CPU1 - Xil_Out32(XPAR_PS7_SCUGIC_DIST_BASEADDR + XSCUGIC_CPU_PRIOR_OFFSET + (CPU1_ID * 4), 0xFF); - Xil_Out32(XPAR_PS7_SCUGIC_DIST_BASEADDR + XSCUGIC_CPU_TARGET_OFFSET + (CPU1_ID * 4), 0x1); - - // Enable interrupts globally - Xil_ExceptionEnableMask(XIL_EXCEPTION_NON_CRITICAL); - - print("Interrupt system setup complete.\r\n"); - */ - - return XST_SUCCESS; -} - -/* We only need to define the handlers in the appropriate core - */ -#if XPAR_CPU_ID == 0 -void CPU0WakeTxHandler() -{ - xil_printf("CPU 0 - WakeTxHandler reached\r\n"); - - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - xMessageBufferReceiveCompletedFromISR(xCPU0to1MessageBuffer, &xHigherPriorityTaskWoken); - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); -} - -void CPU0WakeRxHandler() -{ - xil_printf("CPU 0 - WakeRxHandler reached\r\n"); - - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - xMessageBufferSendCompletedFromISR(xCPU1to0MessageBuffer, &xHigherPriorityTaskWoken); - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); -} -#elif XPAR_CPU_ID == 1 -void CPU1WakeTxHandler() -{ - xil_printf("CPU 1 - WakeTxHandler reached\r\n"); - - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - xMessageBufferReceiveCompletedFromISR(xCPU1to0MessageBuffer, &xHigherPriorityTaskWoken); - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); -} - -void CPU1WakeRxHandler() -{ - xil_printf("CPU 1 - WakeRxHandler reached\r\n"); - - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - xMessageBufferSendCompletedFromISR(xCPU0to1MessageBuffer, &xHigherPriorityTaskWoken); - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); -} -#endif +#include "intr.h" + +/////////////////////////////////////////////////////// +// THIS IS A SHARED FILE, SO IT IS ALWAYS +// IN SYNC IN BOTH CPU0 AND CPU1 +// +// If you need to differentiate something between +// CPUs, use "#if XPAR_CPU_ID == ?" +/////////////////////////////////////////////////////// + +/* The functions in this file are responsible for setting up the + * Xilinx Generic Interrupt Controller (GIC). + * + * Interrupts are needed for Inter-Core Communication, specifically + * the ability to trigger an interrupt in the receiving CPU after a + * message is placed into an empty ICC Message Buffer, + * OR + * the ability to trigger an interrupt in the sending CPU after a + * message is removed from a full ICC Message Buffer + * + * See sys/icc.c for more info. + */ + +int intr_init() +{ + int Status = XST_FAILURE; + + XScuGic_Config *IntcConfig; + + IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); + XScuGic_CfgInitialize(&InterruptController, IntcConfig, IntcConfig->CpuBaseAddress); + + /* + * Perform a self-test to ensure that the hardware was built + * correctly + */ + Status = XScuGic_SelfTest(&InterruptController); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + // Initialize the interrupt controller + Xil_ExceptionRegisterHandler( + XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, &InterruptController); + Xil_ExceptionEnable(); + +#if XPAR_CPU_ID == 0 + // Connect the given interrupt with its handler + XScuGic_Connect(&InterruptController, INTC_1TO0_SEND_INTERRUPT_ID, (Xil_ExceptionHandler) CPU0WakeRxHandler, NULL); + XScuGic_Connect(&InterruptController, INTC_0TO1_RCVE_INTERRUPT_ID, (Xil_ExceptionHandler) CPU0WakeTxHandler, NULL); + +#elif XPAR_CPU_ID == 1 + // Connect the given interrupt with its handler + XScuGic_Connect(&InterruptController, INTC_0TO1_SEND_INTERRUPT_ID, (Xil_ExceptionHandler) CPU1WakeRxHandler, NULL); + XScuGic_Connect(&InterruptController, INTC_1TO0_RCVE_INTERRUPT_ID, (Xil_ExceptionHandler) CPU1WakeTxHandler, NULL); +#endif + + /* + // Enable the interrupt for the second CPU core + XScuGic_SetPriorityTriggerType(&InterruptController, INTC_INTERRUPT_ID, 0xA0, 3); // Set priority and trigger type + XScuGic_Enable(&InterruptController, INTC_INTERRUPT_ID); + + // Enable the interrupt for CPU1 + Xil_Out32(XPAR_PS7_SCUGIC_DIST_BASEADDR + XSCUGIC_CPU_PRIOR_OFFSET + (CPU1_ID * 4), 0xFF); + Xil_Out32(XPAR_PS7_SCUGIC_DIST_BASEADDR + XSCUGIC_CPU_TARGET_OFFSET + (CPU1_ID * 4), 0x1); + + // Enable interrupts globally + Xil_ExceptionEnableMask(XIL_EXCEPTION_NON_CRITICAL); + + print("Interrupt system setup complete.\r\n"); + */ + + return XST_SUCCESS; +} + +/* We only need to define the handlers in the appropriate core + */ +#if XPAR_CPU_ID == 0 +void CPU0WakeTxHandler() +{ + xil_printf("CPU 0 - WakeTxHandler reached\r\n"); + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xMessageBufferReceiveCompletedFromISR(xCPU0to1MessageBuffer, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} + +void CPU0WakeRxHandler() +{ + xil_printf("CPU 0 - WakeRxHandler reached\r\n"); + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xMessageBufferSendCompletedFromISR(xCPU1to0MessageBuffer, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} +#elif XPAR_CPU_ID == 1 +void CPU1WakeTxHandler() +{ + xil_printf("CPU 1 - WakeTxHandler reached\r\n"); + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xMessageBufferReceiveCompletedFromISR(xCPU1to0MessageBuffer, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} + +void CPU1WakeRxHandler() +{ + xil_printf("CPU 1 - WakeRxHandler reached\r\n"); + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xMessageBufferSendCompletedFromISR(xCPU0to1MessageBuffer, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} +#endif diff --git a/sdk/shared/sys/intr.h b/sdk/shared/sys/intr.h index 137771a4..7b29abe0 100644 --- a/sdk/shared/sys/intr.h +++ b/sdk/shared/sys/intr.h @@ -1,51 +1,51 @@ -#ifndef INTR_H -#define INTR_H - -#include "FreeRTOS.h" -#include "icc.h" -#include "xil_exception.h" -#include "xil_printf.h" -#include "xparameters.h" -#include "xscugic.h" - -#include -#include -#include - -// test - -/////////////////////////////////////////////////////// -// THIS IS A SHARED FILE, SO IT IS ALWAYS -// IN SYNC IN BOTH CPU0 AND CPU1 -// -// If you need to differentiate something between -// CPUs, use "#if XPAR_CPU_ID == ?" -/////////////////////////////////////////////////////// - -#define CPU0_ID (XSCUGIC_SPI_CPU0_MASK << 0) -#define CPU1_ID (XSCUGIC_SPI_CPU0_MASK << 1) - -#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID - -#define INTC_0TO1_SEND_INTERRUPT_ID 0U -#define INTC_1TO0_RCVE_INTERRUPT_ID 1U -#define INTC_1TO0_SEND_INTERRUPT_ID 2U -#define INTC_0TO1_RCVE_INTERRUPT_ID 3U - -// Interrupt Controller Instance -// Defined here to be accessable in sys/icc.c -static XScuGic InterruptController; - -int intr_init(); - -/* We only need to define the handlers in the appropriate core - */ -#if XPAR_CPU_ID == 0 -void CPU0WakeTxHandler(); -void CPU0WakeRxHandler(); -#elif XPAR_CPU_ID == 1 -void CPU1WakeTxHandler(); -void CPU1WakeRxHandler(); -#endif - -#endif /* INTR_H */ +#ifndef INTR_H +#define INTR_H + +#include "FreeRTOS.h" +#include "icc.h" +#include "xil_exception.h" +#include "xil_printf.h" +#include "xparameters.h" +#include "xscugic.h" + +#include +#include +#include + +// test + +/////////////////////////////////////////////////////// +// THIS IS A SHARED FILE, SO IT IS ALWAYS +// IN SYNC IN BOTH CPU0 AND CPU1 +// +// If you need to differentiate something between +// CPUs, use "#if XPAR_CPU_ID == ?" +/////////////////////////////////////////////////////// + +#define CPU0_ID (XSCUGIC_SPI_CPU0_MASK << 0) +#define CPU1_ID (XSCUGIC_SPI_CPU0_MASK << 1) + +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID + +#define INTC_0TO1_SEND_INTERRUPT_ID 0U +#define INTC_1TO0_RCVE_INTERRUPT_ID 1U +#define INTC_1TO0_SEND_INTERRUPT_ID 2U +#define INTC_0TO1_RCVE_INTERRUPT_ID 3U + +// Interrupt Controller Instance +// Defined here to be accessable in sys/icc.c +XScuGic InterruptController; + +int intr_init(); + +/* We only need to define the handlers in the appropriate core + */ +#if XPAR_CPU_ID == 0 +void CPU0WakeTxHandler(); +void CPU0WakeRxHandler(); +#elif XPAR_CPU_ID == 1 +void CPU1WakeTxHandler(); +void CPU1WakeRxHandler(); +#endif + +#endif /* INTR_H */ diff --git a/sdk/shared/sys/serial.c b/sdk/shared/sys/serial.c new file mode 100644 index 00000000..b5d973e0 --- /dev/null +++ b/sdk/shared/sys/serial.c @@ -0,0 +1,91 @@ +/* FreeRTOS includes */ +#include "FreeRTOS.h" +#include "task.h" +/* Other includes */ +#include "sys/serial.h" +#include "drv/uart.h" +#include "sys/util.h" +#include + +#define OUTPUT_BUFFER_LENGTH (32 * 1024) + +static char output_buffer[OUTPUT_BUFFER_LENGTH] = { 0 }; +static int output_idx = 0; + +// Used to mark position in `output_buffer` of char which needs to output +// +// -1 means not currently outputting anything +// >= 0 means trying to print at that idx +static int print_idx = -1; + +// Amount of chars we need to print at the moment +static int print_amount = 0; + + +/* task handle */ +static TaskHandle_t xSerialTaskHandle; +static uint8_t taskExists = 0; // extra data to ensure tasks don't get duplicated or double free'd + +void serial_init(void) +{ + if (taskExists) { + return; + } + // Create serial task + xTaskCreate(serial_main, (const char *) "uartSerial", configMINIMAL_STACK_SIZE, + NULL, tskIDLE_PRIORITY, &xSerialTaskHandle); + taskExists = 1; +} + +void serial_main(void *arg) +{ + for (;;) { + vTaskDelay(SERIAL_INTERVAL_TICKS); + if (print_amount > 0) { + // Have work to do! + + // Determine amount of chars to print before buffer wrap + int try_to_send = MIN(print_amount, OUTPUT_BUFFER_LENGTH - print_idx); + + // Try to send that amount of chars to the UART + int bytes_sent = uart_send(&output_buffer[print_idx], try_to_send); + print_amount -= bytes_sent; + + // UART TX FIFO might have been full, so didn't print all we tried + print_idx += bytes_sent; + if (print_idx >= OUTPUT_BUFFER_LENGTH) { + print_idx = 0; + } + + // Check if done outputting data + if (print_amount == 0) { + print_idx = -1; + } + } + } +} + +static void _append_to_output_buffer(char c) +{ + output_buffer[output_idx] = c; + + output_idx++; + if (output_idx >= OUTPUT_BUFFER_LENGTH) { + output_idx = 0; + } +} + +void serial_write(char *msg, int len) +{ + // Mark index to start outputting at in the callback + if (print_idx == -1) { + print_idx = output_idx; + } + + print_amount += len; + + // Copy contents into circular output buffer + for (int i = 0; i < len; i++) { + _append_to_output_buffer(msg[i]); + } +} diff --git a/sdk/shared/sys/serial.h b/sdk/shared/sys/serial.h new file mode 100644 index 00000000..a0d56aa0 --- /dev/null +++ b/sdk/shared/sys/serial.h @@ -0,0 +1,12 @@ +#ifndef SERIAL_H +#define SERIAL_H + +#define SERIAL_UPDATES_PER_SEC (10000) +#define SERIAL_INTERVAL_TICKS (pdMS_TO_TICKS(1000.0 / SERIAL_UPDATES_PER_SEC)) + +void serial_init(void); +void serial_main(void *arg); + +void serial_write(char *msg, int len); + +#endif // SERIAL_H diff --git a/sdk/shared/sys/util.h b/sdk/shared/sys/util.h new file mode 100644 index 00000000..32bee572 --- /dev/null +++ b/sdk/shared/sys/util.h @@ -0,0 +1,22 @@ +#ifndef UTIL_H +#define UTIL_H + +#include +#include + +#define MIN(x, y) (((x) > (y)) ? (y) : (x)) +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +#define BITSET(word, nbit) ((word) |= (1 << (nbit))) +#define BITCLEAR(word, nbit) ((word) &= ~(1 << (nbit))) +#define BITFLIP(word, nbit) ((word) ^= (1 << (nbit))) +#define BITCHECK(word, nbit) ((word) & (1 << (nbit))) + +static inline bool STREQ(char *in1, char *in2) +{ + return (strcmp(in1, in2) == 0) ? true : false; +} + +#endif // UTIL_H