- LiFePO4 Speicher Test         
Ergebnis 1 bis 9 von 9

Thema: I²C Usi mit ATTiny26

  1. #1
    Benutzer Stammmitglied
    Registriert seit
    28.09.2006
    Beiträge
    67

    I²C Usi mit ATTiny26

    Anzeige

    Praxistest und DIY Projekte
    Hallo Leute

    Ich hab hier eine fertige Software von mikrocontroller.net für die USI vom ATTiny26 für einen I²C Slave.

    http://www.mikrocontroller.net/topic/38917#287918

    Danke an dieser Stelle, falls er es liest

    Der Slave scheint einwandfrei zu funktionieren wenn ich nur 1nen Attiny am Bus habe.
    Gebe ich aber einen zweiten Tiny hinzu Addressen (0xA0, 0xB0) hab ich das Problem, das mir auf eine Anfrage auf Addresse 0xA0, BEIDE antworten...
    Genauso auch umgekehrt, er ignoriert also die Addresse...


    Code:
    
    #ifndef _I2C_SLAVE_C_
    #define _I2C_SLAVE_C_
    
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include "i2c_slave.h"
    
    
    #define USI_DATA   			USIDR
    #define USI_STATUS  		USISR
    #define USI_CONTROL 		USICR
    
    //Standart Device Address
    
    
    #define NONE				0
    #define ACK_PR_RX			1
    #define BYTE_RX				2
    #define ACK_PR_TX			3
    #define PR_ACK_TX			4
    #define BYTE_TX				5
    
    // Device dependant defines
    
    #define DDR_USI             DDRB
    #define PORT_USI            PORTB
    #define PIN_USI             PINB
    #define PORT_USI_SDA        PORTB0
    #define PORT_USI_SCL        PORTB2
    
    #define NONE 				0
    
    
    volatile unsigned char USI_address = NONE;
    volatile uint8_t COMM_STATUS = NONE;
    volatile unsigned char send_usi = NONE;
    
    
    void USI_set(unsigned char data)
    {
    send_usi = data ;
    }
    
    void USI_init(unsigned char address) {
    	// Set the Device Address for the Slave Address+1 = Address with Reading 
    	USI_address = address;
    	// 2-wire mode; Hold SCL on start and overflow; ext. clock
    	USI_CONTROL |= (1<<USIWM1) | (1<<USICS1);
    	USI_STATUS = 0xf0;  // write 1 to clear flags, clear counter
    	DDR_USI  &= ~(1<<PORT_USI_SDA);
    	PORT_USI &= ~(1<<PORT_USI_SDA);
    	DDR_USI  |=  (1<<PORT_USI_SCL);
    	PORT_USI |=  (1<<PORT_USI_SCL);
    	// startcondition interrupt enable
    	USI_CONTROL |= (1<<USISIE);
    }
    
    
    
    ISR(USI_STRT_vect) {
        uint8_t tmpUSI_STATUS;
    	tmpUSI_STATUS = USI_STATUS;
    	COMM_STATUS = NONE;
    	// Wait for SCL to go low to ensure the "Start Condition" has completed.
    	// otherwise the counter will count the transition
    	while ( (PIN_USI & (1<<PORT_USI_SCL)) );
    	USI_STATUS = 0xf0; // write 1 to clear flags; clear counter
    	// enable USI interrupt on overflow; SCL goes low on overflow
    	USI_CONTROL |= (1<<USIOIE) | (1<<USIWM0);
    }
    
    
    ISR(USI_OVF_vect) {
    
        uint8_t BUF_USI_DATA = USI_DATA;
    	switch(COMM_STATUS) {
    	case NONE:
    		if (((BUF_USI_DATA & 0xfe)) != USI_address & 0xfe) {	// if not receiving my address
    			// disable USI interrupt on overflow; disable SCL low on overflow
    			USI_CONTROL &= ~((1<<USIOIE) | (1<<USIWM0));
    		}
    		else { // else address is mine
    			DDR_USI  |=  (1<<PORT_USI_SDA);
    			USI_STATUS = 0x0e;	// reload counter for ACK, (SCL) high and back low
    			if (BUF_USI_DATA & 0x01) COMM_STATUS = ACK_PR_TX; else COMM_STATUS = ACK_PR_RX;
    		}
    		break;
    	case ACK_PR_RX:
    		DDR_USI  &= ~(1<<PORT_USI_SDA);
    		COMM_STATUS = BYTE_RX;
    		break;
    	case BYTE_RX:
    		/* Save received byte here! ... = USI_DATA*/
    		DDR_USI  |=  (1<<PORT_USI_SDA);
    		USI_STATUS = 0x0e;	// reload counter for ACK, (SCL) high and back low
    		COMM_STATUS = ACK_PR_RX;
    		break;
    	case ACK_PR_TX:
    		/* Put first byte to transmit in buffer here! USI_DATA = ... */
    		USI_DATA = send_usi;
    		PORT_USI |=  (1<<PORT_USI_SDA); // transparent for shifting data out
    		COMM_STATUS = BYTE_TX;
    		break;
    	case PR_ACK_TX:
    		if(BUF_USI_DATA & 0x01) {
    			COMM_STATUS = NONE; // no ACK from master --> no more bytes to send
    		}
    		else {
    			/* Put next byte to transmit in buffer here! USI_DATA = ... */
    			PORT_USI |=  (1<<PORT_USI_SDA); // transparent for shifting data out
    			DDR_USI  |=  (1<<PORT_USI_SDA);
    			COMM_STATUS = BYTE_TX;
    		}
    		break;
    	case BYTE_TX:
    		DDR_USI  &= ~(1<<PORT_USI_SDA);
    		PORT_USI &= ~(1<<PORT_USI_SDA);
    		USI_STATUS = 0x0e;	// reload counter for ACK, (SCL) high and back low
    		COMM_STATUS = PR_ACK_TX;
    		break;
    	}
    	USI_STATUS |= (1<<USIOIF); // clear overflowinterruptflag, this also releases SCL
    }
    
    #endif
    Bis auf ein paar Kleinigkeiten wurde am Code eigentlich nichts geändert. Sieht wer den Fehler?

    mfg

  2. #2
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    22.05.2005
    Ort
    12°29´ O, 48°38´ N
    Beiträge
    2.731
    Hallo,

    gröbere Schnitzer sind mir jetzt nicht aufgefallen,
    ausser das #define NONE zweimal vorkommt

    Evtl. machst du mal das & 0xfe beim vergleich von USI_address weg,
    in der Zeile nach case NONE:

  3. #3
    Benutzer Stammmitglied
    Registriert seit
    28.09.2006
    Beiträge
    67
    Kann ich nicht, das ist die Bitmaske um das letzte Bit wegzubekommen, das bleibt ja frei um 0(schreiben) und 1(lesen) zur Verfügung zu haben

  4. #4
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    22.05.2005
    Ort
    12°29´ O, 48°38´ N
    Beiträge
    2.731
    Wenn du das bit vorher nicht gesetzt hast, muss Du es hier nicht wieder wegmaskieren,
    probier es mal aus.

    Das ist die einzige Stelle an der die Slaveadresse überprüft wird, und das ist auch die Stelle, die Du u.a. umgebaut hast !

  5. #5
    Benutzer Stammmitglied
    Registriert seit
    28.09.2006
    Beiträge
    67
    naja aber wenn ich die addresse 1111 0000 habe und ich aber 1111 0001
    reinbekomme, muss ich es abfangen...
    Und jo das is ein Teil den ich ändern musste, wegen Verständnissproblemen und weils auf die originale Weise nicht funktioniert hat..
    Testen kann ichs aber leider erst morgen
    mfg

  6. #6
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    22.05.2005
    Ort
    12°29´ O, 48°38´ N
    Beiträge
    2.731
    Aber Du bist doch der, der das programmiert, und wenn Du da keine solche Adresse im Quellcode reinschreibst, musst du das dort nicht wieder rausfiltern.

    Das erste & 0xfe muss natürlich stehen bleiben, weil das die Adresse ist, die der Master gesendet hat.

  7. #7
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Mal ganz vorsichtig gefragt... bist du sicher, daß nicht vielleicht die gleiche Binärdatei auf beiden Slaves landet?
    Disclaimer: none. Sue me.

  8. #8
    Benutzer Stammmitglied
    Registriert seit
    28.09.2006
    Beiträge
    67
    Jo, die Idee kam mir auch schon, nur hab ichs mittlerweile schon beschriftet und mehrfach neu beschrieben..
    Das Problem ist ja auch wenn ich zB ox20 als Addresse in den Slave schreibe, reagiert er ja auch auf 0xA0, auch wenn nur ein Slave vorhanden ist.

  9. #9
    Benutzer Stammmitglied
    Registriert seit
    28.09.2006
    Beiträge
    67
    So Problem gelöst weis aber ned wieso
    Ich vergebe die Addresse jetzt DIREKT in der Interruptroutine und nicht wie vorher über eine Funktion mit eine Buffervariable..ich weiß nicht wieso.. aber es geht
    Danke für die Tips

Berechtigungen

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

LiTime Speicher und Akkus