FPGA에 모터 제어를 집어넣는 작업은 어렵지 않다. 이 글에서는 간소화된 FOC 전류 제어 루프 구현을 단계별로 분석하며, Verilog 코드가 하드웨어와 어떻게 상호작용하는지 살펴본다. 이 버전은 위치 루프나 속도 루프 없이 전류 폐루프 제어에만 집중하며, 빠른 응답이 필요한 상황에 적합하다.
먼저 RTL 구조를 살펴보자. 최상위 모듈은 AD7928의 샘플 데이터를 입력받아 Clarke/Park 변환을 거친 후 PI 제어기로 전달하고, SVPWM 모듈이 듀티 사이클 신호를 생성한다. 흥미로운 점은 전체 데이터 흐름이 고정 소수점 연산으로 처리되며, PI 조정도 자체 정수 연산을 사용한다는 것이다.
ADC 인터페이스는 다음과 같이 구현한다:
module adc_interface(
input clk,
input [11:0] adc_raw,
output reg signed [15:0] phase_current
);
// 전류 보정 계수: 샘플링 저항과 연산 증폭기 회로 기반 계산
parameter SCALE_FACTOR = 3276; // Q12 형식
always @(posedge clk) begin
// 원시 ADC 값을 부호 있는 숫자로 변환
phase_current <= (adc_raw - 2048) * SCALE_FACTOR >>> 12;
end
endmodule
여기서 주의할 점이 있다. AD7928은 단일 입력이므로 영점 드리프트 보정이 필요하다. 실제로는 초기화 시 오프셋을 읽고 전원 켜짐 시 자동 보정을 수행하는 것이 좋다.
PI 제어기 구현은 실력이 드러나는 부분으로, 하드코어 코드를 직접 보자:
module pi_controller(
input clk,
input rst,
input signed [15:0] err,
output reg signed [15:0] out
);
parameter KP = 80; // Q8.8 형식
parameter KI = 5; // Q8.8
reg signed [31:0] integ;
always @(posedge clk or posedge rst) begin
if(rst) begin
integ <= 0;
out <= 0;
end else begin
integ <= integ + (err * KI) >>> 8; // 적분 항
out <= (err * KP + integ) >>> 16; // 오버플로 방지
end
end
endmodule
이 우측 시프트 연산의 위치가 제어 정밀도에 직접적인 영향을 미친다. 시뮬레이션 중 적분 포화가 발생하면, 안티-와인드업 로직을 추가해야 하지만, 이 간소화 버전에서는 생략한다.
SVPWM 생성이 핵심이다. 2-레벨 알고리즘은 다음과 같다:
module svpwm(
input clk,
input signed [15:0] Vα,
input signed [15:0] Vβ,
output reg [2:0] PWM
);
// 공간 벡터 섹터 판별
wire [2:0] sector = calc_sector(Vα, Vβ);
// 듀티 사이클 계산
reg [15:0] T1, T2;
always @(posedge clk) begin
case(sector)
1: begin
T1 = (Vβ * 886) >> 12; // 886 ≈ sqrt(3) * 512
T2 = (Vα * 512 + Vβ * 296) >> 12;
end
//... 다른 섹터는 유사하게 처리
endcase
end
// 타이머 비교값 생성
reg [15:0] cmp[0:2];
always @(*) begin
cmp[0] = (PERIOD - T1 - T2) / 2;
cmp[1] = cmp[0] + T1;
cmp[2] = cmp[1] + T2;
end
endmodule
근사 계산을 통해 삼각 함수를 대체했으며, 측정된 파형 왜곡은 2% 미만이다. 타이머 주기는 PWM 주파수에 따라 조정되어야 하며, 예를 들어 20kHz에서 50us 주기가 타이머 값 = 클록 주파수 * 50e-6에 해당한다.
직렬 통신 모듈은 파라미터 조정을 담당하며, 상태 머신을 통해 명령을 해석한다:
case(rx_state)
IDLE: if(rx_data == 'hAA') rx_state <= CMD;
CMD: begin
case(rx_data)
'h01: begin target_Iq <= next_data; end
'h02: begin Kp <= next_data; end
//...
endcase
end
endcase
실제 측정에서 115200 보드레이트는 문제없지만, 클록 도메인 간 처리에 주의해야 한다. AS5600 피드백 처리는 간단하며, I2C를 통해 매 밀리초마다 각도 값을 읽으면 된다.
Simulink 모델에서 전류 루프는 이산 전달 함수 블록으로 추상화되며, Verilog 코드의 샘플링/계산 주기와 엄격하게 일치한다. 시뮬레이션 중 위상 지연이 30도를 초과하면 계산 주파수를 조정해야 하며, 그때 클록 분할 파라미터를 수정하러 돌아와야 한다.
마지막으로 하드웨어 적응 팁을 소개한다:
- 전류 샘플링 타이밍은 PWM 중점에 맞춰 스위칭 노이즈를 피해야 한다.
- 데드 타임은 PWM 모듈에서 직접 처리하며, 4개의 클록 사이클 지연을 추가한다.
- Q 형식 변환은 Python 스크립트로 계수를 사전 처리하여 수동 계산 오류를 방지하는 것이 좋다.
이 코드는 Artix-7에서 실행되며, 리소스 사용량은 대략 다음과 같다:
- LUT: 12%
- FF: 8%
- BRAM: 3개
- 최대 주파수: 85MHz
다른 플랫폼으로 이식할 때는 주로 세 가지를 수정해야 한다: 클록 관리, 주변 인터페이스 주소, PWM 생성 모듈의 구체적인 구현. 전류 루프 핵심 코드는 기본적으로 변경할 필요가 없으며, 이는 FPGA로 제어하는 장점이다 — 하드웨어가 변경되어도 알고리즘을 다시 작성할 필요가 없다.