저번 포스팅에서 CMSIS 기반 레지스터 정의를 이용하여 LED를 ON/OFF 하는 코드에 대해 알아보았습니다.
void Main(void)
{
GPIOB->CRH = 0x66<<0;
GPIOB->ODR = 0x1<<9;
}
하지만 이런 경우 회로적으로 PB[9:8] 이외에 핀에 다른 회로가 결선되어 있다면 충돌이 발생할 수 있습니다. 이런 문제를 해결하기 위해 이번 포스팅에서는 Bit 연산에 대해 알아보도록 하겠습니다.
아래 코드는 Bit 연산에 의해 LED를 ON/OFF 하는 코드입니다.
void Main(void)
{
/* 이 부분은 임의로 바꾸지 마시오 */
RCC->APB2ENR |= (1<<3);
/* 비트 연산을 이용하여 LED0을 ON, LED1을 OFF로 하는 코드를 설계하시오 */
// OUT, O/D
// LED On, Off
GPIOB->CRH |= ((0x6 << 0) | (0x6 << 4));
GPIOB->ODR &= ~(1 << 8);
GPIOB->ODR |= (1 << 9);
}
**GPIOB->CRH |= ((0x6 << 0) | (0x6 << 4))**에서 **PB8, PB9 핀의 CRH 설정을 0110(Output, Open Drain)**으로 설정합니다. **GPIOB->ODR &= ~(1 << 8)**에서 PB8은 Bit clear 연산으로 0으로 만들고 **GPIOB->ODR |= (1 << 9)**에서 Bit Set 연산으로 PB9를 1로 만들게 됩니다. 따라서 LED0은 켜지고 LED1은 꺼지도록 설계할 수 있습니다.
다음은 Macro Logic에 대해 알아보겠습니다.
// bit operation
#define Macro_Set_Bit(dest, pos) ((dest) |= ((unsigned)0x1<<(pos)))
#define Macro_Clear_Bit(dest, pos) ((dest) &= ~((unsigned)0x1<<(pos)))
#define Macro_Invert_Bit(dest, pos) ((dest) ^= ((unsigned)0x1<<(pos)))
#define Macro_Clear_Area(dest, bits, pos) ((dest) &= ~(((unsigned)bits)<<(pos)))
#define Macro_Set_Area(dest, bits, pos) ((dest) |= (((unsigned)bits)<<(pos)))
#define Macro_Invert_Area(dest, bits, pos) ((dest) ^= (((unsigned)bits)<<(pos)))
#define Macro_Write_Block(dest, bits, data, pos) ((dest) = (((unsigned)dest) & ~(((unsigned)bits)<<(pos))) | (((unsigned)data)<<(pos)))
#define Macro_Extract_Area(dest, bits, pos) ((((unsigned)dest)>>(pos)) & (bits))
#define Macro_Check_Bit_Set(dest, pos) ((((unsigned)dest)>>(pos)) & 0x1)
#define Macro_Check_Bit_Clear(dest, pos) (!((((unsigned)dest)>>(pos)) & 0x1))
// Bit Banding
#define Peri_Bit(reg, bit) (*(volatile unsigned long *)(PERIPH_BB_BASE+((unsigned int)&(reg) - PERIPH_BASE)*32+(unsigned int)(bit)*4))
#define Mem_Bit(mem, bit) (*(volatile unsigned long *)(SRAM_BB_BASE+((unsigned int)(mem) - SRAM_BASE)*32+(unsigned int)(bit)*4))
#define Peri_Set_Bit(reg, bit) (*(volatile unsigned long *)(PERIPH_BB_BASE+((unsigned int)&(reg) - PERIPH_BASE)*32+(unsigned int)(bit)*4) = 1)
#define Peri_Clear_Bit(reg, bit) (*(volatile unsigned long *)(PERIPH_BB_BASE+((unsigned int)&(reg) - PERIPH_BASE)*32+(unsigned int)(bit)*4) = 0)
#define Mem_Set_Bit(mem, bit) (*(volatile unsigned long *)(SRAM_BB_BASE+((unsigned int)(mem) - SRAM_BASE)*32+(unsigned int)(bit)*4) = 1)
#define Mem_Clear_Bit(mem, bit) (*(volatile unsigned long *)(SRAM_BB_BASE+((unsigned int)(mem) - SRAM_BASE)*32+(unsigned int)(bit)*4) = 0)
#define Peri_Check_Bit_Set(reg, bit) (*(volatile unsigned long *)(PERIPH_BB_BASE+((unsigned int)&(reg) - PERIPH_BASE)*32+(unsigned int)(bit)*4))
#define Peri_Check_Bit_Clear(reg, bit) (!*(volatile unsigned long *)(PERIPH_BB_BASE+((unsigned int)&(reg) - PERIPH_BASE)*32+(unsigned int)(bit)*4))
#define Mem_Check_Bit_Set(mem, bit) (*(volatile unsigned long *)(SRAM_BB_BASE+((unsigned int)(mem) - SRAM_BASE)*32+(unsigned int)(bit)*4))
#define Mem_Check_Bit_Clear(mem, bit) (!*(volatile unsigned long *)(SRAM_BB_BASE+((unsigned int)(mem) - SRAM_BASE)*32+(unsigned int)(bit)*4))
Macro.h 파일에 작성한 Macro 로직을 사용하면 Bit 연산을 수월하게 구현할 수 있습니다. 각각 정의된 함수는 아래 실습을 진행하면서 알아보겠습니다.
먼저 앞에서 Bit 연산으로 LED를 ON/OFF 하는 로직을 Macro를 활용해서 ON/OFF 해보려고 합니다.
void Main(void)
{
/* 이 부분은 수정하지 말 것 */
Macro_Set_Bit(RCC->APB2ENR, 3);
/* Macro를 이용하여 LED0을 ON, LED1을 OFF로 하는 코드를 설계하시오 */
Macro_Write_Block(GPIOB->CRH, 0xFF, 0x66, 0);
Macro_Write_Block(GPIOB->ODR, 0x3, 0x1, 8);
}
코드를 보면 **Macro_Write_Block(GPIOB->CRH, 0xFF, 0x66, 0)**에서 **PB8, PB9 총 8 bit를 Output, Open Drain(0110 0110)**으로 한 것을 확인할 수 있습니다. **Macro_Write_Block(GPIOB->ODR, 0x3, 0x1, 8)**을 통해 8번부터 2bit를 01로 만들게 됩니다.
Logic Analyzer로 Pulse를 출력해보면 LED0은 계속 OFF 상태, LED1은 계속 ON 상태인 것을 확인할 수 있습니다.
이번에는 Macro를 활용해서 외부 LED를 Toggling 하는 회로를 구현해보려고 합니다.