01signal.com

디지털 출력 핀에 일반 헤드폰을 연결하여 음악 듣기

이 웹 페이지는 Smart Zynq 보드의 기능을 살펴보는 소규모 프로젝트 모음에 속하는 문서입니다.

이 프로젝트는 HelloFPGA에도 게시되어 있습니다. 이 사이트는 중국어 사용자에게 추천됩니다.

소개

이 튜토리얼은 일반 헤드폰을 Smart Zynq 보드에 연결하여 음악을 듣는 방법을 설명합니다. 이 프로젝트의 목적은 FPGA로 연속 데이터를 보내기 위해 Xillybus 스트림을 사용하는 방법을 시연하는 것입니다. 또한 PWM(Pulse Width Modulation) 변조기를 구현하는 Verilog 코드도 함께 소개합니다.

여기에 보이는 코드는 오디오 출력을 구현하는 방법을 보여주는 예제가 아닙니다. 아날로그 출력을 구현할 때 일반적으로 사용하는 방법은 시그마-델타(Sigma-Delta)라고 하는 더 복잡한 기법입니다. 이 기법도 FPGA에서 구현할 수 있지만, 이론적 배경을 이해하기가 훨씬 어렵습니다.

이 구현의 또 다른 단점은 샘플 레이트(sample rate)가 정확하지 않다는 점입니다(48000Hz 대신 48828Hz). 이 문제는 로직이 사용하는 클록의 주파수를 변경하면 쉽게 해결할 수 있습니다. 다만 이 예제는 정확성보다 단순함에 초점을 두고 있으므로, 이를 위한 클록 조작 방법은 여기서 다루지 않습니다.

이 데모에 필요한 준비물은 다음과 같습니다.

Vivado 프로젝트 준비

데모 번들(demo bundle)의 zip 파일(부트 파티션 키트)에서 새 Vivado 프로젝트를 만드세요. 텍스트 편집기로 verilog/src/xillydemo.v를 여세요. 코드에서 "PART 2"라고 표시된 부분을 삭제하고, 그 자리에 아래 코드 조각을 삽입하세요.

   /*
    * PART 2
    * ======
    *
    * This code demonstrates a PWM-based audio output
    */

   reg [10:0]   pwm_level, threshold_left, threshold_right;
   reg 		pwm_left, pwm_right;
   reg 		fifo_out_valid;
   wire [31:0] 	fifo_out;
   wire 	fifo_empty;

   wire 	fifo_rd_en = !fifo_out_valid && !fifo_empty;
   wire 	next_word = (pwm_level == 11'h7ff);

   assign J6 = { pwm_right, pwm_left };

   always @(posedge bus_clk)
     begin
	pwm_level <= pwm_level + 1;

	if (next_word && fifo_out_valid)
	  begin
	     // The audio samples are signed integers. Change them to
	     // unsigned by adding 1024.
	     threshold_left <= fifo_out[15:5] + 1024;
	     threshold_right <= fifo_out[31:21] + 1024;
	  end
	else if (next_word) // FIFO's output not valid, keep silent
	  begin
	     threshold_left <= 0;
	     threshold_right <= 0;
	  end

	pwm_left <= (threshold_left > pwm_level);
	pwm_right <= (threshold_right > pwm_level);

	if (fifo_rd_en)
	  fifo_out_valid <= 1;
	else if (next_word)
	  fifo_out_valid <= 0;
     end

   // 32-bit FIFO for audio samples
   fifo_32x512 fifo_32
     (
      .clk(bus_clk),
      // Interface with Xillybus IP core
      .srst(!user_w_write_32_open),
      .din(user_w_write_32_data),
      .wr_en(user_w_write_32_wren),
      .full(user_w_write_32_full),

      // Interface with application logic
      .rd_en(fifo_rd_en),
      .dout(fifo_out),
      .empty(fifo_empty)
      );

   // Send the text "PWM" to reassure that the correct bitstream is used.
   assign user_r_read_32_eof = 0;
   assign user_r_read_32_empty = 0;
   assign user_r_read_32_data = 32'h0a_4d_57_50; // "PWM" + LF

또는 변경이 완료된 xillydemo.v 파일을 여기에서 내려받아도 됩니다.

업데이트된 프로젝트에서 데모 번들(demo bundle)용 비트스트림(bitstream) 파일을 만들 때와 같은 방법으로 비트스트림 파일을 만드세요. 그리고 비트스트림 파일을 같은 방법으로 TF 카드에 복사하세요(기존 xillydemo.bit 파일을 이 프로젝트에서 만든 파일로 덮어쓰세요).

헤드폰 연결

오디오 신호가 나오는 I/O 핀, 즉 J6/1(왼쪽 귀) 또는 J6/2(오른쪽 귀)에 50Ω~200Ω 저항을 연결하세요. J6을 찾으려면 Smart Zynq 보드 뒷면에서 "Bank 33 VCCIO Vadj"라고 적힌 부분을 찾으세요. 이 표시 근처에 있는 핀 열이 우리가 사용할 핀 헤더입니다. 따라서 J6/1은 HDMI 커넥터에 가장 가까운 핀입니다.

저항의 다른 쪽 끝을 헤드폰 플러그의 팁 부분에 연결하세요. 이를 위해 악어 클립을 사용할 수 있습니다.

헤드폰 플러그의 슬리브(sleeve) 부분을 Smart Zynq의 접지(GND)에 연결하세요. 핀 헤더의 접지 핀은 J6/35 또는 J6/36에 있습니다. 다만 이 핀들은 전원 공급 핀 근처에 있으므로 사용하지 않는 것이 좋습니다.

대신 J6/3부터 J6/34까지의 핀 중 아무 핀이나 접지로 사용할 수 있습니다. FPGA는 이 핀들을 출력 핀으로 간주하여 논리 '0' 레벨로 유지합니다. 따라서 이 핀들을 접지로 사용할 수 있습니다.

보드 커넥터 중 하나의 외부 금속 부분에 악어 클립을 연결하는 방법으로도 접지를 얻을 수 있습니다. 예를 들어 이더넷 커넥터, HDMI 커넥터, 또는 USB 커넥터 중 하나가 여기에 해당합니다.

보드 시작

평소처럼 Smart Zynq의 전원을 켜세요(또는 재부팅하세요). 다음 단계는 올바른 비트스트림 파일이 FPGA(PL 부분)에 로드되었는지 확인하는 것입니다.

shell 프롬프트에서 "head /dev/xillybus_read_32" 명령을 입력하세요. 이 명령은 /dev/xillybus_read_32에서 처음 몇 행을 읽어 결과를 출력합니다.

# head /dev/xillybus_read_32
PWM
PWM
PWM
PWM
PWM
PWM
PWM
PWM
PWM
PWM

이 명령에서 출력이 없거나 위에 표시된 것과 다른 출력이 나온다면 잘못된 비트스트림이 사용되고 있는 것입니다.

오디오 파일 재생

오디오 파일을 Xillinux 파일 시스템에 복사하세요. 즉, Linux 시스템 안의 명령에서 해당 오디오 파일을 사용할 수 있어야 합니다.

이 파일은 WAV 형식이어야 합니다. 비압축 PCM, 두 채널, s16le 형식이어야 합니다(이것은 거의 모든 WAV 파일이 사용하는 형식입니다). 샘플링 주파수는 48000Hz여야 하지만, 44100Hz여도 비교적 잘 동작합니다.

적절한 오디오 파일을 이 링크에서 내려받을 수 있습니다.

Linux 시스템으로 파일을 복사하는 방법은 여러 가지가 있습니다. 예를 들어 이더넷 네트워크를 사용해 다른 컴퓨터에서 Xillinux의 홈 디렉터리로 파일을 복사할 수 있습니다.

$ scp sample.wav root@192.168.1.10:~/

이 명령은 Linux shell뿐만 아니라 Microsoft Windows의 명령 프롬프트에서도 동작합니다. IP 주소(이 예제에서는 192.168.1.10)를 보드의 IP 주소로 바꾸세요.

NFS나 CIFS를 사용하는 등 Xillinux로 파일을 복사하는 다른 방법도 있습니다.

파일을 Xillinux 파일 시스템에 복사한 후 다음 명령으로 오디오를 재생하세요.

# cat sample.wav > /dev/xillybus_write_32

"sample.wav" 부분을 재생하려는 파일 이름으로 바꾸세요. 여기에 표시된 명령은 파일이 현재 디렉터리에 있을 때 동작합니다.

이 명령은 새 shell 프롬프트가 나타날 때까지 헤드폰으로 파일을 재생합니다. 한쪽 귀에서 음악이 들릴 것입니다(또는 J6/1과 J6/2를 헤드폰 플러그의 서로 다른 접점에 각각 연결했다면 양쪽 귀에서 들릴 것입니다).

이 명령은 CTRL-C로 중간에 중지할 수 있습니다.

이것으로 실용적인 방법은 끝입니다. 이 페이지의 나머지 부분에서는 동작 원리를 설명합니다.

오디오 데이터가 FPGA에 도달하는 방법

cat 명령은 오디오 파일(sample.wav)의 내용을 xillybus_write_32라는 디바이스 파일로 복사합니다. Linux 시스템에서 이는 하드웨어 드라이버로 데이터를 보내는 일반적인 방법입니다. 이 예제에서 드라이버는 Xillybus의 IP 코어(IP core)와 인터페이스합니다. 그 결과 데이터는 FPGA 로직 내부의 FIFO로 보내집니다.

위에서 제시한 Verilog 코드에서 관련 부분을 살펴보겠습니다.

   fifo_32x512 fifo_32
     (
      .clk(bus_clk),
      // Interface with Xillybus IP core
      .srst(!user_w_write_32_open),
      .din(user_w_write_32_data),
      .wr_en(user_w_write_32_wren),
      .full(user_w_write_32_full),

      // Interface with application logic
      .rd_en(fifo_rd_en),
      .dout(fifo_out),
      .empty(fifo_empty)
      );

이것은 표준 FIFO의 인스턴스화(instantiation)입니다. FIFO가 어떻게 동작하는지에 대한 일반적인 설명은 이 페이지를 참조하세요.

이 FIFO에는 FIFO에 데이터를 넣는 것과 관련된 세 개의 포트, 즉 din, wr_en, full(가득 참)이 있습니다. 이 세 포트는 모두 Xillybus IP 코어에 연결되어 있습니다. 다시 말해, 세 신호(user_w_write_32_data, user_w_write_32_wren, user_w_write_32_full)는 xillybus라는 모듈에 연결됩니다. 이렇게 함으로써 Xillybus IP 코어가 FIFO에 데이터를 쓸 수 있습니다.

Xillybus는 이 구성을 이용해 소프트웨어가 /dev/xillybus_write_32에 쓴 데이터로 FIFO를 채웁니다. Xillybus는 계속해서 가능한 한 많은 데이터를 FIFO에 쓰려고 시도하지만, 오버플로(overflow)를 일으키지는 않습니다(즉, FIFO의 full(가득 참) 신호를 따릅니다).

요약하면 다음과 같은 일이 일어납니다.

Simplified data flow diagram for data playback with Xillybus

이 모든 작업은 동시에 그리고 지속적으로 이루어집니다.

Xillybus에 대한 자세한 내용은 이 페이지 모음을 참조하세요. 특히 이 페이지가 도움이 됩니다.

오디오 신호가 만들어지는 방법

지금까지 설명은 데이터가 FPGA 내부의 애플리케이션 로직에 도달하는 방법을 설명했습니다. 이제 데이터가 어떻게 오디오로 변환되는지 살펴보겠습니다.

먼저 Verilog 코드에서 다음 행에 주목하세요.

   assign J6 = { pwm_right, pwm_left };

이 코드에 따르면 두 오디오 출력은 pwm_right와 pwm_left로 구성됩니다. 이 두 레지스터에는 다음과 같이 값이 할당됩니다.

   always @(posedge bus_clk)
     begin
	pwm_level <= pwm_level + 1;

 [ ... ]
	pwm_left <= (threshold_left > pwm_level);
	pwm_right <= (threshold_right > pwm_level);
 [ ... ]
    end

pwm_level은 단순한 카운터입니다. 이 레지스터는 11비트로 구성되어 있으므로 0부터 2047까지 센 다음 다시 0부터 시작합니다.

pwm_left의 값은 threshold_left가 pwm_level보다 클 때 '1'입니다. 즉, threshold_left는 0부터 2047까지 모든 수를 반복해서 지나가는 카운터와 비교됩니다. threshold_left의 값이 클수록 pwm_left가 '1'인 시간이 길어집니다. 이것이 PWM의 원리입니다. 펄스의 길이는 만들고자 하는 아날로그 신호의 값에 선형적으로 비례합니다.

pwm_right도 threshold_right에 대해 같은 방식으로 동작합니다.

threshold_left와 threshold_right는 Xillybus IP 코어를 통해 전송된 WAV 파일의 데이터를 담고 있습니다. 이제 이 과정을 자세히 살펴보겠습니다.

먼저 FIFO 인스턴스화 부분에서 FIFO 읽기와 관련된 부분을 살펴보겠습니다.

      // Interface with application logic
      .rd_en(fifo_rd_en),
      .dout(fifo_out),
      .empty(fifo_empty)

fifo_rd_en은 다음과 같이 정의됩니다.

wire 	fifo_rd_en = !fifo_out_valid && !fifo_empty;

따라서 FIFO의 read enable은 FIFO가 empty(비어 있음) 상태가 아니고 fifo_out_valid가 low일 때 high가 됩니다. 이제 fifo_out_valid의 정의를 살펴보겠습니다.

   always @(posedge bus_clk)
     begin
 [ ... ]
	if (fifo_rd_en)
	  fifo_out_valid <= 1;
	else if (next_word)
	  fifo_out_valid <= 0;
     end

fifo_out_valid의 의미는 이 레지스터가 high이면 FIFO의 출력이 유효하다는 것입니다. 더 정확히 말하면, fifo_out_valid는 FIFO의 출력이 아직 소비되지 않았을 때 high입니다. 따라서 이 레지스터는 fifo_rd_en이 high가 된 후 한 클록 사이클 뒤에 high로 변합니다. 이 레지스터는 next_word가 high일 때 low로 변합니다. 아래에서 보겠지만, PWM을 구현하는 로직은 next_word가 high일 때 FIFO의 출력을 소비합니다.

next_word는 다음과 같이 정의됩니다.

   wire 	next_word = (pwm_level == 11'h7ff);

pwm_level이 0부터 2047 사이의 모든 값을 지나는 카운터임을 기억하세요. 2047의 16진수 표현은 7ff입니다. 따라서 next_word는 pwm_level이 0으로 돌아가기 직전에 high가 됩니다.

next_word는 얼마나 자주 high가 될까요? bus_clk의 주파수는 100MHz입니다. next_word는 2048 클록 사이클마다 한 번씩 high가 됩니다. 100MHz ÷ 2048 ≈ 48828Hz, 즉 next_word는 초당 약 48828번 high가 됩니다.

앞서 next_word는 FIFO의 출력이 소비될 때 high가 된다고 언급했습니다. 이와 관련된 Verilog 코드 부분은 다음과 같습니다.

   always @(posedge bus_clk)
     begin
 [ ... ]

	if (next_word && fifo_out_valid)
	  begin
	     // The audio samples are signed integers. Change them to
	     // unsigned by adding 1024.
	     threshold_left <= fifo_out[15:5] + 1024;
	     threshold_right <= fifo_out[31:21] + 1024;
	  end
	else if (next_word) // FIFO's output not valid, keep silent
	  begin
	     threshold_left <= 0;
	     threshold_right <= 0;
	  end
 [ ... ]
    end

먼저, next_word가 high일 때 threshold_left와 threshold_right 양쪽 모두에 새 값이 할당된다는 점을 확인하세요. fifo_out_valid가 low이면 이 두 레지스터의 값은 0이 됩니다. 이는 FIFO로 보내지는 데이터가 없어서 FIFO가 empty(비어 있음) 상태가 된 경우입니다.

fifo_out_valid가 high이면 FIFO의 dout 포트에 오디오 샘플 값이 들어 있다는 뜻입니다. 이 값은 두 스테레오 채널의 아날로그 신호를 나타냅니다. 각 샘플에는 16비트 2의 보수(2's complement) 형식으로 표현된 두 개의 부호 있는 정수가 들어 있습니다.

왼쪽 스테레오 채널의 오디오 샘플은 fifo_out[15:0]에 담겨 있습니다. 이것은 -32768부터 32767 사이의 부호 있는 정수입니다. 최하위 5비트가 제거되므로 fifo_out[15:5]의 범위는 -1024부터 1023이 됩니다. 따라서 "fifo_out[15:5] + 1024" 수식의 결과는 0부터 2047 사이의 부호 없는 정수입니다. 이 범위는 pwm_level과 비교하기에 적합합니다.

따라서 fifo_out[15:0]이 -32768이면 threshold_left에는 0이 할당됩니다. "threshold_left > pwm_level" 조건이 결코 충족되지 않으므로 pwm_left는 항상 low를 유지합니다. 반면 fifo_out[15:0]이 32767이면 threshold_left의 값은 2047이 됩니다. 그 결과 pwm_left는 거의 항상 high입니다. 이렇게 fifo_out[15:0]이 각 펄스에서 pwm_left가 high인 시간을 제어합니다. fifo_out[31:16]도 같은 방식으로 pwm_right를 제어합니다.

전체 메커니즘을 요약하면 다음과 같습니다. next_word는 2048 클록 사이클마다 한 번 high가 됩니다. next_word가 high이면 FIFO의 출력이 조정되어 threshold_left와 threshold_right로 복사됩니다. 이 과정에서 FIFO의 출력이 소비되므로 fifo_out_valid가 low가 됩니다. 따라서 FIFO가 empty(비어 있음) 상태가 아니라면 fifo_rd_en이 high가 되어 FIFO에서 새 오디오 샘플을 읽습니다.

Xillybus IP 코어가 sample.wav의 내용으로 이 FIFO를 채운다는 점을 기억하세요. 따라서 sample.wav의 내용에서 threshold_left와 threshold_right로 오디오 샘플이 흐르게 됩니다. 앞서 언급했듯이 next_word는 초당 약 48828번 high가 됩니다. 이것이 이 메커니즘의 샘플 레이트(sample rate)입니다.

threshold_left는 pwm_left가 high인 시간의 비율을 제어합니다. threshold_right와 pwm_right의 관계도 마찬가지입니다. 그리고 마지막으로 pwm_right와 pwm_left는 J6이라는 출력 포트에 연결되므로, 이 신호들이 핀 헤더에 나타납니다.

next_word가 high일 때 두 가지 일이 동시에 발생한다는 점에 유의하세요. 오디오 샘플 하나가 소비되고, pwm_level이 0부터 다시 카운트를 시작합니다. 따라서 오디오 샘플마다 펄스가 하나씩 생성됩니다.

"PWM" 출력하기

앞에서 FPGA에 올바른 비트스트림이 들어 있는지 확인하기 위해 "head /dev/xillybus_read_32" 명령을 사용하라고 안내했습니다. 그때 기대했던 결과는 "PWM"이 여러 번 출력되는 것이었습니다. 이것은 Verilog 코드의 다음 부분으로 구현됩니다.

   // Send the text "PWM" to reassure that the correct bitstream is used.
   assign user_r_read_32_eof = 0;
   assign user_r_read_32_empty = 0;
   assign user_r_read_32_data = 32'h0a_4d_57_50; // "PWM" + LF

변경 전의 xillydemo.v를 보면 user_r_read_32_rden, user_r_read_32_data와 user_r_read_32_empty(비어 있음)가 FIFO에 연결되어 있었을 것입니다. Xillybus IP 코어는 이 신호들을 사용해 FIFO에서 데이터를 읽고, 그 데이터를 /dev/xillybus_read_32로 제공되는 데이터 스트림으로 만듭니다.

xillydemo.v를 변경하기 전에는 이 신호들이 Xillybus IP 코어가 데이터를 쓰는 바로 그 FIFO에 연결되어 있었습니다. 그 결과 루프백(loopback)이 만들어졌습니다. 소프트웨어가 /dev/xillybus_write_32에 쓴 데이터는 먼저 Xillybus IP 코어에 의해 FIFO에 들어갔고, Xillybus IP 코어가 그 데이터를 FIFO에서 다시 읽어 /dev/xillybus_read_32로 제공했습니다. 이 루프백은 Xillybus가 어떻게 동작하는지 배우기 위한 출발점이 되도록 만든 것입니다.

xillydemo.v를 변경한 후에는 이 신호들이 FIFO에서 분리되었습니다. 그 대신 user_r_read_32_data는 항상 0x0a4d5750이고, user_r_read_32_empty(비어 있음)는 항상 0입니다. 게다가 로직은 user_r_read_32_rden을 무시합니다. 이로써 절대로 비어 있지 않은 가상의 FIFO가 만들어집니다. 이 가상 FIFO의 출력은 항상 같은 값 0x0a4d5750입니다. Xillybus IP 코어는 마치 이 상수 값으로 항상 채워진 FIFO가 있는 것처럼 동작합니다. 따라서 /dev/xillybus_read_32에서 읽으면 0x0a4d5750이라는 워드가 반복해서 도착합니다. 이 워드를 출력하면 0x50, 0x57, 0x4d, 0x0a의 네 바이트로 해석됩니다. 다시 말해 P, W, M 문자와 라인 피드(line feed, Linux에서 한 줄의 끝을 표시하는 문자)입니다.

Verilog 코드와 실제 핀의 관계

위의 Verilog 코드는 PWM 신호를 J6에 연결합니다. 그런데 이 연결이 어떻게 핀 헤더까지 도달할까요? 답은 xillydemo.xdc에 있습니다. 이 파일은 비트스트림을 생성하는 Vivado 프로젝트의 일부입니다("vivado-essentials" 디렉터리).

xillydemo.xdc에는 FPGA가 전자 부품으로서 올바르게 동작하기 위해 필요한 다양한 정보가 들어 있습니다. 그중에서 이 파일에는 다음과 같은 행이 포함됩니다.

[ ... ]

## J6 on board (BANK33 VADJ)
set_property PACKAGE_PIN U22  [get_ports {J6[0]}];   #J6/1  = IO_B33_LN2
set_property PACKAGE_PIN T22  [get_ports {J6[1]}];   #J6/2  = IO_B33_LP2
set_property PACKAGE_PIN W22  [get_ports {J6[2]}];   #J6/3  = IO_B33_LN3
set_property PACKAGE_PIN V22  [get_ports {J6[3]}];   #J6/4  = IO_B33_LP3
set_property PACKAGE_PIN Y21  [get_ports {J6[4]}];   #J6/5  = IO_B33_LN9
set_property PACKAGE_PIN Y20  [get_ports {J6[5]}];   #J6/6  = IO_B33_LP9
set_property PACKAGE_PIN AB22 [get_ports {J6[6]}];   #J6/7  = IO_B33_LN7
set_property PACKAGE_PIN AA22 [get_ports {J6[7]}];   #J6/8  = IO_B33_LP7

[ ... ]

첫 번째 행은 J6[0] 신호를 U22에 연결해야 한다고 말합니다. U22는 FPGA 물리적 패키지의 위치입니다. Smart Zynq의 회로도에 따르면 이 FPGA 핀은 핀 헤더의 첫 번째 핀에 연결됩니다. 다른 포트들의 위치도 같은 방식으로 정의됩니다.

위에서 J6/3부터 J6/34까지의 핀 중 아무 핀이나 접지로 사용할 수 있다고 언급했습니다. 이 핀들은 출력 핀이며 값이 '0'이기 때문입니다. 이 말이 맞는 이유는 xillydemo.v 시작 부분의 다음 행에서 볼 수 있듯이 J6이 34비트로 구성되어 있기 때문입니다.

  inout [33:0] J6,  //BANK33 VADJ

J6의 값 할당은 다음과 같았음을 기억하세요.

 assign J6 = { pwm_right, pwm_left };

즉, J6[0]은 pwm_left와 같고 J6[1]은 pwm_right와 같습니다. 나머지 비트는 어떻게 될까요? Verilog 문법에 따라 다른 모든 비트에는 0 값이 할당됩니다.

DC 바이어스

핀 헤더는 FPGA의 로직 출력에 연결되어 있습니다. 각 핀은 논리 상태가 '1'일 때 약 3.3V, '0'일 때 약 0V의 전압을 가집니다.

원본 오디오 샘플 값이 0이면 threshold_left와 threshold_right의 값은 1024가 됩니다. 즉, pwm_right와 pwm_left는 평균적으로 절반 동안 high입니다. 따라서 평균 전압(DC)은 3.3V ÷ 2 = 1.65V입니다. WAV 파일의 오디오 샘플이 완벽한 DC 밸런스를 가지고 있더라도 헤드폰에는 DC 성분으로서 1.65V가 인가됩니다.

따라서 100Ω 저항의 목적은 음량을 줄이는 것뿐만 아니라 DC 전류를 제한하는 것이기도 합니다. 하지만 이 저항이 없더라도 FPGA 자체의 전류 제한과 헤드폰의 전기 저항 덕분에 전류는 아마 무해할 것입니다. 저항은 단지 예방 차원의 조치입니다.

요약

이 프로젝트에서는 디지털 출력 핀을 사용해 헤드폰에 직접 연결할 수 있는 아날로그 오디오 신호를 만드는 방법을 보여드렸습니다. 이 프로젝트의 핵심은 소프트웨어에서 FPGA로 데이터를 보내기 위해 Xillybus 스트림을 사용하는 방법을 소개하는 것이었습니다. 또한 간단한 PWM 구현도 함께 살펴보았습니다.

이 페이지는 영어 원문을 기계 번역한 것입니다. 의문이 드는 부분이 있으면 원문을 참조하시기 바랍니다.
Copyright © 2021-2026. All rights reserved. (dcc38493)