Hallo Leute, ich habe einen Atmega 644PA, und den BLMC von Ulrich Radig. Der Atmega644 sendet 2Bytes und danach meldet der TWI 0x38, also Arbitration lost in SLA+W or data bytes. Hat jemand ne Ahnung wie das kommt? Danke im Voraus.
>Der Atmega644 sendet 2Bytes und danach meldet der TWI 0x38, also >Arbitration lost in SLA+W or data bytes. Hat jemand ne Ahnung wie das >kommt? Da zieht irgendwer an den I2C Leitungen. Clockstretching vom BLMC? Keine Ahnung wie der arbeitet.
Hallo ihr beiden, was meinst du mit Clockstretching. Ja SDA und SCL haben 10kOhm Gruß Sven
>was meinst du mit Clockstretching.
Ein uC I2C Slave ist häufig zu langsam um sofort zu antworten.
Um sich ein bisschen Zeit zu verschaffen zieht er einfach
die Clockleitung runter. Wenn er bereit ist lässt er sie wieder los.
Das sollte der I2C Master abkönnen.
Was genau bei dir abgeht solltest du mal mit einem Logicanalyzer
oder Speicherosci ansehen. So ist das nur willenloses rumgerate.
Dein Programm in einer Minimalform zeigen wo der Fehler auftritt
könnte auch ungemein hilfreich sein.
Da wo "hier" steht bleibt er beim nächsten Senden stecken und das printf liefert vorher halt 0x38. Zwischen jedem Senden wird 1Sek. gewartet.
1 | uint8_t TWIM_Write (uint8_t byte) |
2 | {
|
3 | uint8_t twst; |
4 | /*
|
5 | ** Send data to the previously addressed device
|
6 | */
|
7 | TWDR = byte; |
8 | TWCR = (1<<TWINT)|(1<<TWEN); |
9 | /*
|
10 | ** Wait until transmission completed
|
11 | */
|
12 | while (!(TWCR & (1<<TWINT)));/*hier*/ |
13 | /*
|
14 | ** Check value of TWI Status Register. Mask prescaler bits
|
15 | */
|
16 | twst = TWSR & 0xF8; |
17 | printf("0x%02x\n",twst); |
18 | if (twst != TWI_MTX_DATA_ACK) return 1; |
19 | |
20 | return 0; |
21 | }
|
Wie wäre es mit einem vollständigen Programm? Möglicherweise gibt dir der BLMC kein ACK weil die I2C Adresse schon falsch gesendet wurde.
Immerhin gibt es den Status 0x38, und bestimmt auch einen Grund und eine Beschreibung dazu.
Unten habe ich mal die main.c und die TWI_Master.c main.c
1 | /*******************************************************
|
2 | Author: Manfred Langemann
|
3 | mailto: Manfred.Langemann ät t-online.de
|
4 | Begin of project: 04.01.2008
|
5 | Latest version generated: 04.01.2008
|
6 | Filename: Main.c
|
7 | Description: Main routine for testing
|
8 | TWI_Master_main.c
|
9 | ********************************************************/
|
10 | #include <stdio.h> |
11 | #include <avr/interrupt.h> |
12 | |
13 | #include "General.h" |
14 | #include "RS232.h" |
15 | #include "Delay.h" |
16 | #include "TWI_Master.h" |
17 | /*
|
18 | ** This main programm demonstrates how to use the
|
19 | ** implemented TWI master functions. These are:
|
20 | ** TWIM_Init
|
21 | ** TWIM_ReadAck
|
22 | ** TWIM_ReadNack
|
23 | ** TWIM_Write
|
24 | ** TWIM_Stop
|
25 | **
|
26 | ** For testing this program, use the program
|
27 | ** TWI_Slave_main.c in the slave uC and connect the
|
28 | ** two TWI lines properly (don't forget to also
|
29 | ** connect GND between Master and Slave!)
|
30 | **
|
31 | ** Used uC for Master is ATMega32
|
32 | */
|
33 | int main (void) |
34 | {
|
35 | uint8_t i; |
36 | uint8_t j=0; |
37 | //uint8_t Data[8];
|
38 | uint8_t SlaveAddress = 0; |
39 | /*
|
40 | ** Clear any interrupt
|
41 | */
|
42 | cli (); |
43 | /*
|
44 | ** Wait 1 second for POR
|
45 | */
|
46 | Delay_ms (1000); |
47 | /*
|
48 | ** Initiate RS232
|
49 | */
|
50 | RS232_Init (); |
51 | printf ("Hello world...\n"); |
52 | /*
|
53 | ** Initiate TWI Master Interface with bitrate of 100000 Hz
|
54 | */
|
55 | if (!TWIM_Init (100000)) |
56 | {
|
57 | printf ("Error in initiating TWI interface\n"); |
58 | while (1); |
59 | }
|
60 | /*
|
61 | ** Endless loop
|
62 | */
|
63 | while (1) |
64 | {
|
65 | /*
|
66 | ** Write byte(s) to the slave.
|
67 | ** It is implicitely assumed, that the slave will
|
68 | ** accepts 8 bytes
|
69 | */
|
70 | if (!TWIM_Start (SlaveAddress, TWIM_WRITE)) |
71 | {
|
72 | TWIM_Stop (); |
73 | printf ("Could not start TWI Bus for WRITE\n"); |
74 | }
|
75 | else
|
76 | {
|
77 | TWIM_Write (j++); |
78 | printf ("Byte sent: %d\n", j); |
79 | TWIM_Stop (); |
80 | Delay_ms (1000); |
81 | }
|
82 | }
|
83 | |
84 | return 0; |
85 | }
|
TWI-Master
1 | #include <stdio.h> |
2 | #include <avr/interrupt.h> |
3 | |
4 | #include "General.h" |
5 | #include "TWI_Master.h" |
6 | |
7 | /****************************************************************************
|
8 | TWI State codes
|
9 | ****************************************************************************/
|
10 | // General TWI Master staus codes
|
11 | #define TWI_START 0x08 // START has been transmitted
|
12 | #define TWI_REP_START 0x10 // Repeated START has been transmitted
|
13 | #define TWI_ARB_LOST 0x38 // Arbitration lost
|
14 | |
15 | // TWI Master Transmitter staus codes
|
16 | #define TWI_MTX_ADR_ACK 0x18 // SLA+W has been tramsmitted and ACK received
|
17 | #define TWI_MTX_ADR_NACK 0x20 // SLA+W has been tramsmitted and NACK received
|
18 | #define TWI_MTX_DATA_ACK 0x28 // Data byte has been tramsmitted and ACK received
|
19 | #define TWI_MTX_DATA_NACK 0x30 // Data byte has been tramsmitted and NACK received
|
20 | |
21 | // TWI Master Receiver staus codes
|
22 | #define TWI_MRX_ADR_ACK 0x40 // SLA+R has been tramsmitted and ACK received
|
23 | #define TWI_MRX_ADR_NACK 0x48 // SLA+R has been tramsmitted and NACK received
|
24 | #define TWI_MRX_DATA_ACK 0x50 // Data byte has been received and ACK tramsmitted
|
25 | #define TWI_MRX_DATA_NACK 0x58 // Data byte has been received and NACK tramsmitted
|
26 | |
27 | // TWI Slave Transmitter staus codes
|
28 | #define TWI_STX_ADR_ACK 0xA8 // Own SLA+R has been received; ACK has been returned
|
29 | #define TWI_STX_ADR_ACK_M_ARB_LOST 0xB0 // Arbitration lost in SLA+R/W as Master; own SLA+R has been received; ACK has been returned
|
30 | #define TWI_STX_DATA_ACK 0xB8 // Data byte in TWDR has been transmitted; ACK has been received
|
31 | #define TWI_STX_DATA_NACK 0xC0 // Data byte in TWDR has been transmitted; NOT ACK has been received
|
32 | #define TWI_STX_DATA_ACK_LAST_BYTE 0xC8 // Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received
|
33 | |
34 | // TWI Slave Receiver staus codes
|
35 | #define TWI_SRX_ADR_ACK 0x60 // Own SLA+W has been received ACK has been returned
|
36 | #define TWI_SRX_ADR_ACK_M_ARB_LOST 0x68 // Arbitration lost in SLA+R/W as Master; own SLA+W has been received; ACK has been returned
|
37 | #define TWI_SRX_GEN_ACK 0x70 // General call address has been received; ACK has been returned
|
38 | #define TWI_SRX_GEN_ACK_M_ARB_LOST 0x78 // Arbitration lost in SLA+R/W as Master; General call address has been received; ACK has been returned
|
39 | #define TWI_SRX_ADR_DATA_ACK 0x80 // Previously addressed with own SLA+W; data has been received; ACK has been returned
|
40 | #define TWI_SRX_ADR_DATA_NACK 0x88 // Previously addressed with own SLA+W; data has been received; NOT ACK has been returned
|
41 | #define TWI_SRX_GEN_DATA_ACK 0x90 // Previously addressed with general call; data has been received; ACK has been returned
|
42 | #define TWI_SRX_GEN_DATA_NACK 0x98 // Previously addressed with general call; data has been received; NOT ACK has been returned
|
43 | #define TWI_SRX_STOP_RESTART 0xA0 // A STOP condition or repeated START condition has been received while still addressed as Slave
|
44 | |
45 | // TWI Miscellaneous status codes
|
46 | #define TWI_NO_STATE 0xF8 // No relevant state information available; TWINT = “0”
|
47 | #define TWI_BUS_ERROR 0x00 // Bus error due to an illegal START or STOP condition
|
48 | |
49 | /*******************************************************
|
50 | Public Function: TWIM_Init
|
51 | |
52 | Purpose: Initialise the TWI Master Interface
|
53 | |
54 | Input Parameter:
|
55 | - uint16_t TWI_Bitrate (Hz)
|
56 | |
57 | Return Value: uint8_t
|
58 | - FALSE: Bitrate too high
|
59 | - TRUE: Bitrate OK
|
60 | |
61 | *******************************************************/
|
62 | uint8_t TWIM_Init (uint32_t TWI_Bitrate) |
63 | {
|
64 | /*
|
65 | ** Set TWI bitrate
|
66 | ** If bitrate is too high, then error return
|
67 | */
|
68 | TWBR = ((F_CPU/TWI_Bitrate)-16)/2; |
69 | if (TWBR < 11) return FALSE; |
70 | |
71 | return TRUE; |
72 | }
|
73 | /*******************************************************
|
74 | Public Function: TWIM_Start
|
75 | |
76 | Purpose: Start the TWI Master Interface
|
77 | |
78 | Input Parameter:
|
79 | - uint8_t Device address
|
80 | - uint8_t Type of required Operation:
|
81 | TWIM_READ: Read data from the slave
|
82 | TWIM_WRITE: Write data to the slave
|
83 | |
84 | Return Value: uint8_t
|
85 | - TRUE: OK, TWI Master accessible
|
86 | - FALSE: Error in starting TWI Master
|
87 | |
88 | *******************************************************/
|
89 | uint8_t TWIM_Start (uint8_t Address, uint8_t TWIM_Type) |
90 | {
|
91 | uint8_t twst; |
92 | /*
|
93 | ** Send START condition
|
94 | */
|
95 | TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); |
96 | /*
|
97 | ** Wait until transmission completed
|
98 | */
|
99 | while (!(TWCR & (1<<TWINT))); |
100 | /*
|
101 | ** Check value of TWI Status Register. Mask prescaler bits.
|
102 | */
|
103 | twst = TWSR & 0xF8; |
104 | printf("0x%02x\n",twst); |
105 | if ((twst != TWI_START) && (twst != TWI_REP_START)) return FALSE; |
106 | /*
|
107 | ** Send device address
|
108 | */
|
109 | TWDR = (Address<<1) + TWIM_Type; |
110 | TWCR = (1<<TWINT)|(1<<TWEN); |
111 | /*
|
112 | ** Wait until transmission completed and ACK/NACK has been received
|
113 | */
|
114 | while (!(TWCR & (1<<TWINT))); |
115 | /*
|
116 | ** Check value of TWI Status Register. Mask prescaler bits.
|
117 | */
|
118 | twst = TWSR & 0xF8; |
119 | printf("0x%02x\n",twst); |
120 | if ((twst != TWI_MTX_ADR_ACK) && (twst != TWI_MRX_ADR_ACK)) return FALSE; |
121 | |
122 | return TRUE; |
123 | }
|
124 | /*******************************************************
|
125 | Public Function: TWIM_Stop
|
126 | |
127 | Purpose: Stop the TWI Master
|
128 | |
129 | Input Parameter: None
|
130 | |
131 | Return Value: None
|
132 | |
133 | *******************************************************/
|
134 | void TWIM_Stop (void) |
135 | {
|
136 | /*
|
137 | ** Send stop condition
|
138 | */
|
139 | TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); |
140 | /*
|
141 | ** Wait until stop condition is executed and bus released
|
142 | */
|
143 | while (TWCR & (1<<TWINT)); |
144 | }
|
145 | /*******************************************************
|
146 | Public Function: TWIM_Write
|
147 | |
148 | Purpose: Write a byte to the slave
|
149 | |
150 | Input Parameter:
|
151 | - uint8_t Byte to be sent
|
152 | |
153 | Return Value: uint8_t
|
154 | - TRUE: OK, Byte sent
|
155 | - FALSE: Error in byte transmission
|
156 | |
157 | *******************************************************/
|
158 | uint8_t TWIM_Write (uint8_t byte) |
159 | {
|
160 | uint8_t twst; |
161 | /*
|
162 | ** Send data to the previously addressed device
|
163 | */
|
164 | TWDR = byte; |
165 | TWCR = (1<<TWINT)|(1<<TWEN); |
166 | /*
|
167 | ** Wait until transmission completed
|
168 | */
|
169 | while (!(TWCR & (1<<TWINT))); |
170 | /*
|
171 | ** Check value of TWI Status Register. Mask prescaler bits
|
172 | */
|
173 | twst = TWSR & 0xF8; |
174 | printf("0x%02x\n",twst); |
175 | if (twst != TWI_MTX_DATA_ACK) return 1; |
176 | |
177 | return 0; |
178 | }
|
179 | /*******************************************************
|
180 | Public Function: TWIM_ReadAck
|
181 | |
182 | Purpose: Read a byte from the slave and request next byte
|
183 | |
184 | Input Parameter: None
|
185 | |
186 | Return Value: uint8_t
|
187 | - uint8_t Read byte
|
188 | |
189 | *******************************************************/
|
190 | uint8_t TWIM_ReadAck (void) |
191 | {
|
192 | TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA); |
193 | while (!(TWCR & (1<<TWINT))); |
194 | |
195 | return TWDR; |
196 | }
|
197 | /*******************************************************
|
198 | Public Function: TWIM_ReadAck
|
199 | |
200 | Purpose: Read the last byte from the slave
|
201 | |
202 | Input Parameter: None
|
203 | |
204 | Return Value: uint8_t
|
205 | - uint8_t Read byte
|
206 | |
207 | *******************************************************/
|
208 | uint8_t TWIM_ReadNack (void) |
209 | {
|
210 | TWCR = (1<<TWINT)|(1<<TWEN); |
211 | while(!(TWCR & (1<<TWINT))); |
212 | |
213 | return TWDR; |
214 | }
|
>auch schon mal eine andere Slaveadresse probiert? > uint8_t SlaveAddress = 0; 0 ist sicher nicht richtig;)
Wenn ich versuche die adresse 0x0C zu nehmen bekomme ich "Could not start TWI Bus for WRITE". Also bleibe ich schon beim Starten hängen. Hat der Atmega88 vom BLMC vllt. nen CKDIV8 oder etwas ähnliches was den Takt ändert? Oder gibt es noch etwas was ich bei den Fuse-Bits ändern muss außer Externer Quarz also... Full swing crystal oscillator?
>holger schrieb: >> 0 ist sicher nicht richtig;) > >0 spricht alle I2C-Teilnehmer an. Du willst aber nur einen. Wenn 0x0C nicht geht versuch 0x06.
holger schrieb: > Du willst aber nur einen. Im Grunde ist erstmal egal ob nur Einer oder Mehrere. Auch 0x06 bringt kein start erfolg.
>> Du willst aber nur einen. > >Im Grunde ist erstmal egal ob nur Einer oder Mehrere. Nein, ist es nicht. >Welche adressen wurden vergeben? Das ist vermutlich das Problem.
Sven Müller schrieb: > 0 spricht alle I2C-Teilnehmer an. Da gibt es einen broad cast? Weiss jemand mal ne gute Beschreibung über das I2C Protokoll?
So sehe ich das auch. Jeder Slave im Bus braucht eine eigene Adresse (gerade Adresse).
In der BLMC Software ist 0x0C eingestellt und auf die adresse 0 antwortet er ja 2mal mit einem ACK und danach nicht mehr.
I2C Neuling schrieb: > Da gibt es einen broad cast? Ja der I2C hat einen broadcast. @Ulrich Radig Hast du Zeit das wir vllt. mal miteinander Sprechen können?
>In der BLMC Software ist 0x0C eingestellt und auf die adresse 0 >antwortet er ja 2mal mit einem ACK und danach nicht mehr. Auf die antwortet er aber nicht. Auf die um 1 Bit nach rechts geschobene Adresse auch nicht. Dein Programm schiebt die Adresse ja um eine Stelle nach links. Hast du das Programm mit der neuen Adresse überhaupt compiliert? Was ist wenn du 0x70 oder 0x38 nimmst?
Also ist am I2C jetzt nur ein Teilnehmer mit der Adresse 0x0C? Alle anderen Slaves brauchen eine andere Adresse. Dann in der Software Slave Adresse 0x0C einstellen.
Ulrich Radig schrieb: > Also ist am I2C jetzt nur ein Teilnehmer mit der Adresse 0x0C? Ja am I2C hängt nur ein Teilnehmer mit der Adresse 0x0C. holger schrieb: > Hast du das Programm mit der neuen Adresse überhaupt compiliert? Ja habe ich :)
Was ist mit dem Rest meiner Frage?
>Was ist wenn du 0x70 oder 0x38 nimmst?
Deine I2C Adresse ist falsch. Das ist Fakt. Vergiss den Broadcast.
Also wenn du 0x0C in der Software vom BLMC eingestellt hast versuche mal 0x0C oder 0x0D!!!!!
Ulrich Radig schrieb: > In der Software habe ich aber 0x70 verwendet!! Die Adresse habe ich angepasst. holger schrieb: > Was ist wenn du 0x70 oder 0x38 nimmst? Geht auch beides nicht. holger schrieb: > Das ist Fakt. Vergiss den Broadcast. Warum gibt es denn nach vielen Dokus einen Broadcast.
Wenn ich das genau in Erinnerung habe ist 0x0C dann die Leseadresse und 0x0D die Schreibadresse.
Ulrich Radig schrieb: > Wenn ich das genau in Erinnerung habe ist 0x0C dann die Leseadresse und > 0x0D die Schreibadresse. Die Software hängt das R/W Bit selber an.
Also so sieht mein Testprogramm für 4 Motoren auf die Schnelle aus.
1 | #include <avr/interrupt.h> |
2 | #include <avr/io.h> |
3 | #include <util/twi.h> |
4 | |
5 | //Motoradresse
|
6 | #define MOTOR_ADR 0x70
|
7 | |
8 | |
9 | //############################################################################
|
10 | //Hauptprogramm
|
11 | int main (void) |
12 | //############################################################################
|
13 | {
|
14 | unsigned char pwm = 10; |
15 | //Watchdog off
|
16 | asm("wdr"); |
17 | MCUSR &= ~(1<<WDRF); |
18 | //Write logical one to WDCE and WDE
|
19 | WDTCSR |= (1<<WDCE) | (1<<WDE); |
20 | //Turn off WDT
|
21 | WDTCSR = 0x00; |
22 | |
23 | TWSR = 0; |
24 | TWBR = ((12000000/200000)-16)/2; |
25 | DDRC |= (1<<5); //SCL Output |
26 | |
27 | DDRB |= (1<<0); |
28 | PORTB |= (1<<0); |
29 | |
30 | |
31 | while(1) |
32 | {
|
33 | //Start I2C
|
34 | TWCR = (1<<TWSTA) | (1<<TWEN) | (1<<TWINT); |
35 | while (!(TWCR & (1<<TWINT))); |
36 | //Write Motor Adresse
|
37 | TWSR = 0x00; |
38 | TWDR = 0x40; |
39 | TWCR = (1<<TWINT) | (1<<TWEN); |
40 | while (!(TWCR & (1<<TWINT))); |
41 | //Write PWM
|
42 | TWSR = 0x00; |
43 | TWDR = pwm; |
44 | TWCR = (1<<TWINT) | (1<<TWEN); |
45 | while (!(TWCR & (1<<TWINT))); |
46 | //Stop I2C
|
47 | TWCR = (1<<TWEN) | (1<<TWSTO) | (1<<TWINT); |
48 | for(unsigned long a = 0;a<10000;a++) asm("nop"); |
49 | |
50 | //Start I2C
|
51 | TWCR = (1<<TWSTA) | (1<<TWEN) | (1<<TWINT); |
52 | while (!(TWCR & (1<<TWINT))); |
53 | //Write Motor Adresse
|
54 | TWSR = 0x00; |
55 | TWDR = 0x50; |
56 | TWCR = (1<<TWINT) | (1<<TWEN); |
57 | while (!(TWCR & (1<<TWINT))); |
58 | //Write PWM
|
59 | TWSR = 0x00; |
60 | TWDR = pwm; |
61 | TWCR = (1<<TWINT) | (1<<TWEN); |
62 | while (!(TWCR & (1<<TWINT))); |
63 | //Stop I2C
|
64 | TWCR = (1<<TWEN) | (1<<TWSTO) | (1<<TWINT); |
65 | for(unsigned long a = 0;a<10000;a++) asm("nop"); |
66 | |
67 | //Start I2C
|
68 | TWCR = (1<<TWSTA) | (1<<TWEN) | (1<<TWINT); |
69 | while (!(TWCR & (1<<TWINT))); |
70 | //Write Motor Adresse
|
71 | TWSR = 0x00; |
72 | TWDR = 0x60; |
73 | TWCR = (1<<TWINT) | (1<<TWEN); |
74 | while (!(TWCR & (1<<TWINT))); |
75 | //Write PWM
|
76 | TWSR = 0x00; |
77 | TWDR = pwm; |
78 | TWCR = (1<<TWINT) | (1<<TWEN); |
79 | while (!(TWCR & (1<<TWINT))); |
80 | //Stop I2C
|
81 | TWCR = (1<<TWEN) | (1<<TWSTO) | (1<<TWINT); |
82 | for(unsigned long a = 0;a<10000;a++) asm("nop"); |
83 | |
84 | //Start I2C
|
85 | TWCR = (1<<TWSTA) | (1<<TWEN) | (1<<TWINT); |
86 | while (!(TWCR & (1<<TWINT))); |
87 | //Write Motor Adresse
|
88 | TWSR = 0x00; |
89 | TWDR = 0x70; |
90 | TWCR = (1<<TWINT) | (1<<TWEN); |
91 | while (!(TWCR & (1<<TWINT))); |
92 | //Write PWM
|
93 | TWSR = 0x00; |
94 | TWDR = pwm; |
95 | TWCR = (1<<TWINT) | (1<<TWEN); |
96 | while (!(TWCR & (1<<TWINT))); |
97 | //Stop I2C
|
98 | TWCR = (1<<TWEN) | (1<<TWSTO) | (1<<TWINT); |
99 | for(unsigned long a = 0;a<10000;a++) asm("nop"); |
100 | }
|
101 | }
|
>> Die Software hängt das R/W Bit selber an.
habe ich auch gerade gesehen.
Ulrich Radig schrieb: > habe ich auch gerade gesehen. Deswegen ist es glaube sinvoller nur DEC Zahlen anzugeben.
>>In der BLMC Software ist 0x0C eingestellt
Nö ist sie nicht. Dann würde es ja funktionieren.
Oder vieleicht doch 0xC0? Dann versuch auch mal 0x60.
So langsam haben wir alle Adressen durch.
@Sven
Poste deinen aktuellen Code vom BLMC.
holger schrieb: > Poste deinen aktuellen Code vom BLMC.
1 | /*----------------------------------------------------------------------------
|
2 | Copyright: Ulrich Radig (mail@ulrichradig.de)
|
3 | Author: Ulrich Radig
|
4 | Remarks:
|
5 | known Problems: none
|
6 | Version: 23.06.2011
|
7 | Description: Brushless Motor Controller for ATmega48/88/168
|
8 |
|
9 | Dieses Programm ist freie Software. Sie können es unter den Bedingungen der
|
10 | GNU General Public License, wie von der Free Software Foundation veröffentlicht,
|
11 | weitergeben und/oder modifizieren, entweder gemäß Version 2 der Lizenz oder
|
12 | (nach Ihrer Option) jeder späteren Version.
|
13 | |
14 | Die Veröffentlichung dieses Programms erfolgt in der Hoffnung,
|
15 | daß es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE,
|
16 | sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT
|
17 | FÜR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License.
|
18 | |
19 | Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
|
20 | Programm erhalten haben.
|
21 | Falls nicht, schreiben Sie an die Free Software Foundation,
|
22 | Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
23 | ------------------------------------------------------------------------------*/
|
24 | |
25 | #include <avr/interrupt.h> |
26 | #include <avr/io.h> |
27 | #include <util/twi.h> |
28 | |
29 | //Motoradresse
|
30 | #define MOTOR_ADR 0x0C
|
31 | |
32 | //PHASE1 (U)
|
33 | #define UH_DDR DDRB |= (1<<3);
|
34 | #define UH_ON TCCR2A |= (1<<COM2A1);
|
35 | #define UH_OFF TCCR2A &= ~(1<<COM2A1);
|
36 | |
37 | //PHASE1 (U)
|
38 | #define UL_DDR DDRB |= (1<<1);
|
39 | #define UL_ON PORTB |= (1<<1);
|
40 | #define UL_OFF PORTB &= ~(1<<1);
|
41 | |
42 | |
43 | //PHASE2 (V)
|
44 | #define VH_DDR DDRD |= (1<<5);
|
45 | #define VH_ON TCCR0A |= (1<<COM0B1);
|
46 | #define VH_OFF TCCR0A &= ~(1<<COM0B1);
|
47 | |
48 | //PHASE2 (V)
|
49 | #define VL_DDR DDRB |= (1<<2);
|
50 | #define VL_ON PORTB |= (1<<2);
|
51 | #define VL_OFF PORTB &= ~(1<<2);
|
52 | |
53 | |
54 | //PHASE3 (W)
|
55 | #define WH_DDR DDRD |= (1<<3);
|
56 | #define WH_ON TCCR2A |= (1<<COM2B1);
|
57 | #define WH_OFF TCCR2A &= ~(1<<COM2B1);
|
58 | |
59 | //PHASE3 (W)
|
60 | #define WL_DDR DDRC |= (1<<3);
|
61 | #define WL_ON PORTC |= (1<<3);
|
62 | #define WL_OFF PORTC &= ~(1<<3);
|
63 | |
64 | |
65 | #define PHASE_ALL_OFF UH_OFF;UL_OFF;VH_OFF;VL_OFF;WH_OFF;WL_OFF;
|
66 | |
67 | #define SENSE_U ADMUX = 0;
|
68 | #define SENSE_V ADMUX = 1;
|
69 | #define SENSE_W ADMUX = 2;
|
70 | |
71 | #define SENSE_H (ACSR&(1<<ACO))
|
72 | |
73 | #define START_PWM 5
|
74 | |
75 | volatile unsigned long i2c_timeout = 0; |
76 | volatile unsigned char rx_pwm = 0; |
77 | volatile unsigned char rotor_state = 0; |
78 | volatile unsigned char rotor_run = 0; |
79 | |
80 | //############################################################################
|
81 | void next_commutate_state (unsigned char startup) |
82 | //############################################################################
|
83 | {
|
84 | switch (rotor_state) |
85 | {
|
86 | case (0): |
87 | if(!SENSE_H || startup) |
88 | {
|
89 | WH_OFF; |
90 | UH_ON; |
91 | SENSE_W; |
92 | rotor_state = 1; |
93 | TCNT1 = 1; |
94 | }
|
95 | break; |
96 | |
97 | case (1): |
98 | if(SENSE_H || startup) |
99 | {
|
100 | VL_OFF; |
101 | WL_ON; |
102 | SENSE_V; |
103 | rotor_state = 2; |
104 | TCNT1 = 1; |
105 | }
|
106 | break; |
107 | |
108 | case (2): |
109 | if(!SENSE_H || startup) |
110 | {
|
111 | UH_OFF; |
112 | VH_ON; |
113 | SENSE_U; |
114 | rotor_state = 3; |
115 | TCNT1 = 1; |
116 | }
|
117 | break; |
118 | |
119 | case (3): |
120 | if(SENSE_H || startup) |
121 | {
|
122 | WL_OFF; |
123 | UL_ON; |
124 | SENSE_W; |
125 | rotor_state = 4; |
126 | TCNT1 = 1; |
127 | }
|
128 | break; |
129 | |
130 | case (4): |
131 | if(!SENSE_H || startup) |
132 | {
|
133 | VH_OFF; |
134 | WH_ON; |
135 | SENSE_V; |
136 | rotor_state = 5; |
137 | TCNT1 = 1; |
138 | }
|
139 | break; |
140 | |
141 | case (5): |
142 | if(SENSE_H || startup) |
143 | {
|
144 | UL_OFF; |
145 | VL_ON; |
146 | SENSE_U; |
147 | rotor_state = 0; |
148 | TCNT1 = 1; |
149 | }
|
150 | break; |
151 | }
|
152 | }
|
153 | |
154 | //############################################################################
|
155 | //back EMF zero crossing detection
|
156 | ISR (ANALOG_COMP_vect) |
157 | //############################################################################
|
158 | {
|
159 | if(rotor_run == 200) next_commutate_state (0); |
160 | |
161 | rotor_run++; |
162 | if(rotor_run > 200) |
163 | {
|
164 | rotor_run = 200; |
165 | }
|
166 | }
|
167 | |
168 | //############################################################################
|
169 | ISR (TIMER1_OVF_vect) |
170 | //############################################################################
|
171 | {
|
172 | next_commutate_state (1); |
173 | rotor_run = 0; |
174 | OCR2A = START_PWM; |
175 | OCR2B = START_PWM; |
176 | OCR0B = START_PWM; |
177 | }
|
178 | |
179 | //############################################################################
|
180 | ISR (TWI_vect) |
181 | //############################################################################
|
182 | {
|
183 | switch (TWSR & 0xF8) //TW_STATUS |
184 | {
|
185 | //Adresse empfangen
|
186 | case TW_SR_SLA_ACK: |
187 | TWCR |= (1<<TWINT); |
188 | return; |
189 | |
190 | //Daten empfangen
|
191 | case TW_SR_DATA_ACK: |
192 | rx_pwm = TWDR; |
193 | TWCR |= (1<<TWINT); |
194 | i2c_timeout = 0; |
195 | return; |
196 | |
197 | //Bus-Fehler zurücksetzen
|
198 | case TW_NO_INFO: |
199 | TWCR |=(1<<TWSTO) | (1<<TWINT); |
200 | |
201 | //Bus-Fehler zurücksetzen
|
202 | case TW_BUS_ERROR: |
203 | TWCR |=(1<<TWSTO) | (1<<TWINT); |
204 | }
|
205 | //Reset TW
|
206 | TWCR =(1<<TWEA) | (1<<TWINT) | (1<<TWEN) | (1<<TWIE); |
207 | }
|
208 | |
209 | //############################################################################
|
210 | //Hauptprogramm
|
211 | int main (void) |
212 | //############################################################################
|
213 | {
|
214 | //Watchdog on
|
215 | WDTCSR = (1<<WDCE) | (1<<WDE); |
216 | |
217 | //Motordriver output
|
218 | UH_DDR; |
219 | VH_DDR; |
220 | WH_DDR; |
221 | UL_DDR; |
222 | VL_DDR; |
223 | WL_DDR; |
224 | |
225 | //PWM for UH, VH and WH (>32KHz)
|
226 | TCCR0A |= (1<<COM0B1|1<<WGM01|1<<WGM00); |
227 | TCCR0B |= (1<<CS00); |
228 | |
229 | TCCR2A |= (1<<COM2A1|1<<COM2B1|1<<WGM21|1<<WGM20); |
230 | TCCR2B |= (1<<CS20); |
231 | |
232 | //TIMER1 for start commutation or Back EMF lost
|
233 | TCCR1B |= (1<<CS11); |
234 | TIMSK1 |= (1<<TOIE1); |
235 | |
236 | PHASE_ALL_OFF; |
237 | |
238 | //Comperator init for back EMF
|
239 | ADCSRB |= (1<<ACME); |
240 | DIDR1 |= (1<<AIN0D); |
241 | ACSR |= (1<<ACIE); |
242 | |
243 | //I2C Init
|
244 | TWAR = MOTOR_ADR & 0xFE; |
245 | TWCR = (1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE); |
246 | |
247 | //Interrupts enabel
|
248 | sei(); |
249 | |
250 | |
251 | while(1) |
252 | {
|
253 | asm("wdr"); |
254 | if(rx_pwm > START_PWM) |
255 | {
|
256 | ACSR |= (1<<ACIE); |
257 | TIMSK1 |= (1<<TOIE1); |
258 | |
259 | if(rotor_run == 200) |
260 | {
|
261 | OCR2A = rx_pwm; |
262 | OCR2B = rx_pwm; |
263 | OCR0B = rx_pwm; |
264 | }
|
265 | i2c_timeout++; |
266 | |
267 | if(i2c_timeout>100000) |
268 | {
|
269 | rx_pwm = 0; |
270 | }
|
271 | }
|
272 | else
|
273 | {
|
274 | PHASE_ALL_OFF; |
275 | ACSR&=~(1<<ACIE); |
276 | TIMSK1 &= ~(1<<TOIE1); |
277 | }
|
278 | }
|
279 | }
|
Und du bist sicher das du auch immer die aktuelle HEX Datei geflasht hast? Ich mach dir mal einen Vorschlag: Nimm das BLMC Programm. Lass die Adresse bei 0x0C. Mach ein make clean, und neu übersetzen. Nachsehen ob die HEX Datei das aktuelle Datum hat. HEX Datei neu auswählen im Brenndialog. HEX Datei flashen. Das gleiche machst du mit deinem Programm. Mit jedem einzelnen Schritt. Einmal mit 0x0C und 0x06. Wenn das nicht hilft, hilft dir nur noch Gott.
Device clocking option CKSEL3..0 Low power crystal oscillator 1111 - 1000 Full swing crystal oscillator 0111 - 0110 Low frequency crystal oscillator 0101 - 0100 Internal 128kHz RC oscillator 0011 Calibrated internal RC oscillator 0010 External clock 0000 Reserved 0001
Es geht immer noch nicht Hello world... 0x08 0x18 0x28 Byte sent: 1 0x38 Byte sent: 2 bekomme ich per RS232 zurück
Da das Thema gerade abschweift ein letzter Tip von mir. Bei jedem Versuch vorher einfach mal das Gerät ausschalten. Wenn der I2C Chip was falsches in den Hals bekommt könnte er die beleidigte Leberwurst spielen bis man ihm den Saft abdreht. Ich bin dann mal weg.
>Wenn ich andere aberssen nehme bekomme ich Could not start
Probier halt alle geraden Adressen von 0 bis 254 durch.
Eine wird schon passen.
TWDR = (Address<<1) + TWIM_Type; TWCR = (1<<TWINT)|(1<<TWEN); printf("Addr: 0x%02x\n", TWDR); Bringt bei Adresse 0x0C über RS232 Addr: 0x18
>TWDR = (Address<<1) + TWIM_Type; >Bringt bei Adresse 0x0C über RS232 > >Addr: 0x18 0x0C << 1 ist nun mal 0x18. Schwachkopf.
Es kann aber nicht damit zusammenhängen das ich kein Motor dran habe oder? Bin nun erstmal im Bett melde mich morgen :)
Habe den Source Code von dir getestet (siehe Datei im Anhang) und es funktioniert. Mein Motor hat in der Software die Adresse 0x50!!
Hallo Ulrich magst du mal den ganzen Code testen? Habe ihn in den Anhang genommen.
Ich werde deinen Code mal heute Abend Testen :) Und dann mein Ergebnis hier posten.
Wie schon gesagt am SourceCode wird es vermutlich nicht liegen. Die Adresse 0 funktioniert nicht (Generall Call) das muß das Slave Device unterstützen. Du hattest da aber beim ersten mal bei Adresse 0 eine Antwort bekommen. Ich tippe da schwer auf einen Hardwarefehler. Gruß Uli
Ich vermute das es am letzten Bit liegt welches mir durch R/W geklaut wird, werde es mal mit der Adresse 0x50 testen :)
Hast Du mal mit der Ticktack gespielt? 1 MHz Takt ist flott, kann aber nicht jeder. 400KHz sind auch nicht ohne, möglicherweise kann auch das nicht jeder. 100KHz gehen auch noch recht gut. Vergiss' nicht, Du (ATMega644) hast das sagen. Du gibst den Takt an. Kann es sein, dass Du zwar Pull-Up-Widerstände aber keine Abschlusswiderstände hast? Der Unterschied liegt in der Position bzw. im Layout.
amateur schrieb: > Vergiss' nicht, Du (ATMega644) hast das sagen. Du gibst den Takt an. Ja ich weiß gebe 100kHz vor amateur schrieb: > Abschlusswiderstände hast? noch nie bei I2C gesehen Abdul K. schrieb: > SDA mit SCL vertauscht? Poste deine Scope-Aufnahme! Denn würde es ja nie gehen und nach durchgangs prüfungen ist alles richtig Wenn ich ein scope hätte, mach es wenn es sein muss mit meiner Soundkarte
Wir wollen nun das Scopebild sehen! Am Slave! Es sind Pull-up-Rs. Add: Soundkarte, hm. Weiß nicht ob das Sinn macht. Elektronikentwicklung ohne Scope ist einfach Blödsinn.
Abdul K. schrieb: > Elektronikentwicklung > ohne Scope ist einfach Blödsinn. Ich habe die nötigen Geräte sonst in der Schule, aber wir haben ferienn. Zudem bin ich nicht reich und kann mir solche Geräte nicht leisten! Kein Grund jemanden zu verurteilen.
Sven Müller schrieb: > Abdul K. schrieb: >> Elektronikentwicklung >> ohne Scope ist einfach Blödsinn. > > Ich habe die nötigen Geräte sonst in der Schule, aber wir haben ferienn. > Zudem bin ich nicht reich und kann mir solche Geräte nicht leisten! Kein > Grund jemanden zu verurteilen. Das sind ausreden! Heute gibt es unglaublich günstige LAs. Es muss ja kein ausgewachsenes DSO sein. Aber wenn man Embedded Entwicklung betreibt (auch privat) muss man einen Grundstock an Messgeräten haben. Das ist keine Frage des Geldes. Ich kenne im Elektro-Modellflug Menschen mit 30 Jahren Erfahrung, ner 10.000 Euro Maschine (3m Spannweite) aber haben zuhause kein Multimeter. Da kann man nur den Kopf schütteln. Auch fürs Hobby brauchts Ausrüstung! Das ist heute alles saubillig und trotzdem fürs Hobby tauglich. Und wenn man mit seriellen Bussen spielt, sollte man irgendwie die Möglichkeit haben, diese zu sehen. Also einen LA. Ohne solche Technik macht man sich das Leben schwer und den anderen hier auch. gruß cyblord
cyblord ---- schrieb: > Das sind ausreden! Ich bin nich hier um mir etwas unterstellen zu lassen. Ich erwarte ledigtlich ein bisschen hilfe und keine Unterstellungen.
Hallo Ulrich, das ganze geht jetzt nur i-wie läuft der motor so garnicht sauber -.-, Mal läuft er, dann fiept er nur, denn ruckelt er rückwärts.. und immer wild durcheinander ich weiß net was da los ist
Wann hast du denn U.R.'s Zeug runtergeladen? Wenn das nicht länger als 6 Monate her war, das hast du vielleicht noch Garantie! Verklag ihn doch einfach. Achtung, kann Spuren von Ironie enthalten!
Na ja, ein Funken Wahrheit ist an dem was Cyblord und Abdul so schreiben schon dran. Oszis gibts neu für 300 EUR, der EEV-Blogger hat sogar bei Ebay für sage und schreibe 19Aussie Dollar ein voll funktionsfähiges Hameg Speicheroszi aufgetrieben. Und wenn man clever ist kann man selbst mit einem alten Analog-Oszi + externer Triggerung und einem triggernden Port-Bit für ein Standbild sorgen um die Bits auf dem I2C-Bus abzuzählen. Aber was solls. Schuld ist bei nicht funktionsfähigen Nachbauten ja sowieso eh immer derjenige der sich die Mühe machte sich etwas auszudenken und frei zu veröffentlichen.
@Sven
>das ganze geht jetzt
Es wäre nett wenn du mal sagen könntest wo jetzt das Problem war.
Ansonsten kann man diesen Thread als nutzlosen Internetmüll auch
gleich löschen.
Woran es jetzt gelegen hat wurde mir auch nicht verraten. Der geposteten Source Code funktionierte bei mir habe ich gestern Abend noch getestet. Das Ruckeln des Motors liegt am Delay (1000). Die Software ist für eine Drohne ausgelegt. Erhält der Motor nicht innerhalb einer gewissen Zeit ein neues Datenbyte bleibt dieser stehen. Gruß Uli
Sven Müller schrieb: > cyblord ---- schrieb: >> Das sind ausreden! > > Ich bin nich hier um mir etwas unterstellen zu lassen. > > Ich erwarte ledigtlich ein bisschen hilfe und keine Unterstellungen. Das darf natürlich deine Meinung sein und Verurteilung zu unterstellen, find ich auch etwas dreist! Für 10 Euro bekommt man einen LA. Einzige Einschränkung: Ohne Tricks keine analogen Werte. Es läuft halt einfach so: Du bleibst auf deinem Standpunkt und ich helfe dir eben nicht mehr, denn meine Zeit ist auch kostbar.
holger schrieb: > Es wäre nett wenn du mal sagen könntest wo jetzt das Problem war. Das Problem lag bei der Adresse das Motors, das runtersetzen des Delays hat schon zu einer Besserung geführt, aber bei werten wie z.B. 255 fiept der Motor nur und bei 200 springt er auch nur an wenn ich in anschupse.
So hier mal Screens vom Soundkarten scope. die mit sind gemessen mit Motor die ohne sind gemessen ohne Motor jewals L1_L3 und L2_L3, wobei die rote Linie immer L3 zeigt
Und wenn du zuerst mal langsam mit dem Wert 50 Anfägst?? Wie groß ist der Elko auf dem BLMC??
So habe gerade nen anderen Treiber getestet, dieser ging... und ein anderer spackte wieder :/
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.