Busan IT/ARM Controller2015. 10. 6. 14:00

==================================Outline====================================

ARM 3 Core 동작 Test

Keil 컴파일러 사용법

내부 LED 동작 프로그래밍

----------------------------------------------------------------------------

 

ARM 3 Core 동작 Test

 

SERIAL 단자에 USB를 연결하고 카메라를 장착한다.

 

 

하이퍼 터미널을 실행시켜 통신 설정을 해준다.

 



 

[1]번부터 [a]까지 실행시켜 ARM3가 제대로 동작하는지 확인한다.

 

[1]'LED test'LED 단자에 불이 조작에 따라 켜고 꺼지면 정상 작동하는 것이다.

 

[2]'Timer test'LED 단자의 일정한 간격으로 깜빡거린다면 정상 작동하는 것이다.

 

[3]RTC test는 실시간으로 시간이 작동하면 정상 작동이다.

 

...

 

Keil 컴파일러 사용법

 

Keil 컴파일러는 알고 쓰면 편하지만 모르면 복잡한 컴파일러이다.

 

- Ctrl키를 누른 상태에서 마우스 휠을 위로 움직이면 글자 크기가 늘어나고 휠을 아래로 내리면 글자 크기가 줄어든다.

 

- 사용가능 ARM Core의 목록을 보고 싶다면 Pack Installer를 클릭해서 정보를 살펴보면 된다.

- 실행환경 설정을 하고 싶다면 주사위 같이 생긴 버튼을 눌러주면 된다.




- Ctrl + n을 생성하여 코드를 작성할 문서를 생성해주고 원하는 이름과 파일형식을 지정하여 저장해준다.




생성된 파일을 프로젝트에 추가해주어야 한다.




- 새 프로젝트를 생성하기 위해서는 우선 새로운 폴더를 하나 만들고 'Project' -> 'New uVision Project...' 를 선택한 후 폴더의 경로를 지정해주면 해당 폴더 안에 파일들이 생성된다.


 

폴더를 지정해 주고 나면 디바이스 설정 창이 나온다. 디바이스 설정 창에서 Software Packs을 선택하고 search에서는 디바이스의 전체 이름을 검색한 후 선택해준다.

실행 환경 설정에서 'Core', 'Startup', 'Framework', 'GPIO', 'RCC'의 체크박스를 선택해준다.

(추가 사용할 기능이 있으면 추가적으로 체크박스를 선택해주면 된다.)

체크 박스를 선택했을 시 노란색이 뜨면 경고이다. 경고 메세지를 확인하여 수정해주면 노란색이 초록색으로 변동하게 된다.

 

 

내부 LED 동작 프로그래밍



PA2가 low인 상태에서 PA0가 high일 때 LED에 불이 들어오게 된다.




 해당 프로그램을 3가지 방식으로 작성해본다.


1. 단순 코딩(메모리의 주소 값을 사용하여 메모리에 직접 접근)

2. 헤더 파일을 사용

3. firmware를 사용

 

데이터시트에는 레지스터 정보가 없다. 레지스터 정보를 확인하려면 RM0008이라는 'Reference manual'을 참조해야 한다. 페이지 수가 천페이지를 넘기 때문에 원하는 내용을 효율적으로 검색하기 위해서 책갈피를 사용하해야 한다.

 

GPIO(General Purpose Input/Output)가 아니면 APIO(Alternative Purpose Input/Output)라고 생각하면 된다.

 

GPIO를 사용하여 LED를 동작시키는 코딩을 해보자.

 

- GPIO레지스터는 설정 레지스터, 데이터 레지스터, /리셋 레지스터와 잠금레지스터로 구성된다.

- 지금까지 사용한 output방식은 push-pull 방식이다. open-drain방식은 따로 설명할 예정이다.


GPIO_CRLGPIO 0 - 7번까지 입출력 설정을 해주는 레지스터이다.

 


output모드는 어떤 값을 넣어도 상관없다.




 

BSRR레지스터로 BRR의 기능을 사용할 수 있다.

 

컴파일 시 요술봉을 누른 후

 





 

클럭 공급이 필요하다.

 

 

define 값을 사용하지 않고 header 파일을 사용해 코딩을 해보자.

 

헤더 파일을 사용할 때 원하는 구조체의 양식을 보고 싶다면 구조체 위에서 'F12'키를 누르면 구조체가 있는 자리로 이동한다.

 

firmware 라이브러리를 활용하여 프로그램을 만들 수도 있다.




/*** 코드 ***/

#include <stm32f10x.h>

/*
#define GPIOA_CRL   (*((volatile unsigned int *)0x40010800))
#define GPIOA_IDR   (*((volatile unsigned int *)0x40010808))
#define GPIOA_ODR   (*((volatile unsigned int *)0x4001080C))
#define GPIOA_BRR   (*((volatile unsigned int *)0x40010810))
#define GPIOA_BSRR  (*((volatile unsigned int *)0x40010814))
#define RCC_APB2ENR  (*((volatile unsigned int *)0x40021018))
*/
  

void PA2_in(void)
{
    /* Configure all the GPIOA in Input Floating mode */
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  
}

void PA0_out(void)
{
      /* Configure all the GPIOA in Input Floating mode */
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  
}
int main(void)
{
//RCC->APB2ENR |= 0x04;    //clock supply to GPIOA
//RCC_APB2ENR |= 0x04;
/* Enable GPIOA, GPIOB and SPI1 clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);

  
  
//GPIOA->CRL = 0x44444441;  //I/O setting
//GPIOA_CRL = 0x44444441;  //I/O setting
  PA2_in();
  PA0_out();

  
  while(1)
  {  
    //if(0==(GPIOA->IDR & 0x04)) //Switch On
    if(0 == GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2))
    {
          //GPIOA->BSRR = 0x01;
          GPIO_SetBits(GPIOA, GPIO_Pin_0);
    }
    else                                  // Switch Off
    {
        //GPIOA->BRR = 0x01;
      GPIO_ResetBits(GPIOA, GPIO_Pin_0);
    }
  }
  
    
  
    return 0;
}


반응형

'Busan IT > ARM Controller' 카테고리의 다른 글

ARM Clock 설정  (0) 2015.10.12
내부 LED 반전 프로그램 만들기  (0) 2015.10.08
ARM Core3 M3 프로그래밍 환경 설정  (0) 2015.10.05
ADC 전압측정  (0) 2015.09.18
Analogue to Digital Converter  (0) 2015.09.17
Posted by newind2000
Busan IT/Assembly2015. 10. 5. 17:40

==================================Outline====================================

함수의 호출과 작동 원리 

----------------------------------------------------------------------------

'Initialize'라는 함수를 만들 수 디버깅 모드를 활용하여 각 레지스터들의 변화를 살펴보자.

우선 살펴보아야 할 메모리의 주소 값들을 보존시켜둔다.

 

EIP = 0040103E

ESP = 0012FF8C

ESP - 10h = 0012FF7C(스택 레지스터의 변화를 알아보기 위한 설정이다)

Initialize = 00401010

 

함수 호출

 

EIP는 명령어를 가리키는 레지스터이다. 00401043h 주소로 이동하면 ‘Initialize’의 주소로 이동하게 된다.

 

'call Initialize'를 해석 아래와 같다.

 

push ‘return address'(eip)

jmp Initialize

 

 

ret은 개념상 아래와 같다.

 

pop eip

 

eip에 간접적으로 값을 넣을 수 있는 방법은 두 가지인데 ‘call' 혹은 ’ret'명령어를 사용하는 것이다.

 

//cracking - 조건문을 조작하여 eip를 원하는 위치로 점프 시킨다.

 

return문 다음에 숫자를 적을 수도 있다. 이 경우는 나중에 배운다.

 

 



 

‘PUBLIC’ 명령어를 사용하면 다른 파일에서 접근이 가능해진다.

'PUBLIC'을 사용하지 않으면 기본적으로 외부에서 접근이 불가능하다.

 

‘extern’ 다른 파일에서 만들어진 함수를 호출하는 기능을 한다.

 

'NEAR32'4giga byte내에 코드가 존재한다는 뜻이다.

 

 

스택을 사용하는 변수들(지역변수들)

 

//6.3까지 배우고 나서부터는 C언어와 혼용하여 어셈블리를 배운다.

 

 

C에서는 함수를 사용할 때 인자를 입력하여 그 값을 달리하는 것이 가능하였다. CPU레지스터에는 용량의 한계가 있기 때문에 stack을 활용하면 된다. ARM core를 사용할 때 함수의 인자 4개 이상 만들게 되면 메모리에 값을 넣어야 하기 때문에 속도가 느려진다.

 

_stdcall: 함수의 인자를 좌측에서 우측으로 스택에 쌓는다.

_cdecl: 함수의 인자를 우측에서 좌측으로 쌓는다.(기본)

 

//주소보안 옵션 해제 - /DYNAMICBASE:NO

//asm파일 생성 옵션 - /Fa

//makfile에서 ‘@’은 명령어를 화면 창에 표시하지 않는 것이다.

push 300 ; 0000012cH

push 200 ; 000000c8H

push 100 ; 00000064H

call _smart

add esp, 12 ; 0000000cH

 

300, 200, 100순서임으로 _cdecl 형식임을 알 수 있다.

 

함수의 호출이 끝나면 stack은 다시 원래의 자리로 돌아와야 한다. 함수 내에 있던 지역변수는 함수가 종료됨으로써 사라지기 때문이다.

 

_cdecl call에서는 함수를 호출한 함수에서 스택의 값을 되돌려주는 것이다. 반면에 _stdcall은 호출된 함수 자체에서 사용한 변수를 스택에서 삭제한다.

 

aseeembly에서는 'ret'문을 사용하지 않으면 함수가 종료되지 않는다. C언어에서도 return을 삽입하는 습관을 들이자.




//소스


<main.c>

#include <stdio.h>

void smart(int a, int b, int c)
{
  int d=100;
  int e=200;
  int f=300;

  return;
}

int main(void)
{
  
  smart(100200300);
  return 0;
}

<main.asm>

; Listing generated by Microsoft (R) Optimizing Compiler Version 18.00.31101.0 

  TITLE  D:\윤재희\실습\Assembly\20151005\main.c
  .686P
  .XMM
  include listing.inc
  .model  flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC  _smart
PUBLIC  _main
; Function compile flags: /Odtp
_TEXT  SEGMENT
_main  PROC
; File d:\윤재희\실습\assembly\20151005\main.c
; Line 13
  push  ebp
  mov  ebp, esp
; Line 15
  push  300          ; 0000012cH
  push  200          ; 000000c8H
  push  100          ; 00000064H
  call  _smart
  add  esp, 12          ; 0000000cH
; Line 16
  xor  eax, eax
; Line 17
  pop  ebp
  ret  0
_main  ENDP
_TEXT  ENDS
; Function compile flags: /Odtp
_TEXT  SEGMENT
_f$ = -12            ; size = 4
_e$ = -8            ; size = 4
_d$ = -4            ; size = 4
_a$ = 8              ; size = 4
_b$ = 12            ; size = 4
_c$ = 16            ; size = 4
_smart  PROC
; File d:\윤재희\실습\assembly\20151005\main.c
; Line 4
  push  ebp
  mov  ebp, esp
  sub  esp, 12          ; 0000000cH
; Line 5
  mov  DWORD PTR _d$[ebp], 100      ; 00000064H
; Line 6
  mov  DWORD PTR _e$[ebp], 200      ; 000000c8H
; Line 7
  mov  DWORD PTR _f$[ebp], 300      ; 0000012cH
; Line 10
  mov  esp, ebp
  pop  ebp
  ret  0
_smart  ENDP
_TEXT  ENDS
END

<go.bat>

@echo off

@cls 
  cl /Fa %1.c /DYNAMICBASE:no

 


 

 

 

반응형

'Busan IT > Assembly' 카테고리의 다른 글

pushad를 활용한 레지스터 출력  (0) 2015.10.12
Procedure 필수코드, C의 obj파일과 asm의 obj파일 합치기  (0) 2015.10.06
pop, pushad 명령어  (0) 2015.10.02
확장/반복문, Procedures  (0) 2015.10.01
조건문의 사용  (4) 2015.09.30
Posted by newind2000
Busan IT/ARM Controller2015. 10. 5. 13:31

==================================Outline====================================

ARM Core3 M3 프로그래밍 환경 설정

- 개발환경 설정을 위한 다운로드

- STM32 Cortex-M3의 기본 설명

- 예제 프로그래밍을 통한 기능 확인

----------------------------------------------------------------------------

개발환경 설정을 위한 다운로드

우선 새로 지급 받은 CortexM3관련 자료를 자료실에서 몽땅 다운로드 받자.

(FTP 자료실(192.168.0.2)-> 수업자료 -> Digital -> CortexM3)

- 데이터 시트

- 회로도

** 데이터 시트/회로도 다운 http://www.jkelec.co.kr/img/arm/cortex-m3/rabbit_stm32_lqfp64/rabbit_stm32f10x_manual.htm

- 펌웨어 메뉴얼

** st.com에 접속하여 program manual과 reference manual 다운받기

http://www.st.com/web/catalog/mmc/FM141/SC1169/SS1031/LN1565/PF164495?s_searchtype=partnumber

- 컴파일러(Keil)

** Keil 컴파일러 다운 https://www.keil.com/demo/eval/arm.htm#DOWNLOAD

** MDK v4 Legacy Support - http://www2.keil.com/mdk5/legacy

- 프로그램 전송(um0462.zip)


STM32 Cortex-M3의 기본 설명

- STM32 Cortex-M3 에 기반한 32bit ARM 개발보드로 STM32F103VCT6 MCU를 사용하여 최대 72 MHz 속도로 동작 하고 CPU모듈과 Bottom보드가 분리되어 있다. Rabbit Bottom 보드에는 CMOS Camera, nRF24L01 RF, 터치 LCD 등의 다양한 모듈들을 연결하여 테스트 할 수 있다.


전원부는 5v를 입력 받아 3.3v로 변환하여 사용한다

- 우리가 사용하는 보드의 핀은 144핀임으로 다른 핀 설명은 무시하도록 하자.

 

- 시리얼 포트를 이용하여 프로그램을 올릴 예정임으로 'SERIAL_J1'을 주로 사용한다.

- ARM사의 컴파일러는 크게 KeilIAR이다. Keil은 프로그램 예제는 많이 없지만 회사에서 많이 쓰이는 컴파일러이다. 반면에 IAR은 예제가 많이 존재한다.

 

- 데이터 시트를 통해 내용을 살펴보자.



 

- remap기능을 활용하면 GPIO를 제외한 기능을 여러 곳에서 사용하는 것이 가능하다.

 

[Table 5. High-density STM32F103xC/D/E pin definitions] 해당 표를 많이 사용하게 될 것이다.

- 직접 메모리 액세스를 위해서는 위의 표가 필요하다.

 

- keil 컴파일로 다운 받아 위의 업데이트를 수행한다.


예제 프로그래밍을 통한 기능 확인

다운 받은 keil을 실행시킨다.

'project' -> 'open project'를 선택한다.

자료실에서 받은 예제프로그램을 실행시킨 후 하이퍼터미널로 명령어를 전송하여 각 기능을 동작시켜본다.


반응형

'Busan IT > ARM Controller' 카테고리의 다른 글

내부 LED 반전 프로그램 만들기  (0) 2015.10.08
ARM 3 Core Test, 내부 LED 동작 프로그래밍  (0) 2015.10.06
ADC 전압측정  (0) 2015.09.18
Analogue to Digital Converter  (0) 2015.09.17
PWM(Pulse Width Modulation)  (0) 2015.09.14
Posted by newind2000
Busan IT/Assembly2015. 10. 2. 17:46

==================================Outline====================================

pop

pushad

----------------------------------------------------------------------------


pop

pop에 대해 알아보자.

 

pop명령어의 작업순서는,

 

1. 메모리에서 값 추출

2. 주소 값을 증가

 

리틀 엔디안을 빅 엔디안으로 변환하여 지정된 레지스터에 저장한다.

 

 

//처리에 메모리가 개입하게 되면 사이클이 증가한다.

 

 

pushad

 

모든 일반 레지스터를 pushpop을 할수 있는 명령어이다.

 

 


 

 

 

 

popad의 기능이 제대로 작동하는지 메모리에 값을 변경한 후 값을 확인해보자.

 

 

 

eflageip레지스터는 사용자가 직접적으로 조작할 수 없는 레지스터이다. 이것을 간접접근이 가능하다가 일컫는다.

 

eflag의 값을 조작하기 위해서는 pushpop을 사용해야 한다.

eip는 간접접근 조차도 사용하지 못하게 보호해 놓았다.

 

 

프로시져의 본문, 요청과 반환

 

 

함수 호출은 'call' 명령어와 주소를 사용함으로써 해당 주소에 있는 프로시져를 수행하게 된다. 하지만 함수의 주소를 알기 위해서는 메모리를 살펴보아야 하기 때문에 함수의 주소 값의 라벨인 함수의 이름을 입력한다.

 

eip는 다음에 실행될 코드의 메모리 주소를 가리킨다.

 

//esp : 0012ff8c

 

//00 40 10 43

 

_start의 주소: 0x0040103E

Initialize의 주소: 0x00401010

call 이전의 esp : 0012ff8c

call 이전의 eip : 0040103e

 

_start : e8 FF FF FF CD

 

call 명령어는 opCode8e이다. call 명령어는 1bytemnemonic4byte의 주소 총 5byte이다.

 

initialize라는 함수를 호출하는 코드를 살펴보자.

 

e8 FF FF FF CD 라는 코드를 해석해보면, 현재 코드가 끝난 값으로부터 -51바이트가 된 곳에 있는 코드를 실행하라는 내용이다.




반응형
Posted by newind2000
Busan IT/Assembly2015. 10. 1. 17:41

==================================Outline====================================

확장, 반복문

- ECX 점검 명령어 jecxz

- 배열

- 주소 값 복사 명령어 lea

- Pipe의 개념 

Procedures

- 80X86 Stack

----------------------------------------------------------------------------

 

ECX 점검 명령어 jecxz

 

교재 p/175

 

loop문에서 ECX0일 경우 -1 연산이 적용되면 값이 FFFFFFFF되어 버린다.(loop문이 아주 오래 동안 실행된다.)

 

je endFor

 

때문에 ECX0인지 확인을 해주어야 한다. 이때 사용 되는 명령어가 jecxz이다.

 

컴파일러는 프로그래머가 작성한 코드를 효율적으로 기계어로 변환해준다. 현재의 컴파일러는 성능이 향상 되어서 어셈블러 지식이 애매한 프로그래머보다는 최적화된 코드를 제공해준다.

 

C는 컴파일을 거치게 되면 assembly language가 나오게 된다. C를 사용함으로써 기계어와 대응하는 어셈블리어가 나오기 때문에 C언어는 40년째 사용되고 있다.

 

배열

 

교재 p/180, 

 

배열은 프로그래밍에 많이 사용된다. 배열 사용을 지원해주는 명령어에 대해 알아보자.

 

배열 복사를 위한 레지스터

 

ESI(Extended Source Index)

EDS(Extended Dest. Index)

 

주소 값 복사 명령어 lea

 

lea 명령어는 주소 값을 레지스터에 담는 명령어이다.

 

ex) lea ebx, nbrArray

 

 

mov [ebx], eax ;register indirect, 포인터 개념

; &ebx = eax;

 

C에서는 변수의 주소를 1 증가 시키면 변수의 크기만큼 증가하게 되지만 어셈블리에서는 주소는 전부 1byte로 취급하기 때문에 이동시키고 싶은 크기만큼 값을 더해주어야 한다.

 

 

lealoop를 배울 수 있는 예제 교제 p/182 [Program using array]

; p/182 program using array

.386
.MODEL FLAT

INCLUDE io.h            ; header file for input/output


ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD

cr   EQU 0dh  ; carriage return
Lf   EQU 0ah  ; linefeed
maxNbrs  EQU 100  ; size of number array

.STACK 4096    ; reserver 4096-byte stack


.DATA 

directions   BYTE  cr, Lf, "You may enter up to 100 numbers"
    BYTE  " one at a time. ", cr, Lf
    BYTE  "Use any negative number to terminate"
    BYTE  "input.", cr, Lf, Lf
    BYTE  "This Program will then report the average and" 
    BYTE  "list", cr, Lf
    BYTE  "those numbers which are above the"
    BYTE  "average.", cr, Lf, Lf, Lf, 0
Prompt    BYTE  "Number?  ",0
number    BYTE  20 DUP (?)
nbrArray  DWORD  maxNbrs DUP (?)
nbrElts    DWORD  ?
avgLabel  BYTE  cr, Lf, Lf, "The average is"
outValue  BYTE  11 DUP(?), cr, Lf, 0
aboveLabel  BYTE  cr, Lf, "Above Average:", cr,Lf,Lf,0


.CODE    

_start :

; input numbers into array
    
  output   directions
  mov  nbrElts, 0
  lea  ebx, nbrArray
  
whilePos:  output  prompt
    input  number, 20
    atod  number
    jng  endWhile
    mov  [ebx], eax
    inc  nbrElts
    add   ebx, 4
    jmp   whilePos
endWhile:

    mov  eax, 0
    lea   ebx, nbrArray
    mov  ecx, nbrElts

    jecxz  quit

forCount1:  add  eax, [ebx]
    add  ebx, 4
    loop  forCount1

    cdq
    idiv  nbrElts
    dtoa  outValue, eax
    output   avgLabel
    output  aboveLabel
    
    lea  ebx, nbrArray
    mov  ecx, nbrElts

forCount2:  cmp  [ebx], eax
    jng  endIfBig
    dtoa  outValue, [ebx]

    output  outValue

endIfBig:  
    add  ebx, 4
    loop  forCount2

quit:    INVOKE ExitProcess, 0  ; exit with return code 0

PUBLIC _start    ; make entry point public
END      ; end of source code



  


** lea 명령어는 활용도가 높음으로 잘 익혀두는 것이 좋다.

 

Pipe의 개념

 

교재 p/189,

 

 

CPU의 기본 운영 사이클은 다음과 같다.

 

1. 메모리에서 명령어를 가져온다.(fetch)

2. 명령어를 해석한다.(decode)

3. 명령어를 실행한다.(execute)

 

 

각 연산자의 대한 클럭 사이클을 표에서 여러 번 보았다. 이 때의 한 사이클은 CPU1clock을 뜻한다.

 

CPU의 효율을 생각한다면 conditional jump는 좋지 않다. 때문에 조건문을 최소화 하는 것이 pipelining을 최적화하는 방법이다.

 

 

 

chapter에서는 if, 다양한 반복문과 배열에 대해서 배웠다. jmp명령어는 무조건 이동(c에서 goto문과 같은 역할), 조건이동은 플래그의 상태와 operand를 비교함으로써 반복문을 다시 수행할지 빠져나올지 아니면 표시된 자리로 이동할지를 결정한다. loop문은 ECX 레지스터에 들어있는 수에서 -1을 함으로써 ECX 값이 0이 될 때까지 수행하게 된다. 만약 ECX레지스터가 초기에 0이라면 jecxz 명령어를 사용하여 빠져 나올 수 있다. lea 명령어는 변수에 있는 주소 값을 ECX레지스터에 복사하는 역할을 한다. 파이프라이닝은 CPU의 사이클인 fetch-decode-execute가 수행되는 절차와 조건 문이 사용될 때 컴파일 시 파이프라이닝이 초기화됨을 보여줌으로써 효율적인 프로그램을 작성하는데 필요한 CPU 작동 원리를 알려준다.

 

 

p/193 Chapter 6. Procedures

 

1. 80X86 Stack

 

자주 언급해온 메모리의 5대 영역중의 하나인 stack영역은 메모리의 시작번지와 끝 번지가 있다고 치면 끝 번지에서 시작한다.(완전히 끝은 아니지만 개념상 끝이라고 한다.) 메모리의 끝 부분이 stackbase 포인트, 즉 출발 시점이 된다. 이 때 사용되는 레지스터 EBP는 스택 메모리의 시작점이고 스택이 커질수록 ESPbase에서 멀어진다.

 

 

** 프로시져에 관한 내용은 블로그에 비공개로 올려 놓아야 한다.

 

 

esp를 옮기는 명령어는 push이다. 1bytepush되지 않는다.

stack은 최소 2byte 단위로 표시된다. 메모리가 개입할 때 속도가 느려지는 것을 알 수 있다.

push한다는 것은,

 

1. 스택 주소 = 스택 주소 - push한 크기(스택의 크기를 늘리는 작업)

2. 현재 주소 = 값 대입

우선 stack을 확장하고 난 후에 확장된 stack 공간에 자료가 삽입되게 된다.


 

 

pop명령어는 stack에 있는 자료를 꺼내어 레지스터에 저장하기 때문에 immediateoperand로 올 수 없다.

; push instruction

.386
.MODEL FLAT



ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD



.STACK 4096    ; reserver 4096-byte stack


.DATA 




.CODE    

_start :

mov   eax, 83B5h
push   ax
push  0FFFFFF10h




; input numbers into array
    


quit:    INVOKE ExitProcess, 0  ; exit with return code 0

PUBLIC _start    ; make entry point public
END      ; end of source code



  





 

반응형
Posted by newind2000
Busan IT/Assembly2015. 9. 30. 17:45

==================================Outline====================================

조건문의 사용

----------------------------------------------------------------------------

 

 

if문은 jumpcompare의 조합이다.

 

if문 두 개와 if ~else문을 구분해보면 if ~else문이 효율적이지만 큰 차이는 나지 않는다.

embedded에서는 한 푼도 줄 수 없기 때문에 if ~else를 사용하는 것이 좋다.

 

mnemonic loop

 

ECX는 카운트 레지스터로써 loop문을 만나면 1씩 감소하게 된다.

 

mov ecx, number ; number of iterations

...

 

loop forIndex ; repeat body number times

 

loop문은 기준으로 앞으로 127byte 뒤로 128byte가 넘어가게 되면 loop으로 돌아갈 수 없다. 때문에 128byte가 초과할 경우는 jump문을 사용해야 한다.

 

loope/loopzzero 플래그가 0일 때 빠져 나가게 되는 것이고, loopne/loopnzzero 플래그가 0이 아닐 때 빠져나가게 된다.

 

 

1부터 10까지 더하는 프로그램 for문과 while문으로 작성해보자.

 



 

for문이 jmp명령어가 하나 더 있음을 알 수 있다. 현재 코드는 최적화보다는 for문과 while문의 코드 작성 순서에 따른 차이라고 볼 수 있다.

 

 

 

 

반응형
Posted by newind2000
Busan IT/Assembly2015. 9. 24. 16:23

==================================Outline====================================

div 명령어 숙제

큰 수의 덧셈과 뺄셈
- 캐리 플래그 변경 명령어

분기와 순환
- 무조건 이동 

----------------------------------------------------------------------------

 div 명령어 숙제

 

[답안]

 

C = (5/9) * (F - 32)

9C = 5(F-32)

C = 5(F-32)/9

 

mov esi, 70        //esi = F

sub esi, 32        //esi = F - 32

imul esi, 5        // esi = 5(F-32)


mov edi, 9        //edi = 9

mov eax, esi    //eax = 5(F-32)

cdq                //register setting for div.

idiv edi          // eax = 5(F-32)/9


mov edi, eax    //edi = 5(F-32)/9


edi = 15h

 

 

큰 수의 덧셈과 뺄셈(pdf p/130)

 

64bit길이의 숫자를 계산하려면 32bit인 두 개의 변수를 선언하여 하위 32bit와 상위 32bit를 더해준 후에 올림수만 처리해주면 된다. 이 때 adc 명령어를 사용한다.

 

adc = 올림수가 생기는 것까지 포함하여 덧셈을 해주는 연산

 

A B C

+ D E F

----------

 

add C + F ; 일의 자리수는 일반 덧셈 사용

adc B + E ; 올림수가 발생하는 자리는 adc 사용

adc A + D ; 올림수가 발생하는 자리는 adc 사용

 

 

 

덧셈이나 뺄셈 모두 뒤에서부터 올림 수나 빌림 수를 생각하여 계산해야 한다.

 

캐리 플래그 변경 명령어

 

clc: 클리어(0)

stc: (1)

cmc: 보수(0이면 1, 1이면 0)

 

 

 

분기와 순환(Branching and Looping)

 

 

무조건 이동

 

 

Cgoto문과 같은 기능을 한다. 명령어는 jmp이다. 실행 코드 안에서 이동하기 때문에 코드 영역의 주소를 알아야 한다. 때문에 코드 영역에 라벨을 표시하여 명령어가 실행되면 라벨이 표시된 곳으로 이동한다.

 

 

라벨을 표시하는 방법은 라벨:' //라벨은 사용자가 지정

 

 

pdf p/152 예제




jmp는 앞은 물론 뒤로도 가능하다.

 

jmp를 사용할 때 라벨은 문자임으로 어셈블러는 라벨을 숫자로 기억하고 라벨이 끝나는 자리를 기준으로 라벨이 붙혀진 곳을 계산하여 라벨점으로 이동하게 된다.

 

라벨 후 숫자의 용량을 뜻한다. short 1BYTE near4BYTE이다.

 

레지스터도 jmp명령어의 라벨이 될 수 있다. 이것을 레지스터 indirect라고 부른다.

또한 메모리에 저장된 값도 이동 기준이 될 수 있다.


반응형

'Busan IT > Assembly' 카테고리의 다른 글

확장/반복문, Procedures  (0) 2015.10.01
조건문의 사용  (4) 2015.09.30
기본 명령어(나눗셈, 나눗셈 연산 준비, 레지스터 확장)  (1) 2015.09.24
기본 명령어(inc, dec, neg, mul, imul)  (0) 2015.09.22
mov 명령어  (0) 2015.09.21
Posted by newind2000
Busan IT/센서 제어2015. 9. 24. 12:07

==================================Outline====================================

적외선 센서 코딩

----------------------------------------------------------------------------

 

적외선 센서 코딩

 

적외선 센서를 동작시키기 위한 코딩을 해보자.

 

우선 하드웨어 설정을 한 후 데이터 시트를 보고 하나 하나 코딩을 한다.


우선 기본적으로 알아야 할 점들.

- 입력 전압은 3.3V이다. 물체의 표면을 500ms 이내에 정확하게 측정할 수 있다.

- DTS-L300-V2온도계산 프로세서를 내장하고 있어 따로 온도 계산이 필요 없다.

- DTS-L300-V2는 디지털 통신으로 온도 값을 출력한다. 때문에 통신의 연결이 필요하다.

- 주변 온도와 대상 온도를 동시에 측정한다.

 

VCCGND를 제외하고 사용하는 핀은 4개이다.

- SCK: 클럭 공급

- SCE: 적외선 센서 활성화

- SDI: 신호를 입력

- SDO: 신호를 출력

 

이러한 신호들은 SPI통신을 통해 이루어지기 때문에 SPI사용에 대한 숙지를 해야 한다.

 


 

SPI에 대한 학습이 되어 있지 않음으로 우선 I/O를 사용하여 코딩에 성공하면 SPI를 사용하여 코딩을 하도록 하자.

 

우선 데이터 시트에 나와 있는 코드를 주석을 사용하여 해석해보자.

 

unsigned char buffer_Lo, buffer_Hi, p02; //1byte선언


long CHECK(unsigned char datum) //2byte return 함수

{
  
    unsigned char i= 0;
    buffer Lo = 0//버퍼 비워주기
    buffer Hi = 0//버퍼 비워주기
 

    /*** 적외선 준비 설정 ***/
    EN_LOW; //enable low
    delay us(10); //10us 딜레이
    for(i=0; i<8; ++i)
    {
        if( ( (0x80 >> i ) & datum) == 0)
        {
            SDO_LOW; //SDO = 0;
        }
        else
        {
            SDO_HIGH; //SDO = 1;
        }

}

SDO_LOW; //SDO = 0;
delay_ms(10); //10ms 딜레이
/*** 하위 바이트 읽기 ***/
for(i=0; i<8; I++)
{
        buffer_Lo = buffer_Lo << 1//하위 버퍼 좌로 한비트 밀기
        SCK_LOW; //SCK = 0;
        delay_us(1); //1us 딜레이
        SCK_HIGH; //SCK = 1;
        dealy_us(1); //1us 딜레이
        p02 = FP02 //포트의 상태 읽기
        if(p02 == 1)
        {
            buffer_Lo = buffer_Lo|0x01;}
        }
        else
        {
            buffer_Lo = buffer_Lo&0xFE;
         }
}
SDO_LOW; //SDO = 0;
delay_ms(10); //10ms 딜레이

/*** 상위 바이트 읽기 ***/

for(i=0; i<8; i++)
{
     buffer_Hi = buffer_Hi << 1//상위 버퍼 좌로 한비트 밀기
     SCK_LOW; //SCK = 0;
     delay_us(1); //1us 딜레이
     SCK_HIGH; //SCK = 1;
     dealy_us(1); //1us 딜레이
     p02 = FP02 //포트의 상태를 변수에 담아서 판단
     if(p02 == 1)
     {
         buffer_Hi = buffer_Hi|0x01;}
     }
     else
     {
         buffer_Lo = buffer_Lo&0xFE;
     }
}
EN_HIGH; //enable = 1;
return (buffer_Hi*256 + buffer_Lo);

}

 

void main(void)
{
    while(1)
    {
        Target_Value = CHECK(0xa0); // 대상 온도
        delay_ms(50);
         Ambient_Value = CHECK(0xa0); // 주변 온도
        delay_ms(500);
        //LCD에 값 출력 코드 넣기
    }

}

대충 감이 잡히면 코딩을 해보도록 하자. 순서는 아래와 같다.

  

1. 각 핀의 포트설정

 

DDRJ = 0x07; //0~2번핀 출력, 3번핀 입력

 

2. 입력 값에 대한 high, low 값 정의

 

#define SCE_LOW PORTJ=PORTJ&(~0x01)

#define SCE_HIGH PORTJ=PORTJ|0x01

 

#define SCK_LOW PORTJ=PORTJ&(~0x02)

#define SCK_HIGH PORTJ=PORTJ|0x02

 

#define SDO_LOW PORTJ=PORTJ&(~0x08)

#define SDO_HIGH PORTJ=PORTJ|0x08

 

 

 

3. SPI 함수 해석하여 작성

 

int SPI(unsigned char uiMode)

{

unsigned char ucCnt;

ucBuf_Low = ucBuf_High = 0;

SCE_LOW; //enable low

 

(진행 중)

}

 

 

4. main에서 적외선 센서 감지 값을 LCD에서 출력하도록 설정

5. main에서 적외선 센서 감지 값을 LCD로 출력





#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

// B0 : /SS, B1 : SCK, B2 : MOSI, B3 : MISO

#define SS_HIGH   PORTB=PORTB|0x01
#define SS_LOW     PORTB=PORTB&(~0x01)
#define SCK_HIGH   PORTB=PORTB|0x02
#define SCK_LOW   PORTB=PORTB&(~0x02)
#define MOSI_HIGH   PORTB=PORTB|0x04
#define MOSI_LOW   PORTB=PORTB&(~0x04)



// SPI 쓰기 함수 
void SPI_Write(void)
{
  unsigned int uiCnt;
  unsigned int uiData=0;

  SS_LOW;  // /CS = 0
  for(uiCnt=0; uiCnt<8; ++uiCnt)
  {
    if(0xA0 & uiCnt)
    {
      uiData = uiData | 0x01;
    }
    else
    {
      uiData = uiData & (~0x01);

    }
    uiData <<= 1
  
  }
  SDI  // Data 쓰기
  // Delay 10ms
  // Data 쓰기
  // Delay 10ms
  // Data 쓰기
  // /CS = 1
  // Delay 50ms
  // /CS = 0
  // Data 쓰기
  // Delay 10ms
  // Data 쓰기
  // Delay 10ms
  // Data 쓰기
  // /CS = 1
  // Delay
}

// SPI 읽기 함수
unsigned char SPI_Read(void)
{

  // Data 읽기

  // Data 반환
}

int main(void)
{


  // GPIO B 설정
  DDRB = 0xF7;  
  // B0 : /SS, B1 : SCK, B2 : MOSI, B3 : MISO
  
  // SPI
  SPCR = 0b11111101;
  SPSR  = 0b00000000;
  while(1)
  {
    SPI_Write();  // Data 쓰기 실행
    
    // 받은 데이터를 출력한다.
      
  }
  return 0;
}

 

 

 

반응형
Posted by newind2000
Busan IT/Assembly2015. 9. 24. 09:27

==================================Outline====================================

기본 명령어

- 나눗셈 idev/dev

- 나눗셈 연산 준비 cbw, cwd, cdq, cwde

- 레지스터 확장 movezx, movesx

----------------------------------------------------------------------------

 

** 박스의 겉넓이를 구하는 공식에 대한 assembly 공식 문제 풀이

 


2{length(width + height) + width*height)

bx = width + height

cx = width * height


1. bx = width + height

2. cx = width * height

3. ax = bx * length   

4. dx = ax        // dx = length(width+height)

5. dx = dx + cx  // dx = length(width+height) + width * height

5. dx = dx + dx  // dx = 2{length(width+height) + width * height}


나눗셈 idev/dev

나눗셈에 대하여 알아보자. 나눗셈은 division의 약자인 div를 사용한다. div는 양수만을 나눌 때 사용되고 idiv는 음수와 양수 모두(정수)에 사용된다.

 

//imulsigned(정수)이다.

16비트로 나누면 8비트, 8비트 나누어진다.

 

Assembly에서는 나눗셈 연산을 수행하면 몫과 나머지가 동시에 저장된다. 즉 소수점 계산이 아닌 정수 계산으로 연산이 진행된다.

 

 

 

/헥사 값의 첫 수에 영어가 나왔을 때 반드시 0을 붙혀 주어야 한다.

 

 

 

pdf p/133, 134 예제 해보기

책에 나와 있는 그대로 예제를 사용하여 그 값을 확인하면 된다. 어렵지 않다.

 




idiv는 연산 중에 가장 많은 사이클을 소모함을 알 수 있다.

양수는 그나마 사이클을 덜 소모한다.

 

때문에 코딩 시 음수를 사용하지 않는 경우 양수를 사용하는 것이 프로그램 성능에 도움이 된다.

 

나눗셈 연산 준비 cbw, cwd, cdq, cwde


나눗셈을 하는 경우 결과 값은 몫과 나머지가 나오기 때문에 몫과 나머지가 출력되는 레지스터를 정리할 필요가 있다. 몫은 AX레지스터에 입력됨으로 따로 신경 쓸 필요가 없지만 2byte1byte로 나누는 경우 이외의 같은 용량의 바이트의 제수가 피제수를 나누는 경우 DX레지스터를 준비해 주어야 한다.

 

주의함 점은 양수인 경우 확장 레지스터를 0, 음수인 경우 1을 넣어주어야 하는데 이 작업을 수행해주는 명령어가 존재한다. 아래의 명령어들은 operand가 필요없다는 점은 알아야 한다.

 

cbw(convert byte to word): AL -> AX로 확장

cwd(convert word to double): AX -> DX로 확장

cdq(convert double to quardword): EAX -> EDX로 확장

cwde(convert word to double extended): AX -> EAX(일반적으로 나눗셈을 위해 사용되는 명령어이다)



 

//음수인 경우의 수는 오른쪽 쉬프트를 사용할 때 가장 왼쪽 자리의 수는 1로 채워진다.

//음수를 유지하기 위한 작업이다.

 

 

레지스터 확장 movezx, movesx 

 

 

movezx 레지스터가 2byte인 경우 4byte로 확장하면서 0으로 채워준다.

movesx의 경우에는 레지스터의 값이 음수인지 양수인지 판단 후 확장시켜 준다.

 

movesxcwde명령어와 비슷하지만 cwdeAX레지스터에 한정된다는 점이 다르다.

 





반응형
Posted by newind2000
Busan IT/센서 제어2015. 9. 24. 09:09

==================================Outline====================================

서머 커플러

적외선 센서

----------------------------------------------------------------------------

서머 커플러

서머 커플러(Thermocoupler)의 처리도는 아래와 같다.

 

TC K-Type -> Driver IC(MAX6675) -> ATmega8A -> ULN2803A -> FND -> ECR(Error ??? Register)

 

일반적으로 센서의 사용 전압은 -10V ~ 10V, -5V ~ 5V

전류는 4mA ~ 20mA, 0mA ~ 20mA이다.

 

4mA ~ 20mA를 사용하는 이유는 단선 여부를 확인하기 위해서이다.

 

온도 센서는 2가지 틀(온도를 측정하는 방법)로 나뉜다.

1. 접촉: thermistor, Pt 100Ω, Pt 1000Ω, 열전대

2. 비접촉(적외선 센서): 열화상 카메라, 적외선 온도계

 

대부분의 온도계는 접촉식이지만 비접촉식도 있다. 비접촉 식은 흔히 적외선 센서라고 생각하면 된다. 열은 적외선을 방출하기 때문에 적외선으로 온도를 측정할 수 있다.

 

접속식은 저가이고 출력 값이 아날로그 값이다. 비접촉식은 고가이며 출력 값이 디지털 값이다.

 

//저가는 천원미만


적외선 센서 

적외선 센서에 대하여 살펴보자.

출력 값이 디지털이기 때문에 노이즈에 대한 신경을 쓰지 않아도 된다.


 

해당 센서는 사람의 체온을 재기에는 사치일 수 있다. 온도의 측정 구간이 크기 때문이다.

 

전압이 2.4v - 3.6v이기 때문에 ARM3.3v를 사용하는 것이 편하다.





SDI에서 명령을 내리면 SDO에서 값을 측정하게 된다.

 

//데이터시트 4~5page를 보고 코딩을 하면 된다.

 


데이터 시트에 있는 참고용 소스를 활용하여 코딩을 해보자.









반응형

'Busan IT > 센서 제어' 카테고리의 다른 글

적외선 센서 코딩  (0) 2015.09.24
자동차 후진 경고 센서  (0) 2015.09.14
온도계 섭씨 화씨 변경, 초음파의 특성  (0) 2015.09.10
C#을 활용한 NTC 온도 센서  (0) 2015.09.04
NTC 온도계 저항값 변환  (0) 2015.09.04
Posted by newind2000