본문 바로가기

컴퓨터 공학 자료(학부)/LAN card design

(3-2학기 실험) arm7 을 이용한 랜카드 설계와 firmware porting, 어플리케이션 통신 실험

네트워크 랜카드를 직접 '만드는' 수업이다.

즉 CPU(ARM7), 램, 롬, LED,LCD,부터 트렌지스터 다이오드 까지
모두 직접 납땜을 해서
롬에 펌웨어를 어셈블리어+C로 코딩을 해서 올리고,
MAX232 칩과 PCI 버스를 이용, 내 컴퓨터와 상대방 컴퓨터+랜카드와 통신해서
동작하는 어플리케이션 까지 만드는게 수업의 목표다.

즉 하드웨어 low level부터 소프트웨어 application 레벨까지 모두 알 수 있는,
컴공 하면서 들었던 수업중에 가장 재미있고 삽질을 많이하고 배운게 많았던 수업이었다.


우선 설계한 랜카드 회로도는 다음과 같다

 워낙 도는 족보가 많아서; 참고를 하긴 했지만 여하간 이렇게 납떔을 했다.
사실 이 실험의 묘는 위에 언급한대로 다양한 분야를 한꺼번에 해보는데에도 있지만
각 부품의 제조사에서 제공하는 spec paper를 읽고 자료를 찾아보고 그것을 실제에 적용해볼 수 있는
능력을 기르는데에 있다고 본다.
그래서 가급적 스펙 페이퍼와 친해지려고 노력을 많이 했다.



전체 통신 구조는 다음과 같다


랜카드를 장착하고 전원을 켜면,
ROM에 영구 프로그래밍 되어있는 firmware가 동작, 램과 arm에 프로그램 정보를 전달,
레디 상태로 만든다(소위 말하는 부팅)
그리고 컴퓨터에 어플리케이션을 띄우고 어플리케이션이  PCI port를 통해서 랜카드에 신호를 주고받아
통신을 하는 구조이다.


실제 flowchart는 다음과 같다.




실제로 납떔을 완성한 보드는 다음과 같다.



여기까지가 하드웨어 레벨이고
납떔을 하면서 간간히
LED,LCD를 통해 롬, 램 테스트
인터럽트 테스트
통신 테스트 등을
진행해서
모든 단계를 통과해야
비로소 하나의 랜카드가 완성된다.
롬은 최소한 100번은 구웠던 것 같다.


그리고 이건 롬에 올릴 펌웨어 소스
#define SYSCFG 0x03FF0000 //base resgister address
#define IOPMOD ((volatile unsigned *)(SYSCFG+0x5000))
#define IOPDATA ((volatile unsigned *)(SYSCFG+0x5008))
#define EXTDBWTH ((volatile unsigned *)(SYSCFG+0x3010))
#define ROMCON0  ((volatile unsigned *)(SYSCFG+0x3014))
#define ROMCON1  ((volatile unsigned *)(SYSCFG+0x3018))
#define DPRAM ((volatile unsigned char*)(0x00040000))
#define INTPND ((volatile unsigned int*)(SYSCFG+0x4004))
#define UTXBUF ((volatile unsigned int*)0x03ffd00c)
#define URXBUF ((volatile unsigned int*)0x03ffd010)
#define USTAT ((volatile unsigned int*)0x03ffd008)


// for lcd control

#define DB0    (1<<0)
#define DB1    (1<<1)
#define DB2    (1<<2)
#define DB3    (1<<3)
#define DB4    (1<<4)
#define DB5    (1<<5)
#define DB6    (1<<6)
#define DB7    (1<<7)
#define RS     (1<<10)
#define Enable (1<<11)

char rcv[12]                = "Received";
char cmpl[10]               = "Complete";  
char init_first_line[14]    = "I;m waiting for..";
char init_second_line[13]   = "YOU";

//global var
int tx_index = 0, rx_index = 0, is_trash = 1, tx_flag = 0, check_index = 0, flag = 0;

void delay (int d){
int i;
for (i = 0; i <= d; i++) {}
}

void enable_CLCD()
{
*IOPDATA |= Enable;
delay(100);
}

void disable_CLCD()
{
*IOPDATA &= ~Enable;
delay(100);
}

void set_cursor(){
*IOPDATA |= DB6 | DB7;
enable_CLCD();
disable_CLCD();
*IOPDATA = 0;
}

void init_CLCD(){
//Function Set
*IOPDATA = 0;
*IOPDATA |= DB5 | DB4 | DB3;

enable_CLCD();
disable_CLCD();
//Display on/off
*IOPDATA = 0;
*IOPDATA |= DB3 | DB2 | DB1 | DB0;
enable_CLCD();
disable_CLCD();
//Entry mode Set
*IOPDATA = 0;
*IOPDATA |= DB2 | DB1;
enable_CLCD();
disable_CLCD();
//화면 clear
*IOPDATA = 0;
*IOPDATA |= DB0;
enable_CLCD();
disable_CLCD();
*IOPDATA = 0; 
}

void write_str(char* str, int len){
int str_len;

for(str_len = 0; str_len < len; str_len++){
*IOPDATA = RS | str[str_len];
enable_CLCD();
disable_CLCD();
*IOPDATA = 0;
}
}

void write_char(char c){
*IOPDATA = RS | c;
enable_CLCD();
disable_CLCD();
*IOPDATA = 0;
}


void write_data_to_CLCD(){
write_str(init_first_line, 14);
set_cursor();
write_str(init_second_line, 13);
}


void C_IRQ_Handler(void)
{
char ch;
unsigned int pending = *INTPND;
*INTPND &= pending; //clears

if(pending == 0x01) //GPIO가 port8에 연결되어 있기 때문에
{
init_CLCD();
write_str(rcv, 12);
while((*USTAT & 0x040) != 0x040){}
*UTXBUF = '-';
}
if(pending == 0x010)
{
if(tx_flag){
tx_flag = tx_index = 0;
return ;
}
while((*USTAT & 0x040) != 0x040){};
//if((*(DPRAM + tx_index) != '\n') || (*(DPRAM + tx_index) != '\0'))
if(*(DPRAM + tx_index) != '\0')
{
*UTXBUF = *(DPRAM + tx_index);
//*UTXBUF = *DPRAM;
tx_index++;
}
else
{
tx_flag = 1;
*UTXBUF = '\0';
}
}

if(pending == 0x020)
{
while((*USTAT & 0x020) != 0x020){}
ch = *URXBUF;
if(is_trash || (ch == '-')) is_trash = 0;
else{
*(DPRAM + 0x400 + rx_index) = ch;
//*(DPRAM + 0x400) = ch;
if(ch != '\0') rx_index++;
else 
{
is_trash = 1;
rx_index = 0;
flag = 1;
set_cursor();
write_str(cmpl, 10);
}
}
}
}

void C_Entry(void){
int i;

*IOPMOD = 0xFFFFFF;
*IOPDATA = 0;
init_CLCD();
write_data_to_CLCD();

while(1)
{
if(flag)
{
*IOPDATA |= (1<<9); //LINT port9
delay(1000);
*IOPDATA ^=(1<<9) ;
flag = 0;
}
}
}


그리고 이제 이 랜카드를 통해 상대방과 통신할 어플리케이션을 구현할 차례.

1. Application

1.1. Application 소개

채팅을 바탕으로 한 타자게임을 구현한다. application을 실행하면 먼저 메인화면이 나오고 여기서 접속화면을 클릭하면 본 화면이 나타난다. 이 때 게임을 시작하지 않는 상태에서 채팅화면이 먼저 나오고 게임이 시작할 시에 화면이 게임 화면으로 전환된다. 영어문장을 먼저 완성하는 쪽이 점수를 얻고, 가진 에너지를 먼저 소진하는 쪽이 지는 것으로 한다.

1.2. Game Rule

1.2.1. 한 문장에 10점의 공격 점수를 얻는다.

1.2.2. 먼저 한 문장을 완성하는 user가 상대 user를 공격한다.

1.2.3. 오타가 한 자 날 때마다 공격할 수 있는 점수가 1점씩 깎인다.

1.2.4. 먼저 에너지가 다 깎이는 user가 진다.

1.3. 수행 화면

첫 화면에서 접속하기를 누르면 바로 게임이 시작되지 않은 상태이고 채팅화면이 먼저 나타난다. 여기서 게임신청 버튼을 누르면 게임이 시작된다.

게임을 시작하면 왼쪽과 같은 화면이 나오고 하얀 부분에 영어 문장이 출력되는데 이 영어 문장을 정확하게 입력하는 User가 10점의 공격 점수를 얻게 되고 이것을 상대방에게 자동으로 던지게 된다. 이 때 상대방의 에너지가 10 깎이게 된다. 만약 오타가 나면 공격할 수 있는 점수는 작아지는데 한 자가 오타 날 때마다 공격 점수는 1점씩 작아지게 된다. 예를 들어 star를 srat라고 입력하게 되면 8점의 공격점수가 생긴다. 문제가 총 `15문제로 이루어져 있는데 이 15문제를 다 풀게 되는 경우 혹은 에너지가 다 소진되는 경우에 게임이 종료되고 이 때 승리자는 'Win' 패배자는 ‘Lost'라고 출력된다.