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.

Understanding SPI

Other Parts Discussed in Thread: MSP430F5438, MSP430F5529

Hi,

I've been looking at SPI implementations for the last two days, and again, I feel like this is too technical, plus with my limited knowledge about embedded, I just feel lost.

I've read a couple of posts here, and copy pasted some code, but I have no idea where to start.

I'm using the MSP430F5438 microprocessor on our prototype, and if I got it right from the datasheet, it has 4 SPIs?

My situation is such, I have two serial slave components I need to program on initialization, and read data from while the application is running, to be more specific, temperature and accelerometer.

So I'm wondering, according to this on page 57, it seems that the same SPI can be used for multiple devices, is my understanding correct?

I've also had trouble with understanding which registers control what from the datasheet, there is a long register list, and it seems that most of these have many functions, how can distinguish what I need from the list?

Thanks,

Adam.

  • Adam Zehavi said:

    I've been looking at SPI implementations for the last two days, and again, I feel like this is too technical, plus with my limited knowledge about embedded, I just feel lost.

    Do you understand the basic premise of SPI operations and how the physical interface is intended to operate?  I don't want to assume anything.

     

    Adam Zehavi said:

    I'm using the MSP430F5438 microprocessor on our prototype, and if I got it right from the datasheet, it has 4 SPIs?

    The MSP430F5438 has 4 instances of the USCI module, which each module has 2 parts (A and B).  As the datasheet indicates, each part of the USCI module can support SPI operations.  Therefore, technically the MSP430F5438 can support up to 8 unique SPI interfaces if each part of the USCI modules are configured for that mode of operation.

     

    Adam Zehavi said:

    My situation is such, I have two serial slave components I need to program on initialization, and read data from while the application is running, to be more specific, temperature and accelerometer.

    So I'm wondering, according to this on page 57, it seems that the same SPI can be used for multiple devices, is my understanding correct?

    Yes, that is true.  The document you reference is suggesting to use 2 I/O pins to act as chip selects, a unique signal for each slave device.  Your software then needs to comprehend which device you are interacting with by controlling the I/O directly.  This means the USCI module does not control the chip select I/O itself, but rather you higher level driver code running on the processor needs to control this.

    Using this method does save on the number of pins consumed for connecting to SPI slaves.  If you assume only 3 signals are used for a specific SPI slave (CLK, SOMI, SIMO) and the chip select is held active on the slave, to support 2 slave with 2 separate SPI interfaces, you would consume 6 signals (ie. 2 * (CLK, SOMI, SIMO)).
    If you use the chip select method, then 2 chip selects and the common CLK, SOMI, SIMO woudl be 5 signals.
    The trade off is some complexity with the software to manage this.

     

    Adam Zehavi said:

    I've also had trouble with understanding which registers control what from the datasheet, there is a long register list, and it seems that most of these have many functions, how can distinguish what I need from the list?

    You will need to consult the MSP430x5xx Family User's Guide for specifics about the various modules functionality and register definitions.  There are also code examples to help illustrate concepts that you could consult as well.

  • Thank you for your response...

    BrandonAzbell said:
    Do you understand the basic premise of SPI operations and how the physical interface is intended to operate?  I don't want to assume anything.

    Well, I'll go and assume that this is like a Java Input output stream, where data is been queued, and then a flush signals the other side it has content to read, from the proper port, or something similar.

    BrandonAzbell said:
    You will need to consult the MSP430x5xx Family User's Guide for specifics about the various modules functionality and register definitions.  There are also code examples to help illustrate concepts that you could consult as well.

    I'm using MSP430F5438, and the confusion I'm having reading the datasheet is the fact that each register has multiple functions, for example:

    P3.0/UCB0STE/UCA0CLK 33 35

    General-purpose digital I/O

    Slave transmit enable – USCI_B0 SPI mode

    Clock signal input – USCI_A0 SPI slave mode

    Clock signal output – USCI_A0 SPI master mode

    P3.1/UCB0SIMO/UCB0SDA 34 36

    General-purpose digital I/O

    Slave in, master out – USCI_B0 SPI mode

    I2C data – USCI_B0 I2C mode

    P3.2/UCB0SOMI/UCB0SCL 35 37

    General-purpose digital I/O

    Slave out, master in – USCI_B0 SPI mode

    I2C clock – USCI_B0 I2C mode

    P3.3/UCB0CLK/UCA0STE 36 38

    General-purpose digital I/O

    Clock signal input – USCI_B0 SPI slave mode

    Clock signal output – USCI_B0 SPI master mode

    Slave transmit enable – USCI_A0 SPI mode

    DVSS3 37 39 Digital ground supply

    This is the setup from the datasheet of the micro-controller.

    Why does each have multiple names?

    P3.0, and P3.3 confuse me, because of the similarity in their name though 'A' and 'B' are opposite...!?

    Why does each have a few descriptions which seem completely different (for the untrained eye)?

    What do I need to look for, when reading the datasheet of the HW component now connected to the microcontroller?

    Thanks in advance,

    Adam.

  • Adam Zehavi said:
    I'm using MSP430F5438, and the confusion I'm having reading the datasheet is the fact that each register has multiple functions

    The INPUT/OUTPUT SCHEMATICS section of the MSP430F5438 datasheet SLAS612 show how each device pin may be mapped between either software controlled I/O ports or via peripheral modules.

    In the case of P3.0 and P3.3 Table 44. Port P3 (P3.0 to P3.7) Pin Functions has some notes about UCA0CLK function takeing precedence over UCB0STE function.

  • Adam Zehavi said:

    I'm using MSP430F5438, and the confusion I'm having reading the datasheet is the fact that each register has multiple functions, for example:

    P3.0/UCB0STE/UCA0CLK 33 35

    General-purpose digital I/O

    Slave transmit enable – USCI_B0 SPI mode

    Clock signal input – USCI_A0 SPI slave mode

    Clock signal output – USCI_A0 SPI master mode

    P3.1/UCB0SIMO/UCB0SDA 34 36

    General-purpose digital I/O

    Slave in, master out – USCI_B0 SPI mode

    I2C data – USCI_B0 I2C mode

    P3.2/UCB0SOMI/UCB0SCL 35 37

    General-purpose digital I/O

    Slave out, master in – USCI_B0 SPI mode

    I2C clock – USCI_B0 I2C mode

    P3.3/UCB0CLK/UCA0STE 36 38

    General-purpose digital I/O

    Clock signal input – USCI_B0 SPI slave mode

    Clock signal output – USCI_B0 SPI master mode

    Slave transmit enable – USCI_A0 SPI mode

    DVSS3 37 39 Digital ground supply

    This is the setup from the datasheet of the micro-controller.

    Why does each have multiple names?

    For the pins you have listed above, each has multiple possible functions that can be multiplexed out.  As Chester mentioned either Digital I/O (eg. P3.0) or a peripheral functional signal (eg. UCB0STE or UCA0CLK).  Only one of these is available on the pin at any given time and the configuration is description in the Input/Output Schematics section of the datasheet.

     

    Adam Zehavi said:

    P3.0, and P3.3 confuse me, because of the similarity in their name though 'A' and 'B' are opposite...!?

    Recall my comment that each USCI module has 2 parts (or sub-units), the USCI_A and USCI_B sub-modules.  This is described in the MSP430x5xx Family User's Guide.  The A and the B denote which of the subunits is being referenced.

     

    Adam Zehavi said:

    Why does each have a few descriptions which seem completely different (for the untrained eye)?

    Again, each description is related to a particular function which can multiplexed on the pin.  Only 1 of the functions can be active at any given time.

     

    Adam Zehavi said:

    What do I need to look for, when reading the datasheet of the HW component now connected to the microcontroller?

    Don't know what you are asking here.  You should look at both the datasheet of the microcontroller to get an idea of what functionality is available on the specific device you are using and use the Family User's Guide for details about a module that is instantiated on the device.

     

  • Hi Adam Zehavi,

    Basic knowledge of SPI protocol (like what is the functionality of CS, MOSI , MISO , CLK ) and taking a look into the code samples from TI (you will get the library & examples when you install CCS) will be the starting point.

    When reading through the code, you can better understand how a pin is "configured" to work as an SPI pin for eg. Interfacing slaves like accelerometer, temperature sensor etc are posted throughout the forum. A little search would help there.

    ATB,

    -Venkat.

  • Adam Zehavi said:
    Well, I'll go and assume that this is like a Java Input output stream, where data is been queued

    Well, no. Forget about the high-level stuff operating systems offer.
    Microcontroller design usually requires very low-level thinking.

    An SPI interface is barely more than two shift registers and a shift clock generator and some control circuitry.

    After configuring the baudrate and the port pins, the SPI hardware takes a byte you write to its transmit buffer and shifts it out bit by bit together with a clock signal. At the same time, a second shift register is shifting in data from the opposite direction and when 8 bits have been received, the resulting byte is moved into the receive buffer register.
    However, this is just a one-byte buffer. You have to check whether it is empty. (dedicated interrupt flags will allow you to either read the state or let an interrupt function to be called when the state changes)
    However, you cannot simply put a bunch of bytes into a stream queue - unless you write this queue yourself.

    Besides this low-level handling (and the even lower-level initialization) you'll have to deal with the higher-level things such as (software-controlled) chip select signals to notify the slave that you want to send it data or receive from it.

    I don't recommend to start with writing an SPI slave. IT requires tight, timing-critical code and is the most demanding of all serial communications tasks.

    There are lots of threads about SPI in this forum. You should take a look at them.

    Adam Zehavi said:
    Why does each have multiple names?

    Each physical MSp pin can have different modes of operation. Almost always is the default mode plain I/O that can be programmed by software. However, most pins can be switched to secondary functions by selecting their 'module function' (with the PxSEL registers). Depending on which module is available as optional use of this pin, the functionality may be different (even different modules) based on whether the pin is set for input or output. Also, sometimes the module itself can define the actual usage of the pin by its own configuration.

    In case of P3.1, the pin can carry the Port 3 Bit 1 GPIO (P3.1) or USCI B0 module (UCB0) signal. In case of UCB0, this module can operate in I2C mode (then this pin is the serial data signal) or in SPI mode. In SPI mode, it is either slave output (if the mode is in SPI slave mode) or master input (if in SPI master mode). Since USCI B0 can only be in one mode at a time, only one of the different signals is routed to the pin at a time, depending on configuration.

    Adam Zehavi said:
    P3.0, and P3.3 confuse me, because of the similarity in their name though 'A' and 'B' are opposite...!?

    The USCI module has two sub-modules, A and B. Each USCI module has six different signal lines. However, both sub-modules can act as SPI. In 4-wire mode, one sub-module requires 4 signals, leaving only two port pins available for the other sub-module. This means that you cannot have one sub-module run in 4-wire SPI when the other one shall be SPI too (requiring at least 3 wires).
    So the functions have been distributed so that the 4th SPI wire, STE, which is only required for multi-master SPI or SPI slave (3-wire SPI is the normal usage in the very most cases, the usually required CS line is not counted here,as it is GPIO) is on a pin that is only needed for the other sub-modules SPI funciton. So 4-wire SPI can coexist with the (2-wire) UART or I2C operations of the other sub-module.

    Adam Zehavi said:
    What do I need to look for, when reading the datasheet of the HW component now connected to the microcontroller?

    Not the datasheet, the users guide. It contains the description of all modules that are in any one of the MSPs if a family. (though your MSP not necessarily has all of them)

  • First, thank you all for your responses, this is tone of info, and it took a while to process it.

    I've read everything, and tried to make sense of the example SPI master code supplied in a previous link:

    //******************************************************************************
    //   MSP430F54x Demo - USCI_A0, SPI 3-Wire Master Incremented Data
    //
    //   Description: SPI master talks to SPI slave using 3-wire mode. Incrementing
    //   data is sent by the master starting at 0x01. Received data is expected to
    //   be same as the previous transmission.  USCI RX ISR is used to handle
    //   communication with the CPU, normally in LPM0. If high, P1.0 indicates
    //   valid data reception.  Because all execution after LPM0 is in ISRs,
    //   initialization waits for DCO to stabilize against ACLK.
    //   ACLK = ~32.768kHz, MCLK = SMCLK = DCO ~ 1048kHz.  BRCLK = SMCLK/2
    //
    //   Use with SPI Slave Data Echo code example.  If slave is in debug mode, P1.1
    //   slave reset signal conflicts with slave's JTAG; to work around, use IAR's
    //   "Release JTAG on Go" on slave device.  If breakpoints are set in
    //   slave RX ISR, master must stopped also to avoid overrunning slave
    //   RXBUF.
    //
    //                   MSP430F5438
    //                 -----------------
    //             /|\|                 |
    //              | |                 |
    //              --|RST          P1.0|-> LED
    //                |                 |
    //                |             P3.4|-> Data Out (UCA0SIMO)
    //                |                 |
    //                |             P3.5|<- Data In (UCA0SOMI)
    //                |                 |
    //  Slave reset <-|P1.1         P3.0|-> Serial Clock Out (UCA0CLK)
    //
    //
    //   W. Goh
    //   Texas Instruments Inc.
    //   November 2008
    //   Built with CCE Version: 3.2.2 and IAR Embedded Workbench Version: 4.11B
    //******************************************************************************
    
    #include "msp430F5438.h"
    
    unsigned char MST_Data,SLV_Data;
    
    void main(void)
    {
      WDTCTL = WDTPW+WDTHOLD;                   // Stop watchdog timer
    
      P1OUT |= 0x02;                            // Set P1.0 for LED
                                                // Set P1.1 for slave reset
      P1DIR |= 0x03;                            // Set P1.0-2 to output direction
      P3SEL |= 0x31;                            // P3.5,4,0 option select
    
      UCA0CTL1 |= UCSWRST;                      // **Put state machine in reset**
      UCA0CTL0 |= UCMST+UCSYNC+UCCKPL+UCMSB;    // 3-pin, 8-bit SPI master
                                                // Clock polarity high, MSB
      UCA0CTL1 |= UCSSEL_2;                     // SMCLK
      UCA0BR0 = 0x02;                           // /2
      UCA0BR1 = 0;                              //
      UCA0MCTL = 0;                             // No modulation
      UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
      UCA0IE |= UCRXIE;                         // Enable USCI_A0 RX interrupt
    
      P1OUT &= ~0x02;                           // Now with SPI signals initialized,
      P1OUT |= 0x02;                            // reset slave
    
      __delay_cycles(100);                      // Wait for slave to initialize
    
      MST_Data = 0x01;                          // Initialize data values
      SLV_Data = 0x00;                          //
    
      while (!(UCA0IFG&UCTXIFG));               // USCI_A0 TX buffer ready?
      UCA0TXBUF = MST_Data;                     // Transmit first character
    
      __bis_SR_register(LPM0_bits + GIE);       // CPU off, enable interrupts
      while(1);
    }
    
    #pragma vector=USCI_A0_VECTOR
    __interrupt void USCI_A0_ISR(void)
    {
      switch(__even_in_range(UCA0IV,4))
      {
        case 0: break;                          // Vector 0 - no interrupt
        case 2:                                 // Vector 2 - RXIFG
          while (!(UCA0IFG&UCTXIFG));           // USCI_A0 TX buffer ready?
    
          if (UCA0RXBUF==SLV_Data)              // Test for correct character RX'd
            P1OUT |= 0x01;                      // If correct, light LED
          else
            P1OUT &= ~0x01;                     // If incorrect, clear LED
    
          MST_Data++;                           // Increment data
          SLV_Data++;
          UCA0TXBUF = MST_Data;                 // Send next value
    
          __delay_cycles(10);                   // Add time between transmissions to
                                                // make sure slave can process information
          break;
        case 4: break;                          // Vector 4 - TXIFG
        default: break;
      }
    }
    (WOW took me forever to find a good code converter - I'm fixing it... it didn't look like this on the editor!!!)
    
    
    So if I understand this example correctly, then I was off by a mile with the impression I had of SPI when I started.
    • Do I only need to write the byte to the proper TX, and the system would execute the bit by bit transaction?
    • And in order to write a 16 bit data to the SPI, I would have to add a:
      while (!(UCA0IFG&UCTXIFG)); // USCI_A0 TX buffer ready?
      CA0TXBUF = nextValue; // Send next value
      __delay_cycles(40);
      After the  __delay_cycles(40); in the original code, or something like that?
    • If I need to write some parameters to the component and program it, then I need an SPI Master, but later I need to get data back, so do I need also an SPI slave?
    I'm making some assumption... again...
    Thanks in advance,
    Adam.
  • There think there might be a bug in the forum posting editor... if I've copied the text, and changed the font to (in my case) courier new, it gets messed up, and if I don't set any font, then I guess you can see the result...

  • Adam Zehavi said:
    Do I only need to write the byte to the proper TX, and the system would execute the bit by bit transaction?

    Yes. The write action starts the clock signal generation and the transfer (in both directions).

    However, this code uses soem implicit mechanism: When you sent a byte, you already received a byte, which causes an interrupt. (case 2). So an initial write to TXBUF is necessary.
    However, the 'usual' way would be enabling the interupt for TX (case 4) and when it comes wither write to TXBUF inside the ISR (since you got the interrupt, you know that TXBUF is ready for the next byte, no need to do busy-waiting inside an ISR) or (if no more bytes to be sent) clear the TXIE bit so no more interrupts come. The default case in the ISR is superfluous too: since the switch was wrtten with '__even_in_range(xxx,4)' there will be case 0,2,4 only, by definition. No need for a default.

    Adam Zehavi said:
    And in order to write a 16 bit data to the SPI, I would have to add a:...

    Almost, but no. A 16 bit value is just two 8 bit values. So depending on endianess, just split the 16 bit int two as if they were a sequence of 8 bit values. The slave will have them to be joined together again.
    However, a while loop for a hardware event is a very bad idea inside an ISR. Th eidea of an ISR is that it automatically gets called on an event, does the necessary stuff to handle it as fast as possible and then returns control back to the main code.

    If you do busy-waiting of some sort inside an ISR, you could as well move all the ISR code into main() and execute it sequentially.

    Adam Zehavi said:
    If I need to write some parameters to the component and program it, then I need an SPI Master, but later I need to get data back, so do I need also an SPI slave?

    Well, it depends. It depends on who is controllign the timing.

    The master is the peer who decides when and how fast to transfer data. The transfer itself is bi-directional. If you e.g. want to write to an external memory, the MSP is the master and the memory is the slave.

    To write, the master sends a write command, the address to write to, the number of bytes to write, and the data. At the same time, the memory is sending dummy values back. After the last data byte has been written, the master may continue sending dummy bytes while the slave responds with a 'busy' response, until the slave sends a 'done' or 'failure' byte.
    When reading data, the MSP is still the master. It sends a read command, an address and (maybe, as this is superfluous) how many bytes to read. Then it continues sending dummy bytes and the slave will return one data byte for each. Once the last byte has been received, the master will simply stop sending bytes and deselect the slave.

    In both cases, the MSP has controlled when to do a transfer and at which speed (by controlling the SPi clock signal). However, the slave in this example did have a way to tell the master that it is not done yet (writing to flash memory takes some time).

    Don't forget that the answer to data sent can arrive soonest after the next byte sent (possibily a dummy byte). This, and the double-buffering of the USCI (one byte currently being sent in the output shift register, and one byte waiting in TXBUF), can make complex protocols a challenge.

  • Jens-Michael, thank you for your help, and your time.

    Things are much clearer now regarding the SPI communication protocol implementation, but some things are still a miss, so I would try to be more accurate.

    As for transferring 8*x bit, if I understand correct, I would have to know the x byte final values I want to send, and write them to the TX, one by one, on the SPI mater ISR iterations, and since the interrupt is defined to be invoked on RX completion, I can safely assume that the buffer is ready for the next TX byte, is this correct?

    Jens-Michael Gross said:
    the master may continue sending dummy bytes while the slave responds with a 'busy' response, until the slave sends a 'done' or 'failure' byte

    I guessed that while configuring an SPI component, I would require some sort of a feedback from it, and sending dummy bytes, until an ending response is received seems like a nice technic.

    Jens-Michael Gross said:
    When reading data, the MSP is still the slave.

    I'm assuming you mean "MSP is still the master"?

    Jens-Michael Gross said:
    If I need to write some parameters to the component and program it, then I need an SPI Master, but later I need to get data back, so do I need also an SPI slave?

    Well, it depends. It depends on who is controllign the timing.[/quote]

    Due to my previous question in this post, I think I need to rephrase, I need to configure an Accelerometer, and later while the application is running (once a remote BT peer connects) I want the Accelerometer to start output its values and aggregate these to the application, and later send the acceleration data via Bluetooth to a remote BT peer.

    So upon startup I configure the Accelerometer, supply parameters, and set the component activation to "pause".

    Later when the application is running, and a BT peer is connected to the MSP, I set the component activation to "resume", how can I then define a sampling rate to  read the acceleration values? Should I setup a timer to start reading the acceleration values from the component, at whatever rate allowed/supported by the component?

    Thanks,

    Adam.

  • I've failed to understand the meaning of the following lines:

    P1OUT |= 0x02; // Set P1.1 for slave reset

    .... USCI (SPI)  configuration ....

    P1OUT &= ~0x02; // Now with SPI signals initialized,
    P1OUT |= 0x02; // reset slave

    What is the reason for toggling the bit?

    Thanks in advance,

    Adam.

  • Adam Zehavi said:
    I've failed to understand the meaning of the following lines:
    P1OUT |= 0x02; // Set P1.1 for slave reset


    You're not the first one asking :)
    This line seems to be connected to the slaves RESET pin in this specific demo setup. It is poorly documented for an example code. Also, the following code makes some implicit assumptions about slave startup time. Not a good habit for demo code too, as any change in the code may break the timing.

    Normally, a master won't reset the slave. it will only select it and communicate. However, some slaves might need a reset. Not because of the SPI, but because of their main function. E.g. if it is a display controller and the communication protocol does not cover a (software) reset command.

    Adam Zehavi said:
    I'm assuming you mean "MSP is still the master"?

    Yes. I already corrected this typo.

    Adam Zehavi said:
    As for transferring 8*x bit, if I understand correct, I would have to know the x byte final values I want to send, and write them to the TX, one by one, on the SPI mater ISR iterations, and since the interrupt is defined to be invoked on RX completion, I can safely assume that the buffer is ready for the next TX byte, is this correct?

    That's how the code works. (in this case, the values are generated by incrementing their source after each send). However, this approach has the drawback that you only write the next byte after the first has been sent, the answer has been received (1/2 SPi clock cycle later than sendign the last bit) and the ISR has been called. During this time, the SPI is idle. Not a big issue if the SPI speed is slow compared to MCLK. But when you want to send with maximum speed, you're wasting much bandwidth here. And for SPICLK = MCLK, the use of an ISR is a terrible idea. Here hand-crafted inline code or even the use of DMA is required to get maximum throughput. On SPICLK == MCLK, you only have 8 MCLK cycles per byte. Much less than the required cycles jsut for entering and exiting an ISR (with no code in it at all).

    Well, getting that tight to the max is the 'high art' of embedded programming :)

    Adam Zehavi said:
    Should I setup a timer to start reading the acceleration values from the component, at whatever rate allowed/supported by the component?

    That's the usual approach. Start a tiemr which does a data read. The timer interrupt frequency is the component sampling rate. Once the data has been read, flag that there i s new data available and let it send.
    I tis possible that the component provides a 'ready' signal that can be used to trigger a port pin interrupt on the master. Then you won't need a timer. You just wait for the por tpininterrupt ISR being called, and hten read teh values. Or you jsu tdo a busy waiting for the ready signal in main loop. No ISRs neededn then at all (but you can't go into low power mode then while waiting).

  • Thank you.

    I can now say, that together with your expert help and the demo app, I'm able to wrap my mine around the entire concept. My next goal is to write a mechanizem that would accomplish this, and communicate to multiple components, to start with, each component with different USCI.

    Jens-Michael Gross said:
    This line seems to be connected to the slaves RESET pin in this specific demo setup. It is poorly documented for an example code. Also, the following code makes some implicit assumptions about slave startup time. Not a good habit for demo code too, as any change in the code may break the timing.

    How could a code change break the timing?

    Assuming that the code was meant as a demo application for a strip MSP, checking the MSP P1.1 states:

    • General-purpose digital I/O with port interrupt
    • TA0 CCR0 capture: CCI0A input, compare: Out0 output
    • BSL transmit output

    Why was this port chosen for reset?

    Adam.

    FYI, the link at the bottom is broken...

  • Adam Zehavi said:
    How could a code change break the timing?

    Teh master code assumes that after releasing the slave, the slave will be ready to respond when the master is starts the communication.

    However, if you add some functionality to the slave, or reorder the master code, without taking this relation into account, the amster wills tart querying the slave when the slave isn't ready to answer. Since there is no error handling (or even error-detection) in the demo code, this will make th ewhole applicaiton to no longer work. And you don't know why, as this is not really documented.

    Adam Zehavi said:
    Why was this port chosen for reset?

    It is used as plain GPIO port pin. So it was maybe chosen for layout considerations. I don't see any particular reason. Maybe in an existing PCB, this pin was routed to a breakout pin (because it is the BSL output in BSL mode) and wiring it to the slave was easier than with e.g. P1.0
    The application contains no info abput it, so it will remain a mystery unless the author give sus a comment :)

  • I've completed a simple setup for the accelerometer SPI.

    I've taken the demo application and integrated to it some infrastructure, carefully changing the code while verifying the original application behavior remains!

    /** * Modules Configuration. */
    USCI_Configuration accelerometerUSCI_Configuration = { UCSWRST, UCSYNC + UCMST + UCMSB + UCCKPL + UCCKPH, UCSSEL__SMCLK, 0x02, 0, 0} ;
    USCI_Module usciA3_Module = { &UCA3TXBUF, &UCA3RXBUF, &UCA3CTL1, &UCA3CTL0, &UCA3BR0, &UCA3BR1, &UCA3MCTL };
    Interrupt usciA3_Interrupt = { &UCA3IE, &UCA3IFG, &UCA3IV };
    
    /** * Acceleroemter definition. */
    SPI_Component spiAccelerometer = {
    		{ &port10, BIT0, PORT_OUT }, { &port10, BIT3, PORT_OUT }, { &port10, BIT4, PORT_OUT },
    		{ &port10, BIT5, PORT_IN } };
    
    Accelerometer accelerometer = { &spiAccelerometer, &usciA3_Module, &accelerometerUSCI_Configuration, {
    		&port1, BIT5, PORT_IN }, { &port1, BIT6, PORT_IN } };
    
    UCHAR packet[6];
    int index = 0;
    
    volatile UCHAR received[100];
    int receivedIndex = 0;
    
    void sendNextPacket(void) {
    //	*(usciA3_Module.outputBuffer) = MST_Data; // Send next value
    	if (index < 6) {
    		*(usciA3_Module.outputBuffer) = packet[index++]; // Send next value
    	}
    }
    
    void main(void) {
    	packet[0] = XL346_DATA_FORMAT;
    	packet[0] |= 0x40;
    	packet[1] = XL346_RANGE_8G;
    	packet[2] = XL346_POWER_CTL;
    	packet[2] |= 0x40;
    	packet[3] = XL346_MEASURE;
    	packet[4] = XL346_INT_ENABLE;
    	packet[4] |= 0x40;
    	packet[5] = XL346_DATAREADY;
    
    	WDTCTL = WDTPW + WDTHOLD;
    	setupRegister(redIndicationLed);
    	setupRegister(greenIndicationLed);
    	writeValueToRegister(greenIndicationLed, PORT_OFF);
    
    	initializeAccelerometer(accelerometer);
    
    	*(usciA3_Interrupt.controller) |= usciInterruptControls.receiver; // Enable USCI_A0 RX interrupt
    
    	while (!(*(usciA3_Interrupt.flags) & usciInterruptFlags.transmiter))
    		;
    	sendNextPacket();
    	__bis_SR_register(LPM0_bits + GIE);
    	while (1)
    		;
    }
    
    #pragma vector=TIMER0_A1_VECTOR
    __interrupt void AccelerometerISR(void) {
    	if (TA0IV & TA0CCR4 != TA0CCR4) {
    		return;
    	}
    
    }
    
    #pragma vector=USCI_A3_VECTOR
    __interrupt void USCI_A3_ISR(void) {
    	switch (__even_in_range(*(usciA3_Interrupt.vector), 4)) {
    	case 0:
    		break; // Vector 0 - no interrupt
    	case 2: // Vector 2 - RXIFG
    		received[receivedIndex++] = *(usciA3_Module.inputBuffer);
    		sendNextPacket();
    		break;
    	case 4:
    		break; // Vector 4 - TXIFG
    	}
    }

    I'm pretty positive I've configured the component, and its SPI registers properly, and also the RXIFG event arrives, but the data received is always empty, and the interrupt that is supposed to be invoked by the component does not occur, am I sending the data wrong, and therefore I get no feedback?

    Thanks,

    Adam.

  • Adam Zehavi said:
    #pragma vector=TIMER0_A1_VECTOR __interrupt void AccelerometerISR(void) { if (TA0IV & TA0CCR4 != TA0CCR4) { return; } }

    This doesn't make much sense.
    TA0IV is a register that returns the number of the highest pending TA= interrupt. The value is 0,2,4,6...
    Doign an AND with the value in TA0CCR4 register makes no sense, and the result won't be ever equal to TA0CCR4. Hwoever, this ISR make snoting at all, whether the (impossible) condition is met ot not. And the tiemr is not actrivated at all, at least in the code you posted.

    Your variable receivedIndex should be declared volatile. It is changed inside the ISR and (perhaps) indended to be later used in your main code (currently, received[] and receivedIndex seem to be write-only :)

    I don't know what framework you use, and known none of them good enough to know what your initializations do and whether they are correct.
    However, what do you mean wiht 'the data received is always empty'? Is usciA3_Module.inputBuffer always 0x00 or 0xff?
    YOu say teh RX event arrives, but the interrupt does not occur? What do you mean by that? The RX event usually is the interrupt. Either you check for the RXIFG bit manually (with RXIE clear) or lett the ISR be called (with RXIE set).

    Adam Zehavi said:
    packet[0] = XL346_DATA_FORMAT; packet[0] |= 0x40;

    Each second line overwrites the previous one. Or is this intentional (then you should comment the first line of each pair, to make obvious that it is intentional).

    However, for each byte youe send, you'll receive a ybte. Whether it was intentionally sent by the slave or not. YOu will receive a byte even if yo udo not connect the pins at all. The SPI hardware cannot possible know whether incoming data on the SOMI (or MISO) line is valid or not. It just samples the current state of the line at the clock edges.
    Your slave can of course only answer to a command once it has received the command. But when you're done with sending the command, you stop sending comletely. So the slave cannot send its answer as no clock is generated.
    At the moment you put packet[5] into TXBUF, paket[4] has just started to be sent.
    You must wait until both are really send (e.g. by checking the UCBUSY bit).
    Then you can send one (or more) dummy byte(s) that allows the slave to send its answer. (you may simply send one mroe byte, but be sure to pick teh correct answer byte then - your sending process is always 1 byte and 7 bits ahead of any incoming answer.)

  • Sorry for posting that much of code without comments, I have assumed that the SPI issue would be apparent... :(

    Jens-Michael Gross said:
    This doesn't make much sense.
    TA0IV is a register that returns the number of the highest pending TA= interrupt. The value is 0,2,4,6...
    Doign an AND with the value in TA0CCR4 register makes no sense, and the result won't be ever equal to TA0CCR4. Hwoever, this ISR make snoting at all, whether the (impossible) condition is met ot not. And the tiemr is not actrivated at all, at least in the code you posted.

    I've copied this text, but the condition does not matter, I've only wanted to catch the interrupt with the debugger to see that it actually been invoked by the Accelerometer.

    Jens-Michael Gross said:
    Your variable receivedIndex should be declared volatile. It is changed inside the ISR and (perhaps) indended to be later used in your main code (currently, received[] and receivedIndex seem to be write-only :)

    I've changed that in the code already to volatile, and would update it later.

    Jens-Michael Gross said:
    I don't know what framework you use, and known none of them good enough to know what your initializations do and whether they are correct.
    However, what do you mean wiht 'the data received is always empty'? Is usciA3_Module.inputBuffer always 0x00 or 0xff?
    YOu say teh RX event arrives, but the interrupt does not occur? What do you mean by that? The RX event usually is the interrupt. Either you check for the RXIFG bit manually (with RXIE clear) or lett the ISR be called (with RXIE set).

    I don't use any framework, I've just refactored the original code in the demo app into a structured types.
    The data I see in the received[] if always 0x00.
    The RX events arrives to the under interrupt, but there are no interrupts in the at the timer, I thought that the component needs to invoke that, since one of its pins, are connected to the TA0CCR4 pin. (Perhaps I'm naive)


    Jens-Michael Gross said:
    packet[0] = XL346_DATA_FORMAT; packet[0] |= 0x40;

    Each second line overwrites the previous one. Or is this intentional (then you should comment the first line of each pair, to make obvious that it is intentional).[/quote]

    The macros defined for all the i%2==0 are 6bit long, which leaves the last two empty, where the |=40 is meant to change the 7th bit to 1, I have asked specifically here.
    I will add comments from now on!

    Jens-Michael Gross said:
    Your slave can of course only answer to a command once it has received the command. But when you're done with sending the command, you stop sending comletely. So the slave cannot send its answer as no clock is generated.
    At the moment you put packet[5] into TXBUF, paket[4] has just started to be sent.
    You must wait until both are really send (e.g. by checking the UCBUSY bit).
    Then you can send one (or more) dummy byte(s) that allows the slave to send its answer. (you may simply send one mroe byte, but be sure to pick teh correct answer byte then - your sending process is always 1 byte and 7 bits ahead of any incoming answer.)

     

    Ahhhaaa, I've missed that one... will give it a try and post back later!

    Adam.

  • Adam Zehavi said:
    I've only wanted to catch the interrupt with the debugger to see that it actually been invoked by the Accelerometer.

    Since the pragma denotes this ISR as the timer A0 interrupt function, it will be called on a tiemr A0 interrupt. But in your code you nowhere configure the tiemr to cause any interrupts.

    Adam Zehavi said:
    I've just refactored the original code in the demo app into a structured types.

    Okay, but then the type definitions aren't posted, which leaves all  eaders to guessing what you initialize how. There might be a simple typo/twist in the structure sequence and nobody will ever notice.
    Abstraction is a good thing to understand working code, but a very bad thing to debug non-working code. :)

    Adam Zehavi said:
    |=40 is meant to change the 7th bit to 1

    Well, my eyes aren't the best anymore. I simply didn't see the '|' :(
    However, directly adding the or's value to the previous line results in smaller and tighter code, as the compile rthen generates only one access to the register instead of two.

  • Jens-Michael Gross said:
    Since the pragma denotes this ISR as the timer A0 interrupt function, it will be called on a tiemr A0 interrupt. But in your code you nowhere configure the tiemr to cause any interrupts

    Added a timer initialization.

    Jens-Michael Gross said:
    However, directly adding the or's value to the previous line results in smaller and tighter code, as the compile rthen generates only one access to the register instead of two.

    Yes I'm aware of that, but I wanted to be able to remove it with the Ctrl+/ short key, in case I misunderstood the Multi-Byte feature... Which I guess I have... misunderstood it...

    I've attached the refactored master demo project.

    I assume posting the typedefs and functions would be long and less readable...

    Thanks again for the support :)

    Adam.

    6507.SPI Master Demo.rar

  • Adam Zehavi said:
    Added a timer initialization.

    Now you should get an interrupt each time the tiemr counts to CCR0 abd rolsl over to 0. But since you don't program TACCR0, it is 0 and the timer constantly rolls over on every timer tick. Generating an endless stream of interrupts as soon as you set GIE at the end of your main code. And your USCI_A3_ISR is probably never called due to its lower interrupt priority.

    Your USCI_A3_ISR does not have a break condition for sending/receiving. So once it gets called at all, it will produce an endless stream of outgoing bytes and also endlessly read the return values until your ram is full, teh stack has been overwritten and the MSP crashes on ISR exit.

  • Jens-Michael Gross said:
    Now you should get an interrupt each time the tiemr counts to CCR0 abd rolsl over to 0. But since you don't program TACCR0, it is 0 and the timer constantly rolls over on every timer tick. Generating an endless stream of interrupts as soon as you set GIE at the end of your main code. And your USCI_A3_ISR is probably never called due to its lower interrupt priority.

    Actually, the TA0CCR4 register is connected to the accelerometer, if I understood the component specification, then the component should invoke the interrupt on that pin.

    Jens-Michael Gross said:
    Your USCI_A3_ISR does not have a break condition for sending/receiving. So once it gets called at all, it will produce an endless stream of outgoing bytes and also endlessly read the return values until your ram is full, teh stack has been overwritten and the MSP crashes on ISR exit.

    As I've said, I've been really really careful while refactoring the demo code, so the USCI_A3_ISR does work.

    How ever I've wanted to change an approach, I've been told to try and read a value from the component in order to check whether the component is connected correctly, so in order to eliminate one uncertainty, I'm trying to achieve that, and as I hate uncertainties, I want to eliminate the other. After looking at some SPI example if I got it correctly (and lately it feels like I have the tendency not to...), I can also perform the SPI without an interrupt, so I'v sketched this up:

    void main(void) {
    
    	packet[0] = 0xC0; // Read bit high + MB bit high + Address = 0x00
    
    	WDTCTL = WDTPW + WDTHOLD;
    
    	setupRegister(redIndicationLed);
    	setupRegister(greenIndicationLed);
    	writeValueToRegister(greenIndicationLed, REGISTER_LOW);
    	initializeAccelerometer(accelerometer);
    
    	while (!(*(usciA3_Interrupt.flags) & usciInterruptFlags.transmiter))
    		;
    	writeValueToRegister(spiAccelerometer.slaveTransmitEnable, REGISTER_HIGH); // STE HIGH
    
    	*(usciA3_Module.outputBuffer) = packet[0]; // Send read request
    	__delay_cycles(100); // delay ??
    	received[receivedIndex++] = *(usciA3_Module.inputBuffer); // Read response byte
    
    	writeValueToRegister(spiAccelerometer.slaveTransmitEnable, REGISTER_LOW); // STE LOW
    
    	*(usciA3_Module.outputBuffer) = 0xFF; // Send dummy byte
    	__delay_cycles(100); // delay ??
    	received[receivedIndex++] = *(usciA3_Module.inputBuffer); // Read response byte
    
    	*(usciA3_Module.outputBuffer) = 0xFF; // Send dummy byte
    	__delay_cycles(100); // delay ??
    	received[receivedIndex++] = *(usciA3_Module.inputBuffer); // Read response byte
    
    	while (1)
    		;
    }

    The (previous code was the old one... and now with comments :) ) rest of the code is the same as in the ZIP file.

    This seems to get the same result as the interrupt implementation... I can see the registers values (in the USCI_A3 SPI Mode view in IAR) change upon reading and writing.

    Also as before the UCA3RXBUF value remains 0x00.

    Is this valid?

  • I'm rethinking the configuration values for the baudrates and the modulation of the USCI, I've used the default ones from the demo application, would they fit using on a real component? if I need to configure them differently what should I take under consideration while setting them?

    Thanks,
    Adam.

  • Adam Zehavi said:
    I'm rethinking the configuration values for the baudrates and the modulation of the USCI, I've used the default ones from the demo application, would they fit using on a real component?

    Unless you exceed the maximum speed of the slave, or go below a timeout threshold, the baudrate is rather unimportant (at least for the communication, but maybe not for the applicaiton purpose).
    The SPI master provides the clock for the transfer. The baudrate may even change within a byte transfer. No problem. SPI is synchronized ot the clock provided by the master.

    Adam Zehavi said:
    Actually, the TA0CCR4 register is connected to the accelerometer, if I understood the component specification, then the component should invoke the interrupt on that pin.

    Where? I don't see you setting up TACCR4 for capture mode or setting its CIE bit. Maybe I missed it in the jungle of abstraction layers you put around the components, but from a quick glance, TA0CCR4 is never configured to do anything.

    Adam Zehavi said:
    I've been really really careful while refactoring the demo code, so the USCI_A3_ISR does work.

    Yes, it works, but it seems to never stop, continuing to send and receive eternally, writing the received bytes into a buffer that will soon overflow. If you put  abreakpoint there, you won't notice (and probably manually stop the transfer once you got your few bytes sent and received).

    Adam Zehavi said:
    I can see the registers values (in the USCI_A3 SPI Mode view in IAR) change upon reading and writing.
    Also as before the UCA3RXBUF value remains 0x00.


    It seems you forgot a very important thing throughout your project: port pins used by a hardware module needs to be configured for module usage by setting the proper PxSEL bits. Teh 'setupRegister) funciton, however, only sets the direction, it doe snot switch the pin usage form GPIO to module usage.
    Unless you do so, the pins remain in GPIO mode and the module is sewered form the outside. Even if you see the register values change, it has no effect on the outside world.
    As I said, it is very difficult to figure out what your code does or not, due to the multi-layer abstraction (which also seems to add to the code size and execution time).

    P.s.: in your new code, instead usign a fixed delay of 100 MCLK cycles (which may or may not be enough, dependign on the SPI clock speed), you should wait for teh UCRXIFG bit, which indicates that a byte has been received., This bit is automatically cleared when you read the received byte from UCRXBUF.

    P.p.s.: the STE signal is only used for controllign the USCI in multi-master or slave mode. If the MSP is master, STE is not necessary at all. YOu can use this pin, as you do now, as normal GPIO pin for selecting the slave, but you shouldn't call it STE then. And this pin shouldn't be switched to module use. (it's acutally the only pin that works as intended right now)

  • Jens-Michael Gross said:
    It seems you forgot a very important thing throughout your project: port pins used by a hardware module needs to be configured for module usage by setting the proper PxSEL bits. Teh 'setupRegister) funciton, however, only sets the direction, it doe snot switch the pin usage form GPIO to module usage.
    Unless you do so, the pins remain in GPIO mode and the module is sewered form the outside. Even if you see the register values change, it has no effect on the outside world.
    As I said, it is very difficult to figure out what your code does or not, due to the multi-layer abstraction (which also seems to add to the code size and execution time).

    This one hit the Jackpot... I'm dumb as a rock thinking that things would just work, I have to accept the fact that in this world of microprocessor development, I have to actually configure everything to the last detail!!!

    And as for been very very careful I've deleted the following line from the original example:

    //  P3SEL |= 0x31;                            // P3.5,4,0 option select 

    But the demo application still worked, thus I've missed it!!  :(

    Jens-Michael Gross said:
    Where? I don't see you setting up TACCR4 for capture mode or setting its CIE bit. Maybe I missed it in the jungle of abstraction layers you put around the components, but from a quick glance, TA0CCR4 is never configured to do anything.

    Yes, that as well... was not set... although I didn't expect it to work now, since I understood I've miss-configured the SPI... 

    The moment I've configured the selection pins correctly, all the pieces fell in place, and the component behaves as expected.

    Thanks for all your help.

    Adam.

  • I'm not sure what I'm experiencing now...

    Well, after long while of debugging I've got to the conclusion that the bits are shifted:

    1 1 1 1 0 0 1 1 0 1 1 1 0 0 1 1 0 1 1 1 0 0 1 1 0 1 1 1 1 1 1 1 1
    X DEIVD 1 1 1 0 0 1 1 0 BW_RATE 0 0 0 0 1 0 1 0
    1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 0 1 1 1 0 0 1 1 0 1 0 0 0 0 0 1 1
    X DEIVD 1 1 1 0 0 1 1 0 INT_SOURCE 0 0 0 0 0 0 1 0

    1 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 0 0 1 0 0 1 0 -
    INT_SOURCE 0 0 0 0 0 0 1 0 ORIENT_CONF 0 0 1 0 0 1 0 1
    1 0 0 0 0 0 1 1 0 0 1 0 0 1 0 1 0 0 1 0 0 1 0 1 1 1 1 1 1 1 1 -
    ORIENT_CONF 0 0 1 0 0 1 0 1 BW_RATE 0 0 0 0 1 0 1 0

    (The under table continues the upper one)

    The first and third row are the output from the RX, aggregated in one sequence, while the second and fourth row, are the expected data...

    The values market in red are the values that do not match the reset values in the data sheet page 22, the ones in green are values that do match, but only if I shift the stream 1 bit to the left...

    Does this make any sense?

  • The component  data sheet specify that:

    Master ADXL346 operates as slave
    SPI Mode Clock polarity (CPOL) = 1
    Clock phase (CPHA) = 1
    Bit Sequence MSB first mode

    but once I've removed the CPHA/CKPH I receive the data just fine!

    Thanks again.

  • Adam Zehavi said:
    , I have to accept the fact that in this world of microprocessor development, I have to actually configure everything to the last detail!!!

    Usually, you have external components (a chipset) where each pin has one function. On microcontrollers, the requirements of small size and the high integration level require to have different funcitonalities availabel on the same pin and it's up to you to select the one you want. On some MSPs, you can even map soem functions to pins of your choice (while there is a default configuration).
    Since the chip doesn't know which configuration your external hardware requires, it goes into standard configuration on power-on, whcih is GPIO high-impedance input for all pins except those with a single dedicated function.
    An exception are the pinsfor a low-frequency crystal in 2x family which are on some MSPs not dedicated but also mixed with GPIO funcitonality (a tribute to the low pin count). In these cases, the crystal funciton is preselected (to speed up crystal startup) and you'll have to deselect it when you want to use normal I/O on these two pins.

    Adam Zehavi said:
    TA0CCR4 is never configured to do anything.

    Yes, that as well... was not set... although I didn't expect it to work now, since I understood I've miss-configured the SPI... [/quote]
    the timer interrupt should be independent of the SPI, except if you first have to configure the slave to pull the trigger.

    Adam Zehavi said:
    after long while of debugging I've got to the conclusion that the bits are shifted:


    This is a typical problem when looking too close at the SPI slave datasheet. :)
    For some (yet unknown) reason, TI decided that their definition of clock polarity is the opposite of the definition by Motorola.
    If polarity or phase do not match, the bits are received (or sent) at the wrong clock edge and may appear shifted, either for the slave or the master.
    It becomes obvious when you look at the timing diagrams in thr MSP users guide and the slave datasheet. They have to match no matter what the 'naming' of phase or polarity is.
    You already figured a working combination. if you encounter problems, try another one. There are only four and one will work perfectly while one or two others might work, but rather coincidentally and with flaws (timing, racing conditions) and one won't work at all.

  • Thanks for all your help Jens-Michael, I'm finally able to communicate with the accelerometer, and write and read data from its registers.

    Jens-Michael Gross said:
    the timer interrupt should be independent of the SPI, except if you first have to configure the slave to pull the trigger.

    Actually, if I understood the component datasheet, the component is the one that triggers the interrupt, it is configured to P1.5, one of the AppRegisters of the Accelerometer struct. I've went through all the msp430x54xA_ta3_XX.c examples in the code examples zip, but I did not see a matching example(or did I miss it), is there one? 

    Jens-Michael Gross said:
    There are only four and one will work perfectly while one or two others might work, but rather coincidentally and with flaws (timing, racing conditions) and one won't work at all.

    Do you mean that in some combination, I might experience these "flaws" in corrupted data sometime into the running of the application, or these would be obvious from the beginning and force me to try a new combination?

    Thanks...

  • Adam Zehavi said:
    the component is the one that triggers the interrupt

    Right. What I meant that sometimes the component only outputs this signal (if there is such a signal at all, msot SPI slaves won't have one) after it has been instructed to do so.
    Some, of course, start outputting their interrupt signal right after power-on.

    Adam Zehavi said:
    Do you mean that in some combination, I might experience these "flaws" in corrupted data sometime into the running of the application, or these would be obvious from the beginning and force me to try a new combination?

    It depends on timing. Since SPi data is captured on a clock signal edge, configuring hte wrong edge may or may not work (or work instable), depending how fast the clock is, how long it takes to 'notice' the clock edge, how long the other side keeps the data valid after this edge etc.

    To be on the safe side, see in the slave datasheet, which operation (SOMI bit output, SIMO bit input) is done at which edge of the clock signal and pick the corresponding mode on the master side.

  • Jens-Michael Gross said:
    Right. What I meant that sometimes the component only outputs this signal (if there is such a signal at all, msot SPI slaves won't have one) after it has been instructed to do so.
    Some, of course, start outputting their interrupt signal right after power-on.

    According to the data sheet and Analog support I'm configuring the component properly, thus it should invoke the interrupt, but it does not work. 

    I'm failing to see the configuration of the Timer so interrupts could be intercepted... could you point me in the right direction?

  • Adam Zehavi said:
    I've went through all the msp430x54xA_ta3_XX.c examples in the code examples zip, but I did not see a matching example(or did I miss it), is there one? 

    Well, triggering a timer capture interrupt is not part of SPI programming. So you should look into the timer examples (capture mode).

    I see you setting P1.5 as part of the accelerometer structure. But do you configure the timer at all?

    The following three lines are needed:

    P1DIR &= ~BIT5; // this one is probably set by the accelerometer initialization
    P1SEL |= BIT5; // this switches P1.5 form GPIO to TimerA0.CCR4 input
    TA0CCR4 = CCIE|CAP|CM_x; // this puts the timer CCR4 module into capture mode and enables the interrupt. 'x' is 1 to 3, depending on the edge you need to capture. Falling edge is 2, rising edge is 1 and both edges is 3.

    You could as well have used a port interrupt by setting P1IE|=BIT5;P1ES|=BIT5; (or &=~BIT5, depending on edge) and use the PORT1_VECTOR instead of the timer vector.

    Using a capture interrupt rather than a port pin interrupt only makes sense if you either need to trigger on both edges (the port pin can only trigger on one and needs to be reconfigured to switch the detection edge) or (and this is the main use) if you need to know the exact moment of the interrupt, as a capture interrupt copies the current timer count at the moment of the capture into the TACCRx register.

    Remember what I said about the timer ISR and the condition check there. TA0CCR4 is a register where only the CCIFG bit (BIT0) indicates an interrupt. You need to manually clear it before leaving the ISR. Or you read TA0IV which returns 0x08 when TACCR4 was causing the interrupt. In this case the CCIFG bit is automatically cleared as soon as you read TA0IV and next time you read TA0IV, it will return the next interrupt source (or zero, if there is no more).

  • Thanks for the help, I finally got it all working...

    Jens-Michael Gross said:
    P1DIR &= ~BIT5; // this one is probably set by the accelerometer initialization
    P1SEL |= BIT5; // this switches P1.5 form GPIO to TimerA0.CCR4 input
    TA0CCR4 = CCIE|CAP|CM_x; // this puts the timer CCR4 module into capture mode and enables the interrupt. 'x' is 1 to 3, depending on the edge you need to capture. Falling edge is 2, rising edge is 1 and both edges is 3.

    This solution did not work for me, I've tried some configurations but none seem to work... if I would guess correctly, I've misplaced a bit ;)

    however,

    Jens-Michael Gross said:
    You could as well have used a port interrupt by setting P1IE|=BIT5;P1ES|=BIT5; (or &=~BIT5, depending on edge) and use the PORT1_VECTOR instead of the timer vector.

    This solution did work, and using:

    P1IE|= BIT5;
    P1IES&=~BIT5;

    I'm now able to capture the interrupts from the component... 

    I'm going ahead and assuming that just as BIT5 could trigger the interrupt, other pins can do that as well. How can I determine in the interrupt method, which pin invoked the interrupt?

    And also, since I would probably want to reconfigure the component while the application is alive, I wondered is SPI interrupt proof, or should I disable the interrupts while the SPI dialog?

  • Adam Zehavi said:
    P1IE|= BIT5;
    P1IES&=~BIT5;

    Well, the correct sequence is:

    P1IES&=~BIT5; // select edge
    P1IFG&=~BIT5; // clear pending interrupt (may be caused by changing the edge setting!)
    P1IE|=BIT5; // now enable the interrupt

    If you do it the way I originally wrote (a quick draw), you may get an erroneous interrupt as soon as you change the edge or even may have an interrupt pending tha tis executed immediately after setting the IE bit.

    Adam Zehavi said:
    I'm going ahead and assuming that just as BIT5 could trigger the interrupt, other pins can do that as well.

    Yes. Usually all P1 and P2 pins can do.

    Adam Zehavi said:
    How can I determine in the interrupt method, which pin invoked the interrupt?

    On all MSPs, there is the P1IFG register which has a bit set for each pin that detected an edge. You'll need to manually clear this bit before leaving the ISR (or disable the interrupt on this pin by clearing the IE bit).
    On newer MSPs, there is also an P1IV register (P2IFG/P2IV for P2) which returns a value that represents the highest pending interrupt. So if e.g. interrupt sfor P1.1 and P1.5 ar epending, the first read will (I think) return 0x0a, next read of this register will return 0x02. Third read will return 0x00 (no more interrupts pending). At the same time you read the register, the corresponding IFG bit will be automatically cleared.

    Inside the ISR, you can take advantage od this by writing

    switch(even_in_range(P1IV,0x10)){
      case 0: return; // nothing to do
      case 2: break; // P1.0 interrupt
      case 4: break; // P1.1 interrupt
      ...
    }

    Adam Zehavi said:
    I wondered is SPI interrupt proof, or should I disable the interrupts while the SPI dialog?

    Depends on your application. If you want to talk to other slaves on the same SPI bus during interrupt, then interrupts need to be disabled until the current transfer is complete. Also, if you are SPI slave (the amster won't wait and you'll get an RX overflow soon if an ISR interrupts for too long)
    But as long as you're SPI master and the ISR doesn't touch the USCI or the CS port pin, you can leave interrupts enabled.

  • Jens-Michael Gross said:

    Well, the correct sequence is:

    P1IES&=~BIT5; // select edge
    P1IFG&=~BIT5; // clear pending interrupt (may be caused by changing the edge setting!)
    P1IE|=BIT5; // now enable the interrupt

    Yes, once I've figured out the Accelerometer has a daemon values from the previous run in its registers... and that unless I literally programmed the Accelerometer to stop interrupts, I've got them immediately upon enabling the P1IE bit on the next launch, I've just assumed they would reset.

    Jens-Michael Gross said:
    I wondered is SPI interrupt proof, or should I disable the interrupts while the SPI dialog?

    Depends on your application. If you want to talk to other slaves on the same SPI bus during interrupt, then interrupts need to be disabled until the current transfer is complete. Also, if you are SPI slave (the amster won't wait and you'll get an RX overflow soon if an ISR interrupts for too long)
    But as long as you're SPI master and the ISR doesn't touch the USCI or the CS port pin, you can leave interrupts enabled.[/quote]

    Here is what puzzles me, I've integrated the SPI implementation to my bigger application, and found out there is another component interrupting that vector, which is Bluetooth related:

    ENABLE_UART();
    UART_ENABLE_BT_UART_RTS();

    And once I add my Accelerometer SPI data values reading in the ISR, the application crashes with error code: SDK_ERROR_IN_HEADER_FIRST_BYTE.

    I'm guessing my SPI messes with the UART flow?

    Should I move the BT UART to Port 2, or this is doable with a single interrupt port?

    Thanks,

    Adam.


  • The BT is AFAIK a serial conenction, so it is on USCIAx. If your SPI is on USCIBx, the two should be totally independent.
    However, if you spend too much time in the SPI ISR; the UART RX may overflow. An ISR cannot be interrupted by an interrupt (unless you do the very dangerous interrupt nesting, which I don't recommend).

    If you keep your SPI ISR short, things should work fine. Remember, teh purpose of an ISR is to let the hardware wait for an event, so don't do anything inside the ISR that requires the software to wait for something. Like waiting for a free TXBUF or sending strings to the debug etc.

    However, if you use a 2x family device where USCIAx and USCIBx share their RX or BX vectors, you'll have to check at ISR start which one was triggering the interrupt and then do either the BT or the SPI code.
    If this is not possible (BT code is precompiled and has its own ISR fixed) then you'll have to switch to another USCI. (well, there is a workaround for thsi case too, but that requires assembly and is rather dirty)

  • Thank you for the answer...

    I'm a bit confused, again, looking at the code of the demo project reveals the following:


    /** * Copyright (C) 2010 MindTree Ltd. All rights reserved. * \file sdk_pin_config.h * \brief This header file contains pin definitions for the MSP430 setup */
    #ifndef _H_SDK_PIN_CONFIG_ #define _H_SDK_PIN_CONFIG_ /* * UART parameters, the PIOs which are mapped to Rx, Tx, RTS, CTS, * ACLK (32.768kHz slow clock), nShutdown and "flight mode" related * Pin Assignments for CC2560 */ /* Bluetooth UART port definitions */ /* Select UART Tx and Rx port selction register */ #define BT_UART_PORT_SEL P9SEL /* select UART Tx and Rx port direction register */ #define BT_UART_PORT_DIR P9DIR /* select UART Tx and Rx port OUTregister */ #define BT_UART_PORT_OUT P9OUT /* UART tx pin */ #define BT_UART_TX_PIN BIT4 /* UART rx pin */ #define BT_UART_RX_PIN BIT5 /* UART RTS port direction selection register */ #define BT_UART_RTS_PORT_DIR P1DIR /* UART CTS port direction selection register */ #define BT_UART_CTS_PORT_DIR P1DIR
    THIS IS THE CROSSING INTERRUPT I THINK A FEATURE CALLED 'EHCILL' USES THESE...
    #ifdef EZ430_PLATFORM
    #define BT_UART_CTS_PIN BIT4  /* UART CTS pin */
    #define BT_UART_RTS_PIN BIT3  /* UART RTS pin */
    /* Interrupt vector value generated for CTS pin interrupt */
    #define BT_UART_CTS_REG_PXIV P1IV_P1IFG4
    #else /* MSP-EXPF5438 platform */
    #define BT_UART_CTS_PIN BIT3  /* UART CTS pin */
    #define BT_UART_RTS_PIN BIT4  /* UART RTS pin */
    /* Interrupt vector value generated for CTS pin interrupt */
    #define BT_UART_CTS_REG_PXIV P1IV_P1IFG3
    #endif /* EZ430_PLATFORM */
    #define BT_CTS_PIN_VECTOR PORT1_VECTOR
    
    -----------------------------------------------------------------------------------
    /* UART CTS PORT IES */
    #define BT_UART_CTS_PORT_IES P1IES
    /* UART CTS PROT IFG */
    #define BT_UART_CTS_PORT_IFG P1IFG
    /* UART VTS PORT IE */
    #define BT_UART_CTS_PORT_IE P1IE
    /* UART CTS PORT SELECT */
    #define BT_UART_CTS_PORT_SEL P1SEL
    /* UART RTS PORT SELECT */
    #define BT_UART_RTS_PORT_SEL P1SEL
    /* UART RTS port output register */
    #define BT_UART_RTS_PORT_OUT P1OUT
    /* UART CTS port output register */
    #define BT_UART_CTS_PORT_OUT P1OUT
    /* UART CTS port input register */
    #define BT_UART_CTS_PORT_IN P1IN
    /* UART CTS Port Resistor Enable */
    #define BT_UART_CTS_PORT_REN P1REN
    /* UART control register 0 */
    #define BT_UART_REG_UCAXCTL0 UCA2CTL0
    /* UART control register 1 */
    #define BT_UART_REG_UCAXCTL1 UCA2CTL1
    /* UART baudrate selecation register 0 */
    #define BT_UART_REG_UCAXBR0 UCA2BR0
    /* UART baudrate selecation register 1 */
    #define BT_UART_REG_UCAXBR1 UCA2BR1
    /* UART Interrupt vector register */
    #define BT_UART_REG_UCAXIV UCA2IV
    /* UART output status register */
    #define BT_UART_REG_UCAXSTAT UCA2STAT
    /* UART Tx buffer register */
    #define BT_UART_REG_UCAXTXBUF UCA2TXBUF
    /* UART Rx buffer register */
    #define BT_UART_REG_UCAXRXBUF UCA2RXBUF
    /* UART modulation control register */
    #define BT_UART_REG_UCAXMCTL UCA2MCTL
    /* UART interrupt enable register */
    #define BT_UART_REG_UCAXIE UCA2IE
    /* UART interrupt flag register */
    #define BT_UART_REG_UCAXIFG UCA2IFG
    #define BT_UART_VECTOR USCI_A2_VECTOR
    #define USB_UART_VECTOR USCI_A1_VECTOR
    
    
    
    /** * BT controller Related Configuration Parameters */
    #ifdef EZ430_PLATFORM
    #define BT_RF_CLK_PORT_SEL P2SEL  /* Clock Port Select */
    #define BT_RF_CLK_PORT_PIN BIT6  /* Clock Port Pin */
    #define BT_RF_CLK_PORT_DIR P2DIR  /* Clock Port Direction */
    #define BT_RF_CLK_PORT_OUT P2OUT  /* Clock Port Out */
    
    #define BT_RF_NSHUTDOWN_PORT_SEL P2SEL  /* nShutdown Port Select */
    #define BT_RF_NSHUTDOWN_PORT_DIR P2DIR  /* nShutdown Port Direction */
    #define BT_RF_NSHUTDOWN_PORT_PIN BIT7  /* nShutdown Port Pin */
    #define BT_RF_NSHUTDOWN_PORT_OUT P2OUT  /* nShutdown Port Out */
    #else /* MSP-EXPF5438 platform */
    #define BT_RF_CLK_PORT_SEL P11SEL  /* Clock Port Select */
    #define BT_RF_CLK_PORT_PIN BIT0  /* Clock Port Pin */
    #define BT_RF_CLK_PORT_DIR P11DIR  /* Clock Port Direction */
    #define BT_RF_CLK_PORT_OUT P11OUT  /* Clock Port Out */
    
    #define BT_RF_NSHUTDOWN_PORT_SEL P8SEL  /* nShutdown Port Select */
    #define BT_RF_NSHUTDOWN_PORT_DIR P8DIR  /* nShutdown Port Direction */
    #define BT_RF_NSHUTDOWN_PORT_PIN BIT2  /* nShutdown Port Pin */
    #define BT_RF_NSHUTDOWN_PORT_OUT P8OUT  /* nShutdown Port Out */
    #endif /* EZ430_PLATFORM */
    
    #endif /* _H_SDK_PIN_CONFIG_ */
    
    

    
    
    I've bounded the interrupt definition section. 
    As you've said, the Bluetooth UART seem to be interrupted on USCI_A2_VECTOR, but my conflict is with PORT1_VECTOR, on which the CTS and RTS triggers the interrupt.
    
    
    
    
    Jens-Michael Gross said:
    If you keep your SPI ISR short, things should work fine. Remember, teh purpose of an ISR is to let the hardware wait for an event, so don't do anything inside the ISR that requires the software to wait for something. Like waiting for a free TXBUF or sending strings to the debug etc.
    So... I should not perform the actual write & read values from the Accelerometer in that ISR?
    Should I instead raise some boolean flag, and read the data in the timer interrupt? (That kinda diminishes the whole point of configuring the sampling rate of the component)
    
    
    
    
    Jens-Michael Gross said:
    However, if you use a 2x family device where USCIAx and USCIBx share their RX or BX vectors, you'll have to check at ISR start which one was triggering the interrupt and then do either the BT or the SPI code.
    Also, the Bluetooth uses the USCIA2, and my application uses USCIA3, which I guess should not be the issue as well.
    
    
    Thank you for your dedicated support. 
  • Adam Zehavi said:
    So... I should not perform the actual write & read values from the Accelerometer in that ISR?

    It's a bad idea. Inside an ISR, you may start an operation, but not wait for it to finish. This includes transfers.

    Assuming 100kHz I2C Bus speed. A read transfer requires start condition, addressing, byte read, stop condition. This are 20 I2C clock cycles. These are 200µs in which your CPU idles in the ISR and doesn't handle anything else. If you have a parallel 57kBd serial connection, this single byte receiving will take more time than the reception of a byte through UART.
    Now imagine you're not only receiving one byte, but also have to send a command first and then receive several bytes. During this process, you'll get a couple of uart receive buffer overflows since you cannot handle the UART RX interrupt.

    Adam Zehavi said:
    Should I instead raise some boolean flag, and read the data in the timer interrupt?

    This is one way.
    But you may setup an ISR for the I2C transfer and just start the transfer process and exit the port ISR. When the I2C ISR has finished the job, it can set a 'new data available' flag and wake the main thread, so the data can be processed.

    Some illustration: you got a mail from Amazon that a nice article is available (this is the trigger). You immediately order it from Amazon (starting the transfer). Now what you do is going to the door and waiting there for the package to arrive. You don't eat or sleep or pick up the phone while you're waiting for the delivery. Would you do this? I doubt it. So why should you program the processor to work this way? You'll hear the doorbell ring when the delivery is there (another interrupt). And you can do other things in the meantime.

  • Hi,

    Thank you for all your expert help, I'm now able to fully control the Accelerometer component.

  • "In case of P3.1, the pin can carry the Port 3 Bit 1 GPIO (P3.1) or USCI B0 module (UCB0) signal. In case of UCB0, this module can operate in I2C mode (then this pin is the serial data signal) or in SPI mode. In SPI mode, it is either slave output (if the mode is in SPI slave mode) or master input (if in SPI master mode). Since USCI B0 can only be in one mode at a time, only one of the different signals is routed to the pin at a time, depending on configuration."


    I think this may be getting to the source of a very basic problem I am having.  I have the MSP430F5529 LaunchPad Evaluation Kit.  I am using P3.2 as the SPI CLK for UCB0CLK.  So far my logic analyzer does NOT show this pin cycling as a clock, it is just stuck (high I think it was).

    How do I configure this pin to be the SPI CLK for UCBOCLK?  From the diagrams I have it looks like this should be the "default".  Do I need to do something in the code to make this "wiggle" as the clock?


    It seems this should not be terribly complicated, but there are so many options and ways to configure things I am completely at a loss as to what to do!  Please HELP!!

  • Allen Tabbert said:
    How do I configure this pin to be the SPI CLK for UCBOCLK?  From the diagrams I have it looks like this should be the "default".  Do I need to do something in the code to make this "wiggle" as the clock?

    You need to switch the port pin from GPIO mode to module mode by setting the corresponding bit in P3SEL.

    If you take a look at the port pin schematics for P3.2 in the users guide, there is a logic table that tells you the required port pin configuration for this or that purpose. In this case, "P3SEL|=BIT2;" is sufficient, as the USCI sets the direction by itself.

    The default for all port pins is GPIO mode, where PxDIR and PxOUT control the pin output. This is common for all MSP ports and explained in the digital IO chapter of the users guide.

    The additional level of por tpin complexity, the port mapping controller, can be ignored here as the desired mapping of this USCI function to P3.2 is already the default. However, it is not active by default.

**Attention** This is a public forum