TWI(Two-Wire Interface)는 I2C(Inter-Integrated Circuit)로도 알려진 직렬 통신 프로토콜입니다. 이 글에서는 nRF52840에서 TWI Master를 구현하는 방법에 대해 설명합니다. TWI Master는 TWI 통신을 주도하며, Slave 장치에 Clock을 공급하고 명령을 보내거나 데이터를 수신합니다.
1. TWI Master 드라이버 준비
TWI Master 드라이버를 초기화하기 위해서는 nrf_drv_twi_config_t 구조체를 이용하여 SDA 및 SCL 핀, TWI 통신 속도를 설정하고, nrf_drv_twi_init() 함수를 호출하여 드라이버를 초기화해야 합니다. 이후, nrf_drv_twi_enable() 함수를 호출하여 TWI Master 드라이버를 활성화합니다.
#define TWI_M_SDA_PIN NRF_GPIO_PIN_MAP(0, 4)
#define TWI_M_SCL_PIN NRF_GPIO_PIN_MAP(0, 3)
static const nrf_drv_twi_t g_twi_m = NRF_DRV_TWI_INSTANCE(0);
volatile bool g_twi_m_tx_done = false;
volatile bool g_twi_m_rx_done = false;
static void aika_twi_m_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
{
switch(p_event->type)
{
case NRF_DRV_TWI_EVT_DONE:
if(p_event->xfer_desc.type == NRF_DRV_TWI_XFER_TX)
g_twi_m_tx_done = true;
if(p_event->xfer_desc.type == NRF_DRV_TWI_XFER_RX)
g_twi_m_rx_done = true;
break;
default:
break;
}
}
int aika_twi_master_init(void)
{
ret_code_t err_code;
const nrf_drv_twi_config_t sens_ex_i2c_cfg = {
.scl = TWI_M_SCL_PIN, // SCL Pin
.sda = TWI_M_SDA_PIN, // SDA Pin
.frequency = NRF_DRV_TWI_FREQ_400K, // TWI Frequency 100K, 250K, 400K 선택 가능
.interrupt_priority = APP_IRQ_PRIORITY_HIGH, // Interrupt 우선 순위
.clear_bus_init = true
};
err_code = nrf_drv_twi_init(&g_twi_m, &sens_ex_i2c_cfg, aika_twi_m_handler, NULL);
if(NRF_SUCCESS != err_code)
{
NRF_LOG_INFO("TWI Init failed\r\n");
return -1;
}
nrf_drv_twi_enable(&g_twi_m);
NRF_LOG_INFO("TWI Master Init Done\r\n");
return 0;
}
1.1. 코드 설명
- 핀 설정: TWI_M_SDA_PIN과 TWI_M_SCL_PIN으로 SDA와 SCL 핀을 설정합니다.
- 핸들러 설정: aika_twi_m_handler() 함수는 TWI 이벤트가 발생했을 때 호출되며, TX(전송) 및 RX(수신) 완료 여부를 확인합니다.
- 초기화: aika_twi_master_init() 함수는 TWI Master 드라이버를 초기화하고 활성화합니다.
2. TWI Master Write / Read
TWI 통신에서 데이터 전송과 수신은 각각 nrf_drv_twi_tx()와 nrf_drv_twi_rx() 함수를 통해 이루어집니다. TWI 통신이 완료되었는지 확인하기 위해 twi_m_wait_write() 및 twi_m_wait_read() 함수를 사용하여 이전 통신이 완료된 후에만 다음 통신을 시작해야 합니다.
int twi_m_wait_write(uint8_t addr)
{
int check_count = 0;
while(false == g_twi_m_tx_done)
{
check_count++;
nrf_delay_ms(2);
if(3 < check_count)
{
g_twi_m_tx_done = true;
NRF_LOG_INFO("TWI Write Failed 0x%x\r\n", addr);
return -1;
}
}
return 0;
}
int twi_m_wait_read(uint8_t addr)
{
int check_count = 0;
while(false == g_twi_m_rx_done)
{
check_count++;
nrf_delay_ms(2);
if(3 < check_count)
{
g_twi_m_rx_done = true;
NRF_LOG_INFO("TWI Read Failed 0x%x\r\n", addr);
return -1;
}
}
return 0;
}
int aika_twi_m_read(uint8_t addr, uint8_t* cmd, uint8_t cmd_len, uint8_t* resp, uint8_t resp_len)
{
ret_code_t err_code = NRF_SUCCESS;
g_twi_m_tx_done = false;
err_code = nrf_drv_tw_tx(&g_twi_m, addr, cmd, cmd_len, false);
if(NRF_SUCCESS != err_code)
{
NRF_LOG_INFO("[ 0x%x ] %s tx failed with %d\r\n", addr, __func__, err_code);
g_twi_m_tx_done = true;
return -1;
}
if(0 != twi_m_wait_write(addr))
return -1;
nrf_delay_ms(10);// default delay 10ms needed sht40
g_twi_m_rx_done = false;
err_code = nrf_drv_twi_rx(&g_twi_m, addr, resp, resp_len);
if(NRF_SUCCESS != err_code)
{
NRF_LOG_INFO("[ 0x%x ] %s rx failed with %d\r\n", addr, __func__, err_code);
g_twi_m_rx_done = true;
return -1;
}
return twi_m_wait_read(addr);
}
2.1. 코드 설명
- 대기 함수: twi_m_wait_write()와 twi_m_wait_read() 함수는 각각 TX 및 RX 작업이 완료될 때까지 대기합니다.
- 읽기 함수: aika_twi_m_read() 함수는 TWI Master에서 Slave로 명령을 보내고 응답을 받는 과정을 처리합니다.
3. 개선 사항 및 주의점
3.1. 타임아웃 설정
twi_m_wait_write()와 twi_m_wait_read() 함수는 일정 시간 동안 TX 또는 RX 작업이 완료되지 않으면 실패로 간주합니다. 타임아웃 시간을 실제 사용 환경에 맞게 조정할 수 있습니다.
3.2. 오류 처리
TWI 통신이 실패할 경우, 오류 처리를 강화하여 시스템이 적절히 대응할 수 있도록 합니다. 예를 들어, 재시도 횟수를 추가하거나 오류 로그를 기록하는 등의 방법을 고려할 수 있습니다.
3.3. 전력 관리
nRF52840과 같은 저전력 MCU에서는 TWI 통신 완료 후 TWI 모듈을 비활성화하거나 절전 모드로 전환하여 전력 소모를 줄일 수 있습니다.
3.4. 코드 모듈화
이 예제 코드는 TWI 통신의 전형적인 흐름을 간단히 보여줍니다. 실제 응용 프로그램에서는 이러한 코드들을 더 모듈화하고, 필요에 따라 다양한 TWI 장치에 대해 유연하게 대응할 수 있도록 설계하는 것이 좋습니다.
에러 처리와 재시도 로직: TWI 통신은 간헐적으로 실패할 수 있으므로, 안정성을 높이기 위해 재시도 로직을 추가할 수 있습니다.
4. 결론
TWI 통신은 많은 센서 및 장치와 통신하는 데 유용한 프로토콜입니다. nRF52840에서 TWI Master를 구현하는 방법을 이해함으로써 다양한 I2C 장치와의 통신을 쉽게 구현할 수 있습니다. 이 글에서 설명한 코드 예제를 기반으로 자신만의 TWI 드라이버를 개발해 보세요.
'nRF52' 카테고리의 다른 글
nRF52840 SPI 드라이버 활용하기 (0) | 2024.09.03 |
---|---|
nRF52840 TWI(I2C) Slave 드라이버 활용하기 (0) | 2024.09.02 |
nRF52840 TWI I2C 설정 가이드 (0) | 2024.08.31 |
nRF52840 UART 통신 가이드 (0) | 2024.08.30 |
nRF52840 DK 보드 GPIO 기본 설정부터 인터럽트 활용까지 (0) | 2024.08.29 |