I2C read hangs with MDK (PDL 2.1.0, PSoC Creator 4.0)

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
lock attach
Attachments are accessible only for community members.
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

   

 

   

I've been developing a sample project for our original board using S6E1C32.

   

I'm using PSoC Creator 4.0 and PDL 2.1.0 to generate the application framework

   

and added codes extracted from the I2C sample project to handle I2C as mfs_i2c.[ch]

   

 

   

So far, my project runs fine with PSoC Creator 4.0 and IAR EWARM 7.80.2,

   

but with MDK 5.23, the I2C Read function halts.

   

(Note: I install my PDL to C:\Cypress\FM\PDL\2.1.0)

   

 

   

Please teach me how I can fix this problem.

   

 

   

I uploaded a sample project for FM0-64L-S6E1C3.

   

When I stepped the code (with MDK), the code hangs in

   

uint8_t I2c_Read(uint8_t *pRxData, uint8_t u8Size) 

   

which is in mfs_i2c.c (line 240).

   

 

   

Project/workspace for each IDEs are

   

MDK : FM0-64L-S6E1C3\workspace\mdk\i2ctest170410.uvprojx

   

IAR :  FM0-64L-S6E1C3\workspace\iar\i2ctest170410.eww

   

PSoC Creator: FM0-64L-S6E1C3\workspace\workspace.cywrk

   

 

   

Best Regards,

   

12-Apr-2017

   

Motoo Tanaka 

0 Likes
1 Solution
AchimE_41
Employee
Employee
10 sign-ins 5 sign-ins First comment on KBA

Hi Motoo-san,

   

 

   

Of course this is a problem and the team is working on a fix. The dev-team is currently preparing an update for PDL2.1, including a fix for this bug. Although the release date is not defined yet, I got following preliminary code from the team:

   

en_result_t Mfs_I2c_ConfigAck(volatile stc_mfsn_i2c_t* pstcI2c, en_i2c_ack_t enAck)
{
    stc_mfs_i2c_ibcr_field_t stcIbcr;

    if (NULL != pstcI2c)
    {
        return ErrorInvalidParameter;
    }
   
    stcIbcr = pstcI2c->IBCR_f;
    stcIbcr.ACKE = (I2cAck == enAck) ? 1u : 0u;
    stcIbcr.ACT_SCC = 0u; /* Set SCC = 0 to avoid generating a restart */

    pstcI2c->IBCR = *(uint8_t *)&stcIbcr;

    return Ok;
}

   

 

   

I hope this answers your questions.

   

kind regards,

   

Achim

View solution in original post

0 Likes
15 Replies
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

BTW, I noticed that to use UART of FM0-64L-S6E1C3, I had to modify uart_io.c in the utilities\printf_scanf folder.

   

In Function "void Uart_Io_Init(void)"

   

> SetPinFunc_SOT0_0() ;

   

< SetPinFunc_SOT0_1() ; // for FM0-64L-S6E1C3

   

> SetPinFunc_SIN0_0() ;

   

< SetPinFunc_SIN0_1() ; // for FM0-64L-S6E1C3

   

   

Best Regards,

   

12-Apr-2017

   

Motoo Tanaka

0 Likes
AchimE_41
Employee
Employee
10 sign-ins 5 sign-ins First comment on KBA

Hi,

   

can you tell me where exactly the code gets stuck in the I2c_Read function? Or is there even a Hardfault thrown?

   

Does it only occure with the one I2C device you have enabled (HIH6130) in the project at the moment or others, too?

   

 

   

For the different pins in the Uart_Io_Init, someone has picked the wrong UART pins on the starter kit. Normally the debugger is also connected to MFS0_0.

   

 

   

kind regards,

   

Achim

0 Likes
lock attach
Attachments are accessible only for community members.
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Achim-san,

   

 

   

Thank you very much for your response.

   

 

   

Currently, only one HIH6130 is connected to the I2C bus,

   

although in our project, 4 different I2C sensors are running without problem 

   

if we use PSoC Creator (GCC) or IAR EWARM.

   

 

   

I stepped the code, the code is in an infinite loop at

   

mfs_i2c.c : 278 : Mfs_I2c_GetStatus(I2cCh, I2cRxFull)

   

In Mfs_I2c_GetStatus(),  pstcI2c->SSR_f.RDRF never gets to be 1u.

   

So I suspect that the damage is done before entering Mfs_I2c_GetStatus.

   

In the loop there are

   

(1) 275: Mfs_I2c_GetStatus(I2cCh, I2cRxTxIrq)

   

(2) 265: Mfs_I2c_ConfigAck(I2cCh, I2cNAck)

   

(3) 269: Mfs_I2c_ConfigAck(I2cCh, I2cAck) 

   

(4) 273: Mfs_I2c_ClrStatus(I2cCh, I2cRxTxIrq)

   

(5) 278: Mfs_I2c_GetStatus(I2cCh, I2cRxFull) 

   

(6) 284: Mfs_I2c_GetStatus(I2cCh, I2cBusErr)

   

(7) 289: Mfs_I2c_GetStatus(I2cCh, I2cOverrunError)

   

(8) 294: Mfs_I2c_ReceiveData(I2cCh)

   

among these, (1), (5), (6), (7) are Mfs_I2c_GetStatus(es)

   

(2) has not been called before entering the infinite loop.

   

So I think one of (3), (4), (8) may be compiled wrong way with MDK,

   

as PSoC Creator and IAR EWARM does not have this problem.

   

 

   

Best Regards,

   

13-Apr-2017

   

Motoo Tanaka 

0 Likes
AchimE_41
Employee
Employee
10 sign-ins 5 sign-ins First comment on KBA

Hi motoo-san,

   

 

   

It looks like uVision has problems with assigning one struct to another.

   

en_result_t Mfs_I2c_ConfigAck(volatile stc_mfsn_i2c_t* pstcI2c, en_i2c_ack_t enAck)
{
    stc_mfs_i2c_ibcr_field_t stcIbcr =  pstcI2c->IBCR_f; 
  
    if (NULL == pstcI2c)
    {
        return ErrorInvalidParameter;
    }
    
    (I2cAck == enAck) ?  (stcIbcr.ACKE = 1u) :  (stcIbcr.ACKE = 0u);
    
    stcIbcr.ACT_SCC = 0u; // Set SCC = 0 to avoid generating a restart 
    
    pstcI2c->IBCR_f = stcIbcr;
    
    return Ok;
}

   

Unfortunately there is no workaround for this problem, except of writing your own function, because as you noted in your other thread the driver will be rewritten.

   

 

   

Following code uses direct register access and should solve the problem:

   

en_result_t Mfs_I2c_ConfigAck(volatile stc_mfsn_i2c_t* pstcI2c, en_i2c_ack_t enAck)

   

{
    if (NULL == pstcI2c)
    {
        return ErrorInvalidParameter;
    }
    
    pstcI2c->IBCR_f.ACT_SCC = 0u; // Set SCC = 0 to avoid generating a restart
    
    (I2cAck == enAck) ? (pstcI2c->IBCR_f.ACKE = 1u) : (pstcI2c->IBCR_f.ACKE = 0u);
    
    return Ok;
}

   

 

   

I have created an internal bug report for the problem.

   

 

   

kind regards,

   

Achim 

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Achim-san,

   

 

   

Thank you very much for your answer!

   

But, when I tried your code, the program stopped around the same place.

   

As before, I could not figure out exactly where the problem was triggered.

   

I'm afraid that there must be some more problem(s) remaining with this project and MDK.

   

 

   

FYI: Since your work around code has  SCC = 0  before assignment of ack,

   

I tried both case as the original code and your code, but in vain.

   

 

   

Best Regards,

   

19-Apr-2017

   

Motoo Tanaka

0 Likes
KoYa_1937921
Level 1
Level 1
Distributor - Marubun (Japan)
10 sign-ins 5 sign-ins First like received

Hi Achim-san,

   

 

   

I'm working with Motoo.

   

 

   

I have tried another code. The below code is working correctly. This issue may be caused by an implementation dependency of C Language for structure and SCC/ACKE-bit write sequence.

   

 

   

In this sample code, I suppose SCC should be set to zero at the same time when ACKE is set, because your code does not work.

   

Could you confirm the supposing is correct or not?

   

 

   

In IAR's object code of the original source code, the structure assignment is processed by just byte load and store instructions. In armcc's object code, a instruction sequence for each 1-bit field is repeated eight times.This difference may be caused by a difference b/w IAR's and armcc's implementations for structure. Source code provided by Cypress should avoid such implementation dependency of C Language.

   

Could you request your development team to confirm this problem, and solve it if they agree?

   

Could you also feed back your and/or their opinions to me?

   

 

   

The below code is just one of solutions. Please choose better solution if you change your code: e.g. GET/SET macro definition in stead of bit field declaration.

   

 

   

 

   

en_result_t Mfs_I2c_ConfigAck(volatile stc_mfsn_i2c_t* pstcI2c, en_i2c_ack_t enAck)
{
    stc_mfs_i2c_ibcr_field_t stcIbcr; /* =  pstcI2c->IBCR_f; */

   

        *(unsigned char *)(&stcIbcr) = *(unsigned char *)(&(pstcI2c->IBCR_f));
  
    if (NULL == pstcI2c)
    {
        return ErrorInvalidParameter;
    }
    
    (I2cAck == enAck) ?  (stcIbcr.ACKE = 1u) :  (stcIbcr.ACKE = 0u);
    
    stcIbcr.ACT_SCC = 0u; // Set SCC = 0 to avoid generating a restart 
    
    *(unsigned char *)(&(pstcI2c->IBCR_f)) = *(unsigned char *)(&stcIbcr);
    
    return Ok;
    
}

   

 

   

best regards,

   

 

   

Koji Yamada

MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

BTW, while debugging this I noticed that access of

   

pstcI2c member is done before checking if pstcI2c is NULL.

   

 

   

> stc_mfs_i2c_ibcr_field_t stcIbcr =  pstcI2c->IBCR_f; 

   

...

   

>     if (NULL == pstcI2c)

   

 

   

Although this does not seem to be the cause of my problem,

   

this could be a cause of other problem(s), right?

   

Best Regards,

   

24-Apr-2017

   

Motoo Tanaka

0 Likes
AchimE_41
Employee
Employee
10 sign-ins 5 sign-ins First comment on KBA

Hi Koji-san,

   

Yes ACT_SCC should be written at the same time. The problem is ACT_SCC is a different value when reading than writing.

   

Sorry, that was a stupid mistake from my side there 😞

   

 

   

Few thoughts later, my proposal would be to get rid of the complete structs and use bit-banding instead. With this you won't have to bother with the ACT_SCC  bit at all.

   

I made the following proposal to the developers, but still wait their feedback. Keep in mind it is not completely tested yet.

   

en_result_t Mfs_I2c_ConfigAck(volatile stc_mfsn_i2c_t* pstcI2c, en_i2c_ack_t enAck)
{
    if (NULL == pstcI2c)
    {
        return ErrorInvalidParameter;
    }
    
    if(I2cAck == enAck)
    {
        *((volatile uint8_t *)(0x42000000UL + ((&pstcI2c - 0x40000000UL) * 32) + (13 * 4))) = 1; //set ACKE (bit13) by bit-banding
    }else{
        *((volatile uint8_t *)(0x42000000UL + ((&pstcI2c - 0x40000000UL) * 32) + (13 * 4))) = 0; //clear ACKE (bit13) by bit-banding
    }
    
    return Ok;
}

   

 

   

Unfortunately it lacks a bit the readability, probably a macro is needed if it is used in the final implementation.

   

 

   
   

Motoo-san,

   

yes it is a problem as well, but should only very rarely occur. Most of the time it will only read data from a junk address and stores it in stcIbcr. But in the rare case memory protection is used for the addresses next to the null pointer, a Fault condition would be triggered.

   

kind regards,

   

Achim

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Achim-san,

   

 

   

Thank you very much for your answer!

   

Since your code could not be compiled, I modified your code as follow

   

and, yes, it is working now on my FM0-64L-S6E1C3 evaluation board.

   

But I'm afraid that probably this code is not quite good for end products.

   

========================

   

        if (NULL == pstcI2c)
    {
        return ErrorInvalidParameter;
    }
    
// pstcI2c = I2C1 = 0x40038100UL
// #define FM_MFS1_I2C_BASE                          (0x40038100UL) /* MFS1 Base Address */
    if(I2cAck == enAck)
    {
        *((volatile uint8_t *)(0x42000000UL + ((0x40038100UL - 0x40000000UL) * 32) + (13 * 4))) = 1; //set ACKE (bit13) by bit-banding
    }else{
        *((volatile uint8_t *)(0x42000000UL + ((0x40038100UL - 0x40000000UL) * 32) + (13 * 4))) = 0; //clear ACKE (bit13) by bit-banding
    }
    
    return Ok;

   

========================

   

Best Regards,

   

25-Apr-2017

   

Motoo Tanaka

0 Likes
AchimE_41
Employee
Employee
10 sign-ins 5 sign-ins First comment on KBA

Hi Motoo-san,

   

I copied by accident my first draft, that was referring to the wrong address. Correct is the one below.

   

 if(I2cAck == enAck)
    {

   

        *((volatile uint8_t *)(0x42000000UL + ((uint32_t)(pstcI2c - 0x40000000UL) * 32) + (13 * 4))) = 1; //set ACKE (bit13) by bit-banding

   

    }else{

   

        *((volatile uint8_t *)(0x42000000UL + ((uint32_t)(pstcI2c - 0x40000000UL) * 32) + (13 * 4))) = 0; //clear ACKE (bit13) by bit-banding

   

    }

   

 

   

Sorry for the inconvenience,

   

Achim

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Achim-san,

   

 

   

Thank you very much for your correction.

   

Since I'm out of the office today, I can not test it right now, but your code seems better.

   

I'll let you know when I test it tomorrow.

   

 

   

Best Regards,

   

26-Apr-2017

   

Motoo Tanaka

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Achim-san,

   

I have just confirmed that your code works fine!

   

So I think that we can utilize your solution for this particular case.

   

But meantime, as Koji asked, would you let us know

   

(1) If Cypress development team confirmed this problem.

   

(2) Cypress development team's opinion about this problem.

   

(3) If Cypress development team will fix this problem.

   

(4) And if the answer to (3) is yes, how it will be fixed.

   

Best Regards,
27-Apr-2017
Motoo Tanaka

0 Likes
AchimE_41
Employee
Employee
10 sign-ins 5 sign-ins First comment on KBA

Hi Motoo-san,

   

 

   

Of course this is a problem and the team is working on a fix. The dev-team is currently preparing an update for PDL2.1, including a fix for this bug. Although the release date is not defined yet, I got following preliminary code from the team:

   

en_result_t Mfs_I2c_ConfigAck(volatile stc_mfsn_i2c_t* pstcI2c, en_i2c_ack_t enAck)
{
    stc_mfs_i2c_ibcr_field_t stcIbcr;

    if (NULL != pstcI2c)
    {
        return ErrorInvalidParameter;
    }
   
    stcIbcr = pstcI2c->IBCR_f;
    stcIbcr.ACKE = (I2cAck == enAck) ? 1u : 0u;
    stcIbcr.ACT_SCC = 0u; /* Set SCC = 0 to avoid generating a restart */

    pstcI2c->IBCR = *(uint8_t *)&stcIbcr;

    return Ok;
}

   

 

   

I hope this answers your questions.

   

kind regards,

   

Achim

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Dear Achim-san,

   

Thank you very much for your answers!

   

May be I'm a little bit picky, but

   

> pstcI2c->IBCR = *(uint8_t *)&stcIbcr;

   

seems a little bit ambiguous about the meaning of "&",

   

it might be better 

   

<  pstcI2c->IBCR = *(uint8_t *)(&stcIbcr);

   

or

   

< pstcI2c->IBCR = *((uint8_t *)(&stcIbcr));

   

to be precise.

   

Except this, I believe that you have answered all my questions

   

and the cause of the problem was found and workaround is in place.

   

So I think that we can call this case solved.

   

Thank you very much for your nice support!

   

 

   

Best Regards,

   

28-Apr-2017

   

Motoo Tanaka

0 Likes
AchimE_41
Employee
Employee
10 sign-ins 5 sign-ins First comment on KBA

You are right, that should be changed. I will forward the feedback.

0 Likes