mirror of
https://github.com/KevinMidboe/Arduino.git
synced 2025-10-29 17:40:11 +00:00
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:
@@ -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.
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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 Wire’s 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 );
|
||||
}
|
||||
@@ -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 Wire’s 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
|
||||
@@ -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/
|
||||
|
||||
Reference in New Issue
Block a user