페이지

글목록

2016년 8월 11일 목요일

[STM32F4xx] Nucleo 보드 테스트 #11(GPIO 병렬 출력:KEIL)

이번에는 GPIO에 여러핀을 동시에 출력하는 방법을 알아보겠습니다.

핀 설정도 동시에 할 순 있는데, 좀 귀찮아서 핀설정은 각 핀마다 했습니다.

이제 제가 프로젝트를 시작해야 해서, 프로젝트에서 사용해야 할 핀들을 다 포함시킨 상태에서
GPIO 병렬 포트로 사용할 핀을 지정을 해 봤습니다.

GPIO 설정은 Cube 툴에서 할 수 없으니까, 핀이 표시가 되지 않아서 따로 사용할 핀을 정리해 봤습니다.

그리고 현재 사용한 Nucleo 보드에서 핀헤더의 위치도 표시해 봤습니다.


자.. 그럼 핀 설정은 정리해 보자면,
DATA[7:2] : PA15,14,13,12,11,10
DATA[1:0] : PC7,6
SYNC CLK : PB5

핀 설정 코드는 1핀마다 설정을 했더니 너무 길어서 소스코드 첨부해 놓을 테니 참고하시기 바람니다.
main.c 파일 안에 static void MX_GPIO_Init(void) 함수 보시면 되겠습니다.

이렇게 설정을 했습니다. 간단히 설명을 해 보자면, SYNC CLK 의 Rising Edge 마다 8비트 데이터를 출력 하는 테스트 입니다.
8비트 병렬 통신을 구현할 생각이고, STM 칩으로 8비트 데이터를 보내고 SYNC 출력을 1번 내보내는 겁니다.

8번 출력(0x01->0x02->0x04->0x08->0x10->0x20->0x40->0x80) 을 반복해서 내보내도록 했습니다.

다음은 main.c 의 main()함수의 주요 동작 코드입니다.

  for (i=0;i<8 8="" i="" span="">
  {
par_data[i] = (1&lt;&lt; i);
      // (0x01-&gt;0x02-&gt;0x04-&gt;0x08-&gt;0x10-&gt;0x20-&gt;0x40-&gt;0x80) 데이터 생성
  }

  while (1)
  {
par_ReAssemble(par_data,8);
       // (0x01-&gt;0x02-&gt;0x04-&gt;0x08-&gt;0x10-&gt;0x20-&gt;0x40-&gt;0x80) 데이터 출력 + SYNC_CLK 출력
HAL_Delay(1);
  }



현재 핀을 여러용도록 사용했더니, 출력할 포트가 2개로 나뉘어 버려서 8비트 데이터를 재정렬하도록 프로그램을 만들었습니다.
재정렬 함수의 코드는 다음과 같습니다.
void par_ReAssemble(uint8_t *par_data,uint16_t cnt_data)
{
uint16_t i;
for (i=0;i
{
// DATA[7:2] : PA15,14,13,12,11,10
GPIOA-&gt;ODR = (((uint32_t)par_data[i]) &lt;&lt; 8)&amp;0xFC00;
// DATA[1:0] : PC7,6
GPIOC-&gt;ODR = (((uint32_t)par_data[i]) &lt;&lt; 6)&amp;0x00C0;
//HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5,GPIO_PIN_SET);
//HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5,GPIO_PIN_RESET);
GPIOB-&gt;BSRR = GPIO_PIN_5;
GPIOB-&gt;BSRR = (GPIO_PIN_5&lt;<16 16="" div="">
}
}

위의 함수에서 GPIOA-&gt;ODR 이 보이시죠?
이 레지스터가 각각 16비트폭으로서, 병렬 포트를 출력하도록 하는 레지스터입니다.
쉬프트 연산과 마스크 연산을 해서 병렬포트 출력 레지스터에 값을 쓰면 해단 핀들로 0또는 1이 출력 됩니다.

1비트 출력은 2가지 방법이 있습니다.
1. HAL 드라이버에서 제공하는 함수를 사용.
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5,GPIO_PIN_SET);
2. 직접 레지스터에 쓰기.
GPIOB-&gt;BSRR = GPIO_PIN_5;
GPIOB-&gt;BSRR = (GPIO_PIN_5&lt;<16 16="" div="">

HAL_GPIO_WritePin 함수는 누구나 인식하기 쉬워서 보면 아시겠고,
BSRR 레지스터는 32비트 구조인데, 1을 해당 비트에 써주면 하위 16비트는 SET, 상위 16비트는 RESET 기능을 합니다.

위에서 2가지 방법이 있다고 했는데, 사실은 HAL.. 함수에서 BSRR 레지스터를 사용하고 있어서 본래는 1가지 방법입니다.
그런데 제가 왜 레지스터에 집접 썼는가 하면 HAL.. 함수가 너무 느려서 입니다. 
테스트를 해 본 결과, 레지스터를 사용한 방법보다 2배나 느리더군요.

다음은 같은 동작을 수행했을 때, 왼쪽이 HAL 함수, 오른쪽이 레지스터에 직접 쓴 방법을 사용한 결과 입니다.

다음은 8비트로 1바이트를 보냈을 때, 직접 속도를 계산해 봤습니다. 


나중에 설명을 하려고 했는데, 먼저 해 버렸네요.
이게 제가 알려드리고자 한 핵심이고 앞으로 설명할 나머지는 크게 중요하진 않습니다.

사용자의 편의성이냐? 속도냐? 둘 중 하나를 선택하시면 됩니다.

그런데.. 저 파형이 링잉이 발생하는게 거슬리네요. 파형이 원래 그런것인지 오실로 스코프가 문제인지.. 궁금하네요. 내일 오실로 스코프 바꿔서 테스트 해 봐야겠습니다.


다음은 HAL 함수를 사용해서 프로그램을 돌려 본 결과 입니다.
검증을 위해 4채널 오실로 스코프를 이용해서 1로 예상되는 포인트만 찍었습니다. 9개의 신호를 한번에 찍을 수가 없어서 3개의 프로브를 나눠서 측정을 했습니다.

[ SYNC_CLK 와 DATA 0,1,2 ]

[ SYNC_CLK 와 DATA 2,3,4 ]

[ SYNC_CLK 와 DATA 5,6,7 ]


다행이 예상대로 잘 나왔네요.

그럼 이만 마치겠습니다.

소스 코드 첨부 합니다.

댓글 없음:

댓글 쓰기