Sida 1 av 1

I2C problem med AVR

Postat: 20 november 2007, 10:16:50
av dangraf
Hallå!

jag har stött på ett problem med en AVR processor som jag jobbar med. Jag får nämligen inte igång interruptet till I2C drivrutinen.

AVR processorn är av typ: ATMEGA2560 och jag kör med IARs kompilator.

Interrupten verkar fungera för andra enheter som t.ex UART.
Jag har dels skrivit egna rutiner för I2C och har även laddat ner färdiga rutiner som t.ex AVR311 (slave) och AVR315(master).

Den globala interupten är enabelad.
jag tror mig ha satt alla flaggor rätt i TWCR registret (enable TWI modul, enable interrupt, clear interrupt flag).

jag fick även tipset om att stänga av JTAG stödet i fuse bitarna eftersom de i vissa fall använder samma pinnar som I2C pinnarna.

inget av detta verkar hjälpa.

Om jag försöker skriva till bussen ser jag på skåpet att det kommer en klocksignal på SCL, men SDA linan är konstant hög. Enligt schemat är det inget annat än AVR processorns som skall kunna skriva till bussen.

Någon som har nått tips om vad som skulle kunna vara problemet (SBS?? )

Postat: 20 november 2007, 10:22:38
av oJsan
Har du kopplat rätt, dvs med pull-ups? I2C-bussen är ju av typen "öppen-kollektor"..
Kan du posta koden där du skriver till bussen men bara får konstant hög på SDA?

Postat: 20 november 2007, 10:22:50
av björn
Hur ska vi veta det? Du *tror* att de olika registren är rättsatta men vi hade varit mer hjälpta av att få se koden (med kommentarer som berättar vad du gör) och kanske även hårdvaru beskrivning (du har väl inte glömt pullup?)

EDIT:Ojsan hann före....

Postat: 20 november 2007, 10:32:58
av dangraf
Det finns pullups till I2C bussen


här kommer en hel del kod för er alla:

Kod: Markera allt


void vDelay()
{
  int b;
  b = 0x4fff;
  while(b--);
}


 int main(void)
{
   CLKPR=0x80;                                     //  Set Clock Division Factor = 4
  CLKPR=0x02;  
  io_open();
// Detta händer med PORTD i io_open
 //        Port D initialization
  // 0=SCL, 1=SDA, 2=ALARM_TEMP, 3=PW_ON_STATUS, 4=TEST_GREEN, //5=TEST_RED, 6=PWM_CLK, 7=nc
//  DDRD=0x30; // 0011 0010
//  PORTD=0x10; //0001 0000

  io_write(oBOARD_PIN_TEST_LED2 , 1 );
  io_write(SW_ON ,1);
  TWI_Master_Initialise();
   __enable_interrupt();    // enable global interrupts
   
   while(1)
   {
     io_write(oBOARD_PIN_TEST_LED0 , !io_read(oBOARD_PIN_TEST_LED0 ) );
	 TWI_Start_Transceiver_With_Data( u8Temp,2 );
     vDelay();

   }

  

}


koden för I2C finns här och är kopierad från färdiga exempel som borde fungera.

Kod: Markera allt

/*****************************************************************************
*
* Atmel Corporation
*
* File              : TWI_Master.c
* Compiler          : IAR EWAAVR 2.28a/3.10c
* Revision          : $Revision: 1.13 $
* Date              : $Date: 24. mai 2004 11:31:20 $
* Updated by        : $Author: ltwa $
*
* Support mail      : avr@atmel.com
*
* Supported devices : All devices with a TWI module can be used.
*                     The example is written for the ATmega16
*
* AppNote           : AVR315 - TWI Master Implementation
*
* Description       : This is a sample driver for the TWI hardware modules.
*                     It is interrupt driveren. All functionality is controlled through 
*                     passing information to and from functions. Se main.c for samples
*                     of how to use the driver.
*
*
****************************************************************************/

#include "ioavr.h"              
#include "inavr.h"
#include "TWI_Master.h"

static unsigned char TWI_buf[ TWI_BUFFER_SIZE ];    // Transceiver buffer
static unsigned char TWI_msgSize;                   // Number of bytes to be transmitted.
static unsigned char TWI_state = TWI_NO_STATE;      // State byte. Default set to TWI_NO_STATE.

union TWI_statusReg TWI_statusReg = {0};            // TWI_statusReg is defined in TWI_Master.h

/****************************************************************************
Call this function to set up the TWI master to its initial standby state.
Remember to enable interrupts from the main application after initializing the TWI.
****************************************************************************/
void TWI_Master_Initialise(void)
{
  TWBR = TWI_TWBR;                                  // Set bit rate register (Baudrate). Defined in header file.
// TWSR = TWI_TWPS;                                  // Not used. Driver presumes prescaler to be 00.
  TWDR = 0xFF;                                      // Default content = SDA released.
  TWCR = 0x04;  //(1<<TWEN)|                                 // Enable TWI-interface and release TWI pins.
  //       (0<<TWIE)|(0<<TWINT)|                      // Disable Interupt.
  //       (0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|           // No Signal requests.
  //       (0<<TWWC);                                 //
}    
    
/****************************************************************************
Call this function to test if the TWI_ISR is busy transmitting.
****************************************************************************/
unsigned char TWI_Transceiver_Busy( void )
{
  if(TWCR_TWIE)
  {
    return 1;
  }
  else
  {
    return 0;                  // IF TWI Interrupt is enabled then the Transceiver is busy
  }
}

/****************************************************************************
Call this function to fetch the state information of the previous operation. The function will hold execution (loop)
until the TWI_ISR has completed with the previous operation. If there was an error, then the function 
will return the TWI State code. 
****************************************************************************/
unsigned char TWI_Get_State_Info( void )
{
  while ( TWI_Transceiver_Busy() );             // Wait until TWI has completed the transmission.
  return ( TWI_state );                         // Return error state.
}

/****************************************************************************
Call this function to send a prepared message. The first byte must contain the slave address and the
read/write bit. Consecutive bytes contain the data to be sent, or empty locations for data to be read
from the slave. Also include how many bytes that should be sent/read including the address byte.
The function will hold execution (loop) until the TWI_ISR has completed with the previous operation,
then initialize the next operation and return.
****************************************************************************/
void TWI_Start_Transceiver_With_Data( unsigned char *msg, unsigned char msgSize )
{
  unsigned char temp;

  while ( TWI_Transceiver_Busy() );             // Wait until TWI is ready for next transmission.

  TWI_msgSize = msgSize;                        // Number of data to transmit.
  TWI_buf[0]  = msg[0];                         // Store slave address with R/W setting.
  if (!( msg[0] & (TRUE<<TWI_READ_BIT) ))       // If it is a write operation, then also copy data.
  {
    for ( temp = 1; temp < msgSize; temp++ )
      TWI_buf[ temp ] = msg[ temp ];
  }
  TWI_statusReg.all = 0;      
  TWI_state         = TWI_NO_STATE ;
  TWCR = 0xA5;  //(1<<TWEN)|                             // TWI Interface enabled.
  //       (1<<TWIE)|(1<<TWINT)|                  // Enable TWI Interupt and clear the flag.
  //       (0<<TWEA)|(1<<TWSTA)|(0<<TWSTO)|       // Initiate a START condition.
  //       (0<<TWWC);                             //
}

/****************************************************************************
Call this function to resend the last message. The driver will reuse the data previously put in the transceiver buffers.
The function will hold execution (loop) until the TWI_ISR has completed with the previous operation,
then initialize the next operation and return.
****************************************************************************/
void TWI_Start_Transceiver( void )
{
  while ( TWI_Transceiver_Busy() );             // Wait until TWI is ready for next transmission.
  TWI_statusReg.all = 0;      
  TWI_state         = TWI_NO_STATE ;
  TWCR = 0xA5;  //(1<<TWEN)|                             // TWI Interface enabled.
//         (1<<TWIE)|(1<<TWINT)|                  // Enable TWI Interupt and clear the flag.
 //        (0<<TWEA)|(1<<TWSTA)|(0<<TWSTO)|       // Initiate a START condition.
 //        (0<<TWWC);                             //
}

/****************************************************************************
Call this function to read out the requested data from the TWI transceiver buffer. I.e. first call
TWI_Start_Transceiver to send a request for data to the slave. Then Run this function to collect the
data when they have arrived. Include a pointer to where to place the data and the number of bytes
requested (including the address field) in the function call. The function will hold execution (loop)
until the TWI_ISR has completed with the previous operation, before reading out the data and returning.
If there was an error in the previous transmission the function will return the TWI error code.
****************************************************************************/
unsigned char TWI_Get_Data_From_Transceiver( unsigned char *msg, unsigned char msgSize )
{
  unsigned char i;

  while ( TWI_Transceiver_Busy() );             // Wait until TWI is ready for next transmission.

  if( TWI_statusReg.lastTransOK )               // Last transmission competed successfully.              
  {                                             
    for ( i=0; i<msgSize; i++ )                 // Copy data from Transceiver buffer.
    {
      msg[ i ] = TWI_buf[ i ];
    }
  }
  return( TWI_statusReg.lastTransOK );                                   
}

// ********** Interrupt Handlers ********** //
/****************************************************************************
This function is the Interrupt Service Routine (ISR), and called when the TWI interrupt is triggered;
that is whenever a TWI event has occurred. This function should not be called directly from the main
application.
****************************************************************************/
#include "board.h"
#include "io.h"
#pragma vector=TWI_vect
__interrupt void TWI_ISR(void)
{
  static unsigned char TWI_bufPtr;
    io_write(oBOARD_PIN_TEST_LED2 , 0 );
  switch (TWSR)
  {
    case TWI_START:             // START has been transmitted  
    case TWI_REP_START:         // Repeated START has been transmitted
      TWI_bufPtr = 0;                                     // Set buffer pointer to the TWI Address location
    case TWI_MTX_ADR_ACK:       // SLA+W has been tramsmitted and ACK received
    case TWI_MTX_DATA_ACK:      // Data byte has been tramsmitted and ACK received
      if (TWI_bufPtr < TWI_msgSize)
      {
        TWDR = TWI_buf[TWI_bufPtr++];
        TWCR = 0x85;  //(1<<TWEN)|                                 // TWI Interface enabled
      //         (1<<TWIE)|(1<<TWINT)|                      // Enable TWI Interupt and clear the flag to send byte
      //         (0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|           //
      //         (0<<TWWC);                                 //  
      }else                    // Send STOP after last byte
      {
        TWI_statusReg.lastTransOK = TRUE;                 // Set status bits to completed successfully. 
        TWCR = 0x94;//(1<<TWEN)|                                 // TWI Interface enabled
       //        (0<<TWIE)|(1<<TWINT)|                      // Disable TWI Interrupt and clear the flag
       //        (0<<TWEA)|(0<<TWSTA)|(1<<TWSTO)|           // Initiate a STOP condition.
       //        (0<<TWWC);                                 //
      }
      break;
    case TWI_MRX_DATA_ACK:      // Data byte has been received and ACK tramsmitted
      TWI_buf[TWI_bufPtr++] = TWDR;
    case TWI_MRX_ADR_ACK:       // SLA+R has been tramsmitted and ACK received
      if (TWI_bufPtr < (TWI_msgSize-1) )                  // Detect the last byte to NACK it.
      {
        TWCR = 0xC5;  //(1<<TWEN)|                                 // TWI Interface enabled
    //           (1<<TWIE)|(1<<TWINT)|                      // Enable TWI Interupt and clear the flag to read next byte
    //           (1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|           // Send ACK after reception
    //           (0<<TWWC);                                 //  
      }else                    // Send NACK after next reception
      {
        TWCR =  0x85; //(1<<TWEN)|                                 // TWI Interface enabled
   //            (1<<TWIE)|(1<<TWINT)|                      // Enable TWI Interupt and clear the flag to read next byte
   //            (0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|           // Send NACK after reception
   //            (0<<TWWC);                                 // 
      }    
      break; 
    case TWI_MRX_DATA_NACK:     // Data byte has been received and NACK tramsmitted
      TWI_buf[TWI_bufPtr] = TWDR;
      TWI_statusReg.lastTransOK = TRUE;                 // Set status bits to completed successfully. 
      TWCR = 0x94;  //(1<<TWEN)|                                 // TWI Interface enabled
//             (0<<TWIE)|(1<<TWINT)|                      // Disable TWI Interrupt and clear the flag
//             (0<<TWEA)|(0<<TWSTA)|(1<<TWSTO)|           // Initiate a STOP condition.
//             (0<<TWWC);                                 //
      break;      
    case TWI_ARB_LOST:          // Arbitration lost
      TWCR = 0xA5;//(1<<TWEN)|                                 // TWI Interface enabled
    //         (1<<TWIE)|(1<<TWINT)|                      // Enable TWI Interupt and clear the flag
    //         (0<<TWEA)|(1<<TWSTA)|(0<<TWSTO)|           // Initiate a (RE)START condition.
    //         (0<<TWWC);                                 //
      break;
    case TWI_MTX_ADR_NACK:      // SLA+W has been tramsmitted and NACK received
    case TWI_MRX_ADR_NACK:      // SLA+R has been tramsmitted and NACK received    
    case TWI_MTX_DATA_NACK:     // Data byte has been tramsmitted and NACK received
//    case TWI_NO_STATE              // No relevant state information available; TWINT = “0”
    case TWI_BUS_ERROR:         // Bus error due to an illegal START or STOP condition
    default:     
      TWI_state = TWSR;                                 // Store TWSR and automatically sets clears noErrors bit.
                                                        // Reset TWI Interface
      TWCR = 0x04;//(1<<TWEN)|                                 // Enable TWI-interface and release TWI pins
//             (0<<TWIE)|(0<<TWINT)|                      // Disable Interupt
//             (0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|           // No Signal requests
//             (0<<TWWC);                                 //
  }
}


Postat: 20 november 2007, 10:35:16
av dangraf
som ni ser så jag jag lagt till en rad i interrupten för att släcka en lysdiod ifall programmet hoppar dit någon gång. Men dioden släcks inte.

det kommer en konstant ström av klockpulser på SCK vilket jag tycker är lite märkligt eftrsom jag fått för mig att pulserna enbart skall komma tillsammans med data /start / acc osv.

Postat: 20 november 2007, 10:38:11
av björn
Har du kollat så att registernamnen stämmer med ATMEGA2560? kan skilja lite mellan atmega16 och 2560, du får inga kompileringsfel/errer?

EDIT: Jag kommer ihåg att det var en del jag behöde ändra i jämförelse med appnoten när jag körde med atmega88 men minns inte vad just nu.

Postat: 20 november 2007, 10:42:21
av dangraf
Jag har kontrollerat register namnen med de som finns nämnt i databladet för just denna processorn. Jag har inte hittat varken fler eller färre register som styr I2C modulen och de heter samma sak.