semf
softi2cmaster.cpp
Go to the documentation of this file.
1
12
13namespace semf
14{
16: m_scl(scl),
17 m_sda(sda),
18 m_timer(timer)
19{
20}
21
23{
24 SEMF_INFO("start init");
25 m_timer.timeout.connect(m_timemoutSlot);
26 m_scl.set();
27 m_sda.set();
28 m_scl.setDirection(Gpio::Direction::OutputOpendrain);
29 m_sda.setDirection(Gpio::Direction::OutputOpendrain);
30 m_scl.set();
31 m_sda.set();
32 m_bitIndex = 7;
34 m_lastOperationWasWrite = false;
35 m_acknowledgeError = false;
36 m_data = nullptr;
37 m_dataSize = 0;
38 m_dataIndex = 0;
39}
40
42{
43 SEMF_INFO("start deinit");
44 m_timer.timeout.clear();
45 m_scl.setDirection(Gpio::Direction::Input);
46 m_sda.setDirection(Gpio::Direction::Input);
47}
48
50{
51 SEMF_INFO("stop write");
52 deinit();
53 init();
54}
55
57{
58 SEMF_INFO("stop read");
59 deinit();
60 init();
61}
62
63void SoftI2cMaster::writeHardware(const uint8_t data[], size_t size)
64{
65 SEMF_INFO("write data %p with size %u", data, size);
66 m_data = const_cast<uint8_t*>(data);
67 m_dataSize = size;
68 m_dataIndex = 0;
69 m_bitIndex = 7;
70 m_acknowledgeError = false;
71
73 {
74 m_activeByte = address() << 1;
75 m_writingAddress = true;
76 startConditionResetSda();
77 }
78 else
79 {
80 writeByte();
81 }
82 m_lastFrame = frame();
83 m_lastOperationWasWrite = true;
84}
85
86void SoftI2cMaster::readHardware(uint8_t buffer[], size_t bufferSize)
87{
88 SEMF_INFO("read data %p with size %u", buffer, bufferSize);
89 m_data = buffer;
90 m_dataSize = bufferSize;
91 m_dataIndex = 0;
92 m_bitIndex = 7;
93 m_acknowledgeError = false;
94
96 {
97 m_activeByte = static_cast<uint8_t>((address() << 1) | 0x01);
98 m_writingAddress = true;
99 startConditionResetSda();
100 }
101 else if (m_lastOperationWasWrite && (m_lastFrame == CommunicationHardware::Frame::First || m_lastFrame == CommunicationHardware::Frame::Next))
102 {
103 m_activeByte = static_cast<uint8_t>((address() << 1) | 0x01);
104 m_writingAddress = true;
105 resartConditionSetSdaResetScl();
106 }
107 else
108 {
109 readByte();
110 }
111 m_lastFrame = frame();
112 m_lastOperationWasWrite = false;
113}
114
115void SoftI2cMaster::resartConditionSetSdaResetScl()
116{
117 SEMF_INFO("do restart condition (followed by start condition)");
118 m_sda.set();
119 m_scl.reset();
120 m_timemoutSlot.setFunction(SEMF_SLOT_FUNC(resartConditionSetScl));
121}
122
123void SoftI2cMaster::resartConditionSetScl()
124{
125 m_scl.set();
126 m_timemoutSlot.setFunction(SEMF_SLOT_FUNC(startConditionResetSda));
127}
128
129void SoftI2cMaster::startConditionResetSda()
130{
131 SEMF_INFO("do start condition");
132 m_sda.reset();
133 m_timemoutSlot.setFunction(SEMF_SLOT_FUNC(startConditionResetScl));
134}
135
136void SoftI2cMaster::startConditionResetScl()
137{
138 m_scl.reset();
139 writeByte();
140}
141
142void SoftI2cMaster::writeByte()
143{
144 if (m_writingAddress)
145 {
146 SEMF_INFO("start write address: %u", m_activeByte);
147 }
148 else
149 {
150 m_activeByte = m_data[m_dataIndex];
151 SEMF_INFO("start write byte: %u", m_activeByte);
152 }
153 writeByteSetSdaDataBit();
154}
155
156void SoftI2cMaster::writeByteSetSdaDataBit()
157{
158 // Set or reset sda
159 if (m_activeByte & (1 << m_bitIndex))
160 m_sda.set();
161 else
162 m_sda.reset();
163 m_timemoutSlot.setFunction(SEMF_SLOT_FUNC(writeByteSetScl));
164}
165
166void SoftI2cMaster::writeByteSetScl()
167{
168 m_scl.set();
169 m_timemoutSlot.setFunction(SEMF_SLOT_FUNC(writeByteResetScl));
170}
171
172void SoftI2cMaster::writeByteResetScl()
173{
174 m_scl.reset();
175 m_timer.timeout.clear();
176 // Byte not finished -> next bit and goto onWriteByteSetSclLow
177 if (m_bitIndex > 0)
178 {
179 m_bitIndex--;
180 writeByteSetSdaDataBit();
181 }
182 // Byte finished -> goto checkAcknolage
183 else
184 {
185 m_bitIndex = 7;
186 checkAcknowledgeSetSdaInput();
187 }
188}
189
190void SoftI2cMaster::readByte()
191{
192 SEMF_INFO("start read byte");
193 m_sda.set();
194 m_sda.setDirection(Gpio::Direction::Input);
195 m_activeByte = 0x00;
196 readByteReadSdaDataBit();
197}
198
199void SoftI2cMaster::readByteReadSdaDataBit()
200{
201 // Read bit status
202 if (m_sda.state())
203 {
204 m_activeByte = static_cast<uint8_t>(m_activeByte | (1 << m_bitIndex));
205 }
206 m_timemoutSlot.setFunction(SEMF_SLOT_FUNC(readByteSetScl));
207}
208
209void SoftI2cMaster::readByteSetScl()
210{
211 m_scl.set();
212 m_timemoutSlot.setFunction(SEMF_SLOT_FUNC(readByteResetScl));
213}
214
215void SoftI2cMaster::readByteResetScl()
216{
217 m_timer.timeout.clear();
218 m_scl.reset();
219 if (m_bitIndex > 0)
220 {
221 m_bitIndex--;
222 // Read bit status
223 if (m_sda.state())
224 m_activeByte = static_cast<uint8_t>(m_activeByte | (1 << m_bitIndex));
225 readByteReadSdaDataBit();
226 }
227 // Byte finished -> goto checkAcknolage
228 else
229 {
230 m_bitIndex = 7;
231 setAcknowledgeSetSdaOutput();
232 }
233}
234
235void SoftI2cMaster::checkAcknowledgeSetSdaInput()
236{
237 m_sda.set();
238 m_sda.setDirection(Gpio::Direction::Input);
239 m_timemoutSlot.setFunction(SEMF_SLOT_FUNC(checkAcknowledgeSetScl));
240}
241
242void SoftI2cMaster::checkAcknowledgeSetScl()
243{
244 m_scl.set();
245 m_acknowledgeBit = m_sda.state();
246 m_timemoutSlot.setFunction(SEMF_SLOT_FUNC(checkAcknowledgeResetScl));
247}
248
249void SoftI2cMaster::checkAcknowledgeResetScl()
250{
251 m_scl.reset();
252 m_timer.timeout.clear();
253 m_sda.setDirection(Gpio::Direction::OutputOpendrain);
254 finishAcknowledge();
255}
256
257void SoftI2cMaster::setAcknowledgeSetSdaOutput()
258{
259 m_sda.setDirection(Gpio::Direction::OutputOpendrain);
260 if (m_dataIndex + 1 < m_dataSize)
261 m_sda.reset();
262 m_timemoutSlot.setFunction(SEMF_SLOT_FUNC(setAcknowledgeSetScl));
263}
264
265void SoftI2cMaster::setAcknowledgeSetScl()
266{
267 m_scl.set();
268 m_timemoutSlot.setFunction(SEMF_SLOT_FUNC(setAcknowledgeResetScl));
269}
270
271void SoftI2cMaster::setAcknowledgeResetScl()
272{
273 m_timer.timeout.clear();
274 m_scl.reset();
275 finishAcknowledge();
276}
277
278void SoftI2cMaster::finishAcknowledge()
279{
280 if (m_writingAddress)
281 {
282 m_writingAddress = false;
283 }
284 else
285 {
286 if (isBusyReading())
287 m_data[m_dataIndex] = m_activeByte;
288 m_dataIndex++;
289 }
290
291 if (isBusyReading())
292 finishAcknowledgeReadOperation();
293 else
294 finishAcknowledgeWriteOperation();
295}
296
297void SoftI2cMaster::finishAcknowledgeWriteOperation()
298{
299 // Acknowledge error -> Do stop condition and finish with error
300 if (m_acknowledgeBit)
301 {
302 m_acknowledgeError = true;
303 SEMF_INFO("nack");
304 stopConditionResetSda();
305 return;
306 }
307
308 // Finished
309 if (m_dataIndex == m_dataSize)
310 {
312 {
313 stopConditionResetSda();
314 }
315 else
316 {
317 SEMF_INFO("all bytes written");
319 }
320 }
321 // Write next byte
322 else
323 {
324 writeByte();
325 }
326}
327
328void SoftI2cMaster::finishAcknowledgeReadOperation()
329{
330 // Finished
331 if (m_dataIndex == m_dataSize)
332 {
333 m_sda.setDirection(Gpio::Direction::OutputPushpull);
334 m_sda.set();
336 {
337 stopConditionResetSda();
338 }
339 else
340 {
341 SEMF_INFO("all bytes read");
343 }
344 }
345 // Read next byte
346 else
347 {
348 readByte();
349 }
350}
351
352void SoftI2cMaster::stopConditionResetSda()
353{
354 SEMF_INFO("do stop condition");
355 m_sda.reset();
356 m_timemoutSlot.setFunction(SEMF_SLOT_FUNC(stopConditionSetScl));
357}
358
359void SoftI2cMaster::stopConditionSetScl()
360{
361 m_scl.reset();
362 m_scl.set();
363 m_timemoutSlot.setFunction(SEMF_SLOT_FUNC(stopConditionSetSda));
364}
365
366void SoftI2cMaster::stopConditionSetSda()
367{
368 m_timer.timeout.clear();
369 m_sda.set();
370 // Read operation
371 if (isBusyReading() && !m_acknowledgeError)
372 {
373 SEMF_INFO("all data read");
375 }
376 // Write operation
377 else if (isBusyWriting() && !m_acknowledgeError)
378 {
379 SEMF_INFO("all data written");
381 }
382 // Not allowed or acknowledge error
383 else
384 {
385 SEMF_INFO("nack error");
386 onError(Error(kSemfClassId, static_cast<uint32_t>(ErrorCode::StopConditionSetSda_NackError)));
387 }
388}
389
390void SoftI2cMaster::setFrequency(uint32_t hz)
391{
392 (void)hz;
393 SEMF_INFO("not implemented");
394}
395} /* namespace semf */
@ FirstAndLast
start AND stop condition
@ Next
no start AND no stop condition
@ First
start condition, but no stop condition
Interface class for using a GPIO pin of the microcontroller.
Definition: gpio.h:23
virtual void set()=0
virtual bool state() const =0
Returns the current state of the pin.
virtual void reset()=0
virtual void setDirection(Direction direction)=0
Sets the direction of a GPIO.
bool isBusyReading() const override
Communication hardware is busy reading at the moment.
CommunicationHardware::Frame frame() const
Returns the actual frame mode setting.
uint8_t address() const override
Returns the I2C slave device address.
void onError(Error thrown)
Is called if an error occurred by hardware read or write access. Will emit error signal.
bool isBusyWriting() const override
Communication hardware is busy writing at the moment.
void clear()
Disconnect all functions or methods.
Definition: signal.h:81
void connect(SlotBase< Arguments... > &slot)
Connect a method to the signal.
Definition: signal.h:94
void stopWrite() override
SoftI2cMaster(Gpio &scl, Gpio &sda, app::Timer &timer)
Constructor.
void stopRead() override
void deinit() override
void writeHardware(const uint8_t data[], size_t size) override
Hardware will write data. After finished write operation, onDataWritten() function will be called.
void readHardware(uint8_t buffer[], size_t bufferSize) override
Hardware will read data. After finished read operation, onDataAvailable() function will be called.
void init() override
Class for using timer hardware.
Definition: timer.h:24
Signal timeout
Definition: timer.h:36
#define SEMF_INFO(...)
Definition: debug.h:41
#define SEMF_SLOT_FUNC(function)
Creates a binding to a given member function.
Definition: slot.h:21