# HARDWARE.md — STM32F407VGT6 핀맵 & 배선 (SHT30 단일 보드) 대상 MCU: **STM32F407VGT6** (LQFP-100), Cortex-M4F @168MHz. 권장 기준 보드: STM32F4-DISCOVERY 계열 또는 동등한 커스텀 PCB. 핀은 LQFP-100 패키지 기준. 이 문서는 **SHT30 온습도 보드**의 핀 배치, 외부 배선, 전원, 클럭원, 그리고 반드시 해소해야 하는 **핀 충돌(USART2 ↔ LAN8720 MDIO, 둘 다 PA2)** 을 다룬다. > 사이트/하드웨어 결정이 필요한 항목은 `TODO(hw):` 로 표시했다. 코드는 합리적 기본값으로 컴파일된다. --- ## 0. ⚠️ PA2 핀 충돌 (USART2 TX vs. LAN8720 MDIO) — ✅ 코드에서 해소 완료 **문제(배경).** 초기에는 디버그 로그 UART 가 **USART2 (PA2=TX / PA3=RX)** 로 설계되었으나(ST-Link VCP 호환), LAN8720 RMII 연결에서 **MDIO 신호 역시 PA2 (`ETH_MDIO`, AF11)** 를 사용한다. PA2 를 두 기능이 동시에 점유할 수 없고, RMII 동작에 MDIO(PHY 레지스터 설정/링크 폴링)가 필수이므로 PA2 는 반드시 `ETH_MDIO` 여야 한다. **✅ 해소(코드 반영됨).** 로그 UART 를 **USART3 (PD8=TX / PD9=RX, AF7)** 로 이동했다. 반영 위치: - [`common/applog.c`](../common/applog.c): `HAL_UART_MspInit`/`applog_init` 가 USART3 + GPIOD(PD8/PD9, AF7)로 초기화. - [`common/app_config.h`](../common/app_config.h): `APP_LOG_UART_BAUD` 주석을 USART3 PD8/PD9 로 정정. PA2 는 `ETH_MDIO` 전용이며, 코드에는 USART2 사용처가 더 이상 없다. ### 권장 해소안 (택일) | 방안 | 로그 UART 핀 | AF | ST-Link VCP | 권장도 | 비고 | |------|-------------|----|-------------|--------|------| | **A. USART3 → PD8(TX)/PD9(RX)** | PD8/PD9 | AF7 | 별도 USB-UART 어댑터 필요 | **★ 권장** | RMII/I2C 와 충돌 없음. PD 포트는 본 설계에서 비어 있음 | | B. USART1 → PA9(TX)/PA10(RX) | PA9/PA10 | AF7 | 별도 어댑터 | 차선 | PA9/PA10 미사용. 단, PA9 는 USB-OTG VBUS 와 보드에 따라 충돌 가능 — 디스커버리 보드 확인 | | C. USART2 유지 + RMII 포기 | PA2/PA3 | — | VCP 사용 | ✗ 불가 | 이더넷이 필수이므로 채택 불가 | **채택: 방안 A — 로그 UART = USART3 (PD8 TX / PD9 RX, AF7, 115200 8N1).** USART3 의 다른 핀쌍(PB10/PB11, PC10/PC11)은 RMII(PB11=TXEN)·SHT30 I2C 와 겹치므로 **PD8/PD9 를 사용한다.** > **상태:** > 1. ✅ 코드 반영됨: `applog.c` 가 USART3 + GPIOD(PD8/PD9, AF7)로 초기화, `app_config.h` 주석 정정. > 2. ⬜ `TODO(hw)`: ST-Link VCP(PA2/PA3)를 못 쓰므로 운영 로그는 **외부 3.3V USB-UART 어댑터를 PD8/PD9 에 연결**. > 본 문서의 모든 표는 **방안 A(USART3 PD8/PD9)** 기준이다. --- ## 1. LAN8720 Ethernet PHY (RMII) STM32 내장 ETH MAC + 외부 LAN8720 PHY, **RMII 모드**. 모든 RMII 핀은 대체기능 **AF11 (`ETH`)**. | STM32 핀 | 신호 (RMII) | AF | LAN8720 핀 | 방향(MCU 기준) | 비고 | |----------|--------------------|------|-----------|----------------|------| | **PA1** | `ETH_REF_CLK` | AF11 | nINT/REFCLKO | 입력 | 50MHz 기준 클럭 입력 (§1.1) | | **PA2** | `ETH_MDIO` | AF11 | MDIO | 양방향 | ⚠️ §0 충돌 핀 — USART2 금지 | | **PC1** | `ETH_MDC` | AF11 | MDC | 출력 | 관리 클럭 | | **PA7** | `ETH_CRS_DV` | AF11 | CRS_DV | 입력 | 캐리어 감지/데이터 유효 | | **PC4** | `ETH_RXD0` | AF11 | RXD0 | 입력 | 수신 데이터 0 | | **PC5** | `ETH_RXD1` | AF11 | RXD1 | 입력 | 수신 데이터 1 | | **PB11** | `ETH_TX_EN` | AF11 | TXEN | 출력 | 송신 인에이블 | | **PB12** | `ETH_TXD0` | AF11 | TXD0 | 출력 | 송신 데이터 0 | | **PB13** | `ETH_TXD1` | AF11 | TXD1 | 출력 | 송신 데이터 1 | 추가 배선(RMII 표준): | LAN8720 핀 | 연결 | 비고 | |-----------|------|------| | MDIO 풀업 | 1.5kΩ → 3.3V | 권장 | | nRST | MCU GPIO 또는 RC 리셋 | `TODO(hw):` 소프트 리셋 핀 배정 시 GPIO 1개 추가(예 PE0). 미배정 시 전원-온 RC 리셋 | | 25MHz XTAL / OSC | §1.1 클럭 구성에 따라 | | | RXER | (선택) 미사용 가능 | RMII 에서 생략 가능 | > RMII 는 RXD2/RXD3/TXD2/TXD3/COL/CRS/RX_CLK/TX_CLK 가 **없다**(MII 대비 핀 절감). 위 9개 + MDC/MDIO 가 전부다. ### 1.1 RMII 50MHz REF_CLK 소싱 (중요) RMII 는 MAC 과 PHY 가 **공통 50MHz REF_CLK** 를 공유해야 한다. PA1(`ETH_REF_CLK`)은 MCU **입력**이며, 이 50MHz 를 어디서 만들지가 보드 설계의 핵심이다. 두 가지 표준 구성: 1. **PHY 가 50MHz 생성 → MCU 로 공급 (권장, 디스커버리 보드 방식)** - LAN8720 에 25MHz 크리스털을 달고, PHY 내부에서 50MHz 를 만들어 `REFCLKO` → MCU `PA1` 으로 공급. - 보드에 따라 MCU `MCO1(PA8)` 로 25MHz 를 PHY 에 주고 PHY 가 50MHz 를 되돌리는 변형도 있음. 2. **외부 50MHz 오실레이터 → MCU PA1 + PHY 동시 공급** - 50MHz 캔 오실레이터 1개로 두 칩에 동시 분배. 가장 단순하고 안정적. > `TODO(hw):` 보드 설계에 맞춰 1) 또는 2) 중 하나를 확정하고 BOM/스템핑을 결정한다. > 펌웨어 측 RCC `RMII` 클럭 선택(`SYSCFG->PMC.MII_RMII_SEL=RMII`)은 [`common/net.c`](../common/net.c)/`ethernetif.c` > 초기화에서 처리한다(코드 기본값 = RMII). --- ## 2. SHT30 온습도 센서 (`-DBOARD_SHT30`, sensor_id=2) Sensirion SHT30 (한진데이터 P4422-3 모듈), I2C. RPi `sht30_monitor.py` 와 동일 규약. ### 2.1 I2C 배선 | STM32 핀 | 신호 | AF | I2C | 비고 | |----------|------|----|-----|------| | **PB6** | `I2C1_SCL` | AF4 | I2C1 | 오픈드레인, 외부 풀업 필요 | | **PB7** | `I2C1_SDA` | AF4 | I2C1 | 오픈드레인, 외부 풀업 필요 | - 7-bit 주소: **0x44** (`APP_SHT30_I2C_ADDR`). HAL 호출 시 `0x44<<1`. - 명령: `0x2C06` (high-repeatability, clock-stretch off) → ~20ms 대기 → 6바이트 read. - 풀업: SCL/SDA 각각 **4.7kΩ → 3.3V** (모듈에 내장 풀업이 있으면 생략). I2C 속도 100kHz(Standard) 권장. - plausibility 범위(벗어나면 `metric_status="out_of_range"`): T `[-40, 125]°C`, RH `[0, 100]%` ([`common/app_config.h`](../common/app_config.h)). 운영 경보 임계(고온/저온/고습/저습 → SMS)는 **서버 `php/config.php` 의 `METRIC_*` 상수**가 판정한다(펌웨어는 원값만 보고). ``` SHT30 모듈 STM32 ┌────────┐ │ VDD ──┼────────────── 3.3V ──┬──[4.7kΩ]──┐ ┌──[4.7kΩ]── 3.3V │ SCL ──┼────────────── PB6 ───┘ │ │ │ SDA ──┼────────────── PB7 ────────────────┼───┘ │ GND ──┼────────────── GND │ │ ADDR ─┼── GND (주소 0x44; VDD 면 0x45) │ └────────┘ ``` > `TODO(hw):` ADDR 핀 결선으로 0x44(ADDR→GND) / 0x45(ADDR→VDD) 가 결정된다. 본 설계는 **0x44** 고정. ### 2.2 SHT30 보드 핀 요약 | 핀 | 용도 | |----|------| | PB6 / PB7 | I2C1 SCL / SDA (0x44) | | (RMII 9핀) | §1 표 그대로 — **단 PB11/PB12/PB13 가 RMII 에 쓰임에 주의** | | PD8/PD9 | 로그 UART (USART3, §0 방안 A) | | 상태 LED | §3 | > 주의: I2C1 은 PB6/PB7 를 쓰고 RMII 는 PB11/PB12/PB13 을 쓴다 — **PB 포트 내부에서 충돌 없음**. --- ## 3. 공통 주변장치 — 상태 LED, 클럭원, 워치독/RTC, 전원 ### 3.1 상태 LED ([`common/bsp.h`](../common/bsp.h) `bsp_led_*`) | 핀 | 용도 | 비고 | |----|------|------| | **PD12** | 상태 LED (녹색) | `TODO(hw):` 디스커버리 보드 온보드 LED(PD12~PD15) 사용 가정. 커스텀 PCB 면 임의 GPIO 1개로 변경 | 권장 점멸 패턴(운영 가시성): 부팅=점등 / 정상 보고=느린 토글 / 망 단절·TLS 실패=빠른 점멸 / `bsp_fatal()`=고속 점멸. ### 3.2 시스템 클럭 / 오실레이터 | 항목 | 값 | 비고 | |------|----|------| | HSE | **8MHz 크리스털** | `SystemClock_Config()` 가 PLL 로 168MHz 생성([`common/bsp.h`](../common/bsp.h) 주석) | | SYSCLK | 168MHz | Cortex-M4F | | RMII REF_CLK | 50MHz | §1.1 (HSE 와 별개 경로) | > `TODO(hw):` 보드에 HSE 8MHz 크리스털 + 부하 커패시터 실장 확인. 없으면 `SystemClock_Config` 의 HSE 값 정정 필요. ### 3.3 RTC 클럭원 (SNTP → RTC 시간 보존) | 항목 | 권장 | 비고 | |------|------|------| | RTC 클럭원 | **LSE 32.768kHz 크리스털** | TLS 인증서 유효기간 검증 + `timestamp` 필드용. 정전 시 VBAT 로 시간 보존 | | 대안 | LSI(~32kHz, 내장) | 정밀도 낮음. SNTP 로 주기 보정하면 허용. **VBAT 백업 불가** | | VBAT | 코인셀(CR2032) 또는 VBAT→3.3V | LSE + 백업 도메인 유지용. 미실장 시 매 부팅 SNTP 재동기 필요 | > `TODO(hw):` LSE 크리스털 + VBAT 백업 실장 여부 확정. 미실장이면 [`common/timesync.c`](../common/timesync.c) 는 매 부팅 SNTP 동기에 의존(이식 계획 R4: SNTP 실패 시 경보). ### 3.4 워치독 (IWDG) | 항목 | 값 | 비고 | |------|----|------| | IWDG 클럭원 | **LSI (~32kHz, 내장)** | IWDG 는 항상 LSI 구동(별도 핀 없음) | | 타임아웃 | `APP_WATCHDOG_TIMEOUT_MS = 20000` (20s) | 이 시간 내 `watchdog_refresh()` 없으면 MCU 리셋([`common/watchdog.h`](../common/watchdog.h)) | | BOR | 활성 권장 | 브라운아웃 리셋(이식 계획 Phase 7) — `TODO(hw):` 옵션 바이트로 BOR 레벨 설정 | ### 3.5 전원 | 레일 | 용도 | 비고 | |------|------|------| | 3.3V | MCU VDD/VDDA, LAN8720, SHT30, 풀업 | LAN8720 RMII I/O 는 3.3V. PHY 전류 여유(~수십 mA) 확보 | | VDDA | ADC/PLL 기준 | 0.1µF + 1µF 디커플링, 페라이트 비드 권장 | | VBAT | RTC 백업(§3.3) | 코인셀/점퍼 | | 디커플링 | 각 VDD 핀당 0.1µF + 벌크 4.7µF | 표준 STM32 권장 | > `TODO(hw):` PoE/외부 12V→3.3V 등 실제 급전 방식은 설치 환경에 따라 확정. RPi 가 쓰던 5V USB 어댑터 재사용 가능(5V→3.3V 레귤레이터 추가). --- ## 4. 최종 권장 핀맵 (전체 통합) > §0 방안 A(로그 UART = USART3 PD8/PD9) 채택을 가정한 **최종 권장** 핀맵. 충돌 해소 완료 상태. | STM32 핀 | SHT30 보드 | 기능 | AF | 충돌 여부 | |----------|------------|------|----|-----------| | PA1 | ✔ | ETH_REF_CLK (RMII 50MHz in) | AF11 | OK | | PA2 | ✔ | **ETH_MDIO** (USART2 금지) | AF11 | **§0 해소** | | PA7 | ✔ | ETH_CRS_DV | AF11 | OK | | PB6 | ✔ | I2C1_SCL | AF4 | OK | | PB7 | ✔ | I2C1_SDA | AF4 | OK | | PB11 | ✔ | ETH_TX_EN | AF11 | OK | | PB12 | ✔ | ETH_TXD0 | AF11 | OK | | PB13 | ✔ | ETH_TXD1 | AF11 | OK | | PC1 | ✔ | ETH_MDC | AF11 | OK | | PC4 | ✔ | ETH_RXD0 | AF11 | OK | | PC5 | ✔ | ETH_RXD1 | AF11 | OK | | PD8 | ✔ | USART3_TX (로그) | AF7 | OK (방안 A) | | PD9 | ✔ | USART3_RX (로그) | AF7 | OK (방안 A) | | PD12 | ✔ | 상태 LED | — | OK | | OSC_IN/OUT | ✔ | HSE 8MHz | — | OK | | PC14/PC15 | ✔ | LSE 32.768kHz (RTC, 선택) | — | §3.3 | | VBAT | ✔ | RTC 백업 전원(선택) | — | §3.3 | **미사용/주의:** PA2 는 **절대 USART2_TX 로 설정하지 말 것**(이더넷 MDIO 전용). PA3 도 USART2_RX 로 쓰지 않는다. --- ## 5. 핀 충돌 점검표 (요약) | 잠재 충돌 | 상태 | 해소 | |-----------|------|------| | **PA2: USART2_TX ↔ ETH_MDIO** | ✅ 해소(코드) | 로그 UART 를 USART3(PD8/PD9)로 이동(`applog.c`). PA2=ETH_MDIO 고정 | | USART3 PB10/PB11 ↔ ETH_TX_EN(PB11) | 회피됨 | USART3 를 PD8/PD9 핀쌍으로 사용 | | USART3 PC10/PC11 ↔ ETH RXD(PC4/PC5) | 회피됨 | 동일(PD8/PD9 사용) | | 로그 UART(PD8/PD9) ↔ 상태 LED(PD12) | 없음 | 같은 D 포트, 다른 핀 | | I2C1(PB6/PB7) ↔ RMII(PB11~13) | 없음 | PB 포트 내 핀 분리 | | RMII 클럭 게이팅(`bsp.c`) | 무해 | `bsp.c` 가 공통 클럭으로 GPIOA/B/C/D 를 켬. ETH MspInit 도 GPIOA/B/C 를 자체 enable(중복 무해) | > 결론: 코드 기준으로 **남은 핀 충돌은 없다.** PA2 충돌은 로그 UART 를 USART3 PD8/PD9 로 옮겨 해소했고 > (코드 반영 완료), 나머지는 모두 포트 내 핀 분리로 충돌이 없다. 남은 항목은 §0의 외부 USB-UART 어댑터 배선 > 과 §3 의 클럭원/전원 `TODO(hw)` 뿐이다.