mirror of
https://github.com/KevinMidboe/Arduino.git
synced 2026-01-14 13:15:35 +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.
|
||||
Reference in New Issue
Block a user