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.

MSP430G2231 SPI send 16Bit +

Hi all,

i am a beginner and i try to communicate with both, an EEPROM and a CAN Controller.

My Problem is:

I need to send more than 8 Bits via the SPI within one clocking cycle, i.e. 8 bits command + 8/16 bit address.

I checked my code with an osci and I can see, that only USISRL is sent, instead of the whole USISR register.

Can anyone find the mistake in my code???

Code example:

void initialize_usi(void)

{...

USICTL0 |= USIPE7 + USIPE6 + USIPE5 + USIMST + USIOE + USISWRST;
       USICTL1 |= USIIE + USIIFG +USICKPH ;
        USICKCTL |= USIDIV_4 + USISSEL_2 ;//+ USICKPL;
        USICNT = USI16B ;
    USICTL0 &= ~USISWRST;

}

void main(void)

{

...

USISR = 0x030E;                //  03 is the read status register command, 0E the address
    USICNT = 24;
       while (!(USIIFG & USICTL1)) {} ;

...

}

Thanks a lot,

regards

Marcus

  • Hmm, quite some time ago I used the USI and I think it's your USICNT loading:

    USICNT = 24;

    This will have no USI16B set, thus it will only use the USISRL.

    And this is where it gets a bit rusty, but I think you should use: USICNT |= 24; but maybe you have to set all the bits at once using: USICNT = USI16B | 24; 

  • Thanks for your reply.

    Bernhard Weller said:

    And this is where it gets a bit rusty, but I think you should use: USICNT |= 24;

    I´ve seen on the osci, that sclk ticked 24 times

    Bernhard Weller said:

    but maybe you have to set all the bits at once using: USICNT = USI16B | 24;

    Unfortunately that did not work. I

    think it´s ok, to set the USI16 Bit in the USI_initialize function and I´m not quite sure, if the command USICNT |= 24 resets the USI16 Bit. (I don´t think it does)

    Probably it´s not possible to send the USISRH, but I can´t find any information about that in the USI-chapter in the  UsersGuide.

  • Brnhard is right. Your writing of

    Marcus B��nisch said:
        USICNT = 24;
    implicitely clears the USI16B bit.

    However, SPI is a synchronous protocol.

    It makes no difference at all if you send 3*8 bit or 1*16 bit and 1*8 bit. For each single bit, a new clock pulse is generated, and when the operation is complete, no more clock pulses are generated until new data is to be sent. And the clock pulses do not necessarily have to have the same frequency. So when you send 8 bit, and then reload the refgister and send the next 8 bit, the gap between is considered just a very slow clock pulse, not a break in the transmission.

    The synchronizing (telling the slave that a new transfer starts) is done using the separate CS (chip select) line, that you need to control manually through a standard I/O port pin.

  •  

    Marcus B��nisch said:
    Probably it´s not possible to send the USISRH, but I can´t find any information about that in the USI-chapter in the  UsersGuide

    14.2.3.3 USISR Operation reads like it should be possible to use the whole 16 bits. The errata also contains no informations that there is a bug preventing you from doing so.

    Can you check the define of the USI16B - just to verify it's really 0x40? 

  • Ok, now my code looks like that:

    ...

    P1OUT &= ~CS_CTRL;       // CS of can controller mcp2515

    for(i=0;i<20;i++);             // wait for the slave

    USISRL = 0x02;            // write register command

    USICNT = 8;

     while (!(USIIFG & USICTL1));     // wait

    USISRL = 0xAB            // address of register

    USICNT = 8; while (!(USIIFG & USICTL1));

    USISRL = 0xCD        // new config for reg bits

    USICNT = 8; while (!(USIIFG & USICTL1));

    P1OUT |= CS_CTRL;

    Correct me if I get this wrong, but writing to USICNT clears the IFG, which means I don´t have to add: USICTL1 &= ~USIIFG;

  • @ Bernhard: I checked the USI16 Bit and it was set 1 until the prog reached the line USICNT = 24.....which means both of you were right, the bit is cleared by that command, sry ;)

  • Jens-Michael Gross said:

    Brnhard is right. Your writing of

        USICNT = 24;

    implicitely clears the USI16B bit.

    However, SPI is a synchronous protocol.

    It makes no difference at all if you send 3*8 bit or 1*16 bit and 1*8 bit. For each single bit, a new clock pulse is generated, and when the operation is complete, no more clock pulses are generated until new data is to be sent. And the clock pulses do not necessarily have to have the same frequency. So when you send 8 bit, and then reload the refgister and send the next 8 bit, the gap between is considered just a very slow clock pulse, not a break in the transmission.

    The synchronizing (telling the slave that a new transfer starts) is done using the separate CS (chip select) line, that you need to control manually through a standard I/O port pin.

    [/quote]

    I find that's very interesting when USI16B is set, any other USICNTx cannot be set. Can anyone explain this? or it's just my erroneous observation?

  • Marcus B��nisch said:
    @ Bernhard: I checked the USI16 Bit and it was set 1 until the prog reached the line USICNT = 24.....which means both of you were right, the bit is cleared by that command, sry ;)

    Marcus,

    I recently used the USI in 16-bit SPI mode on a 'G2231 to drive the 8x8 LED display on an Olimex "booster board" for the LauchPad. The interface for that array is a pair of 74xx595 shift registers, and I ran into problems with the USICTL register as you have.

    The USICTL register is a bit of an "odd duck" in that it consists of two parts: three high-order control bits and a five-bit count field (bit counts up to 31) which is decremented as the bits are clocked out. This means that you must store a non-zero value into the lower five bits before activity can begin, which you already know, but it also means that when you update the "count" portion of the register (the USICNTx field, bits 4-0) you must be extremely careful not to accidentally disturb the upper three bits.

    In my code, since I was only using the USI to perform SPI 16-bit writes, I could get away with turning on the USI16B bit in the USICTL register once, during initialization:

    USI_Init() {
      ...
      USICTL |= USI16B;

    and then simply update the USICNTx bits on each write using an OR operation:

    USI_Write() {
    ...
      USICTL |= 16; // ---01000 USI16B stays on.

    But, of course, direct assignment of a count won't work, for reasons already mentioned in thread:

      USICTL = 16; // 00001000 USI16B is turned off.

    Looking back, I think that a better way of coding would have been to (redundantly) set the bit with each write:

    USI_Write() {
    ...
      USICTL = USI16B|16; // 00101000 Re-set USI16B.

    The effect would be the same, but the code might be clearer. <grin!>

    Hope this helps.

    Frank McKenney

**Attention** This is a public forum