본문 바로가기
아날로그회로(Analog Circuit)/ADC관련

[AD2S1210] Resolver-to-Digital Converter with STM32G474 SPI Driver

by linuxgo 2025. 8. 14.
반응형

1. 소개 (Introduction)

이 문서는 AD2S1210 리졸버-디지털 변환기와 STM32G474 마이크로컨트롤러를 SPI 드라이버로 통합하는 방법을 설명합니다 (This document explains how to integrate the AD2S1210 Resolver-to-Digital Converter with the STM32G474 microcontroller using an SPI driver). AD2S1210은 고정밀 위치 및 속도 측정을 제공하며, 자동차, 산업, 항공우주 애플리케이션에 적합합니다 (The AD2S1210 provides high-precision position and velocity measurements, suitable for automotive, industrial, and aerospace applications). 

주요 특징 (Key Features)

  • 해상도: 10/12/14/16비트, 설정 가능 (Resolution: 10/12/14/16-bit, configurable).
  • 최대 추적 속도: 10비트, CLKIN=10.24 MHz에서 3125 rps (Max tracking rate: 3125 rps at 10-bit, CLKIN=10.24 MHz).
  • 각도 정확도: ±2.5 arc minutes (B/D 등급) (Angular accuracy: ±2.5 arc minutes for B/D grades).
  • 입력 신호: 사인/코사인, 3.15 V p-p ±27% (Input signals: Sine/Cosine, 3.15 V p-p ±27%).
  • 인터페이스: SPI, 병렬, A-quad-B 엔코더 출력 (Interfaces: SPI, parallel, A-quad-B encoder output).
  • 오류 감지: LOS, DOS, LOT, 클리핑 (Error detection: LOS, DOS, LOT, clipping).
  • 전원: AVDD/DVDD=5V, VDRIVE=2.3V~5.25V (Power: AVDD/DVDD=5V, VDRIVE=2.3V~5.25V).

 

AD2S1210 IC 및 평가보드

2. AD2S1210 핀 기능 (Pin Functions)

AD2S1210은 48-LQFP 패키지로 제공되며, 각 핀은 리졸버 입력, 여기 출력, SPI, 제어, 전원 기능을 수행합니다 (The AD2S1210 is available in a 48-LQFP package, with pins for resolver inputs, excitation outputs, SPI, control, and power). 아래 표는 핀 역할과 사양을 설명합니다 (The table below describes pin roles and specifications).

핀 번호 (Pin Number) 핀 이름 (Pin Name) 기능 (Function) 전기적 사양 (Electrical Specs) 연결 주의사항 (Connection Notes)
1, 12, 13, 24, 25, 36 AVDD 아날로그 전원 (Analog power) 4.75V~5.25V, 35 mA 0.1 µF, 10 µF 디커플링 (Decouple with 0.1 µF, 10 µF)
2 SIN 사인 입력 (Sine input, differential) 3.15 V p-p ±27% 차폐 케이블, SINLO와 쌍 (Shielded cable, pair with SINLO)
3 SINLO 사인 입력 접지 (Sine input ground) - AGND와 분리 (Separate from AGND)
4 COS 코사인 입력 (Cosine input, differential) 3.15 V p-p ±27% 차폐 케이블, COSLO와 쌍 (Shielded cable, pair with COSLO)
5 COSLO 코사인 입력 접지 (Cosine input ground) - AGND와 분리 (Separate from AGND)
8 EXC 여기 출력 (Excitation output) 3.6 V p-p, 28 mA max 리졸버 코일 연결 (Connect to resolver coil)
9 EXC 여기 출력 보수 (Excitation output, complement) 3.6 V p-p, 180° phase 리졸버 코일 연결 (Connect to resolver coil)
14 CLKIN 외부 클럭 입력 (External clock input) 6.144 MHz ~ 10.24 MHz 8.192 MHz 권장 (8.192 MHz recommended)
20 SCLK SPI 클럭 입력 (SPI clock input) Max 25 MHz, VDRIVE level STM32 SCK 연결 (Connect to STM32 SCK)
21 CS SPI 칩 선택 (SPI chip select, active low) Min pulse 20 ns STM32 GPIO 연결 (Connect to STM32 GPIO)
22 SO SPI 데이터 출력 (SPI data output) VDRIVE level STM32 MISO 연결 (Connect to STM32 MISO)
23 SI SPI 데이터 입력 (SPI data input) VDRIVE level STM32 MOSI 연결 (Connect to STM32 MOSI)
26 RESET 리셋 입력 (Reset input, active low) Min 20 µs pulse STM32 GPIO 연결 (Connect to STM32 GPIO)
27 SAMPLE 샘플 트리거 (Sample trigger, active low) Min 20 ns pulse STM32 GPIO 연결 (Connect to STM32 GPIO)
28 LOT 추적 손실 출력 (Loss of tracking output) Open-drain, VDRIVE pull-up STM32 EXTI, 풀업 저항 (STM32 EXTI with pull-up)
29 DOS 신호 열화 출력 (Degradation of signal output) Open-drain, VDRIVE pull-up STM32 EXTI, 풀업 저항 (STM32 EXTI with pull-up)
30 LOS 신호 손실 출력 (Loss of signal output) Open-drain, VDRIVE pull-up STM32 EXTI, 풀업 저항 (STM32 EXTI with pull-up)
31~34, 37~42 DB0~DB9 병렬 데이터 출력 (Parallel data output) VDRIVE level 미사용 시 NC (NC if unused)
43 A A-quad-B 출력 A (A-quad-B output A) VDRIVE level 엔코더 연결 (Connect to encoder)
44 B A-quad-B 출력 B (A-quad-B output B) VDRIVE level 엔코더 연결 (Connect to encoder)

미사용 핀은 NC로 두거나 데이터시트에 따라 처리해야 합니다 (Unused pins should be left NC or handled per the datasheet). VDRIVE는 STM32의 3.3V와 호환되도록 설정합니다 (VDRIVE is set to 3.3V for STM32 compatibility).

3. 인터페이스 방식 (Interface Methods)

AD2S1210은 SPI, 병렬, A-quad-B 엔코더 출력을 지원하여 다양한 시스템 통합이 가능합니다 (The AD2S1210 supports SPI, parallel, and A-quad-B encoder outputs for versatile system integration).

3.1 SPI 인터페이스 (SPI Interface)

4선식 SPI는 레지스터 읽기/쓰기 및 데이터 전송에 사용됩니다 (The 4-wire SPI is used for register read/write and data transfer).

  • 핀: SCLK, CS, SI, SO (Pins: SCLK, CS, SI, SO).
  • 프로토콜: SPI Mode 2 (CPOL=High, CPHA=2Edge), 최대 25 MHz (Protocol: SPI Mode 2, max 25 MHz).
  • 쓰기: CS Low → 주소(8비트, MSB=1) → 데이터 → CS High (Write: CS Low → address (8-bit, MSB=1) → data → CS High).
  • 읽기: CS Low → 주소(8비트, MSB=0) → 데이터 → CS High (Read: CS Low → address (8-bit, MSB=0) → data → CS High).
  • 타이밍: CS 펄스 폭 ≥ 20 ns, SCLK 주기 ≥ 40 ns (Timing: CS pulse ≥ 20 ns, SCLK period ≥ 40 ns).

3.2 병렬 인터페이스 (Parallel Interface)

16비트 병렬 버스는 고속 데이터 전송에 적합합니다 (The 16-bit parallel bus is suitable for high-speed data transfer).

  • 핀: DB0~DB15, A0, A1, RD, WR/FSYNC (Pins: DB0~DB15, A0, A1, RD, WR/FSYNC).
  • 동작: A0/A1로 레지스터 선택, RD/WR로 읽기/쓰기 (Operation: Select register with A0/A1, read/write with RD/WR).
  • 타이밍: 펄스 폭 ≥ 20 ns (Timing: Pulse width ≥ 20 ns).

3.3 A-quad-B 엔코더 출력 (A-quad-B Encoder Output)

쿼드러처 출력은 기존 엔코더 시스템과 호환됩니다 (Quadrature output is compatible with existing encoder systems).

  • 핀: A, B, NM (Pins: A, B, NM).
  • 동작: A/B는 90° 위상 차이 펄스, NM은 회전당 1펄스 (Operation: A/B pulses with 90° phase, NM one pulse per rotation).
  • 설정: 펄스 수 조정 (256, 1024 펄스/회전) (Configuration: Adjust pulse count, e.g., 256, 1024 pulses/rev).

이 드라이버는 SPI를 사용하며, STM32G474의 GPIO와 호환됩니다 (This driver uses SPI, compatible with STM32G474 GPIO).

4. STM32G474와의 하드웨어 연결 (Hardware Connections with STM32G474)

STM32G474는 SPI, UART, CAN, DMA를 지원하여 AD2S1210과 통합됩니다 (The STM32G474 supports SPI, UART, CAN, and DMA for AD2S1210 integration). 연결은 아래 표와 같습니다 (Connections are shown in the table below).

AD2S1210 핀 (Pin) STM32G474 핀 (Pin) 설명 (Description)
SCLK (20) PA5 (SPI1_SCK) SPI 클럭, Mode 2 (SPI clock, Mode 2)
CS (21) PA4 (GPIO) 칩 선택 (Chip select)
SO (22) PA6 (SPI1_MISO) 데이터 출력 (Data output)
SI (23) PA7 (SPI1_MOSI) 데이터 입력 (Data input)
RESET (26) PB0 (GPIO) 리셋, 20 µs 펄스 (Reset, 20 µs pulse)
SAMPLE (27) PB1 (GPIO) 샘플 트리거 (Sample trigger)
LOT (28) PB4 (EXTI) 추적 손실, 풀업 (Loss of tracking, pull-up)
DOS (29) PB3 (EXTI) 신호 열화, 풀업 (Degradation of signal, pull-up)
LOS (30) PB2 (EXTI) 신호 손실, 풀업 (Loss of signal, pull-up)
CLKIN (14) TIMx 출력 (TIMx output) 8.192 MHz 클럭 (8.192 MHz clock)

리졸버 신호는 차폐 케이블로 연결하고, 전원은 디커플링 커패시터를 사용합니다 (Resolver signals use shielded cables, and power uses decoupling capacitors).

5. SPI 드라이버 구현 (SPI Driver Implementation)

STM32Cube HAL 기반 SPI 드라이버는 DMA를 활용하여 CPU 부하를 줄입니다 (The STM32Cube HAL-based SPI driver uses DMA to reduce CPU load). SPI Mode 2로 설정되며, 위치/속도 데이터를 읽습니다 (It is configured for SPI Mode 2 and reads position/velocity data).

코드: ad2s1210_driver.h (Code: ad2s1210_driver.h)

// ad2s1210_driver.h: AD2S1210 드라이버 함수 선언
// ad2s1210_driver.h: AD2S1210 driver function declarations
#ifndef AD2S1210_DRIVER_H
#define AD2S1210_DRIVER_H

#include "stm32g4xx_hal.h"

// AD2S1210 초기화: 리셋, 16비트 해상도, 10 kHz 여기 설정
// Initialize AD2S1210: Reset, 16-bit resolution, 10 kHz excitation
void AD2S1210_Init(void);

// 레지스터 쓰기: SPI로 주소와 데이터 전송 (DMA 사용)
// Write register: Send address and data via SPI (using DMA)
HAL_StatusTypeDef AD2S1210_WriteRegister(uint8_t address, uint8_t value);

// 레지스터 읽기: SPI로 주소에서 데이터 수신 (DMA 사용)
// Read register: Receive data from address via SPI (using DMA)
HAL_StatusTypeDef AD2S1210_ReadRegister(uint8_t address, uint8_t *value);

// 위치 읽기: 16비트 위치 데이터 수신
// Read position: Receive 16-bit position data
HAL_StatusTypeDef AD2S1210_ReadPosition(uint16_t *position);

// 속도 읽기: 16비트 속도 데이터 수신
// Read velocity: Receive 16-bit velocity data
HAL_StatusTypeDef AD2S1210_ReadVelocity(int16_t *velocity);

// 오류 읽기: Fault Register 데이터 수신
// Read fault: Receive Fault Register data
HAL_StatusTypeDef AD2S1210_ReadFault(uint8_t *fault);

// 오류 로그: Fault Register 분석 및 UART 전송
// Log fault: Analyze Fault Register and send via UART
void AD2S1210_LogFault(uint8_t fault);

// CAN 전송: 위치/속도/오류 데이터를 CAN으로 전송
// Send CAN: Transmit position/velocity/fault data via CAN
void AD2S1210_SendCANData(void);

#endif
            

코드: ad2s1210_driver.c (Code: ad2s1210_driver.c)

// ad2s1210_driver.c: AD2S1210 SPI 드라이버 구현
// ad2s1210_driver.c: AD2S1210 SPI driver implementation
#include "ad2s1210_driver.h"
#include "stm32g4xx_hal.h"
#include 
#include 

// 외부 핸들: SPI, UART, CAN, GPIO 핀 정의 (main.c에서 초기화)
// External handles: SPI, UART, CAN, GPIO pins defined (in main.c)
extern SPI_HandleTypeDef hspi1;
extern UART_HandleTypeDef huart1;
extern CAN_HandleTypeDef hcan1;
extern GPIO_TypeDef* CS_GPIO_Port;
extern uint16_t CS_Pin;
extern GPIO_TypeDef* RESET_GPIO_Port;
extern uint16_t RESET_Pin;
extern GPIO_TypeDef* SAMPLE_GPIO_Port;
extern uint16_t SAMPLE_Pin;

// 레지스터 주소 정의 (AD2S1210 데이터시트 참조)
// Register address definitions (refer to AD2S1210 datasheet)
#define REG_POSITION_MSB 0x00  // 위치 데이터 MSB (Position data MSB)
#define REG_POSITION_LSB 0x01  // 위치 데이터 LSB (Position data LSB)
#define REG_VELOCITY_MSB 0x02  // 속도 데이터 MSB (Velocity data MSB)
#define REG_VELOCITY_LSB 0x03  // 속도 데이터 LSB (Velocity data LSB)
#define REG_CONTROL 0x91       // 제어 레지스터: 여기 주파수 등 (Control register: excitation frequency, etc.)
#define REG_CONFIG 0x92        // 설정 레지스터: 해상도 등 (Configuration register: resolution, etc.)
#define REG_FAULT 0xFF         // 오류 레지스터 (Fault register)

// 오류 비트 정의 (Fault Register 비트별 오류)
// Fault bit definitions (Fault Register bit-wise errors)
#define FAULT_LOS (1 << 7)   // 신호 손실 (Loss of signal)
#define FAULT_DOS (1 << 6)   // 신호 열화 (Degradation of signal)
#define FAULT_LOT (1 << 5)   // 추적 손실 (Loss of tracking)
#define FAULT_CLIP (1 << 4)  // 신호 클리핑 (Signal clipping)

// DMA 버퍼: SPI 전송/수신용 (SPI transmit/receive buffers)
static uint8_t spi_tx_buffer[2];
static uint8_t spi_rx_buffer[2];
// 데이터 저장: 위치, 속도, 오류 (Stored data: position, velocity, fault)
static uint16_t position_data;
static int16_t velocity_data;
static uint8_t fault_data;
// UART 출력 버퍼 (UART output buffer)
static char uart_buffer[128];

// CAN 메시지 헤더: ID 0x100, 8바이트 데이터
// CAN message header: ID 0x100, 8-byte data
static CAN_TxHeaderTypeDef can_tx_header = {
    .StdId = 0x100,
    .ExtId = 0,
    .IDE = CAN_ID_STD,
    .RTR = CAN_RTR_DATA,
    .DLC = 8,
    .TransmitGlobalTime = DISABLE
};

// 초기화: AD2S1210 리셋, 16비트 해상도, 10 kHz 여기 설정
// Initialize: Reset AD2S1210, set 16-bit resolution, 10 kHz excitation
void AD2S1210_Init(void) {
    // RESET 핀을 1ms 동안 Low로 설정하여 칩 리셋
    // Set RESET pin low for 1ms to reset the chip
    HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_RESET);
    HAL_Delay(1);
    HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_SET);
    HAL_Delay(10); // 초기화 완료 대기 (Wait for initialization to complete)

    // Configuration Register: 16비트 해상도 설정 (0x0C)
    // Set Configuration Register: 16-bit resolution (0x0C)
    AD2S1210_WriteRegister(REG_CONFIG, 0x0C);
    // Control Register: 10 kHz 여기 주파수 설정 (0x40)
    // Set Control Register: 10 kHz excitation frequency (0x40)
    AD2S1210_WriteRegister(REG_CONTROL, 0x40);
}

// 레지스터 쓰기: SPI로 주소와 데이터 전송 (DMA 사용)
// Write register: Send address and data via SPI (using DMA)
HAL_StatusTypeDef AD2S1210_WriteRegister(uint8_t address, uint8_t value) {
    spi_tx_buffer[0] = address | 0x80; // 주소 MSB=1로 설정 (Set address MSB=1 for write)
    spi_tx_buffer[1] = value;
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); // CS Low
    // DMA로 2바이트 전송: 주소 + 데이터 (Transmit 2 bytes via DMA: address + data)
    HAL_StatusTypeDef status = HAL_SPI_Transmit_DMA(&hspi1, spi_tx_buffer, 2);
    while (HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY); // 전송 완료 대기 (Wait for transmission complete)
    return status;
}

// 레지스터 읽기: SPI로 주소에서 데이터 수신 (DMA 사용)
// Read register: Receive data from address via SPI (using DMA)
HAL_StatusTypeDef AD2S1210_ReadRegister(uint8_t address, uint8_t *value) {
    spi_tx_buffer[0] = address & 0x7F; // 주소 MSB=0으로 설정 (Set address MSB=0 for read)
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); // CS Low
    // DMA로 주소 전송 및 데이터 수신 (Transmit address and receive data via DMA)
    HAL_StatusTypeDef status = HAL_SPI_TransmitReceive_DMA(&hspi1, spi_tx_buffer, spi_rx_buffer, 1);
    while (HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY); // 전송 완료 대기 (Wait for transmission complete)
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); // CS High
    *value = spi_rx_buffer[0];
    return status;
}

// 위치 읽기: 16비트 위치 데이터 수신
// Read position: Receive 16-bit position data
HAL_StatusTypeDef AD2S1210_ReadPosition(uint16_t *position) {
    uint8_t msb, lsb;
    HAL_StatusTypeDef status;

    // SAMPLE 핀 트리거로 데이터 갱신 (Trigger SAMPLE pin to update data)
    HAL_GPIO_WritePin(SAMPLE_GPIO_Port, SAMPLE_Pin, GPIO_PIN_RESET);
    HAL_Delay(1);
    HAL_GPIO_WritePin(SAMPLE_GPIO_Port, SAMPLE_Pin, GPIO_PIN_SET);

    // MSB 읽기 (Read MSB)
    status = AD2S1210_ReadRegister(REG_POSITION_MSB, &msb);
    if (status != HAL_OK) return status;
    // LSB 읽기 (Read LSB)
    status = AD2S1210_ReadRegister(REG_POSITION_LSB, &lsb);
    if (status != HAL_OK) return status;

    // 16비트 데이터 조합 (Combine 16-bit data)
    position_data = ((uint16_t)msb << 8) | lsb;
    *position = position_data;
    return HAL_OK;
}

// 속도 읽기: 16비트 속도 데이터 수신
// Read velocity: Receive 16-bit velocity data
HAL_StatusTypeDef AD2S1210_ReadVelocity(int16_t *velocity) {
    uint8_t msb, lsb;
    HAL_StatusTypeDef status;

    // SAMPLE 핀 트리거 (Trigger SAMPLE pin)
    HAL_GPIO_WritePin(SAMPLE_GPIO_Port, SAMPLE_Pin, GPIO_PIN_RESET);
    HAL_Delay(1);
    HAL_GPIO_WritePin(SAMPLE_GPIO_Port, SAMPLE_Pin, GPIO_PIN_SET);

    // MSB 읽기 (Read MSB)
    status = AD2S1210_ReadRegister(REG_VELOCITY_MSB, &msb);
    if (status != HAL_OK) return status;
    // LSB 읽기 (Read LSB)
    status = AD2S1210_ReadRegister(REG_VELOCITY_LSB, &lsb);
    if (status != HAL_OK) return status;

    // 16비트 데이터 조합 (Combine 16-bit data)
    velocity_data = ((int16_t)msb << 8) | lsb;
    *velocity = velocity_data;
    return HAL_OK;
}

// 오류 읽기: Fault Register 데이터 수신
// Read fault: Receive Fault Register data
HAL_StatusTypeDef AD2S1210_ReadFault(uint8_t *fault) {
    HAL_StatusTypeDef status = AD2S1210_ReadRegister(REG_FAULT, fault);
    fault_data = *fault;
    return status;
}

// 오류 로그: Fault Register 비트 분석 및 UART 전송
// Log fault: Analyze Fault Register bits and send via UART
void AD2S1210_LogFault(uint8_t fault) {
    if (fault) {
        // 오류 메시지 생성 (Generate fault message)
        snprintf(uart_buffer, sizeof(uart_buffer), "Fault: 0x%02X [", fault);
        if (fault & FAULT_LOS) strcat(uart_buffer, "LOS ");
        if (fault & FAULT_DOS) strcat(uart_buffer, "DOS ");
        if (fault & FAULT_LOT) strcat(uart_buffer, "LOT ");
        if (fault & FAULT_CLIP) strcat(uart_buffer, "CLIP ");
        strcat(uart_buffer, "]\n");
        // DMA로 UART 전송 (Transmit via UART using DMA)
        HAL_UART_Transmit_DMA(&huart1, (uint8_t*)uart_buffer, strlen(uart_buffer));
    }
}

// CAN 전송: 위치/속도/오류 데이터를 CAN 메시지로 전송
// Send CAN: Transmit position/velocity/fault data via CAN
void AD2S1210_SendCANData(void) {
    uint8_t can_data[8];
    // 데이터 패킹: 위치(2바이트), 속도(2바이트), 오류(1바이트)
    // Pack data: position (2 bytes), velocity (2 bytes), fault (1 byte)
    can_data[0] = (position_data >> 8) & 0xFF;
    can_data[1] = position_data & 0xFF;
    can_data[2] = (velocity_data >> 8) & 0xFF;
    can_data[3] = velocity_data & 0xFF;
    can_data[4] = fault_data;
    can_data[5] = 0; // 예약 (Reserved)
    can_data[6] = 0; // 예약 (Reserved)
    can_data[7] = 0; // 예약 (Reserved)

    // CAN 메시지 전송 (Transmit CAN message)
    uint32_t mailbox;
    HAL_CAN_AddTxMessage(&hcan1, &can_tx_header, can_data, &mailbox);
}

// SPI DMA 전송 완료 콜백: CS 핀 복원
// SPI DMA transmit complete callback: Restore CS pin
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) {
    if (hspi == &hspi1) {
        HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); // CS High
    }
}

// SPI DMA 수신 완료 콜백: CS 핀 복원
// SPI DMA receive complete callback: Restore CS pin
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
    if (hspi == &hspi1) {
        HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); // CS High
    }
}

// UART DMA 전송 완료 콜백
// UART DMA transmit complete callback
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
    // 전송 완료 후 추가 처리 (Optional post-transmission handling)
}

// 오류 인터럽트: LOS/DOS/LOT 핀 감지 시 오류 로그 생성
// Fault interrupt: Generate fault log on LOS/DOS/LOT pin trigger
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    if (GPIO_Pin == GPIO_PIN_2 || GPIO_Pin == GPIO_PIN_3 || GPIO_Pin == GPIO_PIN_4) {
        uint8_t fault;
        if (AD2S1210_ReadFault(&fault) == HAL_OK) {
            AD2S1210_LogFault(fault); // 오류 로그 전송 (Send fault log)
        }
    }
}
            

코드: main.c (Code: main.c)

// main.c: STM32G474에서 AD2S1210 제어 메인 프로그램
// main.c: Main program for controlling AD2S1210 with STM32G474
#include "main.h"
#include "ad2s1210_driver.h"
#include 

// 핸들 선언: SPI, UART, CAN
// Handle declarations: SPI, UART, CAN
SPI_HandleTypeDef hspi1;
UART_HandleTypeDef huart1;
CAN_HandleTypeDef hcan1;
// GPIO 핀 정의 (GPIO pin definitions)
GPIO_TypeDef* CS_GPIO_Port = GPIOA;
uint16_t CS_Pin = GPIO_PIN_4;
GPIO_TypeDef* RESET_GPIO_Port = GPIOB;
uint16_t RESET_Pin = GPIO_PIN_0;
GPIO_TypeDef* SAMPLE_GPIO_Port = GPIOB;
uint16_t SAMPLE_Pin = GPIO_PIN_1;

// 함수 선언 (Function declarations)
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_CAN1_Init(void);

int main(void) {
    // HAL 초기화 (Initialize HAL)
    HAL_Init();
    // 시스템 클럭 설정: 170 MHz (Configure system clock: 170 MHz)
    SystemClock_Config();
    // GPIO, SPI, UART, CAN 초기화 (Initialize GPIO, SPI, UART, CAN)
    MX_GPIO_Init();
    MX_SPI1_Init();
    MX_USART1_UART_Init();
    MX_CAN1_Init();

    // AD2S1210 초기화 (Initialize AD2S1210)
    AD2S1210_Init();

    // CAN 시작 및 수신 인터럽트 활성화 (Start CAN and enable receive interrupt)
    HAL_CAN_Start(&hcan1);
    HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);

    // 주기적 루프: 100ms마다 데이터 처리
    // Periodic loop: Process data every 100ms
    while (1) {
        uint16_t position;
        int16_t velocity;
        uint8_t fault;

        // 위치 읽기 및 UART 전송 (Read position and send via UART)
        if (AD2S1210_ReadPosition(&position) == HAL_OK) {
            char buffer[64];
            snprintf(buffer, sizeof(buffer), "Position: %u\n", position);
            HAL_UART_Transmit_DMA(&huart1, (uint8_t*)buffer, strlen(buffer));
        }

        // 속도 읽기 및 UART 전송 (Read velocity and send via UART)
        if (AD2S1210_ReadVelocity(&velocity) == HAL_OK) {
            char buffer[64];
            snprintf(buffer, sizeof(buffer), "Velocity: %d\n", velocity);
            HAL_UART_Transmit_DMA(&huart1, (uint8_t*)buffer, strlen(buffer));
        }

        // 오류 확인 및 로그 전송 (Check faults and send log)
        if (AD2S1210_ReadFault(&fault) == HAL_OK && fault) {
            AD2S1210_LogFault(fault);
        }

        // CAN으로 데이터 전송 (Send data via CAN)
        AD2S1210_SendCANData();

        HAL_Delay(100); // 100ms 대기 (Wait 100ms)
    }
}

// 시스템 클럭 설정: 170 MHz (HSE + PLL)
// System clock configuration: 170 MHz (HSE + PLL)
void SystemClock_Config(void) {
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    // HSE 활성화, PLL 설정 (Enable HSE, configure PLL)
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 2;
    RCC_OscInitStruct.PLL.PLLN = 85;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
    RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    // 시스템 클럭, AHB, APB 설정 (Configure system clock, AHB, APB)
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK |
                                  RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
}

// GPIO 초기화: CS, RESET, SAMPLE, LOS/DOS/LOT
// GPIO initialization: CS, RESET, SAMPLE, LOS/DOS/LOT
static void MX_GPIO_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // GPIO 클럭 활성화 (Enable GPIO clocks)
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();

    // CS 핀 (PA4): 출력, 초기 High (CS pin (PA4): Output, initial high)
    GPIO_InitStruct.Pin = GPIO_PIN_4;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);

    // RESET (PB0), SAMPLE (PB1): 출력, 초기 High (RESET (PB0), SAMPLE (PB1): Output, initial high)
    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0 | GPIO_PIN_1, GPIO_PIN_SET);

    // LOS/DOS/LOT (PB2/PB3/PB4): 입력, 풀업, 인터럽트 (LOS/DOS/LOT (PB2/PB3/PB4): Input, pull-up, interrupt)
    GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4;
    GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    // EXTI 인터럽트 활성화 (Enable EXTI interrupts)
    HAL_NVIC_SetPriority(EXTI2_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(EXTI2_IRQn);
    HAL_NVIC_SetPriority(EXTI3_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(EXTI3_IRQn);
    HAL_NVIC_SetPriority(EXTI4_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(EXTI4_IRQn);
}

// SPI1 초기화: Mode 2, 2 MHz, DMA 활성화
// SPI1 initialization: Mode 2, 2 MHz, DMA enabled
static void MX_SPI1_Init(void) {
    hspi1.Instance = SPI1;
    hspi1.Init.Mode = SPI_MODE_MASTER;
    hspi1.Init.Direction = SPI_DIRECTION_2LINES;
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH; // CPOL=High for SPI Mode 2
    hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;      // CPHA=2Edge for SPI Mode 2
    hspi1.Init.NSS = SPI_NSS_SOFT;
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64; // 2 MHz
    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi1.Init.CRCPolynomial = 7;
    HAL_SPI_Init(&hspi1);

    // SPI DMA 설정 (Configure SPI DMA)
    __HAL_RCC_DMA1_CLK_ENABLE();
    HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
    HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
}

// USART1 초기화: 115200 baud, DMA 활성화
// USART1 initialization: 115200 baud, DMA enabled
static void MX_USART1_UART_Init(void) {
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 115200;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLING_DISABLED;
    HAL_UART_Init(&huart1);

    // UART DMA 설정 (Configure UART DMA)
    __HAL_RCC_DMA1_CLK_ENABLE();
    HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
}

// CAN1 초기화: 500 kbps, 필터 설정
// CAN1 initialization: 500 kbps, filter configuration
static void MX_CAN1_Init(void) {
    hcan1.Instance = CAN1;
    hcan1.Init.Prescaler = 17;
    hcan1.Init.Mode = CAN_MODE_NORMAL;
    hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
    hcan1.Init.TimeSeg1 = CAN_BS1_6TQ;
    hcan1.Init.TimeSeg2 = CAN_BS2_2TQ;
    hcan1.Init.TimeTriggeredMode = DISABLE;
    hcan1.Init.AutoBusOff = DISABLE;
    hcan1.Init.AutoWakeUp = DISABLE;
    hcan1.Init.AutoRetransmission = ENABLE;
    hcan1.Init.ReceiveFifoLocked = DISABLE;
    hcan1.Init.TransmitFifoPriority = DISABLE;
    HAL_CAN_Init(&hcan1);

    // CAN 필터: ID 0x100 수신 (CAN filter: Receive ID 0x100)
    CAN_FilterTypeDef filter;
    filter.FilterIdHigh = 0x100 << 5;
    filter.FilterIdLow = 0;
    filter.FilterMaskIdHigh = 0x7FF << 5;
    filter.FilterMaskIdLow = 0;
    filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
    filter.FilterBank = 0;
    filter.FilterMode = CAN_FILTERMODE_IDMASK;
    filter.FilterScale = CAN_FILTERSCALE_32BIT;
    filter.FilterActivation = ENABLE;
    HAL_CAN_ConfigFilter(&hcan1, &filter);

    // CAN 인터럽트 활성화 (Enable CAN interrupts)
    HAL_NVIC_SetPriority(CAN1_TX_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(CAN1_TX_IRQn);
    HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
}

// DMA 인터럽트 핸들러: SPI 및 UART
// DMA interrupt handlers: SPI and UART
void DMA1_Channel3_IRQHandler(void) {
    HAL_DMA_IRQHandler(hspi1.hdmatx); // SPI TX DMA 처리 (Handle SPI TX DMA)
}

void DMA1_Channel4_IRQHandler(void) {
    HAL_DMA_IRQHandler(hspi1.hdmarx); // SPI RX DMA 처리 (Handle SPI RX DMA)
}

void DMA1_Channel5_IRQHandler(void) {
    HAL_DMA_IRQHandler(huart1.hdmatx); // UART TX DMA 처리 (Handle UART TX DMA)
}
            

6. UART/CAN 통신 (UART/CAN Communication)

AD2S1210 데이터를 외부로 전송하기 위해 UART와 CAN을 사용합니다 (UART and CAN are used to transmit AD2S1210 data externally).

  • UART: USART1, 115200 baud, DMA1 Channel 5, 위치/속도/오류 로그 전송 (UART: USART1, 115200 baud, DMA1 Channel 5, sends position/velocity/fault logs).
  • CAN: CAN1, 500 kbps, ID 0x100, 8바이트 프레임 (위치 2바이트, 속도 2바이트, 오류 1바이트) (CAN: CAN1, 500 kbps, ID 0x100, 8-byte frame: position 2 bytes, velocity 2 bytes, fault 1 byte).

7. 오류 처리 (Error Handling)

Fault Register(0xFF)를 통해 오류를 감지합니다 (The Fault Register (0xFF) detects errors).

비트 (Bit) 오류 (Error) 설명 (Description) 대응 (Action)
7 LOS 신호 손실 (Loss of signal) 리졸버 연결 확인 (Check resolver connections)
6 DOS 신호 열화 (Degradation of signal) 신호 품질 점검 (Check signal quality)
5 LOT 추적 손실 (Loss of tracking) CLKIN 안정성 확인 (Check CLKIN stability)
4 클리핑 (Clipping) 입력 신호 클리핑 (Input signal clipping) 입력 진폭 조정 (Adjust input amplitude)

8. 설정 옵션 (Configuration Options)

AD2S1210은 레지스터를 통해 사용자 맞춤 설정이 가능합니다 (The AD2S1210 can be customized via registers).

  • Configuration Register (0x92): 해상도 (Resolution), 엔코더 펄스 수 (Encoder pulse count).
  • Control Register (0x91): 여기 주파수 2~20 kHz (Excitation frequency 2~20 kHz).
  • Fault Threshold Registers (0x80~0x8F): LOS/DOS/LOT 임계값 (LOS/DOS/LOT thresholds).

9. 응용 예시 (Application Examples)

  • 전기 파워 스티어링 (EPS): 조향 각도 측정, ASIL B 인증 (EPS: Steering angle measurement, ASIL B certified).
  • 산업 서보: 로봇 팔 정밀 제어 (Industrial servo: Precise robot arm control).
  • 항공우주: 비행 제어 표면, -55°C~+125°C (Aerospace: Flight control surfaces, -55°C~+125°C).

10. 사용 방법 (Usage Instructions)

  1. STM32CubeMX 설정: SPI1 (DMA, Mode 2), UART1 (DMA), CAN1, GPIO, EXTI 설정 (Configure STM32CubeMX: SPI1 (DMA, Mode 2), UART1 (DMA), CAN1, GPIO, EXTI).
  2. 코드 통합: 위 파일을 STM32CubeIDE 프로젝트에 추가 (Integrate code: Add files to STM32CubeIDE project).
  3. 컴파일 및 업로드: STM32G474에 플래시 (Compile and flash to STM32G474).
  4. 테스트: UART (115200 baud), CAN (ID 0x100)으로 데이터 확인 (Test: Verify data via UART (115200 baud) and CAN (ID 0x100)).

11. 문제 해결 (Troubleshooting)

  • SPI: Mode 2 확인, SCLK ≤ 25 MHz, CS 펄스 ≥ 20 ns (SPI: Verify Mode 2, SCLK ≤ 25 MHz, CS pulse ≥ 20 ns).
  • 리졸버: SIN/COS 차폐 케이블, EXC 전류 ≤ 28 mA (Resolver: Shielded SIN/COS cables, EXC current ≤ 28 mA).
  • 오류: Fault Register 디버깅, EXTI 풀업 확인 (Faults: Debug Fault Register, verify EXTI pull-ups).
  • 전원: VDRIVE=3.3V, AVDD/DVDD=5V (Power: VDRIVE=3.3V, AVDD/DVDD=5V).

12. 추가 자료 (Additional Resources)

  • 데이터시트: AD2S1210 Rev. B, AD2S1210-EP Rev. A (Datasheets: AD2S1210 Rev. B, AD2S1210-EP Rev. A).
  • 애플리케이션 노트: AN-1073, CN-0192, CN0276 (Application notes: AN-1073, CN-0192, CN0276).
  • 평가 키트: EVAL-AD2S1210SDZ, FMCMOTCON2-EBZ (Evaluation kits: EVAL-AD2S1210SDZ, FMCMOTCON2-EBZ).

 

반응형