MKL25 I2C write issue

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

MKL25 I2C write issue

1,846 Views
lisafernandez
Contributor I

Hi Freescale Microcontroller forum,

I'm trying to use I2C on my MKL25Z128 microcontroller to write to a slave device. I've used Processor Expert to set everything up for me. However, no signals go out on my SCL and SDA lines. They both stay high.

I'm in the fortunate position that I use this exact uc with the same PE settings in another project. This other project works fine, and I have found the line of code where their behaviors differ. It happens in the middle of a function generated by PE:

/* ===================================================================*/

LDD_TError I2C_MasterSendBlock(LDD_TDeviceData *DeviceDataPtr, LDD_TData *BufferPtr, LDD_I2C_TSize Size, LDD_I2C_TSendStop SendStop)

{

  I2C_TDeviceData *DeviceDataPrv = (I2C_TDeviceData *)DeviceDataPtr;

  /* Device state test - this test can be disabled by setting the "Ignore enable test"

     property to the "yes" value in the "Configuration inspector" */

  if(!DeviceDataPrv->EnUser) {         /* Is the device disabled by user? */

    return ERR_DISABLED;               /* If yes then error */

  }

  if (Size == 0x00U) {                 /* Test variable Size on zero */

    return ERR_OK;                     /* If zero then OK */

  }

  if (DeviceDataPrv->SendStop == LDD_I2C_SEND_STOP) {

    if ((I2C_PDD_GetBusStatus(I2C0_BASE_PTR) == I2C_PDD_BUS_BUSY) || /* Is the bus busy? */  \

       ((DeviceDataPrv->SerFlag & MASTER_IN_PROGRES) != 0x00U) || \

       (DeviceDataPrv->OutLenM != 0x00U))  {

      return ERR_BUSY;                 /* If yes then error */

    }

  } else {

    if (((DeviceDataPrv->SerFlag & MASTER_IN_PROGRES) != 0x00U) || /* Is the bus busy? */  \

      (DeviceDataPrv->OutLenM != 0x00U))  {

      return ERR_BUSY;                 /* If yes then error */

    }

  }

  /* {Default RTOS Adapter} Critical section begin, general PE function is used */

  EnterCritical();

  DeviceDataPrv->SerFlag |= MASTER_IN_PROGRES; /* Set flag "busy" */

  DeviceDataPrv->OutPtrM = (uint8_t *)BufferPtr; /* Save pointer to data for transmitting */

  DeviceDataPrv->OutLenM = Size;       /* Set the counter of output bufer's content */

  DeviceDataPrv->SendStop = SendStop;  /* Set generating stop condition */

  I2C_PDD_SetTransmitMode(I2C0_BASE_PTR, I2C_PDD_TX_DIRECTION); /* Set TX mode */

  if (I2C_PDD_GetMasterMode(I2C0_BASE_PTR) == I2C_PDD_MASTER_MODE) { /* Is device in master mode? */

    I2C_PDD_RepeatStart(I2C0_BASE_PTR); /* If yes then repeat start cycle generated */

  } else {

    I2C_PDD_SetMasterMode(I2C0_BASE_PTR, I2C_PDD_MASTER_MODE); /* If no then start signal generated */

  }

  I2C_PDD_WriteDataReg(I2C0_BASE_PTR, 0xECU); /* Send slave address */

  /* {Default RTOS Adapter} Critical section end, general PE function is used */

  ExitCritical();

  return ERR_OK;                       /* OK */

}

When this function is reached, the uc has been initialized and enabled using PE code. Both I12 and I2C interrupts have been enabled. This function further configures the uc I2C to be in master transmit mode. The problem occurs at line 38. In the other (working project), completion of this line sets the BUSY register ("Bus is busy") and the IICIF register ("Interrupt pending"). However, in my current project, neither of these two registers are set.

Here are some debugging checks I've made on my own:

--SCL and SDA pins have correct mux setup as I2C signals.

--Slave address is correct.

--I physically disconnected the slave, so that the SCL and SDA lines didn't lead anywhere, and tested the code. The same result happens.

--Clock is configured for 375 kHz, which (as far as I know) is within spec for the I2C peripheral.

--The I2C0 prescaler is set to 1. I saw (here: KL25Z and I2C: Missing Repeated Start Condition | MCU on Eclipse) that there is possibly a bug related to this prescaler.

Any suggestions you can offer would be greatly appreciated! I wasn't sure what parts of my code are relevant, but I'm happy to post more if there is something else you need to see. Just let me know!

Thanks,

Lisa

Labels (1)
Tags (1)
0 Kudos
Reply
8 Replies

1,251 Views
mjbcswitzerland
Specialist V

Hi Lisa

Can your code run on a FRDM-KL25Z or TWR-KL25Z48M?

If it can, you can post the binary here - you will need to tell me the address of the routine I2C_MasterSendBlock() in the code (find its address in the map file) and I can probably tell you what is going wrong.

Regards

Mark

Kinetis: µTasker Kinetis support

KL25: µTasker Kinetis FRDM-KL25Z support / µTasker Kinetis TWR-KL25Z48M support

I2C: http://www.utasker.com/docs/uTasker/uTaskerIIC.PDF

For the complete "out-of-the-box" Kinetis experience and faster time to market

0 Kudos
Reply

1,251 Views
lisafernandez
Contributor I

Update:

I've written a bare-bones code with only the I2C functionality. Here is the main function:

void mainApp(void)

{

    pressI2ClDeviceData.handle = I2C_Init(&I2ClDeviceData);            // Initialize the I2C module

    I2C_Enable(I2ClDeviceData.handle);                                    // Enable the I2C communications

    I2C_Write(SENSOR_RESET);

}

APP_Error I2C_Write(uint8 val)

{

    uint8 res;

    uint8 value[1];

    value[0] = val;

    for(res = 0; res<0xF; res++) {};

    res = I2C_MasterSendBlock(I2ClDeviceData.handle, &value, 1U, LDD_I2C_SEND_STOP);

    if (res!=ERR_OK)

        return ERR_SENSOR_I2C_BLOCK_WR;

    i2cTimer = I2C_TIMEOUT_PERIOD;

    while (!I2ClDeviceData.dataTransmittedFlg)

    {

        if(!i2cTimer)

        {

            I2ClDeviceData.dataTransmittedFlg = FALSE;

            return ERR_SENSOR_I2C_TIMEOUT;

        }

    } /* Wait until data is sent */

    I2ClDeviceData.dataTransmittedFlg = FALSE;

    return ERR_OK;

}

where I2C_Init and I2C_Enable are PE functions that have always worked. I2C_Write includes the PE function I2C_MasterSendBlock where I was having problems.

When I run this bare-bones code on my board, the I2C peripheral functions! The SCL and SDA lines indicate that data is being sent, the correct value is in the I2C data buffer, and the OnMasterBlockSent interrupt is reached.

The only thing that does not appear to be normal here is the SCL frequency. I had it set for ~398kHz, but it clocked at~ 240kHz.

I changed it to 98kHz, but it clocked at 68kHz. I made the change by changing the frequency divider register bits in PE to 100011. I check the appropriate register and confirmed that this setting is implemented. I'm not sure where this clock error is coming from. I will keep investigating, but I would appreciate any suggestions!

Thanks,

Lisa

0 Kudos
Reply

1,251 Views
mjbcswitzerland
Specialist V

Lisa

A value of 0x23 in the divider register means that you must have a bus clock of 18MHz (18MHz/256 = about 70kHz).

Is this what you expect?

Regards

Mark

Kinetis: µTasker Kinetis support

KL25: µTasker Kinetis FRDM-KL25Z support / µTasker Kinetis TWR-KL25Z48M support

For the complete "out-of-the-box" Kinetis experience and faster time to market

0 Kudos
Reply

1,251 Views
lisafernandez
Contributor I

Unfortunately not. My clock is set to 24MHz (using PE). I will try to run an experiment to see what frequency the bus clock is operating at and, if it's not running at the desired frequency, why it's not.

Any ideas as to whether this is the cause of my I2C-not-running-at-all problem in my larger program?

0 Kudos
Reply

1,251 Views
mjbcswitzerland
Specialist V

Hi Lisa

Without complete project details it is not possible to work out why there are these various problems.

Unfortunately a large percentage of difficulties reported on the forum (especially related to I2C) are due to PE generated code and if you use this source you will need to also understand when it works correctly and when not and be able to solve the issues accordingly.

If you post the binary that shows incorrect frequencies that can be loaded to a FRDM board I don't mind spending a short time to tell you where the error is.

Should your company however prefer a solution to stop futher project delays and costs I can offer you a complete solution for the KL25 which I can guarantee will not give you further problems (industrially proven and personally supported) or I can offer you a small contract project (with NDA for your company) to resolve the overall PE/project concerns.

Otherwise you will either need to make a support request to Freescale for help or invest some time in analysing the code that you have and working out either corrections to the PE generated parts or incompatibilities at the system level.

Regards

Mark

Kinetis: µTasker Kinetis support

KL25: µTasker Kinetis FRDM-KL25Z support / µTasker Kinetis TWR-KL25Z48M support

I2C: http://www.utasker.com/docs/uTasker/uTaskerIIC.PDF

For the complete "out-of-the-box" Kinetis experience and faster time to market

0 Kudos
Reply

1,251 Views
lisafernandez
Contributor I

Hi Mark,

Thanks for your help so far. I did not realize that PE generated code often had issues with the I2C! That's good to know, and I will keep it in mind. I think I will continue debugging for a while on my own and take it to the Kinetis support team (In fact, I thought this forum was the place for that --apparently not! It keeps getting harder and harder to get technical support...).

Thanks again,

Lisa

0 Kudos
Reply

1,251 Views
mjbcswitzerland
Specialist V

Hi Lisa

The Freescale forums do have a great deal of help and support from Freescale experts (better and more intensive than at most other places) but it is still a platform that is intended mainly for discussions between users.

If you have serious issues then I am sure that the Freescale technical team is also very willing to help, as long as you can supply them with complete information and code which shows the issue and they can find the time required to do the work.

In serious cases it is probably best to directly request this, epecially if you believe or can prove that the root cause is the software that Freescale has supplied to you.

The problem with software projects is that the issues are often not directly in the software supplied but instead in the overall code or system concept, which makes identifying the cause to sometimes be a complicated and time consuming. Of course no one, including Freescale, will be interested in investing too much of their skilled worker's time identifying and solving (potential) user's concept errors since this is costly time.

One thing that I do often see is that PE generated code, which is very useful for providing basic starting points with new peripherals, is considered to be a silver bullet to all projects designs. What happens is that the users encounter difficulties at some point and then tend to be quite helpless as to what to do about it; lacking the knowledge of what the code is doing, how the peripheral is actually working, how the modules may be interacting or affecting each other, etc.

If you have some free time to work on this it may be a good investment to carefully study the peripheral involved, then the code involved, before debugging the behavior. Actually solving peripheral problems (when directly due to them) with a bit of preporation and experience usually takes only a short time. If you can identify the weakness in PE generated parts then you can also submit the improvement back to Freescale so that others users can benefit.

Regards

Mark

0 Kudos
Reply

1,251 Views
lisafernandez
Contributor I

Hi Mark,

Thanks for your offer to help! I really appreciate it. Unfortunately I may not upload the binary file per my company's policy. However, we do have a FRDM board somewhere, so I will see what I can do on that. I'm going to make a new, bare-bones project with just the I2C functionality. First I'll try it out on my current board, and if that doesn't work I'll see what it does on the FRDM board.

I will let you know how it goes!

Thanks,

Lisa

0 Kudos
Reply