DSP 개요#

SP500 DSP API를 사용하면 REGULUS Cortex-A53 호스트의 애플리케이션이 Vision DSP에서 연산을 실행할 수 있습니다. API는 공유 라이브러리 libsp500.so 하나와 C 헤더 네 개로 구성됩니다.

지원 연산#

연산

헤더

설명

Letterbox

sp500/letterbox.h

종횡비를 유지한 리사이즈와 상수 패딩입니다. 카메라 프레임을 고정 크기의 모델 입력으로 만들고, 검출 결과를 원본 프레임 좌표로 되돌리는 데 필요한 배율과 패딩을 반환합니다.

Log-mel spectrogram

sp500/log_mel.h

float32 PCM에서 Whisper 방식의 log-mel spectrogram을 계산합니다. Whisper, Qwen3-ASR 같은 음성 모델용이며, CPU 참조 구현도 포함합니다.

YOLO decode

sp500/yolo.h

YOLO 네트워크의 raw 출력 텐서를 검출 결과 목록으로 변환합니다. 박스 디코딩, 신뢰도 필터링, 중복 제거를 DSP 왕복 한 번으로 처리하며 detection, segmentation, pose를 지원합니다.

sp500/dsp.h는 기반 헤더로, 상태 코드, DSP 연결, 공유 메모리, 버퍼를 정의합니다. 각 모듈 헤더가 이 헤더를 포함하므로 필요한 모듈 헤더만 포함하면 됩니다.

구조#

 Application (Cortex-A53)
        |  sp500_* calls
        v
 libsp500.so  ----------------------->  Vision DSP firmware
        |        request / completion          |
        v                                      v
 +----------------------- shared-memory window ------------------------+
 |  input and output buffers, read and written in place by the DSP     |
 |  and, through their physical address, by the NPU                     |
 +---------------------------------------------------------------------+
  • 애플리케이션은 호스트에서 API를 호출합니다. 호출할 때마다 DSP 펌웨어에 요청을 하나 보내고 완료될 때까지 기다립니다.

  • 텐서는 버퍼로 전달합니다. 공유 메모리 영역에 할당한 버퍼는 DSP가 그 자리에서 직접 읽고 씁니다. 일반 애플리케이션 메모리에 있는 버퍼는 공유 메모리를 거쳐 전달되므로 방향마다 복사가 한 번씩 발생합니다.

  • 공유 메모리 영역은 물리적으로 연속되어 있습니다. 공유 메모리 버퍼의 물리 주소를 NPU 런타임에 넘기면, DSP와 NPU가 복사 없이 같은 메모리를 사용합니다.

API 설계#

순수 C와 안정적인 ABI#

헤더는 순수 C이며 <stdint.h>와 <stddef.h>만 포함합니다. C는 물론 모든 C++ 컴파일러와 표준 라이브러리, C FFI를 지원하는 모든 언어에서 사용할 수 있습니다. 헤더가 정의하는 모든 이름은 sp500_ 또는 SP500_으로 시작합니다.

함수는 공유 라이브러리의 ABI를 구성하며 다음 규칙을 따릅니다.

  • 모든 함수는 sp500_status(int32_t) 또는 고정 폭 스칼라를 반환합니다. 열거형은 상수 이름만 정의하며, 값은 ABI 경계에서 int32_t 또는 uint32_t로 전달됩니다.

  • 구조체는 값으로 전달하거나 반환하지 않고 포인터로만 전달합니다.

  • 모든 구조체는 0이어야 하는 reserved 배열로 끝납니다. 이후 버전에서 이 필드에 의미가 부여되더라도 값 0은 현재 동작을 뜻합니다.

  • 어떤 함수도 예외를 던지지 않습니다.

파라미터 구조체와 기본값#

각 연산은 파라미터 구조체를 받고, 파라미터 구조체마다 기본값을 채우는 *_params_init() 함수가 있습니다. 기본값이 모두 0은 아니므로 필드를 설정하기 전에 항상 init 함수를 호출하세요. 모든 필드가 0인 구조체는 필수 필드 값이 0이면 유효하지 않으므로 거부됩니다. 하지만 0으로 채운 뒤 필수 필드만 설정한 구조체는 나머지 옵션이 기본값이 아닌 0으로 실행됩니다.

버퍼#

모든 텐서는 sp500_buffer입니다. 버퍼가 자신의 메모리 위치를 기록하므로 같은 함수가 두 종류의 버퍼를 모두 받습니다.

생성 함수

메모리

비용

sp500_buffer_alloc()

공유 메모리 영역

복사 없음. sp500_buffer_release()로 해제합니다.

sp500_buffer_wrap()

애플리케이션이 이미 가진 메모리

호출마다 방향별로 한 번씩 복사합니다. 해제할 필요가 없습니다.

sp500_buffer_none()

없음

선택적 텐서를 사용하지 않는다고 표시합니다.

크기가 큰 텐서와 NPU도 읽고 쓰는 텐서에는 공유 메모리 버퍼를 사용하세요.

스레드#

모든 함수는 여러 스레드와 여러 프로세스에서 동시에 호출할 수 있습니다. 각 DSP 호출은 왕복이 끝날 때까지 모든 스레드와 프로세스가 공유하는 잠금 하나를 잡으므로, 동시 호출은 안전하지만 한 번에 하나씩 실행됩니다. 여러 호출을 하나의 원자적 단위로 묶으려면 sp500_dsp_lock()과 sp500_dsp_unlock()으로 감싸세요.

상태 코드#

모든 호출은 sp500_status를 반환합니다. SP500_OK는 0이고 모든 오류는 음수이므로, rc != SP500_OK와 rc < 0 모두 올바른 검사입니다. sp500_status_string()은 코드를 문자열로 변환합니다. 출력 값은 SP500_OK를 반환했을 때만 유효합니다.

코드

값

의미

SP500_OK

0

완료되었으며 출력 버퍼가 유효합니다.

SP500_ERR_INVALID_ARG

-1

파라미터가 없거나 범위를 벗어났거나 다른 파라미터와 맞지 않습니다.

SP500_ERR_UNSUPPORTED

-2

모듈이 해당 조합을 실행할 수 없습니다.

SP500_ERR_BUFFER_TOO_SMALL

-3

전달한 버퍼가 결과를 담기에 너무 작습니다.

SP500_ERR_NOT_READY

-4

sp500_dsp_open()이 성공하지 않았습니다.

SP500_ERR_NO_MEMORY

-5

호스트 또는 공유 메모리 할당에 실패했습니다.

SP500_ERR_TIMEOUT

-6

DSP가 기한 내에 응답하지 않았습니다.

SP500_ERR_DSP

-7

DSP가 실패를 보고했습니다.

SP500_ERR_INTERNAL

-8

예상하지 못한 내부 상태입니다.

이후 버전에서 코드가 추가될 수 있으므로 알 수 없는 음수 값은 일반 실패로 처리하세요. 다음 두 결과는 오류가 아니라 성공입니다. 검출할 대상이 없는 프레임은 검출 수 0과 함께 SP500_OK를 반환하고, 샘플 수가 hop 하나보다 적은 log-mel 요청은 프레임 수 0과 함께 SP500_OK를 반환합니다.

버전 관리#

라이브러리 버전이 곧 API 버전입니다. sp500_version()은 로드된 라이브러리의 버전을 SP500_VERSION_INT와 같은 방식(major * 10000 + minor * 100 + patch)으로 반환하고, sp500_version_string()은 문자열로 반환합니다.

  • Major 릴리스는 라이브러리 SONAME이 바뀌므로 애플리케이션을 다시 빌드해야 합니다.

  • Minor와 patch 릴리스는 다시 빌드하지 않고 라이브러리만 교체하면 됩니다.

라이브러리는 세 가지 이름으로 설치됩니다.

libsp500.so       -> libsp500.so.1        (link time: what -lsp500 finds)
libsp500.so.1     -> libsp500.so.1.0.0    (run time: the SONAME)
libsp500.so.1.0.0                         (the library itself)

애플리케이션 바이너리에는 libsp500.so.1이 기록됩니다. 장치에 라이브러리를 복사하는 방법은 DSP 프로그래밍 가이드를 참고하세요.