본문 바로가기

RaspberryPi/RP2350

RP2350 SM - HSTX를 이용한 DIV 테스트

HSTX(High-Speed Serial Transmit)는 Raspberry Pi RP2350 마이크로컨트롤러의 새로운 주변 장치이며, 고속 직렬 전송을 위한 인터페이스 이다. 시스템 클럭과 독립적인 속도로 최대 8개의 GPIO를 통해 데이터를 스트리밍할 수 있는 장치이다. 기존의 프로그래밍 입/출력(PIO)나 오버클럭 없이도 고속 데이터 전송을 가능하게 한다. 특히 HDMI출력으로 사용하기에 편리하다.

 

RP2350 HSTX로 HDMI출력 테스트를 해 보자.

기존 RP2040도 PIO를 이용하여 HDMI출력이 가능했지만 PIO만으로 출력하다보니 320x240으로 해상도에 한계가 있었다. 그리고 HDMI출력을 할때는 다른 PIO를 동시에 사용하기 어려워 Camera 입력을 받는예제는 작성하기 어려웠다.

 

RP2350은 별도의 하드웨어 블록으로 HDMI출력이 가능해 PIO를 동시에 사용할 수 있고 640x480 해상도로 출력 할 수 있다.







RP2350 HSTX 핀맵

HSTX 핀은 12~19 까지 4쌍으로 할당되어 있다.

 

 

기존에 제작했던 RP2040용 SSM Type HDMI 테스트 보드를 SM Type 핀맵에 연결 될 수 있도록 핀맵을 수정한 RP2350 SM EXP 보드에 연결해서 DVI출력 테스트를 해 볼수 있다. 다만 +, -핀이 역으로 되어 있어 코드에서 적절한 수정이 필요하다.

 

    // Pinout on Pico DVI sock:
    //   GP13 CK+  GP12 CK-
	//   GP15 D0+  GP14 D0-
    //   GP17 D1+  GP16 D1-
    //   GP19 D2+  GP18 D2-

   // Assign clock pair to two neighbouring pins:
    hstx_ctrl_hw->bit[1] = HSTX_CTRL_BIT0_CLK_BITS;
    hstx_ctrl_hw->bit[0] = HSTX_CTRL_BIT0_CLK_BITS | HSTX_CTRL_BIT0_INV_BITS;
	
    for (uint lane = 0; lane < 3; ++lane) {
        // For each TMDS lane, assign it to the correct GPIO pair based on the
        // desired pinout:
        static const int lane_to_output_bit[3] = {2, 4, 6};
        int bit = lane_to_output_bit[lane];
		
        // Output even bits during first half of each HSTX cycle, and odd bits
        // during second half. The shifter advances by two bits each cycle.
        uint32_t lane_data_sel_bits =
            (lane * 10    ) << HSTX_CTRL_BIT0_SEL_P_LSB |
            (lane * 10 + 1) << HSTX_CTRL_BIT0_SEL_N_LSB;
			
        // The two halves of each pair get identical data, but one pin is inverted.
        hstx_ctrl_hw->bit[bit + 1] = lane_data_sel_bits;
        hstx_ctrl_hw->bit[bit] = lane_data_sel_bits | HSTX_CTRL_BIT0_INV_BITS;
    }


    for (int i = 12; i <= 19; ++i) {
        gpio_set_function(i, 0); // HSTX
    }

RP2350에서 HSTX를 이용한 DVI출력 예제는 플래시 메모리에 저장된 640x480의 이미지(640x480 256color) 를 출력하는 예제이다.

https://github.com/raspberrypi/pico-examples/blob/master/hstx/dvi_out_hstx_encoder/dvi_out_hstx_encoder.c

 

pico-examples/hstx/dvi_out_hstx_encoder/dvi_out_hstx_encoder.c at master · raspberrypi/pico-examples

Contribute to raspberrypi/pico-examples development by creating an account on GitHub.

github.com

 

 

HDMI 커넥터로 출력하는 예제에서 가장 중요한 DMA 로직 함수를 분석해 보면 HSTX로  DVI 신호를 만들어 주고 있다. 기존 RP2040의 PIO(320x240)방식 보다는 간단하고 속도도 빨라 640x480 해상도도 출력이 가능하다.

 

// ----------------------------------------------------------------------------
// DMA logic

#define DMACH_PING 0   // DMA 채널 번호: Ping
#define DMACH_PONG 1   // DMA 채널 번호: Pong

// Ping-Pong 방식으로 DMA를 번갈아가며 사용하기 위한 플래그
static bool dma_pong = false;

// 스캔라인 카운터 (현재 몇 번째 수직 라인인지 추적)
// 초기에는 Ping, Pong이 각각 한 번씩 실행된 상태이므로 2부터 시작
static uint v_scanline = 2;

// 수직 활성 구간(Vertical Active Period)에서
// 한 라인당 두 번의 IRQ 발생: 
// (1) 명령어 리스트 전송, (2) 실제 픽셀 데이터 전송
static bool vactive_cmdlist_posted = false;

void __scratch_x("") dma_irq_handler() {
    // dma_pong 값에 따라 직전에 완료된 DMA 채널(Ping/Pong)을 선택
    // → 완료된 채널을 다시 설정하여 다음 전송에 재사용
    uint ch_num = dma_pong ? DMACH_PONG : DMACH_PING;
    dma_channel_hw_t *ch = &dma_hw->ch[ch_num];

    // 완료된 DMA 채널의 인터럽트 플래그 클리어
    dma_hw->intr = 1u << ch_num;

    // 다음 IRQ에서는 반대 채널(Ping↔Pong)을 사용할 수 있도록 토글
    dma_pong = !dma_pong;

    // 현재 수직 라인(v_scanline)에 따라 DMA에 보낼 데이터 결정
    if (v_scanline >= MODE_V_FRONT_PORCH && 
        v_scanline < (MODE_V_FRONT_PORCH + MODE_V_SYNC_WIDTH)) {
        // 수직 동기 신호(VSync ON) 구간
        ch->read_addr = (uintptr_t)vblank_line_vsync_on;
        ch->transfer_count = count_of(vblank_line_vsync_on);

    } else if (v_scanline < MODE_V_FRONT_PORCH + MODE_V_SYNC_WIDTH + MODE_V_BACK_PORCH) {
        // 수직 동기 신호 해제(VSync OFF) 구간
        ch->read_addr = (uintptr_t)vblank_line_vsync_off;
        ch->transfer_count = count_of(vblank_line_vsync_off);

    } else if (!vactive_cmdlist_posted) {
        // 수직 활성 구간: 첫 번째 IRQ → 명령어 리스트 전송
        ch->read_addr = (uintptr_t)vactive_line;
        ch->transfer_count = count_of(vactive_line);
        vactive_cmdlist_posted = true;

    } else {
        // 수직 활성 구간: 두 번째 IRQ → 실제 프레임 버퍼의 픽셀 데이터 전송
        ch->read_addr = (uintptr_t)&framebuf[
            (v_scanline - (MODE_V_TOTAL_LINES - MODE_V_ACTIVE_LINES)) * MODE_H_ACTIVE_PIXELS
        ];
        ch->transfer_count = MODE_H_ACTIVE_PIXELS / sizeof(uint32_t);
        vactive_cmdlist_posted = false;
    }

    // 픽셀 전송까지 완료되었을 때만 다음 스캔라인으로 진행
    if (!vactive_cmdlist_posted) {
        v_scanline = (v_scanline + 1) % MODE_V_TOTAL_LINES;
    }
}

 

 

RP2350 HSTX DVI 기본 예제는 아래 그림처럼 플래시 메모리에 있는 640x480x8bit  이미지를 출력한다.

 

 

여러가지 다양한 이미지도 출력 테스트 해보면 640x480 이미지도 충분한 속도로 출력 하는것을 확인 할 수 있다.

 

반응형