1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
|
//******************************************************************************
// @file StHalIic.cpp
// @author Nicolai Shlapunov
//
// @details DevCore: STM32 HAL I2C driver, implementation
//
// @copyright Copyright (c) 2018, Devtronic & Nicolai Shlapunov
// All rights reserved.
//
// @section SUPPORT
//
// Devtronic invests time and resources providing this open source code,
// please support Devtronic and open-source hardware/software by
// donations and/or purchasing products from Devtronic.
//
//******************************************************************************
// *****************************************************************************
// *** Includes ************************************************************
// *****************************************************************************
#include "StHalIic.h"
// *****************************************************************************
// *** This driver can be compiled only if I2C configured in CubeMX ********
// *****************************************************************************
#ifdef HAL_I2C_MODULE_ENABLED
// *****************************************************************************
// *** Public: Enable ******************************************************
// *****************************************************************************
Result StHalIic::Enable()
{
// Set PE bit
__HAL_I2C_ENABLE(&hi2c);
// No errors to return
return Result::RESULT_OK;
}
// *****************************************************************************
// *** Public: Disable *****************************************************
// *****************************************************************************
Result StHalIic::Disable()
{
// Clear PE bit
__HAL_I2C_DISABLE(&hi2c);
// No errors to return
return Result::RESULT_OK;
}
// *****************************************************************************
// *** Public: Reset *******************************************************
// *****************************************************************************
Result StHalIic::Reset()
{
// Clear PE bit
CLEAR_BIT(hi2c.Instance->CR1, I2C_CR1_PE);
// PE must be kept low during at least 3 APB clock cycles in order to
// perform the software reset. Wait until it actually cleared.
while(READ_BIT(hi2c.Instance->CR1, I2C_CR1_PE));
// TODO: make some clock on the SCL line here
// Set PE bit
SET_BIT(hi2c.Instance->CR1, I2C_CR1_PE);
// No errors to return
return Result::RESULT_OK;
}
// *************************************************************************
// *** Public: IsDeviceReady *******************************************
// *************************************************************************
Result StHalIic::IsDeviceReady(uint16_t addr, uint8_t retries)
{
Result result;
// Shift address one bit left - HAL blow away LSB, not MSB.
addr <<= 1U;
// Check device status
HAL_StatusTypeDef hal_result = HAL_I2C_IsDeviceReady(&hi2c1, addr, retries, i2c_tx_timeout_ms);
// Convert operation result to Result
result = ConvertResult(hal_result);
// Return result
return result;
}
// *****************************************************************************
// *** Public: Transfer ****************************************************
// *****************************************************************************
Result StHalIic::Transfer(uint16_t addr, uint8_t* tx_buf_ptr, uint32_t tx_size, uint8_t* rx_buf_ptr, uint32_t rx_size)
{
Result result = Result::ERR_NULL_PTR;
// Special hack for use HAL_I2C_Mem_Read() function for send Repeated Start if
// tx_size is 1 or 2 bytes.
if((tx_buf_ptr != nullptr) && (rx_buf_ptr != nullptr) && ((tx_size == 1U) || (tx_size == 2U)))
{
// Variable for store result from the HAL
HAL_StatusTypeDef hal_result = HAL_OK;
// Shift address one bit left - HAL blow away LSB, not MSB.
addr <<= 1U;
// Transmit data
hal_result = HAL_I2C_Mem_Read(&hi2c, addr, tx_buf_ptr[0], tx_size, rx_buf_ptr, rx_size, i2c_tx_timeout_ms);
// Convert operation result to Result
result = ConvertResult(hal_result);
}
else
{
if(tx_buf_ptr != nullptr)
{
// Transmit data
result = Write(addr, tx_buf_ptr, tx_size);
}
if((rx_buf_ptr != nullptr) && result.IsGood())
{
// Clear RX buffer
for(uint32_t i = 0; i < rx_size; i++)
{
rx_buf_ptr[i] = 0;
}
// Receive data
result = Read(addr, rx_buf_ptr, rx_size);
}
}
return result;
}
// *****************************************************************************
// *** Public: Write *******************************************************
// *****************************************************************************
Result StHalIic::Write(uint16_t addr, uint8_t* tx_buf_ptr, uint32_t tx_size)
{
Result result = Result::ERR_NULL_PTR;
if(tx_buf_ptr != nullptr)
{
// Variable for store result from the HAL
HAL_StatusTypeDef hal_result = HAL_OK;
// Shift address one bit left - HAL blow away LSB, not MSB.
addr <<= 1U;
// Transmit data
hal_result = HAL_I2C_Master_Transmit(&hi2c, addr, tx_buf_ptr, tx_size, i2c_tx_timeout_ms);
// Convert operation result to Result
result = ConvertResult(hal_result);
}
return result;
}
// *****************************************************************************
// *** Public: Read ********************************************************
// *****************************************************************************
Result StHalIic::Read(uint16_t addr, uint8_t* rx_buf_ptr, uint32_t rx_size)
{
Result result = Result::ERR_NULL_PTR;
if(rx_buf_ptr != nullptr)
{
// Variable for store result from the HAL
HAL_StatusTypeDef hal_result = HAL_OK;
// Shift address one bit left - HAL blow away LSB, not MSB.
addr <<= 1U;
// Transmit data
hal_result = HAL_I2C_Master_Receive(&hi2c, addr, rx_buf_ptr, rx_size, i2c_tx_timeout_ms);
// Convert operation result to Result
result = ConvertResult(hal_result);
}
return result;
}
// *****************************************************************************
// *** Public: WriteAsync **************************************************
// *****************************************************************************
Result StHalIic::WriteAsync(uint16_t addr, uint8_t* tx_buf_ptr, uint32_t tx_size)
{
Result result = Result::ERR_NOT_IMPLEMENTED;
// Check DMA handler - if it is nullptr this function not implemented in hardware
if(hi2c.hdmatx != nullptr)
{
// Shift address one bit left - HAL blow away LSB, not MSB.
addr <<= 1U;
// Receive data using DMA
HAL_StatusTypeDef hal_result = HAL_I2C_Master_Transmit_DMA(&hi2c, addr, tx_buf_ptr, tx_size);
// Convert operation result to Result
result = ConvertResult(hal_result);
}
return result;
}
// *****************************************************************************
// *** Public: ReadAsync ***************************************************
// *****************************************************************************
Result StHalIic::ReadAsync(uint16_t addr, uint8_t* rx_buf_ptr, uint32_t rx_size)
{
Result result = Result::ERR_NOT_IMPLEMENTED;
// Check DMA handler - if it is nullptr this function not implemented in hardware
if(hi2c.hdmarx != nullptr)
{
// Shift address one bit left - HAL blow away LSB, not MSB.
addr <<= 1U;
// Receive data using DMA
HAL_StatusTypeDef hal_result = HAL_I2C_Master_Receive_DMA(&hi2c, addr, rx_buf_ptr, rx_size);
// Convert operation result to Result
result = ConvertResult(hal_result);
}
return result;
}
// *****************************************************************************
// *** Public: Transfer ****************************************************
// *****************************************************************************
bool StHalIic::IsBusy(void)
{
return (hi2c.State != HAL_I2C_STATE_READY);
}
// *****************************************************************************
// *** Private: ConvertResult **********************************************
// *****************************************************************************
Result StHalIic::ConvertResult(HAL_StatusTypeDef hal_result)
{
Result result = Result::RESULT_OK;
// Convert operation result to Result
switch(hal_result)
{
case HAL_OK:
result = Result::RESULT_OK;
break;
case HAL_ERROR:
result = Result::ERR_I2C_GENERAL;
break;
case HAL_BUSY:
result = Result::ERR_I2C_BUSY;
break;
case HAL_TIMEOUT:
result = Result::ERR_I2C_TIMEOUT;
break;
default:
result = Result::ERR_SPI_UNKNOWN;
break;
}
// Return result
return result;
}
#endif
|