From 47ecb0795caad2eeea37dc50066b541bc249dd01 Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Tue, 4 Feb 2014 11:59:16 +0100 Subject: Interrupt-based read --- main.c | 251 ++++++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 163 insertions(+), 88 deletions(-) diff --git a/main.c b/main.c index 4858a5e..6c23e32 100644 --- a/main.c +++ b/main.c @@ -16,6 +16,12 @@ #define LIS302DL_WHOAMI 0xf #define LIS302DL_CTRLREG1 0x20 +typedef enum { + TWM_INVALID = 0, + TWM_WRITE, + TWM_READ_MULTI, +} twMode; + typedef enum { TWST_WAIT = 0, TWST_OK = 1, @@ -23,10 +29,17 @@ typedef enum { } 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); } + -- cgit v1.2.3