多任务下与UART FIFO相关的错误

时间:2017-10-13 20:35:58

标签: c multithreading embedded uart

附件: 这些代码由我根据TI uart.c驱动程序库编写。

        while(1){
        //check if message on Queue -> read or check UART input
        if(uxQueueMessagesWaiting( UART_TASKQ ) != 0){ //may have bugs

        // deQueue
        xQueueReceive( UART_TASKQ, &UARTTaskHandle, 0x0A );
        //do the task's mission using the data in the stucture(put by control 
        task)
        //Print out the input data.

        //**********debugging data
/*
        testPointer = UARTTaskHandle->dataBuffer;
        testAmount = UARTTaskHandle->dataSize;

        while(testAmount){
            if(*testPointer != 1){
                error = error + 1;
            }
            if(*(testPointer + 1) != 2){
                error = error + 1;
            }
            if(*(testPointer + 2) != 3){
                            error = error + 1;
                        }
            if(*(testPointer + 3) != 4){
                            error = error + 1;
                        }
            if(*(testPointer + 4) != 5){
                            error = error + 1;
                        }
            if(*(testPointer + 5) != 6){
                            error = error + 1;
                        }
            if(*(testPointer + 6) != 7){
                            error = error + 1;
                        }
            if(*(testPointer + 7) != 8){
                            error = error + 1;
                        }

            testPointer = testPointer + 8;
            testAmount = testAmount - 8;
        }
*/

        if(UART_write(UART_Handle, UARTTaskHandle->dataBuffer, UARTTaskHandle->dataSize, 0xff ) >= 0){
        UARTwriteCount = UARTwriteCount + 1;
        }

        //let control task take new command
        //free allocated memory
        free(UARTTaskHandle->dataBuffer);
        free(UARTTaskHandle); // free memory space

//(above is code using UART)


//here are UART driver code:


     unsigned long UARTStatus(unsigned long ulBase){
    ASSERT(UARTBaseValid(ulBase));
    return(HWREG(ulBase + UART_O_FR));
}
//*****************************************
//UART_ISR
//Interrupt service routine for
//the UART read and write process
//*****************************************
void UART_ISR(){


    //read FIFO full or read time out
    if(UARTIntStatus(UART_Handle->UART_PORT,false) & (UART_INT_RX | UART_INT_RT)){
        UARTIntClear(UART_Handle->UART_PORT, UART_INT_RX | UART_INT_RT);    //clear INT flag

        while (!(UARTStatus(UART_Handle->UART_PORT) & UART_FR_RXFE)){
            //data reading
            *UART_Handle->pCurrentRead = UARTCharGet(UART_Handle->UART_PORT); //read autoly clear INT
            UART_Handle->pCurrentRead++;
            UART_Handle->ReadLength--;

            //adjust code here:
            if(UART_Handle->ReadLength == 0){
                break;
            }
        }

        //check if read certain bytes finished
        if(UART_Handle->ReadLength == 0){
            memcpy(UART_Handle->dataput, UART_Handle->pReadBuf,UART_Handle->ReadLengthcpy); // copy data back
            xSemaphoreGiveFromISR( UART_Handle->UARTRead_Semaphore, &xHigherPriorityTaskWoken );// release semaphore
            portYIELD_FROM_ISR( xHigherPriorityTaskWoken );//forcing context exchange
        }

    }

    //send FIFO empty
    if(UARTIntStatus(UART_Handle->UART_PORT,false) & UART_INT_TX){

        UARTIntClear(UART_Handle->UART_PORT, UART_INT_TX);  //clear INT flag

        if(UART_Handle->WriteLength == BUFFEMPTY){

            UART_Handle->UART_SendComplete = true;

            xSemaphoreGiveFromISR( UART_Handle->UARTWrite_Semaphore, &xHigherPriorityTaskWoken );// release semaphore
            portYIELD_FROM_ISR( xHigherPriorityTaskWoken );//forcing context exchange
        }

            //putting data into send FIFO
                if(UART_Handle->WriteLength > FIFOMAX){
                    for( Cindex = 0 ; Cindex < FIFOMAX ;){
                        if(UARTCharPutNonBlocking(UART_Handle->UART_PORT, *(UART_Handle->pCurrentWrite))){//write autoly clear INT
                            (UART_Handle->pCurrentWrite) = (UART_Handle->pCurrentWrite) + 1;
                            (UART_Handle->WriteLength) = (UART_Handle->WriteLength) - 1;
                            Cindex = Cindex + 1;
                            UART_Handle->sentCount = UART_Handle->sentCount + 1;
                        }
                    }
                }else{
                    templength = UART_Handle->WriteLength;
                    for( Cindex = 0; Cindex < templength ;){
                        if(UARTCharPutNonBlocking(UART_Handle->UART_PORT, *(UART_Handle->pCurrentWrite))){//write autoly clear INT
                            (UART_Handle->pCurrentWrite) = (UART_Handle->pCurrentWrite) + 1;
                            (UART_Handle->WriteLength) = (UART_Handle->WriteLength) - 1;
                            Cindex = Cindex + 1;
                            UART_Handle->sentCount = UART_Handle->sentCount + 1;
                        }
                    }
                }

    }

}

//*****************************************
//UART_write
//write certain length of data to UART port
//*****************************************
int32_t UART_write( UART_STATE *UART_Handle, uint8_t *pData, uint32_t length, uint32_t time_out ){


    while(!UART_Handle->UART_SendComplete); //debugging purpose
    UART_Handle->UART_SendComplete = false;//debugging purpose

    UART_Handle->WriteLength = length;

    if(UART_Handle->WriteLength <= UART_Handle->WriteBufSize){

        UARTIntClear(UART_Handle->UART_PORT, UART_INT_TX);  //clear INT flag

        memcpy(UART_Handle->pWriteBuf,pData,UART_Handle->WriteLength); //copy data into writebuff
        UART_Handle->pCurrentWrite = UART_Handle->pWriteBuf;
        //putting data into send FIFO
        if(UART_Handle->WriteLength > FIFOMAX){
            // if
            for( Cindex = 0 ; Cindex < FIFOMAX ;){
                if(UARTCharPutNonBlocking(UART_Handle->UART_PORT, *(UART_Handle->pCurrentWrite))){//write autoly clear INT
                    (UART_Handle->pCurrentWrite) = (UART_Handle->pCurrentWrite) + 1;
                    (UART_Handle->WriteLength) = (UART_Handle->WriteLength) - 1;
                    Cindex = Cindex + 1;
                    UART_Handle->sentCount = UART_Handle->sentCount + 1;
                }
            }
        }else{
            for( Cindex = 0 ; Cindex < FIFOMAX ;){
                if(UARTCharPutNonBlocking(UART_Handle->UART_PORT, *(UART_Handle->pCurrentWrite))){//write autoly clear INT
                    (UART_Handle->pCurrentWrite) = (UART_Handle->pCurrentWrite) + 1;
                    (UART_Handle->WriteLength) = (UART_Handle->WriteLength) - 1;
                    Cindex = Cindex + 1;
                    UART_Handle->sentCount = UART_Handle->sentCount + 1;
                }
            }
        }

        //start sending
        UARTEnable(UART_Handle->UART_PORT);

        if(UART_Handle->UARTWrite_Semaphore != NULL ) {
            if(xSemaphoreTake(UART_Handle->UARTWrite_Semaphore, time_out/(portTICK_PERIOD_MS) ) == pdTRUE){
                reValue = WRITESUCCESS; //wait return till write complete

            }else{
                reValue = WRITETIMEOUT; // timeout (ms)

                 }
        }else{
            while(1); //no Semaphore
             }

        return reValue;

    }else{
        return FAILURE; //wrong length
    }

}

//*****************************************
//UART_read
//read certain length of data from UART port
//*****************************************
int32_t UART_read(UART_STATE *UART_Handle, uint8_t *pData, uint32_t length, uint32_t time_out){



    //later added part
    UARTDisable(UART_Handle->UART_PORT);    //clearUART
    UARTFIFOEnable(UART_Handle->UART_PORT);
    //

    UART_Handle->ReadLength = length;   // set readlength
    UART_Handle->ReadLengthcpy = length;

    if(UART_Handle->ReadLength <= UART_Handle->ReadBufSize){

        UARTIntClear(UART_Handle->UART_PORT, UART_INT_RX | UART_INT_RT);    //clear INT flag
        UART_Handle->dataput = pData; //store the destination buffer address
        UART_Handle->pCurrentRead = UART_Handle->pReadBuf; //set current read

        UARTEnable(UART_Handle->UART_PORT); //start receiving

        //suspend before read ISR finish whole process
        if(UART_Handle->UARTRead_Semaphore != NULL ) {
                    if(xSemaphoreTake(UART_Handle->UARTRead_Semaphore, time_out/(portTICK_PERIOD_MS) ) == pdTRUE){
                        reValue = READSUCCESS; //wait return till write complete
                    }else{
                        reValue = READTIMEOUT; // timeout (ms)
                         }
                }else{
                    while(1); //no Semaphore
                     }

                return reValue;

    }else{
        return FAILURE; //wrong length
    }
}

//*****************************************
//UART_open
//open UART for certain port and bandrate
//*****************************************
UART_HANDLE UART_open(uint32_t UART_port, uint32_t UART_portperiph, uint32_t UART_baudrate){

    //initialize structure
    UART_Handle = (UART_HANDLE)malloc(sizeof(UART_STATE));

    UART_Handle->ReadBufSize = UARTBUFFERSIZE;
    UART_Handle->WriteBufSize = UARTBUFFERSIZE;
    UART_Handle->UART_PORT = UART_port;
    UART_Handle->UART_PORTPERIPH = UART_portperiph;
    UART_Handle->UART_BRATE = UART_baudrate;
    UART_Handle->pWriteBuf = (uint8_t*)malloc(UART_Handle->WriteBufSize * sizeof(uint8_t));
    UART_Handle->pReadBuf = (uint8_t*)malloc(UART_Handle->ReadBufSize * sizeof(uint8_t));
    UART_Handle->pCurrentWrite = UART_Handle->pWriteBuf;
    UART_Handle->pCurrentRead = UART_Handle->pReadBuf;
    UART_Handle->UARTWrite_Semaphore = NULL;
    UART_Handle->UARTRead_Semaphore = NULL;
    UART_Handle->UARTprotect_Semaphore = NULL;
    UART_Handle->UART_SendComplete = true;

    UART_Handle->sentCount = 0;//debugging purpose

    vSemaphoreCreateBinary( UART_Handle->UARTWrite_Semaphore ); //semaphore create
    vSemaphoreCreateBinary( UART_Handle->UARTRead_Semaphore ); //semaphore create
//  vSemaphoreCreateBinary( UART_Handle->UARTprotect_Semaphore ); //debugging purpose
    xSemaphoreTake( UART_Handle->UARTRead_Semaphore, portMAX_DELAY );   //semaphore take
    xSemaphoreTake( UART_Handle->UARTWrite_Semaphore, portMAX_DELAY );  //semaphore take

    // Enable Peripheral Clocks
    MAP_PRCMPeripheralClkEnable(UART_Handle->UART_PORTPERIPH, PRCM_RUN_MODE_CLK);

    // Configure PIN_55 for UART0 UART0_TX
    MAP_PinTypeUART(PIN_55, PIN_MODE_3);

    // Configure PIN_57 for UART0 UART0_RX
    MAP_PinTypeUART(PIN_57, PIN_MODE_3);

    // configuration, 8 bits length data width, 1 stop bit, no parity check
    UARTConfigSetExpClk(UART_Handle->UART_PORT,PRCMPeripheralClockGet(  UART_Handle->UART_PORTPERIPH),
            UART_Handle->UART_BRATE, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
             UART_CONFIG_PAR_NONE));

    // disable UART since function above contained UARTenable
    UARTDisable(UART_Handle->UART_PORT);

    UARTIntEnable(UART_Handle->UART_PORT, UART_INT_TX | UART_INT_RX | UART_INT_RT); // enable interrupt for send and receive and receive timeout
    UARTIntRegister(UART_Handle->UART_PORT, UART_ISR);  //hook ISR
    UARTFIFOEnable(UART_Handle->UART_PORT); //enable FIFO for send and receive
    UARTFIFOLevelSet(UART_Handle->UART_PORT, UART_FIFO_TX1_8, UART_FIFO_RX4_8); //Interrupt occur when 7 bytes send from FIFO or read in FIFO


    return UART_Handle;
}

我正在处理一个多线程的bug很长一段时间。经过多次测试后,我意识到最有可能与UART FIFO传输有关的错误。

以下是我对我的计划的描述: 该程序基于Free-RTOS。它有两个并行运行的线程。 一个线程通过I2C驱动程序从传感器读取。另一种是通过UART驱动程序将数据从读取任务发送到计算机。我有一个多任务框架,用于将数据从读取任务传输到发送任务。我有一个计时器文件来控制实时测量。我的I2C驱动程序和UART驱动程序都是基于中断的。

问题描述: 我的数据读数只有2分钟。之后,我的数据发生了变化。在测试时,我阻止了I2C驱动程序,只将常数数据“1 2 3 4 5 6 7 8”放入I2C读缓冲区,并将它们传送到发送任务进行UART发送。 2分钟后,我读出的数据将变为“8 1 2 3 4 5 6 7”,在第一次更改后,后来的变化很快发生,“7 8 1 2 3 4 5 6”并继续到计时结束。 this is plot of one channel of my data, begin with 8 and changing

我已经为我的程序设置了很多测试,我确信我的多任务框架(从读取任务到发送任务的转换数据)不会改变数据。 重要观察: 1.当我把read和send放到一个线程中时,数据非常好,没有这个bug。 2.我在我的UART驱动程序中设置计数,发现发送量是正确的,这里发送将字节放入TX FIFO。但是,在Excel中,我通过JAVA UART程序读取数据,错过了。并且JAVA UART程序应该没问题,因为当我使用单线程测试时它运行良好。 3.调试时CCS没有内存泄漏错误。

所以我想,在多线程环境下,在我将字节放入之后,某些东西停止了我的UART TX FIFO传输。但我无法找到我的代码中的错误,它们似乎都是正确的。

另一个合理的原因可能是我的指针在中断中被改变了,在链接图片中是“pCurrentWrite”指针。但该指针只能由UART驱动程序访问,并且在中断完成之前,下一次UART写操作无法进入。

我在链接中包含部分代码,我想在其中显示数据被放入TX FIFO,并且发送计数是正确的。

我不能包含所有代码,我认为没有人想检查那些长代码。没有运行它,很难找出错误的地方。

所以,我只是想描述我遇到的情况,看看之前是否有人有类似的错误。也许有人在多线程环境下知道UART FIFO的问题。如果可以帮助的人想要查看代码,我们可以进一步联系。

谢谢(我的新帐户还不能包含图片,图片链接如下)

This code is part of my UART driver, in the sending interrupt. I use the PutCharNonBlocking to put byte, since it return 1 if success, return 0 if FIFO full, so in this way I make sure the program will send all my data into the FIFO, which turn out to be true, all data was put into the TX FIFO

1 个答案:

答案 0 :(得分:0)

虽然你已经包含了信号量的使用,但我会建议进一步reading on mutual exclusion and shared resources.

解决方案过于复杂,更好地抽象代码并简化。

注意:您should not cast the result of malloc

UART_Handle = (UART_HANDLE)malloc(sizeof(UART_STATE));