펌웨어로 무언가를 개발하려면 제일 먼저 하는 건, LED 켜고 끄기다. 사실 더 이전에 하는 일은 전원이 정상 들어오는지?
터지지 않는지? 오실레이터가 정상적으로 발진하는지, JTAG과 CPU가 정상적으로 통신하는지... 등이 있다.

그래서 가장 마지막에 테스트하는 GPIO로 LED가 제어가 된다면 개발 관련해서는 50% 이상은 한 것이나 마찬가지이다.
(개발 관련은..)


- GPIO -

출력 설정을 하려면 GPIO_PinModeSet 함수를 이용하면 된다. 포트와 PIN 번호를 가지고 풀업을 하지 말지

그리고 초기 출력값을 무엇으로 할지 결정하면 된다.

em_gpio.c

 

또 CMU_ClockEnable 함수로 GPIO 클럭 활성화도 같이 해주면 된다. 위는 PORTD의 4번 핀에 있는 LED를 풀업으로 초기값 '1'로 설정하는 방법이다. 나중에 상황에 맞춰 GPIO_PinOutSet 함수를 사용하면 되고 Toggle을 하고 싶을 때는 GPIO_PinOutToggle 함수로 간단하게 토글을 할 수 있다. 그다음으로 개발하는 것은 디버깅 로그 확인 및 통신을 위해 UART, Serial 통신이다.

- USART -

8비트 마이 컴퓨터로 개발할 때는 데이터시트를 보면서 baudrate를 계산하기 위해 크리스탈 클럭과 계산 공식으로 일일이 다 계산을 했었는데 지금은 제공하는 함수만 사용하면 된다. (아는 지인은 이런 부분 때문에 아래 직원들이 개발할 줄 모른다고 타박을 놓기도 하더라.. 물론 나도 인정하는 부분)

void uart_serial_init()
{
#if defined(_CMU_HFPERCLKEN0_MASK)
	CMU_ClockEnable(cmuClock_HFPER, true);
#endif
	
	USART_TypeDef           *usart = USART1;
	USART_InitAsync_TypeDef init   = USART_INITASYNC_DEFAULT;
	
	CMU_ClockEnable(cmuClock_GPIO, true);
	CMU_ClockEnable(cmuClock_USART1, true);
	
	GPIO_PinModeSet(gpioPortA, 6, gpioModePushPull, 1);
	GPIO_PinModeSet(gpioPortA, 5, gpioModeInputPull, 1);
	
	init.enable = usartDisable;
	init.baudrate = 115200;
	
	USART_InitAsync(usart, &init);
	
#if defined(GPIO_USART_ROUTEEN_RXPEN)
	GPIO->USARTROUTE[1].RXROUTE = (gpioPortA << _GPIO_USART_RXROUTE_PORT_SHIFT)
	   | (5 << _GPIO_USART_RXROUTE_PIN_SHIFT);
	
	GPIO->USARTROUTE[1].TXROUTE = (gpioPortA << _GPIO_USART_TXROUTE_PORT_SHIFT)
	   | (6 << _GPIO_USART_TXROUTE_PIN_SHIFT);
	// Enable RX and TX
	
	GPIO->USARTROUTE[1].ROUTEEN = GPIO_USART_ROUTEEN_RXPEN | GPIO_USART_ROUTEEN_TXPEN;
	// Configure and enable USART0
	
#else
	usart->ROUTE = USART_ROUTE_RXPEN | USART_ROUTE_TXPEN | RETARGET_LOCATION;
#endif
	
	FlushQueue (ENUM_UART_DEBUG);
	
	USART_IntClear(USART1, USART_IF_RXDATAV);
	NVIC_ClearPendingIRQ(USART1_RX_IRQn);
	
	/* Enable RX interrupts */
	USART_IntEnable(USART1, USART_IF_RXDATAV);
	NVIC_SetPriority (USART1_RX_IRQn, 4 /*5*/);
	NVIC_EnableIRQ(USART1_RX_IRQn);	
	USART_Enable(usart, usartEnable);	
}

static uint32_t uart_tx_write(uint8_t *pui8Data, uint32_t ui32NumBytes)
{
	uint32_t i = 0;
	while (i < ui32NumBytes)
	{
		USART_Tx(USART1,pui8Data[i++]);
	}
	return i;
} // uart_tx_write()

 

uart_tx_write 함수로 데이터를 전송하면 테라텀등의 터미널 프로그램으로 데이터를 받아 볼 수 있게 된다. 그런데 다른 칩은 모르겠는데 EFR32BG21 칩이 특이한 기능이 있어서 개발에 큰 도움이 된 적이 있다. 보통 CPU의 각 핀은 멀티 funtion을 지원하더라도 다른 핀과 기능을 바꾸는 기능은 없었다. 그런데 EFR32BG21은 Digital Peripheral Connectivity 라 해서 디지털 리소스(UART나 i2c, timer 등)을 라우팅할 수 있다고 한다. 게다가 Rx, Tx 같은 기능이 다른 핀 설정까지도!

사실 하드웨어 팀에서 UART Tx와 Rx를 꼬와서 개발을 해버렸다. EV 보드에서 잘 되는 게 안돼서 회로도를 보니 핀 이 잘못되어 있었던 것... 하드웨어 팀한테 점 터를 날려달라 할까 하다가 데이터시트를 보고 설마 하고 핀 설정을 바꿔서 하니... 바로 동작했다. 펌웨어 개발 10년 만에 이렇게 놀란건 NXP 이후로 처음인 것 같다. 설정하는 방법은 간단하다. 위 소스의 RXROUTE 와 TXROUTE 의 핀설정을 바꿔주기만 하면 되었다. GPIO_PinModeSet도 같이 변경하였다.


다음에는 특이했던 인터럽트 핸들러와 타이머 인터럽트를 정리해 봐야겠다.