1 | // ---------------------------------------------------------------
|
2 | // Initialisiere das E2Prom
|
3 | // ---------------------------------------------------------------
|
4 | void e2p_Init_I2C()
|
5 | {
|
6 | GPIO_InitTypeDef GPIO_InitStruct; // Port Init Struct
|
7 | I2C_InitTypeDef I2C_InitStruct; // I2C Init Struct
|
8 |
|
9 | // Peripherie Takt einschalten I2C3: PA8 (I2C SCL) und PC9 (I2C3_SDA)
|
10 | RCC_APB1PeriphClockCmd(I2C_RCC, ENABLE); // Enable APB1 peripheral clock für I2C3
|
11 | RCC_AHB1PeriphClockCmd(I2C_PERIPH_SCL_PORT, ENABLE); // Enable clock für PortA SCL pin
|
12 | RCC_AHB1PeriphClockCmd(I2C_PERIPH_SDA_PORT, ENABLE); // Enable clock für PortC SDA pin
|
13 |
|
14 | I2C_Cmd(I2C_CHANNEL, DISABLE); // I2C abschalten, damit Bus still bleibt
|
15 |
|
16 | // Port mit SCL einrichten
|
17 | GPIO_InitStruct.GPIO_Pin = I2C_SCL_PIN; // Pin A8 (I2C3_SCL)
|
18 | GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // Pins als Alternate Function einstellen
|
19 | GPIO_InitStruct.GPIO_Speed = GPIO_Fast_Speed; // IO Speed, nicht Baudrate, 2 Mhz reicht
|
20 | GPIO_InitStruct.GPIO_OType = GPIO_OType_OD; // Open Drain Output
|
21 | GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
22 | GPIO_Init(I2C_SCL_PORT, &GPIO_InitStruct);
|
23 |
|
24 | // Port mit SDA einrichten
|
25 | GPIO_InitStruct.GPIO_Pin = I2C_SDA_PIN;
|
26 | GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // Pin C9 (SDA)
|
27 | GPIO_InitStruct.GPIO_Speed = GPIO_Fast_Speed;
|
28 | GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
|
29 | GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
30 | GPIO_Init(I2C_SDA_PORT, &GPIO_InitStruct);
|
31 |
|
32 | // Pins sind nun auf AF verbunden
|
33 | // USART3 kann nun Kontrolle über Pins übernehmen
|
34 | GPIO_PinAFConfig(I2C_SCL_PORT, I2C_SCL_SOURCE, I2C_GPIO_AF);
|
35 | GPIO_PinAFConfig(I2C_SDA_PORT, I2C_SDA_SOURCE, I2C_GPIO_AF);
|
36 |
|
37 | // Struktur Parameter fuer I2C setzen
|
38 | I2C_StructInit(&I2C_InitStruct); // Rücksetzen auf Default
|
39 | I2C_InitStruct.I2C_ClockSpeed = 100000; // 100 khz Busfrequenz
|
40 | I2C_InitStruct.I2C_Mode = I2C_Mode_I2C; // Normaler I2C Mode
|
41 | I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 50:50 Duty Cycle
|
42 | I2C_InitStruct.I2C_OwnAddress1 = 0xEE;
|
43 | I2C_InitStruct.I2C_Ack = I2C_Ack_Enable; // ACK senden
|
44 | I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // 7 Bit Adressierung
|
45 |
|
46 | // I2C einschalten
|
47 | I2C_Cmd(I2C_CHANNEL, ENABLE);
|
48 |
|
49 | // I2C3 mit den obigen Parametern konfigurieren
|
50 | I2C_Init(I2C_CHANNEL, &I2C_InitStruct);
|
51 | }
|
52 |
|
53 | // ---------------------------------------------------------------
|
54 | // Setzt alle Einstellungen zurück auf Default
|
55 | // ---------------------------------------------------------------
|
56 | void e2p_DeInit_I2C()
|
57 | {
|
58 | // I2C Einheit zurücksetzen
|
59 | I2C_DeInit(I2C_CHANNEL);
|
60 | RCC_APB1PeriphClockCmd(I2C_RCC, DISABLE); // Enable APB1 peripheral clock für I2C3
|
61 | I2C_initialized = false;
|
62 | }
|
63 |
|
64 | // ---------------------------------------------------------------
|
65 | // Beschreibe das E2PROM einzelnen mit mehreren Bytes
|
66 | // ---------------------------------------------------------------
|
67 | uint8_t e2p_WriteMultiBytes(uint16_t addr, uint8_t *data, size_t nrBytes)
|
68 | {
|
69 | if (!I2C_initialized) {
|
70 | e2p_Init_I2C(I2C_CHANNEL);
|
71 | I2C_initialized = true;
|
72 | }
|
73 |
|
74 | for (uint16_t i = 0; i< nrBytes; i++) {
|
75 | if (e2p_Write_Byte(addr++,*(data++)))
|
76 | return ERROR;
|
77 | }
|
78 |
|
79 | return SUCCESS;
|
80 | }
|
81 |
|
82 | // ---------------------------------------------------------------
|
83 | // Beschreibe das E2PROM mit einem Byte
|
84 | // ---------------------------------------------------------------
|
85 | uint8_t e2p_Write_Byte(uint16_t Addr, const uint8_t Data)
|
86 | {
|
87 | if (!I2C_initialized) {
|
88 | e2p_Init_I2C(I2C_CHANNEL);
|
89 | I2C_initialized = true;
|
90 | }
|
91 |
|
92 | // Transmission starten
|
93 | e2p_StartWriteAddress(Addr);
|
94 |
|
95 | // Sende Datum
|
96 | I2C_SendData(I2C_CHANNEL, Data);
|
97 | if (I2C_WaitForEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
|
98 | return ERROR;
|
99 |
|
100 | // Sende I2C3 STOP Condition
|
101 | I2C_GenerateSTOP(I2C_CHANNEL, ENABLE);
|
102 |
|
103 | // Warte bis fertig geschrieben
|
104 | if (e2p_WaitForWriteReady() != SUCCESS)
|
105 | return ERROR;
|
106 |
|
107 | return SUCCESS;
|
108 | }
|
109 |
|
110 | // ---------------------------------------------------------------
|
111 | // Ein Byte aus E2PROM lesen
|
112 | // ---------------------------------------------------------------
|
113 | uint8_t e2p_Read_Byte(const uint16_t Addr)
|
114 | {
|
115 | if (!I2C_initialized) {
|
116 | e2p_Init_I2C(I2C_CHANNEL);
|
117 | I2C_initialized = true;
|
118 | }
|
119 |
|
120 | // ACK ein
|
121 | I2C_AcknowledgeConfig(I2C_CHANNEL, ENABLE);
|
122 |
|
123 | // Transmission starten
|
124 | if (e2p_StartWriteAddress(Addr) != SUCCESS)
|
125 | return ERROR;
|
126 |
|
127 | // AF Flag evtl löschen
|
128 | I2C_CHANNEL->SR1 |= (uint16_t)0x0400;
|
129 |
|
130 | /* -------- E2PROM Lesemodus (MASTER Receiver Mode)------ */
|
131 |
|
132 | // Erzeuge START Bedingung
|
133 | I2C_GenerateSTART(I2C_CHANNEL, ENABLE);
|
134 | if (I2C_WaitForEvent( I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
|
135 | return 0xff;
|
136 |
|
137 | // Adressiere das E2PROM
|
138 | I2C_Send7bitAddress(I2C_CHANNEL, MEM_DEVICE_READ_ADDR, I2C_Direction_Receiver);
|
139 | if (I2C_WaitForEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS)
|
140 | return 0xff;
|
141 |
|
142 | /* Wichtiger Hinweis, bzgl der Reihenfolge des Bit Setzens, Manual. STM32F407, S834
|
143 | Die Konfiguration muss VOR dem Buszugriff erfolgen, d.h. das Datenbyte wird
|
144 | erst ganz zum Schluss ausgelesen */
|
145 |
|
146 | // NACK einstellen E2PROM anzuzeigen, dass keine weiteren Daten angefordert sind
|
147 | I2C_AcknowledgeConfig(I2C_CHANNEL, DISABLE);
|
148 | if (I2C_WaitForEvent(I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS)
|
149 | return 0xff;
|
150 |
|
151 | // Stop Bedingung erzeugen NACH dem nächsten Lesezugriff
|
152 | I2C_GenerateSTOP(I2C_CHANNEL, ENABLE);
|
153 | if (I2C_WaitForEvent(I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS)
|
154 | return 0xff;
|
155 |
|
156 | return I2C_ReceiveData(I2C_CHANNEL);
|
157 | }
|
158 |
|
159 | /* /////////////////////////////////////////////////////////
|
160 | Low Level Routinen für die Bedienung des E2PROMs
|
161 | * /////////////////////////////////////////////////////// */
|
162 |
|
163 |
|
164 | // Hilfsroutine zum Auslesen der Events mit Timeout
|
165 | static uint8_t I2C_WaitForEvent(uint32_t event)
|
166 | {
|
167 | timeout = I2C_TIMEOUT_MAX;
|
168 | while(I2C_CheckEvent(I2C_CHANNEL, event) != SUCCESS) {
|
169 | if ((timeout--) == 0) return ERROR;
|
170 | }
|
171 | return SUCCESS;
|
172 | }
|
173 |
|
174 | // ---------------------------------------------------------------
|
175 | // Starte die E2PROM Sequenz: Startbit, E2prom Adresse, Zieladresse...
|
176 | // ---------------------------------------------------------------
|
177 | static uint8_t e2p_StartWriteAddress(uint16_t Addr)
|
178 | {
|
179 | uint8_t lower_addr, upper_addr;
|
180 |
|
181 | lower_addr = (uint8_t)((0x00FF) & Addr);
|
182 | Addr = Addr>>8;
|
183 | upper_addr = (uint8_t)((0x00FF) & Addr);
|
184 |
|
185 | /* -------- E2PROM Adresszeiger auf Zieladresse setzen ------ */
|
186 |
|
187 | // Erzeuge START Bedingung
|
188 | I2C_GenerateSTART(I2C_CHANNEL, ENABLE);
|
189 | if (I2C_WaitForEvent(I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
|
190 | return 0xff;
|
191 |
|
192 | // Adressiere das E2PROM
|
193 | I2C_Send7bitAddress(I2C_CHANNEL, MEM_DEVICE_WRITE_ADDR, I2C_Direction_Transmitter);
|
194 | if (I2C_WaitForEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS)
|
195 | return 0xff;
|
196 |
|
197 | // Adresse als 2 x 8 Bit senden
|
198 | I2C_SendData(I2C_CHANNEL,upper_addr);
|
199 | if (I2C_WaitForEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
|
200 | return 0xff;
|
201 |
|
202 | I2C_SendData(I2C_CHANNEL, lower_addr);
|
203 | if (I2C_WaitForEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
|
204 | return 0xff;
|
205 |
|
206 | return SUCCESS;
|
207 | }
|
208 |
|
209 | // ---------------------------------------------------------------
|
210 | // Warte bis Schreibzyklus beendet ist (ACK Polling)
|
211 | // ---------------------------------------------------------------
|
212 | static uint8_t e2p_WaitForWriteReady() {
|
213 |
|
214 | // Warte bis Byte weggeschrieben wurde (Slave sendet solange kein ACK)
|
215 | uint32_t timeout = I2C_TIMEOUT_MAX;
|
216 | do{
|
217 | if (--timeout == 0)
|
218 | return ERROR;
|
219 | // Erzeuge Schreibzugriff......
|
220 | I2C_GenerateSTART(I2C_CHANNEL, ENABLE);
|
221 | while(!I2C_CheckEvent(I2C_CHANNEL, I2C_EVENT_MASTER_MODE_SELECT));
|
222 | I2C_Send7bitAddress(I2C_CHANNEL, MEM_DEVICE_WRITE_ADDR, I2C_Direction_Transmitter);
|
223 | } while(I2C_WaitForEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);
|
224 |
|
225 | // Sequenz abschliessen
|
226 | I2C_GenerateSTOP(I2C_CHANNEL, ENABLE);
|
227 |
|
228 | return SUCCESS;
|
229 | }
|