Init commit with many years of arduino sketches and projects. I dont know if the esp8266 includes much, but there are also libraries. I hope they dont have crazy automatic versioning through the Arduino IDE.

This commit is contained in:
2019-05-30 23:41:53 +02:00
parent 2d047634f2
commit 6c84b31f2c
1480 changed files with 198581 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
SoftI2CMaster
=============
Software I2C Arduino library
This is a very fast and light-weight software I2C-master library
written in assembler, which is based on Peter Fleury's software
I2C library http://homepage.hispeed.ch/peterfleury/avr-software.html
. It can use any pins on any AVR chip to drive the SDA and SCL lines.
It assumes a single master and does not support bus arbitration. It
allows for clock stretching by slave devices and also can detect lock
ups of the I2C bus, i.e., if the SCL line is held low indefinitely.
Even on 1MHz systems, you can get a transfer speed of 40 kbit/sec, so
you can use it to interface with SMbus devices.

View File

@@ -0,0 +1,509 @@
/* Arduino SoftI2C library.
*
* This is a very fast and very light-weight software I2C-master library
* written in assembler. It is based on Peter Fleury's I2C software
* library: http://homepage.hispeed.ch/peterfleury/avr-software.html
*
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino I2cMaster Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
/* In order to use the library, you need to define SDA_PIN, SCL_PIN,
* SDA_PORT and SCL_PORT before including this file. Have a look at
* http://www.arduino.cc/en/Reference/PortManipulation for finding out
* which values to use. For example, if you use digital pin 3 for
* SDA and digital pin 13 for SCL you have to use the following
* definitions:
* #define SDA_PIN 3
* #define SDA_PORT PORTB
* #define SCL_PIN 5
* #define SCL_PORT PORTB
*
* You can also define the following constants (see also below):
* - I2C_CPUFREQ, when changing CPU clock frequency dynamically
* - I2C_FASTMODE = 1 meaning that the I2C bus allows speeds up to 400 kHz
* - I2C_SLOWMODE = 1 meaning that the I2C bus will allow only up to 25 kHz
* - I2C_NOINTERRUPT = 1 in order to prohibit interrupts while
* communicating (see below). This can be useful if you use the library
* for communicationg with SMbus devices, which have timeouts.
* Note, however, that interrupts are disabledfrom issuing a start condition
* until issuing a stop condition. So use this option with care!
* - I2C_TIMEOUT = 0..10000 mssec in order to return from the I2C functions
* in case of a I2C bus lockup (i.e., SCL constantly low). 0 means no timeout
*/
/* Changelog:
* Version 1.1:
* - removed I2C_CLOCK_STRETCHING
* - added I2C_TIMEOUT time in msec (0..10000) until timeout or 0 if no timeout
* - changed i2c_init to return true iff both SDA and SCL are high
* - changed interrupt disabling so that the previous IRQ state is retored
* Version 1.0: basic functionality
*/
#include <avr/io.h>
#include <Arduino.h>
#ifndef _SOFTI2C_H
#define _SOFTI2C_H 1
// Init function. Needs to be called once in the beginning.
// Returns false if SDA or SCL are low, which probably means
// a I2C bus lockup or that the lines are not pulled up.
boolean __attribute__ ((noinline)) i2c_init(void);
// Start transfer function: <addr> is the 8-bit I2C address (including the R/W
// bit).
// Return: true if the slave replies with an "acknowledge", false otherwise
bool __attribute__ ((noinline)) i2c_start(uint8_t addr);
// Similar to start function, but wait for an ACK! Be careful, this can
// result in an infinite loop!
void __attribute__ ((noinline)) i2c_start_wait(uint8_t addr);
// Repeated start function: After having claimed the bus with a start condition,
// you can address another or the same chip again without an intervening
// stop condition.
// Return: true if the slave replies with an "acknowledge", false otherwise
bool __attribute__ ((noinline)) i2c_rep_start(uint8_t addr);
// Issue a stop condition, freeing the bus.
void __attribute__ ((noinline)) i2c_stop(void) asm("ass_i2c_stop");
// Write one byte to the slave chip that had been addressed
// by the previous start call. <value> is the byte to be sent.
// Return: true if the slave replies with an "acknowledge", false otherwise
bool __attribute__ ((noinline)) i2c_write(uint8_t value) asm("ass_i2c_write");
// Read one byte. If <last> is true, we send a NAK after having received
// the byte in order to terminate the read sequence.
uint8_t __attribute__ ((noinline)) i2c_read(bool last);
// You can set I2C_CPUFREQ independently of F_CPU if you
// change the CPU frequency on the fly. If do not define it,
// it will use the value of F_CPU
#ifndef I2C_CPUFREQ
#define I2C_CPUFREQ F_CPU
#endif
// If I2C_FASTMODE is set to 1, then the highest possible frequency below 400kHz
// is selected. Be aware that not all slave chips may be able to deal with that!
#ifndef I2C_FASTMODE
#define I2C_FASTMODE 0
#endif
// If I2C_FASTMODE is not defined or defined to be 0, then you can set
// I2C_SLOWMODE to 1. In this case, the I2C frequency will not be higher
// than 25KHz. This could be useful for problematic buses.
#ifndef I2C_SLOWMODE
#define I2C_SLOWMODE 0
#endif
// if I2C_NOINTERRUPT is 1, then the I2C routines are not interruptable.
// This is most probably only necessary if you are using a 1MHz system clock,
// you are communicating with a SMBus device, and you want to avoid timeouts.
// Be aware that the interrupt bit is enabled after each call. So the
// I2C functions should not be called in interrupt routines or critical regions.
#ifndef I2C_NOINTERRUPT
#define I2C_NOINTERRUPT 0
#endif
// I2C_TIMEOUT can be set to a value between 1 and 10000.
// If it is defined and nonzero, it leads to a timeout if the
// SCL is low longer than I2C_TIMEOUT milliseconds, i.e., max timeout is 10 sec
#ifndef I2C_TIMEOUT
#define I2C_TIMEOUT 0
#else
#if I2C_TIMEOUT > 10000
#error I2C_TIMEOUT is too large
#endif
#endif
#define I2C_TIMEOUT_DELAY_LOOPS (I2C_CPUFREQ/1000UL)*I2C_TIMEOUT/4000UL
#if I2C_TIMEOUT_DELAY_LOOPS < 1
#define I2C_MAX_STRETCH 1
#else
#if I2C_TIMEOUT_DELAY_LOOPS > 60000UL
#define I2C_MAX_STRETCH 60000UL
#else
#define I2C_MAX_STRETCH I2C_TIMEOUT_DELAY_LOOPS
#endif
#endif
#if I2C_FASTMODE
#define I2C_DELAY_COUNTER (((I2C_CPUFREQ/400000L)/2-19)/3)
#else
#if I2C_SLOWMODE
#define I2C_DELAY_COUNTER (((I2C_CPUFREQ/25000L)/2-19)/3)
#else
#define I2C_DELAY_COUNTER (((I2C_CPUFREQ/100000L)/2-19)/3)
#endif
#endif
// Table of I2C bus speed in kbit/sec:
// CPU clock: 1MHz 2MHz 4MHz 8MHz 16MHz 20MHz
// Fast I2C mode 40 80 150 300 400 400
// Standard I2C mode 40 80 100 100 100 100
// Slow I2C mode 25 25 25 25 25 25
// constants for reading & writing
#define I2C_READ 1
#define I2C_WRITE 0
// map the IO register back into the IO address space
#define SDA_DDR (_SFR_IO_ADDR(SDA_PORT) - 1)
#define SCL_DDR (_SFR_IO_ADDR(SCL_PORT) - 1)
#define SDA_OUT _SFR_IO_ADDR(SDA_PORT)
#define SCL_OUT _SFR_IO_ADDR(SCL_PORT)
#define SDA_IN (_SFR_IO_ADDR(SDA_PORT) - 2)
#define SCL_IN (_SFR_IO_ADDR(SCL_PORT) - 2)
#ifndef __tmp_reg__
#define __tmp_reg__ 0
#endif
// Internal delay functions.
void __attribute__ ((noinline)) i2c_delay_half(void) asm("ass_i2c_delay_half");
void __attribute__ ((noinline)) i2c_wait_scl_high(void) asm("ass_i2c_wait_scl_high");
void i2c_delay_half(void)
{ // function call 3 cycles => 3C
#if I2C_DELAY_COUNTER < 1
__asm__ __volatile__ (" ret");
// 7 cycles for call and return
#else
__asm__ __volatile__
(
" ldi r25, %[DELAY] ;load delay constant ;; 4C \n\t"
"_Lidelay: \n\t"
" dec r25 ;decrement counter ;; 4C+xC \n\t"
" brne _Lidelay ;;5C+(x-1)2C+xC\n\t"
" ret ;; 9C+(x-1)2C+xC = 7C+xC"
: : [DELAY] "M" I2C_DELAY_COUNTER : "r25");
// 7 cycles + 3 times x cycles
#endif
}
void i2c_wait_scl_high(void)
{
#if I2C_TIMEOUT <= 0
__asm__ __volatile__
("_Li2c_wait_stretch: \n\t"
" sbis %[SCLIN],%[SCLPIN] ;wait for SCL high \n\t"
" rjmp _Li2c_wait_stretch \n\t"
" cln ;signal: no timeout \n\t"
" ret "
: : [SCLIN] "I" (SCL_IN), [SCLPIN] "I" (SCL_PIN));
#else
__asm__ __volatile__
( " ldi r27, %[HISTRETCH] ;load delay counter \n\t"
" ldi r26, %[LOSTRETCH] \n\t"
"_Lwait_stretch: \n\t"
" clr __tmp_reg__ ;do next loop 255 times \n\t"
"_Lwait_stretch_inner_loop: \n\t"
" rcall _Lcheck_scl_level ;call check function ;; 12C \n\t"
" brpl _Lstretch_done ;done if N=0 ;; +1 = 13C\n\t"
" dec __tmp_reg__ ;dec inner loop counter;; +1 = 14C\n\t"
" brne _Lwait_stretch_inner_loop ;; +2 = 16C\n\t"
" sbiw r26,1 ;dec outer loop counter \n\t"
" brne _Lwait_stretch ;continue with outer loop \n\t"
" sen ;timeout -> set N-bit=1 \n\t"
" rjmp _Lwait_return ;and return with N=1\n\t"
"_Lstretch_done: ;SCL=1 sensed \n\t"
" cln ;OK -> clear N-bit \n\t"
" rjmp _Lwait_return ; and return with N=0 \n\t"
"_Lcheck_scl_level: ;; call = 3C\n\t"
" cln ;; +1C = 4C \n\t"
" sbic %[SCLIN],%[SCLPIN] ;skip if SCL still low ;; +2C = 6C \n\t"
" rjmp _Lscl_high ;; +0C = 6C \n\t"
" sen ;; +1 = 7C\n\t "
"_Lscl_high: "
" nop ;; +1C = 8C \n\t"
" ret ;return N-Bit=1 if low ;; +4 = 12C\n\t"
"_Lwait_return:"
: : [SCLIN] "I" (SCL_IN), [SCLPIN] "I" (SCL_PIN),
[HISTRETCH] "M" (I2C_MAX_STRETCH>>8),
[LOSTRETCH] "M" (I2C_MAX_STRETCH&0xFF)
: "r26", "r27");
#endif
}
boolean i2c_init(void)
{
__asm__ __volatile__
(" cbi %[SDADDR],%[SDAPIN] ;release SDA \n\t"
" cbi %[SCLDDR],%[SCLPIN] ;release SCL \n\t"
" cbi %[SDAOUT],%[SDAPIN] ;clear SDA output value \n\t"
" cbi %[SCLOUT],%[SCLPIN] ;clear SCL output value \n\t"
" clr r24 ;set return value to false \n\t"
" clr r25 ;set return value to false \n\t"
" sbis %[SDAIN],%[SDAPIN] ;check for SDA high\n\t"
" ret ;if low return with false \n\t"
" sbis %[SCLIN],%[SCLPIN] ;check for SCL high \n\t"
" ret ;if low return with false \n\t"
" ldi r24,1 ;set return value to true \n\t"
" ret "
: :
[SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN),
[SCLIN] "I" (SCL_IN), [SCLOUT] "I" (SCL_OUT),
[SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN),
[SDAIN] "I" (SDA_IN), [SDAOUT] "I" (SDA_OUT));
return true;
}
bool i2c_start(uint8_t addr)
{
__asm__ __volatile__
(
#if I2C_NOINTERRUPT
" cli ;clear IRQ bit \n\t"
#endif
" sbis %[SCLIN],%[SCLPIN] ;check for clock stretching slave\n\t"
" rcall ass_i2c_wait_scl_high ;wait until SCL=H\n\t"
" sbi %[SDADDR],%[SDAPIN] ;force SDA low \n\t"
" rcall ass_i2c_delay_half ;wait T/2 \n\t"
" rcall ass_i2c_write ;now write address \n\t"
" ret"
: : [SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN),
[SCLIN] "I" (SCL_IN),[SCLPIN] "I" (SCL_PIN));
return true; // we never return here!
}
bool i2c_rep_start(uint8_t addr)
{
__asm__ __volatile__
(
#if I2C_NOINTERRUPT
" cli \n\t"
#endif
" sbi %[SCLDDR],%[SCLPIN] ;force SCL low \n\t"
" rcall ass_i2c_delay_half ;delay T/2 \n\t"
" cbi %[SDADDR],%[SDAPIN] ;release SDA \n\t"
" rcall ass_i2c_delay_half ;delay T/2 \n\t"
" cbi %[SCLDDR],%[SCLPIN] ;release SCL \n\t"
" rcall ass_i2c_delay_half ;delay T/2 \n\t"
" sbis %[SCLIN],%[SCLPIN] ;check for clock stretching slave\n\t"
" rcall ass_i2c_wait_scl_high ;wait until SCL=H\n\t"
" sbi %[SDADDR],%[SDAPIN] ;force SDA low \n\t"
" rcall ass_i2c_delay_half ;delay T/2 \n\t"
" rcall ass_i2c_write \n\t"
" ret"
: : [SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN),[SCLIN] "I" (SCL_IN),
[SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN));
return true; // just to fool the compiler
}
void i2c_start_wait(uint8_t addr)
{
__asm__ __volatile__
(
" push r24 ;save original parameter \n\t"
"_Li2c_start_wait1: \n\t"
" pop r24 ;restore original parameter\n\t"
" push r24 ;and save again \n\t"
#if I2C_NOINTERRUPT
" cli ;disable interrupts \n\t"
#endif
" sbis %[SCLIN],%[SCLPIN] ;check for clock stretching slave\n\t"
" rcall ass_i2c_wait_scl_high ;wait until SCL=H\n\t"
" sbi %[SDADDR],%[SDAPIN] ;force SDA low \n\t"
" rcall ass_i2c_delay_half ;delay T/2 \n\t"
" rcall ass_i2c_write ;write address \n\t"
" tst r24 ;if device not busy -> done \n\t"
" brne _Li2c_start_wait_done \n\t"
" rcall ass_i2c_stop ;terminate write & enable IRQ \n\t"
" rjmp _Li2c_start_wait1 ;device busy, poll ack again \n\t"
"_Li2c_start_wait_done: \n\t"
" pop __tmp_reg__ ;pop off orig argument \n\t"
" ret "
: : [SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN),
[SCLIN] "I" (SCL_IN),[SCLPIN] "I" (SCL_PIN));
}
void i2c_stop(void)
{
__asm__ __volatile__
(
" sbi %[SCLDDR],%[SCLPIN] ;force SCL low \n\t"
" sbi %[SDADDR],%[SDAPIN] ;force SDA low \n\t"
" rcall ass_i2c_delay_half ;T/2 delay \n\t"
" cbi %[SCLDDR],%[SCLPIN] ;release SCL \n\t"
" rcall ass_i2c_delay_half ;T/2 delay \n\t"
" sbis %[SCLIN],%[SCLPIN] ;check for clock stretching slave\n\t"
" rcall ass_i2c_wait_scl_high ;wait until SCL=H\n\t"
" cbi %[SDADDR],%[SDAPIN] ;release SDA \n\t"
" rcall ass_i2c_delay_half \n\t"
#if I2C_NOINTERRUPT
" sei ;enable interrupts again!\n\t"
#endif
: : [SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN), [SCLIN] "I" (SCL_IN),
[SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN));
}
bool i2c_write(uint8_t value)
{
__asm__ __volatile__
(
" sec ;set carry flag \n\t"
" rol r24 ;shift in carry and shift out MSB \n\t"
" rjmp _Li2c_write_first \n\t"
"_Li2c_write_bit:\n\t"
" lsl r24 ;left shift into carry ;; 1C\n\t"
"_Li2c_write_first:\n\t"
" breq _Li2c_get_ack ;jump if TXreg is empty;; +1 = 2C \n\t"
" sbi %[SCLDDR],%[SCLPIN] ;force SCL low ;; +2 = 4C \n\t"
" nop \n\t"
" nop \n\t"
" nop \n\t"
" brcc _Li2c_write_low ;;+1/+2=5/6C\n\t"
" nop ;; +1 = 7C \n\t"
" cbi %[SDADDR],%[SDAPIN] ;release SDA ;; +2 = 9C \n\t"
" rjmp _Li2c_write_high ;; +2 = 11C \n\t"
"_Li2c_write_low: \n\t"
" sbi %[SDADDR],%[SDAPIN] ;force SDA low ;; +2 = 9C \n\t"
" rjmp _Li2c_write_high ;;+2 = 11C \n\t"
"_Li2c_write_high: \n\t"
#if I2C_DELAY_COUNTER >= 1
" rcall ass_i2c_delay_half ;delay T/2 ;;+X = 11C+X\n\t"
#endif
" cbi %[SCLDDR],%[SCLPIN] ;release SCL ;;+2 = 13C+X\n\t"
" cln ;clear N-bit ;;+1 = 14C+X\n\t"
" nop \n\t"
" nop \n\t"
" nop \n\t"
" sbis %[SCLIN],%[SCLPIN] ;check for SCL high ;;+2 = 16C+X\n\t"
" rcall ass_i2c_wait_scl_high \n\t"
" brpl _Ldelay_scl_high ;;+2 = 18C+X\n\t"
"_Li2c_write_return_false: \n\t"
" clr r24 ; return false because of timeout \n\t"
" rjmp _Li2c_write_return \n\t"
"_Ldelay_scl_high: \n\t"
#if I2C_DELAY_COUNTER >= 1
" rcall ass_i2c_delay_half ;delay T/2 ;;+X= 18C+2X\n\t"
#endif
" rjmp _Li2c_write_bit \n\t"
" ;; +2 = 20C +2X for one bit-loop \n\t"
"_Li2c_get_ack: \n\t"
" sbi %[SCLDDR],%[SCLPIN] ;force SCL low ;; +2 = 5C \n\t"
" nop \n\t"
" nop \n\t"
" cbi %[SDADDR],%[SDAPIN] ;release SDA ;;+2 = 7C \n\t"
#if I2C_DELAY_COUNTER >= 1
" rcall ass_i2c_delay_half ;delay T/2 ;; +X = 7C+X \n\t"
#endif
" clr r25 ;; 17C+2X \n\t"
" clr r24 ;return 0 ;; 14C + X \n\t"
" cbi %[SCLDDR],%[SCLPIN] ;release SCL ;; +2 = 9C+X\n\t"
"_Li2c_ack_wait: \n\t"
" cln ; clear N-bit ;; 10C + X\n\t"
" nop \n\t"
" sbis %[SCLIN],%[SCLPIN] ;wait SCL high ;; 12C + X \n\t"
" rcall ass_i2c_wait_scl_high \n\t"
" brmi _Li2c_write_return_false ;; 13C + X \n\t "
" sbis %[SDAIN],%[SDAPIN] ;if SDA hi -> return 0 ;; 15C + X \n\t"
" ldi r24,1 ;return true ;; 16C + X \n\t"
#if I2C_DELAY_COUNTER >= 1
" rcall ass_i2c_delay_half ;delay T/2 ;; 16C + 2X \n\t"
#endif
"_Li2c_write_return: \n\t"
" nop \n\t "
" nop \n\t "
" sbi %[SCLDDR],%[SCLPIN] ;force SCL low so SCL=H is short\n\t"
" ret \n\t"
" ;; + 4 = 17C + 2X for acknowldge bit"
::
[SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN), [SCLIN] "I" (SCL_IN),
[SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN), [SDAIN] "I" (SDA_IN));
return true; // fooling the compiler
}
uint8_t i2c_read(bool last)
{
__asm__ __volatile__
(
" ldi r23,0x01 \n\t"
"_Li2c_read_bit: \n\t"
" sbi %[SCLDDR],%[SCLPIN] ;force SCL low ;; 2C \n\t"
" cbi %[SDADDR],%[SDAPIN] ;release SDA(prev. ACK);; 4C \n\t"
" nop \n\t"
" nop \n\t"
" nop \n\t"
#if I2C_DELAY_COUNTER >= 1
" rcall ass_i2c_delay_half ;delay T/2 ;; 4C+X \n\t"
#endif
" cbi %[SCLDDR],%[SCLPIN] ;release SCL ;; 6C + X \n\t"
#if I2C_DELAY_COUNTER >= 1
" rcall ass_i2c_delay_half ;delay T/2 ;; 6C + 2X \n\t"
#endif
" cln ; clear N-bit ;; 7C + 2X \n\t"
" nop \n\t "
" nop \n\t "
" nop \n\t "
" sbis %[SCLIN], %[SCLPIN] ;check for SCL high ;; 9C +2X \n\t"
" rcall ass_i2c_wait_scl_high \n\t"
" brmi _Li2c_read_return ;return if timeout ;; 10C + 2X\n\t"
" clc ;clear carry flag ;; 11C + 2X\n\t"
" sbic %[SDAIN],%[SDAPIN] ;if SDA is high ;; 11C + 2X\n\t"
" sec ;set carry flag ;; 12C + 2X\n\t"
" rol r23 ;store bit ;; 13C + 2X\n\t"
" brcc _Li2c_read_bit ;while receiv reg not full \n\t"
" ;; 15C + 2X for one bit loop \n\t"
"_Li2c_put_ack: \n\t"
" sbi %[SCLDDR],%[SCLPIN] ;force SCL low ;; 2C \n\t"
" cpi r24,0 ;; 3C \n\t"
" breq _Li2c_put_ack_low ;if (ack=0) ;; 5C \n\t"
" cbi %[SDADDR],%[SDAPIN] ;release SDA \n\t"
" rjmp _Li2c_put_ack_high \n\t"
"_Li2c_put_ack_low: ;else \n\t"
" sbi %[SDADDR],%[SDAPIN] ;force SDA low ;; 7C \n\t"
"_Li2c_put_ack_high: \n\t"
" nop \n\t "
" nop \n\t "
" nop \n\t "
#if I2C_DELAY_COUNTER >= 1
" rcall ass_i2c_delay_half ;delay T/2 ;; 7C + X \n\t"
#endif
" cbi %[SCLDDR],%[SCLPIN] ;release SCL ;; 9C +X \n\t"
" cln ;clear N ;; +1 = 10C\n\t"
" nop \n\t "
" nop \n\t "
" sbis %[SCLIN],%[SCLPIN] ;wait SCL high ;; 12C + X\n\t"
" rcall ass_i2c_wait_scl_high \n\t"
#if I2C_DELAY_COUNTER >= 1
" rcall ass_i2c_delay_half ;delay T/2 ;; 11C + 2X\n\t"
#endif
"_Li2c_read_return: \n\t"
" nop \n\t "
" nop \n\t "
"sbi %[SCLDDR],%[SCLPIN] ;force SCL low so SCL=H is short\n\t"
" mov r24,r23 ;; 12C + 2X \n\t"
" clr r25 ;; 13 C + 2X\n\t"
" ret ;; 17C + X"
::
[SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN), [SCLIN] "I" (SCL_IN),
[SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN), [SDAIN] "I" (SDA_IN)
);
return ' '; // fool the compiler!
}
#endif

View File

@@ -0,0 +1,98 @@
// Simple sketch to read out BMA020 using SoftI2C
// Readout BMA020 chip
// use low processor speed (you have to change the baud rate to 2400!)
// #define I2C_CPUFREQ (F_CPU/8)
#define NO_INTERRUPT 1
#define I2C_TIMEOUT 1000
#define SDA_PORT PORTD
#define SDA_PIN 3
#define SCL_PORT PORTD
#define SCL_PIN 5
#include <SoftI2CMaster.h>
#include <avr/io.h>
#define BMAADDR 0x70
int xval, yval, zval;
void CPUSlowDown(void) {
// slow down processor by a factor of 8
CLKPR = _BV(CLKPCE);
CLKPR = _BV(CLKPS1) | _BV(CLKPS0);
}
boolean setControlBits(uint8_t cntr)
{
Serial.println(F("Soft reset"));
if (!i2c_start(BMAADDR | I2C_WRITE)) {
return false;
}
if (!i2c_write(0x0A)) {
return false;
}
if (!i2c_write(cntr)) {
return false;
}
i2c_stop();
return true;
}
boolean initBma(void)
{
if (!setControlBits(B00000010)) return false;;
delay(100);
return true;
}
int readOneVal(boolean last)
{
uint8_t msb, lsb;
lsb = i2c_read(false);
msb = i2c_read(last);
if (last) i2c_stop();
return (int)((msb<<8)|lsb)/64;
}
boolean readBma(void)
{
xval = 0xFFFF;
yval = 0xFFFF;
zval = 0xFFFF;
if (!i2c_start(BMAADDR | I2C_WRITE)) return false;
if (!i2c_write(0x02)) return false;
if (!i2c_rep_start(BMAADDR | I2C_READ)) return false;
xval = readOneVal(false);
yval = readOneVal(false);
zval = readOneVal(true);
return true;
}
//------------------------------------------------------------------------------
void setup(void) {
#if I2C_CPUFREQ == (F_CPU/8)
CPUSlowDown();
#endif
Serial.begin(19200); // in case of CPU slow down, change to baud rate / 8!
if (!initBma()) {
Serial.println(F("INIT ERROR"));
}
}
void loop(void){
if (!readBma()) Serial.println(F("READ ERROR"));
Serial.print(F("X="));
Serial.print(xval);
Serial.print(F(" Y="));
Serial.print(yval);
Serial.print(F(" Z="));
Serial.println(zval);
delay(300);
}

View File

@@ -0,0 +1,298 @@
// Sketch to explore 24AA1024 using SoftI2C
#define SDA_PORT PORTD
#define SDA_PIN 3
#define SCL_PORT PORTD
#define SCL_PIN 5
#define I2C_FASTMODE 0
// #define I2C_TIMEOUT 10 // timeout after 10 msec
// #define I1C_NOINTERRUPT 1 // no interrupts
// #define I2C_CPUFREQ (F_CPU/8) // slow down CPU frequency
#include <SoftI2CMaster.h>
#define EEPROMADDR 0xA6 // set by jumper
#define MAXADDR 0x1FFFF
#define MAXTESTADDR 0x03FFF
void CPUSlowDown(void) {
// slow down processor by a factor of 8
CLKPR = _BV(CLKPCE);
CLKPR = _BV(CLKPS1) | _BV(CLKPS0);
}
//------------------------------------------------------------------------------
/*
* read one byte from address
*/
boolean readEEPROM(unsigned long address, uint8_t *byte) {
// issue a start condition, send device address and write direction bit
if (!i2c_start(EEPROMADDR | I2C_WRITE | (address&0x10000 ? 8 : 0) )) return false;
// send the address
if (!i2c_write((address>>8)&0xFF)) return false;
if (!i2c_write(address&0xFF)) return false;
// issue a repeated start condition, send device address and read direction bit
if (!i2c_rep_start(EEPROMADDR | I2C_READ | (address&0x10000 ? 8 : 0) ))return false;
*byte = i2c_read(true);
i2c_stop();
return true;
}
//------------------------------------------------------------------------------
/*
*burst read
*/
boolean readBurstEEPROM(unsigned long start, unsigned long stop) {
// does not handle the transition from 0x0FFFF to 0x10000
// since we only use it for performance evaluation, we do not care!
unsigned long addr = start;
uint8_t byte;
// issue a start condition, send device address and write direction bit
if (!i2c_start(EEPROMADDR | I2C_WRITE | (addr&0x10000 ? 8 : 0) )) return false;
// send the address
if (!i2c_write((addr>>8)&0xFF)) return false;
if (!i2c_write(addr&0xFF)) return false;
// issue a repeated start condition, send device address and read direction bit
if (!i2c_rep_start(EEPROMADDR | I2C_READ | (addr&0x10000 ? 8 : 0) ))return false;
addr++;
while (addr++ < stop) byte = i2c_read(false);
byte = i2c_read(true);
i2c_stop();
return true;
}
//------------------------------------------------------------------------------
/*
* write 1 byte to 'address' in eeprom
*/
boolean writeEEPROM(long unsigned address, uint8_t byte) {
// issue a start condition, send device address and write direction bit
if (!i2c_start(EEPROMADDR | I2C_WRITE | (address&0x10000 ? 8 : 0))) return false;
// send the address
if (!i2c_write((address>>8)&0xFF)) return false;
if (!i2c_write(address&0xFF)) return false;
// send data to EEPROM
if (!i2c_write(byte)) return false;
// issue a stop condition
i2c_stop();
delay(6);
return true;
}
//------------------------------------------------------------------------------
/*
* delete eeprom
*/
boolean deleteEEPROM(long unsigned from, unsigned long to, uint8_t byte,
boolean poll) {
unsigned long tempto, i;
boolean firstpage = true;
while (from <= to) {
tempto = ((from/128)+1)*128-1;
if (tempto > to) tempto = to;
if (firstpage || !poll) {
if (!i2c_start(EEPROMADDR | I2C_WRITE | (from&0x10000 ? 8 : 0)))
return false;
} else i2c_start_wait(EEPROMADDR | I2C_WRITE | (from&0x10000 ? 8 : 0));
// send the address
if (!i2c_write((from>>8)&0xFF)) return false;
if (!i2c_write(from&0xFF)) return false;
// send data to EEPROM
for (i=from; i<=tempto; i++)
if (!i2c_write(byte)) return false;
// issue a stop condition
i2c_stop();
// wait for ack again
if (!poll) delay(6);
from = tempto+1;
firstpage = false;
}
return true;
}
//------------------------------------------------------------------------------
boolean performanceTest() {
unsigned long eeaddr;
unsigned long startmicros, endmicros;
int avgtime;
boolean OK = true;
uint8_t byte;
Serial.println(F("\nPerformance test:"));
Serial.println(F("Sequential reads ..."));
startmicros = micros();
OK &= readBurstEEPROM(0,MAXTESTADDR);
endmicros = micros();
Serial.print(F("Time: "));
avgtime = (endmicros-startmicros)/(MAXTESTADDR+1);
Serial.print(avgtime);
Serial.println(F(" micro secs/byte"));
Serial.println(F("Random reads ..."));
startmicros = micros();
for (eeaddr = 0; eeaddr <= MAXTESTADDR; eeaddr++)
OK &= readEEPROM(eeaddr,&byte);
endmicros = micros();
Serial.print(F("Time: "));
avgtime = (endmicros-startmicros)/(MAXTESTADDR+1);
Serial.print(avgtime);
Serial.println(F(" micro secs/byte"));
Serial.println(F("Page writes with wait ..."));
startmicros = micros();
OK &= deleteEEPROM(0,MAXTESTADDR,0xFF,false);
endmicros = micros();
Serial.print(F("Time: "));
avgtime = (endmicros-startmicros)/(MAXTESTADDR+1);
Serial.print(avgtime);
Serial.println(F(" micro secs/byte"));
Serial.println(F("Page writes with poll ..."));
startmicros = micros();
OK &= deleteEEPROM(0,MAXTESTADDR,0xFF,true);
endmicros = micros();
Serial.print(F("Time: "));
avgtime = (endmicros-startmicros)/(MAXTESTADDR+1);
Serial.print(avgtime);
Serial.println(F(" micro secs/byte"));
return OK;
}
//------------------------------------------------------------------------------
unsigned long parseHex() {
unsigned long result = 0L;
char byte = '\0';
// while (hexdigit(byte)) {
while (byte != '\r' && byte != '#') {
while (!Serial.available());
byte = Serial.read();
// if (!hexdigit(byte)) break;
if (byte == '\r' || byte == '#') break;
if (byte >= 'a' && byte <= 'f')
byte = byte -'a' + 'A';
if ((byte >= '0' && byte <= '9') ||
(byte >= 'A' && byte <= 'F')) {
Serial.print(byte);
if (byte >= '0' && byte <= '9') byte = byte - '0';
else byte = byte - 'A' + 10;
result = result * 16;
result = result + byte;
}
}
Serial.println();
return result;
}
void help (void) {
Serial.println();
Serial.println(F("r - read byte from address"));
Serial.println(F("w - write byte to address"));
Serial.println(F("d - delete from start address to end address"));
Serial.println(F("l - list memory range"));
Serial.println(F("p - test performance"));
Serial.println(F("h - help message"));
Serial.println(F("Finish all numeric inputs with '#'"));
}
//------------------------------------------------------------------------------
void setup(void) {
#if I2C_CPUFREQ == (F_CPU/8)
CPUSlowDown();
#endif
Serial.begin(19200);
Serial.println(F("\n\nTest program for EEPROM 24AA1024"));
help();
}
void loop(void) {
char cmd;
uint8_t byte;
boolean noterror;
unsigned long addr, toaddr;
while (!Serial.available());
cmd = Serial.read();
switch (cmd) {
case 'r': Serial.print(F("Read from addr: "));
addr = parseHex();
Serial.println(F("Reading..."));
noterror = readEEPROM(addr,&byte);
Serial.print(addr,HEX);
Serial.print(F(": "));
Serial.println(byte,HEX);
if (!noterror) Serial.println(F("Error while reading"));
break;
case 'w':
Serial.print(F("Write to addr: "));
addr = parseHex();
Serial.print(F("Value: "));
byte = parseHex();
Serial.println(F("Writing..."));
noterror = writeEEPROM(addr,byte);
if (!noterror) Serial.println(F("Error while reading"));
break;
case 'd':
Serial.print(F("Delete from addr: "));
addr = parseHex();
Serial.print(F("to addr: "));
toaddr = parseHex();
Serial.print(F("Value: "));
byte = parseHex();
Serial.print(F("Deleting ... "));
noterror = deleteEEPROM(addr,toaddr,byte,false);
Serial.println(F("...done"));
if (!noterror) Serial.println(F("Error while deleting"));
break;
case 'l':
Serial.print(F("List from addr: "));
addr = parseHex();
Serial.print(F("to addr: "));
toaddr = parseHex();
while (addr <= toaddr) {
noterror = readEEPROM(addr,&byte);
Serial.print(addr,HEX);
Serial.print(F(": "));
Serial.println(byte,HEX);
if (!noterror) Serial.println(F("Error while reading"));
addr++;
}
case 'p':
noterror = performanceTest();
if (!noterror) Serial.println(F("Error while executing performance test"));
break;
case 'h':
help();
break;
default:
Serial.println(F("Unknown command"));
Serial.println();
help();
}
}

View File

@@ -0,0 +1,91 @@
// Scan I2C bus for device responses
#define SDA_PORT PORTD
#define SDA_PIN 3
#define SCL_PORT PORTD
#define SCL_PIN 5
#define I2C_TIMEOUT 100
#define I2C_NOINTERRUPT 0
#define I2C_SLOWMODE 1
#define FAC 1
#define I2C_CPUFREQ (F_CPU/FAC)
/* Corresponds to A4/A5 - the hardware I2C pins on Arduinos
#define SDA_PORT PORTC
#define SDA_PIN 4
#define SCL_PORT PORTC
#define SCL_PIN 5
#define I2C_FASTMODE 1
*/
#include <SoftI2CMaster.h>
#include <avr/io.h>
//------------------------------------------------------------------------------
void CPUSlowDown(int fac) {
// slow down processor by a fac
CLKPR = _BV(CLKPCE);
CLKPR = _BV(CLKPS1) | _BV(CLKPS0);
}
void setup(void) {
#if FAC != 1
CPUSlowDown(FAC);
#endif
Serial.begin(19200); // change baudrate to 2400 on terminal when low CPU freq!
Serial.println(F("Intializing ..."));
Serial.print("I2C delay counter: ");
Serial.println(I2C_DELAY_COUNTER);
if (!i2c_init())
Serial.println(F("Initialization error. SDA or SCL are low"));
else
Serial.println(F("...done"));
}
void loop(void)
{
uint8_t add = 0;
int found = false;
Serial.println("Scanning ...");
Serial.println(" 8-bit 7-bit addr");
// try read
do {
if (i2c_start(add | I2C_READ)) {
found = true;
i2c_read(true);
i2c_stop();
Serial.print("Read: 0x");
if (add < 0x0F) Serial.print(0, HEX);
Serial.print(add+I2C_READ, HEX);
Serial.print(" 0x");
if (add>>1 < 0x0F) Serial.print(0, HEX);
Serial.println(add>>1, HEX);
} else i2c_stop();
add += 2;
} while (add);
// try write
add = 0;
do {
if (i2c_start(add | I2C_WRITE)) {
found = true;
i2c_stop();
Serial.print("Write: 0x");
if (add < 0x0F) Serial.print(0, HEX);
Serial.print(add+I2C_WRITE, HEX);
Serial.print(" 0x");
if (add>>1 < 0x0F) Serial.print(0, HEX);
Serial.println(add>>1, HEX);
} else i2c_stop();
i2c_stop();
add += 2;
} while (add);
if (!found) Serial.println(F("No I2C device found."));
Serial.println("Done\n\n");
delay(1000/FAC);
}

View File

@@ -0,0 +1,60 @@
// reads out the MLX90614 infrared thermometer
#include <Arduino.h>
#define SDA_PORT PORTD
#define SDA_PIN 3
#define SCL_PORT PORTD
#define SCL_PIN 5
#include <SoftI2CMaster.h>
#define DEVICE (0x5A<<1)
void setup(){
#if (__AVR_ARCH__ == 5) // means ATMEGA
Serial.begin(19200);
Serial.println("Setup...");
#endif
i2c_init();
}
void loop(){
int dev = 0x5A<<1;
int data_low = 0;
int data_high = 0;
int pec = 0;
i2c_start(dev+I2C_WRITE);
i2c_write(0x07);
// read
i2c_rep_start(dev+I2C_READ);
data_low = i2c_read(false); //Read 1 byte and then send ack
data_high = i2c_read(false); //Read 1 byte and then send ack
pec = i2c_read(true);
i2c_stop();
//This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps
double tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
double tempData = 0x0000; // zero out the data
int frac; // data past the decimal point
// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
tempData = (double)(((data_high & 0x007F) << 8) + data_low);
tempData = (tempData * tempFactor)-0.01;
float celcius = tempData - 273.15;
float fahrenheit = (celcius*1.8) + 32;
#if (__AVR_ARCH__ == 5) // means ATMEGA
Serial.print("Celcius: ");
Serial.println(celcius);
Serial.print("Fahrenheit: ");
Serial.println(fahrenheit);
#endif
delay(1000); // wait a second before printing again
}

View File

@@ -0,0 +1,53 @@
#ifndef _TSL2561_H_
#define _TSL2561_H_
#define TSL2561_VISIBLE 2 // channel 0 - channel 1
#define TSL2561_INFRARED 1 // channel 1
#define TSL2561_FULLSPECTRUM 0 // channel 0
#define TSL2561_LUX_LUXSCALE (14) // Scale by 2^14
#define TSL2561_LUX_RATIOSCALE (9) // Scale ratio by 2^9
#define TSL2561_LUX_CHSCALE (10) // Scale channel values by 2^10
#define TSL2561_LUX_CHSCALE_TINT0 (0x7517) // 322/11 * 2^TSL2561_LUX_CHSCALE
#define TSL2561_LUX_CHSCALE_TINT1 (0x0FE7) // 322/81 * 2^TSL2561_LUX_CHSCALE
// T, FN and CL package values
#define TSL2561_LUX_K1T (0x0040) // 0.125 * 2^RATIO_SCALE
#define TSL2561_LUX_B1T (0x01f2) // 0.0304 * 2^LUX_SCALE
#define TSL2561_LUX_M1T (0x01be) // 0.0272 * 2^LUX_SCALE
#define TSL2561_LUX_K2T (0x0080) // 0.250 * 2^RATIO_SCALE
#define TSL2561_LUX_B2T (0x0214) // 0.0325 * 2^LUX_SCALE
#define TSL2561_LUX_M2T (0x02d1) // 0.0440 * 2^LUX_SCALE
#define TSL2561_LUX_K3T (0x00c0) // 0.375 * 2^RATIO_SCALE
#define TSL2561_LUX_B3T (0x023f) // 0.0351 * 2^LUX_SCALE
#define TSL2561_LUX_M3T (0x037b) // 0.0544 * 2^LUX_SCALE
#define TSL2561_LUX_K4T (0x0100) // 0.50 * 2^RATIO_SCALE
#define TSL2561_LUX_B4T (0x0270) // 0.0381 * 2^LUX_SCALE
#define TSL2561_LUX_M4T (0x03fe) // 0.0624 * 2^LUX_SCALE
#define TSL2561_LUX_K5T (0x0138) // 0.61 * 2^RATIO_SCALE
#define TSL2561_LUX_B5T (0x016f) // 0.0224 * 2^LUX_SCALE
#define TSL2561_LUX_M5T (0x01fc) // 0.0310 * 2^LUX_SCALE
#define TSL2561_LUX_K6T (0x019a) // 0.80 * 2^RATIO_SCALE
#define TSL2561_LUX_B6T (0x00d2) // 0.0128 * 2^LUX_SCALE
#define TSL2561_LUX_M6T (0x00fb) // 0.0153 * 2^LUX_SCALE
#define TSL2561_LUX_K7T (0x029a) // 1.3 * 2^RATIO_SCALE
#define TSL2561_LUX_B7T (0x0018) // 0.00146 * 2^LUX_SCALE
#define TSL2561_LUX_M7T (0x0012) // 0.00112 * 2^LUX_SCALE
#define TSL2561_LUX_K8T (0x029a) // 1.3 * 2^RATIO_SCALE
#define TSL2561_LUX_B8T (0x0000) // 0.000 * 2^LUX_SCALE
#define TSL2561_LUX_M8T (0x0000) // 0.000 * 2^LUX_SCALE
// Auto-gain thresholds
#define TSL2561_AGC_THI_13MS (4850) // Max value at Ti 13ms = 5047
#define TSL2561_AGC_TLO_13MS (100)
#define TSL2561_AGC_THI_101MS (36000) // Max value at Ti 101ms = 37177
#define TSL2561_AGC_TLO_101MS (200)
#define TSL2561_AGC_THI_402MS (63000) // Max value at Ti 402ms = 65535
#define TSL2561_AGC_TLO_402MS (500)
// Clipping thresholds
#define TSL2561_CLIPPING_13MS (4900)
#define TSL2561_CLIPPING_101MS (37000)
#define TSL2561_CLIPPING_402MS (65000)
#endif

View File

@@ -0,0 +1,100 @@
// Sketch to explore the luminosity sensor TSL2561 (breakout board by Adafruit)
#define SDA_PORT PORTD
#define SDA_PIN 3
#define SCL_PORT PORTD
#define SCL_PIN 5
#include <SoftI2CMaster.h>
#include "TSL2561Soft.h"
#define ADDR 0x72
//------------------------------------------------------------------------------
unsigned long computeLux(unsigned long channel0, unsigned long channel1){
/* Make sure the sensor isn't saturated! */
uint16_t clipThreshold = TSL2561_CLIPPING_402MS;;
/* Return 0 lux if the sensor is saturated */
if ((channel0 > clipThreshold) || (channel1 > clipThreshold))
{
Serial.println(F("Sensor is saturated"));
return 32000;
}
/* Find the ratio of the channel values (Channel1/Channel0) */
unsigned long ratio1 = 0;
if (channel0 != 0) ratio1 = (channel1 << (TSL2561_LUX_RATIOSCALE+1)) / channel0;
/* round the ratio value */
unsigned long ratio = (ratio1 + 1) >> 1;
unsigned int b, m;
if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1T))
{b=TSL2561_LUX_B1T; m=TSL2561_LUX_M1T;}
else if (ratio <= TSL2561_LUX_K2T)
{b=TSL2561_LUX_B2T; m=TSL2561_LUX_M2T;}
else if (ratio <= TSL2561_LUX_K3T)
{b=TSL2561_LUX_B3T; m=TSL2561_LUX_M3T;}
else if (ratio <= TSL2561_LUX_K4T)
{b=TSL2561_LUX_B4T; m=TSL2561_LUX_M4T;}
else if (ratio <= TSL2561_LUX_K5T)
{b=TSL2561_LUX_B5T; m=TSL2561_LUX_M5T;}
else if (ratio <= TSL2561_LUX_K6T)
{b=TSL2561_LUX_B6T; m=TSL2561_LUX_M6T;}
else if (ratio <= TSL2561_LUX_K7T)
{b=TSL2561_LUX_B7T; m=TSL2561_LUX_M7T;}
else if (ratio > TSL2561_LUX_K8T)
{b=TSL2561_LUX_B8T; m=TSL2561_LUX_M8T;}
unsigned long temp;
temp = ((channel0 * b) - (channel1 * m));
/* Do not allow negative lux value */
if (temp < 0) temp = 0;
/* Round lsb (2^(LUX_SCALE-1)) */
temp += (1 << (TSL2561_LUX_LUXSCALE-1));
/* Strip off fractional portion */
uint32_t lux = temp >> TSL2561_LUX_LUXSCALE;
return lux;
}
void setup(void) {
Serial.begin(19200);
Serial.println("Initializing ...");
i2c_init();
if (!i2c_start(ADDR | I2C_WRITE)) Serial.println(F("Device does not respond"));
if (!i2c_write(0x80)) Serial.println(F("Cannot address reg 0"));
if (!i2c_write(0x03)) Serial.println(F("Cannot wake up"));
i2c_stop();
}
void loop (void) {
unsigned int low0, high0, low1, high1;
unsigned int chan0, chan1;
unsigned int lux;
delay(1000);
i2c_start(ADDR | I2C_WRITE);
i2c_write(0x8C);
i2c_rep_start(ADDR | I2C_READ);
low0 = i2c_read(false);
high0 = i2c_read(false);
low1 = i2c_read(false);
high1 = i2c_read(true);
i2c_stop();
Serial.print(F("Raw values: chan0="));
Serial.print(chan0=(low0+(high0<<8)));
Serial.print(F(" / chan1="));
Serial.println(chan1=(low1+(high1<<8)));
lux = computeLux(chan0,chan1);
Serial.print(F("Lux value="));
Serial.println(lux);
}

View File

@@ -0,0 +1,52 @@
// This is a short sketch that stretches the low pulse on an I2C bus
// in order to test the timeout feature.
// Put any Arduino and I2C device, e.g. a memory chip, as usual on a breadboard,
// then use another Arduino and flash this program into it. Connect the
// pin 5 (of PORTD) with the SCL line and verify on the scope that the
// low period is indeed stretched.
#include <avr/io.h>
#define SCL_PORT PORTD
#define SCL_PIN 5
#define DELAY 8 // strech SCL low for that many milli seconds
#define SCL_DDR (_SFR_IO_ADDR(SCL_PORT) - 1)
#define SCL_OUT _SFR_IO_ADDR(SCL_PORT)
#define SCL_IN (_SFR_IO_ADDR(SCL_PORT) - 2)
void initScl(void) {
asm volatile
(" cbi %[SCLDDR],%[SCLPIN] ;release SCL \n\t"
" cbi %[SCLOUT],%[SCLPIN] ;clear SCL output value \n\t"
:: [SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN), [SCLOUT] "I" (SCL_OUT));
}
void grabScl(void) {
asm volatile
("_L_wait: \n\t"
" sbic %[SCLIN],%[SCLPIN] \n\t"
" rjmp _L_wait \n\t"
" sbi %[SCLDDR],%[SCLPIN]"
::[SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN), [SCLIN] "I" (SCL_IN));
}
void releaseScl(void) {
asm volatile
(" cbi %[SCLDDR],%[SCLPIN] \n\t"
:: [SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN));
}
void setup(void)
{
Serial.begin(19200);
Serial.println("Intializing ...");
initScl();
}
void loop(void) {
grabScl();
delay(DELAY);
releaseScl();
}

View File

@@ -0,0 +1,25 @@
Software License Agreement (BSD License)
Copyright (c) 2012, Adafruit Industries. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,328 @@
/*
* SoftI2CMaster.cpp -- Multi-instance software I2C Master library
*
*
* 2010-12 Tod E. Kurt, http://todbot.com/blog/
*
* This code takes some tricks from:
* http://codinglab.blogspot.com/2008/10/i2c-on-avr-using-bit-banging.html
*
* 2014, by Testato: update library and examples for follow Wires API of Arduino IDE 1.x
*
*/
#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
#include "SoftI2CMaster.h"
#include <util/delay.h>
#include <string.h>
#define i2cbitdelay 50
#define I2C_ACK 1
#define I2C_NAK 0
#define i2c_scl_release() \
*_sclDirReg &=~ _sclBitMask
#define i2c_sda_release() \
*_sdaDirReg &=~ _sdaBitMask
// sets SCL low and drives output
#define i2c_scl_lo() \
*_sclPortReg &=~ _sclBitMask; \
*_sclDirReg |= _sclBitMask;
// sets SDA low and drives output
#define i2c_sda_lo() \
*_sdaPortReg &=~ _sdaBitMask; \
*_sdaDirReg |= _sdaBitMask;
// set SCL high and to input (releases pin) (i.e. change to input,turnon pullup)
#define i2c_scl_hi() \
*_sclDirReg &=~ _sclBitMask; \
if(usePullups) { *_sclPortReg |= _sclBitMask; }
// set SDA high and to input (releases pin) (i.e. change to input,turnon pullup)
#define i2c_sda_hi() \
*_sdaDirReg &=~ _sdaBitMask; \
if(usePullups) { *_sdaPortReg |= _sdaBitMask; }
//
// Constructor
//
SoftI2CMaster::SoftI2CMaster()
{
// do nothing, use setPins() later
}
//
SoftI2CMaster::SoftI2CMaster(uint8_t sclPin, uint8_t sdaPin)
{
setPins(sclPin, sdaPin, true);
i2c_init();
}
//
SoftI2CMaster::SoftI2CMaster(uint8_t sclPin, uint8_t sdaPin, uint8_t pullups)
{
setPins(sclPin, sdaPin, pullups);
i2c_init();
}
//
// Turn Arduino pin numbers into PORTx, DDRx, and PINx
//
void SoftI2CMaster::setPins(uint8_t sclPin, uint8_t sdaPin, uint8_t pullups)
{
uint8_t port;
usePullups = pullups;
_sclPin = sclPin;
_sdaPin = sdaPin;
_sclBitMask = digitalPinToBitMask(sclPin);
_sdaBitMask = digitalPinToBitMask(sdaPin);
port = digitalPinToPort(sclPin);
_sclPortReg = portOutputRegister(port);
_sclDirReg = portModeRegister(port);
port = digitalPinToPort(sdaPin);
_sdaPortReg = portOutputRegister(port);
_sdaDirReg = portModeRegister(port);
}
//
//
//
uint8_t SoftI2CMaster::beginTransmission(uint8_t address)
{
i2c_start();
uint8_t rc = i2c_write((address<<1) | 0); // clr read bit
return rc;
}
//
uint8_t SoftI2CMaster::requestFrom(uint8_t address)
{
i2c_start();
uint8_t rc = i2c_write((address<<1) | 1); // set read bit
return rc;
}
//
uint8_t SoftI2CMaster::requestFrom(int address)
{
return requestFrom( (uint8_t) address);
}
//
uint8_t SoftI2CMaster::beginTransmission(int address)
{
return beginTransmission((uint8_t)address);
}
//
//
//
uint8_t SoftI2CMaster::endTransmission(void)
{
i2c_stop();
//return ret; // FIXME
return 0;
}
// must be called in:
// slave tx event callback
// or after beginTransmission(address)
uint8_t SoftI2CMaster::write(uint8_t data)
{
return i2c_write(data);
}
// must be called in:
// slave tx event callback
// or after beginTransmission(address)
void SoftI2CMaster::write(uint8_t* data, uint8_t quantity)
{
for(uint8_t i = 0; i < quantity; ++i){
write(data[i]);
}
}
// must be called in:
// slave tx event callback
// or after beginTransmission(address)
void SoftI2CMaster::write(char* data)
{
write((uint8_t*)data, strlen(data));
}
// must be called in:
// slave tx event callback
// or after beginTransmission(address)
void SoftI2CMaster::write(int data)
{
write((uint8_t)data);
}
//--------------------------------------------------------------------
void SoftI2CMaster::i2c_writebit( uint8_t c )
{
if ( c > 0 ) {
i2c_sda_hi();
} else {
i2c_sda_lo();
}
i2c_scl_hi();
_delay_us(i2cbitdelay);
i2c_scl_lo();
_delay_us(i2cbitdelay);
if ( c > 0 ) {
i2c_sda_lo();
}
_delay_us(i2cbitdelay);
}
//
uint8_t SoftI2CMaster::i2c_readbit(void)
{
i2c_sda_hi();
i2c_scl_hi();
_delay_us(i2cbitdelay);
uint8_t port = digitalPinToPort(_sdaPin);
volatile uint8_t* pinReg = portInputRegister(port);
uint8_t c = *pinReg; // I2C_PIN;
i2c_scl_lo();
_delay_us(i2cbitdelay);
return ( c & _sdaBitMask) ? 1 : 0;
}
// Inits bitbanging port, must be called before using the functions below
//
void SoftI2CMaster::i2c_init(void)
{
//I2C_PORT &=~ (_BV( I2C_SDA ) | _BV( I2C_SCL ));
//*_sclPortReg &=~ (_sdaBitMask | _sclBitMask);
i2c_sda_hi();
i2c_scl_hi();
_delay_us(i2cbitdelay);
}
// Send a START Condition
//
void SoftI2CMaster::i2c_start(void)
{
// set both to high at the same time
//I2C_DDR &=~ (_BV( I2C_SDA ) | _BV( I2C_SCL ));
//*_sclDirReg &=~ (_sdaBitMask | _sclBitMask);
i2c_sda_hi();
i2c_scl_hi();
_delay_us(i2cbitdelay);
i2c_sda_lo();
_delay_us(i2cbitdelay);
i2c_scl_lo();
_delay_us(i2cbitdelay);
}
void SoftI2CMaster::i2c_repstart(void)
{
// set both to high at the same time (releases drive on both lines)
//I2C_DDR &=~ (_BV( I2C_SDA ) | _BV( I2C_SCL ));
//*_sclDirReg &=~ (_sdaBitMask | _sclBitMask);
i2c_sda_hi();
i2c_scl_hi();
i2c_scl_lo(); // force SCL low
_delay_us(i2cbitdelay);
i2c_sda_release(); // release SDA
_delay_us(i2cbitdelay);
i2c_scl_release(); // release SCL
_delay_us(i2cbitdelay);
i2c_sda_lo(); // force SDA low
_delay_us(i2cbitdelay);
}
// Send a STOP Condition
//
void SoftI2CMaster::i2c_stop(void)
{
i2c_scl_hi();
_delay_us(i2cbitdelay);
i2c_sda_hi();
_delay_us(i2cbitdelay);
}
// write a byte to the I2C slave device
//
uint8_t SoftI2CMaster::i2c_write( uint8_t c )
{
for ( uint8_t i=0;i<8;i++) {
i2c_writebit( c & 128 );
c<<=1;
}
return i2c_readbit();
}
// read a byte from the I2C slave device
//
uint8_t SoftI2CMaster::i2c_read( uint8_t ack )
{
uint8_t res = 0;
for ( uint8_t i=0;i<8;i++) {
res <<= 1;
res |= i2c_readbit();
}
if ( ack )
i2c_writebit( 0 );
else
i2c_writebit( 1 );
_delay_us(i2cbitdelay);
return res;
}
// FIXME: this isn't right, surely
uint8_t SoftI2CMaster::read( uint8_t ack )
{
return i2c_read( ack );
}
//
uint8_t SoftI2CMaster::read()
{
return i2c_read( I2C_ACK );
}
//
uint8_t SoftI2CMaster::readLast()
{
return i2c_read( I2C_NAK );
}

View File

@@ -0,0 +1,68 @@
/*
* SoftI2CMaster.h -- Multi-instance software I2C Master library
*
* 2010-2012 Tod E. Kurt, http://todbot.com/blog/
* 2014, by Testato: update library and examples for follow Wires API of Arduino IDE 1.x
*
*/
#ifndef SoftI2CMaster_h
#define SoftI2CMaster_h
#include <inttypes.h>
#define _SOFTI2CMASTER_VERSION 13 // software version of this library
class SoftI2CMaster
{
private:
// per object data
uint8_t _sclPin;
uint8_t _sdaPin;
uint8_t _sclBitMask;
uint8_t _sdaBitMask;
volatile uint8_t *_sclPortReg;
volatile uint8_t *_sdaPortReg;
volatile uint8_t *_sclDirReg;
volatile uint8_t *_sdaDirReg;
uint8_t usePullups;
// private methods
void i2c_writebit( uint8_t c );
uint8_t i2c_readbit(void);
void i2c_init(void);
void i2c_start(void);
void i2c_repstart(void);
void i2c_stop(void);
uint8_t i2c_write( uint8_t c );
uint8_t i2c_read( uint8_t ack );
public:
// public methods
SoftI2CMaster();
SoftI2CMaster(uint8_t sclPin, uint8_t sdaPin);
SoftI2CMaster(uint8_t sclPin, uint8_t sdaPin, uint8_t usePullups);
void setPins(uint8_t sclPin, uint8_t sdaPin, uint8_t usePullups);
uint8_t beginTransmission(uint8_t address);
uint8_t beginTransmission(int address);
uint8_t endTransmission(void);
uint8_t write(uint8_t);
void write(uint8_t*, uint8_t);
void write(int);
void write(char*);
uint8_t requestFrom(int address);
uint8_t requestFrom(uint8_t address);
uint8_t read( uint8_t ack );
uint8_t read();
uint8_t readLast();
};
#endif

View File

@@ -0,0 +1,33 @@
Copyright (c) Tod E. Kurt, 2010-2015
---
LICENSE:
Creative Commons - Attribution - ShareAlike 3.0
http://creativecommons.org/licenses/by-sa/3.0/
See why we chose this license: http://www.inmojo.com/licenses/
This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
This is a human-readable summary of the full license.
You are free:
- to Share - to copy, distribute and transmit the work, and
- to Remix - to adapt the work
Under the following conditions:
- Attribution - You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work.)
- Share Alike - If you alter, transform, or build upon this work, you may distribute the resulting work only under the same, similar or a compatible license.
With the understanding that:
- Waiver - Any of the above conditions can be waived if you get permission from the copyright holder.
- Other Rights - In no way are any of the following rights affected by the license:
-- your fair dealing or fair use rights;
-- the author's moral rights; and
-- rights other persons may have either in the work itself or in how the work is used, such as publicity or privacy rights.
Notice - For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do that is with a link to
http://creativecommons.org/licenses/by-sa/3.0/