반응형

1. interrupts 체크

 

# cat /proc/interrupts | grep mmc
 45:        160          0          0          0     GIC-0 161 Level     mmc0
 46:          0          0          0          0     GIC-0 159 Level     mmc1
 47:       1223          0          0          0     GIC-0 157 Level     mmc2

 

 

2. debugfs 활용 (mount -t debugfs none /sys/kernel/debug)

 

# cat /sys/kernel/debug/mmc0/ios 
clock:          50000000 Hz
vdd:            21 (3.3 ~ 3.4 V)
bus mode:       2 (push-pull)
chip select:    0 (don't care)
power mode:     2 (on)
bus width:      2 (4 bits)
timing spec:    7 (sd uhs DDR50)
signal voltage: 1 (1.80 V)
driver type:    0 (driver type B)

# cat /sys/kernel/debug/mmc2/ios 
clock:          100000000 Hz
vdd:            7 (1.65 - 1.95 V)
bus mode:       2 (push-pull)
chip select:    0 (don't care)
power mode:     2 (on)
bus width:      3 (8 bits)
timing spec:    9 (mmc HS200)
signal voltage: 1 (1.80 V)
driver type:    0 (driver type B)

반응형
반응형

2.1 ARMv8-A

ARMv8-A 아키텍처는 애플리케이션 프로파일을 대상으로 하는 최신 세대의 ARM 아키텍처입니다.
ARMv8이라는 이름은 이제 32비트 실행과 64비트 실행을 모두 포함하는 전체 아키텍처를 설명하는 데 사용됩니다.
기존 ARMv7 소프트웨어와의 하위 호환성을 유지하면서 64비트 와이드 레지스터로 실행할 수 있는 기능을 도입했습니다.

 

ARMv8-A 아키텍처는 여러 가지 변경 사항을 도입하여 훨씬 더 높은 성능의 프로세서 구현을 설계할 수 있게 합니다.

 

Large physical address

                        프로세서가 4GB 이상으로 접근이 가능하도록 합니다.

64-bit virtual addressing

                        4GB 제한을 초과하는 가상메모리를 사용할 수 있습니다. memory mapped file I/O 또는 sparse addressing
                        (희소 주소 지정)을 사용하는 최신 데스크톱 및 서버 소프트웨어에 중요합니다.

Automatic event signaling

                        전력 효율이 높고 고성능의 spinlock을 구현할 수 있습니다.

Larger register files

                         31개의 64비트 범용 레지스터는 성능을 향상시키고 스택 사용량을 줄입니다.

Efficient 64-bit immediate generation

                         리터럴풀 사용을 줄일 수 있습니다.

Large PC-relative addressing range

                         공유 라이브러리 및 위치 독립 실행 파일 내에서 효율적인 데이터 주소 지정을 위한 +/-4GB 주소 범위.

Additional 16KB and 64KB translation granules

                         번역 조회 버퍼(TLB) 누락률과 페이지 탐색 깊이가 줄어듭니다.

New exception model

                         이를 통해 운영체제 및 하이퍼바이저 소프트웨어의 복잡성이 줄어듭니다.

Eifficient cache management

                         사용자 공간 캐시 작업은 동적 코드 생성 효율성을 향상시킵니다.
                         데이터 캐시 제로 명령어를 사용한 빠른 데이터 캐시 클리어 기능도 제공합니다.

Hadware-accelerated cryptography

                         3배에서 10배 향상된 소프트웨어 암호화 성능을 제공합니다. 
                         이는 HTTPS와 같이 하드웨어 가속기로 효율적으로 오프로드하기에는 너무 작은 단위의 암호화 및 복호화에
                         유용합니다.

Load-Acquire, Store-Release instructions

                         C++11, C11, Java 메모리 모델에 맞춰 설계되었습니다. 
                         명시적인 메모리 배리어 명령어를 제거하여 스레드 안전 코드의 성능을 향상시킵니다.

NEON double-precision floating-point advanced SIMD

                         이를 통해 SIMD 벡터화는 과학 계산, 고성능 컴퓨팅(HPC) 및 슈퍼컴퓨터와 같은 
                         훨씬 더 광범위한 알고리즘에 적용될 수 있습니다.

 

반응형
반응형

1. DRM

DRM (Direct Rendering Manager)은 Linux Kernel에서 디스플레이 및 그래픽 장치를 관리하는 서브 시스템으로 유저 공간 애플리케이션과 GPU/디스플레이 하드웨어 사이의 인터페이스 역할을 합니다.

Linux Kernel에는 이미 그래픽 어댑터의 프레임버퍼를 관리하는 데 사용되는 fbdev 드라이버 및 API가 있었지만 최신 3D 가속 GPU 기반 비디오 하드웨어의 요구 사항을 처리하는 데는 어려움이 있었습니다.

 

이러한 장치는 일반적으로 자체 메모리(VRAM 및 CMA)에서 명령 대기열을 설정하고 관리하여 GPU에 명령을 전송해야 하며 해당 메모리 내의 버퍼와 여유 공간을 관리해야 합니다.

 

처음에는 사용자 공간 프로그램(X Server)이 이러한 리소스를 직접 관리했지만 일반적으로 자신만이 액세스할 수 있는 것처럼 작동했습니다. 두 개 이상의 프로그램이 동시에 같은 하드웨어를 제어하고 각기 다른 방식으로 리소스를 설정하려고 하면 대부분의 상황에서 문제가 발생하였습니다.

 

Direct Rendering Manager는 여러 프로그램이 비디오 하드웨어 리소스를 공동으로 사용할 수 있도록 만들어졌습니다. DRM은 GPU에 독점적으로 접근하며 명령 대기열, 메모리 및 기타 하드웨어 리소스를 초기화하고 유지 관리합니다.

 

Without DRM
With DRM

GPU를 사용하려는 프로그램은 DRM에 요청을 보내면 DRM은 중재자 역할을 하며 충돌 가능성을 방지합니다.

위의 주된 이유로 인하여 DRM 형태로 전환하여 Linux Kernel이 발전하였으며 모드 설정, 메모리 공유 개체 및 동기화와 같이 이전에 사용자 공간에서 처리해야 했던 더 많은 기능을 포함하도록 확장되어 왔습니다.

  • 사용자 공간으로부터의 디스플레이 제어 요청 처리
  • 프레임버퍼 관리
  • 페이지 플립(Page Flip), VBlank 이벤트 등 스케줄링
  • 멀티 디스플레이 환경 지원
  • GPU 메모리 관리 및 버퍼 공유 (GEM, DMA-BUF)

주 목적은 렌더링 버퍼 관리, 화면 출력, VBlank 이벤트, atomic state 변경, 그리고 플러그 앤 플레이 디스플레이 제어입니다.

 

DRM 구성 요소 요약

구성 요소

 

설명

 
DRM Core /drivers/gpu/drm/drm*.c 등에서 구현. 공통 로직을 담당
DRM (Platform) Driver 각 하드웨어에 특화된 드라이버 (예: i915, amdgpu, rockchip, exynos 등)
DRM Helper 공통된 코드 재사용을 위한 helper 함수 (예: drm_gem_cma_helper)
DRM KMS (Kernel Mode Setting) 해상도, 모니터 제어, 플립 등을 위한 인터페이스
 

 

2. DRM Software Archtecture

DRM은 Kernel Space에 존재하므로 유저 공간 프로그램은 Kernel의 System Call을 통해 DRM에 필요한 서비스를 요청해야 합니다.

 

DRM에서 감지한 각 GPU는 DRM 장치로 인식되며 디바이스 노드(/dev/dri/cardX)가 생성되어 이와 상호 작용 합니다. GPU와 통신하려는 유저 공간 프로그램은 디바이스 장치 파일을 열어 ioctl 호출을 사용하여 DRM과 통신해야 합니다.

 

libdrm은 Kernel의 DRM드라이버를 사용하기 위한 user space 라이브러리(wrapper) 입니다. libdrm을 사용하면 커널 인터페이스가 사용자 공간에 직접 노출되는 것을 피할 수 있을 뿐만 아니라 프로그램 간에 코드를 재사용하고 공유할 수 있는 이점이 있습니다.

 

위의 그림과 같이 DRM은 크게 두 부분으로 구성됩니다. 일반적인 Kernel의 DRM Core 와 각 유형의 지원 하드웨어에 대한 DRM (Platform) Driver 입니다. DRM Core는 다양한 DRM Driver가 등록할 수 있는 기본 프레임워크를 제공하고 사용자 공간에 공통적인 하드웨어 독립적인 기능을 갖춘 최소한의 ioctl 기능을 제공합니다.

반면 DRM 드라이버는 지원하는 GPU 유형에 따라 특정 API의 하드웨어 종속 부분을 구현합니다. DRM 코어에서 다루지 않는 나머지 ioctl 구현을 제공해야 하지만 API를 확장하여 해당 하드웨어에서만 사용할 수 있는 추가 기능을 갖춘 추가 ioctl을 제공할 수도 있습니다.

특정 DRM 드라이버가 향상된 API를 제공하는 경우 사용자 공간 libdrm도 추가 ioctl과 인터페이스 하기 위해 사용자 공간에서 사용할 수 있는 추가 라이브러리 libdrm-specific_driver 형태로 확장됩니다.

 

DRM Core는 사용자 공간 애플리케이션에 여러 인터페이스를 내보내며, 일반적으로 해당 래퍼 함수를 ​​통해 사용됩니다. 또한 드라이버는 ioctls 및 sysfs 파일을 통해 사용자 공간 드라이버 및 장치 인식 애플리케이션에서 사용할 수 있도록 장치별 인터페이스를 내보냅니다.

외부 인터페이스에는 메모리 매핑, 컨텍스트 관리, DMA 작업, AGP 관리, vblank 제어, fence 관리, 메모리 관리 및 출력 관리가 포함됩니다.

3. Kernel Mode Setting (KMS)

리눅스 그래픽 스택에서 KMS (Kernel Mode Setting) 는 디스플레이 장치의 출력 모드를 설정하고 제어하는 핵심 기능입니다.
여기서 모드(mode) 란 해상도(Resolution), 컬러 포맷(Color Format), 주사율(Refresh Rate) 등 디스플레이가 출력할 수 있는 상태를 의미합니다.

즉, KMS는 GPU 장치가 연결된 디스플레이가 지원하는 값 범위 내에서 올바른 모드를 선택하고, 이를 하드웨어 레벨에서 설정하는 역할을 합니다.

과거에는 X.Org Server 또는 특정 그래픽 애플리케이션이 직접 하드웨어에 접근하여 모드를 설정했습니다.
이 방식에는 두 가지 문제가 있었습니다:

  1. 보안 문제
    • 사용자 공간 프로그램이 직접 하드웨어를 제어하기 위해 루트 권한으로 실행되어야 했습니다.
    • 이는 안정성과 보안 측면에서 위험 요소가 많았습니다.
  2. 일관성 부족
    • 여러 애플리케이션이 각각 하드웨어를 제어하려고 하면 충돌이나 비정상적인 동작이 발생할 수 있었습니다.

이러한 문제를 해결하기 위해 커널이 모드 설정을 담당(Kernel Mode Setting) 하도록 변경되었고,
사용자 공간에서는 안전하게 DRM(Direct Rendering Manager) 인터페이스를 통해 제어 명령을 전달하는 구조로 발전했습니다.

 

KMS의 주요 구성 요소

KMS는 단일 하드웨어 블록이 아니라, 디스플레이 파이프라인을 구성하는 여러 요소의 조합으로 동작합니다. DRM 드라이버는 일반적으로 다음 세 가지 주요 객체를 관리합니다:

  1. CRTC
    • 프레임 버퍼 메모리에서 픽셀 데이터를 읽어와 화면에 출력하는 역할
    • 스캔아웃(scanout) 동작을 담당하며, vsync와 같은 타이밍 제어를 관리
  2. Encoder
    • CRTC에서 출력된 데이터를 특정 디스플레이 신호 형식(HDMI, DisplayPort, DVI 등)으로 변환
    • 하나의 CRTC는 여러 Encoder와 연결될 수 있음
  3. Connector
    • 실제 물리적인 디스플레이 장치(모니터, 패널 등)에 연결되는 지점
    • EDID(Extended Display Identification Data)를 읽어 디스플레이가 지원하는 모드를 파악

이 세 가지 객체를 조합하여 커널은 '어떤 프레임 버퍼를 어떤 방식으로 어떤 출력 장치에 보여줄 것인가'를 결정하게 됩니다.

 

 

이번 글에서는 DRM과 KMS의 기본 개념과 필요성, 그리고 주요 객체(CRTC/Encoder/Connector)의 역할을 살펴보았습니다.

 

다음 글에서는 이 추상화 구조가 실제 SoC에서 어떻게 매핑 되는지, 그리고 Simple Pipe와 전통적인 구현 방식이 어떻게 다른지 구체적으로 다루어 보겠습니다.

반응형
반응형

간단한 CRC 체크를 위한 함수는 아래와 같습니다.

 

CRC Check할 데이터의 address(pointer) 및 data length를 parameter로 crc 및 checksum 값을 확인할 수 있습니다.

- crc.h

#ifndef CRC_H
#define CRC_H

#include <stdint.h>
#include <stddef.h>

//EDB88320 Table
static const uint32_t crc32_table[256] = {
    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
    0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
    0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
    0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
    0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
    0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
    0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
    0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
    0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
    0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
    0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
    0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
    0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
    0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
    0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
    0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
    0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
    0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
    0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
    0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
    0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
    0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
    0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
    0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
    0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
    0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
    0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
    0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
    0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};

uint32_t crc32(const uint8_t *data, size_t length);

unsigned short crc16_ccitt( const void *buf, int len);
uint8_t calculate_checksum(const uint8_t *data, uint16_t length);

#endif

 

 

 

- crc.c 

#include <crc.h>

uint32_t crc32(const uint8_t *data, size_t length) {
    uint32_t crc = 0xFFFFFFFF;
    for (size_t i = 0; i < length; i++) {
        uint8_t byte = data[i];
        uint32_t table_index = (crc ^ byte) & 0xFF;
        crc = (crc >> 8) ^ crc32_table[table_index];
    }
    return crc ^ 0xFFFFFFFF;
}

unsigned short crc16_ccitt( const void *buf, int len )
{
	unsigned short crc = 0;
	while( len-- ) {
		int i;
		crc ^= *(char *)buf++ << 8;
		for( i = 0; i < 8; ++i ) {
			if( crc & 0x8000 )
				crc = (crc << 1) ^ 0x1021;
			else
				crc = crc << 1;
		}
	}
	return crc;
}

uint8_t calculate_checksum(const uint8_t *data, uint16_t length) {
    uint8_t checksum = 0;
    while (length--) {
        checksum += *data++;
    }
    return checksum;
}
반응형

'Programming Language > C&C++' 카테고리의 다른 글

CMSIS USART XMODEM Code  (0) 2024.10.29
[C++] STL 및 Container 종류  (0) 2021.08.25
반응형

- XMODEM

XMODEM은 시리얼 통신 매체를 활용하여 CP/M 플로피 디스크에 사용된 기본 블록 크기인 128Byte를 채택해 128byte의 데이터 단위 전송 및 프로토콜 규약으로 당시 모뎀을 통한 파일 전송을 보다 쉽게 만들기 위해 탄생했습니다.

 

XMODEM은 간단하면서도 신뢰성 있는 데이터 전송방식을 제공하여, 이후 YMODEM, ZMODEM 같은 확장 프로토콜이 탄생할 수 있는 기초가 되었습니다.

 

대부분의 파일 전송 프로토콜과 같이 XMODEM은 원래의 데이터를 일련의 패킷으로 쪼개어 수신자에게 보내며 여기에 추가 정보를 담고 있어서 수신자가 어느 패킷을 올바르게 받았는지를 결정할 수 있게 합니다.

 

128Byte 프로토콜에서 1Kbyte 형태로 발전하기도 했으며, Checksum 이외에 CRC16 형태로 확장되기도 하여 각 상황 및 설정에 맞춰 통신을 할 수 있도록 설계되어야 합니다.

 

이번 글에서는 XMODEM 프로토콜의 작동 방식과 패킷 구조, 전송 흐름을 알아보겠습니다.

 

 

 

- XMODEM 프로토콜의 기본 개념

XMODEM은 양방향 통신을 기반으로 하는 오류 검출 방식을 채택하여 데이터를 전송합니다.

특히 종단 간 오류 제어를 위해 체크섬(Checksum) 방식이 사용됩니다.

 

데이터 전송 시 오류가 발생하면 수신 측에서 오류 패킷을 다시 요청하여 재전송하는 방식으로 파일의 신뢰성을 유지합니다.

 

XMODEM은 전송 중 패킷 손실이나 손상된 데이터를 감지할 수 있어 당시 모뎀 환경에서 매우 유용했습니다.

 

 

 

- Data Packet Structure

XMODEM 패킷은 128바이트 크기의 고정된 데이터 블록으로 이루어져 있습니다.

각 패킷은 다음과 같은 형식으로 구성됩니다.

 

  1. SOH (Start of Header): 1바이트, 패킷의 시작을 나타내며 ASCII 코드 0x01로 표시됩니다.
  2. 블록 번호: 1바이트, 현재 패킷의 순서를 표시합니다. 0부터 시작하여 1씩 증가하며, 255를 넘어가면 다시 0으로 돌아갑니다.
  3. 블록 번호의 보수: 1바이트, 블록 번호의 보수를 저장하여 오류를 검증하는 데 사용됩니다.
  4. 데이터: 128바이트의 실제 데이터 내용입니다. 파일의 마지막 패킷에서는 부족한 바이트를 0x1A(EOF 문자)로 채웁니다.
  5. 체크섬: 1바이트, 오류 검출을 위한 값으로, 데이터 필드의 모든 바이트의 합을 1바이트로 나타냅니다.

Checksum 과 CRC16 프로토콜의 차이는 Data Packet 이후 에러 검출을 위하여 Checksum 1 byte 또는 CRC16의 2 byte 에 따른 데이터 끝부분의 차이가 존재합니다.

 

 

- 기본 패킷(Checksum)

SOH Packet
Number
1's Compliment of
Packet Number
Data Packet Checksum
1 Byte 1 Byte 1 Byte 128 Byte 1 Byte

 

- CRC16 패킷

SOH Packet
Number
1's Compliment of
Packet Number
Data Packet Checksum
1 Byte 1 Byte 1 Byte 128 Byte 2 Byte

 

 

 

- Transfer flow

XMODEM 프로토콜은 간단하지만 규칙적인 전송 과정을 따릅니다. 송신 측과 수신 측이 데이터를 주고받는 과정을 단계별로 살펴보겠습니다.

  1. 전송 시작 신호: 수신 측이 준비되면 ASCII 코드 0x15(NAK) 또는 0x43(C)을 송신 측으로 보내 파일 전송을 시작합니다. 이를 통해 송신 측은 수신 측이 준비되었음을 알 수 있습니다.
  2. 데이터 패킷 전송: 송신 측은 각 데이터 블록을 패킷 구조에 맞추어 순차적으로 전송합니다.
  3. ACK/NAK 확인: 수신 측은 패킷을 수신한 후 체크섬을 확인합니다. 오류가 없는 경우 ACK(0x16) 신호를, 오류가 있는 경우 NAK 신호를 송신 측에 보냅니다. NAK(0x15) 신호를 받으면 송신 측은 해당 패킷을 다시 전송합니다.
  4. 파일 전송 완료: 모든 데이터 패킷 전송이 완료되면 송신 측은 EOT(End of Transmission) 신호를 보내 파일 전송을 마무리합니다. 수신 측이 EOT(0x04) 신호를 확인하면 전송이 끝났음을 인지하게 됩니다.

 

아래의 표와 같이 위에 설명한 수신 측에서 CRC의 경우 0x43('C')를 전송하여 전송측에 전송 요청을 보내어 통신 시작 및 싱크를 맞춰 진행합니다.

 

CRC 방식이 아닌 Checksum의 경우 0x15(NAK)를 보내어 시작합니다. 

전송 측으로 전달된 첫 패킷을 수신측에서 제대로 수신할 수 없는 경우 Checksum에서는 0x15(NAK)를 보내지만 CRC의 경우 0x43('C') 값을 보내야 합니다.

 

해당 상황에서 CRC 전송에서 첫 패킷에 0x15(NAK)를 보내게 될 경우 Tera Term 등의 프로토콜에서는 자동으로 Checksum으로 전환되니 해당 시퀀스에 대해 주의해야 합니다.

 

 

전송 시작 이후 SOH 와 각 Data Format에 맞춰 파일 데이터를 수신하며 Checksum 또는 CRC 패킷을 통해 Data 오류 검출 및 정합성을 확인하여 파일 데이터를 수신하고 EOT를 수신하게 되면 통신이 모두 종료되게 됩니다.

 

결론

XMODEM은 초기 파일 전송 프로토콜로서 통신 기술 발전에 중요한 기여를 했습니다.

이 프로토콜은 기본적인 오류 검출 기능을 통해 파일 전송의 신뢰성을 보장하며, 데이터 통신의 기초 개념을 잘 보여줍니다.

 

XMODEM을 이해하면, 이후 발전한 다양한 프로토콜의 배경과 원리를 쉽게 이해할 수 있습니다.

이상으로 XMODEM의 개념과 작동 방식을 알아보았습니다.

반응형
반응형
#include "Driver_USART.h"
#include "xmodem_lib.h"
#include "crc.h"

#define PACKET_SIZE 128

extern ARM_DRIVER_USART Driver_USART0;
static ARM_DRIVER_USART *USARTdrv = &Driver_USART0;

static const uint8_t SOH = 0x01;
static const uint8_t EOT = 0x04;
static const uint8_t ACK = 0x06;
static const uint8_t NAK = 0x15;

#ifdef XMODEM_CRC16
static uint8_t rx_buffer[PACKET_SIZE + 5]; // SOH, Block, ~Block, Data[128], CRC[2]
static const uint8_t SELC = 0x43;
#else
static uint8_t rx_buffer[PACKET_SIZE + 4]; // SOH, Block, ~Block, Data[128], checksum
#endif

void USART_Callback(uint32_t event) {
    // Handle USART events here
}

void XMODEM_Init(void) {
    USARTdrv->Initialize(USART_Callback);
    USARTdrv->PowerControl(ARM_POWER_FULL);
    USARTdrv->Control(ARM_USART_MODE_ASYNCHRONOUS |
                      ARM_USART_DATA_BITS_8 |
                      ARM_USART_PARITY_NONE |
                      ARM_USART_STOP_BITS_1 |
                      ARM_USART_FLOW_CONTROL_NONE, 115200);
    USARTdrv->Control(ARM_USART_CONTROL_RX, 0);
}

unsigned short crc16_ccitt( const void *buf, int len )
{
	unsigned short crc = 0;
	while( len-- ) {
		int i;
		crc ^= *(char *)buf++ << 8;
		for( i = 0; i < 8; ++i ) {
			if( crc & 0x8000 )
				crc = (crc << 1) ^ 0x1021;
			else
				crc = crc << 1;
		}
	}
	return crc;
}

uint8_t calculate_checksum(const uint8_t *data, uint16_t length) {
    uint8_t checksum = 0;
    while (length--) {
        checksum += *data++;
    }
    return checksum;
}

int XMODEM_Receive(uint8_t *data, uint32_t length) {
    uint8_t block_number = 1, started = 0;
    uint32_t received = 0, timeout = 0;
    uint32_t count;

    //Clear RXFIFO
    while (USARTdrv->GetRxCount() > 0) {
        uint8_t dummy;
        USARTdrv->Receive(&dummy, 1);
    }

#ifdef XMODEM_CRC16
    USARTdrv->Send(&SELC, 1);
#else
    USARTdrv->Send(&ACK, 1);
#endif
    
    while (received < length) {
        memset(rx_buffer, 0x0, sizeof(rx_buffer));
        USARTdrv->Receive(rx_buffer, sizeof(rx_buffer));
        count = USARTdrv->GetRxCount();
        if((!started) && (count > 0))
            started = 1;
        // Wait for data reception to complete
        // Implement timeout handling here

        if (rx_buffer[0] == SOH && rx_buffer[1] == block_number && rx_buffer[2] == (uint8_t)~block_number) {
#ifdef XMODEM_CRC16
            uint16_t crc_received = (rx_buffer[PACKET_SIZE + 3] << 8) | rx_buffer[PACKET_SIZE + 4];
            uint16_t crc_calculated = crc16_ccitt(&rx_buffer[3], PACKET_SIZE);
            if (crc_received == crc_calculated) {
#else
            uint8_t checksum_received = rx_buffer[PACKET_SIZE + 3];
            uint8_t checksum_calculated = calculate_checksum(&rx_buffer[3], PACKET_SIZE);
            if (checksum_received == checksum_calculated) {
#endif
                memcpy(&data[received], &rx_buffer[3], PACKET_SIZE);
                received += PACKET_SIZE;
                started = 1;
                block_number++;
                USARTdrv->Send(&ACK, 1);
                timeout = 0;
            } else {
                if(block_number == 1)
                    USARTdrv->Send(&SELC, 1);
                else
                    USARTdrv->Send(&NAK, 1);
            }
        } else if (rx_buffer[0] == EOT) {
            USARTdrv->Send(&ACK, 1);
            break;
        } else {
            //Clear Read Buffer For Packet align
            if(count > 0) {
                do {
                    USARTdrv->Receive(rx_buffer, sizeof(rx_buffer));
                } while (USARTdrv->GetRxCount());
            }
#ifdef XMODEM_CRC16
            if(block_number == 1)
                    USARTdrv->Send(&SELC, 1);
            else
#endif
                USARTdrv->Send(&NAK, 1);
            
            if(started && timeout > 15) {
                block_number = 1;
                received = 0;
                started = 0;
                timeout = 0;
            } else if (started) {
                timeout++;
            }
        }
    }

    return received;
}
반응형

'Programming Language > C&C++' 카테고리의 다른 글

CRC16/32 & Checksum C언어 코드  (0) 2024.11.14
[C++] STL 및 Container 종류  (0) 2021.08.25

+ Recent posts