[현대오토에버SW스쿨4기] 임베디드 C프로그래밍 기초(2)

chaehun·2025년 2월 25일

'Embedded C Programming 기초' Digital Output 이해와 활용


칩에서 우리가 하드웨어 적으로 bitwise 연산 해줄게 -> 이게 무슨 뜻인지 읽어보자


여기서 OTYPER에 0x01 써서 open drain 줬더니 그냥 코드가 죽어버렸다. ㅜㅜ

Struct 예제


//Structure & Array
typedef struct
{
  volatile unsigned int MODER;        /*!< GPIO port mode register,                     Address offset: 0x00 */
  volatile unsigned int OTYPER;       /*!< GPIO port output type register,              Address offset: 0x04 */
  volatile unsigned int OSPEEDR;      /*!< GPIO port output speed register,             Address offset: 0x08 */
  volatile unsigned int PUPDR;        /*!< GPIO port pull-up/pull-down register,        Address offset: 0x0C */
  volatile unsigned int IDR;          /*!< GPIO port input data register,               Address offset: 0x10 */
  volatile unsigned int ODR;          /*!< GPIO port output data register,              Address offset: 0x14 */
  volatile unsigned int BSRR;         /*!< GPIO port bit set/reset registerBSRR,        Address offset: 0x18 */
  volatile unsigned int LCKR;         /*!< GPIO port configuration lock register,       Address offset: 0x1C */
  volatile unsigned int AFR[2];       /*!< GPIO alternate function register,            Address offset: 0x20-0x24 */
  volatile unsigned int BRR;          /*!< GPIO bit reset register,                     Address offset: 0x28 */
}GPIO_TypeDef;

#define PERIPH_BASE       (0x40000000UL) /*!< Peripheral base address in the alias region */
#define AHBPERIPH_BASE    (PERIPH_BASE + 0x00020000UL)
#define RCC_BASE          (AHBPERIPH_BASE + 0x00001000UL)
#define RCC_IOPENR		*((volatile unsigned int*)(RCC_BASE + 0x0000002CUL))
#define RCC_GPIOA_EN			((unsigned int)0x00000001U)

//#define GPIO_PA5PIN_BASE    (unsigned int)0x50000000UL
#define GPIOA_BASE		     ((unsigned int)0x50000000UL)
#define GPIOA			     (GPIO_TypeDef *) GPIOA_BASE
#define GPIO_PIN_5_POS				5

#define GPIO_2BIT_POS_MASK    ((unsigned int)0x00000003U)
#define GPIO_1BIT_POS_MASK    ((unsigned int)0x00000001U)

#define GPIO_MODE_OUTPUT      			((unsigned int)0x00000001U)   /*!< GPIO OutPut Mode                 */
#define GPIO_OUTPUT_TYPE_0      		((unsigned int)0x00000000U)		/* PushPull */
#define GPIO_NOPUPD				((unsigned int)0x00000000U)		/* No Pull up / down */
#define GPIO_SPEED_FREQ_VERY_HIGH   	((unsigned int)0x00000003U)  /*!< range  10 MHz to 35 MHz, please refer to the product datasheet */

#define LED2_ON					((unsigned int)0x00000001U)
#define LED2_OFF					((unsigned int)0x00000000U)	

void delay(unsigned int delay_cnt)
{
		volatile int counter = 0;

		while(counter < delay_cnt) //delay loop
		{
			counter++;
		}
}

int main()
{
	unsigned int position = GPIO_PIN_5_POS; //Pin Position: PA5
	unsigned int temp = 0x0U;
	unsigned int mode = 0x0U;
	unsigned int reg = 0x0U;
	GPIO_TypeDef *GPIOA_reg = GPIOA;
	
	//RCC-GPIOA
	RCC_IOPENR |= RCC_GPIOA_EN;
	
	//PA5 Mode
	reg = GPIOA_reg->MODER;	//GPIO_PA5PIN_MODE
	temp = ~(GPIO_2BIT_POS_MASK << (position*2U)); //0xFFFFF3FF
	reg &= temp;
	mode = GPIO_MODE_OUTPUT << (position*2U) ;	// GPO Mode - 2bit 0x00000400
	reg |= mode;
	GPIOA_reg->MODER = reg;

	//OTYPER
	reg = GPIOA_reg->OTYPER;	//GPIO_PA5PIN_OTYPE
	temp = ~(GPIO_1BIT_POS_MASK << position);	//~0x20 ==> 0xFFFFFFDF
	reg &= temp;
	mode = GPIO_OUTPUT_TYPE_0 << position ;	//PP Output type - 1bit
	reg |= mode;
	GPIOA_reg->OTYPER = reg;

	//OSPEEDR
	reg = GPIOA_reg->OSPEEDR;	//GPIO_PA5PIN_OSPEEDR
	temp = ~(GPIO_2BIT_POS_MASK << (position*2U)); //0xFFFFF3FF
	reg &= temp;
	mode = GPIO_SPEED_FREQ_VERY_HIGH << (position*2U) ;	//Very High Mode - 2bit 0x00000C00
	reg |= mode;
	GPIOA_reg->OSPEEDR = reg;
	
	//OPUPDR
	reg = GPIOA_reg->PUPDR;
	temp = ~(0x03U << (position*2U)); //0xFFFFF3FF
	reg &= temp;
	mode = 0x0U << (position*2U) ;	//No Pull Up - Pull Down - 2bit 0x24000000
	reg |= mode;
	GPIOA_reg->PUPDR = reg;

	//ODR
	reg = GPIOA_reg->ODR;	//GPIO_PA5PIN_ODR
	temp = ~(GPIO_1BIT_POS_MASK << position);	//~0x20 ==> 0xFFFFFFDF
	reg &= temp;

	mode = LED2_ON << position ;	
	GPIOA_reg->ODR = reg | mode;

	while(1)
	{
		delay(0x20000);
		mode = ~mode&(GPIO_1BIT_POS_MASK << position);
		GPIOA_reg->ODR = reg | mode;

	}

}

이 코드를 이제 함수화 시켜보자

GPIO 함수 & 2 LED Blinking


//Structure & Array
typedef struct
{
  volatile unsigned int MODER;        /*!< GPIO port mode register,                     Address offset: 0x00 */
  volatile unsigned int OTYPER;       /*!< GPIO port output type register,              Address offset: 0x04 */
  volatile unsigned int OSPEEDR;      /*!< GPIO port output speed register,             Address offset: 0x08 */
  volatile unsigned int PUPDR;        /*!< GPIO port pull-up/pull-down register,        Address offset: 0x0C */
  volatile unsigned int IDR;          /*!< GPIO port input data register,               Address offset: 0x10 */
  volatile unsigned int ODR;          /*!< GPIO port output data register,              Address offset: 0x14 */
  volatile unsigned int BSRR;         /*!< GPIO port bit set/reset registerBSRR,        Address offset: 0x18 */
  volatile unsigned int LCKR;         /*!< GPIO port configuration lock register,       Address offset: 0x1C */
  volatile unsigned int AFR[2];       /*!< GPIO alternate function register,            Address offset: 0x20-0x24 */
  volatile unsigned int BRR;          /*!< GPIO bit reset register,                     Address offset: 0x28 */
}GPIO_TypeDef;

typedef enum
{
	GPIO_PIN_RESET = 0U,
	GPIO_PIN_SET
} GPIO_PinState;

#define PERIPH_BASE       (0x40000000UL) /*!< Peripheral base address in the alias region */
#define AHBPERIPH_BASE    (PERIPH_BASE + 0x00020000UL)
#define RCC_BASE          (AHBPERIPH_BASE + 0x00001000UL)
#define RCC_IOPENR		*((volatile unsigned int*)(RCC_BASE + 0x0000002CUL))
#define RCC_GPIOA_EN			((unsigned int)0x00000001U)

//#define GPIO_PA5PIN_BASE    (unsigned int)0x50000000UL
#define GPIOA_BASE		     ((unsigned int)0x50000000UL)
#define GPIOA			     (GPIO_TypeDef *) GPIOA_BASE
#define GPIO_PIN_5_POS				5
#define GPIO_PIN_8_POS        8

#define GPIO_2BIT_POS_MASK    ((unsigned int)0x00000003U)
#define GPIO_1BIT_POS_MASK    ((unsigned int)0x00000001U)

#define GPIO_MODE_OUTPUT      			((unsigned int)0x00000001U)   /*!< GPIO OutPut Mode                 */
#define GPIO_OUTPUT_TYPE_0      		((unsigned int)0x00000000U)		/* PushPull */
#define GPIO_NOPUPD				((unsigned int)0x00000000U)		/* No Pull up / down */
#define GPIO_SPEED_FREQ_VERY_HIGH   	((unsigned int)0x00000003U)  /*!< range  10 MHz to 35 MHz, please refer to the product datasheet */

#define LED2_ON					((unsigned int)0x00000001U)
#define LED2_OFF					((unsigned int)0x00000000U)


void delay(unsigned int delay_cnt)
{
		volatile int counter = 0;

		while(counter < delay_cnt) //delay loop
		{
			counter++;
		}
}

void GPIO_Init(GPIO_TypeDef* pGPIO_Type, unsigned short pin, GPIO_TypeDef* initVal){
	unsigned int position = pin;
	
	//PA5 Mode
	pGPIO_Type->MODER &= ~(GPIO_2BIT_POS_MASK << (position*2U));
	pGPIO_Type->MODER |= initVal->MODER << (position*2U) ;

	//OTYPER
	pGPIO_Type->OTYPER &= ~(GPIO_1BIT_POS_MASK << position);
	pGPIO_Type->OTYPER |= initVal->OTYPER << position ;

	//OSPEEDR
	pGPIO_Type->OSPEEDR &= ~(GPIO_2BIT_POS_MASK << (position*2U));
	pGPIO_Type->OSPEEDR |= initVal->OSPEEDR << (position*2U) ;
	
	//OPUPDR
	pGPIO_Type->PUPDR &= ~(0x03U << (position*2U)); 
	pGPIO_Type->PUPDR |= initVal->PUPDR << (position*2U) ;
}

void GPIO_Write_Pin(GPIO_TypeDef* pGPIO_Type, unsigned short pin, GPIO_PinState state)
{
	unsigned int mode = 0x0U;
	unsigned int reg = 0x0U;
	
	reg = pGPIO_Type->ODR;
	reg &= ~(GPIO_1BIT_POS_MASK << pin);
	mode = state << pin;
	pGPIO_Type->ODR = reg |= mode;
}

int main()
{
	GPIO_TypeDef initVal;
	GPIO_PinState pin_state = GPIO_PIN_RESET;
	
	//RCC-GPIOA
	RCC_IOPENR |= RCC_GPIOA_EN;
	
	initVal.MODER = GPIO_MODE_OUTPUT;
	initVal.OTYPER = GPIO_OUTPUT_TYPE_0;
	initVal.OSPEEDR = GPIO_SPEED_FREQ_VERY_HIGH;
	initVal.PUPDR = GPIO_NOPUPD;
	
	GPIO_Init(GPIOA, GPIO_PIN_5_POS, &initVal);
	GPIO_Write_Pin(GPIOA, GPIO_PIN_5_POS, pin_state);
	
	GPIO_Init(GPIOA, GPIO_PIN_8_POS, &initVal);
	GPIO_Write_Pin(GPIOA, GPIO_PIN_8_POS, (GPIO_PinState)!pin_state);
	
	
	while(1)
	{
		delay(0x20000);
		pin_state = (GPIO_PinState)(!pin_state);
		GPIO_Write_Pin(GPIOA, GPIO_PIN_5_POS, pin_state);
		GPIO_Write_Pin(GPIOA, GPIO_PIN_8_POS, (GPIO_PinState)!pin_state);
	}

}

마지막으로 레지스터 정보를 배열에 저장하고 BSS/BSSR 레지스터를 사용해보자

배열 & BSRR & BRR 이용한 소스


//Structure & Array
typedef struct
{
  volatile unsigned int MODER;        /*!< GPIO port mode register,                     Address offset: 0x00 */
  volatile unsigned int OTYPER;       /*!< GPIO port output type register,              Address offset: 0x04 */
  volatile unsigned int OSPEEDR;      /*!< GPIO port output speed register,             Address offset: 0x08 */
  volatile unsigned int PUPDR;        /*!< GPIO port pull-up/pull-down register,        Address offset: 0x0C */
  volatile unsigned int IDR;          /*!< GPIO port input data register,               Address offset: 0x10 */
  volatile unsigned int ODR;          /*!< GPIO port output data register,              Address offset: 0x14 */
  volatile unsigned int BSRR;         /*!< GPIO port bit set/reset registerBSRR,        Address offset: 0x18 */
  volatile unsigned int LCKR;         /*!< GPIO port configuration lock register,       Address offset: 0x1C */
  volatile unsigned int AFR[2];       /*!< GPIO alternate function register,            Address offset: 0x20-0x24 */
  volatile unsigned int BRR;          /*!< GPIO bit reset register,                     Address offset: 0x28 */
}GPIO_TypeDef;

typedef enum
{
	GPIO_PIN_RESET = 0U,
	GPIO_PIN_SET
} GPIO_PinState;

typedef enum
{
	LED2 = 0,
	USER_LED1,
}Led_TypeDef;

#define PERIPH_BASE       (0x40000000UL) /*!< Peripheral base address in the alias region */
#define AHBPERIPH_BASE    (PERIPH_BASE + 0x00020000UL)
#define RCC_BASE          (AHBPERIPH_BASE + 0x00001000UL)
#define RCC_IOPENR		*((volatile unsigned int*)(RCC_BASE + 0x0000002CUL))
#define RCC_GPIOA_EN			((unsigned int)0x00000001U)

//#define GPIO_PA5PIN_BASE    (unsigned int)0x50000000UL
#define GPIOA_BASE		     ((unsigned int)0x50000000UL)
#define GPIOA			     (GPIO_TypeDef *) GPIOA_BASE
#define GPIO_PIN_5_POS				5
#define GPIO_PIN_8_POS        8

#define GPIO_NUMBER           (16U)
#define GPIO_2BIT_POS_MASK    ((unsigned int)0x00000003U)
#define GPIO_1BIT_POS_MASK    ((unsigned int)0x00000001U)

#define GPIO_MODE_OUTPUT      			((unsigned int)0x00000001U)   /*!< GPIO OutPut Mode                 */
#define GPIO_OUTPUT_TYPE_0      		((unsigned int)0x00000000U)		/* PushPull */
#define GPIO_NOPUPD				((unsigned int)0x00000000U)		/* No Pull up / down */
#define GPIO_SPEED_FREQ_VERY_HIGH   	((unsigned int)0x00000003U)  /*!< range  10 MHz to 35 MHz, please refer to the product datasheet */

#define LED2_ON					((unsigned int)0x00000001U)
#define LED2_OFF					((unsigned int)0x00000000U)
	
#define LEDn 2

GPIO_TypeDef* LED_PORT[LEDn] = {GPIOA, GPIOA};
unsigned short LED_PIN[LEDn] = {GPIO_PIN_5_POS, GPIO_PIN_8_POS};

void delay(unsigned int delay_cnt);
void GPIO_Init(GPIO_TypeDef* pGPIO_Type, unsigned short pin, GPIO_TypeDef* initVal);
void GPIO_Write_Pin(GPIO_TypeDef* pGPIO_Type, unsigned short pin, GPIO_PinState state);
void GPIO_Toggle_Pin(GPIO_TypeDef* pGPIO_Type, unsigned short GPIO_Pin);

int main()
{
	GPIO_TypeDef initVal;
	GPIO_PinState pin_state = GPIO_PIN_RESET;
	
	//RCC-GPIOA
	RCC_IOPENR |= RCC_GPIOA_EN;
	
	initVal.MODER = GPIO_MODE_OUTPUT;
	initVal.OTYPER = GPIO_OUTPUT_TYPE_0;
	initVal.OSPEEDR = GPIO_SPEED_FREQ_VERY_HIGH;
	initVal.PUPDR = GPIO_NOPUPD;
	
	GPIO_Init(LED_PORT[LED2], LED_PIN[LED2], &initVal);
	GPIO_Write_Pin(LED_PORT[LED2], LED_PIN[LED2], pin_state);
	
	GPIO_Init(LED_PORT[USER_LED1], LED_PIN[USER_LED1], &initVal);
	GPIO_Write_Pin(LED_PORT[USER_LED1], LED_PIN[USER_LED1], (GPIO_PinState)!pin_state);
	
	
	while(1)
	{
		delay(0x20000);
		pin_state = (GPIO_PinState)(!pin_state);
		GPIO_Toggle_Pin(LED_PORT[LED2], LED_PIN[LED2]);
		GPIO_Toggle_Pin(LED_PORT[USER_LED1], LED_PIN[USER_LED1]);
	}

}


void delay(unsigned int delay_cnt)
{
		volatile int counter = 0;

		while(counter < delay_cnt) //delay loop
		{
			counter++;
		}
}

void GPIO_Init(GPIO_TypeDef* pGPIO_Type, unsigned short pin, GPIO_TypeDef* initVal){
	unsigned int position = pin;
	
	//PA5 Mode
	pGPIO_Type->MODER &= ~(GPIO_2BIT_POS_MASK << (position*2U));
	pGPIO_Type->MODER |= initVal->MODER << (position*2U) ;

	//OTYPER
	pGPIO_Type->OTYPER &= ~(GPIO_1BIT_POS_MASK << position);
	pGPIO_Type->OTYPER |= initVal->OTYPER << position ;

	//OSPEEDR
	pGPIO_Type->OSPEEDR &= ~(GPIO_2BIT_POS_MASK << (position*2U));
	pGPIO_Type->OSPEEDR |= initVal->OSPEEDR << (position*2U) ;
	
	//OPUPDR
	pGPIO_Type->PUPDR &= ~(0x03U << (position*2U)); 
	pGPIO_Type->PUPDR |= initVal->PUPDR << (position*2U) ;
}

void GPIO_Write_Pin(GPIO_TypeDef* pGPIO_Type, unsigned short pin, GPIO_PinState state)
{
	unsigned int mode = 0x0U;
	unsigned int reg = 0x0U;
	
	reg = pGPIO_Type->ODR;
	reg &= ~(GPIO_1BIT_POS_MASK << pin);
	mode = state << pin;
	pGPIO_Type->ODR = reg |= mode;
}

void GPIO_Toggle_Pin(GPIO_TypeDef* pGPIO_Type, unsigned short GPIO_Pin)
{
	unsigned int position = 0;
	position = GPIO_1BIT_POS_MASK << (GPIO_Pin);
	unsigned int odr;
	/* get current Output Data Register value */
	odr = pGPIO_Type->ODR;

	/* Set selected pins that were at low level, and reset ones that were high */
	pGPIO_Type->BSRR = ((odr & position) << GPIO_NUMBER) | (~odr & position);
}

끄읕!

0개의 댓글