aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars-Dominik Braun <lars@6xq.net>2014-02-04 11:59:16 +0100
committerLars-Dominik Braun <lars@6xq.net>2014-02-04 11:59:16 +0100
commit47ecb0795caad2eeea37dc50066b541bc249dd01 (patch)
tree96cfe01efa03aec25428cf7d3c4da1a6b06ed5c1
parentc037f0676fc079db1643b2cc400f387ce39ed30c (diff)
downloadhourglass-47ecb0795caad2eeea37dc50066b541bc249dd01.tar.gz
hourglass-47ecb0795caad2eeea37dc50066b541bc249dd01.tar.bz2
hourglass-47ecb0795caad2eeea37dc50066b541bc249dd01.zip
Interrupt-based read
-rw-r--r--main.c251
1 files changed, 163 insertions, 88 deletions
diff --git a/main.c b/main.c
index 4858a5e..6c23e32 100644
--- a/main.c
+++ b/main.c
@@ -17,16 +17,29 @@
#define LIS302DL_CTRLREG1 0x20
typedef enum {
+ TWM_INVALID = 0,
+ TWM_WRITE,
+ TWM_READ_MULTI,
+} twMode;
+
+typedef enum {
TWST_WAIT = 0,
TWST_OK = 1,
TWST_ERR = 2,
} twStatus;
typedef struct {
+ twMode mode;
uint8_t address;
uint8_t subaddress;
uint8_t data;
uint8_t step;
+ /* read data store */
+ uint8_t *retData;
+ /* number of bytes to be read */
+ uint8_t count;
+ /* current byte */
+ uint8_t i;
twStatus status;
} twReq;
@@ -72,6 +85,7 @@ void twInit () {
TWBR = 2;
TWSR |= 0x3; /* set prescaler to 64 */
+ twr.mode = TWM_INVALID;
twr.status = TWST_ERR;
}
@@ -83,7 +97,8 @@ static bool twWrite (uint8_t address, uint8_t subaddress, uint8_t data) {
return false;
}
- twr.address = address | TW_WRITE;
+ twr.mode = TWM_WRITE;
+ twr.address = address;
twr.subaddress = subaddress;
twr.data = data;
twr.step = 0;
@@ -95,6 +110,28 @@ static bool twWrite (uint8_t address, uint8_t subaddress, uint8_t data) {
return true;
}
+static bool twReadMulti (uint8_t address, uint8_t subaddress,
+ uint8_t *retData, uint8_t count) {
+ /* do not start if request is pending */
+ if (twr.status == TWST_WAIT) {
+ return false;
+ }
+
+ twr.mode = TWM_READ_MULTI;
+ twr.address = address;
+ twr.subaddress = subaddress;
+ twr.retData = retData;
+ twr.count = count;
+ twr.i = 0;
+ twr.step = 0;
+ twr.status = TWST_WAIT;
+ /* wait for stop finish */
+ while (TW_STATUS != 0xf8);
+ twStartRaw ();
+
+ return true;
+}
+
void ledInit () {
/* set led1,led2 to output */
DDRB |= (1 << PB6) | (1 << PB7);
@@ -153,12 +190,13 @@ void cpuInit () {
CLKPR = 0b00000011;
}
-ISR(TWI_vect) {
- printf ("interupt hit with step %i\n", twr.step);
+/* handle interrupt, write request
+ */
+static void twIntWrite () {
switch (twr.step) {
case 0:
if (TW_STATUS == TW_START) {
- twWriteRaw (twr.address);
+ twWriteRaw (twr.address | TW_WRITE);
twFlushRaw ();
} else {
twr.status = TWST_ERR;
@@ -191,10 +229,119 @@ ISR(TWI_vect) {
twr.status = TWST_ERR;
}
break;
+
+ default:
+ printf ("nope\n");
+ break;
}
++twr.step;
}
+static void twIntReadMulti () {
+ switch (twr.step) {
+ case 0:
+ if (TW_STATUS == TW_START) {
+ /* write device address */
+ twWriteRaw (twr.address | TW_WRITE);
+ twFlushRaw ();
+ ++twr.step;
+ } else {
+ twr.status = TWST_ERR;
+ }
+ break;
+
+ case 1:
+ if (TW_STATUS == TW_MT_SLA_ACK) {
+ /* write subaddress, enable auto-increment */
+ twWriteRaw ((1 << 7) | twr.subaddress);
+ twFlushRaw ();
+ ++twr.step;
+ } else {
+ twr.status = TWST_ERR;
+ }
+ break;
+
+ case 2:
+ if (TW_STATUS == TW_MT_DATA_ACK) {
+ /* send repeated start */
+ twStartRaw ();
+ ++twr.step;
+ } else {
+ twr.status = TWST_ERR;
+ }
+ break;
+
+ case 3:
+ if (TW_STATUS == TW_REP_START) {
+ /* now start the actual read request */
+ twWriteRaw (twr.address | TW_READ);
+ twFlushRaw ();
+ ++twr.step;
+ } else {
+ twr.status = TWST_ERR;
+ }
+ break;
+
+ case 4:
+ if (TW_STATUS == TW_MR_SLA_ACK) {
+ /* send master ack if next data block is received */
+ twFlushContRaw ();
+ ++twr.step;
+ } else {
+ twr.status = TWST_ERR;
+ }
+
+ case 5:
+ if (TW_STATUS == TW_MR_DATA_ACK) {
+ twr.retData[twr.i] = TWDR;
+ ++twr.i;
+ if (twr.i < twr.count-1) {
+ /* read another byte, not the last one */
+ twFlushContRaw ();
+ /* step stays the same */
+ } else {
+ /* read last byte, send master nack */
+ twFlushRaw ();
+ ++twr.step;
+ }
+ } else {
+ twr.status = TWST_ERR;
+ }
+ break;
+
+ case 6:
+ if (TW_STATUS == TW_MR_DATA_NACK) {
+ /* receive final byte, send stop */
+ twr.retData[twr.i] = TWDR;
+ twStopRaw ();
+ twr.status = TWST_OK;
+ } else {
+ twr.status = TWST_ERR;
+ }
+ break;
+
+ default:
+ printf ("twIntReadMulti: nope\n");
+ break;
+ }
+}
+
+ISR(TWI_vect) {
+ switch (twr.mode) {
+ case TWM_WRITE:
+ twIntWrite ();
+ break;
+
+ case TWM_READ_MULTI:
+ twIntReadMulti ();
+ break;
+
+ default:
+ printf ("nope\n");
+ break;
+ }
+}
+
int main(void) {
cpuInit ();
ledInit ();
@@ -206,6 +353,7 @@ int main(void) {
printf ("initialization done\n");
+ /* global interrupt enable */
sei ();
/* disable power-down-mode */
if (!twWrite (LIS302DL, LIS302DL_CTRLREG1, 0b01000111)) {
@@ -213,93 +361,20 @@ int main(void) {
}
while (twr.status == TWST_WAIT);
printf ("final twi status was %i\n", twr.status);
- cli ();
while (1) {
- signed char val[6];
- twStartRaw ();
- twWaitRaw ();
- unsigned char status = 0x0;
-
- /* check status code */
- if ((status = TW_STATUS) == TW_START) {
-
- /* write device address and write bit */
- TWDR = LIS302DL | TW_WRITE;
- if (TWCR & (1 << TWWC)) {
- printf("write collision\n");
- }
- twFlushRaw ();
- twWaitRaw ();
- if ((status = TW_STATUS) == TW_MT_SLA_ACK) {
- } else {
- printf ("fail with code %x\n", status);
- }
-
- /* auto increment + subaddress */
- TWDR = (1 << 7) | 0x28;
- if (TWCR & (1 << TWWC)) {
- printf("write collision\n");
- }
- twFlushRaw ();
- twWaitRaw ();
- if ((status = TW_STATUS) == TW_MT_DATA_ACK) {
- } else {
- printf ("fail with code %x\n", status);
- }
-
- /* repeated start */
- twStartRaw ();
- twWaitRaw ();
- if ((status = TW_STATUS) == TW_REP_START) {
- } else {
- printf ("fail with code %x\n", status);
- }
-
- /* write device address and read bit */
- TWDR = LIS302DL | TW_READ;
- if (TWCR & (1 << TWWC)) {
- printf("write collision\n");
- }
- twFlushRaw ();
- twWaitRaw ();
- if ((status = TW_STATUS) == TW_MR_SLA_ACK) {
- } else {
- printf ("fail with code %x\n", status);
- }
-
- for (uint8_t i = 0; i < 6; i++) {
- /* clear twint and wait for response */
- if (i < 5) {
- twFlushContRaw ();
- twWaitRaw ();
- if ((status = TW_STATUS) == TW_MR_DATA_ACK) {
- } else {
- printf ("fail with code %x in val %i\n", status, i);
- }
- } else {
- twFlushRaw ();
- twWaitRaw ();
- if ((status = TW_STATUS) == TW_MR_DATA_NACK) {
- } else {
- printf ("fail with code %x in val %i\n", status, i);
- }
- }
- unsigned char ret = TWDR;
- val[i] = ret;
- }
-
- twStopRaw ();
-
- /* there is no way to tell whether stop has been sent or not, just wait */
- _delay_ms (10);
- } else {
- printf ("fail with code %x\n", status);
- _delay_ms (1000);
- }
- //printf ("%i/%i/%i\n", (val[1] << 8) | val[0], (val[3] << 8) | val[2], (val[5] << 8) | val[4]);
- printf ("%i/%i/%i\n", val[1], val[3], val[5]);
+ uint8_t val[6];
+ if (!twReadMulti (LIS302DL, 0x28, val, 6)) {
+ printf ("cannot start read\n");
+ }
+ while (twr.status == TWST_WAIT);
+ printf ("%i/%i/%i\n", (int8_t) val[1], (int8_t) val[3], (int8_t) val[5]);
+ /* XXX: why do we need the delay here? */
+ _delay_ms (250);
}
+ /* global interrupt disable */
+ cli ();
while (1);
}
+