问题
Program attached: Those codes are written by me based on the TI uart.c driver library.
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;
}
I am dealing with a multi-thread bug for long time. After many test, I aware that the bug most possibly related to the UART FIFO transmitting.
Here is my description of my program: The program is based on Free-RTOS. It has two threads running in parallel. one thread is reading from sensor by I2C driver. another is sending data from the reading task to the computer by UART driver. I have a multi-task frame to transfer data from reading task to sending task. I have a timer file to control real time measuring. My I2C driver and UART driver are all interrupt based.
Problem description: My data reading is good only for 2 mins. after that, my data shift. When do testing, I blocked the I2C driver, only put constant data "1 2 3 4 5 6 7 8" into the I2C read buffer, and transfer them to sending task to do UART send. And after 2 mins, my data read out will become "8 1 2 3 4 5 6 7" and after the first change, later changes happen quickly, "7 8 1 2 3 4 5 6" and continue till the end of timing. this is plot of one channel of my data, begin with 8 and changing
I set many test to my program already, and I am sure my multi-task frame (trans data from reading task to sending task) don't alter the data. Important observations: 1.when I put read and send into one thread, the data is very good, without this bug. 2.I set counting in my UART driver, found that the amount of sending is correct, here the sending is putting bytes into the TX FIFO. However, in the Excel, I read by a JAVA UART program, data missed. And JAVA UART program should be ok, since it works well when I use the single thread testing. 3. no memory leak error pump up by CCS while debugging.
So I am thinking, under the multi-thread environment, something stopped my UART TX FIFO transmit after I put bytes into that. But I can't find out where is wrong in my codes, they all seems correct.
And another reasonable reason can be something altered my pointer in the interrupt, in linked picture the "pCurrentWrite" pointer. But that pointer only accessed by UART driver, and before the interrupt finished, the next UART write can't enter.
I include partial code in the link, where I want to show that the data is put into the TX FIFO, and the send count is correct.
I can't include all codes, I don't think anyone want to check those long codes. and without running it, it's hard to find out where is wrong.
So, I just want to describe the situation i met, and see if someone had similar bug before. And maybe someone know the problem of UART FIFO under multi-thread environment. If someone who can help do want to see the code, we can do further contact.
thanks (My new account can't include picture yet, picture linked below)
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:
Although you have included the use of semaphores, I would suggest further reading on mutual exclusion and shared resources.
The solution is overly complex and it would be pertinent to better abstract your code and simplify.
Note: you should not cast the result of malloc.
UART_Handle = (UART_HANDLE)malloc(sizeof(UART_STATE));
来源:https://stackoverflow.com/questions/46737663/bug-related-to-uart-fifo-under-multi-tasks