Saturday, August 31, 2013

I2C/TWI with AVR Register Intialization

We learned about the different registers available in the Atmel AVR microcontroller to program the TWI interface. In this section we'll go through the twi_init API and the initialization of the TWI interface.

The initialization code in the testbench.c initializes the TWI/I2C library as follows:
x_twi_init_params.e_mode = eTWI_INIT_MODE_16_0000M_100K_1;
x_twi_init_params.pfn_debug = testbench_debug;
e_twi_ret = twi_init(&x_twi_init_params);
if(eTWI_SUCCESS != e_twi_ret)
{
   i_ret = -1;
   goto LBL_INIT_IO_RET;
}

The API twi_init takes a structure variable x_twi_init_params of the type shown below.  The definition is in twi.h
typedef struct _TWI_INIT_PARAMS_X
{
   TWI_INIT_MODE_E e_mode;
   TWI_DEBUG_PFN pfn_debug;
 
}TWI_INIT_PARAMS_X;

The TWI interface can be initialized based on several modes each of which is given an identifier which signifies the CPU clock frequency, SCL clock speed and the pre-scaler value. For instance in the enumeration definition below eTWI_INIT_MODE_16_0000M_100K_1 is the mode for a 16.0000MHz micro-controller, with the desired SCL clock frequency set at 100KHz and the pre-scaler set to 1.
typedef enum _TWI_INIT_MODE_E
{
   eTWI_INIT_MODE_16_0000M_100K_1 = 0,
   eTWI_INIT_MODE_16_0000M_400K_1,
   eTWI_INIT_MODE_16_0000M_100K_4,
   eTWI_INIT_MODE_16_0000M_400K_4,
   eTWI_INIT_MODE_INVALID
 
}TWI_INIT_MODE_E;

Internally if we take a look at the twi_init function defined in twi.c we see a look up table is employed to initialize the5 registers TWBR, TWCR, TWSR, TWDR, TWAR. The look up table has the following structure for each row:

typedef struct _TWI_INIT_REG_X
{
   TWI_INIT_MODE_E e_mode;
   uint8_t uc_twbr;
   uint8_t uc_twcr;
   uint8_t uc_twsr;
   uint8_t uc_twdr;
   uint8_t uc_twar;
    
}TWI_INIT_REG_X;
The lookup table is a global array gxa_init_reg and is defined as follows:
static TWI_INIT_REG_X gxa_init_reg[] =
{
   {
      eTWI_INIT_MODE_16_0000M_100K_1,
      0x48,                               //0b01001000
      0x80,                               //0b10000000
      0x00,                               //0b00000000
      0x00,                               //0b00000000
      0x00                                //0b00000000
   }
};
The code in twi_init cycles through the array gxa_init_reg until it finds the correct mode and then initializes the 5 registers with the values associated with the mode.
for(uc_i = 0 ; uc_i < uc_size_arr ; uc_i++)
{
   if(px_init_params->e_mode == gxa_init_reg[uc_i].e_mode)
   {
      px_init_reg = &gxa_init_reg[uc_i];
      break;
   }
}
 
if(NULL == px_init_reg)
{
   if(NULL != px_init_params->pfn_debug)
   {
      px_init_params->pfn_debug("Can't find correct mode");
   }
    
   e_ret = eTWI_FAILURE;
   goto LBL_TWI_INIT_RET;
}
 
TWBR = px_init_reg->uc_twbr;
TWCR = px_init_reg->uc_twcr;
TWSR = px_init_reg->uc_twsr;
TWDR = px_init_reg->uc_twdr;
TWAR = px_init_reg->uc_twar;
In the next section we'll check out transmit and receive functionality on the TWI/I2C bus with I2C/TWI with AVR Data Transfer.

No comments:

Post a Comment