This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Semaphore problem

Has anyone experienced problems using semaphores in interrupt routines? I have a UART ISR that places a received character into a FIFO buffer and sets a semaphore using isr_sem_send().

void SerialIsr(void) __irq
{
    volatile uint8_t Temp;
    switch( COMIID0 & 0x0fU )
    {
        case MSI:
            Temp = COMSTA1;
        break ;

        case THRE:
        break;

        case RDA:
            Temp = (char_t)COMRX;
            if(BufferCount < BUFFER_SIZE)
            {
                BufferCount++;
                isr_sem_send(SerialSemaphor);
            }
        break;
        case RLS:
            Temp = COMSTA0;
        break ;

        default:
        case NO_PENDING_INTERUPT:
        break;
    }
}

The GetByte routine waits on this semaphore for a specified timeout period. If the semaphore is set, the next available char in the buffer is returned, otherwise a user defined timeout character is returned. The problem I am getting is that it appears that the semaphore is becoming corrupted and generating a lot of tokens. I test this by trapping the condition where os_sem_wait(sem) != OS_R_TMO and the buffer is empty. I.e. a semaphore token has been returned but the buffer is empty.
note that I have replaced the buffers with a counter for simplicity.

char_t GetByte (uint16_t File, uint32_t Timeout)
{

    OS_RESULT Result;
    char_t RetValue;
    uint32_t Copy;

    DISABLE_UART_INT();
    Copy = SerialSemaphor[0];

    Result = os_sem_wait(SerialSemaphor,Timeout);
    if(Result !=  OS_R_TMO && BufferCount == 0U)
    {
        Result = 1;
    }

    if(BufferCount == 0)
    {
        RetValue = ( (char_t)GETC_TIMEOUT_CHAR );
    }
    else
    {
        BufferCount--;
    }
    ENABLE_UART_INT();

    return RetValue;
}

If I then look at the semaphore object I can see that the most significant 16 bits of the first 32 bit word in the semaphore object is 0xFFFF (I am assuming this is the token counter). Subsequent calls os_sem_wait() return OS_R_OK, decrementing the token counter each time. This has the result that the thread is not released until the os_sem_wait() has been called sufficient times to decrement the token counter to zero (The os_sem_wait() is the only function to release the thread).

The target is an ADuC7021 and I am using the RTL-ARM.

Parents
  • I'm not sure, but as far as understand your code, you're disabling the IR so that isr_sem_send() is never really called:

    
        DISABLE_UART_INT();   // disable SerialIsr?!
        Copy = SerialSemaphor[0];
    
        Result = os_sem_wait(SerialSemaphor,Timeout);
    
        ...
        // will only be reached when timed out but never
        // when char is received
    

Reply
  • I'm not sure, but as far as understand your code, you're disabling the IR so that isr_sem_send() is never really called:

    
        DISABLE_UART_INT();   // disable SerialIsr?!
        Copy = SerialSemaphor[0];
    
        Result = os_sem_wait(SerialSemaphor,Timeout);
    
        ...
        // will only be reached when timed out but never
        // when char is received
    

Children
  • That is true and my code is incorrect, but that's not the problem.
    I am finding that periodically the semaphore count is decrementing to 0xFFFF (-1) when os_sem_wait() is called. When this occurs, the thread will not release until the semaphore count returns to zero.
    This only happens when the serial ISR is being fired.

  • I have ported this code to the lpc2131 and it works fine.

    The problem seems to be specific to the aduc7021 - could it be to do with the different interrupt controllers?

  • Yes there is a problem with aduc7021 devices interrupt controller. The problem is in a device inability to mask forced-programming software interrupts. We have implemented a workaround in RL-ARM version 3.00. The latest update for aduc7021 RTOS configuration has been done in version 3.03a.

    What version of RL-ARM are you using?

  • I've got everything that came with uVision v3.5. I'm not sure how to find the version of the RL-ARM, but is located in a directory \rv30 in the installation directory.

    The config file is V3.04 / 10-jan-2007. The only mod I have done to this file is to comment out the interrupt vectors as these are handled in another file.

    here is my interrupt vectors code

    IRQSTA_ADR      EQU     0xFFFF0000             ; IRQSTA Address
    
    
                    IMPORT  SerialIsr                 ; User serial interrupt Function
    mSer_IRQ        EQU     (1<<14)             ; User serial interrupt Mask    ( UART )
    
    ; OS Interrupt Functions
    
                    IMPORT  os_clock_interrupt
                    IMPORT  os_def_interrupt
    
    mIRQ_OS         EQU     ((1<<2) | (1<<1))             ; OS IRQ Mask (SWI + Timer )
    
    
                    AREA    IRQ, CODE, READONLY
                    ARM
    
                    PRESERVE8
                    ALIGN
                    EXPORT  IRQ_Handler
    IRQ_Handler
    
                    STMDB   SP!,{R0}               ; Save R0
    
                    LDR     R0,=IRQSTA_ADR         ; Load IRQSTA Address
                    LDR     R0,[R0]                ; Load IRQSTA Value
    
                    TST     R0,#mIRQ_OS            ; Check OS IRQ Flag
                    LDMNEIA SP!,{R0}               ; Restore R0
                    LDRNE   PC,=os_clock_interrupt ; OS Clock IRQ Function
    
                    TST     R0,#mSer_IRQ            ; Check serial IRQ Flag
                    LDMNEIA SP!,{R0}               ; Restore R0
                    LDRNE   PC,=SerialIsr            ; UART interrupt
    
                                    LDMIA   SP!,{R0}               ; Restore R0
                    LDR     PC,=os_def_interrupt   ; OS Default IRQ Function
    
    
                    AREA    FIQ, CODE, READONLY
                    ARM
    
                    PRESERVE8
                    ALIGN
                    EXPORT  Undef_Handler
        EXPORT  PAbt_Handler
        EXPORT  DAbt_Handler
        EXPORT  FIQ_Handler
    
    Undef_Handler   B    Undef_Handler
    PAbt_Handler    B    PAbt_Handler
    DAbt_Handler    B    DAbt_Handler
    FIQ_Handler     B   FIQ_Handler
    
                                    END
    

  • Try to put the OS IRQ handler the last in the chain as you see in the RTX_Config.c configuration. It should have the lowest priority.

                    LDR     R0,=IRQSTA_ADR         ; Load IRQSTA Address
                    LDR     R0,[R0]                ; Load IRQSTA Value
    
                    TST     R0,#mSer_IRQ           ; Check serial IRQ Flag
                    LDMNEIA SP!,{R0}               ; Restore R0
                    LDRNE   PC,=SerialIsr          ; UART interrupt
    
                    TST     R0,#mIRQ_OS            ; Check OS IRQ Flag
                    LDMNEIA SP!,{R0}               ; Restore R0
                    LDRNE   PC,=os_clock_interrupt ; OS Clock IRQ Function
    
                    LDMIA   SP!,{R0}               ; Restore R0
                    LDR     PC,=os_def_interrupt   ; OS Default IRQ Function
    
    

    Did you declare your UART handler with attribute __irq?

    __irq void SerialIsr (void);
    

    Do you acknowledge correctly UART serial interrupts?

  • I've changed the interrupt chain to put the IRQ_OS at the end, but the problem still occurs.

    SerialIsr() is declared using attribute __irq.

    I have changed the ISR to insure as far as I can tell from the data sheet that the interrupt is acknowledged properly as follows

    #define ENABLE_UART_INT()       IRQEN |= (1<<14)
    #define DISABLE_UART_INT()      IRQCLR = (1<<14)
    
    __irq void SerialIsr(void)
    {
        volatile uint8_t Temp;
        uint8_t IntSource;
    
        DISABLE_UART_INT();
    
        Temp = COMSTA1; /* Clear any modem status interrupts as these are not serviced */
        Temp = COMIID0; /* Clear Transmit buffer empty interrupt */
        IntSource = COMSTA0;
    
        if(IntSource & (1<<SLR_THRE))
        {
        }
    
        if(IntSource & (1<<SLR_RDR))
        {
            Temp = (char_t)COMRX;
            if(BufferCount < BUFFER_SIZE)
            {
                BufferCount++;
                isr_sem_send(SerialSemaphor);
            }
        }
    
        ENABLE_UART_INT();
    }
    
    


    If you want I can send you the full source code.
    Your help is much appreciated.

  • Yes please, send your code to: support@keil.com