대학원/대회 준비 관련

[ZCU-104]DMA + echo

오비루 2024. 6. 11. 15:59
728x90
728x90

Echo와 DMA를 하나의 프로그램으로 연결하기 위한 과정.

처음에는 갈피를 잡지 못 하여 DMA라는 것에 대한 기초적인 동작 방식을 이해하기 시작함.

DMA

DMA를 사용하기 위해서는 AXI DMA에 대한 개념 이해가 약간은 필요했음.

우선 DMA라는 것은 Simple mode와 Scatter Gather mode가 존재함.

(이에 대한 내용은 SG의 경우 앞서 했으니 pass)

처음에는 SG를 사용하다가 이해가 가지 않아 Simple mode로 다시 수행함.

이는 AXI DMA의 address offset을 조절하며 각 상태를 설정함.

 

728x90

그에 대한 내용은 위에 적힌 코드와 같다.

각 register에 대한 offset에 맞게 데이터를 설정해줌.

[자세한 설명은 pg021_axi_dma를 통해서 확인]

아마 이러한 방식을 API로 구현한 것이 Simple mode인 것 같음.

따라서 Simple dma를 lwip와 융합하여 코드를 작성함.

처음에는 interrupt를 사용하는 방식을 이용하고자 했으나, lwip & DMA의 interrupt가 중첩되며 오류가 발생하여 해결 방법을 찾지 못하여 polling을 이용했다.

처음에 DMA를 공부하며 헷갈렸던 부분은 RxBuffer & TxBuffer의 역할이었다.

이후 공부하며 이해를 하니 Txbuffer는 내가 보내고자 하는 주소에 대한 위치이므로, 별도의 변수(Source)를 사용한다면 Source에 대한 주소값을 작성함으로써 Tx에 대한 위치 선언을 하게 된다.

또한, RxBuffer는 DDR(저장 위치)에 대한 주소 값으로 lwip를 통해 수신 되는 frame별로 추가적으로 주소 위치를 조정하여 데이터 값을 저장해준다.

 

 

그 결과 데이터를 저장한 Rx_Buffer 주소 값에 맞게 결과 값이 저장된 것을 확인할 수 있음.

 

또한, 입력 값과 저장 값이 동일한지 확인하기 위한 Checksum 함수를 사용했다.

 

320x100

여기서 python을 통해 port를 맞춰 ethernet에 데이터를 입력해주었는데, 이 방식에 있어서 그냥 10진수, 16진수 값을 그대로 보내면 이상한 값이 들어가게 된다.

 

 

따라서 입력 결과 값을 to_bytes 함수를 사용해서 정수 값을 바이트로 변환해 줘야 한다.

import math
import numpy as np
import os

# 파일 경로 설정   
TXT_file_dir = r"C:\Users\zmzmt\Desktop\IT-Soc\Semiconductor Design Exhibition\Python_data_sending2port"
IN_file_dir = r"C:\Users\zmzmt\Desktop\IT-Soc\Semiconductor Design Exhibition\Python_data_sending2port\input"
OUT_file_dir = r"C:\Users\zmzmt\Desktop\IT-Soc\Semiconductor Design Exhibition\Python_data_sending2port\output"

# directory 안 모든 txt file에 대해 반복
for filename in os.listdir(TXT_file_dir):
    # file path 생성
    filepath = os.path.join(TXT_file_dir, filename)
    
    # 파일인지 확인 후 확장자가 .txt인지 확인
    if os.path.isfile(filepath) and filename.endswith('.txt'):
        
        # 텍스트 파일을 열어서 처리
        with open(filepath, 'r') as file:
            # 파일 내용 읽기
            lines = file.readlines()  # 각 줄을 element로 하는 리스트를 반환
            
        # 8(s,5,3) with integer clipping
        x = np.array([(math.floor((min(float(line.strip()), pow(2.0, 5) - 1) if (float(line.strip()) >= 0) 
                                    else max(float(line.strip()), -pow(2.0, 5))) * pow(2.0, 3))) / pow(2.0, 3) for line in lines])

        # 16진수로 변환 후 1바이트로 저장
        hex_values = []
        for value in x:
            int_value = int(value * pow(2, 3))
            if int_value < 0:
                int_value = (1 << 8) + int_value  # 2의 보수 변환
            hex_values.append(int_value & 0xFF)  # 8비트로 자르기

        # 파일 저장 경로 설정
        saveFileName = 'fixed_' + os.path.splitext(filename)[0] + '_rev.txt'
        saveFilePath = os.path.join(IN_file_dir, saveFileName)
        
        # 1바이트 단위로 파일에 저장
        with open(saveFilePath, 'wb') as w:
            for element in hex_values:
                byte_data = element.to_bytes(1, byteorder='big')
                w.write(byte_data)

print("모든 파일이 처리되었습니다.")

 

from socket import socket, AF_INET, SOCK_STREAM
import time

FPGA_IP = "192.168.1.10"  # FPGA의 IP 주소
FPGA_PORT = 7  
CHUNK_SIZE = 1024  # 청크 크기 설정
received_data = 1

def send_txt_file(filename, sock):
    try:
        chunk_number = 0                                                            # For frame_number checking
        global received_data                                                        # Global로 선언해야 수신받은 값을 사용 가능
        with open(filename, "rb") as file:                                          # 텍스트 파일 열기
            start_time = time.time()  # 송신 시작 시간 기록
            while True:                             
                if (received_data == 1 or chunk_number == 0):                       # 받은 데이터가 '1'이면
                    received_data = 0
                    txt_chunk = file.read(CHUNK_SIZE)                               # 청크 단위로 파일을 읽음
                    if not txt_chunk:                                               # 파일 끝에 도달하면 전송 중단
                        break           
                    header = chunk_number.to_bytes(2, byteorder='big')              # 청크 번호를 2바이트 헤더로 변환
                    sock.sendall(header + txt_chunk)                                # send data (frame number (0,1 번지), 나머지는 데이터)
                    chunk_number += 1                                               # 다음 청크 번호 증가
                    received_data = sock.recv(1)                                    # 1바이트 데이터 수신
                    received_data = int.from_bytes(received_data, byteorder='big')  # 0x01로 되어있는 byte 표현 숫자로 바꿔주기
            end_time = time.time()  # 송신 종료 시간 기록
            # print("텍스트 파일을 전송했습니다.")
            elapsed_time = end_time - start_time  # 소요된 전체 시간 계산
            print("전송에 걸린 시간:", elapsed_time, "초")  # 전송에 걸린 시간 출력
    except FileNotFoundError:
        print(f"파일 '{filename}'을 찾을 수 없습니다.")

def receive_txt_file(filename, sock):
    try:
        with open(filename, "wb") as file:                                          # 텍스트 파일 열기
            while True:
                received_data = sock.recv(CHUNK_SIZE)                               # 최대 CHUNK_SIZE 바이트 데이터 수신
                if not received_data:                                               # 수신된 데이터가 없으면 수신 중단
                    break
                file.write(received_data)                                           # 수신된 데이터를 파일에 씀
        print("텍스트 파일을 수신했습니다.")
    except:
        print("데이터를 수신하지 못했습니다.")

s = socket(AF_INET, SOCK_STREAM)                                                    # 소켓 생성
s.connect((FPGA_IP, FPGA_PORT))                                                     # TCP 서버가 수신 대기 중인 주소에 연결

# 텍스트 파일을 전송
send_txt_file("fixed_Test_1_rev.txt", s)

# 데이터 받기
# receive_txt_file("received_text.txt", s)

s.close()  # 소켓 닫기

이 결과 데이터 처리 속도는 약 0.04초 수준으로 나타났다.

 

 

속도를 빠르게 만들어 주기 위해서 다음과 같이 Burst size를 최대치로 높여주었다.

Echo와 DMA를 하나의 프로그램으로 연결하기 위한 과정.

처음에는 갈피를 잡지 못 하여 DMA라는 것에 대한 기초적인 동작 방식을 이해하기 시작함.

 

[코드는.. Notion에는 적어두었지만 따로 올려두지는 않음..]

728x90
반응형

'대학원 > 대회 준비 관련' 카테고리의 다른 글

plt.pcolormesh 함수 확인하기  (0) 2024.06.18
DMA vs CDMA  (1) 2024.06.14
[ZCU-104]AXI DMA Scatter Gather  (1) 2024.05.28
[ZCU-104]DMA + DDR 공부 내용  (0) 2024.05.28
[ZCU-104] DMA 기본적인 배경  (2) 2024.04.18