Function not using passed value

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

Function not using passed value

Jump to solution
1,067 Views
kaslewis
Contributor III

I have two functions to send I2C data and two to receive I2C data, one is for only one data byte and the other is for multiple data bytes. The issue is the single data byte function does not appear to be using the passed in values and I cannot work out why this would be. As you can see I have set the values of device_address and device_register in the functions to see if this prevents the I2C from hanging and it does. If I do not add these explicit declarations the code hangs at the first i2c_Data_Transmit_Delay(); in each of the one byte functions. Checking the passed in values of device_address and device_register they are both incorrect and appear  to be 0x98 which does not appear in my code and neither does 0x4C which would be 0x98 shifted right once. I have also attached a copy of the full code for further reference.

 

Any help would be very much appreciated.

 

Here is the write function that uses accepts only one data byte

void i2c_Write(char device_address, char device_register, char data){   device_address = 0x4B;                                              //TODO: Fix addressing issue   device_register = 0x03;   data = 0x12;       I2C0_C1 |= I2C_C1_MST_MASK | I2C_C1_TX_MASK;                        //Send start bit     // I2C0_C1 &= ~I2C_C1_TXAK_MASK;      I2C0_D = (device_address << 1) | I2C_MASTER_WRITE;                  //Device address with write bit set     while ((I2C0_S & I2C_S_IICIF_MASK) == 0){     //Wait for data to transmit   }   I2C0_S |= I2C_S_IICIF_MASK; //    i2c_Data_Trasmit_Delay();       I2C0_D = device_register;                                           //Device register to write to     while ((I2C0_S & I2C_S_IICIF_MASK) == 0){     //Wait for data to transmit   }   I2C0_S |= I2C_S_IICIF_MASK; //    i2c_Data_Trasmit_Delay();       I2C0_D = data;                                                      //Write to register     while ((I2C0_S & I2C_S_IICIF_MASK) == 0){     //Wait for data to transmit   }   I2C0_S |= I2C_S_IICIF_MASK; //    i2c_Data_Trasmit_Delay();       I2C0_S |= I2C_S_IICIF_MASK;     I2C0_C1 &= ~I2C_C1_MST_MASK;       while((I2C0_FLT & I2C_FLT_STOPF_MASK) == 0){                        //Delay for stop bit         //Wait for stop bit to transmit     }     I2C0_FLT &= ~I2C_FLT_STOPF_MASK; }   

 

Here is the write function that accepts multiple data bytes

void i2c_Write_Multi(char device_address, char device_register, char* data_array, unsigned char length){     int i = 0;       I2C0_C1 |= I2C_C1_MST_MASK | I2C_C1_TX_MASK | I2C_C1_IICEN_MASK;       I2C0_C1 |= I2C_C1_MST_MASK | I2C_C1_TX_MASK;                        //Send start bit     I2C0_C1 &= ~I2C_C1_TXAK_MASK;      I2C0_D = (device_address << 1) | I2C_MASTER_WRITE;                  //Device address with write bit set     i2c_Data_Trasmit_Delay();      I2C0_D = device_register;                                           //Device register to write to     i2c_Data_Trasmit_Delay();       for(i = 0; i < length; i++){                                        //Write n bytes         I2C0_D = data_array[i];         i2c_Data_Trasmit_Delay();     }       I2C0_S |= I2C_S_IICIF_MASK;     I2C0_C1 &= ~I2C_C1_MST_MASK;       while((I2C0_FLT & I2C_FLT_STOPF_MASK) == 0){                        //Delay for stop bit         //Wait for stop bit to transmit     }     I2C0_FLT &= ~I2C_FLT_STOPF_MASK; }   

 

 

Here are the two write functions

char i2c_Read(uint8_t device_address, char device_register){     char temp;     device_address = 0x4B;                                              //TODO: Fix addressing issue     device_register = 0x0B;       I2C0_C1 |= I2C_C1_MST_MASK | I2C_C1_TX_MASK;                        //Send start bit     // I2C0_C1 &= ~I2C_C1_TXAK_MASK;       I2C0_D = (device_address << 1) | I2C_MASTER_WRITE;                  //Device address with write bit set     i2c_Data_Trasmit_Delay();       I2C0_D = device_register;                                           //Device register to read from     i2c_Data_Trasmit_Delay();       I2C0_C1 |= I2C_C1_RSTA_MASK;                                        //Send restart      I2C0_D = (device_address << 1) | I2C_MASTER_READ;                   //Device address with read bit set     i2c_Data_Trasmit_Delay();       I2C0_C1 &= ~I2C_C1_TX_MASK;                                         //Change to Rx mode       I2C0_C1 |= I2C_C1_TXAK_MASK;                                        //Set NACK     temp = I2C0_D;                                                      //Receive data byte     i2c_Data_Trasmit_Delay();       I2C0_C1 &= ~I2C_C1_MST_MASK;                                        //Set stop bit     I2C0_C1 |= I2C_C1_TX_MASK;                                          //Change to Tx mode       return I2C0_D; }   void i2c_Read_Multi(char device_address, char device_register, char* data_array, unsigned char length){     int i = 0;     char temp;       I2C0_C1 |= I2C_C1_MST_MASK | I2C_C1_TX_MASK | I2C_C1_IICEN_MASK;       I2C0_C1 |= I2C_C1_MST_MASK | I2C_C1_TX_MASK;                        //Send start bit     // I2C0_C1 &= ~I2C_C1_TXAK_MASK;       I2C0_D = (device_address << 1) | I2C_MASTER_WRITE;                  //Device address with write bit set     i2c_Data_Trasmit_Delay();      I2C0_D = device_register;                                           //Device register to read from     i2c_Data_Trasmit_Delay();      I2C0_C1 |= I2C_C1_RSTA_MASK;                                        //Send restart      I2C0_D = (device_address << 1) | I2C_MASTER_READ;                   //Device address with read bit set     i2c_Data_Trasmit_Delay();    

 

 

void i2c_Read_Multi(char device_address, char device_register, char* data_array, unsigned char length){     int i = 0;     char temp;       I2C0_C1 |= I2C_C1_MST_MASK | I2C_C1_TX_MASK | I2C_C1_IICEN_MASK;       I2C0_C1 |= I2C_C1_MST_MASK | I2C_C1_TX_MASK;                        //Send start bit     // I2C0_C1 &= ~I2C_C1_TXAK_MASK;       I2C0_D = (device_address << 1) | I2C_MASTER_WRITE;                  //Device address with write bit set     i2c_Data_Trasmit_Delay();      I2C0_D = device_register;                                           //Device register to read from     i2c_Data_Trasmit_Delay();      I2C0_C1 |= I2C_C1_RSTA_MASK;                                        //Send restart      I2C0_D = (device_address << 1) | I2C_MASTER_READ;                   //Device address with read bit set     i2c_Data_Trasmit_Delay();      I2C0_C1 &= ~I2C_C1_TX_MASK;                                         //Change to Rx mode     temp = I2C0_D;     i2c_Data_Trasmit_Delay();       for (i = 0; i < length - 2; i ++){                                  //Receive first n - 1 bytes         data_array[i] = I2C0_D;         i2c_Data_Trasmit_Delay();     }       I2C0_C1 |= I2C_C1_TXAK_MASK;                                        //Receive last byte     data_array[i] = I2C0_D;     i2c_Data_Trasmit_Delay();       I2C0_C1 &= ~I2C_C1_MST_MASK;                                        //Set stop bit     I2C0_C1 |= I2C_C1_TX_MASK;                                          //Change to Tx mode     data_array[i + 1] = I2C0_D;                                         //Read final byte }                 

 

For clarity here is the i2c_Data_Transmit_Delay() function

void i2c_Data_Trasmit_Delay(){             while ((I2C0_S & I2C_S_IICIF_MASK) == 0){             //Wait for data to transmit         }         I2C0_S |= I2C_S_IICIF_MASK; }   

 

Lastly here is the call from main

int main(void) {     char temp;     char i2cReadArray[] = {0,0,0,0,0,0,0,0,0};     char i2cWriteArray[] = {0,0,0,0,0,0,0,0,0};       clk_Init();     i2c_Init();       i2cWriteArray[0] = 0x12;     i2cWriteArray[1] = 0x34;     i2cWriteArray[2] = 0x56;     i2cWriteArray[3] = 0x78;       i2c_Write_Multi(0x4B, 0x04, i2cWriteArray, 2);     i2c_Read_Multi(0x4B, 0x04, i2cReadArray, 2);      while(1){         i2c_Write_Multi(0x4B, 0x04, i2cWriteArray, 2);         i2c_Read_Multi(0x4B, 0x04, i2cReadArray, 2);               i2c_Write_Multi(0x4B, 0x04, i2cWriteArray, 4);         i2c_Read_Multi(0x4B, 0x04, i2cReadArray, 4);           temp = i2c_Read(0x4B, 0x0B);         i2c_Write(0x4B, 0x03, 0x12);     } }            

 

Point in the code where the i2c_wite() hangs and the values of the 3 passed values:

device_address value (same in both places)

18114_18114.jpg2014-12-26 11_45_23-Debug - Car_Window_Control_Sources_main.c - CodeWarrior Development Studio.jpg

 

device_register value (different from hover to watch window)

18115_18115.jpg2014-12-26 11_44_29-Debug - Car_Window_Control_Sources_main.c - CodeWarrior Development Studio.jpg

data register value (different from hover to watch window)

18116_18116.jpg2014-12-26 11_45_54-Debug - Car_Window_Control_Sources_main.c - CodeWarrior Development Studio.jpg

 

 

Looking into it further (using a logic analyzer) I can call i2c_write() or i2c_read() once before I get a hang on the calling either of these again. Any combination of i2c_write() and i2c_read() leads to a hang up on the second function call.

i2c_write() -> i2c_read()            Hangs in i2c_read()

i2c_write() -> i2c_write()           Hangs in i2c_write()

i2c_read() -> i2c_read()             Hangs in i2c_read()

i2c_read() -> i2c_write()            Hangs in i2c_write()

 

Evan adding a i2c_write_multi() or i2c_read_multi() between the two calls does not help anything but the multi calls work with no issue.

 

If there is at all any suggestions I would be happy to hear them as this is holding up my project, if there is any more information that is needed I will haphappilyswer what you need if it helps resolve this odd issue.

 

Kas

Original Attachment has been moved to: main.c.txt.zip

0 Kudos
1 Solution
629 Views
mjbcswitzerland
Specialist V

Kas

I would check the use of

I2C0_FLT &= ~I2C_FLT_STOPF_MASK;

This is a "write-'1'" to clear flag and so writing a '0' to it will not do anything.

Also you may prefer to use the busy bit to wait for the stop bit to complete (IBB in I2Cx_S). I know that sending a new message when the bus is still busy will cause problems (bus arbitration error) but generally I would send a repeated start anyway if the previous mesage has not completed because the HW will co-ordinate tagging on the following one, which is also more efficient (no stop/start states needed).

Regards

Mark

http://www.utasker.com/kinetis.html

View solution in original post

0 Kudos
4 Replies
630 Views
mjbcswitzerland
Specialist V

Kas

I would check the use of

I2C0_FLT &= ~I2C_FLT_STOPF_MASK;

This is a "write-'1'" to clear flag and so writing a '0' to it will not do anything.

Also you may prefer to use the busy bit to wait for the stop bit to complete (IBB in I2Cx_S). I know that sending a new message when the bus is still busy will cause problems (bus arbitration error) but generally I would send a repeated start anyway if the previous mesage has not completed because the HW will co-ordinate tagging on the following one, which is also more efficient (no stop/start states needed).

Regards

Mark

http://www.utasker.com/kinetis.html

0 Kudos
631 Views
kaslewis
Contributor III

Hello Mark,

Is there any reason why the order of the lines I mentioned in my previous comment would matter, the one line is only to turn on and off the ACKs presumably when in Rx mode and would make no difference in Tx mode. Any hits as to what is really going on here would be nice.

Also why not clearing the STOPF caused issues for the single read/write but had no effect on the multi read/write and why it caused it to load wierd values in the registers but if the values were hard coded in the function the issue went away. An explinatin for this very odd behaviour would be helpful in better understanding how this microcontroller works.

Thanks

Kas

0 Kudos
631 Views
mjbcswitzerland
Specialist V

Hi Kas

I can't explain how the device operates in all circumstances (sometimes there are behavioural differences that can be postulated about but never fully understood) - I just do, for example,

I2C0_C1 = (IIC_IEN | IIC_TXAK); // send end condition and disable interrupts

to send the stop condition rather than using two operations (the final register content is known and so there is little point in two operations on it and introducing possible race state issues with the ordering of the operations and adding 6x more instructions than needed) and so never thought about it (nor saw any strange behavior involved).

Regards

Mark

µTasker Kinetis support

0 Kudos
631 Views
kaslewis
Contributor III

Mark,

WOW!! One small bit set incorrectly... I used that to move away from a time delay and missed the w1c in the data sheet. After changing that the read works fine, as for the write it appears the order of changing back to write from read was wrong ie

I2C0_C1 &= ~I2C_C1_TXAK_MASK;

I2C0_C1 |= I2C_C1_MST_MASK | I2C_C1_TX_MASK;

VS.

I2C0_C1 |= I2C_C1_MST_MASK | I2C_C1_TX_MASK;

I2C0_C1 &= ~I2C_C1_TXAK_MASK;

The second one is correct the first one seems to cause the hang.

Thank you very much

Kas

0 Kudos