c - 多任务下与UART FIFO相关的Bug

标签 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,并且发送计数是正确的。

我无法包含所有代码,我认为没有人想检查那些长代码。而且如果不运行它,就很难找出问题所在。

所以,我只是想描述一下我遇到的情况,看看以前是否有人遇到过类似的bug。也许有人知道多线程环境下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

最佳答案

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

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

注意:你 should not cast the result of malloc .

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

关于c - 多任务下与UART FIFO相关的Bug,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46737663/

相关文章:

java - ScheduledThreadPoolExecutor 和 corePoolSize 0?

c# - 处理任务和并行循环中的异常。 (线程 - TPL)

C错误: control reaches end of non void function

c - 返回指针的函数在第二次调用时使指针无效

c - 在c中初始化数组时遇到问题

c# - AutoResetEvent 和 maximumCount = 1 的信号量之间有什么区别吗?

embedded - 嵌入式编程的替代语言

c++ - 如何通过本地 LAN 使用网络别名自动访问嵌入式设备的 Web 服务器?

c - 替代一大组 if 语句?

c - 如何使用 FILE *fp 和 fopen 读取文件?