LED0은 ON, LED1은 OFF 시키기 위한 코드를 설계해보겠습니다.

image.png

먼저 각 포트의 PIN 속성을 결정합니다. 이번 실습에서는 LED: PB[9:8]을 사용하므로 GPIOB_CRH 레지스터의 [7:0] 비트에 의해 타입이 설정됩니다. LED: PB[9:8]은 GPIOB_CRH 레지스터의 최하위 2bit에 의해 정해지게 됩니다. STM32의 GPIO 설정을 보면 아래와 같습니다.

image.png

실습에서는 Open drain 출력에 최대 제한 속도는 2MHz로 하였기 때문에 LED: PB[9:8] -> 0110으로 설정하고 실습을 진행했습니다.

image.png

STM32에서는 레지스터 주소를 직접 지정해 GPIO를 제어할 수 있다.

아래 코드는 GPIOB 포트의 8~15번 핀의 모드와 속도를 설정하는 제어 레지스터를 의미하며, 출력 데이터 레지스터로, 각 핀의 High(1)/Low(0) 상태를 결정한다.

#define GPIOB_CRH (*(int *)0x40010C04)
#define GPIOB_ODR (*(int *)0x40010C0C)
#include <device_driver.h>

// 여기에 사용자 임의의 define을 작성하시오

// define 앞에 () 빼면 우선 순위 문제가 생길 수 있음.
#define GPIOB_CRH (*(int *)0x40010C04)
#define GPIOB_ODR (*(int *)0x40010C0C)

void Main(void)
{
	  // 이 부분은 임의로 바꾸지 마시오
	  RCC_APB2ENR |= (1<<3);

	  // GPB[9:8]을 출력 모드로 설정하시오

	  // (*(int *)0x40010C04) = 0x00000066;
	  GPIOB_CRH = 0x00000066;

	  // GPB[9:8]에 LED0은 OFF, LED1은 ON 시키도록 설정하시오

	  // GPIOB_ODR (*(int *)0x40010C0C) = 0x00000200;
	  GPIOB_ODR = 0x00000200;
	  // 0x200으로 써도 됨
}

/*
	if define가 없다면?
	
	= 0x00000066;

	= 0x00000200;

	이런 코드를 실행하게 됨
*/

image.png

#include "device_driver.h"

void Main(void)
{
	volatile int i;

	Uart_Init(115200);
	Uart_Printf("CMSIS Based Register Define\\n");

	// 이 부분은 수정하지 말 것
	RCC->APB2ENR |= (1<<3);

	RCC->APB2ENR |= (1<<2);

	// LED Pin을 출력으로 설정

    // 0~7은 LOW 사용 0110으로 켜야하므로 6
	GPIOA->CRL = 0x600;

	for(;;)
	{
		// LED 모두 ON

		GPIOA->ODR = 0x0;

		for(i=0; i<0x40000; i++);

		// LED 모두 OFF

		GPIOA->ODR = 0x4;

		for(i=0; i<0x40000; i++);
	}
}

image.png

Logic Analyzer 보드의 0~7 포트에 와이어를 연결하여 해당 Channel에 파형을 측정할 수 있습니다. STM32 보드의 Reset Switch를 누른 상태로 Start를 누르면 아래와 같이 파형을 측정할 수 있습니다.

image.png

이때 Trigger 설정에서 Channel을 LED0으로 설정하고 Falling Edge부터 시작해 3초동안 Pulse를 측정하면 위와 같이 파형이 나오게 됩니다.

image.png

Channel을 LED4로 바꾸고 Logic Analyzer 보드의 4번에 와이어를 연결하여 다른 Channel에서 파형을 측정할 수 있습니다. 파형을 보면 LED가 반복적으로 ON/OFF 되는 것을 확인할 수 있습니다.

다음은 CMSIS 방식으로 LED를 켜는 프로그램을 알아보도록 하겠습니다. GPIOB는 GPIO_TypeDef 구조체 포인터에 정의되어 있고 CRH, CRL, IDR, ODR은 해당 구조체 안에 멤버입니다.

#include "device_driver.h"

/* LED0 -> ON, LED1 -> OFF */

void Main(void)
{
	RCC->APB2ENR |= (1<<3);

	GPIOB->CRH = 0x66<<0;
	GPIOB->ODR = 0x1<<9;
}

코드에서 GPIOB->CRH = 0x66<<0 부분을 보면 GPIOB->CRH의 0번째 bit부터 01100110으로 만드는 것을 알 수 있습니다(Output, O/D). 또한 GPIOB->ODR 부분에서 GPIOB->ODR의 8번째 bit을 1로 만드는 것을 확인할 수 있습니다(LED0->on, LED1->off).