2011-02-11 08:50 AM
masking USART interrupt without disabling
2011-05-17 05:24 AM
Hello,
I want to mask USART interrupt without disabling it in order not to miss a char during the time it is disabled.
You don't miss a char: first, the receiption works also while an interrupt is disabled, second, the UART normally needs a lot of time to receive the next character. To solve the problem of the access to the resource ''counter'' you can use SWI to change its value because SWI cannot be interrupted. As soon as you leave SWI, pending UART interrupt can be processed again.
2011-05-17 05:24 AM
Why do you want to disable the Rx interrupt? Interrupts work especially well on Cortex machines.
Okay, I looked at your code. Is this in your ISR? Any character that comes in during your ISR (perhaps due to a long running higher priority interrupt) will get you another interrupt as soon as you exit. Try it by forcing the condition. At 9600 baud a 10-bit frame arrives every 1.0417 milliseconds. Setup a higher priority ISR that burns the CPU for 1.5 milliseconds every 3 milliseconds. (50% of the time in the higher priority ISR.) Stream simple pattern data saving it all to RAM. You won’t miss anything. Here is why The USART has a shifter and USART_DR. As soon as your frame has completely shifted in it’s copied to the data register. The shifter becomes empty and ready to accept another byte. I’ve posted http://www.hmtown.com/fifo.htm before. It focuses more on why and a general purpose what rather than implementation details. ColdWeather mentioned a way to use a single counter. My approach uses a pair of pointers. It works nicely even if the source and sink processes are in separate processors coupled only by RAM.2011-05-17 05:24 AM
Is this in your ISR?
I think, the piece of code of the main poster is not an ISR (''source'') but the ''sink'' process reading from the queue (watch pQueue->Count--). Meanwhile I looked at my code from some test firmware. An easy way is to use a ''critical section'' flag: The ''sink/reader'' process: if ( pQueue->Count) { // read an item out ... // decrement the counter within the critical section csflag = 1; // critical section begin pQueue->Count--; csflag = 0; // critical section end // reenable/confirm interrupt USART_ITConfig(UsartAddress, USART_IT_RXNE, ENABLE); } ISR: if (csflag == 0) { c = USART_ReceiveData(usart); // Put a char ''c'' into the queue ... // increment the counter pQueue->Count++; } else { // the critical section has been interrupted! USART_ITConfig(UsartAddress, USART_IT_RXNE, DISABLE); // leave the interrupt. // RXNE is still set because no read from DR done yet } The idea: if the ISR encounters that the critical section has been interrupted, it disables itself and leaves. The interrupt is still pending, a char stays in DR. As soon as the ''sink'' process leaves the critical section (csflag = 0) and reenables the interrupt, it shots again immediately, and the first part of the ISR is executed placing the char into the queue.2011-05-17 05:24 AM
The concept is very common indeed - one might even say that it's the standard way
Indeed. Which is why the vendor (ST) should provide an example for this. This is always one of the first things I implement on a new micro and almost everyone else does also. Lots of parallel effort that could be saved with one common, efficient and well documented example. In fairness to ST many other vendors do not provide this either. An open source example library would make sense to me, that way we all contribute to something that grows and improves over time. Won't be holding my breath for ST to embrace this tough.
2011-05-17 05:24 AM
''I’ve posted http://www.hmtown.com/fifo.htm before.''
Good link! The technigque is also often called a Ring buffer or a Circular buffer - because of the way the pointers chase around & around the buffer in a ring or circle. The concept is very common indeed - one might even say that it's the standard way to handle interrupt-driven serial comms! Googling these terms will find you many references & examples. But I think there's a mistake: The four ''pointers'' are described as follows
First First byte address of buffer
In Address within buffer where next byte goes IN to the bufferOut Address within buffer where next byte comes OUT from the buffer
Limit The last byte address+1 of the buffer (note that they don't actually all need to be ''pointers'' - they could be indexes within the buffer) The mistake, I think, lies in the getData() function:
char getData() {
char temp; if (in == out) {whatever;} temp = *in; // The order here in+++; // is important return temp; { Apart from the obvious typo with the closing brace, surely this should be using the Out pointer - since it is taking data out from the buffer?2011-05-17 05:24 AM
Thanks all, guys for your comments.
This is my actual code for push/pop the usart queue and the usart routine itself. I have three queues for the three usart I need. The usart ISR pushes the data into queue, main loop gets the data (pop).
Thanks and best regards.
typedef struct tagQUEUE {
// Top
u16 Top;
// Bottom
u16 Bottom;
// Count
u16 Count;
// queue overflow
u16 Overflow;
// Errors
uint32_t ErrOverrun;
uint32_t ErrFrame;
uint32_t ErrParity;
uint32_t ErrNoise;
// Buffer
u8 pBuffer[__RX_QUEUE_SIZE__];
} QUEUE;
//---------------------------------------------------------------------------
// Queue Push
//---------------------------------------------------------------------------
void QueuePush(QUEUE* pQueue,BYTE Data)
{
if (pQueue->Count == __RX_QUEUE_SIZE__) { pQueue->Overflow++; return; }
pQueue->pBuffer[pQueue->Top]=Data;
++pQueue->Top;
if (pQueue->Top == __RX_QUEUE_SIZE__) pQueue->Top = 0;
pQueue->Count++;
}
//---------------------------------------------------------------------------
// Queue Pop
//---------------------------------------------------------------------------
BYTE QueuePop(QUEUE* pQueue, BYTE Channel)
{
BYTE Data;
USART_TypeDef *UsartAddress;
switch(Channel)
{
case 0:
UsartAddress = USART1;
break;
case 1:
UsartAddress = USART2;
break;
case 2:
UsartAddress = USART3;
break;
}
if (pQueue->Count == 0) return(0);
Data=pQueue->pBuffer[pQueue->Bottom];
++pQueue->Bottom;
if (pQueue->Bottom == __RX_QUEUE_SIZE__) pQueue->Bottom = 0;
USART_ITConfig(UsartAddress, USART_IT_RXNE, DISABLE);
pQueue->Count--;
USART_ITConfig(UsartAddress, USART_IT_RXNE, ENABLE);
return(Data);
}
void USART3_IRQHandler(void) {
uint8_t ch;
if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
{
ch = (uint8_t)USART_ReceiveData(USART3);
QueuePush(&Queues[CHANNEL_SERIAL_3], ch);
}
}
2011-05-17 05:24 AM
yes, the code reported was from the sink routine. I attached my actual, I will switch to your since It seems faster than mine.
Thanks