Cortex-M3/STM32F1032010.05.13 13:24
[임베디드/Cortex-M3] - (STM32 무작정 LED켜기 1) AHB와 APB

(STM32 무작정 LED켜기 1) 에서 GPIO 에 해당하는 APB2 BUS에 클럭을 공급해줬으니. 이제는 GPIO포트에 DATA를 보내주기만 하면 된다 ! 

우선 GPIO관련 레지스터를 살펴보면
(RM0008)'Datasheet에도 있는거같다.'



GPIOx_CRL : Port configuration register low
GPIOx_CRH : Port configuration register high
GPIOx_IDR : Port input data register
GPIOx_ODR : Port output data register
GPIOx_BSSR : Port bit set/reset register
GPIOx_BRR : Port bit reset register
GPIOx_LCKR : Port configuration lock register

여기서 잠깐 집고 넘어가야할것은. 레지스터 이름을 보면 GPIOx_CRL, GPIOx_CRH 라고 x가 붙는데 
(RM0008) 아래그림은 GPIOx_CRL의 레지스터 설명이다.
뒤에보면 (x=A..G) 라고 적혀있는데 x가 말하는것이 A~G까지 된다. 

GPIOA_CRL
GPIOB_CRL
       .
       .
GPIOG_CRL 

즉 모든 CRL레지스터는 이름(주소)만 틀릴뿐 같은모양이다. 

그러므로 A포트를 제어하는것과 B포트를 제어하는것은 레지스터 번지만 틀릴뿐이지 똑같다는 것이다. (CPU입장에서..)
(CPU입장에서) LED를 켠다는것은 GPIO PORT로 High든 Low든 출력을 내보내야 함으로. ('음.. 말이 어렵네..')
GPIOx_CRL,  GPIOx_CRH,  
GPIOx_ODR
이 3가지 레지스터를 봐야한다.


GPIOx_CRL,  GPIOx_CRH
Port Configuration Register Low
Port Configuration Register High

0~3 Bit의 CNF0, MODE0 이 두가지가 계속 반복된다 
MODEx (x=0...15) 즉 외부로 나와있는 Port의 갯수를 말하는것이다.
(PORTA는 PA0, PA1, ... PA15까지 있으므로 각 해당하는 Bit를 설정할수 있는것이다) 

GPIOx_CRL (Low)는  0~7 Bit까지 설정할수있고
GPIOx_CRH (High)는 8~15 Bit까지 설정할수있다.

아래그램(RM0008)을보면 CNF와 MODE를 설정하는데있어서의 설명이 나와있다.
Reset Value가 0x4444 4444이므로 
이런식으로 Bit가 초기화 되어있을것이다.

MODEx 에는 0b00 이므로 InputMode이고
CNFx에는 0b01이므로 Input모드에서 0b01은 Floating Input이므로 
Reset되었을때 포트의 초기값은 Input모드로 설정이 되어있다.

우리는 LED를 켜기위해(출력) Output Mode로 설정해야 한다.
MODEx = 0b01;
로 셋팅해서 OutputMode로 만들어준다 (Max Speed는 Output으로 나오는 신호의 주기를 나타낸단다.. )
단순히 LED 켜는 기능에서는 어느속도로 해도 상관이 없으므로 max speed 10MHz로 설정한다.

다음은 CNF의 설정이다.
Output Mode에서의 CNF설정은 
General Purpose로 사용할것이냐, Alternate Function으로 사용할것이냐 두가지로 나뉘는데 
우리는 General Purpose로 사용할 것이다. 
('아직 Alternate Function이 정확하게 어떤놈인지 모르겠다.. 저모드로 설정하면 GPIO로 I2C같은 통신도 구현할수도 있다고 하는데.. 나중에 써볼일이 있겠지뭐..')

그럼 걸러진게 General Purpose Output에서 Push-Pull이냐, Open-Drain이냐를 선택해야 하는데..

(Datasheet) Basic Structure of an I/O Port Bit에 보면
Push-Pull은 내부에 (INPUT DRIVER)를 이용해서 High나 Low를 출력시키는것이고
Open-Drain은 내부 (OUTPUT DRIVER)의 FET를 이용해서 HIGH나 LOW를 출력시키는 것이다. 
('두개가 틀린점이 있다지만.. 간단하게 생각하면 같은거라고 생각하고 넘어가자.. -_-; ')

자세한것은 푸우님의 블로그.. 
윤교수님의 기술노트 9
('아직 정확하게 이해가안되서 서술하기가 힘들다..ㅠㅠ')


어쨋든 두가지경우중 아무거나 써도 지금은 문제가 없을거 같다!

그러므로 . 

CNFx = 0b00;  으로 사용을 하겠다.



자 이제 PORTx를 General Purpose Output Push-Pull (Max Speed 10MHz)로 설정했으니. 
이제는 Push-Pull을 이용해서 HIGH이든, LOW이든 출력만 시켜주면 된다. 

(RM0008)아래그림은 
GPIOx_ODR 레지스터에 대한 설명이다.
레지스터 이름에서 느껴지듯이 Port의 Output Data를 설정하는 레지스터이다.
1을 넣으면 HIGH가 출력이되고, 0을 넣으면 LOW가 출력이된다.


1장의 LED회로에서 보면 PORT에 LOW를 출력시켯을때 LED가 켜지니. 
GPIOx_ODR레지스터에 해당비트에 0을 쏴주면 되겠다.

아래회로의 LED를 전부 켜기 위해서는

간단하게.
GPIOA_ODR = 0;
GPIOE_ODR = 0;
라고 적어주면 되겟다. (ODR의 Reset Value가 0x0000 0000 이므로 위 코드가 없더라도 LED는 켜질 것이다.)


#define  RCC_APB2ENR    (*(volatile unsigned int*)0x40021018)  
#define  GPIOA_CRH
#define  GPIOA_CRL    (*(volatile unsigned int*)0x40010800)

#define  GPIOE_CRH    
#define  GPIOE_CRL    (*(volatile unsigned int*)0x40011800)

int main()
{

  RCC_APB2ENR |= (1<<2| (1<<6);    

  GPIOA_CRL |= (0x3333 << 16);

  GPIOE_CRL |= 0x3333;

  while(1);
}

위의 소스를 사용하여 LED1~8번까지 켜보았다.

사용하는 보드는 STM32-OAK보드이다.
http://cafe.naver.com/armcortex 

LED는 기본 초록색 LED가 다닥다닥 붙어있어서 잘 티가나지 않아서 굴러다니는거 몇개 줒어서 바꿔 보았다.ㅎ  





Posted by 시긔양

댓글을 달아 주세요

  1. 이제 한번 해보려고 보는 중인데 정말 자세히 설명되있네요.
    그런데 보다보니
    "General Purpose Output Push-Pull (Max Speed 10MHz)" 라고 하셨는데,
    그러면 세팅이 0x01 라고 해야 하지 않나요 ?
    3으로 하면 동작 주파수가 50MHz 아닌가요 ?

    2011.08.20 22:35 신고 [ ADDR : EDIT/ DEL : REPLY ]

Cortex-M3/STM32F1032010.05.12 19:38

STM32F103 Datasheet의 내용이다.
아래 그림을 보면 여러종류의 BUS가 있는데 그중 GPIO, USART등의 주변장치를 이어주는 BUS이다.


AHB는 두개의 APB(APB1, APB2)를 연결해주고 
APB1은 최고 36MHz
APB2는 최고 72MHz로 동작한단다.
'GPIO, USART1, SPI1, ADC1 등 APB2에 속한놈들이 더빨리 동작하겠군..'
'datasheet의 memory map을 보면 AHB에도 뭔가가 있다.'


우선 LED를 제어해보기 위해.. 
'LED는 외부 회로상에 연결 된거기때문에.. GPIO.. 음.. 그럼 GPIO가 속해있는 APB2를 건들여야 하겠군..'
'LED가 Low에서 켜지는지, High에서 켜지는지는 나중에 생각하도록하고..'

RM0008 Reference manual(이하 RM0008)을 보면 RCC레지스터가 있다.
-Reset and clock control register (RCC)
밑에 그림은 RCC register map이며 리셋시 값이 어떻게 되는지 보여주는 표이다 (RM0008)




위에서부터 정리해보면
RCC_CR : Clock Control
RCC_CFGR : Clock Configuration
RCC_CIR : Clock Interrupt
RCC_APB2RSTR : APB2 Peripheral Reset
RCC_APB1RSTR : APB1 Peripheral Reset
RCC_AHBENR : AHB Peripheral Clock Enable
RCC_APB2ENR : APB2 Peripheral Clock Enable
RCC_APB1ENR : APB1 Peripheral Clock Enable
RCC_BDCR : Backup Domain Control
RCC_CSR : Control/Status

'이름을 보니 뭔가 클럭틱한(?) 레지스터들이다..'

우선은 LED를 켜야하니.. LED는 GPIO에 연결되어있고 GPIO는 APB2라는놈과 관련이 있으니..
RCC_APB2RSTR : APB2 Peripheral Reset
RCC_APB2ENR  : APB2 Peripheral Clock Enable

이 두개의 레지스터와 크게 관련이 있을거 같아서 살펴보겠다.

우선 RCC_APB2RSTR
(RM0008) 아래 그림에서 보면 해당비트에 '1'을 넣으면 해당 기능이 Reset된단다.. 
Reset Value가 전부 0 이므로 아직은 아무일도 일어나지 않았다.
그리고 필요할때 (Reset을 시켜야할때) 1로 채워주면 될거같다.!!


그리고 RCC_APB2ENR 
(RM0008) 해당비트를 1로 설정하면 해당기능의 클럭이 활성화 된단다.
Reset Value가 전부 0이므로,

해당기능을 사용하기 위해서는 
RCC_APB2ENR 의 해당비트를 1로 만들어줘서 클럭을 공급해줘야겠다.
'Atmega는 이런거 없어도 잘되는데..'



내가사용하는 M3 Board의 회로도중 LED부분이다.
PA 4~7, PE 0~3 에 연결되어있으므로 PORTA와 PORTE의 Clock을 Enable 시켜줘야 한다. 
"회로도가 다를수 있으므로 자신의 Board의 회로도를 확인한후 설정해야한다!!"

그리고 이회로는 CPU(M3)의 Port에서 Low레벨의 Output이 나가야지 LED가 ON되는 회로이다. 
"혹~시 LED켜지는 원리를 모르시는분은 인터넷에 검색하길.."




코드상으로는..

#define   RCC_APB2ENR    (*(volatile unsigned int*)0x40021018)
int main()
{
  RCC_APB2ENR = 0x44

  while(1);
  return 0;
}


이런코드가 나오게 되겠다.!!

혹은 조금더 '아..주 조금더' 고급스럽게

RCC_APB2ENR = 0x44; 부분을 아래와같이..

RCC_APB2ENR |= (1<<2) | (1<<6);  이런식이나..

#define   IOPEEN    0x40
#define   IOPAEN    0x04

RCC_APB2ENR |= IOPEEN | IOPAEN;   이런식으로 쓸수있겠다.. 

'더 고급스럽게 해보고싶지만 한계인가보다..'


SIGI는 초보프로그래머다. 아직 Datasheet도 잘 볼줄 모르고.. 코딩도 잘하지 못한다.. 설명은 더더욱.. 
블로그는 개인 노트 용도로 쓰고 있으므로, 잘못된점이나 수정해야할점있으면 고수님들 지적 부탁드립니다. Plz..


STM32 무작정 LED켜기 2 탄에서 이어 집니다. ㅎ 


Posted by 시긔양

댓글을 달아 주세요

  1. 우왕

    너무 감사해요

    ATMEGA128 하다가 넘어왔는데

    IO가 많이 달라서 햇깔렸는데

    관련 레지스터를 알기쉽게 잘 정리해 주셨군요 감사해용 ㅋ

    2012.02.10 00:59 [ ADDR : EDIT/ DEL : REPLY ]