kimera: Improve method to checkout i2c timeout
This commit is contained in:
parent
24483be2f7
commit
a66936bf2a
@ -90,6 +90,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define NO_ACTION_MACRO
|
#define NO_ACTION_MACRO
|
||||||
//#define NO_ACTION_FUNCTION
|
//#define NO_ACTION_FUNCTION
|
||||||
|
|
||||||
#define NO_SUSPEND_POWER_DOWN
|
//#define NO_SUSPEND_POWER_DOWN
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -18,78 +18,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#include <avr/interrupt.h>
|
#include <avr/interrupt.h>
|
||||||
#include <avr/wdt.h>
|
#include <avr/wdt.h>
|
||||||
#include <util/delay.h>
|
#include <util/delay.h>
|
||||||
|
#include "timer.h"
|
||||||
#include "i2cmaster.h"
|
#include "i2cmaster.h"
|
||||||
#include "i2c_wrapper.h"
|
#include "i2c_wrapper.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
#define wdt_intr_enable(value) \
|
|
||||||
__asm__ __volatile__ ( \
|
|
||||||
"in __tmp_reg__,__SREG__" "\n\t" \
|
|
||||||
"cli" "\n\t" \
|
|
||||||
"wdr" "\n\t" \
|
|
||||||
"sts %0,%1" "\n\t" \
|
|
||||||
"out __SREG__,__tmp_reg__" "\n\t" \
|
|
||||||
"sts %0,%2" "\n\t" \
|
|
||||||
: /* no outputs */ \
|
|
||||||
: "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \
|
|
||||||
"r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \
|
|
||||||
"r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | \
|
|
||||||
_BV(WDIE) | (value & 0x07)) ) \
|
|
||||||
: "r0" \
|
|
||||||
)
|
|
||||||
|
|
||||||
#define SCL_CLOCK 400000L
|
|
||||||
#define SCL_DURATION (1000000L/SCL_CLOCK)/2
|
|
||||||
|
|
||||||
static uint8_t i2c_wdt_enabled = 0;
|
|
||||||
|
|
||||||
extern uint8_t i2c_force_stop;
|
|
||||||
|
|
||||||
static void wdt_init(void);
|
|
||||||
|
|
||||||
void i2c_wrapper_init(void)
|
void i2c_wrapper_init(void)
|
||||||
{
|
{
|
||||||
|
dprintf("I2C Init\n");
|
||||||
|
|
||||||
|
/* init timer */
|
||||||
|
timer_init();
|
||||||
|
|
||||||
/* init i2c */
|
/* init i2c */
|
||||||
i2c_init();
|
i2c_init();
|
||||||
|
|
||||||
/* init watch dog */
|
|
||||||
wdt_init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void i2c_wrapper_task(void)
|
void i2c_wrapper_task(void)
|
||||||
{
|
{
|
||||||
/* reset watch dog counter */
|
|
||||||
wdt_reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void wdt_init(void)
|
|
||||||
{
|
|
||||||
cli();
|
|
||||||
wdt_reset();
|
|
||||||
wdt_intr_enable(WDTO_2S);
|
|
||||||
sei();
|
|
||||||
}
|
|
||||||
|
|
||||||
ISR(WDT_vect)
|
|
||||||
{
|
|
||||||
xprintf("i2c timeout\n");
|
|
||||||
|
|
||||||
/* let slave to release SDA */
|
|
||||||
TWCR = 0;
|
|
||||||
DDRD |= (1<<PD0);
|
|
||||||
DDRD &= ~(1<<PD1);
|
|
||||||
if (!(PIND & (1<<PD1))) {
|
|
||||||
for (uint8_t i = 0; i < 9; i++) {
|
|
||||||
PORTD &= ~(1<<PD0);
|
|
||||||
_delay_us(SCL_DURATION);
|
|
||||||
PORTD |= (1<<PD0);
|
|
||||||
_delay_us(SCL_DURATION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* send stop condition */
|
|
||||||
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
|
|
||||||
|
|
||||||
/* escape from loop */
|
|
||||||
i2c_force_stop = 1;
|
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,10 @@
|
|||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <compat/twi.h>
|
#include <compat/twi.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
#include <i2cmaster.h>
|
#include <i2cmaster.h>
|
||||||
|
#include "timer.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
|
||||||
@ -20,9 +22,30 @@
|
|||||||
|
|
||||||
/* I2C clock in Hz */
|
/* I2C clock in Hz */
|
||||||
#define SCL_CLOCK 400000L
|
#define SCL_CLOCK 400000L
|
||||||
|
#define SCL_DURATION (1000000L/SCL_CLOCK)/2
|
||||||
|
|
||||||
volatile uint8_t i2c_force_stop = 0;
|
volatile uint8_t i2c_force_stop = 0;
|
||||||
|
#define TIMEOUT 3000
|
||||||
#define CHECK_FORCE_STOP() if(i2c_force_stop){i2c_force_stop=0;break;}
|
#define CHECK_FORCE_STOP() if(i2c_force_stop){i2c_force_stop=0;break;}
|
||||||
|
#define CHECK_TIMEOUT_PRE() \
|
||||||
|
uint16_t start; \
|
||||||
|
uint8_t once = 1;
|
||||||
|
#define CHECK_TIMEOUT_PRE2() \
|
||||||
|
once = 1;
|
||||||
|
#define CHECK_TIMEOUT(retval) { \
|
||||||
|
if (once) { \
|
||||||
|
start = timer_read(); \
|
||||||
|
once = 0; \
|
||||||
|
} \
|
||||||
|
else { \
|
||||||
|
if (timer_elapsed(start) >= TIMEOUT) { \
|
||||||
|
i2c_forceStop(); \
|
||||||
|
return retval; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i2c_forceStop(void);
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
Initialization of the I2C bus interface. Need to be called only once
|
Initialization of the I2C bus interface. Need to be called only once
|
||||||
@ -49,7 +72,8 @@ unsigned char i2c_start(unsigned char address)
|
|||||||
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
|
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
|
||||||
|
|
||||||
// wait until transmission completed
|
// wait until transmission completed
|
||||||
while(!(TWCR & (1<<TWINT))) { CHECK_FORCE_STOP(); };
|
CHECK_TIMEOUT_PRE();
|
||||||
|
while(!(TWCR & (1<<TWINT))) { CHECK_TIMEOUT(2); };
|
||||||
|
|
||||||
// check value of TWI Status Register. Mask prescaler bits.
|
// check value of TWI Status Register. Mask prescaler bits.
|
||||||
twst = TW_STATUS & 0xF8;
|
twst = TW_STATUS & 0xF8;
|
||||||
@ -60,7 +84,8 @@ unsigned char i2c_start(unsigned char address)
|
|||||||
TWCR = (1<<TWINT) | (1<<TWEN);
|
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||||
|
|
||||||
// wail until transmission completed and ACK/NACK has been received
|
// wail until transmission completed and ACK/NACK has been received
|
||||||
while(!(TWCR & (1<<TWINT))) { CHECK_FORCE_STOP(); };
|
CHECK_TIMEOUT_PRE2();
|
||||||
|
while(!(TWCR & (1<<TWINT))) { CHECK_TIMEOUT(2); };
|
||||||
|
|
||||||
// check value of TWI Status Register. Mask prescaler bits.
|
// check value of TWI Status Register. Mask prescaler bits.
|
||||||
twst = TW_STATUS & 0xF8;
|
twst = TW_STATUS & 0xF8;
|
||||||
@ -109,7 +134,8 @@ void i2c_start_wait(unsigned char address)
|
|||||||
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
|
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
|
||||||
|
|
||||||
// wait until stop condition is executed and bus released
|
// wait until stop condition is executed and bus released
|
||||||
while(TWCR & (1<<TWSTO)) { CHECK_FORCE_STOP(); };
|
CHECK_TIMEOUT_PRE();
|
||||||
|
while(TWCR & (1<<TWSTO)) { CHECK_TIMEOUT(); };
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -144,7 +170,8 @@ void i2c_stop(void)
|
|||||||
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
|
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
|
||||||
|
|
||||||
// wait until stop condition is executed and bus released
|
// wait until stop condition is executed and bus released
|
||||||
while(TWCR & (1<<TWSTO)) { CHECK_FORCE_STOP(); };
|
CHECK_TIMEOUT_PRE();
|
||||||
|
while(TWCR & (1<<TWSTO)) { CHECK_TIMEOUT(); };
|
||||||
|
|
||||||
}/* i2c_stop */
|
}/* i2c_stop */
|
||||||
|
|
||||||
@ -165,7 +192,8 @@ unsigned char i2c_write( unsigned char data )
|
|||||||
TWCR = (1<<TWINT) | (1<<TWEN);
|
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||||
|
|
||||||
// wait until transmission completed
|
// wait until transmission completed
|
||||||
while(!(TWCR & (1<<TWINT))) { CHECK_FORCE_STOP() };
|
CHECK_TIMEOUT_PRE();
|
||||||
|
while(!(TWCR & (1<<TWINT))) { CHECK_TIMEOUT(2) };
|
||||||
|
|
||||||
// check value of TWI Status Register. Mask prescaler bits
|
// check value of TWI Status Register. Mask prescaler bits
|
||||||
twst = TW_STATUS & 0xF8;
|
twst = TW_STATUS & 0xF8;
|
||||||
@ -183,7 +211,8 @@ Return: byte read from I2C device
|
|||||||
unsigned char i2c_readAck(void)
|
unsigned char i2c_readAck(void)
|
||||||
{
|
{
|
||||||
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
|
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
|
||||||
while(!(TWCR & (1<<TWINT))) { CHECK_FORCE_STOP(); };
|
CHECK_TIMEOUT_PRE();
|
||||||
|
while(!(TWCR & (1<<TWINT))) { CHECK_TIMEOUT(2); };
|
||||||
|
|
||||||
return TWDR;
|
return TWDR;
|
||||||
|
|
||||||
@ -198,8 +227,32 @@ Return: byte read from I2C device
|
|||||||
unsigned char i2c_readNak(void)
|
unsigned char i2c_readNak(void)
|
||||||
{
|
{
|
||||||
TWCR = (1<<TWINT) | (1<<TWEN);
|
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||||
while(!(TWCR & (1<<TWINT))) { CHECK_FORCE_STOP(); };
|
CHECK_TIMEOUT_PRE();
|
||||||
|
while(!(TWCR & (1<<TWINT))) { CHECK_TIMEOUT(2); };
|
||||||
|
|
||||||
return TWDR;
|
return TWDR;
|
||||||
|
|
||||||
}/* i2c_readNak */
|
}/* i2c_readNak */
|
||||||
|
|
||||||
|
void i2c_forceStop(void)
|
||||||
|
{
|
||||||
|
xprintf("i2c timeout\n");
|
||||||
|
|
||||||
|
/* let slave to release SDA */
|
||||||
|
TWCR = 0;
|
||||||
|
DDRD |= (1<<PD0);
|
||||||
|
DDRD &= ~(1<<PD1);
|
||||||
|
_delay_us(30);
|
||||||
|
if ((PIND & (1<<PD1)) == 0) {
|
||||||
|
for (uint8_t i = 0; i < 9; i++) {
|
||||||
|
PORTD &= ~(1<<PD0);
|
||||||
|
_delay_us(SCL_DURATION);
|
||||||
|
PORTD |= (1<<PD0);
|
||||||
|
_delay_us(SCL_DURATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DDRD &= ~(1<<PD0);
|
||||||
|
|
||||||
|
/* send stop condition */
|
||||||
|
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user