Bare Metal Programming Tool Kit
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
i2c.h
Go to the documentation of this file.
1 //***************************************************************************
2 //
3 // file : bmptk/hardware/i2c.h
4 //
5 // LICENSE (MIT expat license, copy of license.txt)
6 //
7 // Copyright (c) 2013 Wouter van Ooijen (wouter@voti.nl)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included
18 // in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE..
27 //
28 //***************************************************************************
29 
30 // document everything in this file
33 namespace bmptk {
34 namespace hardware {
35 
37 class i2c_interface {
38 public:
39 
41  enum { type = type_i2c_bus };
42 
44  static void init();
45 
47  static void put_start();
48 
50  static void put_stop();
51 
53  //
59  static bool get_ack();
60 
62  static void put_ack();
63 
65  static void put_nack();
66 
68  static void put_byte( unsigned char x );
69 
71  static unsigned char get_byte();
72 
74  //
77  static void write( unsigned char address, unsigned const char *data, int n ){
78  put_start();
79  put_byte( address << 1 );
80  for( int i = 0; i < n; i++ ){
81  get_ack();
82  put_byte( data[ i ] );
83  }
84  get_ack();
85  put_stop();
86  }
87 
89  //
92  static void read( unsigned char address, unsigned char *data, int n ){
93  put_start();
94  put_byte( ( address << 1 ) | 0x01 );
95  for( int i = 0; i < n; i++ ){
96  get_ack();
97  data[ i ] = get_byte();
98  }
99  put_stop();
100  }
101 
102 };
103 
105 //
113 template<
114  class extern_scl,
115  class extern_sda,
116  unsigned int frequency = 1 * bmptk::MHz
117 >
118 class i2c_master : public i2c_interface {
119 private:
120 
121  static_assert(
122  ( (int)extern_scl::type == bmptk::type_pin_out )
123  | ( (int)extern_scl::type == bmptk::type_pin_in_out )
124  | ( (int)extern_scl::type == bmptk::type_pin_oc ),
125  "scl must be a pin_out, pin_in_out or a pin_oc"
126  );
127  static_assert(
128  ( (int)extern_sda::type == bmptk::type_pin_out )
129  | ( (int)extern_sda::type == bmptk::type_pin_in_out )
130  | ( (int)extern_sda::type == bmptk::type_pin_oc ),
131  "sda must be a pin_out, pin_in_out or a pin_oc"
132  );
133 
136 
138  static void delay_half_period(){
139  static bmptk::time epoch = 0 * bmptk::us;
140  epoch += bmptk::s / ( 2 * frequency );
141  bmptk::wait_until( epoch );
142  epoch = bmptk::current_time();
143  }
144 
146  static void put_bit( bool x ){
147  scl::set( 0 );
148  delay_half_period();
149  sda::set( x );
150  scl::set( 1 );
151  delay_half_period();
152  }
153 
155  static bool get_bit(){
156  scl::set( 0 );
157  delay_half_period();
158  sda::set( 1 );
159  scl::set( 1 );
160  delay_half_period();
161  bool result = sda::get();
162  delay_half_period();
163  return result;
164  }
165 
166 public:
167 
169  static void init(){
170  scl::init();
171  sda::init();
172  scl::set( 1 );
173  sda::set( 1 );
174  }
175 
177  static void put_start(){
178  sda::set( 0 );
179  delay_half_period();
180  scl::set( 0 );
181  delay_half_period();
182  }
183 
185  static void put_stop(){
186  scl::set( 0 );
187  delay_half_period();
188  sda::set( 0 );
189  delay_half_period();
190  scl::set( 1 );
191  delay_half_period();
192  sda::set( 1 );
193  delay_half_period();
194  }
195 
197  static bool get_ack(){
198  bool ack = ! get_bit();
199  return ack;
200  }
201 
203  static void put_ack(){
204  put_bit( 0 );
205  }
206 
208  static void put_nack(){
209  put_bit( 1 );
210  }
211 
213  static void put_byte( unsigned char x ){
214  for( int i = 0; i < 8; i++ ){
215  put_bit( ( x & 0x80 ) != 0 );
216  x = x << 1;
217  }
218  }
219 
221  static unsigned char get_byte(){
222  unsigned char result = 0;
223  for( int i = 0; i < 8; i++ ){
224  result = result << 1;
225  if( get_bit() ){
226  result |= 0x01;
227  }
228  }
229  return result;
230  }
231 
232 };
233 
234 
235 }; // namespace hardware
236 }; // namespace bmptk