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.

Mysterious glitch in MSP430F2013 USI module

I've been fighting a very strange problem with the USI module.  Occasionally, USICNT spontaneously takes on strange values.  I've attached a short program that demonstrates the problem.  It shows up on different chips (both 14-DIP and TSSOP-14) in various circuit setups, including a simple ez430-F2013.  It is extremely timing-sensitive, to the point where slight changes to bus capacitance make the problem show up or disappear.

Am I doing something wrong that's causing this?  If not, is there anything I can do to avoid it?  It's wreaking havoc with my system.

Thanks!

John-Paul Gignac

2148.msp430-bug-2.txt
;***********************************************************************
;* This program demonstrates a glitch in the MSP430F2013's USI module. *
;* I've tested it successfully with the EZ430-F2013, as well as other  *
;* setups.  If the glitch doesn't show up within a few moments, try    *
;* modifying the impedance of SCL very slightly by placing your hand   *
;* near, or attaching a long (eg, 24 inches) conductor to pin 8.       *
;***********************************************************************
#include  "msp430x20x2.h"

            RSEG    CSTACK                  ; Define stack segment
            RSEG    CODE                    ; Assemble to Flash memory
            EVEN

RESET       mov #0x5A80, &0x0120      ; Stop watchdog timer
            mov.w #SFE(CSTACK),SP     ; Initialize the stack pointer

            ; Set the clock speed to around 1MHz
            mov #0x86BA, &0x0056

            ; Setup pin assignments
            mov.b #0xFF, &0x0021      ; P1OUT = 0xFF
            mov.b #0xFF, &0x0022      ; P1DIR = 0xFF
            mov.b #0x00, &0x0026      ; P1SEL = 0x00
            mov.b #0xC0, &0x0027      ; P1REN = 0xC0  ; P1.6 & P1.7 Pullups

            ; Setup the USI in master mode
            mov.b #0xCB, &0x0078      ; USICTL0    ; Initiate software reset
            mov.b #0x50, &0x0079      ; USICTL1
            mov.b #0x6A, &0x007A      ; USICKCTL   ; SMCLK / 8
            mov.b #0x00, &0x007B      ; USICNT = USIIFGCC
            mov.b #0xCA, &0x0078      ; Finish the software reset
            mov.b #0x50, &0x0079      ; Clear the interrupt flags

            eint

main_loop
            ; Begin with a short delay
            mov #500, r12
delay
            dec r12
            jne delay 

            clr r7
            mov.b #0x08, &0x007B      ; Start transmitting 8 bits

;****************************************************************
;* We watch for the glitch while the byte is being transmitted. *
;* The symptom is that USICNT spontaneously takes on a value    *
;* higher than what was assigned to it.  A typical observed     *
;* value is around 0x1A.                                        *
;****************************************************************
watch_for_glitch
            cmp.b #0x09, &0x007B
            jhs glitch
            tst r7
            jeq watch_for_glitch
            jmp main_loop

glitch
;************************************************************************
;* Place a breakpoint here or trigger your oscilloscope on P1.0 (pin 2) *
;************************************************************************
            dint
            bic.b #1, &0x0021
            bis.b #1, &0x0021
            mov.b #0x00, &0x007B
            bic.b #3, &0x0079
            eint
            jmp main_loop

;*****************************
;* Interrupt Service Routine *
;*****************************
USI_ISR     mov #1, r7
            bic.b #1, &0x0079
            reti

            COMMON  INTVEC
            ORG     RESET_VECTOR            ; MSP430 RESET Vector
            DW      RESET                   ;
            ORG     USI_VECTOR              ; USICNT
            DW      USI_ISR                 ;
            END

  • I will try your code when I have time to do it.

    Most people would wait for USICNT to count down to 0 and set the IFG. They either poll the IFG or let it generates an interrupt. Why do you choose to poll USICNT?

  • Thanks in advance for having a look.  The code I provided is purely a stripped-down demonstration of the bug.  I poll USICNT because that's the register that glitches.  The problem also occurs periodically in my actual program, which is interrupt-driven.

  • I figured out the problem.

    If you change my sample program to stop checking for the glitch, the problem goes away!  (As evidenced by watching SCL on an oscilloscope.)  Believe it or not, *reading* USICNT at the wrong moment actually causes it to take on garbage values.

    You're probably wondering why I was reading USICNT in the first place.  In short, I shot myself in the foot by adding assertions into my original program.  :-(

    Shouldn't this issue be described in the errata?

  • Hi John-Paul,

    I'm curious about this issue. When you try reading USICNT and you get an erroneous value, does it persist to be erroneous if you read it again? Or does it revert back to a value you would expect?

    When I first read your post, I thought, "Oh, he must be a slave", and therefore USICNT would change asynchronously to your MCLK. However, the your code appears to be running as master with SMCLK/8, so I don't think that is the case.

    I'm assuming you have your setup such that the shift register clocks on the rising edge of the input clock (SMCLK/8), which might update USICNT after it receives this clock. If I understand this all correctly, you could have a race between MCLK and USICNT. In this case, I don't think it would be an errata per se. It just means you shouldn't poll USICNT. If the USICNT register stays corrupted, then you might be onto something.

    Thanks

    darkwzrd

  • Thanks for telling me that. Now I do not need to try your test code ;)

    BTW "mov #0x86BA,&0x0056" will change the byte &0x0056 to #0xBA. But it will not change the byte &0x0057 to 0x86 as you might have that in mind.

  • All I'm good at is wild speculation. I think you should both test the code! :)

    It would certainly make sense for the module to make a copy of the count register into a temporary, kind of like how the DMA module works. The DMA document clearly specifies that a copy is being made. Perhaps the USI isn't that sophisticated. The block diagram shows the USICNT as lines coming off a counter. It probably just ripples until the IFG falls out as it clocks.

    But who knows? All I have is wild speculation. These diagrams are often simplified, and might not 100% represent the real hardware.

    I think that if you (or the OP) really want to test it, slow down SCL enough (like divide 64 or 128) so that it is guaranteed you can get off a few reads before an update on UCICNT occurs. A divide 8 might be cutting it close.

  • darkwzrd said:

    I'm curious about this issue. When you try reading USICNT and you get an erroneous value, does it persist to be erroneous if you read it again? Or does it revert back to a value you would expect?

    USICNT retains the corrupted value.  For instance, if the value 0x1a is observed, then 26 bits will be transmitted.

  • old_cow_yellow said:

    BTW "mov #0x86BA,&0x0056" will change the byte &0x0056 to #0xBA. But it will not change the byte &0x0057 to 0x86 as you might have that in mind.

     

    I did have that in mind - thanks for pointing that out.  :-)

    For the record, this error doesn't affect the test.

  • I know that you shouldn't have this sort of issue since your SCL and MCLK are synchronous and you're clock is probably too slow to violate setup/hold times. But I thought, it sure sounds like this sort of issue, so lets check to see if the hardware really acts that way. 

    It sounds like you're saying that a read access actually MODIFIES the USICNT register (since it transmitted 26 bits). Well that sucks doesn't it? I wonder what could be going on....

  • NJC used USI to send 10-bits (Start + 8-bit data + Stop) and it took a long long time. See:

    http://www.msp430launchpad.com/2010/08/using-usi-as-uart.html#comments

    He said:

    " ... I think it is the USI, it seems to be taking FOREVER to finish and throw and interrupt. Why? Is this normal? I don't know. The 175.6kbps is more than enough for my project which needs to sent 16 bits at a rate of 4.5kHz (72kbps), so I will not be looking into why the USI takes so long. I will leave that up to you. If anyone finds out why there is such a long delay between transmissions, please comment and let me know..."

    May be the same bug?

  • old_cow_yellow said:
    May be the same bug?

    I think I see what you mean.  Is it possible that the bug might also occur when polling USIIFG?  You implied earlier that polling USIIFG was common practice.

  • Yes, polling USIIFG or let USIIFG generate an interrupt is commonly used. But that does not seem to solve the problem according to NJC.

    Do you really want to mark your postings as answered and verified? I think not.

  • darkwzrd said:
    I know that you shouldn't have this sort of issue since your SCL and MCLK are synchronous

    That was my first though too. It is  aknown problem that reading a register while the hardware is at the same time trying to modify this may prevent it from being modified (happens with PORT interrupts when a port interrupt is happening right at the moment of reading the interrupt flag register - the newer interrupt vectors circumvent it)

    In case of the USI, I can think of a problem that when the USICNT is being read while the internal hardware tries to update the count, the register gets corrupted. This may even happen if MCLK and the USI CLK are synchronized. We don't know at which exact moment during a clock cycle the register update happens and when or how it might collide with the read.

    Normally this shouldn't happen, but sh*t happens.

**Attention** This is a public forum