Debouncing of buttons using DMA on STM32

버튼 입력을 처리하는데 채터링은 항상 골치 아픈 문제다. 하드웨어적으로 로우패스 필터 역할을 하는 회로가 버튼 입력에 붙으면 좋겠지만, 그렇지 못한 상황에서는 소프트웨어적으로 해결해야 한다.

일반적인 경우, 일정한 주기의 (1ms) 인터럽트에서 키 입력에 해당하는 GPIO 비트의 변화를 감시하고, 몇 번의 인터럽트동안 비트의 변화가 없는 경우 키의 상태를 반영하면 채터링을 제거할 수 있다.

단순히 EXTI 로 처리하게 된다면 순간적인 노이즈나 버튼을 살짝 건드리는 경우에도 동작하게 되어 문제가 된다. 이를 해결하려면 타이머까지 동원하여 복잡하게 될 것이다.

이리저리 고민하다 최대한 프로그래밍을 하지않고 해결할 방법을 찾아보았다. 앞서 말했듯이 일정한 기간동안 비트의 변화가 없다는 것을 DMA로 해결해보려고 하였다. 기본적인 아이디어는 다음과 같다.

  1. 타이머 하나를 1ms 마다 update 이벤트가 생기도록 설정한다.
  2. 1ms 마다 DMA로 GPIO 포트 (16 bits, half word) 를 읽는다.
  3. 이 동작을 5번 하게 되었을 때 (5ms) DMA 완료가 된다. (0, 1, 2, 3, 4ms)
  4. 5개 비트들 중 해당하는 비트를 논리 연산을 통해 일정하게 유지되는지 확인
  5. 만약 유지가 되었다면, 키 입력 변수에 3번의 결과를 저장
  6. DMA는 circular 모드로 세팅하여 5ms마다 1번 반복

1ms 타이머 인터럽트에서 처리해야 할 것을 5ms마다 DMA가 완료될 때로 미루고, 소프트웨어 처리를 최대한 줄일 수 있다.

uint16_t portb_[5];
bool key_ = false;
void DMA_PORTB_COMPLETED(DMA_HandleTypeDef *hdma)
{
uint16_t mand = 0xFFFF, mor = 0;
for (int i = 0; i < DIMOF(portb_); ++i) {
mand &= portb_[i];
mor |= portb_[i];
}
if (0 == ((mand ^ mor) & ENC_BTN_Pin)) {
key_ = (mand & ENC_BTN_Pin);
}
}

HAL_TIM_Base_Start_DMA는 ARR 레지스트를 사용하도록 하드코딩되어 있기 때문에, HAL 코드를 응용하여 타이머와 DMA가 동작하도록 하였다.

htim4.hdma[TIM_DMA_ID_UPDATE]->XferCpltCallback = DMA_PORTB_COMPLETED;
HAL_DMA_Start_IT(htim4.hdma[TIM_DMA_ID_UPDATE], (uint32_t)&GPIOB->IDR, (uint32_t)portb_, DIMOF(portb_));
__HAL_TIM_ENABLE_DMA(&htim4, TIM_DMA_UPDATE);
__HAL_TIM_ENABLE(&htim4);

키 상태를 안정적으로 입력 받을 수 있게 되었으므로, 이전 키 값과 비교하여 키의 변화를 리포팅 하거나 큐 처리하여 사용하자.

Integrate Redmine + GIT with Docker #1

레드마인과 git 서비스를 도커를 이용해 설치한다.

설계

  • 사용자가 redmine.example.com 을 웹브라우저에 입력하면 IP(A) 주소로 접속하게 된다.
  • IP(A) 의 http(80) 포트는 옵션(i) 을 컨테이너(2) 생성 시 지정하고, http 접속은 컨테이너(2) 내부의 nginx 설정으로 https(443) 으로 리다이렉트 되도록 한다.
  • https://redmine.example.com 으로 요청이 바뀌어 컨테이너(2) 로 접속하면 ssl 암호화를 처리하고 컨테이너(4)로 http 프록시를 이용해 요청을 전달한다.
  • 컨테이너(4)는 실질적인 redmine 서버스를 컨테이너(2)를 통해 제공하며 외부에 노출되지 않는다.
  • 컨테이너(3)은 사용자 인증 정보와 redmine 서비스의 데이터베이스이다.
  • 컨테이너(4)는 git 서비스를 redmine 의 사용자 인증 정보를 이용하여 관리할 수 있도록 별도의 아파치 서버로 구성된다. (Redmine.pm 모듈이 아파치 전용이기 때문)
  • 만약 추가적인 IP(B)가 있다면 git 웹 서비스 포트 80, 443을 직접 사용할 수 있다. 아니라면 IP(A):8080:80 같은 식으로 포트 지정 필요.
  • 만약 추가적인 IP(B)가 있다면 옵션 (ii) 로 기본 ssh 포트를 활용할 수 있다. 호스트의 /etc/ssh/sshd_config 설정 중 기본 ListenAddress 변경 필요. 추가 IP 가 없다면 다른 포트를 지정. (2222:22)