AnsweredAssumed Answered

Another I2C problem - code works in polled mode, doesn't work from ISR

Question asked by FridgeFreezer on Sep 7, 2011
Latest reply on Sep 29, 2011 by FridgeFreezer

This has been bugging me all day and I can't for the life of me see what's going wrong... MCU is MCF52259, CodeWarrior 7.2. I'm reading data from an MCP23017 I/O expander.

 

If I use I2C0, initialise it with Freescale's own code and then run their polled I2C routine it works fine:

/* * I2CreceiveByte: I2C read byte * * Parameters: address: address to read *      id: I2C device to read * * Return : data: byte read it from device */uint8 FSI2CxreceiveByte(uint8 address, uint8 id){ uint8 data;  /* setting in Tx mode */ MCF_I2C0_I2CR |= MCF_I2C_I2CR_MTX;     /* send start condition */ MCF_I2C0_I2CR |= MCF_I2C_I2CR_MSTA;  /* devide ID to write */ MCF_I2C0_I2DR = id;         /* wait until one byte transfer completion */ while( !(MCF_I2C0_I2SR & MCF_I2C_I2SR_IIF )) ; /* clear the completion transfer flag */ MCF_I2C0_I2SR &= ~MCF_I2C_I2SR_IIF;  /* memory address */ MCF_I2C0_I2DR = address;        /* wait until one byte transfer completion */ while( !(MCF_I2C0_I2SR & MCF_I2C_I2SR_IIF )) ; /* clear the completion transfer flag */ MCF_I2C0_I2SR &= ~MCF_I2C_I2SR_IIF;    /* resend start */  MCF_I2C0_I2CR |= MCF_I2C_I2CR_RSTA;    /* device id to read */  MCF_I2C0_I2DR = (uint8)(id | 0x01);       /* wait until one byte transfer completion */ while( !(MCF_I2C0_I2SR & MCF_I2C_I2SR_IIF )) ; /* clear the completion transfer flag */ MCF_I2C0_I2SR &= ~MCF_I2C_I2SR_IIF;  /* setting in Rx mode */ MCF_I2C0_I2CR &= ~MCF_I2C_I2CR_MTX;   /* send NO ACK */  MCF_I2C0_I2CR |= MCF_I2C_I2CR_TXAK;   /* dummy read */   data = MCF_I2C0_I2DR;        /* wait until one byte transfer completion */ while( !(MCF_I2C0_I2SR & MCF_I2C_I2SR_IIF )) ; /* clear the completion transfer flag */ MCF_I2C0_I2SR &= ~MCF_I2C_I2SR_IIF;  /* read data received */ data = MCF_I2C0_I2DR;        /* wait until one byte transfer completion */ while( !(MCF_I2C0_I2SR & MCF_I2C_I2SR_IIF )) ; /* clear the completion transfer flag */ MCF_I2C0_I2SR &= ~MCF_I2C_I2SR_IIF;  /* generates stop condition */ MCF_I2C0_I2CR &= ~MCF_I2C_I2CR_MSTA;  /* send the received data */ return data;}

 

But if I enable interrupt 17 (I2C0) and then use the following routine, it doesn't work and the "data" read back is actually the "address" I'm supposed to be reading (EG I'm supposed to send chip ID 0x4E, register address 0x12 and get back "0xFF" as data I instead get "0x12" back as data. Using a scope I can't see any data going back & forth on the I2C bus lines either.

Anyway, here's my ISR, it's a complete copy-and-paste of the FS routine above but with the wait loops replaced with an incrementing state-machine counter:

 

__interrupt void i2c_isr(void){<variables, interrupt mask, etc. here> switch(state) {  //  // Start - setup port, send start & device ID  //  case 1:      // clear the interrupt   MCF_I2C0_I2SR = 0;            /* setting in Tx mode */      MCF_I2C0_I2CR = MCF_I2C_I2CR_IEN | MCF_I2C_I2CR_IIEN | MCF_I2C_I2CR_MTX; // Enable         /* send start condition */   MCF_I2C0_I2CR |= MCF_I2C_I2CR_MSTA;      /* devide ID to write */   MCF_I2C0_I2DR = id;         // wait until one byte transfer completion   break;    //  // Started, device ID sent, now send register address  //  case 2:   /* clear the completion transfer flag */   MCF_I2C0_I2SR &= ~MCF_I2C_I2SR_IIF;      /* memory address */   MCF_I2C0_I2DR = address;    // wait until one byte transfer completion    break;    //  // Register address sent, restart in read mode  //  case 3:   /* clear the completion transfer flag */   MCF_I2C0_I2SR &= ~MCF_I2C_I2SR_IIF;        /* resend start */   MCF_I2C0_I2CR |= MCF_I2C_I2CR_RSTA;          /* device id to read */    MCF_I2C0_I2DR = (uint8)(id | 0x01);      // wait until one byte transfer completion    break;    //  // Send clock pulses to read data  //  case 4:   /* clear the completion transfer flag */   MCF_I2C0_I2SR &= ~MCF_I2C_I2SR_IIF;      /* setting in Rx mode */   MCF_I2C0_I2CR &= ~MCF_I2C_I2CR_MTX;       /* send NO ACK */    MCF_I2C0_I2CR |= MCF_I2C_I2CR_TXAK;       /* dummy read */     temp = MCF_I2C0_I2DR;   break;      //  // Read data  //  case 5:   /* clear the completion transfer flag */   MCF_I2C0_I2SR &= ~MCF_I2C_I2SR_IIF;      /* read data received */   data = MCF_I2C0_I2DR;    // This will trigger another read   // ...so wait until one byte transfer completion    break;    //  // Finish  //  case 6:   /* clear the completion transfer flag */   MCF_I2C0_I2SR &= ~MCF_I2C_I2SR_IIF;       /* generates stop condition */   MCF_I2C0_I2CR &= ~MCF_I2C_I2CR_MSTA;    break;  //  // Default / end  //  case 0:  default:   // Reset / go round again   break; }  if(state < 7) // Stop after one run {  state++; }}

 

I'm sure I must be doing something wrong somewhere but I can't for the life of me see it :smileysad:

Outcomes