Browse Source

Offload I2C work onto interrupts. For now, we just spin while waiting

for the I2C activity to complete.
master
Gavan Fantom 13 years ago
parent
commit
0f508fb424
  1. 157
      i2c.c
  2. 26
      i2c.h
  3. 15
      main.c
  4. 2
      types.h
  5. 124
      wmp.c

157
i2c.c

@ -1,5 +1,6 @@
#include "i2c.h"
#include "interrupt.h"
#define I2CBASE 0xE001C000
@ -21,6 +22,11 @@
#define SI (IREG(I2CONSET) & SIFLAG)
void __attribute__((interrupt("IRQ"))) i2c_interrupt_handler(void);
struct i2c_transaction *i2c_transaction;
int i2c_bytes;
void init_i2c(void)
{
IREG(I2CONSET) = 0x40; /* Enable I2C ready for Master Tx */
@ -32,17 +38,7 @@ void init_i2c(void)
IWREG(I2SCLL) = 73; /* ~100kHz */
IWREG(I2SCLH) = 73;
#endif
}
int i2cstat;
int i2c_wait(void)
{
int stat;
while (!SI);
stat = IREG(I2STAT);
i2cstat = stat;
return stat;
interrupt_register(I2C0, i2c_interrupt_handler);
}
int i2c_conreg(void)
@ -55,61 +51,110 @@ int i2c_statreg(void)
return IREG(I2STAT);
}
bool i2c_send_start(void)
bool i2c_busy(void)
{
IREG(I2CONCLR) = STOFLAG | STAFLAG;
IREG(I2CONSET) = STAFLAG;
switch (i2c_wait()) {
case 0x08:
case 0x10:
return TRUE;
default:
i2c_send_stop();
return FALSE;
}
return i2c_transaction != NULL;
}
bool i2c_send_address(int addr, bool write)
bool i2c_start_transaction(struct i2c_transaction *t)
{
return i2c_send_data((addr<<1) + (write?0:1));
if (i2c_transaction)
return FALSE;
i2c_transaction = t;
*(t->result) = I2C_IN_PROGRESS;
/* Paranoia in case we left things in a bad state */
IREG(I2CONCLR) = STOFLAG | STAFLAG;
/* Set it all going */
IREG(I2CONSET) = STAFLAG;
return TRUE;
}
bool i2c_send_data(unsigned int data)
void __attribute__((interrupt("IRQ"))) i2c_interrupt_handler(void)
{
IREG(I2DAT) = data;
IREG(I2CONCLR) = STAFLAG | STOFLAG | SIFLAG;
switch (i2c_wait()) {
case 0x18:
case 0x28:
case 0x40:
return TRUE;
default:
i2c_send_stop();
return FALSE;
int stat = IREG(I2STAT);
if (!i2c_transaction) {
IREG(I2CONSET) = STOFLAG;
IREG(I2CONCLR) = STAFLAG | AAFLAG | SIFLAG;
interrupt_clear();
return;
}
}
bool i2c_receive_data(unsigned int *data, bool last)
{
if (!last)
IREG(I2CONSET) = AAFLAG;
IREG(I2CONCLR) = STAFLAG | STOFLAG | SIFLAG | (last?AAFLAG:0);
switch (i2c_wait()) {
case 0x50:
case 0x58:
*data = IREG(I2DAT);
return TRUE;
default:
i2c_send_stop();
return FALSE;
switch (stat) {
case 0x08: /* START transmitted */
case 0x10: /* repeated START transmitted */
IREG(I2DAT) = i2c_transaction->address;
IREG(I2CONCLR) = STAFLAG | STOFLAG | SIFLAG;
i2c_bytes = 0;
break;
case 0x18: /* SA+W transmitted, ACK received */
case 0x28: /* data transmitted, ACK received */
if (i2c_bytes < i2c_transaction->bytes) {
IREG(I2DAT) = i2c_transaction->data[i2c_bytes++];
IREG(I2CONCLR) = STAFLAG | STOFLAG | SIFLAG;
} else {
*(i2c_transaction->result) = I2C_SUCCESS;
if (i2c_transaction->next) {
i2c_transaction = i2c_transaction->next;
i2c_bytes = 0;
IREG(I2CONSET) = STAFLAG;
IREG(I2CONCLR) = STOFLAG | AAFLAG | SIFLAG;
} else {
i2c_transaction = NULL;
IREG(I2CONSET) = STOFLAG;
IREG(I2CONCLR) = STAFLAG | AAFLAG | SIFLAG;
}
}
break;
case 0x50: /* data received, ACK returned */
i2c_transaction->data[i2c_bytes++] = IREG(I2DAT);
/* fall through */
case 0x40: /* SA+R transmitted, ACK received */
if (i2c_bytes < (i2c_transaction->bytes-1)) {
IREG(I2CONSET) = AAFLAG;
IREG(I2CONCLR) = STAFLAG | STOFLAG | SIFLAG;
} else {
IREG(I2CONCLR) = STAFLAG | STOFLAG | SIFLAG
| AAFLAG;
}
break;
case 0x58: /* data received, NACK returned */
i2c_transaction->data[i2c_bytes] = IREG(I2DAT);
*(i2c_transaction->result) = I2C_SUCCESS;
if (i2c_transaction->next) {
i2c_transaction = i2c_transaction->next;
i2c_bytes = 0;
IREG(I2CONSET) = STAFLAG;
IREG(I2CONCLR) = STOFLAG | AAFLAG | SIFLAG;
} else {
i2c_transaction = NULL;
IREG(I2CONSET) = STOFLAG;
IREG(I2CONCLR) = STAFLAG | AAFLAG | SIFLAG;
}
break;
case 0x20: /* SA+W transmitted, NACK received */
case 0x30: /* data transmitted, NACK received */
case 0x48: /* SA+R transmitted, NACK received */
case 0x38: /* arbitration lost during SA+W or data */
case 0x00: /* bus error */
*(i2c_transaction->result) = I2C_FAIL;
i2c_transaction = NULL;
IREG(I2CONSET) = STOFLAG;
IREG(I2CONCLR) = STAFLAG | AAFLAG | SIFLAG;
break;
/* We don't handle slave mode */
}
}
void i2c_send_stop(void)
{
IREG(I2CONCLR) = STAFLAG | AAFLAG;
IREG(I2CONSET) = STOFLAG;
IREG(I2CONCLR) = SIFLAG;
/* Don't think we need to wait here. Could be wrong. */
interrupt_clear();
}

26
i2c.h

@ -2,16 +2,26 @@
#define __I2C_H
#include "types.h"
#define I2C_IN_PROGRESS 0
#define I2C_SUCCESS 1
#define I2C_FAIL 2
typedef int i2c_result;
struct i2c_transaction {
int address; /* i2c first byte, including address and r/w flag */
int bytes; /* number of bytes to read or write */
unsigned char *data; /* pointer to the data */
i2c_result *result; /* pointer to store the result */
struct i2c_transaction *next; /* NULL or next transaction */
};
void init_i2c(void);
extern int i2cstat;
int i2c_wait(void);
void i2c_go(void);
int i2c_conreg(void);
int i2c_statreg(void);
bool i2c_send_start(void);
bool i2c_send_address(int addr, bool write);
bool i2c_send_data(unsigned int data);
bool i2c_receive_data(unsigned int *data, bool last);
void i2c_send_stop(void);
bool i2c_start_transaction(struct i2c_transaction *t);
bool i2c_busy(void);
#endif /* __I2C_H */

15
main.c

@ -160,6 +160,7 @@ void average_sample(void)
int main(void) {
int i;
init_interrupt();
init_uart();
init_i2c();
@ -193,8 +194,6 @@ int main(void) {
reply("Help is not available. Try a psychiatrist.");
break;
case 'T':
putstr("I2C status was: ");
puthex(i2cstat);
putstr(" I2C status is: ");
puthex(i2c_statreg());
reply(".");
@ -202,18 +201,6 @@ int main(void) {
puthex(i2c_conreg());
reply(".");
break;
case 'S':
putstr("Sending START... ");
if (i2c_send_start())
reply("OK");
else
reply("FAIL");
break;
case 'O':
putstr("Sending STOP... ");
i2c_send_stop();
reply("sent");
break;
case 'I':
putstr("Initialising WMP... ");
if (wmp_init())

2
types.h

@ -5,4 +5,6 @@ typedef int bool;
#define TRUE 1
#define FALSE 0
#define NULL 0
#endif /* __TYPES_H */

124
wmp.c

@ -2,46 +2,77 @@
#include "wmp.h"
#include "i2c.h"
unsigned char wmp_init_command[2] = {0xfe, 0x04};
i2c_result wmp_result;
struct i2c_transaction wmp_init_transaction = {
(0x53 << 1) + 0, /* write */
2,
wmp_init_command,
&wmp_result,
NULL
};
unsigned char wmp_read_cal_command[1] = {0x20};
struct i2c_transaction wmp_read_cal_transaction2;
struct i2c_transaction wmp_read_cal_transaction = {
(0x53 << 1) + 0, /* write */
1,
wmp_read_cal_command,
&wmp_result,
&wmp_read_cal_transaction2
};
struct i2c_transaction wmp_read_cal_transaction2 = {
(0x53 << 1) + 1, /* read */
0x20,
wmp_calibration_data,
&wmp_result,
NULL
};
unsigned char wmp_sample_command[1] = {0x00};
unsigned char wmp_sample_data[6];
struct i2c_transaction wmp_sample_transaction2;
struct i2c_transaction wmp_sample_transaction = {
(0x52 << 1) + 0, /* write */
1,
wmp_sample_command,
&wmp_result,
&wmp_sample_transaction2
};
struct i2c_transaction wmp_sample_transaction2 = {
(0x52 << 1) + 1, /* read */
6,
wmp_sample_data,
&wmp_result,
NULL
};
bool wmp_init(void)
{
if (!i2c_send_start())
return FALSE;
if (!i2c_send_address(0x53, TRUE))
return FALSE;
if (!i2c_send_data(0xfe))
if (!i2c_start_transaction(&wmp_init_transaction))
return FALSE;
if (!i2c_send_data(0x04))
return FALSE;
i2c_send_stop();
return TRUE;
while (i2c_busy()) ;
return (wmp_result == I2C_SUCCESS);
}
unsigned char wmp_calibration_data[0x20];
bool wmp_read_calibration_data(void)
{
int i;
if (!i2c_send_start())
return FALSE;
if (!i2c_send_address(0x53, TRUE))
return FALSE;
if (!i2c_send_data(0x20))
return FALSE;
i2c_send_stop();
if (!i2c_send_start())
if (!i2c_start_transaction(&wmp_read_cal_transaction))
return FALSE;
if (!i2c_send_address(0x53, FALSE))
return FALSE;
for (i = 0; i < 0x20; i++) {
unsigned int data;
if (!i2c_receive_data(&data, (i == 0x1f)))
return FALSE;
wmp_calibration_data[i] = data;
}
i2c_send_stop();
return TRUE;
while (i2c_busy());
return (wmp_result == I2C_SUCCESS);
}
unsigned int wmp_yaw;
@ -66,35 +97,22 @@ bool wmp_roll_fast;
bool wmp_sample(void)
{
int i;
unsigned int b[6];
if (!i2c_send_start())
return FALSE;
if (!i2c_send_address(0x52, TRUE))
if (!i2c_start_transaction(&wmp_sample_transaction))
return FALSE;
if (!i2c_send_data(0x00))
return FALSE;
i2c_send_stop();
if (!i2c_send_start())
return FALSE;
if (!i2c_send_address(0x52, FALSE))
while (i2c_busy());
if (wmp_result != I2C_SUCCESS)
return FALSE;
for (i = 0; i < 6; i++) {
if (!i2c_receive_data(&(b[i]), (i == 5)))
return FALSE;
}
i2c_send_stop();
wmp_yaw = ((b[3]>>2)<<8) + b[0];
wmp_pitch = ((b[4]>>2)<<8) + b[1];
wmp_roll = ((b[5]>>2)<<8) + b[2];
wmp_yaw = ((wmp_sample_data[3]>>2)<<8) + wmp_sample_data[0];
wmp_pitch = ((wmp_sample_data[4]>>2)<<8) + wmp_sample_data[1];
wmp_roll = ((wmp_sample_data[5]>>2)<<8) + wmp_sample_data[2];
/* XXX We don't take into account the fast/slow mode flag here */
wmp_yaw_fast = !(b[3] & 0x2);
wmp_pitch_fast = !(b[3] & 0x1);
wmp_roll_fast = !(b[4] & 0x2);
wmp_yaw_fast = !(wmp_sample_data[3] & 0x2);
wmp_pitch_fast = !(wmp_sample_data[3] & 0x1);
wmp_roll_fast = !(wmp_sample_data[4] & 0x2);
return TRUE;
}

Loading…
Cancel
Save