Microchip® Advanced Software Framework

Quick start guide for XMEGA TWI driver

This is the quick start guide for the TWI Driver, with step-by-step instructions on how to configure and use the driver for specific use cases.

The section described below can be compiled into e.g. the main application loop or any other function that might use the TWI functionality.

Basic use case of the TWI driver

In our basic use case, the TWI driver is used to set up internal communication between two TWI modules on the XMEGA A1 Xplained board, since this is the most simple way to show functionality without external dependencies. TWIC is set up in master mode, and TWIF is set up in slave mode, and these are connected together on the board by placing a connection between SDA/SCL on J1 to SDA/SCL on J4.

Specific use case for XMEGA E devices

Prerequisites

The System Clock Management module is required to enable the clock to the TWI modules. The TWI Master driver and TWI Slave driver must also be included.

Setup

When the System Clock Management module has been included, it must be initialized:

Use case

Example code

#define TWI_MASTER TWIC
#define TWI_MASTER_PORT PORTC
#define TWI_SLAVE TWIF
#define TWI_SPEED 50000
#define TWI_MASTER_ADDR 0x50
#define TWI_SLAVE_ADDR 0x60
#define DATA_LENGTH 8
uint8_t data[DATA_LENGTH] = {
0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f
};
uint8_t recv_data[DATA_LENGTH] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
twi_options_t m_options = {
.chip = TWI_MASTER_ADDR,
};
static void slave_process(void) {
int i;
for(i = 0; i < DATA_LENGTH; i++) {
recv_data[i] = slave.receivedData[i];
}
}
ISR(TWIF_TWIS_vect) {
}
void send_and_recv_twi()
{
twi_package_t packet = {
.chip = TWI_SLAVE_ADDR,
.buffer = (void *)data,
.length = DATA_LENGTH,
.no_wait = false
};
uint8_t i;
TWI_MASTER_PORT.PIN0CTRL = PORT_OPC_WIREDANDPULL_gc;
TWI_MASTER_PORT.PIN1CTRL = PORT_OPC_WIREDANDPULL_gc;
irq_initialize_vectors();
twi_master_init(&TWI_MASTER, &m_options);
TWI_SLAVE_INTLVL_MED_gc);
for (i = 0; i < TWIS_SEND_BUFFER_SIZE; i++) {
slave.receivedData[i] = 0;
}
do {
// Nothing
} while(slave.result != TWIS_RESULT_OK);
}

Workflow

We first create some definitions. TWI master and slave, speed, and addresses:

#define TWI_MASTER TWIC
#define TWI_MASTER_PORT PORTC
#define TWI_SLAVE TWIF
#define TWI_SPEED 50000
#define TWI_MASTER_ADDR 0x50
#define TWI_SLAVE_ADDR 0x60
#define DATA_LENGTH 8

We create a handle to contain information about the slave module:

We create two variables, one which contains data that will be transmitted, and one which will contain the received data:

uint8_t data[DATA_LENGTH] = {
0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f
};
uint8_t recv_data[DATA_LENGTH] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

Options for the TWI module initialization procedure are given below:

twi_options_t m_options = {
.chip = TWI_MASTER_ADDR,
};

The TWI slave will fire an interrupt when it has received data, and the function below will be called, which will copy the data from the driver to our recv_data buffer:

static void slave_process(void) {
int i;
for(i = 0; i < DATA_LENGTH; i++) {
recv_data[i] = slave.receivedData[i];
}
}

Set up the interrupt handler:

ISR(TWIF_TWIS_vect) {
}

We create a packet for the data that we will send to the slave TWI:

twi_package_t packet = {
.chip = TWI_SLAVE_ADDR,
.buffer = (void *)data,
.length = DATA_LENGTH,
.no_wait = false
};

We need to set SDA/SCL pins for the master TWI to be wired and enable pull-up:

TWI_MASTER_PORT.PIN0CTRL = PORT_OPC_WIREDANDPULL_gc;
TWI_MASTER_PORT.PIN1CTRL = PORT_OPC_WIREDANDPULL_gc;

We enable all interrupt levels:

irq_initialize_vectors();

We enable the clock to the master module, and initialize it with the options we described before:

We do the same for the slave, using the slave portion of the driver, passing through the slave_process function, its address, and set medium interrupt level:

We zero out the receive buffer in the slave handle:

for (i = 0; i < TWIS_SEND_BUFFER_SIZE; i++) {
slave.receivedData[i] = 0;
}

And enable interrupts:

Finally, we write our packet through the master TWI module:

We wait for the slave to finish receiving:

do {
// Waiting
} while(slave.result != TWIS_RESULT_OK);
Note
When the slave has finished receiving, the slave_process() function will copy the received data into our recv_data buffer, which now contains what was sent through the master.