This is tutorial is not intended to be a guide for learning C language or about the Nordic SDK platform. It’s primary target is to provide developers a concise guide about integrating peripheral modules and features into active applications.
If you are a beginner, I would recommend you look into an nRF52 Project Setup guide like this one.
https://medium.com/vicara-hardware-university/nrf52-project-setup-with-segger-embedded-system-f64958052a2d
Another easy way to get started with coding, without bothering with all basic stuff like files and driver inclusion, check out this Code Generation Tool
nrf52 Code Generator: https://vicara.co/nrf52-code-generator
Two Wire Interface, as the name suggests uses two wires, the clock and data, to enable communication between several devices. This protocol allows communication of a single master device with multiple slave devices. Differentiation is done either by address of the slave device, or using a GPIO pin to enable only a single device at a time.
Devices which use TWI or I2C include sensor peripheral devices like IMU, Temperature Sensors and Multi-Channel Motor Control Devices.
In the following section, I will provide a guide as it has been tested in the nRF52832 Dev Kit. However, the same structure will remain common across all nRF52 devices.
Include the TWI Driver files. This file should be titled, nrf_drv_twi.c It is at SDK/integration/nrfx/legacy folder.
#include "nrf_drv_twi.h"
/* TWI instance ID. */
#define TWI_INSTANCE_ID 0
/* TWI instance. */
staticconstnrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);
/* Indicates if operation on TWI has ended. */
staticvolatilebool m_xfer_done = false;
voidtwi_handler (nrf_drv_twi_evt_tconst *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_RX)
{
}
m_xfer_done = true;
break;
default:
break;
}
}
Note: One callback function is needed per instance
voidtwi_init(void)
{
ret_code_t err_code;
constnrf_drv_twi_config_t twi_config = {
.scl = 15,
.sda = 14,
.frequency = NRF_TWI_FREQ_100K,
.interrupt_priority = APP_IRQ_PRIORITY_HIGH,
.clear_bus_init = false,
.hold_bus_uninit = false};
err_code = nrf_drv_twi_init(&m_twi, &twi_config, twi_handler, NULL);
APP_ERROR_CHECK(err_code);
nrf_drv_twi_enable(&m_twi);
}
Note: The above block of code configures and enables one instance of TWI. If another instance is needed, a new variable of type nrf_drv_twi_config_tneeds to be defined again. nrf_drv_twi_init and nrf_drv_twi_enable need to be called again. Interrupt priority options are 2, 3, 6, 7.
twi_init(); // After default definition, before Advertise Start
/*
* dev_addr -> Device address
* reg_adddr -> Register address
* data -> Buffer which holds data to be written
* length -> Length of data to be written
*/
int8_ttwi_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t length)
{
uint32_t err_code;
uint8_t buffer[255] = {0};
buffer[0] = reg_addr;
memcpy(&buffer[1], data, length);
m_xfer_done = false;
err_code = nrf_drv_twi_tx(&m_twi, dev_addr, buffer, sizeof(length), false);
APP_ERROR_CHECK(err_code);
while (m_xfer_done == false);
return err_code;
}
/*
* dev_addr -> Device address
* reg_adddr -> Register address
* data -> Buffer where data read from TWI will be stored
* length -> Length of data to be read
*/
int8_ttwi_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t length)
{
uint32_t err_code;
m_xfer_done = false;
err_code = nrf_drv_twi_tx(&m_twi, dev_addr, ®_addr, sizeof(reg_addr), true);
APP_ERROR_CHECK(err_code);
while (m_xfer_done == false);
m_xfer_done = false;
err_code = nrf_drv_twi_rx(&m_twi, dev_addr, data, length);
APP_ERROR_CHECK(err_code);
while (m_xfer_done == false);
return err_code;
}
With the above steps anyone can easily get started with incorporating TWI.
There is another easier method to initialize and auto-generate code for nRF52. This tool, will handle all library additions and code generations for a variety of peripherals like SPI, I2C, UART etc.
Link: https://vicara.co/nrf52-code-generator