Hallo ihr Profis ... ich beschäftige mich nun ein paar Tage mit dem MSP430F4794 und einem I2C EEPROM (M24C32). Ich glaube das schreiben (Byteweise) funktioniert. Wenn ich aber die Bytes wieder lesen will, habe ich eine Verschiebung drin so... Meine Frage ist eigentlich : hat schon jemand I2C Routinen für I2C EEproms die er mir schicken könnte ? oder Code Schnipsel o.ä. hier sind mal meine Anfänge : unsigned char EEPROM_ByteWrite(unsigned int address,unsigned char data) { while (UCB0STAT&UCBBUSY); // wait until I2C module has finished all operations I2CBuffer[0] = ((unsigned char)*((unsigned char*)&address + 1)); // calculate high byte I2CBuffer[1] = ((unsigned char)*((unsigned char*)&address + 0)); // calculate low byte I2CBuffer[2] = data; I2C_WRITECNT = 3; // set I2CBuffer Pointer IFG2 &= ~(UCB0TXIFG | UCB0RXIFG); // clear Access ready interrupt flag IE2 &= ~ (UCB0RXIE | UCB0TXIE); // RX / TX Interrupt sperren P3DIR |= BIT0;P3OUT&=~BIT0; UCB0CTL1 |= UCTR ; // Repeated start condition generation + R/W UCB0CTL1 |= UCTXSTT; // Repeated start condition generation + R/W while (!(IFG2 & UCB0TXIFG)); // wait until I2C module has finished all operations IFG2 &= ~UCB0TXIFG; unsigned char i; for (i=0;i<I2C_WRITECNT;i++) { UCB0TXBUF = I2CBuffer[i]; while (!(IFG2 & UCB0TXIFG)); // warten bis Byte gesendet wurde IFG2 &= ~UCB0TXIFG; } UCB0CTL1 |= UCTXSTP; // Stop condition while (UCB0CTL1 & UCTXSTP); // Loop until I2C STT is sent P3OUT |=BIT0; DelayMsI2C(12); // (10ms warten laut Datenblatt !) return 1; } unsigned char EEPROM_RandomRead(unsigned int Address) { unsigned char rec=0; while (UCB0STAT&UCBBUSY); // wait until I2C module has finished all operations I2CBuffer[0] = ((unsigned char)*((unsigned char*)&Address + 1)); // calculate high byte I2CBuffer[1] = ((unsigned char)*((unsigned char*)&Address + 0)); // calculate low byte I2C_WRITECNT = 2; // set I2CBuffer Pointer IFG2 &= ~(UCB0TXIFG | UCB0RXIFG); // clear Access ready interrupt flag IE2 &= ~ (UCB0RXIE | UCB0TXIE); // RX / TX Interrupt sperren UCB0CTL1 |= UCTR | UCTXSTT; // Start while (!(IFG2 & UCB0TXIFG)); // warten bis Start Byte gesendet wurde UCB0TXBUF = ((unsigned char)*((unsigned char*)&Address + 1)); while (!(IFG2 & UCB0TXIFG)); // warten bis Byte gesendet wurde IFG2 &= ~UCB0TXIFG; UCB0TXBUF = ((unsigned char)*((unsigned char*)&Address + 0)); while (!(IFG2 & UCB0TXIFG)); // warten bis Byte gesendet wurde IFG2 &= ~UCB0TXIFG; rec = UCB0RXBUF; UCB0CTL1 &= ~UCTR; // R/W löschen UCB0CTL1 |= UCTXSTT; // start condition generation while (UCB0CTL1 & UCTXSTT); // warten bis Byte gesendet wurde IFG2 &= ~UCB0RXIFG; rec = UCB0RXBUF; UCB0CTL1 |= UCTXSTP; // Stop condition while (UCB0CTL1 & UCTXSTP); // Loop until I2C STT is sent DelayMsI2C(1); // warten laut Datenblatt !!! return rec; } wenn ich zuerst 16 Bytes schreibe von 0 bis 15 und dort den Wert 0 bis 15 rein schreibe bekomme ich dann beim lesen auf Addr 0 und 1 eine 0 und ab Addr2 dann 1..15 . Ich hoffe ihr könnst verstehen was ich meine ... Wäre super wenn jemand schon tiefer in diesem Tham drin wäre und helfen könnte. Ich danke euch auf jedenfall schon mal im Voraus. Gruß Royw
Ich steigt bei deinem Code jetzt nicht ganz durch, ich pack mal meinen Code rein. Der ist zwar auch noch nicht 100%ig fertig, funktioniert aber schon fehlerfrei (Mit FRAM). Geschrieben für MSP430F2254.
1 | //////////////////////////////////////////////////////////////////////////
|
2 | unsigned char fram_write_byte (unsigned int addr, unsigned char data) |
3 | {
|
4 | unsigned char addr_h; |
5 | unsigned char addr_l; |
6 | |
7 | addr_h = addr>>8; |
8 | addr_l = addr; |
9 | |
10 | // UCB0STAT &=~UCNACKIFG;
|
11 | |
12 | UCB0I2CSA = I2C_ADDR_FRAM; |
13 | |
14 | UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition |
15 | UCB0TXBUF = addr_h; |
16 | |
17 | while(UCB0CTL1 & UCTXSTT); // Warten bis Start und Adresse gesendet |
18 | |
19 | if (UCB0STAT & UCNACKIFG) return FALSE; |
20 | |
21 | // while (!(IFG2 & UCB0TXIFG));
|
22 | |
23 | while (!(IFG2 & UCB0TXIFG)); |
24 | UCB0TXBUF = addr_l; |
25 | while (!(IFG2 & UCB0TXIFG)); |
26 | UCB0TXBUF = data; |
27 | while (!(IFG2 & UCB0TXIFG)); |
28 | |
29 | UCB0CTL1 |= UCTXSTP; // I2C stop condition |
30 | while(UCB0CTL1 & UCTXSTP); |
31 | |
32 | return TRUE; |
33 | }
|
34 | //////////////////////////////////////////////////////////////////////////
|
35 | |
36 | //////////////////////////////////////////////////////////////////////////
|
37 | unsigned char fram_write (unsigned int addr, unsigned char data_cnt, unsigned char *data) |
38 | {
|
39 | unsigned char addr_h; |
40 | unsigned char addr_l; |
41 | unsigned int i; |
42 | |
43 | addr_h = addr>>8; |
44 | addr_l = addr; |
45 | |
46 | |
47 | UCB0I2CSA = I2C_ADDR_FRAM; |
48 | |
49 | UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition |
50 | |
51 | while (!(IFG2 & UCB0TXIFG)); |
52 | UCB0TXBUF = addr_h; |
53 | while (!(IFG2 & UCB0TXIFG)); |
54 | UCB0TXBUF = addr_l; |
55 | |
56 | for(i = 0; i < data_cnt; i++) |
57 | {
|
58 | while (!(IFG2 & UCB0TXIFG)); |
59 | UCB0TXBUF = data[i]; |
60 | }
|
61 | |
62 | while (!(IFG2 & UCB0TXIFG)); |
63 | |
64 | UCB0CTL1 |= UCTXSTP; // I2C stop condition |
65 | while(UCB0CTL1 & UCTXSTP); |
66 | |
67 | return TRUE; |
68 | }
|
69 | //////////////////////////////////////////////////////////////////////////
|
70 | |
71 | //////////////////////////////////////////////////////////////////////////
|
72 | unsigned char fram_read_byte (unsigned int addr, unsigned char *data) |
73 | {
|
74 | unsigned char addr_h; |
75 | unsigned char addr_l; |
76 | |
77 | addr_h = addr>>8; |
78 | addr_l = addr; |
79 | |
80 | // UCB0STAT &=~UCNACKIFG;
|
81 | |
82 | UCB0I2CSA = I2C_ADDR_FRAM; |
83 | |
84 | UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition |
85 | |
86 | // while(UCB0CTL1 & UCTXSTT); // Warten bis Start und Adresse gesendet
|
87 | /*
|
88 | if (UCB0STAT & UCNACKIFG)
|
89 | {
|
90 | UCB0CTL1 |= UCTXSTP; // I2C stop condition
|
91 | UCB0STAT &=~UCNACKIFG;
|
92 | return FALSE;
|
93 | }
|
94 | */
|
95 | while (!(IFG2 & UCB0TXIFG)); |
96 | UCB0TXBUF = addr_h; |
97 | while (!(IFG2 & UCB0TXIFG)); |
98 | UCB0TXBUF = addr_l; |
99 | while (!(IFG2 & UCB0TXIFG)); |
100 | |
101 | UCB0CTL1 &=~UCTR; // I2C RX, start condition |
102 | UCB0CTL1 |= UCTXSTT; // I2C start condition |
103 | |
104 | while (!(IFG2 & UCB0RXIFG)); |
105 | *data = UCB0RXBUF; |
106 | |
107 | UCB0CTL1 |= UCTXSTP; // I2C stop condition |
108 | while(UCB0CTL1 & UCTXSTP); |
109 | |
110 | return TRUE; |
111 | }
|
112 | //////////////////////////////////////////////////////////////////////////
|
113 | |
114 | //////////////////////////////////////////////////////////////////////////
|
115 | unsigned char fram_read (unsigned int addr, unsigned char data_cnt, unsigned char *data) |
116 | {
|
117 | unsigned char addr_h; |
118 | unsigned char addr_l; |
119 | unsigned int i; |
120 | |
121 | addr_h = addr>>8; |
122 | addr_l = addr; |
123 | |
124 | // UCB0STAT &=~UCNACKIFG;
|
125 | |
126 | UCB0I2CSA = I2C_ADDR_FRAM; |
127 | |
128 | UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition |
129 | |
130 | // while(UCB0CTL1 & UCTXSTT); // Warten bis Start und Adresse gesendet
|
131 | /*
|
132 | if (UCB0STAT & UCNACKIFG)
|
133 | {
|
134 | UCB0CTL1 |= UCTXSTP; // I2C stop condition
|
135 | UCB0STAT &=~UCNACKIFG;
|
136 | return FALSE;
|
137 | }
|
138 | */
|
139 | while (!(IFG2 & UCB0TXIFG)); |
140 | UCB0TXBUF = addr_h; |
141 | while (!(IFG2 & UCB0TXIFG)); |
142 | UCB0TXBUF = addr_l; |
143 | while (!(IFG2 & UCB0TXIFG)); |
144 | |
145 | UCB0CTL1 &=~UCTR; // I2C RX |
146 | UCB0CTL1 |= UCTXSTT; // I2C start condition |
147 | |
148 | for (i = 0; i < data_cnt; i++) |
149 | {
|
150 | while (!(IFG2 & UCB0RXIFG)); |
151 | data[i] = UCB0RXBUF; |
152 | }
|
153 | |
154 | UCB0CTL1 |= UCTXSTP; // I2C stop condition |
155 | while(UCB0CTL1 & UCTXSTP); |
156 | |
157 | return TRUE; |
158 | }
|
159 | //////////////////////////////////////////////////////////////////////////
|
Vielen Dank für deien Antwort. Ich habe ma lunsere Routinen verglichen und habe festgestellt das sie eigentlich sehr ähnlich sind um nicht zusagen das gleiche tun sollten. Was mir aber auffiel wenn man 2 mal nacheinander ein Frame_Read ausführt, sind die Daten des 2. Frame Read um eins verschoben. Z.B. : EEPROM Zelle 0 enthält 0 , Zelle 1 enthält 1 ... Zelle 15 enthält 15. 1. Frame_Read klappt noch super. bei dem 2. Frame_Read steht dann in Addr0 ein zufallswert und in Zelle 1 eine 0 in Zelle2 eine 1 ... Zelle 15 eine 14. Jetzt habe ich herausgefunden das man hinter dem Stop senden einfach den UCB0RXBUF nochmal lesen sollte.Danach klappt das 2. Frame_Read auch ! (Vielleicht hilf dir das auch) Vielen Dank für deine Hilfe. Royw
Mir sind doch 2 Sachen an deinem EEPROM_RandomRead Code aufgefallen (Siehe Kommentar im Code)
1 | unsigned char EEPROM_RandomRead(unsigned int Address) |
2 | .....
|
3 | UCB0TXBUF = ((unsigned char)*((unsigned char*)&Address + 1)); |
4 | while (!(IFG2 & UCB0TXIFG)); // warten bis Byte gesendet wurde |
5 | IFG2 &= ~UCB0TXIFG; |
6 | UCB0TXBUF = ((unsigned char)*((unsigned char*)&Address + 0)); |
7 | while (!(IFG2 & UCB0TXIFG)); // warten bis Byte gesendet wurde |
8 | IFG2 &= ~UCB0TXIFG; |
9 | |
10 | // Wozu RX Buffer lesen?
|
11 | rec = UCB0RXBUF; |
12 | UCB0CTL1 &= ~UCTR; // R/W löschen |
13 | UCB0CTL1 |= UCTXSTT; // start condition generation |
14 | while (UCB0CTL1 & UCTXSTT); // warten bis Byte gesendet wurde |
15 | IFG2 &= ~UCB0RXIFG; |
16 | // Du liest Daten ein obwohl noch kein RX IFG gekommen ist!
|
17 | rec = UCB0RXBUF; |
18 | UCB0CTL1 |= UCTXSTP; // Stop condition |
19 | while (UCB0CTL1 & UCTXSTP); // Loop until I2C STT is sent |
20 | DelayMsI2C(1); // warten laut Datenblatt !!! |
21 | return rec; |
Das Prob kenne ich vom MSP430F149. Liest man den RX Buffer nicht aus kann es zu Problemen führen, auch wenn das andere hier nicht glauben. Ich habe Routinen da geht es NUR wenn ich ihn auslese (obschon ich den Inhalt nicht benötige). Bei anderen Routinen klappt es einwandfrei. Bin noch nicht dahinter gekommen an was es genau liegt. Gruss
Durch das lesen wird das RX IFG zurückgesetzt (wenn man die Daten vorher nicht geholt hat). Ansonsten hat die F2xx Serie ein anderes I2C/UART Interface als die F1xx. Sind also nicht direkt vergleichbar.
So ich habe nun eine funktionierende PAGE_WRITE Routine ... Mit dieser kann ich jetzt den EEPROM beschreiben (auch mit mehr als 32 Byte am Stück) Ein Problem habe ich jetzt noch , wenn der EEPROM die ersten 32 Byte schreibt ist im Datenblatt des M24C32 eine Schreibzeit von max. 10ms angegeben. Weiterhin ist beschrieben das diese aber in der Regel kürzer ist. Man kann wohl den EEPROM mit STARTs "beschiessen" solange bis ACK anstelle NACK kommt. Wenn ich das aber mit Code zwischen den Sternchen mache geht das nicht. Hat einer ne Ahnung was ich da falsch mache ? Royw
1 | unsigned char I2C_EEPROM_FRAME_WRITE (unsigned int addr, unsigned char data_cnt, unsigned char *data) |
2 | {
|
3 | P3DIR |= BIT0;P3OUT&=~BIT0; // WC auf low |
4 | unsigned int i,i1; |
5 | UCB0I2CSA = I2C_ADDR_EEPROM; |
6 | //***************************************
|
7 | // Abfrage ob EEPROM ein Acknolege sendet
|
8 | do
|
9 | { // solange START senden bis ACK kommt |
10 | UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition |
11 | while (!(IFG2 & UCB0TXIFG)); // warten bis DS gesendet wurde |
12 | } while (UCB0STAT & UCNACKIFG) |
13 | //***************************************
|
14 | |
15 | |
16 | unsigned int add = addr; |
17 | if (data_cnt>31) |
18 | for (i1=0;i1<=data_cnt/32;i1++) |
19 | { // Schleife für Block (32Byte) |
20 | add = addr + i1*32; |
21 | UCB0TXBUF = ((unsigned char)*((unsigned char*)&add + 1)); |
22 | while (!(IFG2 & UCB0TXIFG)); |
23 | UCB0TXBUF = ((unsigned char)*((unsigned char*)&add + 0)); |
24 | for(i = 0; i < 32; i++) |
25 | {
|
26 | while (!(IFG2 & UCB0TXIFG)); |
27 | UCB0TXBUF = data[add+i]; |
28 | }
|
29 | while (!(IFG2 & UCB0TXIFG)); |
30 | UCB0CTL1 |= UCTXSTP; // I2C stop condition |
31 | while(UCB0CTL1 & UCTXSTP); |
32 | i = UCB0RXBUF; // I2C RXbuffer leeren |
33 | DelayMsI2C(10); |
34 | }
|
35 | if (data_cnt%32>0) |
36 | {// und noch den Rest übertragen |
37 | do
|
38 | {
|
39 | UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition |
40 | while (!(UCB0CTL1 & UCTXSTT)); |
41 | } while (UCB0STAT & UCNACKIFG); |
42 | |
43 | add = addr + i1*32; |
44 | UCB0TXBUF = ((unsigned char)*((unsigned char*)&add + 1)); |
45 | while (!(IFG2 & UCB0TXIFG)); |
46 | UCB0TXBUF = ((unsigned char)*((unsigned char*)&add + 0)); |
47 | for(i = 0; i <= data_cnt%32; i++) |
48 | {
|
49 | while (!(IFG2 & UCB0TXIFG)); |
50 | UCB0TXBUF = data[add+i]; |
51 | }
|
52 | while (!(IFG2 & UCB0TXIFG)); |
53 | UCB0CTL1 |= UCTXSTP; // I2C stop condition |
54 | while(UCB0CTL1 & UCTXSTP); |
55 | i = UCB0RXBUF; // I2C RXbuffer leeren |
56 | |
57 | }
|
58 | P3DIR |= BIT0;P3OUT&=~BIT0; // WC auf high |
59 | DelayMsI2C(10); // ca. 10ms warten --> Datenblatt |
60 | return 1; |
61 | }
|
so habe jetzt auch dafür eine Lösung ... (Damit konnte ich die Wartezeit von 10ms auf ca. 2.7ms senken .) Das Problem wiederum daran ist, das anscheinend die Interrupts gesperrt werden müssen. Doch leider brauche ich die Interrupts für die UART, um mich mit dem Gerät unterhalten zu können. Hat da vielleicht einer noch ne Lösung ? Gruß Royw
1 | do
|
2 | {
|
3 | __disable_interrupt(); |
4 | UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP ; // I2C TX, start + stop condition |
5 | while (UCB0CTL1 & UCTXSTP); // wait for STOP condition |
6 | __enable_interrupt(); |
7 | } while (UCB0STAT & UCNACKIFG); |
Hab gerade eien Antwort von TI bekommen, das es nur mit disable der Interrupts geht. schade ...
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.