Busan IT/로봇제어2015. 11. 2. 15:50

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

저수준 프로그래밍

- GPIO를 제어하는 레지스터

- GPIO를 활용한 LED 제어

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

 

저수준 C 프로그래밍

 

p/459

 

ATmega 시리즈에서는 PORTx로 각 핀을 제어하면 값을 넣을 때마다 모든 값이 갱신된다. ARM 시리즈에서는 SET레지스터와 CLEAR레지스터가 따로 있어서 값이 갱신되는 것을 방지한다. 또한 해당 비트를 갱신해주지 않는 한 해당 핀의 값은 유지된다.

라즈베리파이의 하드웨어를 제어하려면 하드웨어에 대한 정보가 있어야 한다. 라즈베리파이는 브로드컴의 BCM2835 칩셋을 사용하고 있다. 데이터시트는 URL을 통해 내려 받을 수 있다.

(http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf)

AP(Application Process)CPU제조에서 도면을 구입하여 제작한 CPU제품을 말한다.

 

GPIO를 제어하는 레지스터

 

GPFSELn(GPIO Alternate function select register, n: 0 ~ 5): 핀의 기능 설정

GPSETn(GPIO Pin Output Set Register): /출력 모드 시, high설정

GPCLRn(GPIO Output Clear Register): /출력 모드 시, low설정

GPLEVn(GPIO Pin Level Registers, n: 0 ~ 1): /출력 모드 시, 해당 핀의 값 확인

GPEDSn(GPIO Event Detect Status Register): /출력 모드 시, 특정 핀의 상태 변화를 감지

GPRENn(GPIO Pin Rising Edge Detect Enable): /출력 모드 시, 상승 에지 감지

GPFENn(GPIO Pin Falling Edge Detect Enable): /출력 모드 시, 하강 에지 감지

GPPUD(GPIO Pull-up/down Registers): /출력 모드 시, 풀업 풀다운 기능 설정

 

실제 메모리의 주소로는 접근할 수 없고 가상 주소를 사용해야 한다.

 

'c'는 캐릭터 디바이스


GPIO를 활용한 LED 제어

p/472 

 

운영체제에서는 메모리 사용의 효율성을 위해서 가상 메모리를 사용하게 되고 메모리 보호를 위해서 물리적 메모리의 직접적인 접근을 허용하지 않는다. 때문에 메모리에 접근하려면 가상 메모리의 주소를 알아야 한다. 물리 메모리의 주소를 입력하면 가상화 메모리 주소로 변환시켜주는 함수 'mmap'을 사용해야 한다.



RaspberryPi2의 물리메모리 주소는 ‘3F’로 시작한다.


 

교재의 예제를 코딩해보자.



 

/*** 소스 ***/

 #include <stdio.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/mman.h>

 int main()
 {
     int mem_fd;
     int i;
     unsigned int *GPIO_BASE;
     unsigned int *GPIO_GPFSEL1;
     unsigned int *GPIO_GPSET0;
     unsigned int *GPIO_GPCRL0;

     mem_fd = open("/dev/mem", O_RDWR|O_SYNC);

     GPIO_BASE = (unsigned int *)mmap(00x60, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0x3F200000);

     GPIO_GPFSEL1 = (unsigned int *)(GPIO_BASE + 0x04/4);
     GPIO_GPSET0 = (unsigned int *)(GPIO_BASE + 0x1c/4);
     GPIO_GPCRL0 = (unsigned int *)(GPIO_BASE + 0x28/4);

     *GPIO_GPFSEL1 &= 0xFF1FFFFF;
     usleep(2000);
     *GPIO_GPFSEL1 |= (0x1 << 21);
     usleep(2000);

     for(i=0; i < 5; ++i)
     {
         *GPIO_GPSET0 |= (0x1 << 17);
         printf("GPIO17 LED on\n");
         sleep(1);
         *GPIO_GPCRL0 |= (0x1 << 17);
         printf("GPIO17 LED off\n");
         sleep(1);
     }

     close(mem_fd);
     munmap(GPIO_BASE, 0x60);

     return 0;
 }

 


반응형
Posted by newind2000
Busan IT/ARM Controller2015. 11. 2. 12:06

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

PWM를 사용한 LED 불 밝기 조절

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

 

PWM를 사용한 LED 불 밝기 조절

 

PA0번 핀의 기능을 확인해보자.

 

[PA0]

 

 

PA0PWM의 출력으로 사용 설정을 해준다

 

1. PA/AFIO/TIM2 clock 공급: RCC->APB2ENR, APB1ENR

2. PA 설정: PA0 출력 설정. AFIO를 사용한다. 내부적인 특수 기능을 사용하기 때문에 AFIO를 사용해야 한다.

 

출력 설정 시 open drainpush pull을 사용할 수 있다. push/pull은 입출력시 high/low값이 확실하게 구분된다. open drain값은 high출력이 없고 low만 존재한다. open drain은 그라운드 연결을 스위치로 제어하면서 제어하는 방식을 뜻한다.

 

3. TIM2 설정: TIM2_ARR은 카운팅 시 꼭지점이다. TIM2_CCR은 카운터의 비교 값이 들어있는 레지스터이다. 카운터의 값이 CCR과 일치할 경우 인터럽트가 발생한다.

 

 

특정 키를 입력 받았을 때 불 밝기가 조절 되도록 코딩을 해보자.





/*** 소스 ***/

#include <stm32f10x.h>
volatile unsigned int Timer2_Counter=0;
 
void init_port(void)
{    
    GPIO_InitTypeDef PORTA;
    GPIO_InitTypeDef PORTC;
 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);
     
    PORTA.GPIO_Pin = GPIO_Pin_0;
    PORTA.GPIO_Mode = GPIO_Mode_AF_PP;
    PORTA.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_Init(GPIOA, &PORTA);
     
    PORTC.GPIO_Pin = GPIO_Pin_12;
    PORTC.GPIO_Mode = GPIO_Mode_Out_PP;
    PORTC.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_Init(GPIOC, &PORTC);
}
 
void TIM2_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET)
    {
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // Clear the interrupt flag
        Timer2_Counter++;
        GPIOC->BRR = GPIO_Pin_12;  // PB0 OFF
    }
 
    if(TIM_GetITStatus(TIM2,TIM_IT_CC1) != RESET)
    {
        TIM_ClearITPendingBit(TIM2,TIM_IT_CC1);
        GPIOC->BSRR = GPIO_Pin_12;  // PB0 ON
    }
}
 
void init_Timer2()
{
    NVIC_InitTypeDef NVIC_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef OutputChannel;    
     
    /* TIM2 Clock Enable */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
     
    /* Enable TIM2 Global Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
     
    /* TIM2 Initialize */   
    TIM_TimeBaseStructure.TIM_Period=100-1// 100kHz
    TIM_TimeBaseStructure.TIM_Prescaler=24-1;
    TIM_TimeBaseStructure.TIM_ClockDivision=0;
    TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
     
    /* TIM2 PWM Initialize */
    OutputChannel.TIM_OCMode = TIM_OCMode_PWM1;
    OutputChannel.TIM_OutputState=TIM_OutputState_Enable;
    OutputChannel.TIM_OutputNState=TIM_OutputNState_Enable;
    OutputChannel.TIM_Pulse=50-1// 50% duty ratio
    OutputChannel.TIM_OCPolarity=TIM_OCPolarity_Low;
    OutputChannel.TIM_OCNPolarity=TIM_OCNPolarity_High;
    OutputChannel.TIM_OCIdleState=TIM_OCIdleState_Set;
    OutputChannel.TIM_OCNIdleState=TIM_OCIdleState_Reset;
    TIM_OC1Init(TIM2,&OutputChannel);
     
    /* TIM2 Enale */
    TIM_Cmd(TIM2,ENABLE);
    TIM_ITConfig(TIM2,TIM_IT_Update | TIM_IT_CC1 ,ENABLE); // interrupt enable
}
 
void make_pwm(u16 val)
{
    TIM_OCInitTypeDef OutputChannel;
     
    OutputChannel.TIM_OCMode = TIM_OCMode_PWM1;
    OutputChannel.TIM_OutputState=TIM_OutputState_Enable;
    OutputChannel.TIM_OutputNState=TIM_OutputNState_Enable;
    OutputChannel.TIM_Pulse=val;
    OutputChannel.TIM_OCPolarity=TIM_OCPolarity_Low;
    OutputChannel.TIM_OCNPolarity=TIM_OCNPolarity_High;
    OutputChannel.TIM_OCIdleState=TIM_OCIdleState_Set;
    OutputChannel.TIM_OCNIdleState=TIM_OCIdleState_Reset;
    TIM_OC1Init(TIM2,&OutputChannel);
}
 
void delay(unsigned int del)
{
    Timer2_Counter=0;
    while(Timer2_Counter < del);
}
 
int main()
{
    u16 i;
    SystemInit();
    init_port();
    init_Timer2();
     
    while(1)
    {        
        for(i=0; i<100; i++)
        {
            TIM2->CCR1 = i;
            delay(100);
        }
         
        for(i=98; i>0; i--)
        {
            TIM2->CCR1 = i;
            delay(100);
        }
    }
}


반응형

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

USART를 활용한 LED ON/OFF  (0) 2015.10.30
Timer를 활용한 LED제어, LCD 제어  (0) 2015.10.20
Timer  (0) 2015.10.19
Advanced-control timers(TIM1&8)  (0) 2015.10.16
인터럽트 코드 분석  (0) 2015.10.13
Posted by newind2000
Busan IT/Assembly2015. 11. 2. 08:52

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

Repeat Prefixes and More String Instructions

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

 

Repeat Prefixes and More String Instructions

 

p/239

 

 

'rep' 명령어는 ‘ecx’ 레지스터를 카운터로 사용한다.

 

'rep'를 풀어서 쓰면 다음과 같다.

 

rep movsb

 

jecxz endCopy ;skip loop if count is zero

 

copy: movsb ;move 1 character

loop copy ;decrement count and continue

 

endCopy:

'ecx' 값은 'rep' 명령어 operand가 수행되기 전에 0인지 확인되고 'ZF'플래그는 operand가 수행되고 나서 검사가 된다.

 

첫 번째 문자가 같지 않으면 'ecx'값과 ‘ZF' 값이 동시에 0이 아님으로 ’repz'명령어는 멈추게 된다.

 

//‘repz’/‘repe’는 같은 명령어이다.

교재 p/244 String search program



[sca.asm]


.386
.MODEL FLAT
ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD
INCLUDE io.h
cr  equ   0dh
Lf  equ   0ah

.STACK 4096

.DATA
prompt1    BYTE   "String to search? "0
prompt2    BYTE   cr, Lf, "Key to search for? "0
target    BYTE  80 DUP (?)
key    BYTE  80 DUP (?)
trgtLength  DWORD  ?
KeyLength  DWORD  ?
lastPosn  DWORD  ?
failure    BYTE  cr, Lf, Lf, "The key does not appear in the string.", cr, Lf, 0
success    BYTE  cr, Lf, Lf, "The key appear in the string."
position  BYTE  11 DUP (?)
    BYTE  " in the string.", cr, Lf, 0

PUBLIC _start
.CODE

_start:    output   prompt1  ;
    input  target,  80 ;
    lea  eax,  target ;
    push  eax ;
    call  strlen ;
    mov  trgtLength,  eax;
    output  prompt2 ;
    input   key, 80 ;
    lea  eax,  key ;
    push  eax ;
    call  strlen ;
    mov  keyLength, eax ;

    mov  eax, trgtLength ;
    sub  eax, keyLength ;
    inc   eax ;
    mov lastPosn,  eax ;
    cld

    mov  eax, 1 ;

whilePosn:  cmp  eax, lastPosn ;
    jnle  endWhilePosn ;

    lea  esi, target ;
    add   esi, eax ;
    dec  esi ;
    lea  edi, key ;
    mov  ecx, keyLength ;
    repe  cmpsb ;
    jz  found ;
    inc  eax ;
    jmp  whilePosn ;
endWhilePosn:
    output  failure ;
    jmp  quit ;

found:    dtoa  position, eax ;
    output   success ;
quit:
    INVOKE ExitProcess,  0 ;

strlen    PROC  NEAR32 ;

    push  ebp ;
    mov  ebp, esp ;
    pushf ;
    push  ebx ;
    sub  eax, eax ;
    mov  ebx,  [ebp+8] ;

whileChar:  cmp  BYTE PTR [ebx], 0 ;
    je  endWhileChar ;
    inc   eax ;
    inc  ebx ;
    jmp  whileChar ;

endWhileChar:
    pop  ebx ;
    popf ;
    pop  ebp ;
    ret  4

strlen    ENDP

    END

 

 

 

 


반응형
Posted by newind2000