This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RF430FRL152H: I2C hangs after flipping VDDSW

Part Number: RF430FRL152H
Other Parts Discussed in Thread: , MSP-FET

Hi,

I am using RF430FRL152H as I2C master with a single slave device (MAX5395). I'm encountering issues where the I2C write will get stuck infinitely waiting on an interrupt flag to be set in UCB0IFG, only after flipping VDDSW (either by physically disconnecting VDDB from VDDSW, or by exposing the device to an RF field and causing a change in BS_VR_VBN).

My I2C initialization code:

    // Set pins to I2C (see datasheet p.33-34)
    // SDA
    P1DIR |= BIT0;
    P1SEL0 |= BIT0;
    P1SEL1 &= ~BIT0;
    // SCL
    P1DIR |= BIT1;
    P1SEL0 |= BIT1;
    P1SEL1 &= ~BIT1;

    // Initialize USCI
    UCB0CTL1 |= UCSWRST;                                // Software reset enabled
    UCB0CTLW0 |= UCMODE_3  + UCMST + UCSYNC + UCTR;     // I2C mode, Master mode, sync, transmitter
    UCB0CTLW0 |= UCSSEL_2;                              // select SMCLK at 2MHz
    UCB0CTLW1 |= UCASTP_1 + UCGLIT_0;                   // Automatic STOP generation, deglitch time
    UCB0BRW = 40;                                       // 2Mhz / 40 = 50kHz
    UCB0CTL1  &= ~UCSWRST;                              // exit reset mode

My I2C write code:

    UCB0CTL1 |= UCSWRST;                // Software reset enabled
    UCB0I2CSA  = MAX5395_I2C_ADDR;                // I2C slave address
    UCB0CTLW1 = UCASTP_1;
    UCB0TBCNT = 0x0002;

    UCB0CTL1  &= ~UCSWRST;           // put eUSCI out of reset

    UCB0CTL1 |= UCTXSTT + UCTR;     // start i2c write operation
    while(!(UCB0IFG & UCTXIFG0));   // send the I2C address
    UCB0TXBUF = command;                // send the command
    while(!(UCB0IFG & UCTXIFG0));    // wait until the command is sent out
    UCB0TXBUF = txData;           // send the LSB
    while(!(UCB0IFG & UCBCNTIFG));  // wait until it has been transmitted
    UCB0CTL1 |= UCTXSTP;             // send the stop condition
    while(!(UCB0IFG & UCSTPIFG));   // wait until it has been received
    UCB0CTL1  |= UCSWRST;            // put the eUSCI into reset mode

My main loop is set to repeatedly run both the initialization & write code in a loop. It works, until I flip VDDSW, after which it always stalls after writing the I2C address, as shown in the logic analyzer capture below. But I know that that the device retains power, because other functionality works (e.g. the program keeps executing if I disable the I2C code... a PWM output on a different pin still works... etc).

Please let me know any suggestions to resolve.

Thanks,

Jason

  • To add additional detail, when I investigate using the debugger, I can see that the UCTXIFG0 bit is actually set in UCB0IFG. So I have no idea why it's stalling here.

  • Hi Jason,

    is it possible that you get glitches on the I2C lines when power is flipped or RF energy is applied?

    Noise which might not be possible on the logic analyzer?

    Would the part work once you applied a RESET or do you need a power cycle to get it running?

    Also not easy to see is if the slave sends the ACK?

    Another question would the same behavior appear if you would use an interrupt handler instead of polling the flags?

  • Hi Dietmar,

    Thanks for your response.

    • It certainly is possible that there's some noise/glitching on I2C lines when the switch flips. However, the problem occurs even if the I2C transaction is delayed far past the point of the switch flipping. For example - if I insert a 2 second delay between each transaction and flip the switch during the delay - the next transaction is the one that stalls. So I reset the bus every time (using UCSWRST) but the problem still occurs.
    • If I apply a RESET with the switch off, the firmware restarts but the first I2C transaction also stalls in a similar manner. If I apply a RESET with the switch on, the firmware restarts and works.
    • The slave does send the ACK, according to my logic analyzer.
    • Regarding using an interrupt handler, I strangely can't seem to get USCI_B0_VECTOR to work on this part. If I enable the interrupt using
      UCB0IE = UCTXIE0 + UCRXIE0;

      and place some code in the ISR

      #pragma vector = USCI_B0_VECTOR
      __interrupt void USCI_B0_ISR(void)
      {
          P1SEL0 &= ~(BIT0);
          P1SEL0 &= ~(BIT1);
      
          UCB0CTLW0 |= UCSWRST;   // Reset
          UCB0CTLW0 &= ~UCSWRST;
      
          P1SEL0 |=  (BIT0 | BIT1);
      }

      and put a breakpoint in the ISR, I never see the breakpoint reached.

  • Jason,

    thanks for more details.

    1. the glitches would affect the I2C state machine also with delays between the transmission because state machine is always enabled and might react on signals on SCL and SDA. However if you trace with a scope to detect glitches you can confirm or exclude this theory. Not sure if your logic analyzer is capable to trigger on glitches. But the RF item points to it.

    2. Ok UCSWRST will not work which is a bit strange. However you do not know when the stuck happens right. Because if it happens from re-init to ADR transmission the UCSWRST will not have an effect because device hangs at the flag pollling.
    Interesting would be if you are connected to debugger to reset the PC to the I2C init and execute again to see if another SWRST would help, can you try this?

    3. What do you mean apply RESET with switch off/on? However especially with switch off the I2C init would executed a 2nd time and then point #2 is answered right?

    4. Regarding Interrupt I would recommend to enable the global interrupt enable (GIE) if not done. Otherwise we need to find out why interrupts does not work.

  • Hi Dietmar,

    1. Unfortunately I don't have access to a scope at the moment (due to the quarantines!) but will look more closely at this next time I'm able. I'm pretty much assuming that there is some momentary glitching - and want to figure out how to reset the I2C state machine properly to deal with it.
    2. How can I reset the PC to I2C init using Code Composer Studio?
    3. I'm talking about using the Soft Reset button in CCS, with an external switch between VDDSW & VDDB closed (on) or open (off). Basically SV7 on the EVM, although I'm using a custom board.
    4. Yes, I do have GIE enabled but still can't get the interrupt handler to work. Do you have any suggestions to investigate further?

    Thanks for your help!

    Jason

  • Hi Jason,

    regarding #2.)
    - insert a breakpoint at the line where you set the SWRST bit, then open the register view and go to CPU registers, check the PC value (program counter) when you hit the breakpoint
    - then you remove the BP and execute, trigger your failure and stop the debugger, you should see it hangs in the flag polling loop
    - go the register view open the PC value window and enter the address you noted down before

  • Jason,

    sorry something went wrong with my browser


    regarding #2.)
    - insert a break point at the line where you set the SWRST bit, then open the register view and go to CPU registers, check the PC value (program counter) when you hit the break point
    - then you remove the BP and execute, trigger your failure and stop the debugger, you should see it hangs in the flag polling loop
    - go the register view open the PC value window and enter the address you noted down before

    regarding #3)
    - so trying to understand the supply scenario when it appears and disappears
    - means you have the switch "BS_VR_VBN" connected to VDDBSW to supply from battery right?
    - then you have the switch "EN_BATSWITCH' closed during reset (on) --> behavior disappears after reset
    - if you have the switch "EN_BATSWITCH' open during reset (off) --> behavior still present?
    - I mean if you supply via battery ("BS_VR_VBN" connected to VDDBSW) you have to have it closed otherwise you backdoor supply via JTAG right?

    regarding #4)
    - this is strange GIE is enabled and I2C interrupts are enabled, flags are set -> means the interrupt must be executed
    - can you please share the binary hex file to see if the corresponding interrupt vector and the ISR are generated correct?

  • Hi Dietmar,

    (2) This doesn't seem to fix the issue, and actually seems to cause some kind of issue with debugger - I recorded a screen capture so you can see what happens: https://www.youtube.com/watch?v=MqG0rOgseW4&feature=youtu.be

    (3) EN_BATSWITCH is set the entire time. BS_VR_VBN also stays closed the entire time, as far as I can tell. Instead of changing EN_BATSWITCH, I am flipping a physical switch that shorts the VDDSW pin to the VDDB on the IC. Just like SV7 on the RF430FRL152HEVM. I found that you need to have this switch in place to flash the chip via JTAG. But ideally we don't want to have this switch in place during production.


    (4) Please see attached file and let me know.

    s3-firmware.zip


    Thanks,

    Jason

  • Related to the interrupts, it seems like the value of UCB0IE is just not changing. Even after stepping past a line of code like

    UCB0IE = UCTXIE0 | UCRXIE0;

    while UCSWRST bit is set, the value of UCB0IE as per the CCS register view stays at 0x0000.

  • Hi Dietmar,

    Apologies for the multiple posts, but I figured providing some sample code to reproduce the issue on the EVM might be helpful to you.

    • For the attached project, I built and ran it on the RF430FRL152HEVM (with no slave device attached or anything - just the bare PCB).
    • The EVM is powered by an MSP-FET connected to SV2. S6 is set to Supply. SV7 is jumpered.
    • When running the program, it gets caught on line 56 of max5395.c, which is a while loop waiting for the UCTXIFG0 bit to be set. If I understand correctly, this bit should get set when the USCI is done transmitting the byte, regardless of the presence of an external slave device on the bus.
    • I notice that UCB0IE = 0x0000, even though I am attempting to set the UCTXIE0 flag in line 49 of max5395.c.
    • My questions would be - why is the code getting stuck on line 56 - and why is the value of the UCB0IE register not updating?

    Hope this helps, and thanks again for your assistance.

    rf430frl152h-issue.zip

    Best,

    Jason

  • Jason,

    ok thanks for all the information let's work step by step
    1. Regarding the debug it's hard to understand what you did in the youtube video. I think it is not exactly what I proposed.

    2. The binary image you send has at the location of eUSCIB vector at address 0xFFF0 the value 0x0xFEAA defined. This is where you ISR is located.
    At 0xFEAA at least is code located.

    3. If the module specific interrupt enables are not set this the reason why the interrupt is not handled properly.
    Does it never work to set these bits or only if failure appeared?

    So I think we need to first find out why the interrupt enables cannot be set looks like something with your project or JTAG connection is strange.

    I tried to import your CCS project but get a failure on the used compiler version. So can you please let me know which compiler you're using so that I can install it on my CCS?

  • Hi Jason,

    my colleague has the RF430FRL152HEVM available. He compiled you project you provided and we are able to see that the Interrupt enable bits cannot be set. We controlled the disassembled code (machine code) and can confirm that compiler translated it correctly to mov instruction. Also the address of the register 0x66A was correct.

    So we will focus on this now and provide update as soon as possible. Due to current COVID-19 situation our ability to do physical experiments is a bit limited at the moment therefore pls understand some delays, thanks!

  • Hello Jason,

    Dietmar asked my to take a look to your RF430FRL152H firmware sample with IRQ.

    After putting your code to my target I see the same problem as you do but this is because your code has to be changed a lot to be able to work with interrupt.

    The UCB0IE register, which seemed is not writeable, is not a fault, because this register can only be written when UCSWRST is set to "0" otherwise it will hold the UCB0IE register in reset. I was also wondering about this behavior at first, but learned that it is ok.

    After reading the thread in detail, I will come back to questions about the power supply of your circuit.

    Can you please explain how your board will work in terms of the supply. Will it be always powered by VDDB? Should it work also powered only by RF?

    From which supply is the MAX5395 powered? To which supply are the I2C pullups connected? Is the FET tool supplying the board during debug?

    Have you checked if all supply voltage capacitors are as recommended?

    When you open the switch between VDDB and VDDSW should the device be powered by VDDB in this case? The reason for the question is that I could not see any code that closes the battery switch.

    Sorry for all these questions but it is necessary to understand the power supply which is a bit complex because of all the different sources (Battery, RF, Debugtool) and possible ways to switch between.

    When your code stuck in the loop waiting for the TXIFG, have you tried looking at the disassembly window and doing assembler steps?

    Let's see if we can find the reason for the strange behavior of your circuit.

    Best regards,
    Helfried 

        

  • Hi Helfried,

    Thanks for your reply & for confirming the point about UCB0IE not being writeable with UCSWRST is cleared. To answer your questions:

    • The board is powered by VDDB. But, we have an interrupt attached to VDDR (RFPMMIEVR) which we use as a sort of "wake-on-write" functionality (ideally we wanted to wake up on change to NDEF payload - but found that's not possible on this chip without substituting the whole NFC stack - so this is a compromise). I found that this interrupt does not work if VDDB is shorted to VDDSW.
    • MAX5395 is powered by VDD2X. There is a level shifter between VDDB and VDD2X for the I2C bus.
    • All supply voltage capacitors follow datasheet recommendations.
    • Yes, it wasn't shown in my example but I close the battery switch as follows:
      RFPMMCTL0 = PMMPW | RFPMM_EN_BATSWITCH | RFPMM_EN_V_DOUB; // enable battery switch and internal charge pump

      right at the beginning of main().

    • I haven't looked at the disassembly, I will try to do this and report back if I get time in the next few days.

    Best,

    Jason