YAHAL
Yet Another Hardware Abstraction Library
Loading...
Searching...
No Matches
soft_i2c_slave.h
1// ---------------------------------------------
2// This file is part of
3// _ _ __ _ _ __ __
4// ( \/ ) /__\ ( )_( ) /__\ ( )
5// \ / /(__)\ ) _ ( /(__)\ )(__
6// (__)(__)(__)(_) (_)(__)(__)(____)
7//
8// Yet Another HW Abstraction Library
9// Copyright (C) Andreas Terstegge
10// BSD Licensed (see file LICENSE)
11//
12// ---------------------------------------------
13//
14// This is a I2C slave driver implemented in SW.
15// The I2C protocol is decoded with 2 GPIO lines,
16// which need support for both edge interrupts. The
17// interrupt handlers generate 5 events (start, stop,
18// high, low, SCL falling), which in turn are processed
19// by a state machine. The user code has to provide 3
20// callback methods, which are used within the state
21// machine:
22//
23// bool receive(uint8_t index, uint8_t data)
24//
25// This method is called when the state machine has
26// received a complete byte. The index is a number
27// being incremented within one Start sequence, starting
28// from 0.
29//
30// uint8_t transmit(uint8_t index)
31//
32// This method is called when the state machine needs
33// a new byte to send.
34//
35// void stop()
36//
37// This method is called when a stop-condition is detected.
38// It can be used to recognize restart conditions.
39
40#ifndef _SOFT_I2C_SLAVE_H_
41#define _SOFT_I2C_SLAVE_H_
42
43#include <gpio_interface.h>
44#include "soft_i2c_slave_states.h"
45
46#include <cstdint>
47#include <functional>
48
50
51 // The I2C states are our friends
52 friend class I2C::STATE;
53 friend class I2C::IDLE;
54 friend class I2C::READ_ADDR;
55 friend class I2C::WRITE_ACK;
56 friend class I2C::READ_DATA;
57 friend class I2C::WRITE_DATA;
58 friend class I2C::READ_ACK;
59
60public:
61 // The receive() handler passes received data to the user code.
62 // The index ranges from 0..N and counts every received/transmitted
63 // byte (without the slave addresses) after a start condition.
64 // So for a I2C sequence with repeated starts, the index starts
65 // with 0 after every start condition. Stop conditions can be
66 // detected with the stop() callback.
67 // The transmit() handler asks for new user data to be sent. The
68 // index is the save as for read operations (0 for the first byte
69 // after the I2C address).
70 soft_i2c_slave(gpio_interface & sda, gpio_interface & scl, bool pullup = false);
71
72 void set_callbacks(std::function<bool(uint16_t index, uint8_t data)> receive,
73 std::function<uint8_t(uint16_t index)> transmit,
74 std::function<void()> stop);
75
76 virtual ~soft_i2c_slave();
77
78 // Getter/Setter for slaves I2C address it listens to
79 inline uint8_t getI2cAddress() {
80 return _i2c_address;
81 }
82 inline void setI2cAddress(uint8_t a) {
83 if (!_init) init();
84 _i2c_address = a;
85 }
86
87 // No copy, no assignment
88 soft_i2c_slave (const soft_i2c_slave &) = delete;
89 soft_i2c_slave & operator = (const soft_i2c_slave &) = delete;
90
91private:
92 // HW attributes
93 gpio_interface & _sda;
94 gpio_interface & _scl;
95 bool _init;
96 bool _pullup;
97
98 // callback methods
99 std::function<bool (uint16_t index, uint8_t data)> _receive;
100 std::function<uint8_t(uint16_t index)> _transmit;
101 std::function<void()> _stop;
102
103 uint8_t _i2c_address; // the I2C address of the slave
104
105 // State instances
106 I2C::STATE * _state; // current state
107 I2C::IDLE _idle;
108 I2C::READ_ADDR _read_addr;
109 I2C::WRITE_ACK _write_ack;
110 I2C::READ_DATA _read_data;
111 I2C::WRITE_DATA _write_data;
112 I2C::READ_ACK _read_ack;
113
114 // Variables for inter-State communication
115 bool _ack; // acknowledge state
116 int _byte_index; // data byte index 0...N within one start sequence
117 bool _send; // I2C read or write
118
119 void init();
120
121 inline void setState(I2C::STATE * s) {
122 if (_state) { _state->leave(); }
123 _state = s;
124 if (_state) { _state->enter(); }
125 }
126};
127
128#endif // _SOFT_I2C_SLAVE_H_