PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] Problem mit I2C Bus Slave via Interrupt ...



Ritchie
16.07.2012, 20:56
Hallo Zusammen,

ich habe einen atmega32 als I2C Slave im Interrupt Mode geschrieben. Der Code (siehe unten) arbeitet ohne Probleme bei einer Datenlänge als Antwort kleiner 3 Bytes. Werden längere Antwort erwartet, scheint nur Blödsinn (oder 0xff) am Master anzukommen.

Der Master, ruft ohne Probleme an einem Hardware Client (RTC Uhr) die Daten in einem Rutsch ab (5 Byte). Das ganze bei einem Atmega 32 (20Mhz) geht jedoch derzeit schief.

Bei der Abfrage mit dem Bereich "K" erwarte ich eigentlich eine Antwort mit "1,2,3,4,5,6", gesendet wird aber "1,2,1,255,255,255" und das sehr stabil !



SIGNAL (SIG_2WIRE_SERIAL)
{
unsigned char data=0;

switch (TW_STATUS) //Check the TWI-Status register
{
case TW_SR_SLA_ACK: // 0x30 Slave Receiver, Slave was addressed
m_buffer_adr=NULL; // Buffer position is not defined
TWCR_ACK; // Send Ack and request the next data byte
break;

// get variables from the system

case TW_SR_DATA_ACK: // 0x80 Slave Receiver, a data byte received
data=TWDR; // get the data byte from the register
if (m_buffer_adr == NULL) // Is it the first byte to receive (setup buffer)
{
switch( data ) // get the command byte, which data area
{
case 'A': // Actual position
m_buffer_adr = (char*) &m_ActualPosition[0];
m_NumberOfBytesToSend=sizeof(m_ActualPosition);
break;
case 'B': // Bumper state
m_buffer_adr = (char*) &m_BumperState;
m_NumberOfBytesToSend=sizeof(m_BumperState);
break;
case 'C': // Command byte send
m_buffer_adr = (char*) &m_command;
m_NumberOfBytesToSend=sizeof(m_command);
break;
case 'E': // End position
m_buffer_adr = (char*) &m_EndPosition[0];
m_NumberOfBytesToSend=sizeof(m_EndPosition);
break;
case 'G': // Actual position in grid unit
m_buffer_adr = (char*) &m_ActualPositionLow[0];
m_NumberOfBytesToSend=sizeof(m_ActualPositionLow);
break;
case 'L': // velocity Left
m_buffer_adr = (char*) &m_TargetSpeedLeft;
m_NumberOfBytesToSend=sizeof(m_TargetSpeedLeft);
break;
case 'S': // Start position
m_buffer_adr = (char*) &m_StartPosition[0];
m_NumberOfBytesToSend=sizeof(m_StartPosition);
break;
case 'O': // Base Angle
m_buffer_adr = (char*) &m_BaseOrientation;
m_NumberOfBytesToSend=sizeof(m_BaseOrientation);
break;
case 'P': // Actual Angle (Cal. by all different values)
m_buffer_adr = (char*) &m_ActualOrientation;
m_NumberOfBytesToSend=sizeof(m_ActualOrientation);
break;
case 'D': // Actual Angle by the Decoder (Impulse module)
m_buffer_adr = (char*) &m_ActualOrientationEnCoder;
m_NumberOfBytesToSend=sizeof(m_ActualOrientationEn Coder);
break;
case 'Y': // Actual Angle by the Gyro module (Angle change per second)
m_buffer_adr = (char*) &m_ActualOrientationGyro;
m_NumberOfBytesToSend=sizeof(m_ActualOrientationGy ro);
break;
case 'R': // velocity Right
m_buffer_adr = (char*) &m_TargetSpeedRight;
m_NumberOfBytesToSend=sizeof(m_TargetSpeedRight);
break;
case '!': // Status of the Program
m_buffer_adr = (char*) &m_Status;
m_NumberOfBytesToSend=sizeof(m_Status);
break;
case '@': // Steps of the sensors (Array)
m_buffer_adr = (char*) &sensSteps;
m_NumberOfBytesToSend=sizeof(sensSteps);
break;
case '?': // Version of the
m_buffer_adr = (char*) &m_version;
m_NumberOfBytesToSend=sizeof(m_version);
break;

case 'K': // Data buffer of PID Controller of other Diagnosis values
DataBuffer[0] = (char) control[0].setActPoint;
DataBuffer[1] = (char) control[1].setActPoint;
DataBuffer[2] = (char) control[0].setOutPut;
DataBuffer[3] = (char) control[1].setOutPut;
DataBuffer[4] = (char) control[0].difValue;
DataBuffer[5] = (char) control[1].difValue;
m_buffer_adr = (char*) &DataBuffer;
m_NumberOfBytesToSend=sizeof(DataBuffer);
break;
case '1': //
m_buffer_adr = (char*) &m_MotorTemperatur_Left;
m_NumberOfBytesToSend=sizeof(m_MotorTemperatur_Lef t);
break;
case '2': //
m_buffer_adr = (char*) &m_MotorTemperatur_Right;
m_NumberOfBytesToSend=sizeof(m_MotorTemperatur_Rig ht);
break;
case '5': //
m_buffer_adr = (char*) &m_MotorCurrent_Left;
m_NumberOfBytesToSend=sizeof(m_MotorCurrent_Left);
break;
case '6': //
m_buffer_adr = (char*) &m_MotorCurrent_Right;
m_NumberOfBytesToSend=sizeof(m_MotorCurrent_Right) ;
break;
case '7': //
m_buffer_adr = (char*) &m_AkkuVoltage;
m_NumberOfBytesToSend=sizeof(m_AkkuVoltage);
break;

default:
DataBuffer[0] = (char) 0; // Give dummy data back
m_buffer_adr = (char*) &DataBuffer;
m_NumberOfBytesToSend=1;
}
TWCR_ACK; // Set ack and get the next byte to receive
}
else

// get now the data into the buffer
{
if(m_NumberOfBytesToSend > 0)
{
if( m_buffer_adr != NULL ) // Do we have a valid pointer
{
*m_buffer_adr=data; // Store the data into the buffer
m_buffer_adr++; // Incr. Buffer address for the next byte
}

m_NumberOfBytesToSend--; // dec. counter of byte to send/receive
if(m_NumberOfBytesToSend < 1)
{
m_buffer_adr=NULL;
}
TWCR_ACK; // we still have to receive bytes
}
else
{
TWCR_NACK; // We have a Problem. All was send before
}
}
break;

//Slave transmitter ================================================== ==========================

case TW_ST_SLA_ACK: //0xA8 Slave addressed in read mode
//no break, the rest of the code will also execute

case TW_ST_DATA_ACK: //0xB8 Slave Transmitter, Request of data

// Transmitting variables to the Master system (reading)

if(m_buffer_adr != NULL) // Buffer set up ?
{
if(m_NumberOfBytesToSend > 0) // do we have to send bytes still
{
TWDR = *m_buffer_adr; // send the data byte
m_buffer_adr++; // get the next byte of the buffer
m_NumberOfBytesToSend--; // dec. counter of byte to send

if(m_NumberOfBytesToSend > 0) // are we finished to send
{
TWCR_ACK; // we still have to receive bytes
}
else
{
m_buffer_adr=NULL;
TWCR_NACK; // we have all bytes send
}
}
else
{
TWCR_NACK; // we have all bytes send
}
}
else
{
TWCR_NACK;
}
break;

// case TW_ST_DATA_NACK: // 0xC0 No more data requested
// case TW_SR_DATA_NACK: // 0x88
// case TW_ST_LAST_DATA: // 0xC8 Last data byte in TWDR has ben transmitted (TWEA = “0”); ACK has been received
default:
TWCR_RESET;
break;
break;
}
}


Hat jemand eine Idee, welchen Fehler ich hier gemacht habe. Laut Tabelle sollte der atMega mit dieser taktfreq. doch einen 100k oder sogar 400kBus handhaben können oder ?

Grundsätzlich entspricht dieser Code der RN.Wissen DB (http://www.rn-wissen.de/index.php/TWI_Slave_mit_avr-gcc)

Edit:
So arbeitet der Code jetzt. Was lernen wir daraus. Niemal einen laufenden Code versuchen zu optimieren, wenn man kurz danach für 3 Wochen in Urlaub und danach auf Dienstreise fährt.

Edit 2:
Nun ja, weiss ich ich auch noch einen weiteren Grund für meine Probleme. Der neue Kernel benutzt ein Speed von 250kBaud. Da komme ich schon an die Grenzen von meinem Amtel atmega32. Evtl. werde ich dann doch den Port auf dem atmega644 vorziehen, da dieser nochmal was schneller ist (20Mhz). Nur das ganze Programm wieder anpassen...


Gruss R.

Ritchie
17.07.2012, 20:37
Hallo Zusammen,

ich prüfe gerade meine Routine nochmals anhand des Datenprotokoll aus dem I2C-bus specification.

Die Abfrage der Daten (Daten lesen vom atmega) geht mittels folgendem Telegram:

fett = Slave Antwort

<StartCond.><SlaveAdresse/ & Write Bit><Ack><Kommando><Ack>
<Repeated Start><SlaveAdresse + Read bit><Ack>
<Data><Ack><Data>....<Last Data><Nack><StopCond.>

Also jeweils folgende Case Zweige der Interruptroutine:

<StartCond.> = Event: TW_START
<SlaveAdresse + Write Bit>= Event: TW_SR_SLA_ACK
<Kommando> = Event: TW_SR_DATA_ACK
<Repeated Start> = Event: TW_REP_START
<SlaveAdresse + Read Bit>= Event: TW_ST_SLA_ACK
<StopCond.> = Event: TW_SR_STOP

Sehe ich das so richtig, da anhand dieses Ablauf die einzelen Routinen zu prüfen sind.

Gruss R.