- MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad         
Ergebnis 1 bis 2 von 2

Thema: Problem mit I2C Bus Slave via Interrupt ...

  1. #1
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    07.11.2004
    Beiträge
    332

    Problem mit I2C Bus Slave via Interrupt ...

    Anzeige

    LiFePo4 Akku selber bauen - Video
    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 !

    Code:
    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_ActualOrientationEnCoder);
                                    break;
                            case    'Y':                            // Actual Angle by the Gyro module (Angle change per second)
                                    m_buffer_adr = (char*) &m_ActualOrientationGyro;
                                    m_NumberOfBytesToSend=sizeof(m_ActualOrientationGyro);
                                    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_Left);
                                    break;
                            case    '2':                            //
                                    m_buffer_adr = (char*) &m_MotorTemperatur_Right;    
                                    m_NumberOfBytesToSend=sizeof(m_MotorTemperatur_Right);
                                    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.
    Geändert von Ritchie (20.07.2012 um 18:50 Uhr) Grund: Code fehlerfrei gemacht
    Kaum macht man es richtig, schon funktioniert's ...

  2. #2
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    07.11.2004
    Beiträge
    332
    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.
    Geändert von Ritchie (17.07.2012 um 21:43 Uhr)
    Kaum macht man es richtig, schon funktioniert's ...

Ähnliche Themen

  1. Interrupt beim I2C Slave
    Von guenter1604 im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 3
    Letzter Beitrag: 07.12.2009, 19:59
  2. Interrupt bei TWI Slave (Atmega8)?
    Von ingo pirker im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 2
    Letzter Beitrag: 20.11.2009, 23:36
  3. I2C Slave Interrupt
    Von simple im Forum C - Programmierung (GCC u.a.)
    Antworten: 1
    Letzter Beitrag: 29.11.2006, 18:53
  4. SPI slave transmit problem
    Von tristate im Forum C - Programmierung (GCC u.a.)
    Antworten: 5
    Letzter Beitrag: 04.11.2005, 17:52
  5. Problem Atmega8 als I2C-Slave
    Von Robo2004 im Forum C - Programmierung (GCC u.a.)
    Antworten: 1
    Letzter Beitrag: 03.07.2005, 19:29

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Labornetzteil AliExpress