이 블로그는 임베디드 컴퓨터를 이용한 장치(시스템) 개발과 원격제어에 필요한 지식을 공유 하기 위한 블로그 입니다.
실제 개발과 프로그램 예를 위하여 Microchip 사의 ATmega128를 사용한 보드와 Arduino Mega 보드(ATmega2560), Raspberry Pi, Raspberry Pi Pico, WiFi 모듈을 사용 합니다.

asm-avr-software-debugging

Software Debugging - ASM
  Software Debugging - ASM


  • Functional Debugging
    • 가능한 Input에 대하여 Output이 예상되는 결과와 일치하는지를 검증한다.

    • Simulator를 이용 한 Functional Debugging
    • 참고자료: "Debugger를 이용한 Instruction Set과 Microprocessor의 이해"

    • Real Time Debugging
    • 프로그램이 실 시간으로 실행 되는 상태에서 Debugging에 필요한 정보를 수집 한다.

      • 모니터 또는 Output Port(LED 등)에 필요한 정보를 출력 하는 방법
        • SREG 등의 상태를 보기 위하여 Binary Data를 Hex 값으로 출력(Binary to Hex data)하는 Code를 삽입하거나 LED Array(8 Bits)에 상태를 출력한다.
      • Buffer에 필요한 정보를 일시적으로 저장 한 후 출력 하여 조사 하는 방법
        • 빠른 프로그램 실행이 필요한 경우(모니터 등 속도가 느린 I/O 장치를 사용 하면 문제가 발생 하는 경우) Debugging에 필요한 정보를 일시적으로 Buffer에 저장 한 다음 출력 하여 Debugging 한다.
      • 출력 되는 정보가 너무 많은 경우 Filter를 사용 한다.
        • Loop 내 Data의 조건, SW 의 상태 등에 따라 Data를 Filtering 하여 출력 되는 정보량을 줄인다.
      • 오실로스코프(Oscilloscope) 등 계측기와 Output Port를 사용 하는 방법
        • 출력 장치나 Buffer를 이용 하기에는 너무 빠르고 많은 Data가 주기 적으로 발생 하는 경우에 오실로스코프(Oscilloscope) 등 계측기를 사용 하여 관찰 한다.
    • 프로그램 개발 시 자주 발생 하는 문제
      • Carry Flag를 Clear 하지 않아 발생 하는 문제
        • 프로그램 예: debug_ex_led_basic_shift_carry_clear
        • 실험을 위한 준비
        • 실험 방법
          • GCC ASM Project(debug_ex_led_basic_shift_carry_clear)를 생성한다.
          • 참고자료: GCC ASM Project 만들기

          • 위 프로그램을 main.s에 복사하고 저장한다.
          • Build → Build Solution 를 실행 하면 프로그램이 Build 되어 debug_ex_led_basic_shift_carry_clear.hex 파일이 생성된다.
          • debug_ex_led_basic_shift_carry_clear.hex 파일을 Target Board에 Upload 하고 프로그램을 실행한다.
          • 실험:
            • clc 명령을 활성화 하면 프로그램이 바르게 동작(Turn on된 LED가 1초 간격으로 Shift 됨)하는 것을 확인 할 수 있다.
            • clc 명령을 활성화 하지 않으면 프로그램이 정상으로 동작 하지 않는 것(LED가 1초 간격으로 Turn on 되어 모든 LED가 Turn on 됨)을 확인 할 수 있다.
      • Pull up 저항을 사용 하여 Switch를 연결 한 경우 프로그램에서 Pull Up 설정을 바르게 하지 않아서 발생 하는 문제.
        • Pull up 저항을 바르게 설정하지 않고 Switch를 연결 한 경우 Switch의 상태를 바르게 Input 하지 못할 가능성이 커진다.

      • Input Port의 Pin 신호는 Pin 신호를 읽기 1.5 Cycle 이전에 안정화 되어야 한다. 이 조건을 지키지 못하여 발생 하는 문제.
        • Keypad Scan 시 발생 하는 문제 : Keypad Scan 시 NOP 명령을 생략하여 발생 하는 문제를 이해 하기 위한 예.
        • 실험을 위한 준비
          • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 RXD와 Atmega128의 TXD0(PE1)를 연결한다.
          • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 TXD와 Atmega128의 RXD0(PE0)를 연결한다.
          • 주: 컴퓨터에 Serial Port가 없는 경우 "USB --> UART(RS232) 변환 모듈"를 사용(USB Port를 Serial Port로 변환)하여 연결한다. 개발보드에 따라서는 "USB --> UART(RS232) 변환 모듈"을 내장하고 있는 경우가 많기 때문에 본인이 사용하는 개발보드에서 확인 하여야 한다.

            참고자료: USB - Serial 변환 모듈

          • 컴퓨터(USB --> UART(RS232)의 GND와 Atmega128의 GND를 연결한다. "USB --> UART(RS232) 변환 모듈"를 사용하는 경우 변환 모듈의 GND와 Atmega128의 GND를 연결한다.
        • 실험 방법
          • debug_ex_keypad_pin_signal_setup_time.zip를 다운로드하여 압축을 해제한다.
          • Microchip Studio를 실행하고 Build → Build Solution 를 실행 하면 프로그램이 Build 되어 debug_ex_keypad_pin_signal_setup_time.hex 파일이 생성된다.
          • debug_ex_keypad_pin_signal_setup_time.hex 파일을 Target Board에 Upload 하고 프로그램을 실행한다.
          • 실험:
            • NOP 명령을 사용하여 Input Port의 Pin 신호를 Pin 신호를 읽기 1.5 Cycle 이전에 안정화 시킨 경우
              • GCC_asm_get_keypad_soft.s 파일의 171번 라인에 NOP Code를 활성화 시킨(Comment를 제거) 상태)에서 Project를 Build 하여 프로그램을 실행한다.
              • 모니터 프로그램을 실행하면 "Keypad Test" 메세지가 출력된다.
              • Keypad에서 문자를 입력하면 입력된 문자가 모니터에 출력돤다.
            • NOP 명령을 사용하지 않아 Pin 신호가 안정화되지 못한 경우
              • GCC_asm_get_keypad_soft.s 파일의 171번 라인에 NOP Code를 비활성화 시킨(NOP Code를 Comment 처리) 상태)에서 Project를 Build 하여 프로그램을 실행한다.
              • 모니터 프로그램을 실행하면 "Keypad Test" 메세지가 출력된다.
              • Keypad에서 문자를 입력하여도 문자가 바르게 입력되지 않는다.

              주: 모니터 프로그램(예: OC-Console, Tera Term)과 hex 파일을 Target Board에 Upload 하는 프로그램이 동일한 Port를 사용하기 때문에 모니터 프로그램을 중지하고 Upload를 실행하여야 한다.

      • 우선 순위가 높은 Interrupt Service Routine을 길게 작성 하여 발생 하는 문제
        • 우선 순위가 높은 External Interrupt Routine의 실행 시간이 긴 경우, Interrupt Priority 가 낮은 Interrupt(Timer 등)가 실행 되지 못하여 문제가 발생 할 수 있다.
      • Interrupt Routine 내에서 이전 프로그램에서 사용 하는 Rg, Flag(SREG) 등을 변경 하여 발생 하는 문제.
      • Interrupt Flag를 Clear 하지 않아 발생 하는 문제
        • 실험을 위한 준비
          • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 RXD와 Atmega128의 TXD0(PE1)를 연결한다.
          • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 TXD와 Atmega128의 RXD0(PE0)를 연결한다.
          • 주: 컴퓨터에 Serial Port가 없는 경우 "USB --> UART(RS232) 변환 모듈"를 사용(USB Port를 Serial Port로 변환)하여 연결한다. 개발보드에 따라서는 "USB --> UART(RS232) 변환 모듈"을 내장하고 있는 경우가 많기 때문에 본인이 사용하는 개발보드에서 확인 하여야 한다.

            참고자료: USB - Serial 변환 모듈

          • 컴퓨터(USB --> UART(RS232)의 GND와 Atmega128의 GND를 연결한다. "USB --> UART(RS232) 변환 모듈"를 사용하는 경우 변환 모듈의 GND와 Atmega128의 GND를 연결한다.
        • 실험 방법
          • debug_ex_keypad_timer2_interrupt_flag.zip를 다운로드하여 압축을 해제한다.
          • Microchip Studio를 실행하고 Build → Build Solution 를 실행 하면 프로그램이 Build 되어 debug_ex_keypad_timer2_interrupt_flag.hex 파일이 생성된다.
          • debug_ex_keypad_timer2_interrupt_flag.hex 파일을 Target Board에 Upload 하고 프로그램을 실행한다.
          • 실험:
            • Interrupt falg를 바르게 Clear한 경우
              • GCC_asm_get_keypad_interrupt.s 프로그램의 External Interrupt flag(409-411 3줄) 와 Timer2 over flow interrupt falg(466-468 3줄)를 Comment 처리하지 않은 상태에서는 프로그램이 정상으로 동작한다.
              • 모니터 프로그램을 실행하면 "Keypad Test" 메세지가 출력된다.
              • Keypad에서 문자를 입력하면 입력된 문자가 모니터에 출력돤다.
            • Interrupt falg를 바르게 Clear하지 않은 경우
              • GCC_asm_get_keypad_interrupt.s 프로그램의 External Interrupt flag(409-411 3줄) 와 Timer2 over flow interrupt falg(466-468 3줄)를 Comment 처리한 상태에서는 프로그램이 정상으로 동작하지 않는다.
              • 모니터 프로그램을 실행하면 "Keypad Test" 메세지가 출력된다.
              • Keypad에서 문자를 입력하여도 문자가 바르게 입력되지 않는다.

              주: 모니터 프로그램(예: OC-Console, Tera Term)과 hex 파일을 Target Board에 Upload 하는 프로그램이 동일한 Port를 사용하기 때문에 모니터 프로그램을 중지하고 Upload를 실행하여야 한다.

      • Compiler의 최적화 때문에 발생 하는 문제
        • C 언어를 사용 하는 경우 c Compiler가 원하지 않는 최적화를 수행 하여 문제가 발생 할 수 있다. Memory-Mapped I/O처럼 Memory 번지에 할당된 I/O Rg, External Interrupt 와 Timer Interrupt 등에서 사용 하는 변수 등에 읽거나 쓰는 명령을 Compiler 가 최적화 (해당 명령을 Complier가 삭제) 하는 경우 문제가 발생 할 수 있다. 이런 경우 해당 변수에 Volatile 문을 사용 하면 Complier 가 최적화를 하지 않고 프로그램 대로 Compile 하기 때문에 이러한 문제를 해결 할 수 있다.
        • 실험을 위한 준비
          • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 RXD와 Atmega128의 TXD0(PE1)를 연결한다.
          • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 TXD와 Atmega128의 RXD0(PE0)를 연결한다.
          • 주: 컴퓨터에 Serial Port가 없는 경우 "USB --> UART(RS232) 변환 모듈"를 사용(USB Port를 Serial Port로 변환)하여 연결한다. 개발보드에 따라서는 "USB --> UART(RS232) 변환 모듈"을 내장하고 있는 경우가 많기 때문에 본인이 사용하는 개발보드에서 확인 하여야 한다.

            참고자료: USB - Serial 변환 모듈

          • 컴퓨터(USB --> UART(RS232)의 GND와 Atmega128의 GND를 연결한다. "USB --> UART(RS232) 변환 모듈"를 사용하는 경우 변환 모듈의 GND와 Atmega128의 GND를 연결한다.
        • 실험 방법
          • cho_keypad_basic_ext_int_timer2.zip를 다운로드하여 압축을 해제한다.
          • Microchip Studio를 실행하고 Build → Build Solution 를 실행 하면 프로그램이 Build 되어 cho_keypad_basic_ext_int_timer2.hex 파일이 생성된다.
          • cho_keypad_basic_ext_int_timer2.hex 파일을 Target Board에 Upload 하고 프로그램을 실행한다.
          • 실험:
            • 이 실험을 위하여는 아래를 참고하여 c Complier 최적화 옵션을 -O3로 설정하여야한다.
            • Complier 최적화 옵션 설정: Project → Properties... → Toolchain → Optimization Level: 에서 Optimize most(-O3)를 선택한다.

            • volatile 키위드를 바르게 사용한 경우
              • GCC_asm_get_keypad_interrupt.s 과 delay_timer2.c 프로그램에서 volatile 키위드 사용하여 선언한 전역 변수를 사용한다. volatile 키위드 사용하지 않은 전역 변수를 Comment 처리한다.
              • 모니터 프로그램을 실행하면 "Keypad Test" 메세지가 출력된다.
              • Keypad에서 문자를 입력하면 입력된 문자가 모니터에 출력돤다.
            • volatile 키위드를 사용하지 않은 경우
            • GCC_asm_get_keypad_interrupt.s 과 delay_timer2.c 프로그램에서 volatile 키위드 사용하지 않은 전역 변수를 사용한다. volatile 키위드 사용하여 선언한 전역 변수를 Comment 처리한다.
            • 모니터 프로그램을 실행하면 "Keypad Test" 메세지가 출력된다.
            • Keypad에서 문자를 입력하여도 문자가 바르게 입력되지 않는다.

            주: 모니터 프로그램(예: OC-Console, Tera Term)과 hex 파일을 Target Board에 Upload 하는 프로그램이 동일한 Port를 사용하기 때문에 모니터 프로그램을 중지하고 Upload를 실행하여야 한다.


  • Profiling
    • Profiling은 관심을 갖는 사항에 대하여 Time history 정보를 수집하여 분석하는 디버깅 방법이다. 실시간 제어에 Interrupt를 사용 하거나 Simulator 만으로 Debugging 하기 어려운 경우 (Simulator로 Debugging 하기 어려운 I/O 장치가 사용되는 경우 등) 실시간 Debugging을 위하여 Profiling 기술을 사용 할 수있다.

    • 프로그램 실행 시 Time과 프로그램 실행 순서 등의 위치 정보에 대한 Profile를 이용 하여 debugging 한다.
    • 시간과 위치가 관심의 대상 이다.

      • Unconditional Profiling
        • 프로그램 실행 과정을 Trace 하기 위하여 프로그램 내에 표시 문자를 출력 하는 Code를 삽입 한다.
        • 실험을 위한 준비
          • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 RXD와 Atmega128의 TXD0(PE1)를 연결한다.
          • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 TXD와 Atmega128의 RXD0(PE0)를 연결한다.
          • 주: 컴퓨터에 Serial Port가 없는 경우 "USB --> UART(RS232) 변환 모듈"를 사용(USB Port를 Serial Port로 변환)하여 연결한다. 개발보드에 따라서는 "USB --> UART(RS232) 변환 모듈"을 내장하고 있는 경우가 많기 때문에 본인이 사용하는 개발보드에서 확인 하여야 한다.

            참고자료: USB - Serial 변환 모듈

          • 컴퓨터(USB --> UART(RS232)의 GND와 Atmega128의 GND를 연결한다. "USB --> UART(RS232) 변환 모듈"를 사용하는 경우 변환 모듈의 GND와 Atmega128의 GND를 연결한다.
        • 실험 방법
          • debug_ex_keypad_interrupt_timer2_profile.zip를 다운로드하여 압축을 해제한다.
          • Microchip Studio를 실행하고 Build → Build Solution 를 실행 하면 프로그램이 Build 되어 debug_ex_keypad_interrupt_timer2_profile.hex 파일이 생성된다.
          • debug_ex_keypad_interrupt_timer2_profile.hex 파일을 Target Board에 Upload 하고 프로그램을 실행한다.
          • 모니터(터미널) 프로그램을 실행한다.
          • 실험:
            • 프로그램이 실행되면 모니터에 "Keypad Test" 메세지가 출력되고
            • M:02 K:00 이 출력된다.
              • M:02는 main.s에서 출력되는 Profile로 해당 위치에서 SREG의 상태가 02(Zero Flag 가 Set된 상태) 인 것을 알 수 있다.
              • K:00는 GCC_asm_get_keypad_interrupt.s 파일의 get_key 함수에서 출력된 Profile로 해당 위치에서 SREG의 상태가 00 인 것을 알 수 있다.
            • 모니터에 M:02 K:00 만 출력되는 것은 현재 프로그램 실행 위치가 GCC_asm_get_keypad_interrupt.s 파일의 get_key 함수의 get_key1: Label 이 위치한 곳으로 여기서 loop를 반복 실행하며 Key 입력을 기다리는 상태이다.
            • get_key1: Label 이 위치한 곳에 있는 loop에 있는 Profile을 출력하는 Macro는 조건(새로운 Key Code 값이 Zero가 아닌 경우에만 Profile을 출력)를 에 따라 Profile을 출력하기 때문에 Key 입력을 기다리는 상태에서는 모니터에 출력이 발생하지 않는다.
            • 만약 1번 Key를 누르면 I:02 S:02 L:31 1 K:00 I:02 S:02 가 출력된다.
              • I:02는 External Interrupt(INT4_vect, INT5_vect, INT6_vect) Service Roputine(ISR) 내에서 출력되는 Profile로 Key 입력에 의하여 External Interrupt가 발생하여 Interrupt Service Roputine(ISR)이 정상적으로 실행된 상태를 의미한다.
              • S:02는 key_scan 함수 내의 Profile로 key_scan 함수가 정상적으로 실행된 상태를 의미한다.
              • L:31는 get_key1: 함수 내의 Conditional Profile로 key_scan 결과 Zero가 아닌 Key Code 값 발생한 경우 출력된다. 31은 문자 1의 ASCII Code 값이다.
              • 1 출력은 main.s의 loop 내에서 ASM_putchar 함수에 의하여 문자 1이 출력된 것 이다.
              • 문자 1이 출력된 다음 main.s의 loop 내에서 가 출력되어 모니터의 커서가 다음 줄로 이동한다.
              • 다음 즐의 K:00는 main.s의 loop 내에서 get_key 함수를 다시 Call 하여 GCC_asm_get_keypad_interrupt.s 파일의 get_key 함수에서 출력된 Profile 이다.
              • I:02는 External Interrupt(INT4_vect, INT5_vect, INT6_vect) Service Roputine(ISR) 내에서 출력되는 Profile로 Key 입력에 의하여 External Interrupt가 발생하여 Interrupt Service Roputine(ISR)이 실행된 상태를 의미한다.
              • S:02는 key_scan 함수 내의 Profile로 key_scan 함수가 정상적으로 실행된 상태를 의미한다.
              • key_scan 함수가 실행되었어도 문자 출력이 발생하지 않는 것은 현재 발생한 External Interrupt가 Key를 Release 할때 발생한 Bouncing 현상에 의한 것이기 때문에 Key Code 값이 Zero 이기 때문이다. Key Code 값이 Zero 인 경우 무시하고 get_key 함수의 get_key1: Label 이 위치한 곳에서 loop를 반복 실행하며 Key 입력을 기다리는 상태가 된다.
              • Key 입력을 기다리는 상태에서 새로운 Key를 입력하면 윗 과정이 반복된다.
              • 주: Key Code 값이 Zero인 상태에서 get_key1: loop 내의 tst RG_ARG0_L 명령이 실행되어 SREG의 Zero Flag가 Set된 상태에서 L: Profile을 출력하는 Macro 함수가 실행 되는 도중에 KeyCode 값이 변동하는 경우 L: Profile이 2번 출력되는 겅우가 발생한다.

                주: 이 Profile은 동작 속도가 느린 UART 통신을 이용하기 때문에 많은 정보를 용이하게 출력할 수 있는 장점이 있지만 실시간 동작을 필요로 하는 프로그램에서 문제가 발생할 수 있다.

            주: 모니터 프로그램(예: OC-Console, Tera Term)과 hex 파일을 Target Board에 Upload 하는 프로그램이 동일한 Port를 사용하기 때문에 모니터 프로그램을 중지하고 Upload를 실행하여야 한다.

        • Conditional Profiling
          • 무한 Loop 내(너무 많은 Profile 정보가 발생 한다.)의 상태를 Check하기 위하여 조건에 따라 Profile 정보를 출력 하게 한다. 이 때 조건문 또는 Switch의 상태를 이용 하여 원하는 조건에 맞는 정보만 Profiling 한다.
            • 위 Project(debug_ex_keypad_interrupt_timer2_profile) 예에서 GCC_asm_get_keypad_interrupt.s 파일의 get_key 함수 내에 get_key1: Label 이 위치한 loop에 있는 L: Profile을 출력하는 Macro 함수가 Conditional Profiling의 예 이다.

          • Circular Buffer의 Full 상태를 Test 하기 위하여 Switch를 사용하여 Buffer 출력을 일시적으로 정지 시키는 방법
        • Output Port를 사용한 Profiling
          • Output port(LED 등)_를 이용하여 Profile을 관찰함
        • Thread Profile
          • Multiple Threads 가 실행될 경우 각 Thread를 Output port pin에 할당하여 각 Thread가 실행되는 동안 해당 Pin에 1를 출력하여 이 신호를 Multiple-channel scope로 관측하여 각 Thread의 실행 Profile를 알 수 있다

    • Performance Debugging
      • System의 Time Behavior를 검증한다. System이 Run하고 있는 중, 예상 시간 내에 예상되는 결과 (대규모 Data Transfer, I/O 등)를 얻을 수 있는지 검증 한다.

      • Timer를 이용 하여 프로그램 실행 시간을 측정 한다.
        • 16 Bit counter TCNT를 이용하여 시간 정보를 측정한다.
      • Output Port를 이용 한 시간 측정
        • 프로그램 실행 속도 측정을 위한 신호를 Output Port에 출력하고 오실로스코프 등의 장비로 시간을 측정한다.

    • Measurement of Dynamic Efficiency
      • 아래와 같은 방법을 사용 할 수 있다.

      • Assembly Listing 을 이용한 Bus cycles count 방법
      • Internal Timer(TCNT) 를 이용한 처리 시간 측정 방법
      • Output pin에 신호를 출력하고 Oscilloscope 또는 Logic Analyzer를 이용한 시간 측정 방법


    • Software Debugging - ASM 관련 페이지 보기