64 boolean __attribute__ ((noinline)) i2c_init(
void);
69 bool __attribute__ ((noinline)) i2c_start(uint8_t addr);
73 void __attribute__ ((noinline)) i2c_start_wait(uint8_t addr);
79 bool __attribute__ ((noinline)) i2c_rep_start(uint8_t addr);
82 void __attribute__ ((noinline)) i2c_stop(
void) asm("ass_i2c_stop");
87 bool __attribute__ ((noinline)) i2c_write(uint8_t value) asm("ass_i2c_write");
91 uint8_t __attribute__ ((noinline)) i2c_read(
bool last);
97 #define I2C_CPUFREQ F_CPU
103 #define I2C_FASTMODE 0
110 #define I2C_SLOWMODE 0
118 #ifndef I2C_NOINTERRUPT
119 #define I2C_NOINTERRUPT 0
126 #define I2C_TIMEOUT 0
128 #if I2C_TIMEOUT > 10000
129 #error I2C_TIMEOUT is too large
133 #define I2C_TIMEOUT_DELAY_LOOPS (I2C_CPUFREQ/1000UL)*I2C_TIMEOUT/4000UL
134 #if I2C_TIMEOUT_DELAY_LOOPS < 1
135 #define I2C_MAX_STRETCH 1
137 #if I2C_TIMEOUT_DELAY_LOOPS > 60000UL
138 #define I2C_MAX_STRETCH 60000UL
140 #define I2C_MAX_STRETCH I2C_TIMEOUT_DELAY_LOOPS
145 #define I2C_DELAY_COUNTER (((I2C_CPUFREQ/400000L)/2-19)/3)
148 #define I2C_DELAY_COUNTER (((I2C_CPUFREQ/25000L)/2-19)/3)
150 #define I2C_DELAY_COUNTER (((I2C_CPUFREQ/100000L)/2-19)/3)
165 #define SDA_DDR (_SFR_IO_ADDR(SDA_PORT) - 1)
166 #define SCL_DDR (_SFR_IO_ADDR(SCL_PORT) - 1)
167 #define SDA_OUT _SFR_IO_ADDR(SDA_PORT)
168 #define SCL_OUT _SFR_IO_ADDR(SCL_PORT)
169 #define SDA_IN (_SFR_IO_ADDR(SDA_PORT) - 2)
170 #define SCL_IN (_SFR_IO_ADDR(SCL_PORT) - 2)
173 #define __tmp_reg__ 0
178 void __attribute__ ((noinline)) i2c_delay_half(
void) asm("ass_i2c_delay_half");
179 void __attribute__ ((noinline)) i2c_wait_scl_high(
void) asm("ass_i2c_wait_scl_high");
181 void i2c_delay_half(
void)
183 #if I2C_DELAY_COUNTER < 1
184 __asm__ __volatile__ (
" ret");
189 " ldi r25, %[DELAY] ;load delay constant ;; 4C \n\t"
191 " dec r25 ;decrement counter ;; 4C+xC \n\t"
192 " brne _Lidelay ;;5C+(x-1)2C+xC\n\t"
193 " ret ;; 9C+(x-1)2C+xC = 7C+xC"
194 : : [DELAY]
"M" I2C_DELAY_COUNTER :
"r25");
199 void i2c_wait_scl_high(
void)
203 (
"_Li2c_wait_stretch: \n\t"
204 " sbis %[SCLIN],%[SCLPIN] ;wait for SCL high \n\t"
205 " rjmp _Li2c_wait_stretch \n\t"
206 " cln ;signal: no timeout \n\t"
208 : : [SCLIN]
"I" (SCL_IN), [SCLPIN]
"I" (SCL_PIN));
211 (
" ldi r27, %[HISTRETCH] ;load delay counter \n\t"
212 " ldi r26, %[LOSTRETCH] \n\t"
213 "_Lwait_stretch: \n\t"
214 " clr __tmp_reg__ ;do next loop 255 times \n\t"
215 "_Lwait_stretch_inner_loop: \n\t"
216 " rcall _Lcheck_scl_level ;call check function ;; 12C \n\t"
217 " brpl _Lstretch_done ;done if N=0 ;; +1 = 13C\n\t"
218 " dec __tmp_reg__ ;dec inner loop counter;; +1 = 14C\n\t"
219 " brne _Lwait_stretch_inner_loop ;; +2 = 16C\n\t"
220 " sbiw r26,1 ;dec outer loop counter \n\t"
221 " brne _Lwait_stretch ;continue with outer loop \n\t"
222 " sen ;timeout -> set N-bit=1 \n\t"
223 " rjmp _Lwait_return ;and return with N=1\n\t"
224 "_Lstretch_done: ;SCL=1 sensed \n\t"
225 " cln ;OK -> clear N-bit \n\t"
226 " rjmp _Lwait_return ; and return with N=0 \n\t"
228 "_Lcheck_scl_level: ;; call = 3C\n\t"
229 " cln ;; +1C = 4C \n\t"
230 " sbic %[SCLIN],%[SCLPIN] ;skip if SCL still low ;; +2C = 6C \n\t"
231 " rjmp _Lscl_high ;; +0C = 6C \n\t"
232 " sen ;; +1 = 7C\n\t "
234 " nop ;; +1C = 8C \n\t"
235 " ret ;return N-Bit=1 if low ;; +4 = 12C\n\t"
238 : : [SCLIN]
"I" (SCL_IN), [SCLPIN]
"I" (SCL_PIN),
239 [HISTRETCH]
"M" (I2C_MAX_STRETCH>>8),
240 [LOSTRETCH]
"M" (I2C_MAX_STRETCH&0xFF)
246 boolean i2c_init(
void)
249 (
" cbi %[SDADDR],%[SDAPIN] ;release SDA \n\t"
250 " cbi %[SCLDDR],%[SCLPIN] ;release SCL \n\t"
251 " cbi %[SDAOUT],%[SDAPIN] ;clear SDA output value \n\t"
252 " cbi %[SCLOUT],%[SCLPIN] ;clear SCL output value \n\t"
253 " clr r24 ;set return value to false \n\t"
254 " clr r25 ;set return value to false \n\t"
255 " sbis %[SDAIN],%[SDAPIN] ;check for SDA high\n\t"
256 " ret ;if low return with false \n\t"
257 " sbis %[SCLIN],%[SCLPIN] ;check for SCL high \n\t"
258 " ret ;if low return with false \n\t"
259 " ldi r24,1 ;set return value to true \n\t"
262 [SCLDDR]
"I" (SCL_DDR), [SCLPIN]
"I" (SCL_PIN),
263 [SCLIN]
"I" (SCL_IN), [SCLOUT]
"I" (SCL_OUT),
264 [SDADDR]
"I" (SDA_DDR), [SDAPIN]
"I" (SDA_PIN),
265 [SDAIN]
"I" (SDA_IN), [SDAOUT]
"I" (SDA_OUT));
269 bool i2c_start(uint8_t addr)
274 " cli ;clear IRQ bit \n\t"
276 " sbis %[SCLIN],%[SCLPIN] ;check for clock stretching slave\n\t"
277 " rcall ass_i2c_wait_scl_high ;wait until SCL=H\n\t"
278 " sbi %[SDADDR],%[SDAPIN] ;force SDA low \n\t"
279 " rcall ass_i2c_delay_half ;wait T/2 \n\t"
280 " rcall ass_i2c_write ;now write address \n\t"
282 : : [SDADDR]
"I" (SDA_DDR), [SDAPIN]
"I" (SDA_PIN),
283 [SCLIN]
"I" (SCL_IN),[SCLPIN]
"I" (SCL_PIN));
287 bool i2c_rep_start(uint8_t addr)
295 " sbi %[SCLDDR],%[SCLPIN] ;force SCL low \n\t"
296 " rcall ass_i2c_delay_half ;delay T/2 \n\t"
297 " cbi %[SDADDR],%[SDAPIN] ;release SDA \n\t"
298 " rcall ass_i2c_delay_half ;delay T/2 \n\t"
299 " cbi %[SCLDDR],%[SCLPIN] ;release SCL \n\t"
300 " rcall ass_i2c_delay_half ;delay T/2 \n\t"
301 " sbis %[SCLIN],%[SCLPIN] ;check for clock stretching slave\n\t"
302 " rcall ass_i2c_wait_scl_high ;wait until SCL=H\n\t"
303 " sbi %[SDADDR],%[SDAPIN] ;force SDA low \n\t"
304 " rcall ass_i2c_delay_half ;delay T/2 \n\t"
305 " rcall ass_i2c_write \n\t"
307 : : [SCLDDR]
"I" (SCL_DDR), [SCLPIN]
"I" (SCL_PIN),[SCLIN]
"I" (SCL_IN),
308 [SDADDR]
"I" (SDA_DDR), [SDAPIN]
"I" (SDA_PIN));
312 void i2c_start_wait(uint8_t addr)
316 " push r24 ;save original parameter \n\t"
317 "_Li2c_start_wait1: \n\t"
318 " pop r24 ;restore original parameter\n\t"
319 " push r24 ;and save again \n\t"
321 " cli ;disable interrupts \n\t"
323 " sbis %[SCLIN],%[SCLPIN] ;check for clock stretching slave\n\t"
324 " rcall ass_i2c_wait_scl_high ;wait until SCL=H\n\t"
325 " sbi %[SDADDR],%[SDAPIN] ;force SDA low \n\t"
326 " rcall ass_i2c_delay_half ;delay T/2 \n\t"
327 " rcall ass_i2c_write ;write address \n\t"
328 " tst r24 ;if device not busy -> done \n\t"
329 " brne _Li2c_start_wait_done \n\t"
330 " rcall ass_i2c_stop ;terminate write & enable IRQ \n\t"
331 " rjmp _Li2c_start_wait1 ;device busy, poll ack again \n\t"
332 "_Li2c_start_wait_done: \n\t"
333 " pop __tmp_reg__ ;pop off orig argument \n\t"
335 : : [SDADDR]
"I" (SDA_DDR), [SDAPIN]
"I" (SDA_PIN),
336 [SCLIN]
"I" (SCL_IN),[SCLPIN]
"I" (SCL_PIN));
343 " sbi %[SCLDDR],%[SCLPIN] ;force SCL low \n\t"
344 " sbi %[SDADDR],%[SDAPIN] ;force SDA low \n\t"
345 " rcall ass_i2c_delay_half ;T/2 delay \n\t"
346 " cbi %[SCLDDR],%[SCLPIN] ;release SCL \n\t"
347 " rcall ass_i2c_delay_half ;T/2 delay \n\t"
348 " sbis %[SCLIN],%[SCLPIN] ;check for clock stretching slave\n\t"
349 " rcall ass_i2c_wait_scl_high ;wait until SCL=H\n\t"
350 " cbi %[SDADDR],%[SDAPIN] ;release SDA \n\t"
351 " rcall ass_i2c_delay_half \n\t"
353 " sei ;enable interrupts again!\n\t"
355 : : [SCLDDR]
"I" (SCL_DDR), [SCLPIN]
"I" (SCL_PIN), [SCLIN]
"I" (SCL_IN),
356 [SDADDR]
"I" (SDA_DDR), [SDAPIN]
"I" (SDA_PIN));
359 bool i2c_write(uint8_t value)
363 " sec ;set carry flag \n\t"
364 " rol r24 ;shift in carry and shift out MSB \n\t"
365 " rjmp _Li2c_write_first \n\t"
366 "_Li2c_write_bit:\n\t"
367 " lsl r24 ;left shift into carry ;; 1C\n\t"
368 "_Li2c_write_first:\n\t"
369 " breq _Li2c_get_ack ;jump if TXreg is empty;; +1 = 2C \n\t"
370 " sbi %[SCLDDR],%[SCLPIN] ;force SCL low ;; +2 = 4C \n\t"
374 " brcc _Li2c_write_low ;;+1/+2=5/6C\n\t"
375 " nop ;; +1 = 7C \n\t"
376 " cbi %[SDADDR],%[SDAPIN] ;release SDA ;; +2 = 9C \n\t"
377 " rjmp _Li2c_write_high ;; +2 = 11C \n\t"
378 "_Li2c_write_low: \n\t"
379 " sbi %[SDADDR],%[SDAPIN] ;force SDA low ;; +2 = 9C \n\t"
380 " rjmp _Li2c_write_high ;;+2 = 11C \n\t"
381 "_Li2c_write_high: \n\t"
382 #
if I2C_DELAY_COUNTER >= 1
383 " rcall ass_i2c_delay_half ;delay T/2 ;;+X = 11C+X\n\t"
385 " cbi %[SCLDDR],%[SCLPIN] ;release SCL ;;+2 = 13C+X\n\t"
386 " cln ;clear N-bit ;;+1 = 14C+X\n\t"
390 " sbis %[SCLIN],%[SCLPIN] ;check for SCL high ;;+2 = 16C+X\n\t"
391 " rcall ass_i2c_wait_scl_high \n\t"
392 " brpl _Ldelay_scl_high ;;+2 = 18C+X\n\t"
393 "_Li2c_write_return_false: \n\t"
394 " clr r24 ; return false because of timeout \n\t"
395 " rjmp _Li2c_write_return \n\t"
396 "_Ldelay_scl_high: \n\t"
397 #
if I2C_DELAY_COUNTER >= 1
398 " rcall ass_i2c_delay_half ;delay T/2 ;;+X= 18C+2X\n\t"
400 " rjmp _Li2c_write_bit \n\t"
401 " ;; +2 = 20C +2X for one bit-loop \n\t"
402 "_Li2c_get_ack: \n\t"
403 " sbi %[SCLDDR],%[SCLPIN] ;force SCL low ;; +2 = 5C \n\t"
406 " cbi %[SDADDR],%[SDAPIN] ;release SDA ;;+2 = 7C \n\t"
407 #
if I2C_DELAY_COUNTER >= 1
408 " rcall ass_i2c_delay_half ;delay T/2 ;; +X = 7C+X \n\t"
410 " clr r25 ;; 17C+2X \n\t"
411 " clr r24 ;return 0 ;; 14C + X \n\t"
412 " cbi %[SCLDDR],%[SCLPIN] ;release SCL ;; +2 = 9C+X\n\t"
413 "_Li2c_ack_wait: \n\t"
414 " cln ; clear N-bit ;; 10C + X\n\t"
416 " sbis %[SCLIN],%[SCLPIN] ;wait SCL high ;; 12C + X \n\t"
417 " rcall ass_i2c_wait_scl_high \n\t"
418 " brmi _Li2c_write_return_false ;; 13C + X \n\t "
419 " sbis %[SDAIN],%[SDAPIN] ;if SDA hi -> return 0 ;; 15C + X \n\t"
420 " ldi r24,1 ;return true ;; 16C + X \n\t"
421 #
if I2C_DELAY_COUNTER >= 1
422 " rcall ass_i2c_delay_half ;delay T/2 ;; 16C + 2X \n\t"
424 "_Li2c_write_return: \n\t"
427 " sbi %[SCLDDR],%[SCLPIN] ;force SCL low so SCL=H is short\n\t"
429 " ;; + 4 = 17C + 2X for acknowldge bit"
431 [SCLDDR]
"I" (SCL_DDR), [SCLPIN]
"I" (SCL_PIN), [SCLIN]
"I" (SCL_IN),
432 [SDADDR]
"I" (SDA_DDR), [SDAPIN]
"I" (SDA_PIN), [SDAIN]
"I" (SDA_IN));
436 uint8_t i2c_read(
bool last)
441 "_Li2c_read_bit: \n\t"
442 " sbi %[SCLDDR],%[SCLPIN] ;force SCL low ;; 2C \n\t"
443 " cbi %[SDADDR],%[SDAPIN] ;release SDA(prev. ACK);; 4C \n\t"
447 #
if I2C_DELAY_COUNTER >= 1
448 " rcall ass_i2c_delay_half ;delay T/2 ;; 4C+X \n\t"
450 " cbi %[SCLDDR],%[SCLPIN] ;release SCL ;; 6C + X \n\t"
451 #
if I2C_DELAY_COUNTER >= 1
452 " rcall ass_i2c_delay_half ;delay T/2 ;; 6C + 2X \n\t"
454 " cln ; clear N-bit ;; 7C + 2X \n\t"
458 " sbis %[SCLIN], %[SCLPIN] ;check for SCL high ;; 9C +2X \n\t"
459 " rcall ass_i2c_wait_scl_high \n\t"
460 " brmi _Li2c_read_return ;return if timeout ;; 10C + 2X\n\t"
461 " clc ;clear carry flag ;; 11C + 2X\n\t"
462 " sbic %[SDAIN],%[SDAPIN] ;if SDA is high ;; 11C + 2X\n\t"
463 " sec ;set carry flag ;; 12C + 2X\n\t"
464 " rol r23 ;store bit ;; 13C + 2X\n\t"
465 " brcc _Li2c_read_bit ;while receiv reg not full \n\t"
466 " ;; 15C + 2X for one bit loop \n\t"
468 "_Li2c_put_ack: \n\t"
469 " sbi %[SCLDDR],%[SCLPIN] ;force SCL low ;; 2C \n\t"
470 " cpi r24,0 ;; 3C \n\t"
471 " breq _Li2c_put_ack_low ;if (ack=0) ;; 5C \n\t"
472 " cbi %[SDADDR],%[SDAPIN] ;release SDA \n\t"
473 " rjmp _Li2c_put_ack_high \n\t"
474 "_Li2c_put_ack_low: ;else \n\t"
475 " sbi %[SDADDR],%[SDAPIN] ;force SDA low ;; 7C \n\t"
476 "_Li2c_put_ack_high: \n\t"
480 #
if I2C_DELAY_COUNTER >= 1
481 " rcall ass_i2c_delay_half ;delay T/2 ;; 7C + X \n\t"
483 " cbi %[SCLDDR],%[SCLPIN] ;release SCL ;; 9C +X \n\t"
484 " cln ;clear N ;; +1 = 10C\n\t"
487 " sbis %[SCLIN],%[SCLPIN] ;wait SCL high ;; 12C + X\n\t"
488 " rcall ass_i2c_wait_scl_high \n\t"
489 #
if I2C_DELAY_COUNTER >= 1
490 " rcall ass_i2c_delay_half ;delay T/2 ;; 11C + 2X\n\t"
492 "_Li2c_read_return: \n\t"
495 "sbi %[SCLDDR],%[SCLPIN] ;force SCL low so SCL=H is short\n\t"
496 " mov r24,r23 ;; 12C + 2X \n\t"
497 " clr r25 ;; 13 C + 2X\n\t"
500 [SCLDDR]
"I" (SCL_DDR), [SCLPIN]
"I" (SCL_PIN), [SCLIN]
"I" (SCL_IN),
501 [SDADDR]
"I" (SDA_DDR), [SDAPIN]
"I" (SDA_PIN), [SDAIN]
"I" (SDA_IN)