Hallo, ich bin gerade am Aufbau einer I2C-Verbindung zwischen einem AtTiny2313 und dem FoxBoard G20. Ich habe nun das Problem, dass ich den AtTiny nicht "finden" kann. Mit dem Befehl "i2cdetect -y 0" werden die I2C-Adressen von 00h bis 77h durchsucht, ob sich Geräte melden. Beim AtTiny wird aber nichts erkannt. Andere Bausteine funktionieren. Muss man beim AtTiny zuvor noch irgendwelche Register setzen (Umschaltung SPI/I2C) oder ähnliches? Die Pinbelgung: AtTiny - FoxBoard 10 GND - J6.40 GND 17 SDA - J6.32 SDA 19 SCL - J6.31 SCL 20 VCC - +5V Der Bus hat 2 Pullup-R mit 4,7kOhm auf 5V. Um Hilfe wäre ich sehr Dankbar.
Alex B. schrieb: > Muss man beim AtTiny zuvor noch irgendwelche Register setzen > (Umschaltung SPI/I2C) oder ähnliches? Du mußt vor allem erstmal ein Programm drauf flashen, was den Tiny zum I2C-Slave macht. Das Ding ist ein µC und wie jeder µC macht der ohne ein Programm erstmal garnix (jedenfalls nix sinnvolles).
Und außerdem: Bist du sicher, daß die I2C-Leitungen vom FoxBoard TTL-Level haben? Meistens hat dieser ARM-basierende Kram nur noch 3.3 V Gruss, Heinz
Danke. Ich dachte die Adresse sei von Anfang an ansprechbar. Die 5V Busspannung sind ein Fehler von mir. Müssen natürlich 3,3V sein.
Hi >Ich dachte die Adresse sei von Anfang an ansprechbar. Nö. Aber es gibt eine AppNote bei ATMEL: http://www.atmel.com/Images/doc2560.pdf Software: http://www.atmel.com/Images/AVR312.zip MfG Spess
Danke. Ich habs mittlerweile hinbekommen. Jedoch hab ich grad Verständnis Probleme. Ich schreibe vom FoxBoard zum Tiny mit dem Befehl:
1 | I2C_WriteToDevice(i2c_fd, 0x02, 0x00); |
wobei die Routine so aussieht:
1 | void I2C_WriteToDevice(int fd, int reg, int val) { |
2 | |
3 | char buf[2]; |
4 | buf[0] = reg; //Register |
5 | buf[1] = val; //Wert |
6 | if (write(fd, buf, 2) != 2) { |
7 | printf("Schreiben fehlgeschlagen...\n"); |
8 | return(0); |
9 | }
|
10 | }
|
Ich schreibe also den Wert 0x00 an das Register 0x02. Die Auswertung auf dem Tiny hat ergeben, dass wenn ich an Register 2 schreibe, ich auf "Wert == 2" abfragen muss, bei Register 1 auf "Wert == 1" usw., damit ich ein True erhalte. Ich kann jetzt aber nicht einfach auf irgendwelche Register schreiben. Daher die Frage auf welche kann ich? Die freien, auf dem Datenblatt mit Reserved gekenzeichneten? Passt das ganze so überhaupt wie ich das hier erkläre??? Kommt mir etwas komisch vor. Mfg Alex
Hallo, das Thema oben hat sich mittlerweile erledigt. Nun habe ich aber ein weiteres "Problem" bzw ein Verhalten, dass ich nicht verstehe. Zunächst mal der Code vom Master:
1 | i2c_buffer[0] = 3; |
2 | i2c_buffer[1] = 6; |
3 | i2c_buffer[2] = 40; |
4 | i2c_buffer[3] = 50; |
5 | i2c_buffer[4] = 152; |
6 | I2C_WriteToDevice(); |
7 | |
8 | //------------ |
9 | |
10 | void I2C_WriteToDevice(void) { |
11 | |
12 | if (write(i2c_fd, i2c_buffer, sizeof(i2c_buffer)) != sizeof(i2c_buffer)) { |
13 | printf("Schreiben fehlgeschlagen...\n"); |
14 | return(0); |
15 | } |
16 | } |
ich möchte also die oben geschriebenen Werte dem Slave übergeben (ATTiny2313). Der hat folgenden Code:
1 | /****************************************************/ |
2 | /* The USI as Slave */ |
3 | /* Author: Axel Gartner */ |
4 | /****************************************************/ |
5 | #define F_CPU 1000000UL |
6 | |
7 | #include <util/delay.h> |
8 | #include <avr/io.h> |
9 | #include <avr/interrupt.h> |
10 | |
11 | #define USI_DATA USIDR |
12 | #define USI_STATUS USISR |
13 | #define USI_CONTROL USICR |
14 | #define USI_ADDRESS 0x20 |
15 | |
16 | #define NONE 0 |
17 | #define ACK_PR_RX 1 |
18 | #define BYTE_RX 2 |
19 | #define ACK_PR_TX 3 |
20 | #define PR_ACK_TX 4 |
21 | #define BYTE_TX 5 |
22 | |
23 | // Device dependant defines |
24 | /*#if defined(__at90tiny26__) | defined(__attiny26__) |
25 | #define DDR_USI DDRB |
26 | #define PORT_USI PORTB |
27 | #define PIN_USI PINB |
28 | #define PORT_USI_SDA PORTB0 |
29 | #define PORT_USI_SCL PORTB2 |
30 | #endif*/ |
31 | |
32 | #if defined(__AVR_ATtiny2313A__) |
33 | #define DDR_USI DDRB |
34 | #define PORT_USI PORTB |
35 | #define PIN_USI PINB |
36 | #define PORT_USI_SDA PORTB5 |
37 | #define PORT_USI_SCL PORTB7 |
38 | #endif |
39 | |
40 | volatile uint8_t COMM_STATUS = NONE; |
41 | |
42 | |
43 | //uint8_t tmp1[2]; |
44 | |
45 | |
46 | void USI_init(void) { |
47 | // 2-wire mode; Hold SCL on start and overflow; ext. clock |
48 | USI_CONTROL |= (1<<USIWM1) | (1<<USICS1); |
49 | USI_STATUS = 0xf0; // write 1 to clear flags, clear counter |
50 | DDR_USI &= ~(1<<PORT_USI_SDA); |
51 | PORT_USI &= ~(1<<PORT_USI_SDA); |
52 | DDR_USI |= (1<<PORT_USI_SCL); |
53 | PORT_USI |= (1<<PORT_USI_SCL); |
54 | // startcondition interrupt enable |
55 | USI_CONTROL |= (1<<USISIE); |
56 | } |
57 | |
58 | int main(void) { |
59 | |
60 | USI_init(); |
61 | sei(); |
62 | |
63 | for(;;) { |
64 | } |
65 | |
66 | } |
67 | |
68 | SIGNAL(USI_START_vect ) { |
69 | uint8_t tmpUSI_STATUS; |
70 | tmpUSI_STATUS = USI_STATUS; |
71 | COMM_STATUS = NONE; |
72 | // Wait for SCL to go low to ensure the "Start Condition" has completed. |
73 | // otherwise the counter will count the transition |
74 | while ( (PIN_USI & (1<<PORT_USI_SCL)) ); |
75 | USI_STATUS = 0xf0; // write 1 to clear flags; clear counter |
76 | // enable USI interrupt on overflow; SCL goes low on overflow |
77 | USI_CONTROL |= (1<<USIOIE) | (1<<USIWM0); |
78 | } |
79 | |
80 | SIGNAL(USI_OVERFLOW_vect ) { |
81 | uint8_t BUF_USI_DATA = USI_DATA; |
82 | |
83 | switch(COMM_STATUS) { |
84 | case NONE: |
85 | if (((BUF_USI_DATA & 0xfe) >> 1) != USI_ADDRESS) { // if not receiving my address |
86 | // disable USI interrupt on overflow; disable SCL low on overflow |
87 | USI_CONTROL &= ~((1<<USIOIE) | (1<<USIWM0)); |
88 | } |
89 | else { // else address is mine |
90 | DDR_USI |= (1<<PORT_USI_SDA); |
91 | USI_STATUS = 0x0e; // reload counter for ACK, (SCL) high and back low |
92 | if (BUF_USI_DATA & 0x01) COMM_STATUS = ACK_PR_TX; else COMM_STATUS = ACK_PR_RX; |
93 | } |
94 | break; |
95 | |
96 | case ACK_PR_RX: |
97 | DDR_USI &= ~(1<<PORT_USI_SDA); |
98 | COMM_STATUS = BYTE_RX; |
99 | break; |
100 | |
101 | case BYTE_RX: |
102 | /* Save received byte here! ... = USI_DATA */ |
103 | |
104 | if (USI_DATA == 6) { |
105 | PORTD |= (1<<PD3); |
106 | _delay_ms(1000); |
107 | PORTD &= ~(1<<PD3); |
108 | } |
109 | |
110 | DDR_USI |= (1<<PORT_USI_SDA); |
111 | USI_STATUS = 0x0e; // reload counter for ACK, (SCL) high and back low |
112 | COMM_STATUS = ACK_PR_RX; |
113 | break; |
114 | |
115 | case ACK_PR_TX: |
116 | /* Put first byte to transmit in buffer here! USI_DATA = ... */ |
117 | |
118 | PORT_USI |= (1<<PORT_USI_SDA); // transparent for shifting data out |
119 | COMM_STATUS = BYTE_TX; |
120 | break; |
121 | |
122 | case PR_ACK_TX: |
123 | if(BUF_USI_DATA & 0x01) { |
124 | COMM_STATUS = NONE; // no ACK from master --> no more bytes to send |
125 | } |
126 | else { |
127 | /* Put next byte to transmit in buffer here! USI_DATA = ... */ |
128 | PORT_USI |= (1<<PORT_USI_SDA); // transparent for shifting data out |
129 | DDR_USI |= (1<<PORT_USI_SDA); |
130 | COMM_STATUS = BYTE_TX; |
131 | } |
132 | break; |
133 | |
134 | case BYTE_TX: |
135 | DDR_USI &= ~(1<<PORT_USI_SDA); |
136 | PORT_USI &= ~(1<<PORT_USI_SDA); |
137 | USI_STATUS = 0x0e; // reload counter for ACK, (SCL) high and back low |
138 | COMM_STATUS = PR_ACK_TX; |
139 | break; |
140 | } |
141 | USI_STATUS |= (1<<USIOIF); // clear overflowinterruptflag, this also releases SCL |
142 | } |
Wenn ich nun das Register "USI_DATA" abfrage, sind darin alle gesendeten Werte vom Master enthalten. Die If-Abfrage trifft also bei 3, 6 ... zu. USI_DATA ist ja aber nur ein 1 Byte Register. Wie können darin dann 5 Bytes enthalten sein? Und wie bekomme ich es hin, die Bytes einzel auszulesen?
Alex B. schrieb: > /* Save received byte here! ... = USI_DATA */ Indem du an der Stelle, genau wie es im Kommentar steht, die empfangenen Bytes speicherst. Dazu machst du dir ein Array und merkst dir die aktuelle Schreibeposition. Dahin kommt dann dein Byte. [c] empfangsbuffer[akutelle_position] = USI_DATA; [c] Noch ein bisschen Verwaltungskram drumrum und eine Erkennung dafür, wann ein Datenpaket komplett ist, und du bist fertig.
Hi, das ist klar.
1 | for (uint8_t i=0; i<5; i++) { |
2 | tmp1[i] = USI_DATA; |
3 | } |
Aber so wird in jedes tmp1-Byte der gesamt Inhalt geschrieben. Wie es dann aber weiter geht, kapier ich nicht. Hab mir das DB auch schon durchgelesen, blicks aber nicht. Wird nach jedem Byte ein Interrupt ausgelöst, oder wenn alle Bytes angekommen sind? Wann muss ich in tmp das nächste Byte angeben?
:
Bearbeitet durch User
Ich habe mit dem I²C des ATTiny2313 noch nicht gearbeitet, aber normalerweise wird für jedes Byte ein Interrupt erzeugt. Daher ist eine Schleife an der Stelle vollkommen ungeeignet. Du schreibst jeden Interrupt-Aufruf ein Byte in dein Array und wertest es aus, wenn du deine 5 Bytes hast.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.