| [개요] |
일반적으로 시제품에 Firmware를 업데이트하고 시험하기 전 Simulation Level에서 실제 부하를 모델링하고 변경한 제어 알고리즘이 안정적으로 동작되는지 사전 검증을 하거나 또는 실제 환경에서는 DAC 채널 수 부족이나 애초에 DAC를 지원하지 않는 등의 제약 조건으로 경향성을 보기 어려운 내부 Parameter들에 대해 어떤 양상이 있는지 등을 확인할 때 Simulation을 많이 접하게 됩니다.
특히나 연구, 개발하시는 Target Microcontroller(MCU)와 같이 이산 시간(Discrete-Time) 환경에서 알고리즘을 검증하기 위해서는 C언어로 개발한 함수를 그대로 적용하여 검증하기 용이한 C Block, DLL Block이라는 Model을 PSIM에서 지원하고 있습니다.
기존에 Dev-C++[1], Visual Studio Community[2](구 Express) 환경에서도 DLL을 생성해 사용했었지만 Dev-C++은 복수 개의 프로그램 실행이 불가하다는 단점, Visual Studio Community는 기업에서 사용하려면 License가 필요하다는 단점이 있기도 하고 요즘은 취미로 Python이나 ESP32 Board도 사용하다 보니 Visual Studio Code 환경에 익숙해져서 DLL 생성도 같은 환경에서 사용하려고 시도해보았고 그 과정을 정리해보고자 합니다.
| [본문] |
1. Compiler 환경 Setup
1.1 MSYS2 설치
우선 MSYS2[3]를 설치합니다. Windows 환경에서 Unix 계열 개발 도구와 라이브러리를 사용하고 Software를 Build할 수 있게 해주는 Software platform이라고 합니다.

설치를 완료한 후 MSYS2 UCRT64를 실행시킵니다.

Terminal 창이 나오고 아래와 같은 명령어를 입력하여 Update를 진행합니다.
pacman -Syu

중간에 Y를 눌러 설치를 진행시키고 Y를 눌러 닫고 다시 UCRT64를 실행시킵니다.

다시 실행된 Terminal에 아래 명령어를 입력하여 설치된 패키지에 대한 최신 업데이트를 한번 더 Check 및 진행하고 끝나길 기다립니다.
pacman -Su

다음은 GCC 및 Build 도구를 설치합니다. 명령어는 아래와 같습니다.
pacman -S --needed mingw-w64-ucrt-x86_64-toolchain

중간에 Package 선택이 나오면 default로 전체 설치를 합니다. (그냥 Enter 누르면 됨)
이후 gcc가 설치되었는지 확인합니다.
gcc --version

위와 같이 gcc 16.2.0 version이 확인되었으니 이제 설치 경로를 확인합니다.
which gcc

설치 경로가 "/ucrt64/bin/gcc"로 나오는지 확인합니다.
1.2 Windows 기반 환경 변수 등록
VS Code의 PowerShell Terminal에서 gcc를 사용하려면 Windows 환경 변수 등록이 필요합니다.
기본 MSYS2 설치 위치가 C:\msys64\ucrt64\bin 라면
"Windows 시작 버튼 - 설정 - 시스템 - 정보 - 고급 시스템 설정 - 환경 변수" 로 들어가서 시스템 변수의 path를 찾고 아래와 같이 설치 경로를 추가해줍니다.


여기서 저의 경우 Compile시에 LaTeX로 문서 작성을 위해 설치했던 Strawberry안에도 gcc가 있어서 환경변수 우선순위를 UCRT64를 더 높게 설정해주었습니다.
이후 VS Code를 실행하고 Terminal을 엽니다.

앞서 UCRT64에서 확인했던 gcc version Check 명령어를 적용해서 아래 사진과 같이 출력되면 VS Code와 gcc가 연동됐다고 판단할 수 있습니다.

1.3 VS Code Extension 설치
다음은 VS Code의 Extension 설치를 진행합니다. 좌측 패널에서 Extension Marketplace를 열고 "ms-vscode.cpptools" 를 검색하고 설치합니다.

2. PSIM DLL 파일 생성
2.1 Workspace 구조 설정
우선 폴더 트리 예시를 잡고 가겠습니다. 저는 하나의 Workspace안에 2개의 Project를 생성하고 각각의 DLL 파일을 PSIM Schematic에서 2개의 DLL을 연동해 사용하고자 합니다.
기본적인 Workspace Folder Tree는 아래와 같습니다.
TEST_DLL(Workspace)
│
├─ CNV(Project 1)
│ ├─ Source Folder
│ │─ main.c
│ ├─ Header Folder
│ └─ main.h
│
├─ INV(Project 2)
│ ├─ Source Folder
│ │─ main.c
│ ├─ Header Folder
│ └─ main.h
│
├─ Converter.dll
├─ Inverter.dll
└─ PSIM.psimsch
이와 같이 Workspace 하위에 2개의 Project Folder로 각각 관리를 하고 Build 시에는 선택한 Project 만 별도 Build 진행 그리고 생성되는 DLL 파일은 상위 폴더인 Workspace Folder 안에 생성되어 관리하고자 합니다.


우선 DLL 파일을 제외하고 원하는 구조로 임시 구성해둔 후 나중에도 본 구조의 Workspace를 VS Code에서 불러올 수 있도록 저장합니다.
File - Save Workspace As... 를 누르고 Workspace 안으로 경로를 지정해서 저장해줍니다.

저장을 하게되면 아래 사진과 같이 저장당시 지정한 명칭으로 Workspace 이름이 바뀌게되며 ".code-workspace" 파일이 생성된 것을 확인할 수 있습니다.
제가 만든 Workspace 폴더는 실제 이름은 TEST_DLL이었지만 Workspace를 저장하면서 정의한 명칭은 "PCS_Si"로 저장했습니다.

2.2 Workspace & Project & Makefile Setup
앞서 생성된 ".code-workspace" 파일을 더블클릭으로 열어보면 아래와 같이 나오게 됩니다.
만약 제가 작업중인 것 처럼 2개 이상의 Project 폴더를 이용하자고 한다면 여기서 본 Workspace에 프로젝트명과 실제 폴더명을 Matching 시켜줄 수 있습니다.

아래 사진에서 "path", "name"의 정의는 아래와 같습니다.
"path" : Workspace안에 실제 Project Folder 명칭
"name" : VS Code에서 인식하는 대체 명칭
저는 아래와 같이 Workspace 안의 폴더 CNV, INV를 각각 Converter, Inverter로 인식되도록 변경 적용 하였습니다.
{
"folders": [
{
"name": "Converter",
"path": "CNV"
},
{
"name": "Inverter",
"path": "INV"
},
],
"settings": {
"makefile.configureOnOpen": false
}
}

다음은 2개의 Project 폴더 안에 각각 ".vscode" 라는 이름의 폴더를 생성하고 그 안에 "c_cpp_properties.json", "tasks.json" 파일을 생성합니다.
우선 "c_cpp_properties.json" 파일은 build 시 2개의 Project 각각 build를 선택할 수 있도록 명칭을 정의합니다.
"name" : build 시 복수 개의 프로젝트 중 선택하기 용이한 명칭으로 정의
"includePath" : 프로젝트 파일 내부 Source & Header File의 검색 시 정확한 경로를 Searching 하도록 하는 VS Code IntelliSense 용 경로 Matching
{
"configurations": [
{
"name": "Converter GCC",
"compilerPath": "C:/msys64/ucrt64/bin/gcc.exe",
"includePath": [
"${workspaceFolder}/Header/**",
"${workspaceFolder}/Source/**"
],
"defines": [
"_WIN64"
],
"cStandard": "c11",
"intelliSenseMode": "windows-gcc-x64"
}
],
"version": 4
}

다음은 "tasks.json" 파일로 단축키(Ctrl + Shift + B)로 build Task를 실행하고 결과 값에 build가 성공적인지 실패했는지 시간은 얼마나 걸렸는지를 Terminal 상에 현시 해주는 내용을 담고 있습니다.
{
"version": "2.0.0",
"tasks": [
{
"label": "Build Converter DLL",
"type": "shell",
"command": "$sw = [System.Diagnostics.Stopwatch]::StartNew(); mingw32-make; $code = $LASTEXITCODE; $sw.Stop(); Write-Host ''; if ($code -eq 0) { Write-Host ('========== BUILD SUCCESS : {0:N3} sec ==========' -f $sw.Elapsed.TotalSeconds) } else { Write-Host ('========== BUILD FAILED : {0:N3} sec ==========' -f $sw.Elapsed.TotalSeconds) }; exit $code",
"options": {
"cwd": "${workspaceFolder}"
},
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
}
]
}

마지막으로 가장 중요한 "Makefile" 입니다.
Makefile은 Source/ 아래에 모든 .c 파일을 재귀적으로 찾아 gcc로 컴파일하고, Header/ 아래의 모든 .h 파일을 자동으로 Include 한 뒤 최종적으로 .dll을 생성하는 compile을 담당합니다.
우선 2개의 Project 폴더 안에 각각 New File로 확장자 없이 "Makefile"이라는 것을 생성해줍니다. (내용은 아래 내용을 붙여 넣습니다.)
SHELL := cmd.exe
CC = gcc
TARGET = ../CNV.dll
OBJ_DIR = build/obj
# ============================================================
# Recursive Wildcard
# ============================================================
rwildcard = $(foreach d,$(wildcard $1*),\
$(call rwildcard,$d/,$2) \
$(filter $(subst *,%,$2),$d))
# ============================================================
# Source Files
# ============================================================
SRC = $(call rwildcard,Source/,*.c)
# ============================================================
# Header Include Directories
# ============================================================
HEADER_FILES = $(call rwildcard,Header/,*.h)
HEADER_DIRS = $(sort $(dir $(HEADER_FILES)))
INCLUDES = $(addprefix -I,$(HEADER_DIRS))
# ============================================================
# Object / Dependency Files
# ============================================================
OBJ = $(patsubst Source/%.c,$(OBJ_DIR)/%.o,$(SRC))
DEP = $(OBJ:.o=.d)
# ============================================================
# Compiler / Linker Options
# ============================================================
CFLAGS = -O2 -Wall -std=c11 $(INCLUDES) -MMD -MP
LDFLAGS = -shared
# ============================================================
# Build DLL
# ============================================================
all: $(TARGET)
$(TARGET): $(OBJ)
$(CC) $(LDFLAGS) $(OBJ) -o $(TARGET)
# ============================================================
# Compile C -> Object
# ============================================================
$(OBJ_DIR)/%.o: Source/%.c
@if not exist "$(subst /,\,$(dir $@))" mkdir "$(subst /,\,$(dir $@))"
$(CC) $(CFLAGS) -c $< -o $@
# ============================================================
# Dependency
# ============================================================
-include $(DEP)
# ============================================================
# Clean
# ============================================================
clean:
@if exist build rmdir /S /Q build
@if exist "$(subst /,\,$(TARGET))" del /Q "$(subst /,\,$(TARGET))"
지금까지 상기 내용과 같이 복수개의 프로젝트들 내부에 Source Folder, Header Folder 안에 .c, .h 파일을 나눠서 넣어줬다면 dll이 생성되는 경로인 "TARGET = ../CNV.dll" 이 부분만 원하시는 이름으로 수정하셔서 사용할 수 있습니다.

2.3 build 동작 확인
마지막으로 Terminal 창에서 단축키(Ctrl + Shift + B)를 Command 한다면 아래 사진과 같이 상단에 2개의 프로젝트가 현시되면서 선택이 가능하게되며 수정작업이 완료된 프로젝트를 클릭하면 build를 진행합니다.

build가 진행중일때 build 폴더가 생성되면서 폴더 내부에 object 파일이 생성됩니다.
초기 처음 build를 진행시에는 시간이 다소 소요되지만 이후부터는 수정사항이 연관된 부분만 build를 수행하고 나머지는 기존 build시 생성된 파일들을 참조하여 시간을 단축시키게 됩니다.
build가 완료되면 아래 사진과 같이 "BUILD SUCCESS" 라는 문구가 Terminal에 표기됩니다.


저는 Project 1 (Converter)에서 입력된 값을 2배로 출력, Project2 (Inverter)에서 입력된 값을 3배로 출력되도록 Test Code를 적용해보았습니다.

결과적으로 2개의 dll 파일이 제가 원했던 Workspace (Project1, Project2의 상위 경로) 각각 생성되었음을 확인할 수 있습니다.
이렇게 구성하면 Project1, Project2가 서로 영향을 주지 않고 필요한 Project를 추가하거나 빼기 용이하며 PSIM Schematic과 동일 위치에 dll 파일이 있어서 경로로 인한 인식 불가 현상도 막을 수 있습니다.

2개의 General DLL Block에 생성한 CNV.dll, INV.dll을 매칭시켜두었고 100[V]의 Sine wavefrom을 입력받아 각각 dll을 거쳐 출력하는 간단한 구성을 그려보았습니다.

dll 연동 및 동작이 정상적으로 수행됨을 알 수 있습니다.
3. 결론
지금까지 VS Code 기반에서 PSIM Schematic에 연동하기위한 DLL Block용 dll 파일 생성 방법에 대해 정리해 보았습니다. 생성된 dll 파일은 x64 기반으로 동작하게 됩니다. (x86 기반으로 변경시에는 본 내용을 따라 1차적으로 만들고 AI의 도움을 받아보면 쉽게 해결될 것으로 사료됩니다. ㅎ)
| [참고자료] |
[1] : https://www.dev-cpp.com/
[2] : https://visualstudio.microsoft.com/ko/vs/community/
Visual Studio Community | 최신 무료 버전 다운로드
Windows, Android 및 iOS용 최신 개발자 앱을 만들기 위한 모든 기능을 갖춘 확장 가능한 무료 IDE를 사용해 보세요. 지금 무료로 커뮤니티를 다운로드하세요.
visualstudio.microsoft.com
[3] : https://www.msys2.org/
MSYS2
Software Distribution and Building Platform for Windows
www.msys2.org


































