libpropeller
Making PropellerGCC Easier
 All Classes Files Functions Variables Enumerations Enumerator Macros Pages
i2c_base.h
Go to the documentation of this file.
1 #ifndef LIBPROPELLER_I2C_BASE_H_
2 #define LIBPROPELLER_I2C_BASE_H_
3 
4 #include <propeller.h>
5 
6 #define I2C_FLOAT_SCL_HIGH (DIRA &= ~scl_mask_)
7 #define I2C_SET_SCL_LOW (DIRA |= scl_mask_)
8 #define I2C_FLOAT_SDA_HIGH (DIRA &= ~sda_mask_)
9 #define I2C_SET_SDA_LOW (DIRA |= sda_mask_)
10 
11 //Note: refactoring this into it's own class took all of 8 bytes extra :^)
12 
19 class I2CBase {
20 public:
21 
30  void Init(const int scl = 28, const int sda = 29, const int frequency = 400000) {
31  scl_mask_ = 1 << scl;
32  sda_mask_ = 1 << sda;
33 
34  SetFrequency(frequency);
35 
36  //Set pins to input
39 
40 
41  //Set outputs low
42  OUTA &= ~scl_mask_;
43  OUTA &= ~sda_mask_;
44 
45 
46  }
47 
51  void SetFrequency(const int frequency){
52 
53 
54  //Clock delay values (@80MHz system clock):
55  // 1600 == 25kHz
56  // 400 == 100kHz
57  // 100 == 400kHz
58  // 90 == 444kHz
59  // 32 == 1.25MHz
60 
61 
62 
63  //clock_delay_ = 100; //90;
64 
65  clock_delay_ = CLKFREQ/(2*frequency);
66 
67  }
68 
71  void Start(void) {
76  }
77 
80  void Stop(void) {
83  }
84 
90  bool SendByte(const unsigned char byte) {
91  int result;
92 
93  int datamask, nextCNT, temp;
94 
95  __asm__ volatile(
96  " fcache #(PutByteEnd - PutByteStart)\n\t"
97  " .compress off \n\t"
98  /* Setup for transmit loop */
99  "PutByteStart: "
100  " mov %[datamask], #256 \n\t" /* 0x100 */
101  " mov %[result], #0 \n\t"
102  " mov %[nextCNT], cnt \n\t"
103  " add %[nextCNT], %[clockDelay] \n\t"
104 
105  /* Transmit Loop (8x) */
106  //Output bit of byte
107  "PutByteLoop: "
108  " shr %[datamask], #1 \n\t" // Set up mask
109  " and %[datamask], %[databyte] wz,nr \n\t" // Move the bit into Z flag
110  " muxz dira, %[SDAMask] \n\t"
111 
112  //Pulse clock
113  " waitcnt %[nextCNT], %[clockDelay] \n\t"
114  " andn dira, %[SCLMask] \n\t" // Set SCL high
115  " waitcnt %[nextCNT], %[clockDelay] \n\t"
116  " or dira, %[SCLMask] \n\t" // Set SCL low
117 
118  //Return for more bits
119  " djnz %[datamask], #__LMM_FCACHE_START+(PutByteLoop-PutByteStart) nr \n\t"
120 
121  // Get ACK
122  " andn dira, %[SDAMask] \n\t" // Float SDA high (release SDA)
123  " waitcnt %[nextCNT], %[clockDelay] \n\t"
124  " andn dira, %[SCLMask] \n\t" // SCL high (by float)
125  " waitcnt %[nextCNT], %[clockDelay] \n\t"
126  " mov %[temp], ina \n\t" //Sample input
127  " and %[SDAMask], %[temp] wz,nr \n\t" // If != 0, ack'd, else nack
128  " muxz %[result], #1 \n\t" // Set result to equal to Z flag (aka, 1 if ack'd)
129  " or dira, %[SCLMask] \n\t" // Set scl low
130  " or dira, %[SDAMask] \n\t" // Set sda low
131  " jmp __LMM_RET \n\t"
132  "PutByteEnd: "
133  " .compress default \n\t"
134  : // Outputs
135  [datamask] "=&r" (datamask),
136  [result] "=&r" (result),
137  [nextCNT] "=&r" (nextCNT),
138  [temp] "=&r" (temp)
139  : // Inputs
140  [SDAMask] "r" (sda_mask_),
141  [SCLMask] "r" (scl_mask_),
142  [databyte] "r" (byte),
143  [clockDelay] "r" (clock_delay_)
144  );
145 
146  return result;
147  }
148 
154  unsigned char ReadByte(const bool acknowledge) {
155 
156  int result = 0;
157  int datamask, nextCNT, temp;
158 
159  __asm__ volatile(
160  " fcache #(GetByteEnd - GetByteStart)\n\t"
161  " .compress off \n\t"
162  // Setup for receive loop
163  "GetByteStart: "
164  " andn dira, %[SDAMask] \n\t"
165  " mov %[datamask], #256 \n\t" /* 0x100 */
166  " mov %[result], #0 \n\t"
167  " mov %[nextCNT], cnt \n\t"
168  " add %[nextCNT], %[clockDelay] \n\t"
169 
170  // Recieve Loop (8x)
171  //Get bit of byte
172  "GetByteLoop: "
173 
174  " waitcnt %[nextCNT], %[clockDelay] \n\t"
175  " shr %[datamask], #1 \n\t" // Set up mask
176 
177  //Pulse clock
178  " andn dira, %[SCLMask] \n\t" // Set SCL high
179  " waitcnt %[nextCNT], %[clockDelay] \n\t"
180  " mov %[temp], ina \n\t" //Sample the input
181  " and %[temp], %[SDAMask] nr,wz \n\t"
182  " muxnz %[result], %[datamask] \n\t"
183  " or dira, %[SCLMask] \n\t" // Set SCL low
184 
185  //Return for more bits
186  " djnz %[datamask], #__LMM_FCACHE_START+(GetByteLoop-GetByteStart) nr \n\t"
187 
188  // Put ACK
189 
190  " and %[acknowledge], #1 nr,wz \n\t" //Output ACK
191 
192  " muxnz dira, %[SDAMask] \n\t"
193  " waitcnt %[nextCNT], %[clockDelay] \n\t"
194  " andn dira, %[SCLMask] \n\t" // SCL high (by float)
195  " waitcnt %[nextCNT], %[clockDelay] \n\t"
196 
197  " or dira, %[SCLMask] \n\t" // Set scl low
198  " or dira, %[SDAMask] \n\t" // Set sda low
199  " jmp __LMM_RET \n\t"
200  "GetByteEnd: "
201  " .compress default \n\t"
202 
203  : // Outputs
204  [datamask] "=&r" (datamask),
205  [result] "=&r" (result),
206  [temp] "=&r" (temp),
207  [nextCNT] "=&r" (nextCNT)
208 
209  : // Inputs
210  [SDAMask] "r" (sda_mask_),
211  [SCLMask] "r" (scl_mask_),
212  [acknowledge] "r" (acknowledge),
213  [clockDelay] "r" (clock_delay_)
214  );
215 
216  return result;
217 
218  }
219 
220 private:
221  unsigned int scl_mask_;
222  unsigned int sda_mask_;
223 
224  int clock_delay_;
225 
226 };
227 
228 
229 
230 #endif // LIBPROPELLER_I2C_BASE_H_