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.

Problem with IAR and MSP430F5438

Other Parts Discussed in Thread: MSP430F5438

Prompt please!

I use MSP430F5438 and IAR  for MSP430 5.10.1.

Here a part of my code:

#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:                                   // Rx
  
    //Определение команды
    if ((deviceState) == CASE_CMD_STATE)
    {
      RX_buf = UCA0RXBUF;
      if (j == 3)
      {
        pnum = RX_buf;
      }
      if (j == 7)
      {
        psi = RX_buf;
        if (psi == 0x02)
        {
          j = 0;
          deviceState = START_STOP_STATE;
          break;
        }
        else
          if (psi == 0x00)
          {
            j = 0;
            deviceState = CONFIG_CODEC_STATE;
            break;
          }
       
        if (psi == 0x01)
          {
            if (pnum == 0x00)
            {
            j = 0;
            deviceState = CONFIG_TLV_STATE;
            break;
            }
            if (pnum == 0x01)
            {
              j = 0;
              deviceState = CONFIG_XE_STATE;
              break;
            }
          }
       
          if (psi == 0x04)
          {
            j = 0;
            deviceState = RST_CMD_STATE;
            break;
          }
      }
      j++;
    }
   

................................................

I don't write a part of the code.

.................................................


    break;
  case 4:break;                             // Vector 4 - TXIFG
  default: break;
  }
}

When I make project IAR write:

Error[Ta022]: Code too large for switch(__even_in_range(X,N)), please use switch(X) instead.

Prompt how to solve a problem? I should use a lot of code in this interrup!

  • If you change your statement from

    switch(__even_in_range(X,N))

    to

    switch(X)

    does the code work?  It should work!

    The __even_in_range technique has a "distance" limit over which it can jump to each "case" because it uses the basic JMP instruction.  The JMP instruction is limited to advancing 512 words forward (and 511 words backwards).  You have too much code in your RX case!  Either shorten the code, add a goto statement, or change the switch statement not to use __even_in_range.  (I vote shorten the code; it's an ISR after all.)

    Jeff

  • Hi,

    please read corresponding chapter in IAR_EW430_CompilerRef.pdf document (p.41) , it describes in details what __even_in_range() does.
    According to IAR description there is assumption that the code is from specified range and is even.

    You can write an equivalent part of the code that does the same, for example:

    unsigned int vector1 = UCA0IV & 0x06; //  binary 0110
    switch( vector1 )
    {
    [...]

    Regards,
    Piotr Romaniuk,
    ELESOFTROM

     

     

  • This thread really has me thinking if maybe IAR (and others?) should implement an __even_in_range switch differently.

    A typical implementation follows:

          MOV.W   &TA0IV, R15
          ADDA    R15, PC
          JMP     CASE_0
          JMP     CASE_2
          JMP     CASE_4

    CASE_0 <...CODE...>

    CASE_2 <...CODE...>

    CASE_4 <...CODE...>

    This implementation has the limitation noted in this thread.  Namely that a JMP statement has distance limits.  Consider this alternate implementation, which allows jumps up to 32767 words forward, not just 512 words forward.

          MOV.W   &TA0IV, R15
          MOV.W   OTBL(R15), R15
          ADDA    R15, PC
    OTBL  DC.W    CASE_0-OTBL
          DC.W    CASE_2-OTBL
          DC.W    CASE_4-OTBL

    CASE_0 <...CODE...>

    CASE_2 <...CODE...>

    CASE_4 <...CODE...>

    It's only one instruction longer!  (Yes, it's a slow, 2-word instruction, but still!)  One problem you might notice with this alternate implementation is that it is not position independent (PI).  PI code is still used sometimes, but the compiler always knows when it is supposed to generate PI code.  In that case, the highlighted instruction MOV.W  OTBL(R15), R15 must be replaced by two new instructions:

          ADDA    PC, R15
          MOV.W   OTBL-$(R15), R15

    The compiler could use the original method in ISR functions, and it could use the more flexible method elsewhere.  I just looked in my code and found two uses of __even_in_range (not in ISRs) that are very near the JMP limit already!

    Do any compiler writers monitor this forum?  Does the extra size and slower execution speed kill this idea?

    Jeff

  • Another idea is to use functions for handling separated events in this interrupt:

    switch(__even_in_range(UCA0IV,4))
      {
      case 0:
                   b
    reak;                             // Vector 0 - no interrupt
      case 2:                                   // Rx
                   UART_Rx_handler(  UCA0RXBUF );
                   break;

      case 4:                            // Vector 4 - TXIFG
                   UART_Txifg_handler( );
                   break;
     
    default:
                   break;
      }

    You will pay the cost of calling the function that can be not very high.
    The handling functions have no limits to their size like the switch(__even_in_range()).
    Nevertheless it is not good idea to put a lot of code in the ISR.
    Please remember that during ISR processing interrupts are dissabled, so you are not able
    receive and process other interrupt based events.
    The better method is to detect something in ISR and signal it to main part of code (i.e. outside of ISR),
    or to thread if you are using RTOS.
    Maybe you should rather use buffer for collecting received data and process them outside ISR?
    In ISR you would only receive a character and put it into the buffer.

    Piotr Romaniuk, Ph.D.
    ELESOFTROM

     

  • I think, the reason for doing it the way you observed is that before MSP430X, the way to do it (and as I do it too) is

    ADD &TA0IV, PC

    which is small and fast. And best suited for time-critical ISRs. While this still works in ISRs (which have to reside in low memory anyway), it won't work anymore if it is used in non-ISR code above 64k. And the ADDA instruction takes both parameters as 20 bit, which would result in a wrong reading of TA0IV. Hence two instructions.

    Normally, it makes not much sense using the TAIV register outside an ISR, but the __even_in_range intrinsic can be used on different arguments too, so it seemed to be necessary to 'improve' the implementation. For this case, your suggestion would be a further improvement, but inside time-critical ISRs, the additional cycles are maybe the droplet that makes the barrel overflow.

    Jeff Tenney said:
    The compiler could use the original method in ISR functions, and it could use the more flexible method elsewhere.

    Yes, it would work. But I fear the compiler (especially the optimizer) isn't 'smart' enough to handle ISRs differently to other code, except for the entry/exit code.

    Jeff Tenney said:
    I just looked in my code and found two uses of __even_in_range (not in ISRs) that are very near the JMP limit already!

    Well, in this case, just remove the 'even_in:range_ intrinsic and it works fine again. It's an optimization for cases where every cycle counts. Makign it flexible and slow will make it somewhat superfluous again. :)

    Jeff Tenney said:
    Do any compiler writers monitor this forum?

    Possibly not. There's a separate forum for CCS and no IAR forum at all (AFAIK) on this site.

    Jeff Tenney said:
    Does the extra size and slower execution speed kill this idea?

    .Partly. For shorter case lists, this would result in slower execution and more code than without.
    Personally, I too think that the limited jump length of the JMP is a drawback. But it allows the use of a fast one-word instruction which is a plus.

    I could imagine a second implementation of this intrinsic. If the code won't fit for the size, the parameter could be shifted before being added, allowing 4 bytes per case, so you can use a JZ (for the first) or JNZ instruction. It's longer for longer case lists, but faster than the additional add.

**Attention** This is a public forum