Bare Metal Programming Tool Kit
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
spi.h
Go to the documentation of this file.
1 //***************************************************************************
2 //
3 // file : bmptk/hardware/spi.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 //
47 template<
48  class sclk_extern,
49  class mosi_extern,
50  class miso_extern,
51  unsigned int frequency = 1 * bmptk::MHz
53 
55  enum { type = type_spi_bus };
56 
57  static_assert(
58  ( (int)sclk_extern::type == bmptk::type_port_out )
59  | ( (int)sclk_extern::type == bmptk::type_pin_in_out )
60  | ( (int)sclk_extern::type == bmptk::type_pin_oc ),
61  "sclk must be a port_out, pin_in_out or a pin_oc"
62  );
63  static_assert(
64  ( (int)mosi_extern::type == bmptk::type_pin_out )
65  | ( (int)mosi_extern::type == bmptk::type_pin_in_out )
66  | ( (int)mosi_extern::type == bmptk::type_pin_oc ),
67  "mosi must be a pin_out, pin_in_out or a pin_oc"
68  );
69  static_assert(
70  ( (int)miso_extern::type == bmptk::type_pin_in )
71  | ( (int)miso_extern::type == bmptk::type_pin_in_out )
72  | ( (int)miso_extern::type == bmptk::type_pin_oc ),
73  "miso must be a pin_out, pin_in_out or a pin_oc"
74  );
75 
78 
81 
84 
86  static void wait(){
87  static bmptk::time epoch = 0 * bmptk::us;
88  epoch += bmptk::s / ( 2 * frequency );
89  bmptk::wait_until( epoch );
90  epoch = bmptk::current_time();
91  }
92 
94  static void init(){
95  sclk::init();
96  mosi::init();
97  miso::init();
98  }
99 
100 };
101 
103 enum spi_mode {
104 
106  //
110 
112  //
116 
118  //
122 
124  //
128 };
129 
130 
132 //
139 template<
140  typename bus,
141  typename ss_extern,
142  int mode = spi_mode_0
143 > class spi_channel {
144 private:
145 
146  static const bool cpha = ( mode & 0x01 ) != 0;
147  static const bool cpol = ( mode & 0x02 ) != 0;
148 
149  static_assert(
150  ( (int)bus::type == bmptk::type_spi_bus ),
151  "bus must be a spi bus"
152  );
153 
154  static_assert(
155  ( (int)ss_extern::type == bmptk::type_pin_out )
156  | ( (int)ss_extern::type == bmptk::type_pin_in_out )
157  | ( (int)ss_extern::type == bmptk::type_pin_oc ),
158  "ss must be a pin_out, pin_in_out or a pin_oc"
159  );
160 
163 
164  static unsigned char byte_in_out(
165  unsigned char out
166  ){
167  int in = 0;
168  bus::wait();
169  for( int i = 0; i < 8; i++ ){
170 
171  in = in << 1;
172 
173  if( cpha == 0 ){
174 
175  bus::mosi::set( out & 0x80 );
176  bus::wait();
177 
178  bus::sclk::set( ! cpol );
179  if( bus::miso::get() ){
180  in |= 0x80;
181  }
182 
183  bus::wait();
184  bus::sclk::set( cpol );
185 
186  } else {
187 
188  bus::sclk::set( ! cpol );
189  bus::wait();
190 
191  bus::mosi::set( out & 0x80 );
192  bus::sclk::set( cpol );
193  bus::wait();
194 
195  if( bus::miso::get() ){
196  in |= 0x80;
197  }
198  }
199  out = out << 1;
200  }
201  return in;
202  }
203 
204 public:
205 
207  enum { type = type_spi_channel };
208 
210  static void init(){
211  bus::init();
212  ss::init();
213  }
214 
216  //
223  static void transaction_in_out_n(
224  unsigned char *input,
225  unsigned char *output,
226  int n_bytes
227  ){
228  bus::sclk::set( cpol );
229  ss::set( 0 );
230 
231  while( n_bytes-- ){
232  unsigned char in, out = 0;
233  if( output ){
234  out = *output++;
235  }
236  in = byte_in_out( out );
237  if( input ){
238  *input++ = in;
239  }
240  }
241 
242  ss::set( 1 );
243  }
244 
246  static void transaction_in_n(
247  unsigned char *input,
248  int n_bytes
249  ){
250  transaction_in_out_n( input, 0, n_bytes );
251  }
252 
254  static void transaction_out_n(
255  unsigned char *output,
256  int n_bytes
257  ){
258  transaction_in_out_n( 0, output, n_bytes );
259  }
260 
261 };
262 
263 }; // namespace hardware
264 }; // namespace bmptk