new i2c support for lpc on I2C2, working with infrared_i2c

This commit is contained in:
Gautier Hattenberger
2010-09-03 14:24:35 +00:00
parent b72f1419e9
commit f10ce38ced
6 changed files with 382 additions and 99 deletions
+243 -1
View File
@@ -1,7 +1,7 @@
/*
* $Id$
*
* Copyright (C) 2008 Pascal Brisset, Antoine Drouin
* Copyright (C) 2010 The Paparazzi Team
*
* This file is part of paparazzi.
*
@@ -32,6 +32,142 @@
#include "interrupt_hw.h"
///////////////////
// I2C Automaton //
///////////////////
static inline void I2cSendStart(struct i2c_periph* p) {
p->status = I2CStartRequested;
((i2cRegs_t *)(p->reg_addr))->conset = _BV(STA);
}
static inline void I2cSendAck(void* reg) {
((i2cRegs_t *)reg)->conset = _BV(AA);
}
static inline void I2cEndOfTransaction(struct i2c_periph* p) {
// handle fifo here
p->trans_extract_idx++;
if (p->trans_extract_idx >= I2C_TRANSACTION_QUEUE_LEN)
p->trans_extract_idx = 0;
// if no more transaction to process, stop here, else start next transaction
if (p->trans_extract_idx == p->trans_insert_idx) {
p->status = I2CIdle;
}
else {
I2cSendStart(p);
}
}
static inline void I2cFinished(struct i2c_periph* p, struct i2c_transaction* t) {
// transaction finished with success
t->status = I2CTransSuccess;
I2cEndOfTransaction(p);
}
static inline void I2cSendStop(struct i2c_periph* p, struct i2c_transaction* t) {
((i2cRegs_t *)(p->reg_addr))->conset = _BV(STO);
I2cFinished(p,t);
}
static inline void I2cFail(struct i2c_periph* p, struct i2c_transaction* t) {
((i2cRegs_t *)(p->reg_addr))->conset = _BV(STO);
t->status = I2CTransFailed;
p->status = I2CFailed;
// FIXME I2C should be reseted here
I2cEndOfTransaction(p);
}
static inline void I2cSendByte(void* reg, uint8_t b) {
((i2cRegs_t *)reg)->dat = b;
}
static inline void I2cReceive(void* reg, bool_t ack) {
if (ack) ((i2cRegs_t *)reg)->conset = _BV(AA);
else ((i2cRegs_t *)reg)->conclr = _BV(AAC);
}
static inline void I2cClearStart(void* reg) {
((i2cRegs_t *)reg)->conclr = _BV(STAC);
}
static inline void I2cClearIT(void* reg) {
((i2cRegs_t *)reg)->conclr = _BV(SIC);
}
static inline void I2cAutomaton(int32_t state, struct i2c_periph* p) {
struct i2c_transaction* trans = p->trans[p->trans_extract_idx];
switch (state) {
case I2C_START:
case I2C_RESTART:
// Set R/W flag
switch (trans->type) {
case I2CTransRx :
SetBit(trans->slave_addr,0);
break;
case I2CTransTx:
case I2CTransTxRx:
ClearBit(trans->slave_addr,0);
break;
}
I2cSendByte(p->reg_addr,trans->slave_addr);
I2cClearStart(p->reg_addr);
p->idx_buf = 0;
break;
case I2C_MR_DATA_ACK:
if (p->idx_buf < trans->len_r) {
trans->buf[p->idx_buf] = ((i2cRegs_t *)(p->reg_addr))->dat;
p->idx_buf++;
I2cReceive(p->reg_addr,p->idx_buf < trans->len_r - 1);
}
else {
/* error , we should have got NACK */
I2cSendStop(p,trans);
}
break;
case I2C_MR_SLA_ACK: /* At least one char */
/* Wait and reply with ACK or NACK */
I2cReceive(p->reg_addr,p->idx_buf < trans->len_r - 1);
break;
case I2C_MR_SLA_NACK:
case I2C_MT_SLA_NACK:
I2cSendStart(p);
break;
case I2C_MT_SLA_ACK:
case I2C_MT_DATA_ACK:
if (p->idx_buf < trans->len_w) {
I2cSendByte(p->reg_addr,trans->buf[p->idx_buf]);
p->idx_buf++;
} else {
if (trans->type == I2CTransTxRx) {
trans->type = I2CTransRx; /* FIXME should not change type */
p->idx_buf = 0;
trans->slave_addr |= 1;
I2cSendStart(p);
} else {
if (trans->stop_after_transmit) {
I2cSendStop(p,trans);
} else {
I2cFinished(p,trans);
}
}
}
break;
case I2C_MR_DATA_NACK:
if (p->idx_buf < trans->len_r) {
trans->buf[p->idx_buf] = ((i2cRegs_t *)(p->reg_addr))->dat;
}
I2cSendStop(p,trans);
break;
default:
I2cSendStop(p,trans);
//I2cFail(p,trans);
/* FIXME log error */
break;
}
}
#ifdef USE_I2C0
/* default clock speed 37.5KHz with our 15MHz PCLK
@@ -189,3 +325,109 @@ void i2c1_ISR(void)
#endif /* USE_I2C1 */
#ifdef USE_I2C2
/* default clock speed 37.5KHz with our 15MHz PCLK
I2C0_CLOCK = PCLK / (I2C0_SCLL + I2C0_SCLH) */
#ifndef I2C0_SCLL
#define I2C0_SCLL 200
#endif
#ifndef I2C0_SCLH
#define I2C0_SCLH 200
#endif
/* adjust for other PCLKs */
#if (PCLK == 15000000)
#define I2C0_SCLL_D I2C0_SCLL
#define I2C0_SCLH_D I2C0_SCLH
#else
#if (PCLK == 30000000)
#define I2C0_SCLL_D (2*I2C0_SCLL)
#define I2C0_SCLH_D (2*I2C0_SCLH)
#else
#if (PCLK == 60000000)
#define I2C0_SCLL_D (4*I2C0_SCLL)
#define I2C0_SCLH_D (4*I2C0_SCLH)
#else
#error unknown PCLK frequency
#endif
#endif
#endif
#ifndef I2C0_VIC_SLOT
#define I2C0_VIC_SLOT 9
#endif
void i2c0_ISR(void) __attribute__((naked));
/* SDA0 on P0.3 */
/* SCL0 on P0.2 */
void i2c2_hw_init ( void ) {
i2c2.reg_addr = I2C0;
/* set P0.2 and P0.3 to I2C0 */
PINSEL0 |= 1 << 4 | 1 << 6;
/* clear all flags */
I2C0CONCLR = _BV(AAC) | _BV(SIC) | _BV(STAC) | _BV(I2ENC);
/* enable I2C */
I2C0CONSET = _BV(I2EN);
/* set bitrate */
I2C0SCLL = I2C0_SCLL_D;
I2C0SCLH = I2C0_SCLH_D;
// initialize the interrupt vector
VICIntSelect &= ~VIC_BIT(VIC_I2C0); // I2C0 selected as IRQ
VICIntEnable = VIC_BIT(VIC_I2C0); // I2C0 interrupt enabled
_VIC_CNTL(I2C0_VIC_SLOT) = VIC_ENABLE | VIC_I2C0;
_VIC_ADDR(I2C0_VIC_SLOT) = (uint32_t)i2c0_ISR; // address of the ISR
}
#define I2C_STATUS_REG I2C0STAT
void i2c0_ISR(void)
{
ISR_ENTRY();
uint32_t state = I2C_STATUS_REG;
I2cAutomaton(state,&i2c2);
I2cClearIT(i2c2.reg_addr);
VICVectAddr = 0x00000000; // clear this interrupt from the VIC
ISR_EXIT(); // recover registers and return
}
bool_t i2c_submit(struct i2c_periph* p, struct i2c_transaction* t) {
uint8_t idx;
idx = p->trans_insert_idx + 1;
if (idx >= I2C_TRANSACTION_QUEUE_LEN) idx = 0;
if (idx == p->trans_extract_idx)
return FALSE; // queue full
t->status = I2CTransPending;
// disable irq
int_disable();
p->trans[p->trans_insert_idx] = t;
p->trans_insert_idx = idx;
/* if peripheral is idle, start the transaction */
if (p->status == I2CIdle)
I2cSendStart(p);
/* else it will be started by the interrupt handler when the previous transactions completes */
// enable irq
int_enable();
return TRUE;
}
#endif /* USE_I2C2 */
+1 -22
View File
@@ -199,28 +199,7 @@ extern void i2c1_hw_init(void);
#ifdef USE_I2C2
extern void i2c0_hw_init(void);
#define I2c0SendAck() { I2C0CONSET = _BV(AA); }
#define I2c0Finished() { \
if (i2c0_finished) *i2c0_finished = TRUE; \
i2c0_status = I2C_IDLE; \
}
#define I2c0SendStop() { \
I2C0CONSET = _BV(STO); \
I2c0Finished(); \
}
#define I2c0SendStart() { I2C0CONSET = _BV(STA); }
#define I2c0SendByte(b) { I2C_DATA_REG = b; }
#define I2c0Receive(_ack) { \
if (_ack) I2C0CONSET = _BV(AA); \
else I2C0CONCLR = _BV(AAC); \
}
#define I2c0ClearStart() { I2C0CONCLR = _BV(STAC); }
#define I2c0ClearIT() { I2C0CONCLR = _BV(SIC); }
extern void i2c2_hw_init(void);
#endif
+39 -1
View File
@@ -15,7 +15,8 @@ enum I2CTransactionStatus {
I2CTransPending,
I2CTransRunning,
I2CTransSuccess,
I2CTransFailed
I2CTransFailed,
I2CTransDone
};
enum I2CStatus {
@@ -145,4 +146,41 @@ extern void i2c2_init(void);
extern void i2c_init(struct i2c_periph* p);
extern bool_t i2c_submit(struct i2c_periph* p, struct i2c_transaction* t);
#define I2CReceive(_p, _t, _s_addr, _len) { \
_t.type = I2CTransRx; \
_t.slave_addr = _s_addr; \
_t.len_r = _len; \
_t.len_w = 0; \
_t.stop_after_transmit = TRUE; \
i2c_submit(&(_p),&(_t)); \
}
#define I2CTransmit(_p, _t, _s_addr, _len) { \
_t.type = I2CTransTx; \
_t.slave_addr = _s_addr; \
_t.len_r = 0; \
_t.len_w = _len; \
_t.stop_after_transmit = TRUE; \
i2c_submit(&(_p),&(_t)); \
}
#define I2CTransmitNoStop(_p, _t, _s_addr, _len) { \
_t.type = I2CTransTx; \
_t.slave_addr = _s_addr; \
_t.len_r = 0; \
_t.len_w = _len; \
_t.stop_after_transmit = FALSE; \
i2c_submit(&(_p),&(_t)); \
}
#define I2CTransceive(_p, _t, _s_addr, _len_w, _len_r) { \
_t.type = I2CTransTxRx; \
_t.slave_addr = _s_addr; \
_t.len_r = _len_r; \
_t.len_w = _len_w; \
_t.stop_after_transmit = TRUE; \
i2c_submit(&(_p),&(_t)); \
}
#endif /* I2C_H */
+5 -1
View File
@@ -79,7 +79,7 @@
#include "srf08.h"
#endif
#if defined USE_I2C0 || USE_I2C1
#if defined USE_I2C0 || USE_I2C1 || USE_I2C2
#include "i2c.h"
#endif
@@ -741,6 +741,10 @@ void init_ap( void ) {
i2c1_init();
#endif
#ifdef USE_I2C2
i2c2_init();
#endif
#ifdef USE_AIRSPEED_ETS
airspeed_ets_init();
#endif
+78 -72
View File
@@ -21,7 +21,6 @@
*/
#include "sensors/infrared_i2c.h"
#include "i2c.h"
#include "estimator.h"
// IR I2C definitions
@@ -34,15 +33,6 @@
#define IR_HOR_I2C_SELECT_IR1 (0 << 5)
#define IR_HOR_I2C_SELECT_IR2 (1 << 5)
#define IR_I2C_IDLE 0
#define IR_I2C_READ_IR1 1
#define IR_I2C_IR2_SELECTED 2
#define IR_I2C_READ_TOP 3
#define IR_I2C_READ_IR2 4
#define IR_I2C_IR1_SELECTED 5
#define IR_I2C_CONFIGURE_HOR 6
#define IR_I2C_CONFIGURE_VER 7
#ifndef IR_I2C_IR1_NEUTRAL
#define IR_I2C_IR1_NEUTRAL 0
#endif
@@ -138,28 +128,39 @@ int16_t ir_i2c_top;
float ir_i2c_phi, ir_i2c_theta;
volatile bool_t ir_i2c_done;
bool_t ir_i2c_data_available;
uint8_t ir_i2c_conf_word;
bool_t ir_i2c_conf_done;
bool_t ir_i2c_conf_hor_done, ir_i2c_conf_ver_done;
// Local variables
static uint8_t ir_i2c_status;
#define IR_I2C_IDLE 0
#define IR_I2C_READ_IR1 1
#define IR_I2C_IR2_SELECTED 2
#define IR_I2C_READ_IR2 3
#define IR_I2C_IR1_SELECTED 4
#define IR_I2C_CONFIGURE_HOR 5
static uint8_t ir_i2c_hor_status;
#define NO_CONF_WORD 0xff
#define ValidConfWord(_x) (_x < 0x4)
// I2C structure
struct i2c_transaction irh_trans, irv_trans;
//FIXME standard infrared should not ba ADC-dependent
void ir_init(void) {}
/** Initialisation
*/
void infrared_i2c_init( void ) {
ir_i2c_done = TRUE;
ir_i2c_data_available = FALSE;
ir_i2c_status = IR_I2C_IDLE;
ir_i2c_hor_status = IR_I2C_IDLE;
ir_i2c_conf_word = IR_I2C_DEFAULT_CONF;
ir_i2c_conf_done = FALSE;
ir_i2c_conf_hor_done = FALSE;
ir_i2c_conf_ver_done = FALSE;
irh_trans.status = I2CTransDone;
irv_trans.status = I2CTransDone;
// Initialisation of standard infrared interface
ir_roll_neutral = RadOfDeg(IR_ROLL_NEUTRAL_DEFAULT);
@@ -175,21 +176,31 @@ void infrared_i2c_init( void ) {
ir_vertical_correction = IR_VERTICAL_CORRECTION;
}
#include "led.h"
void infrared_i2c_update( void ) {
#if ! (defined SITL || defined HITL)
if (ir_i2c_done && ir_i2c_status == IR_I2C_IDLE) {
if (ValidConfWord(ir_i2c_conf_word) && !ir_i2c_conf_done) {
i2c0_buf[0] = 0;
i2c0_buf[0] = ir_i2c_conf_word | IR_HOR_OC_BIT | IR_START_CONV;
i2c0_transmit(IR_HOR_I2C_ADDR, 1, &ir_i2c_done);
ir_i2c_done = FALSE;
ir_i2c_status = IR_I2C_CONFIGURE_HOR;
// IR horizontal
if (irh_trans.status == I2CTransDone && ir_i2c_hor_status == IR_I2C_IDLE) {
if (ValidConfWord(ir_i2c_conf_word) && !ir_i2c_conf_hor_done) {
irh_trans.buf[0] = ir_i2c_conf_word | IR_HOR_OC_BIT | IR_START_CONV ;
I2CTransmit(i2c2, irh_trans, IR_HOR_I2C_ADDR, 1);
ir_i2c_hor_status = IR_I2C_CONFIGURE_HOR;
} else {
// Read next values
i2c0_receive(IR_HOR_I2C_ADDR, 3, &ir_i2c_done);
ir_i2c_done = FALSE;
I2CReceive(i2c2, irh_trans, IR_HOR_I2C_ADDR, 3);
ir_i2c_data_available = FALSE;
ir_i2c_hor_status = IR_I2C_READ_IR1;
}
}
// IR vertical
if (irv_trans.status == I2CTransDone) {
if (ValidConfWord(ir_i2c_conf_word) && !ir_i2c_conf_ver_done) {
irv_trans.buf[0] = ir_i2c_conf_word | IR_VER_OC_BIT;
I2CTransmit(i2c2, irv_trans, IR_VER_I2C_ADDR, 1);
} else {
// Read next values
I2CReceive(i2c2, irv_trans, IR_VER_I2C_ADDR, 2);
ir_i2c_data_available = FALSE;
ir_i2c_status = IR_I2C_READ_IR1;
}
}
#else /* SITL || HITL */
@@ -198,79 +209,74 @@ void infrared_i2c_update( void ) {
#endif
}
void infrared_i2c_event( void ) {
void infrared_i2c_hor_event( void ) {
#if ! (defined SITL || defined HITL)
switch (ir_i2c_status) {
irh_trans.status = I2CTransDone;
switch (ir_i2c_hor_status) {
case IR_I2C_IDLE :
break;
case IR_I2C_READ_IR1 :
if (bit_is_set(i2c0_buf[2],7)) {
i2c0_receive(IR_HOR_I2C_ADDR, 3, &ir_i2c_done);
ir_i2c_done = FALSE;
if (bit_is_set(irh_trans.buf[2],7)) {
I2CReceive(i2c2, irh_trans, IR_HOR_I2C_ADDR, 3);
break;
}
// Read IR1 value
ir_i2c_ir1 = (i2c0_buf[0]<<8) | i2c0_buf[1];
ir_i2c_ir1 = (irh_trans.buf[0]<<8) | irh_trans.buf[1];
// Select IR2 channel
i2c0_buf[0] = 0;
i2c0_buf[0] = IR_HOR_I2C_SELECT_IR2 | IR_HOR_OC_BIT | ir_i2c_conf_word | IR_START_CONV;
i2c0_transmit(IR_HOR_I2C_ADDR, 1, &ir_i2c_done);
ir_i2c_done = FALSE;
ir_i2c_status = IR_I2C_IR2_SELECTED;
irh_trans.buf[0] = IR_HOR_I2C_SELECT_IR2 | IR_HOR_OC_BIT | ir_i2c_conf_word | IR_START_CONV;
I2CTransmit(i2c2, irh_trans, IR_HOR_I2C_ADDR, 1);
ir_i2c_hor_status = IR_I2C_IR2_SELECTED;
break;
case IR_I2C_IR2_SELECTED :
// IR2 selected, asking for TOP value
i2c0_receive(IR_VER_I2C_ADDR, 2, &ir_i2c_done);
ir_i2c_done = FALSE;
ir_i2c_status = IR_I2C_READ_TOP;
break;
case IR_I2C_READ_TOP :
// Read TOP value
ir_i2c_top = (i2c0_buf[0]<<8) | i2c0_buf[1];
// Asking for IR2 value
i2c0_receive(IR_HOR_I2C_ADDR, 3, &ir_i2c_done);
ir_i2c_done = FALSE;
ir_i2c_status = IR_I2C_READ_IR2;
// IR2 selected, asking for IR2 value
I2CReceive(i2c2, irh_trans, IR_HOR_I2C_ADDR, 3);
ir_i2c_hor_status = IR_I2C_READ_IR2;
break;
case IR_I2C_READ_IR2 :
// Read IR2 value
if (bit_is_set(i2c0_buf[2],7)) {
i2c0_receive(IR_HOR_I2C_ADDR, 3, &ir_i2c_done);
ir_i2c_done = FALSE;
if (bit_is_set(irh_trans.buf[2],7)) {
I2CReceive(i2c2, irh_trans, IR_HOR_I2C_ADDR, 3);
break;
}
ir_i2c_ir2 = (i2c0_buf[0]<<8) | i2c0_buf[1];
ir_i2c_ir2 = (irh_trans.buf[0]<<8) | irh_trans.buf[1];
// Update estimator
ir_i2c_data_available = TRUE;
ir_update();
estimator_update_state_infrared();
// Select IR1 channel
i2c0_buf[0] = 0;
i2c0_buf[0] = IR_HOR_I2C_SELECT_IR1 | IR_HOR_OC_BIT | ir_i2c_conf_word | IR_START_CONV;
i2c0_transmit(IR_HOR_I2C_ADDR, 1, &ir_i2c_done);
ir_i2c_done = FALSE;
ir_i2c_status = IR_I2C_IR1_SELECTED;
irh_trans.buf[0] = IR_HOR_I2C_SELECT_IR1 | IR_HOR_OC_BIT | ir_i2c_conf_word | IR_START_CONV;
I2CTransmit(i2c2, irh_trans, IR_HOR_I2C_ADDR, 1);
ir_i2c_hor_status = IR_I2C_IR1_SELECTED;
break;
case IR_I2C_IR1_SELECTED :
// End reading cycle
ir_update();
estimator_update_state_infrared();
ir_i2c_status = IR_I2C_IDLE;
ir_i2c_hor_status = IR_I2C_IDLE;
break;
case IR_I2C_CONFIGURE_HOR :
// HOR configured, now configuring TOP
i2c0_buf[0] = 0;
i2c0_buf[0] = ir_i2c_conf_word | IR_VER_OC_BIT;
i2c0_transmit(IR_VER_I2C_ADDR, 1, &ir_i2c_done);
ir_i2c_done = FALSE;
ir_i2c_status = IR_I2C_CONFIGURE_VER;
break;
case IR_I2C_CONFIGURE_VER :
// VER configured, end conf cycle
ir_i2c_conf_done = TRUE;
ir_i2c_status = IR_I2C_IDLE;
// End conf cycle
ir_i2c_conf_hor_done = TRUE;
ir_i2c_hor_status = IR_I2C_IDLE;
break;
}
#endif /* !SITL && !HITL */
}
void infrared_i2c_ver_event( void ) {
#if ! (defined SITL || defined HITL)
irv_trans.status = I2CTransDone;
// Read TOP value
if (irv_trans.type == I2CTransRx) {
ir_i2c_top = (irv_trans.buf[0]<<8) | irv_trans.buf[1];
ir_i2c_data_available = TRUE;
ir_update();
estimator_update_state_infrared();
}
if (irv_trans.type == I2CTransTx) {
ir_i2c_conf_ver_done = TRUE;
}
#endif /* !SITL && !HITL */
}
#include "stdio.h"
void ir_update(void) {
+16 -2
View File
@@ -30,6 +30,7 @@
#include "std.h"
#include "airframe.h"
#include "infrared.h"
#include "i2c.h"
extern int16_t ir_i2c_ir1;
extern int16_t ir_i2c_ir2;
@@ -37,13 +38,26 @@ extern int16_t ir_i2c_top;
extern volatile bool_t ir_i2c_done;
extern bool_t ir_i2c_data_available;
extern uint8_t ir_i2c_conf_word;
extern bool_t ir_i2c_conf_hor_done, ir_i2c_conf_ver_done;
extern struct i2c_transaction irh_trans, irv_trans;
extern void infrared_i2c_init( void );
extern void infrared_i2c_update( void );
extern void infrared_i2c_event( void );
extern void infrared_i2c_hor_event( void );
extern void infrared_i2c_ver_event( void );
#define infrared_i2cEvent() { if (ir_i2c_done) infrared_i2c_event(); }
#define infrared_i2cEvent() { \
if (irh_trans.status == I2CTransSuccess) infrared_i2c_hor_event(); \
if (irv_trans.status == I2CTransSuccess) infrared_i2c_ver_event(); \
}
#define infrared_i2cDownlink() DOWNLINK_SEND_DEBUG_IR_I2C(DefaultChannel, &ir_i2c_ir1, &ir_i2c_ir2, &ir_i2c_top)
#define infrared_i2c_SetConfWord(_v) { \
ir_i2c_conf_hor_done = FALSE; \
ir_i2c_conf_ver_done = FALSE; \
ir_i2c_conf_word = _v; \
}
#endif // INFRARED_I2C_H