CodeVision XMEGA32E5 and I2C Slave

Go To Last Post
3 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm having a number of problems using codevision's TWI driver to work as an I2C slave.

I've got past 90% of them, but I'm stuck with the final part.

 

Firstly I'll explain about my setup.

 

I have an Arduino Mega2560 (master mode) which sends an increasing value (unsigned char) to I2C address 0x51

It then reads 8 bytes from I2C

 

On the XMEGA32E5 (in slave mode as address 0x51) I receive a byte, send it to the USART as text (so I can read it)

And then put 0 to 7 in the TX buffer.

 

When I run my tests, the XMEGA32E5 is reading and receiving the address correctly (YAY)

I can see my buffer is filled with values from 0 to 7, but appears on the I2C buss is 8 lots of 255 (0xFF).

 

I've got a logic analyser on the lines and I can clearly see the correct WRITE, ADDRESS, ACK, NACK, and so on. And the data being returned is definately 0xFF

Here's an extract of I2C logic analyser output (waveforms confirm this)

Setup write to [0x51] + ACK

0x09 + ACK

Setup Read to [0x51] + ACK

0xFF + ACK

0xFF + ACK

0xFF + ACK

0xFF + ACK

0xFF + ACK

0xFF + ACK

0xFF + ACK

0xFF + NACK

 

Setup write to [0x51] + ACK

0x0A + ACK

Setup Read to [0x51] + ACK

0xFF + ACK

0xFF + ACK

0xFF + ACK

...... (from 0x00 to 0xFF)

 

 

I'm just using the off the shelf CodeVision libraries.

 

Here's the code (again straight from codevision library I've just added in my debugging);

/*******************************************************
TWI initialization created by the
CodeWizardAVR V3.25 Automatic Program Generator
© Copyright 1998-2016 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project : uEMG
*******************************************************/

// I/O Registers definitions
#include <io.h>
#include <stdio.h>

// TWI initialization functions
#include "twi_init.h"

unsigned char Twi_RX_Flag = 0;
unsigned char twic_slave_tx_buffer[]={'0','1','2','3','4','5','6','7'};

// TWIC initialization
// Structure that holds information used by the TWIC Slave
// for performing a TWI bus transaction
TWI_SLAVE_INFO_t twic_slave;

// TWIC Slave receive buffer
// Note: TWIC_SLAVE_RX_BUFFER_SIZE is #define-d in 'twi_init.h' with the value 64
unsigned char twic_slave_rx_buffer[TWIC_SLAVE_RX_BUFFER_SIZE];

// TWIC Slave transmit buffer
// Note: TWIC_SLAVE_TX_BUFFER_SIZE is #define-d in 'twi_init.h' with the value 64
unsigned char twic_slave_tx_buffer[TWIC_SLAVE_TX_BUFFER_SIZE];

void twic_init(void)
{
// General TWIC initialization
// External Driver Interface: Off
// SDA Hold: Off
twi_init(&TWIC,false,TWI_SDAHOLD_OFF_gc);

// TWIC Master is disabled
TWIC.MASTER.CTRLA=0;

// TWIC Slave initialization
// Slave interrupt: High Level
// Match any slave address: Off
// Slave address: 0x51
// Use second slave address: Off
// Address mask: 0x00
twi_slave_init(&twic_slave,&TWIC,TWI_SLAVE_INTLVL_HI_gc,
    false,0x51,(0x00 << 1) | 0,
    twic_slave_rx_buffer,TWIC_SLAVE_RX_BUFFER_SIZE,
    twic_slave_tx_buffer,twic_slave_trans);
}

// TWIC Slave interrupt service routine
#pragma optsize- // optimize for speed
interrupt [TWIC_TWIS_vect] void twic_slave_isr(void)
{
// This gets called EVERYTIME something happens on the I2C bus


twi_slave_int_handler(&twic_slave);
}
#pragma optsize_default

// TWIC Slave transaction processing function
void twic_slave_trans(void)
{
unsigned char data;

// read the received data from the TWIC Slave receive buffer

    data=twic_slave_rx_buffer[twic_slave.rx_index];
    printf("\r\n RX: %d \r\n",data);


if (twic_slave.bytes_to_tx==0)
    {
    twic_slave_tx_buffer[0]=0;
    twic_slave_tx_buffer[1]=1;
    twic_slave_tx_buffer[2]=2;
    twic_slave_tx_buffer[3]=3;
    twic_slave_tx_buffer[4]=4;
    twic_slave_tx_buffer[5]=5;
    twic_slave_tx_buffer[6]=6;
    twic_slave_tx_buffer[7]=7;

    twic_slave.bytes_to_tx=8;

    printf("To TX; %d \r\n", twic_slave_tx_buffer[0]);

   }

// NOtes from User guide
// after each transaction is finished the bytes_to_tx is set to 0



}


void twi_put_buffer(unsigned char data)
{
   twic_slave.tx_buffer[twic_slave.tx_index++] = data;
}

PORTC is set as inputs (which I believe is what is required for I2C Slave operation);

// PORTC initialization
// OUT register
PORTC.OUT=0x80;
// Pin0: Input
// Pin1: Input
// Pin2: Input
// Pin3: Input
// Pin4: Input
// Pin5: Input
// Pin6: Input
// Pin7: Output
PORTC.DIR=0x80;
// Pin0 Output/Pull configuration: Totempole/No
// Pin0 Input/Sense configuration: Sense both edges
// Pin0 Inverted: Off
PORTC.PIN0CTRL=PORT_OPC_PULLUP_gc | PORT_ISC_BOTHEDGES_gc;
// Pin1 Output/Pull configuration: Totempole/Pull-up (on input)
// Pin1 Input/Sense configuration: Sense both edges
// Pin1 Inverted: Off
PORTC.PIN1CTRL=PORT_OPC_PULLUP_gc | PORT_ISC_BOTHEDGES_gc;
// Pin2 Output/Pull configuration: Totempole/No
// Pin2 Input/Sense configuration: Sense both edges
// Pin2 Inverted: Off

I'd appreciate any help anyone has to offer, this is my first time using I2C and I'm already loathing it.

 

Many thanks

Paula

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here's some screen grabs;

 

First the Logic analyser output;

 

 

Next the Logic analyser output of their I2C monitor;

 

and finally the output of my debugging, window on the left is from the XMEGA32E5, window on the right from the Arduino;

 

Again, thanks in advance.

 

Paula

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Fixed it, I'm not sure why, I suspect it's something to do with new transactions.

 

The solution is make sure the bytes to tx is set in the ISR.

it would've saved me a LOT of time (~two weeks) if this had been mentioned in the documentation!

 

revised ISR;

interrupt [TWIC_TWIS_vect] void twic_slave_isr(void)    // HERE BE DRAGONS
{

    if (twic_slave.bytes_to_tx == 0)
    {
        twic_slave.bytes_to_tx=8;
    }

    twi_slave_int_handler(&twic_slave);
}

Screen shot of logic analyser;