STM32F4 DISCOVERY BOARD 를 이용한 I/O 제어 (3)
앞에서 GPIO의 클럭 활서화와 포트설정에 대해 알아보았다.
이제 남은것은 포트의 출력값을 변경시켜 주는것과 Alternate 라는 기능이다.
이제 GPIO의 함수들에대해 알아보자
stm32f4xx_gpio.h 를 보면 아래와 같은 함수들이 선언되어 있다.
stm32f4xx_gpio.h 의 함수선언 부분
/* Function used to set the GPIO configuration to the default reset state ****/
void GPIO_DeInit(GPIO_TypeDef* GPIOx);
/* Initialization and Configuration functions *********************************/
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
/* GPIO Read and Write functions **********************************************/
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
void GPIO_ToggleBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
/* GPIO Alternate functions configuration function ****************************/
void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF);
초기화 함수는 제목들을 보면 바로 이해할 수 있을 것이다. 아니면 함수정의로 가보면 거기에도 설명이 자세히 나와있다.
아래의 함수부터 보도록 하자.
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
stm32f4xx_gpio.c 의 함수 정의부분
stm32f4xx.h 의 GPIO_TypeDef 구조체 선언부분
stm32f4xx_gpio.c 의 함수 정의부분
/**
* @brief Reads the specified input port pin.
* @param GPIOx: where x can be (A..I) to select the GPIO peripheral.
* @param GPIO_Pin: specifies the port bit to read.
* This parameter can be GPIO_Pin_x where x can be (0..15).
* @retval The input port pin value.
*/
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
uint8_t bitstatus = 0x00;
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GET_GPIO_PIN(GPIO_Pin));
if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)Bit_RESET)
{
bitstatus = (uint8_t)Bit_SET;
}
else
{
bitstatus = (uint8_t)Bit_RESET;
}
return bitstatus;
}
/**
* @brief Reads the specified GPIO input data port.
* @param GPIOx: where x can be (A..I) to select the GPIO peripheral.
* @retval GPIO input data port value.
*/
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
return ((uint16_t)GPIOx->IDR);
}
/**
* @brief Reads the specified output data port bit.
* @param GPIOx: where x can be (A..I) to select the GPIO peripheral.
* @param GPIO_Pin: specifies the port bit to read.
* This parameter can be GPIO_Pin_x where x can be (0..15).
* @retval The output port pin value.
*/
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
uint8_t bitstatus = 0x00;
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GET_GPIO_PIN(GPIO_Pin));
if ((GPIOx->ODR & GPIO_Pin) != (uint32_t)Bit_RESET)
{
bitstatus = (uint8_t)Bit_SET;
}
else
{
bitstatus = (uint8_t)Bit_RESET;
}
return bitstatus;
}
/**
* @brief Reads the specified GPIO output data port.
* @param GPIOx: where x can be (A..I) to select the GPIO peripheral.
* @retval GPIO output data port value.
*/
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
return ((uint16_t)GPIOx->ODR);
}
/**
* @brief Sets the selected data port bits.
* @note This functions uses GPIOx_BSRR register to allow atomic read/modify
* accesses. In this way, there is no risk of an IRQ occurring between
* the read and the modify access.
* @param GPIOx: where x can be (A..I) to select the GPIO peripheral.
* @param GPIO_Pin: specifies the port bits to be written.
* This parameter can be any combination of GPIO_Pin_x where x can be (0..15).
* @retval None
*/
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));
GPIOx->BSRRL = GPIO_Pin;
}
stm32f4xx.h 의 GPIO_TypeDef 구조체 선언부분
typedef struct
{
__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
__IO uint16_t BSRRL; /*!< GPIO port bit set/reset low register, Address offset: 0x18 */
__IO uint16_t BSRRH; /*!< GPIO port bit set/reset high register, Address offset: 0x1A */
__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
__IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
} GPIO_TypeDef;
위의 데이터를 보변
GPIO_ReadInputData(Bit) 에서는 IDR 즉 input data register 의 값을 읽어오는 함수이고
GPIO_ReadOutputData(Bit) 에서는 ODR 즉 outpu data register 의 값을 읽어오는 함수이다.
뒤에 Bit 가 붙은 함수는 비트 연산을 통해 하나의 비트만 출력하는 함수이고....
안의 코드를 보면 알수 있지만 간결하고 효율적으로 구성되어 있는것을 확인할 수 있다.
이정도는 그냥 레지스터를 써도 간편하게 될듯 하기도 싶은데?..
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
이부분이 포트의 핀출력을 설정하는 함수이다.
아래는 stm32f4xx_gpio.c 의 함수 정의부분
stm32f4xx_gpio.c
/**
* @brief Sets the selected data port bits.
* @note This functions uses GPIOx_BSRR register to allow atomic read/modify
* accesses. In this way, there is no risk of an IRQ occurring between
* the read and the modify access.
* @param GPIOx: where x can be (A..I) to select the GPIO peripheral.
* @param GPIO_Pin: specifies the port bits to be written.
* This parameter can be any combination of GPIO_Pin_x where x can be (0..15).
* @retval None
*/
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));
GPIOx->BSRRL = GPIO_Pin;
}
/**
* @brief Clears the selected data port bits.
* @note This functions uses GPIOx_BSRR register to allow atomic read/modify
* accesses. In this way, there is no risk of an IRQ occurring between
* the read and the modify access.
* @param GPIOx: where x can be (A..I) to select the GPIO peripheral.
* @param GPIO_Pin: specifies the port bits to be written.
* This parameter can be any combination of GPIO_Pin_x where x can be (0..15).
* @retval None
*/
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));
GPIOx->BSRRH = GPIO_Pin;
}
/**
* @brief Sets or clears the selected data port bit.
* @param GPIOx: where x can be (A..I) to select the GPIO peripheral.
* @param GPIO_Pin: specifies the port bit to be written.
* This parameter can be one of GPIO_Pin_x where x can be (0..15).
* @param BitVal: specifies the value to be written to the selected bit.
* This parameter can be one of the BitAction enum values:
* @arg Bit_RESET: to clear the port pin
* @arg Bit_SET: to set the port pin
* @retval None
*/
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GET_GPIO_PIN(GPIO_Pin));
assert_param(IS_GPIO_BIT_ACTION(BitVal));
if (BitVal != Bit_RESET)
{
GPIOx->BSRRL = GPIO_Pin;
}
else
{
GPIOx->BSRRH = GPIO_Pin ;
}
}
Reference manual중.
위의 함수와 레퍼런스 메뉴얼을 보면 데이터를 쓰고 지우기 위해 BSRR 레지스터를 이용하는 것을 알 수 있다.
실제 핀의 입출력을 담당하는 레지스터는 ODR 임에도 불구하고 함수에서는 BSRR 레지스터를 이용하는 것을 보고 이게 bit banding 이 아닐까 생각했었는데 잘못된 생각이였다.
이건 비트를 밴딩시켰다기보다 그냥 JK플립플롭의 J K 를 연상시킨다.
실제 레지스터를 셋 리셋 시키는 스위치랄까?
기존의 방법에 의해 비트를 설정하려면 레지스터에서 값을 읽어 원하고자 하는 비트에 데이터를 비트연산 시켜 그 결과값을 다시 레지스터에 써야 하는 단계를 거친다.
(물론 다른 핀 출력을 고려하지 않아도 될 경우 그냥 데이터를 레지스터에 입력하곤 했지만...)
그러데 여기서는 새로운 레지스터가 생겼다.
BSRRL에 데이터를 입력하면 1이 입력된 핀레지스터만 SET(1) 된다.
BSRRH에 데이터를 입력하면 1이 입력된 비트만 ODR 에서 RESET(0) 된다.
그러니 이건 마치 JK 플립플롭 같은거지....
그리고 마지막으로
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
void GPIO_ToggleBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
GPIOx->ODR = PortVal;
}
/**
* @brief Toggles the specified GPIO pins..
* @param GPIOx: where x can be (A..I) to select the GPIO peripheral.
* @param GPIO_Pin: Specifies the pins to be toggled.
* @retval None
*/
void GPIO_ToggleBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
GPIOx->ODR ^= GPIO_Pin;
}
위의 함수의 경우 ODR 레지스터를 이용해 직접 데이터비트를 쓰고 비트연산을 통해 토글시키는 기능을 가지고 있다.
이걸로 IO 에서는 Alternate function 과,locking mechanism 만 남은듯 하다.
alternate는 공부를 했는데 locking mechanism은 좀더 공부를 하던가 아니면 후로 미뤄야 겠는걸?
이걸로 I/O도 대충 마쳤으니 이제 슬슬 코딩작업으로 들어가서 다른 기능들을 사용하며
사용한 기능들에 대한 설명으로 차후 ARM 게시판을 채워나가야 겠다.
일단 다음과제는 Alternate가 되겠네.... *^^*
그 다음은 아마도 타이머가 될 듯 하고....ㅋㅋ