UART FIFO psoc 5

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
ezbe_290006
Level 2
Level 2
10 replies posted 10 sign-ins 5 replies posted

hi,

i found  a problem  using the rx hw fifo buffer,

if i read a byte from the fifo and in that exact time anew byte is recived the data i read i corrupted.

is there any way to read the fifo without that problem?

thanks.

0 Likes
20 Replies
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

Although I'm not sure if the following sample of mine could provide you some hints,

at least I've been using it for a while now.

Note: Please try the latest version in the discussion (tty_utils_test_5LP_200504)

https://community.cypress.com/t5/Code-Examples/tty-utils-a-utility-sample-for-CLI-type-program/m-p/7...

moto

 

0 Likes
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

ezbe,

Can you provide your project to this thread?

I wonder if your DMA TD is reading the serial buffer memory instead of the FIFO.   The serial buffer memory is the immediate capture value.  The FIFO is the secondarily stored value of the serial buffer once the Rx data is fully received.

In the case of the UART you should be reading from UART_RXDATA_REG.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

i dont use the dma.

i check how many bytes are in the fifo in my main isr, and then reads that amount of bytes.

i dont use the uart interrupt , but my own isr.

i will upload the project later.

 

0 Likes
lock attach
Attachments are accessible only for community members.

i have attached a full explanation of the problem,

thanks for your help.

0 Likes

exbe,

I downloaded your project.   I'll take a look at it to see if I can reproduce your results.  It might take a few days.  I have an uber-critical project that needs to be completed.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

hi,

did you have a chance to check that?

0 Likes

EzBe,

I've been dividing my time between my project and your issue.

The results so far indicate that the FIFO has no issue.

I realize that you have a proprietary project with sensitive IP.  This is why you don't want to upload your project to the forum.  

This poses a problem.   There could be MANY reasons that data can get corrupted.  You say it is when data is read from the FIFO at the exact time new data is being placed into the FIFO.  Verifying this is difficult to coordinate between to asynchronous systems.  This is especially true when using the CPU to pull data from the FIFO.

When you get corrupt data, is it 100% of the time?  

As I said, I realize you can't share your project with the forum.  However, I technique I use is if I am having problems with a subsystem (let's say the UART data transfer), I deactivate other parts of the program to try to isolate the subsystem.  This allows other disabled parts of the program not to influence the CPU.

Having said that, is it possible for you to strip down your project (eliminate the proprietary IP) and upload it with the UART subsystem still obtaining corrupted data?

One of the potential many reasons for UART Rx data corruption could be CPU latency.   For example, if you were to use blocking functions inside interrupt service routines, this could account for major CPU latencies.  For example, I helped a user eliminate significant CyDelay() calls inside his ISRs.   The CyDelay()s (many of them were >500ms) were causing the CPU to delay processing other ISRs needed in a timely fashion. 

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

EzBe,

Sorry for my lengthy post today.

As I indicated, my results cannot replicate yours.   This is probably because my timing on reading the UART FIFO and the new data being input into the FIFO is not accurate enough.

Here is some debugging ideas that will help me (and others) to replicate what you are seeing.

The following recommendations require an oscilloscope or logic analyzer to display the signals and they're timing relationship.

Create a HW signal when the Rx byte is received

You already have the UART configured as "Advanced/Interrupt Sources/RX - On Byte Received" set ONLY. 

Attach a digital output pin to the UART's rx_interrupt output. (See pic)

Len_CONSULTRON_3-1618778387556.png

 

This will be the signal reference when the new byte is actually received.  It will be HW-dependent and not SW-dependent.   Therefore the timing relationship will be extremely accurate.

Create a HW signal when the Rx byte is read from the FIFO.

Allocate another digital output pin.  (See pic)  

Len_CONSULTRON_2-1618777731067.png

This output is used to frame the SW read of the FIFO byte.

In your code that reads the FIFO byte:

while(((UART_2_ReadRxStatus()&UART_2_RX_STS_FIFO_NOTEMPTY)>0)&&(received_bytes<24))
{ 
  n= UART_2_ReadRxData();	//GetByte				
  pll_data_receive[received_bytes]=n;
  received_bytes++;
}

Change to:

while(((UART_2_ReadRxStatus()&UART_2_RX_STS_FIFO_NOTEMPTY)>0)&&(received_bytes<24))
{ 
  Read_FIFO_byte_frm_Write(1);  // turn on the frame
  n= UART_2_ReadRxData();	//GetByte				
  Read_FIFO_byte_frm_Write(0);  // turn off the frame
  pll_data_receive[received_bytes]=n;
  received_bytes++;
}

This signal is a combination of HW and SW dependent.  It is HW because it frames the ReadRxData() function but since it is in code, it can be pre-empted by other events such as other interrupts or DMA (if you have that turned on).

Create a HW signal for when the Data Error occurs

Allocate another digital output pin.  (See pic)  

Len_CONSULTRON_4-1618778632132.png

This is a SW-dependent signal that flags to the outside world that a data error occurred.

In your modified code that reads the FIFO byte:

while(((UART_2_ReadRxStatus()&UART_2_RX_STS_FIFO_NOTEMPTY)>0)&&(received_bytes<24))
{ 
  Read_FIFO_byte_frm_Write(1);  // turn on the frame
  n= UART_2_ReadRxData();	//GetByte				
  Read_FIFO_byte_frm_Write(0);  // turn off the frame
/* Analyze if a data error occurred */
  if(... code that determines an error occurred ...)
  {
    Data_ERROR_Write(1);  // turn on the frame
    Data_ERROR_Write(0);  // turn off the frame
  }
  pll_data_receive[received_bytes]=n;
  received_bytes++;
}

 

Analysis Phase

Now that you have the three HW signals on an oscilloscope or logic analyzer, look for when the Data_ERROR signal is valid (you can probably trigger on that event) and now you should have the timing relationship that occurs when the new byte is received into the FIFO and when the FIFO read occurs.

If you share these results with me (or the forum) others will have a much better time to replicate your results.

 

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
lock attach
Attachments are accessible only for community members.

hi,

i did as you suggested, and attached the results, i think i understand now what the problem is, can you please help in solving that?

thanks for all your help.

0 Likes

ezbe,

I'm still digesting your latest revD doc.

However, I believe I understand the nature of the issue you are having and can venture a possible solution.

The Issue

The Rx and Tx Status registers reflecting the current status of the UART are "clear on read".   This would mean if more than one 'task' (main(), isr_1 or UART_Rx_isr) performs a UART_2_ReadRxStatus() or UART_2_ReadTxStatus(), the value of the immediate status will be true for the first task that reads it.  In addition, the UART_RX_STS_FIFO_NOTEMPY bit flag is clear when ALL the available data is read from the FIFO.

The result is that multiple tasks monitoring the UART status registers may not have accurate status information because it is read (or data is pulled from the FIFO) by another task.

It's a classic situation of the "left hand not knowing what the right hand is doing".

The Potential Solution

The most common way to solve this issue is to perform "isolation and abstraction".  In other words, isolate the UART HW operations into a single task.  If you have a UART_Rx_isr, then perform all UART Rx HW operations in this one task.   

This prevents the other tasks from needing to know about the UART HW resources and API calls.   Not only does this prevent the issue mentioned above but it also disassociates the other tasks from each other.   For example, the isr_1 task does not need to know about whether a UART resource is present.   With proper coding on the isr_1, I2C, SPI or other communication method can be easily substituted for variations in the design.  This is a form of 'abstraction'.

Now you're probably asking:  How does isr_1 know when there is data available?

In the UART Rx HW task, when data is available, it is read (clearing the UART_RX_STS_FIFO_NOTEMPY flag in the RxStatus reg) and the data is placed in a RAM buffer.  Additionally the UART Rx HW task, signals all other tasks needing this data relevant information by placing flag(s) and other information in sharable RAM between the tasks.

The receiving tasks (isr_1 for example) would read this data information RAM and grab the data and clear any flags so that the UART Rx HW task can update the data RAM with new info as it comes in.

I'll give your revD doc another look shortly.

Hopefully this lengthy description might be of use.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

ezbe,

I've provided a first pass at a potential reason and solution.

Hopefully it helps.

I've taken another closer look at your revD doc.  I have a few observations.

Observation1

You list: Software (inside of isr_1):

Len_CONSULTRON_0-1619008904439.png

The while() loop (as well as do()) is very 'dangerous' inside an ISR.   The general rule-of-thumb for ISRs is to "get in and get out quickly".   ISR are intended to service the immediate needs of an event.  In the case of isr_1 it is the 30Hz 'tick'.  

Avoid using blocking functions (CyDelay() is terrible) or blocking code such as while() and do().   The while() loop is time-indeterminate.  There is NO guarantee that the conditions to satisfy the while() will occur in a timely manner.  You could be stuck in isr_1 for a long time and the other interrupt tasks and main() may not be serviced properly.

Recommendation:  In the isr_1 which is the 30Hz tick, create a flag in RAM:  _Bool tick_30Hz.   In the isr_1, set 

tick_30Hz = 1;  

 In the main() task

while(tick_30Hz == 1) 
{ /* The 30Hz tick occurred */
  tick_30Hz = 0; /* reset the flag */
/* place your code here to process the 30 Hz tick */
}
... /* go do other things as needed */

 

Observation2

It appears you are potentially using ALL the bytes of the 4-byte FIFO.

The FIFO is intended to buffer in case the CPU is experiencing latencies in getting to the data.   As a general rule, it is best to code as if  you don't have a FIFO.

Recommendation:   If you don't already have one, create a UART_RX_isr component and place it on the UART_2 rx_interrupt pin.

In the isr code for this interrupt (let's call it isr_UART_RX), allocate enough buffer data in RAM needed for the 30Hz tick to process.  

In the isr_UART_RX() for every byte you receive, store it in the RAM Rx buffer and increment a variable called rx_idx.  The rx_idx > 0 can signal the 30Hz tick task that data is available.   This is ALL the UART_RX_isr does.  Short and sweet.

uint8 rx_buffer[4]; /* 4 bytes in the buffer */
_Bool rx_idx=0;  /* rx buffer count idx */

CY_ISR(UART_RX_isr)
{
  rx_buffer[rx_idx] = UART_2_ReadRxData();
  rx_idx++;
}

In the main() task that processes the 30Hz tick subtask, check for tick_30Hz flag (see code frags above).  If set,  process all the data (as indicated by buffer_idx)  in the RAM Rx buffer.  Lastly before exiting the 30Hz tick subtask, you need to do cleanup.

while(tick_30Hz == 1) 
{ /* The 30Hz tick occurred */
  tick_30Hz = 0; /* reset the flag */
/* place your code here to process the 30 Hz tick */
   ...  /* process the Rx Buffer data as needed */
/* Lastly do cleanup */
  UART_DisableRxInt()  /* Temporarily disable the UART_Rx interrupt during the cleanup */
  rx_idx = 0;  /* reset the Rx buffer index */
  UART_EnableRxInt()  /* re-enable the UART_Rx interrupt */
}
... /* go do other things as needed */

 

Len
"Engineering is an Art. The Art of Compromise."

Hi Len,

The root of the issue here is that the bit for the RX interrupt signal "RX - On Byte Received" is the same bit as "UART_RX_STS_FIFO_NOTEMPTY" (According to the UART data sheet page 9). And as can be seen in the scope picture "RX - On Byte Received" goes to '0' for the 9us duration of the received stop bit. Therefore if the "UART_RX_STS_FIFO_NOTEMPTY" flag is read during the 9us of the stop bit (very possible) one might think the FIFO is empty when it is not!! 

The conclusion would be that the UART RX can't EVER be read asynchronously and must be read with an interrupt?

0 Likes

michael,

Theoretically, if you had an ISR for just "RX - On Byte Received" AND you read ALL the Rx bytes from the FIFO using a for() loop with UART_GetRxBufferSize() and UART_GetChar() this should eliminate any collision with the UART_RX_STS_FIFO_NOTEMPTY status bit.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

So it is not possible to use the uart RX without using an isr?

0 Likes

Michael,

You don't need to use an ISR.  You can poll the UART Rx status in the main() loop task.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

hi,

the problem is this:

my isr is every 278usec, with no Interrupt source selected in uart.

when i check if FIFO not empty in the main isr, i sometimes get that FIFO is empty, eventhought it is not empty.

when i checked why, i found that the RX_FIFO_NOT_EMPTY is the same as RX_ON_BYTE_RECEIVED so every byte that the uart gets that signal drops down for 9msec, even though the FIFO is still not empty, why is that? why does the RX_FIFO_NOT_EMPTY  signal goes to zero with every byte received ?

 

 

0 Likes
shinsakka
Level 1
Level 1
5 replies posted First like received First reply posted

Cypress' UART component (at least up to version 2.50) is buggy. The fifo-not-empty signal is only valid if there's not more than one byte in the fifo.

The UART component works as long as you poll the UART at least once every byte received: for example at least every 86 µs for 115'200 bps / 8N2). Same for the UART ISR (must be executed before 2nd byte has been received).

As a workaround, I modified the verilog description and repaired the generation of the not-empty signal. (...a few years ago, would have to look up the details).

0 Likes

hi,

how can i modify the verilog of the UART in Psoc?

thanks

0 Likes

Basically by customizing the existing component:

  • import components into your project (alternatively, create a library project): UART_v2_50 and B_UART_v2_50 (both from CyComponentLibrary)
  • optionally rename them or assign new version number (tedious process, several files need to be edited manually)
  • edit the B_UART_v2_50 instance in the UART_v2_50 schematic to point to your own version (probably not necessary if you keep the component names)
  • the verilog file in question is "B_UART_v2_50.v"
  • I also added a new input signal to feed the busclock into the component. As far as I remember, it was required to correctly cross the clock domains from uart component clock to busclock (i.e., fifo signals facing bus side)
0 Likes

 

can you please share what you have changed?

thanks.

0 Likes