7-Segment Device Control - Device driver Jo, Heeseung
HBE-SM5-S4210 의 M3 Module 에는 6 자리를가지는 7-Segment 모듈이아래그림처럼실장 6 Digit 7-Segment 2
6-Digit 7-Segment LED controller 16비트로구성된 2개의레지스터에의해제어 SEG_Sel_Reg(Segment Select Register) SEG_Data_Reg(Segment Data Register) 레지스터들은 Read와 Write 모두가능하도록설계 SEG_Sel_Reg 0~5bit 에 0 또는 1 을써넣음으로써 display 될 digit 를선택 SEG_Data_Reg 0~7bit 에 0 또는 1 을써넣음으로써 display 될 segment 들을선택 3
Segment Select Register 와 Segment Data Register 각비트에대응되는 6Digit 7-Segment 의핀배치도 SEL3 SEL4 SEL2 SEL1 SEL5 SEL6 SEG_F SEG_G SEG_E SEG_D SEG_A SEG_B SEG_C SEG_H 4
SEG_Sel_Reg 비트구조 Physical Address 0x0500_0030 SEG_Sel_Reg BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Reserved SEL 6 SEL 5 SEL 4 SEL 3 SEL 2 SEL 1 Reset X X X X X X X X X X 0 0 0 0 0 0 Bits Name Description 0 SEL1 Digit 1 Select Bit0 (Active Low) 1 SEL2 Digit 1 Select Bit1 (Active Low) 2 SEL3 Digit 1 Select Bit2 (Active Low) 3 SEL4 Digit 1 Select Bit3 (Active Low) 4 SEL5 Digit 1 Select Bit4 (Active Low) 5 SEL6 Digit 1 Select Bit5 (Active Low) 5
SEL1 ~ SEL6 6-Digit 7-Segment LED 중 display될 digit를선택하는 bit 1을입력할경우선택해제 0을입력할경우선택 6
SEG_Data_Reg 비트구조 Physical Address 0x0500_0032 SEG_Data_Reg BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Reserved SEG_ A SEG_ B SEG_ C SEG_ D SEG_ E SEG_ F SEG_ G SEG_ H Reset X X X X X X X X 0 0 0 0 0 0 0 0 Bits Name Description 0 SEG_A Segment Display Bit0 (Active High) 1 SEG_B Segment Display Bit1 (Active High) 2 SEG_C Segment Display Bit2 (Active High) 3 SEG_D Segment Display Bit3 (Active High) 4 SEG_E Segment Display Bit4 (Active High) 5 SEG_F Segment Display Bit5 (Active High) 6 SEG_G Segment Display Bit6 (Active High) 7 SEG_H Segment Display Bit7 (Active High) 7
SEG_A ~ SEG_G 6 Digit 7-Segment 중 display 될 digit 의 segment 들을선택하는 bit 0 을입력할경우선택해제 1 을입력할경우선택 8
6 개의 7-Segment Array 에 "123456" 의숫자를표시하기위한과정과각신호라인의펄스타이밍도 지속해서신호를주어야불이켜진것처럼보임 1 2 6 3 5 4 7 1 2 3 4 5 6 10
Device driver 소스파일 7-Segment 리눅스디바이스드라이버는커널에포함 menuconfig 실행 - Device Drivers -> [*] Misc devices -> [*] Hanback Electronics M3(FPGA) Device Support -> <*>7 Segment linux-2.6.35-s4210/drivers/misc/hanback/segment.c 참조 12
EL3 linux-2.6.35-s4210/drivers/misc/hanback/segment.c SEL4 EL2 EL1 unsigned short Getsegmentcode (short x) { unsigned short code; switch (x) { case 0x0 : code = 0xfc; break; case 0x1 : code = 0x60; break; case 0x2 : code = 0xda; break; case 0x3 : code = 0xf2; break; case 0x4 : code = 0x66; break; case 0x5 : code = 0xb6; break; case 0x6 : code = 0xbe; break; case 0x7 : code = 0xe4; break; case 0x8 : code = 0xfe; break; case 0x9 : code = 0xf6; break; SEL5 SEL6 SEG_F SEG_G SEG_E SEG_D SEG_A SEG_B SEG_C SEG_H case 0xa : code = 0xfa; break; case 0xb : code = 0x3e; break; case 0xc : code = 0x1a; break; case 0xd : code = 0x7a; break; case 0xe : code = 0x9e; break; case 0xf : code = 0x8e; break; default : code = 0; break; return code; 13
ssize_t segment_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what) { unsigned char data[6]; unsigned char digit[6]={0x20, 0x10, 0x08, 0x04, 0x02, 0x01; unsigned int i,num,ret; unsigned int count=0,temp1,temp2; ret=copy_from_user(&num,gdata,4); count = num; if(num!=0) { data[5]=getsegmentcode(count/100000); temp1=count%100000; data[4]=getsegmentcode(temp1/10000); temp2=temp1%10000; data[3]=getsegmentcode(temp2/1000); temp1=temp2%1000; data[2]=getsegmentcode(temp1/100); temp2=temp1%100; data[1]=getsegmentcode(temp2/10); data[0]=getsegmentcode(temp2%10); 14
switch (mode_select) { case MODE_0_TIMER_FORM: break; case MODE_1_CLOCK_FORM: // dot print data[4] += 1; data[2] += 1; break; // print for(i=0;i<6;i++) { *segment_grid = digit[i]; *segment_data = data[i]; mdelay(1); *segment_grid = ~digit[0]; *segment_data = 0; return length; 15
seg_test.c 프로그램작성 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <time.h> int main (int argc, char *argv[]) { int fd, value = 1, i, count, clock, ch; unsigned short input, dir = 0; if (argc <= 1) { printf ("please input the parameter! ex) %s 123456\n", argv[0]); return -1; 16
if ((fd = open ("/dev/segment", O_RDWR O_SYNC)) < 0) { printf ("FND open fail\n"); exit (1); count = atoi(argv[1]); for (i = 0; i < 400; i++) { write (fd, &count, 4); usleep (1000); close (fd); return 0; 17
Makefile 작성 CC = arm-linux-gcc CFLAGS = -DNO_DEBUG EXEC = seg_test OBJS = $(EXEC).o all: $(EXEC) $(EXEC): $(OBJS) $(CC) -o $@ $^ clean: rm -f $(OBJS) $(EXEC) 18
컴파일 make clean 하면먼저컴파일된실행예제파일삭제 make 명령어로컴파일실행 root@ubuntu:/working/device_driver/seg_driver# ls Makefile seg_test.c root@ubuntu:/working/device_driver/seg_driver# make clean; make ------------------다음과같은메시지가출력된다 ----------------- rm -f seg_test.o seg_test arm-linux-gcc -c -DNO_DEBUG -o seg_test.o seg_test.c arm-linux-gcc -o seg_test seg_test.o root@ubuntu:/working/device_driver/seg_driver# ls Makefile seg_test seg_test.c seg_test.o 테스트 board 에서실행 19
7-Segment Device Control - mmap() Jo, Heeseung
7-Segment 제어 7-Segment 원하는자리에원하는부분 ( 세그먼트 ) 를켜서데이터를출력 해당데이터에따라 7-Segment에숫자나영문자를표시 그리드선택번지 : 0x05000030 세그먼트선택번지 : 0x05000032 그리드선택번지의데이터형식 0x01 SEG1을선택 0x02 SEG2를선택 0x04 SEG3을선택 0x08 SEG4를선택 0x10 SEG5를선택 0x20 SEG6을선택 23
7-Segment 제어 EL3 EL2 EL1 다음으로세그먼트데이터형식 숫자 0 : 0xfc 숫자 1 : 0x60 숫자 2 : 0xda 숫자 3 : 0xf2 숫자 4 : 0x66 숫자 5 : 0xb6 숫자 6 : 0xbe 숫자 7 : 0xe4 숫자 8 : 0xfe 숫자 9 : 0xf6 영문 a : 0xfa 영문 b : 0x3e 영문 c : 0x1a 영문 d : 0x7a 영문 e : 0x9e 영문 f : 0x8e SEL4 SEL5 SEL6 SEG_F SEG_G SEG_E SEG_D SEG_A SEG_B SEG_C SEG_H 24
7-Segment 제어 segment.c 작성 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <fcntl.h> unsigned short Getsegcode(short x); #define FPGA_BASEADDRESS #define SEG_GRID_OFFSET #define SEG_DATA_OFFSET 0x05000000 0x30 0x32 int main() { int fd; volatile int i,j; unsigned int count=1,num,temp1,temp2; unsigned short data[6]; unsigned short digit[6]={0x20, 0x10, 0x08, 0x04, 0x02, 0x01; unsigned short *addr_fpga; unsigned short *addr_grid, *addr_data; 25
7-Segment 제어 if((fd=open("/dev/mem",o_rdwr O_SYNC)) < 0) { printf("mem open fail\n"); exit(1); addr_fpga= (unsigned short *)mmap(null, 4096, PROT_READ PROT_WRITE, MAP_SHARED, fd, FPGA_BASEADDRESS); if(*addr_fpga == (unsigned short)-1) { close(fd); printf("mmap error\n"); exit(1); addr_grid=addr_fpga+seg_grid_offset; addr_data=addr_fpga+seg_data_offset; printf("- 7 Segment\n"); 26
7-Segment 제어 while(count!=0) { num=0; printf("input count value: [1-999999] (0 : exit program) \n"); scanf("%d", &count); while(num<=count ) { data[5]=getsegcode(num/100000); temp1=num%100000; data[4]=getsegcode(temp1/10000); temp2=temp1%10000; data[3]=getsegcode(temp2/1000); temp1=temp2%1000; data[2]=getsegcode(temp1/100); temp2=temp1%100; data[1]=getsegcode(temp2/10); data[0]=getsegcode(temp2%10); for(j=0;j<20;j++) { for(i=0;i<6;i++) { *addr_grid = digit[i]; *addr_data = data[i]; usleep(1000); num++; *addr_grid = ~digit[0]; *addr_data = 0; 28
7-Segment 제어 munmap(addr_fpga,4096); close(fd); return 0; unsigned short Getsegcode(short x) { unsigned short code; switch (x) { case 0x0 : code = 0xfc; break; case 0x1 : code = 0x60; break; case 0x2 : code = 0xda; break; case 0x3 : code = 0xf2; break; case 0x4 : code = 0x66; break; case 0x5 : code = 0xb6; break; case 0x6 : code = 0xbe; break; case 0x7 : code = 0xe4; break; case 0x8 : code = 0xfe; break; case 0x9 : code = 0xf6; break; case 0xa : code = 0xfa; break; case 0xb : code = 0x3e; break; case 0xc : code = 0x1a; break; case 0xd : code = 0x7a; break; case 0xe : code = 0x9e; break; case 0xf : code = 0x8e; break; default : code = 0; break; return code; 29
7-Segment 제어 Makefile 작성 CC = arm-linux-gcc CFLAGS = -DNO_DEBUG EXEC = segment OBJS = $(EXEC).o all: $(EXEC) $(EXEC): $(OBJS) $(CC) -o $@ $^ clean: rm -f $(OBJS) $(EXEC) 30
7-Segment 제어 컴파일 make clean 하면먼저컴파일된실행예제파일삭제 make 명령어로컴파일실행 root@ubuntu:/working/mmap/segment# make arm-linux-gcc -c -DNO_DEBUG -o segment.o segment.c arm-linux-gcc -o segment segment.o root@ubuntu:/working/mmap/segment# ls Makefile segment segment.c segment.o 테스트 board 에서실행 31