왜 LED는 계속 High 상태인가 1

Nitroblue 1·2025년 9월 19일

디버깅 지옥 시작

Debug #1 : SVC 호출 여부 확인

gpio_toggle()과 sleep_ms()에서 syscall을 호출할 때, 실제로 svc_call()을 통해 SVC 핸들러 (svcall_rust)에 도달하고 있는가?

Check : svcall_rust() 내부에 rtt 찍어본다.
extern "C" fn svcall_rust(frame: &mut ExceptionFrame) {
        let call_id = (frame.r0 & 0xFF) as u8;

        rprintln!("[SVC] svcall_rust called with ID: {}", call_id);

        SVC_COUNTER.fetch_add(1, Ordering::Relaxed);
        if call_id == abi::NOW_MS {
            NOW_COUNT.fetch_add(1, Ordering::Relaxed);
        }

        let ret = unsafe {
            kernel_dispatch(call_id, frame.r1, frame.r2, frame.r3, frame.r12)
        };
        frame.r0 = ret;
    }

실행 결과, SVC call은 잘 되지만, 다음 task가 돌아가지 않았다. 즉, 한 번만 호출된 것.

 Terminal                                                                            
[mini-os] Booting
11:35:31.961: p0=0x200007F8 p1=0x20000BF8 p2=0x20000FF8
11:35:31.961: Starting scheduler...
11:35:31.961: [SVC] svcall_rust called with ID: 3

이를 통해 예측할 수 있는 오류 원인은

첫 Task 실행 후 Context Switch가 일어나지 않았다.

  • SysTick interrupt가 발생하지 않으면 PendSV도 발생하지 않고, 결과적으로 다른 Task로 전환되지 않는다.
  • 그러면 Task0만 실행되고, gpio_toggle() 한 번 실행 후 무한 sleep_ms()를 도는 것이다.

그러면 이제 SysTick()에서 interrupt가 잘 발생하고 있는지 확인해보자.

#[exception]
    fn SysTick() {
        rprintln!("[SysTick] interrupt fired");
        unsafe { core::ptr::write_volatile(ICSR, 1 << 28); }
    }

실행 결과, rtt가 무한으로 찍히고 있었다.
-> 일단 SysTick()은 잘 호출되고 있었다. 즉, init_systick_50us()에서 설정한 SysTick 타이머가 정상적으로 작동한다는 것이다
-> 따라서 원인을 더욱 좁혀보자면

PendSV 핸들러가 실행되지 않는다!

0개의 댓글