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.

Concurrent use of USCI_A (e.g. UART) and USCI_B (e.g. SPI)

Other Parts Discussed in Thread: MSP430F2272

I have a question on concurrent use of UART and SPI.
Since the USCI has 2 modules (USCI_A and USCI_B), it seems
that I can use both concurrently.

However, the interrupt vector is shared with 1 vector
named as vector=USCIAB0TX_VECTOR (or vector=USCIAB0RX_VECTOR),
should I use this vector for both of UART and SPI with
if sentence?


The following is some sample program which I came up with,
for using UART and SPI.

Is this the right way to use both of UART and SPI? Or are
there any way to split the interrupt vector?

----------------

#pragma vector=USCIAB0TX_VECTOR
__interrupt void USCI0TX_ISR(void)
{

    if(IFG2&UCA0TXIFG) { // UART (USCI_A)
 // process for UART
        UCA0TXBUF = zbuf;
    } else if(IFG2&UCB0TXIFG) { // SPI (USCI_B)
 // process for SPI
        UCB0TXBUF = zbuf;
    }
 
    // where zbuf is some buffer to be sent
       
}

#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)

 
    if(IFG2 & UCA0RXIFG) { // UART (USCI_A)
 // process for UART
 zbuf = UCA0RXBUF;
    } else {
 // process for SPI
 zbuf = UCB0RXBUF; // SPI (USCI_B)
    }
}

  • Each USCI has 2 serial channels (1 "A" Channel, 1 "B" Channel) which can be run at the same time or independently. Each channel is mutually exclusive of the other.

    Care needs to be taken that the required configuration is available on the pinout of the MSP430. This can be determined by looking at the pin description in the device datasheet. Multiplexing of the MSP430 pins can prevent some configurations from being used.

    For devices with 2 USCI modules, then four channels are available: two "A" Channels and two "B" Channels. These are all independent and can be run simultaneously as long as the pinout for that device permits access to all necessary configurations.

    I just use "if" statements to manage the shared interrupt vector:

    // the below code is for the transmit vector

    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
      if(IFG2&UCA0TXIFG)                        // Check for UART TX
        UCA0TXBUF = UART_Data++;                // Load TX buffer
     
      if(IFG2&UCB0TXIFG)                        // Check for SPI TX
        UCB0TXBUF = SPI_Data++;                 // Load TX buffer
     
      _NOP();
    }

    // Similarly for the RX vector...

    #pragma vector = USCIAB0RX_VECTOR
    __interrupt void USCIAB0RX_ISR(void)
    {
      if(IFG2&UCA0RXIFG)
        UART_Data = UCA0RXBUF;                  // Store RX'ed UART data
     
      if(IFG2&UCB0RXIFG)
        SPI_Data = UCB0RXBUF;                   // Store RX'ed SPI data
    }

  • Thank you for your reply, Brandon.

     

    This is exactly what I wanted to know.

    I'll take care about the configuration of the pinout.

     

    Best regards

  • Hi,

    I would like a question on this matter: Is there any possibility of running into trouble if interrupts are requested nearly simultaneously by both the USCI_A and USCI_B module.

    To better illustrate what I have in mind, let's imagine the following scenario: USCI_A and USCI_B are configured for UART (slave) and I2C (master), i.e. the respective MSP430 µc is located in the middle of a three-tier hierarchy. I confine my consideration to the Rx ISR acocording to Brandons approach as an example:

     

    #pragma vector = USCIAB0RX_VECTOR
    __interrupt void USCIAB0RX_ISR(void)
    {
      if(IFG2&UCA0RXIFG)
        UART_Data = UCA0RXBUF;                  // Store RX'ed UART data
     
      if(IFG2&UCB0RXIFG)
        IC2_Data = UCB0RXBUF;                   // Store RX'ed I2C data
    }

    Now imagine, this ISR is called upon by the USCI_B module (i.e. UCB0RXBUF has received a freshly arrived byte during an I2C transfer). While the CPU is processing the I2C related part of the ISR, USCI_A receives an UART character.

    My current understanding is, that an ISR will mask all maskable interrupts via GIE, which also includes those ones which are associated with the USCI_A/USCI_B RX/TX interrupt vectors. That is, in this scenario, an interrupt generated by USCI_A will NOT fire (?).

    I.e. in this case the µc's programm will not learn about the received UART character retrieve it, the former at least until the next character arrives and a Rx-Buffer overflow occurs.

    Is this assumtion correct? Could one simply defuse this problem by swapping the instruction in the ISR, e.g.:

    #pragma vector = USCIAB0RX_VECTOR
    __interrupt void USCIAB0RX_ISR(void)
    {


      if(IFG2&UCB0RXIFG)
        IC2_Data = UCB0RXBUF;                   // Store RX'ed I2C data

      if(IFG2&UCA0RXIFG)
        UART_Data = UCA0RXBUF;                  // Store RX'ed UART data
     
    }

    So that in this case UCA0RXIFG is checked upon leaving the ISR, thereby preserving a chance for the programm to take notice of the received character?

     

    Moreover as a general question concerning interrupt: I understand that in case a maskable  interrupt occurs while another ISR is beeing processed, the interrupt will not fire and the associated ISR never be carried out. I.e. there is no means of putting interrupts into a queue for servicing at a later time, if so to speak. At least the understanding that the above consideration is based on.

     

  • Thomas said:
    Is there any possibility of running into trouble if interrupts are requested nearly simultaneously by both the USCI_A and USCI_B module.

    Not by hardware, but by software. The MSP interrupt mechanism is quite robust. Once an ISR is entered, no other interrupt can interrupt it. Interrupts accumulate, so if an interrupt happens while an ISR is executed, it is queued. However, if an interrupt flag is cleared (by hardware or software) before its ISR has been executed, the interrupt is lost as if it never were. The same interrupt cannot happen twice if the first occurrence is still unhandled (that's why some modules have an overflow flag).

    So when both USCIs flag an interrupt, your ISR will be called until all IFG flags are clear again. It depends on you and your software to 1) detect which interrupts are pending and 2) clear the interrupt flags (either manually, or implicitely, e.g. by reading RXBUF).
    It is your choice whether you handle multiple events inside your ISR or check for more than one event befor eleaving the ISR. The first approach allows higher-priority itnerrupts to be handled between two USCI ISR calls, teh second approach reduces latency as it doe snot leave and re-enter the ISRs unnecessarily. Which one to choose depends on the application.

    In your example, the moment when USCI_A receives a character, its RXIFG bit will be set. You can check this inside teh ISR or not. But if, when you exit the ISR, the RXIFG bit of USCI_A is still set, the ISR will be called immediately again.

    A counterexample: your ISR is called because of an incoming character from USCI_A, but inside the ISR you do not read RXBUF (because you doN't care for the value and only want to reacto on the fact that something was sent at all). nor do you manually clear teh RXIFG bit. Then, wen exiting the ISR, it will immediately be re-entered (except if a higher-priority interrupt is pending, then this one will be handled first). You'll be trapped in an entless loop of ISR calls, until the ISR finally clears the RXIFG bit this way or another.

    To summarize: it is not the event that triggers an interrupt, it is the simple fact that both, an IFG and an IE bit, are set simultaneously while GIE is set. If the ISR doesn't clear one of them (!) (or both), then the ISR will eb called over and over again. If one of them is cleared before the ISR has been called, it will not be called anymore at all.

    while(1) If (GIE && IF && IE) interrupt();

    There is an exception: The timer CCR0 interrupt will automatically clear the CCIFG bit in TxCCR0 the instant the interrupt handler is entered. Since this interrupt vector has only one trigger, there is no need to check it and to clear it maually. This auto-clear saves a few clock cycles. This does NOT happen for CCR1..x, as their interrupt vector shares several different triggers.

  • Thank you so much, this helped a lot.

     

  • Just one more thing: I'm still somwhat concerned about a possible overflow of UCA0RXBUF during the servicing of an I2C related part of the RX-ISR (or TX-ISR). That is,in case that that during entering of the I2C part of the ISR  two UART characters might arrive in quick enough sucession to cause the first UART character to be overwritten by the seccond one, because the I2C-ISR does not finish in time for the RX-ISR to (re)start and deal with retrieving the first UARTcharacter before it is too late.

     

    Though I suspect that is very unlikely to happen, if said I2C part of said ISR does only check the UCB0RXIFG flag and writes or reads a single byte, which it should accomplish in no time. And it would be even less likely if the UART part of the ISR, e.g.

    if(IFG2&UCA0RXIFG)
        UART_Data = UCA0RXBUF;                  // Store RX'ed UART data

    is put at its end, thus making sure that UCA0RXIFG is checked for the arrival of an UART character (and appropriate action taken) immedeately before the ISR terminates, right?

  • Thomas said:
    I'm still somwhat concerned about a possible overflow of UCA0RXBUF during the servicing of an I2C related part of the RX-ISR (or TX-ISR).

    That's why one shouldn't do any time-consuming tasks inside an ISR. ISRs are quick-in quick-out functions.
    And the worst thing you can do inside an ISR is busy-waiting for the next character.
    If you really have to handle a complete protocol inside an ISR, you can set up a state machine (that means: you have a static variable that is incremented for each step of the protocol and then you exit the ISR. On next ISR entry (or even on different ISRs, if the protocol is that complex), you check its state and jump to the proper position in the code, do what is necessary and increment it further, then exit the ISR again.

    This way, all other events can be handled fast enough.

    I did the initialization of an SD card this way in my 1ms timer interrupt. The initialization itself can take several 100 ms bevore the card is available to the system. But due to the state machine, it runs in the background and does not block anything else, and background sending and receiving of one or more UARTs with 155kBd works wihtout overflows even when hot-plugging the SD card while the rest of the system is busy.

    A rough estimate about how likely an overrun is, can be done by calculating the number of CPU cycles between the arrival of two data bytes. As long as all ISRs that may happn in this time doe require less than this number of cycles to execute, you're safe.

    And yes, checking for a received byte at the end of the ISR will make things better.
    Also, if the ISR is entered, you don't know whether it was because of I2C or UART, so you'll have to check for both IFGs anyway. No need to exit the ISR after you positively checked for one of them and handled it.

  • Hi, thanks again for your help!


    If you really have to handle a complete protocol inside an ISR, you can set up a state machine (that means: you have a static variable that is incremented for each step of the protocol and then you exit the ISR.

    A rough estimate about how likely an overrun is, can be done by calculating the number of CPU cycles between the arrival of two data bytes.

    I though that too. Perhaps I should get a bit more specific.
    What I have in mind, is this:

    #pragma vector = USCIAB0RX_VECTOR
    __interrupt void USCIAB0RX_ISR(void)
    {

      if(IFG2&UCA0RXIFG) {
         *UART_RXData = UCB0RXBUF;                   // Store RX'ed UART data analogous to I2C part of //ISR
    UARTRX_Data++; //Increment pointer
    UCA0RXCOUNT++; //Increment byte counter
    };
    if(UCA0RXCOUNT ==2) {
    //Peform various data processing actions icluding, evalutaion of received data, creating and //evaluating crc bytes,

    //reading and writing to data structures, tx reqtested data to //busmaster etc.
    };
    //This optionally:
    if()
    {}
    }
    With Tx ISR as follows:

    #pragma vector = USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX_ISR(void)
    {
    if(IFGF&UCB0TXIFG)
    {
        UCA0TXBUF = *I2C_TXData++  ;                  // Take to be  TX'ed bytes from were pointer

                                                                               //I2C_TXData points at, icrement pointer
                                                                             //These locations would be inside uint8_t type

                                                                             //variable, i.e. a character within a string of characters, such as     
                                                                             //I2C_TXData_string_u8 [m],  m being an appropriate integer number

    UCB0TXCOUNT++; //Increment byte counter
    }
      if(IFG2&UCB0RXIFG) {
        *I2C_Data = UCA0RXBUF;                  // Store RX'ed bytes were pointer I2C_data points //at.
                                                                             //These locations would be inside uint8_t type //variable, i.e. a character within a string of characters, such as     
                                                                      //I2C_RXData_string [n],  n being an appropriate integer number
    I2C_Data++; //Increment pointer
    UCB0RXCOUNT++; //Increment byte counter
    If(UCB0TXCOUNT == UCB0TXMAX && TXSTOP_ENABLE)
    UCB0CTL1 |= UCTXSTP;  //Stop transmission when last byte has been send and stoppig hase been enabled
    else
    UCB0CTL1 |= UCTXSTT;  //else issue restart condition

    }

     If(UCB0RXCOUNT == UCB0RXMAX && RXSTOP_ENABLE)
    UCB0CTL1 |= UCRXSTP;  //Stop transmission when last byte has been send and stopping transfers //has been enabled
    __low_power_mode_off_on_exit();     //Back to active mode on exit     
    }


    Counter and Pointer variables are global and declared volatile. Main programm initiates I2C transfers and evaluates the asssociated counter variables and strings. I put the functionality for stopping I2C transfers into the ISRs, rather than the main programm check coditions and issue a stop, as I assume this the wiser thing to do...
    (See below, why I'm not checking UCA0TXIFG in here...)
    Let's assume the worst case scenario. Which would occur if an UART character arrives (UCA0RXIFG is set) while the TX ISR ( UCB0RXIFG or UCB0TXIFG are set) is already beeing initiated.


     Afaik any ISR has a delay of 6 lock cycles for initiating(pushing SR and Programm Counter to the stack and so on) and another 5 for returning.
    As a result of the constrains imposed by the UART protocoll. USCI_A and USCI_B are operating in separate ISRs (the UART Tx operation beeing handled in the Rx ISR, see below for details)!
    The DCO and mlck are set to 1 MHz (using calibration data from CALBC1_1MHZ and CALDCO_1MHZ for more precise operation of the DCO).
    So we've got a maximum delay of
    - 6 clk cycles of  the USCIAB0TX_ISR  engagement delay +
    - unknown number of clk cycles needed or processing  either RX or TX related I2C operations +
    - 5 clk cycles to return to main programm +
    - 6 clk cycles toinitiate  the USCIAB0RX_ISR +
     - unknown numer of clk cycles needed for evaluating the initial if-condition in the UART part of the RX ISR and retrieving of the UART charater from UCA0RXBUF.


    The User Guide (in this case MSP430F2272/F2274) provides a reference (Table 3-16) with respect to the numbers of clk cycles required to perform certain commands depending on the adressing mode. But all examples are provided in Assembler. And neither deep enough into both MSP430 adressing modes nor Assembler, to guess what an Assembler equivalent of my C-code would look like and how many cycles it take at maximum.
    Perhaps someone could take a look at it and give some rough estimation?


    Either way at 9600 Baud it should not be critical. If we assume an UART character to conist of a total of 10 bits (start bit, 8 bits payload, stop bit, no multiprocessor format, bitrate = baudrate),
    character rate is 960 char/s. I.e. the transfer time of a single character woul be about 1.04 ms. Considering that at 1 Mhz a single clk cycle is 1µs, we've got about 1000 cycles to retrieve a character, which seems being plenty of time.
    However, at 115200 Baud we've got only about 86 μs, or 86 clk cycles. Now, that seems a bit narrow...
    I would like to run the CPU at 16 Mhz but I feel compelled to use 1 Mhz as I would to use Timer_A for a 1s periodic count in up mode using smlck, and trigger an interrupt after 1s. This meant for waking the µc from LPM0 every 1s, have it perform the required actions and go to sleep again. To be woken again when either Timer_A or USCIA0 triggers an interrupt. As the 16bit register of TACCR0 is confined to a max count 65536 on one hand and I can divide smlck only by 8 twice, I am forced to feed Timer_A with a minimum clk of 15625 Hz. So I have Timer_A count up to 15625 to produce the desired 1s period. The only way to handle this, that I can think of is to have the Timer_A ISR reset the register and icrement an auxilary int variable. But then I get even more Timer_A related clock skew, which I can atm not correctly estimate, so its less than an ideal solution.
    I suppose I will have to bear with that.


    And the worst thing you can do inside an ISR is busy-waiting for the next character.

    Unfortunately, I suppose I have to this. The UART part of the RX ISR is supposed to handle a protocol. This includes receiving 3 UART characters from the busmaster, evaluate these, and respond with appropriate action.
    The problem is: Once these three characters have arrived, the µc MUST evaluate them and respond with a three character sequence of its own IMMEDEATELY. Things are that way, because of time constrains.


    That is, I can not have the UART part of the  USCIAB0RX_ISR merely prepare some variables, which will be evaluated at some time by a dedicated part of the main programm, which in turn initiates a reply sequence, thus in turn triggering the USCIAB0TX_ISR.


    The USCIAB0RX_ISR could return at any stage of the main programm and some considerable time might elapse, before that dedicated piece of source code is being processed. I.e. TXing an prepared reply sequence has to happen inside the ISR. This includes polling the UCA0TXIFG flag inside the USCIAB0RX_ISR.
    Though in this case it would not be time critical, as USCI_B will stretch SCL if UB0RXBUF is not read out, so I think I can afford to have a rather time consuming UART part of the RX ISR.


    Sorry, if this post might a bit large but I felt it that much information to fully explain my concerns.
    Edit: I had to apply some changes, as I just came across the fact, that with I2C mode both Tx and Rx interrupts use the same ISR....

  • Thomas said:
    The User Guide (in this case MSP430F2272/F2274) provides a reference (Table 3-16) with respect to the numbers of clk cycles required to perform certain commands depending on the adressing mode. But all examples are provided in Assembler. And neither deep enough into both MSP430 adressing modes nor Assembler, to guess what an Assembler equivalent of my C-code would look like and how many cycles it take at maximum.
    Perhaps someone could take a look at it and give some rough estimation?


    That's impossible. The execution tiem for assemply isntruction sis known, but it is completely unknown into which assembly isntructions the compiler will translate your C code. This may even change between two compilation runs when you changed something somewhere else. If oyu don't let the compielr do any optimizations, then you can do  arough estimate, but in this case, your code will be usually significantly larger and slower than with optimization, so it won't help.

    What you can do is lookign at a disassembly listing (if provided by the linker) and then count the cycles on the actually generated code.

    Thomas said:
    Either way at 9600 Baud it should not be critical.

    9600Bd are one byte per millisecond. On 1MHz this are 1000 cycles.
    However, some operations are really time-consuming (such as divisions, multiplications on MSPs without hardwar emultiplier, and float/double operations).
    Loops are time-.consuming too. Especially busy-waiting loops. because if you wait for an event, you might be waiting exactly the time you have between two events.

    Thomas said:
    However, at 115200 Baud we've got only about 86 μs, or 86 clk cycles. Now, that seems a bit narrow...

    indeed. A stable transfer on 115kbd is a tight job on a system with only 1MHz. With 4 or 8 MHz I never had any problems. (on 16MHz I was even doing 4 simultaneous bi-directional UARt connections without drops - a stress test for my UART library code), but 86 clock cycles aren't much.

    Thomas said:
    I would like to run the CPU at 16 Mhz but I feel compelled to use 1 Mhz as I would to use Timer_A for a 1s periodic count in up mode using smlck, and trigger an interrupt after 1s.

    well, 4MHz are doable: 4000000/8/8 = 62500. Still within the timer count range.

    Thomas said:
    And the worst thing you can do inside an ISR is busy-waiting for the next character.


    Unfortunately, I suppose I have to this. The UART part of the RX ISR is supposed to handle a protocol. This includes receiving 3 UART characters from the busmaster, evaluate these, and respond with appropriate action.
    The problem is: Once these three characters have arrived, the µc MUST evaluate them and respond with a three character sequence of its own IMMEDEATELY. Things are that way, because of time constrains. [/quote]THat's the job for a stat emachine.

    Start a global variable with 0.
    Once the first charater arrived, store it, and increment the variable. And exit the ISR
    repeat with the second char.
    When the third has arrived, do the evaluation, prepare the result, reset teh variable to 0 and start sending the first byte of the answer. And set another variable to 1. And exit the ISR
    Your TX ISR is then called once the first byte is sent (actually earlier due to the USCIs double-buffering). It sees the second global variable on 1, and know shat it has to send the second character of the answer.. Doe sit, increments the second variable, and exits. So on until the last byte is sent and the second variable is set back to 0.

    No need to stay in an ISR until the whole protocol is done. Jost in and out and write down on which point inside the protocol you were last time.

    I agree, it is rather comple at first, but sometimes it is the best way to handle things, as it completely eliminates the need for busy-waiting.

    I've done such a thing inside my tiemr ISR for initializing an SD card. It also needs a complex protocol and some tight timing, but then some steps can take several hundred milliseconds before the card enters. With this state machine, I was progressing every millisecond by a small step (or just checked whether the card is ready for the next), and the rest of the code didn't even notice that there are a realyl complex job in the works. No 'hourglass' or 'frozen mouse pointer' situations when plugging a device in :)

    Thomas said:
    I had to apply some changes, as I just came across the fact, that with I2C mode both Tx and Rx interrupts use the same ISR....

    Indeed. The other ISR is used for handlign state events, like receiving a NACK or detectign a start or stop condition. Mostly for I2C slave use.
    On the 5x family, all interrupts of an USCI share the same ISR, but A and B each have its own. Also, there is an interrupt vector register that makes deciphering the different interrupt reasone much easier and faster.

  • Hi,

    thanks again for your kind help. I have to stress that is been extremely valuable for me to improve my understanding and to fill in the gaps

    in my knowlwdge (and there are still quite a lot).

    A stable transfer on 115kbd is a tight job on a system with only 1MHz.

     

    I think that John H. Davies mentions that the DCO may have a deviation od up to 20% from face value (5 % when using an external resistor) depending on the enviromental temperature. I suppose that whould put the feasibility of 115kbd whithout an external clk source into question anyway. After all in, asynchronous communication you depend on accurate and stable timing on either side, don't you?

    well, 4MHz are doable: 4000000/8/8 = 62500. Still within the timer count range.

    Yes, but in this case I would have to calibrate the DCO myself. This currently beyond the reach of my capabilities. Besides, I thought running the DCO at 8  Mhz and let the Timer_A ISR evaluate an auxilary variable, so that the ISR will only trigger a return to active mode after it has reached it ceiling count twice. Of course, I'll et even more skew - especially whenever Timer_A reaches its maximum count while another ISR is already beeing processed (i.e. which addtional delay for resetting the auxilary vaiables).

     

    However it  is not neccesarily required that Timer_A  should sound a wakeup call exactly every 1s. It's just there to make sure that the required operations are performed with a rate of one time per 1s in regular operation. I will reduce the Timer-Intervall from 1s to ,say, 800ms, to provide a reserve for the UART communication, and everything should be fine.

    Better still, I could run Timer_A Up/Down mode (if I´m not mistaken in this TAIFG will set and an interrupt requested when Timer_A has counted down to 0 again after counting up to TACC0), this way I could do 8 Mhz even without having to resort to the use of auxilary variables. And with 8 Mhz I should be on the safe side concerning incoming UART characters.

    Just to provide a sketch of the main programm, to illustrate of what I´m talking about::

     

    main (void]

    {

              while(1) {

                    //Perform some actions

                    //When done switch to LPM0

                  //Wake from LPM0 via Timer_A ISR after 800ms have elapsed

             }

    }

  • Thomas said:
    I think that John H. Davies mentions that the DCO may have a deviation od up to 20% from face value (5 % when using an external resistor) depending on the enviromental temperature. I suppose that whould put the feasibility of 115kbd whithout an external clk source into question anyway. After all in, asynchronous communication you depend on accurate and stable timing on either side, don't you?

    With calibrated values, you'r emuch closer. And in fact, a properly calibrated DCO ona stabel temperature doesn't have too many problems with high baudrate UART transfers.
    However, there are two sources of additional errors: First, the baudrate divider. Unless the target baudrate is an ingeger fraction of the clock baudrate, you need to use modulation. However, modulation means that for some bits you use n clock cycles, and for some bits you use n+1 cycles, in an attempt to keep the bit timing error within an acceptable range. That's fine if your clock is a steady, jitter-free clock.

    However, the DCO does not produce a jitter-free clock signal. At least for 97% of all output frequencies. The reason isthat the DCO itself uses modulation to get the desirted frequencies.
    Example: for 1MHz output, the DCO might run on 950kHz for one tick and 1.05MHz on the next, giving you 1MHz average. This is because the DCo has only a limited number of output frequencies, and in the very most cases none of them is your desired frequency.
    So you have a jitter on every clock tick. This jitter affects the baudrate the more the smaller the baudrate divider is. So the DCO jitter forms an interference pattern with the baudrate divide rmodulation, causing a rather unpreditable error skew.

    The faster the DCO is, and the higher the baudrate divider is, the smaller the effects of baudrate divider modulation and clock jitter.

    Thomas said:
    Besides, I thought running the DCO at 8  Mhz and let the Timer_A ISR evaluate an auxilary variable, so that the ISR will only trigger a return to active mode after it has reached it ceiling count twice. Of course, I'll et even more skew - especially whenever Timer_A reaches its maximum count while another ISR is already beeing processed (i.e. which addtional delay for resetting the auxilary vaiables).

    That's the typical way. And if you code it properly, you won't get a clock skew, only an absolute shift, as it takes always the same time to increment the counter and to check for it being even or odd. Also, a simple
    count++; if(count&1){}
    takes only a few clock cycles. And you have 8 times as many clock cycles in the same time interval. Actually it even reduces the ISR latency (the time that passes between ISR trigger and start of ISR execution) by a factor of 8.

    Thomas said:
    Better still, I could run Timer_A Up/Down mode

    Yes, this will work.

    Thomas said:
                  //Wake from LPM0 via Timer_A ISR after 800ms have elapsed

    No need for the safety margin. SInce the tiemr continues to count after the interrupt is executed, it will have reached 200ms (or whatever) already when main is done with its job. The next timer interrupt happens exactly 1 second after the last (and not 1s after main has done its job). So unless your main takes longer than one second for what it has to do every second, the timing is precise. (and in the other case you're hosed anyway)

  • I believe there is a bug with this implementation, please tell me the recommended way to handle it, or if it is not an issue:

    After enabling UART and SPI to both use interrupts, the Tx interrupt flags for both are set since the Tx buffers are empty.  Let's say that UCA0TXIE = 0 and UCB0TXIE = 1.  Then the UCAB0TX interrupt handler will run, and load both UCA0TXBUF and UCB0TXBUF.  In other words, enabling either UART OR SPI (but not both) causes both UART and SPI to transmit bytes initially. 


    Currently I plan to use the following change in the conditionals:

    if( (IFG2 & UCA0TXIFG) && (IE2 & UCA0TXIE) ){

    //Send UART data

    }

    if( (IFG2 & UCB0TXIFG) && (IE2 & UCB0TXIE) ){

    //Send SPI data

    }

**Attention** This is a public forum