9S12DP512 IIC not working

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

9S12DP512 IIC not working

867 Views
Chris_sirhC
Contributor I

I'm trying to interface an I2C device and so far have measured nothing but noise coming from the output of the device. I followed the exact process given by the AN3291.pdf file (which pretty much has the init and send functions already written). I am fairly certain that the actual I2C functions that I'm using (I2C_Open() and I2C_Send()) are correct. In addition, I added a timer wait of 250ms at the end of the I2C_Send() function to ensure that the slave device has enough time to process the request.

 

I'm thinking the problem could be the MODRR register. What should I be setting it to, if anything?

 

I've attached the AN3291.pdf file. Here's my code:

 

/************************* I2C.c *************************/
#include "I2C.h"

/************************* Public Functions *************************/
/************************* I2C_Open *************************/
// Inputs: none
// Outputs: none
// enable I2C interface on 9S12
void I2C_Open(void) {

  MODRR = 0x00;
  IBFD = 0x4C; // frequency divider register: 91kHz (@ 8MHz)
  IBCR = 0x80; // enable I2C module with no interrupts
}

/************************* I2C_Send *************************/
// Inputs:
//   slaveAddr - the address of the slave device (TEA6320T)
//   slaveReg - the register to write to on TEA6320T
//   data -  data to send to slave device (TEA6320T)
// Outputs: none
// will transmit a byte of data to TEA6320T
void I2C_Send(uint8 slaveAddr, uint8 slaveReg, uint8 data) {
  IBCR_TXAK = 0;
  IBCR |= 0x30;                          // send start
  IBDR = slaveAddr & (0xFE); // send slave address
  while(!IBSR_IBIF);                  // wait for the address to be sent
  IBSR_IBIF = 1;                        // clear IBIF
  while(IBSR_RXAK);              // wait for "ack" from slave
  IBDR = slaveReg;                 // send first byte
  while(!IBSR_IBIF);                // wait for the data to be sent
  IBSR_IBIF = 1;                      // clear IBIF
  while(IBSR_RXAK);             // wait for "ack" from slave
  IBDR = slaveReg;                // send second byte
  while(!IBSR_IBIF);               // wait for the data to be sent
  IBSR_IBIF = 1;                     // clear IBIF  
  while(IBSR_RXAK);           // wait for "ack" from slave
  IBDR = data;                       // send data to slave
  while (!IBSR_IBIF);            // wait for the data to be sent
  IBSR_IBIF = 1;                   // clear IBIF
  while(IBSR_RXAK);          // wait for "ack" from slave
  IBCR_MS_SL = 0;            // generate STOP condition;
 
  //WAIT FOR SLAVE TO PROCESS DATA
  Timer_msWait(250);
}

Labels (1)
0 Kudos
3 Replies

565 Views
kef
Specialist I
  • I'm thinking the problem could be the MODRR register. What should I be setting it to, if anything?

Check the port integration module (s12dp256pimv3.pdf). I2C is not routable to different pins. It is easy to check by looking at pin diagram. If you would see more than one instance of SDA or SCL, then I2C module would be routable to different pins and you would need to check module routing register (MODRR) settings.

 

  • I am fairly certain that the actual I2C functions that I'm using (I2C_Open() and I2C_Send()) are correct.

Your code is wrong. It ALWAYS helps to look into datasheet and at your code again and again. What is TEA6320 protocol? It is 1) address byte, which is always 0x80 for this device, 2) subaddress (register number like volume, bass etc), 3) data. Now look at your code. It is 1) address, 2) subaddress, 3) again subaddress, 4) data.

 

  • In addition, I added a timer wait of 250ms at the end of the I2C_Send() function to ensure that the slave device has enough time to process the request.

It is useless on I2C. Master can't go further while slave is busy.

 

 AN3291 is good example of dangerous code. First of all why do thy wait for RXAK? RXAK is updated when byte is transferred to the slave. RXAK is updated as soon as IBIF is set and won't get updated until next byte is transferred to the slave. In case of failure, when for some reason slave doesn't ack your data, your MCU will stuck in endless loop waiting for RXAK that will never occur because your MCU doesn't transfer more bytes because it is waiting for RXAK. If you expect RXAK=0 and it is =1, then you should signal error, change direction to read, read dummy byte from data register, generate stop condition and exit.

 

0 Kudos

565 Views
Chris_sirhC
Contributor I

You were right. I did have one byte too many in mt send protocol, I guess that was a copy-and-paste error. Also, that AN3291 file is misleading, I thought the while(IBSR_RXAK) meant that we were waiting for a flag, not an actual value. Anyway, I fixed it and here's the new code in case anyone else has the same problems. Thanks for the quick response!

 

/************************* I2C.c *************************/
#include "I2C.h"

/************************* Public Functions *************************/
/************************* I2C_Open *************************/
// Inputs: none
// Outputs: none
// enable I2C interface on 9S12
void I2C_Open(void) {
  IBFD = 0x4C; // frequency divider register: 91kHz (@ 8MHz)
  IBCR = 0x80; // enable I2C module with no interrupts
}

/************************* I2C_Send *************************/
// Inputs:
//   slaveAddr - the address of the slave device (TEA6320T)
//   slaveReg - the register to write to on TEA6320T
//   data -  data to send to slave device (TEA6320T)
// Outputs: none
// will transmit a byte of data to TEA6320T
uint8 I2C_Send(const uint8 slaveAddr, const uint8 slaveReg, const uint8 data) {
  uint8 dummy;
  PTP_PTP7 = 1;
  IBCR_TXAK = 0;
  IBCR_MS_SL = 1;            // generate start condition
  IBCR_TX_RX = 1;            // set MCU to transmit mode
  IBDR = slaveAddr & (0xFE); // send slave address
  while(!IBSR_IBIF);         // wait for the address to be sent
  IBSR_IBIF = 1;             // clear IBIF
  if(IBSR_RXAK) {            // "nack" was sent back from slave
    IBCR_TX_RX = 0;          // set MCU to receive mode
    dummy = IBDR;            // dummy read
    IBCR_MS_SL = 0;          // generate STOP condition;
    return 0;                // report failure
  }
  // "ack" was sent back from slave
  IBDR = slaveReg;           // send first byte
  while(!IBSR_IBIF);         // wait for the data to be sent
  IBSR_IBIF = 1;             // clear IBIF
  if(IBSR_RXAK) {            // "nack" was sent back from slave
    IBCR_TX_RX = 0;          // set MCU to receive mode
    dummy = IBDR;            // dummy read
    IBCR_MS_SL = 0;          // generate STOP condition;
    return 0;                // report failure
  }
  // "ack" was sent back from slave
  IBDR = data;               // send data to slave
  while (!IBSR_IBIF);        // wait for the data to be sent
  IBSR_IBIF = 1;             // clear IBIF
  if(IBSR_RXAK) {            // "nack" was sent back from slave
    IBCR_TX_RX = 0;          // set MCU to receive mode
    dummy = IBDR;            // dummy read
    IBCR_MS_SL = 0;          // generate STOP condition;
    return 0;                // report failure
  }
  // "ack" was sent back from slave
  IBCR_MS_SL = 0;            // generate STOP condition;
  PTP_PTP7 = 0;
  Timer_msWait(500);
  return 1;                  // report success
}

Also, when calling the I2C_Send() function, it's being done in a while loop like this:

 

while(!I2C_Send(...));

 

0 Kudos

565 Views
Chris_sirhC
Contributor I

Actually that Timer_msWait(500); isn't needed (at the bottom of I2C_Send()). I just had it in there for debugging. I was oscillating an LED so I just wanted to slow it down so the flashing would be visible.

0 Kudos