Summary
In the last Article I showed you how to use the JLINK RTT Streamport to make Tracealyzer work. When I did that port I didn’t really like having to use a JLink, it seemed like a pain to have another box. I knew that it was possible to make a UART based Streamport. So, that is what I am going to do, create a Tracealyzer PSoC Streamport. This Article is going to be broken up into two parts. In Part 1 I will show you a software based port and the problems that it creates. In Part 2 I will show you how to use DMA to hopefully (as I haven’t done the work yet) make it work much better. I was hoping this morning when I started working on this Article that it would only take me a couple of hours, but that did not turn out to be the case as I ran into a PSoC Creator bug which made it hard to figure out what was going on.
Cypress USB Serial Bridge & CY8CKIT-049
If you remember from the last article, the Tracealyzer needs to stream about 20KBs. That is a big B as in Bytes. Which means that a 115200 Kbs (aka 14.4 KBs) UART probably won’t do the trick. That is OK as the PSoC SCB UART can run at up to 921600 aka 115.2 KBs. The problem is the Kitprog bridge on my development kit is limited to 115200 (I’m not sure why) I didn’t realize that limitation this morning when I started working on this problem. But it turns out that the CY8CKIT-049 has a Cypress USB Serial Bridge.which is used to boatload the PSoC4200. And… it is designed to break off the kit.
So I broke it off and gave it to my lab assistant to solder (he isn’t normally that grumpy, but he stayed up all night at a birthday party)
Now I have two wires which I can use to talk to the CY8CKIT-044 UART.
After I got the wires on the bridge, I installed the USB Serial Configuration Utility and set the chip up to be 921600 baud. To do this, run the utility.
Connect to your bridge, in this case the CY7C65211-24LTXI
Then pick the SCB (which stands for Serial Communication Block)
Click the configure, then set the baud to 921600.
Now, I wire the two kits together (the Jlink is just sitting there)
Creating a Tracealyzer PSoC UART Streamport
The first thing to do is modify the previous project to also have a UART.
Then connect the UART to Pins P3[0] & P3[1]
To make the Tracealyzer PSoC Streamport work I make a copy of the TraceRecorder/streamports/USB_CDC and called it PSoC_UART. After I cut all all of the ST USB crap, I realized that all I need to provide is a
- A function to receive bytes … called PSoC_Receive
- A function to transmit bytes… called PSoC_Transmit
Next you need to modify these 10 CPP Macros to support the Tracealyzer PSoC Streamport. (I only had to modify INIT, READ and SEND)
- TRC_STREAM_PORT_ALLOCATE_FIELDS
- TRC_STREAM_PORT_MALLOC
- TRC_STREAM_PORT_INIT
- TRC_STREAM_PORT_ALLOCATE_EVENT
- TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT
- TRC_STREAM_PORT_COMMIT_EVENT
- TRC_STREAM_PORT_READ_DATA
- TRC_STREAM_PORT_PERIODIC_SEND_DATA
- TRC_STREAM_PORT_ON_TRACE_BEGIN
- TRC_STREAM_PORT_ON_TRACE_END
In addition I provide function prototypes for PSoC_Receive and PSoC_Transmit which are called by TRC_STREAM_PORT_READ_DATA and TRC_STREAM_PORT_PERIODIC_SEND_DATA
// An Adaption of the Percepio CDC Library to PSoC SCB UART #include <project.h> #ifndef TRC_STREAMING_PORT_H #define TRC_STREAMING_PORT_H #ifdef __cplusplus extern "C" { #endif /******************************************************************************* * Implement the below macros to define your own stream port. If your transfer * method uses RTOS functions, you should not send the data directly but use * the recorder's internal buffer to store the trace data, for later transfer by * the TzCtrl task. Check the predefined stream ports for examples on how to use * the internal buffer (e.g., TCP/IP, UART or USB CDC). * * Read more at http://percepio.com/2016/10/05/rtos-tracing/ ******************************************************************************/ int32_t PSoC_Receive(void *data, uint32_t size, int32_t *numOfBytesReceived); int32_t PSoC_Transmit(void *data, uint32_t size, int32_t *numOfBytesSent ); #if TRC_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_STATIC #define TRC_STREAM_PORT_ALLOCATE_FIELDS() static char _TzTraceData[TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT * TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE]; /* Static allocation. */ #define TRC_STREAM_PORT_MALLOC() /* Static allocation. Not used. */ #else #define TRC_STREAM_PORT_ALLOCATE_FIELDS() static char* _TzTraceData = NULL; /* Dynamic allocation. */ #define TRC_STREAM_PORT_MALLOC() _TzTraceData = TRC_PORT_MALLOC(TRC_PAGED_EVENT_BUFFER_PAGE_COUNT * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE); #endif #define TRC_STREAM_PORT_INIT() \ UART_Start(); \ TRC_STREAM_PORT_MALLOC(); /*Dynamic allocation or empty if static */ #define TRC_STREAM_PORT_ALLOCATE_EVENT(_type, _ptrData, _size) _type* _ptrData; _ptrData = (_type*)prvPagedEventBufferGetWritePointer(_size); #define TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(_type, _ptrData, _size) TRC_STREAM_PORT_ALLOCATE_EVENT(_type, _ptrData, _size) /* We do the same thing as for non-dynamic event sizes */ #define TRC_STREAM_PORT_COMMIT_EVENT(_ptrData, _size) /* Not needed since we write immediately into the buffer received above by TRC_STREAM_PORT_ALLOCATE_EVENT, and the TRC_STREAM_PORT_PERIODIC_SEND_DATA defined below will take care of the actual trace transfer. */ #define TRC_STREAM_PORT_READ_DATA(_ptrData, _size, _ptrBytesRead) PSoC_Receive(_ptrData, _size, _ptrBytesRead); #define TRC_STREAM_PORT_PERIODIC_SEND_DATA(_ptrBytesSent) prvPagedEventBufferTransfer(PSoC_Transmit, _ptrBytesSent); #define TRC_STREAM_PORT_ON_TRACE_BEGIN() { prvPagedEventBufferInit(_TzTraceData); } #define TRC_STREAM_PORT_ON_TRACE_END() /* Do nothing */ #ifdef __cplusplus } #endif #endif /* TRC_STREAMING_PORT_H */
The last thing to make this work is provide the C function to read and write the UART by modifying trcStreamingPort.c
// An adataption of the Percepio USB_CDC Port to PSoC Serial #include "trcRecorder.h" #if (TRC_USE_TRACEALYZER_RECORDER == 1) #if(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) #include "stdint.h" int32_t PSoC_Receive(void *data, uint32_t size, int32_t *numOfBytesReceived) { uint8_t *myData= (uint8_t *)data; *numOfBytesReceived = 0; while( (*numOfBytesReceived < (int32_t)size) && UART_SpiUartGetRxBufferSize()) { myData[*numOfBytesReceived] = UART_SpiUartReadRxData(); *numOfBytesReceived += 1; } return 0; // Doesnt matter what you return... i dont think that it is checked } int32_t PSoC_Transmit(void* data, uint32_t size, int32_t *numOfBytesSent ) { UART_SpiUartPutArray((uint8_t *)data,size); *numOfBytesSent=size; return 0; // Doesnt matter what you return... i dont think that it is checked } #endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/ #endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/
There at two things that are a bit goofy.
- The return values for both of these function is not used by the calling functions… and is not defined what it means.
- The 3rd parameter of both functions is defined as int32_t, but in the TraceRecorder library it is defined as int. This makes a warning, which I got rid of by fixing the bug in the Percepio code.
Testing
To test this you need to change the Tracealyzer settings from JLink to Serial and fix the COM port and baud rate.
When I built this code originally, I tried 115200 baud. But it didn’t work at all (it locked up FreeRTOS). Then I tried 921600 which locked up the Tracealyzer. I am running Tracealyzer and PSoC Creator on a Mac in a VMWare Fusion Windows 7 box and I am pretty sure that there is a USB bridging problem (I am going to try it on a Windows box). After grinding for a while I found out that both 230400 and 460800 both worked but both showed something very funny, look at the data:
230400 Baud
460800 Baud
I knew that my implementation of the Percepio Tracealyzer PSoC Streamport would be demanding on the CPU, but I did not predict that it would take 30-50% of the CPU. This is definitely a problem as the JLink RTT Streamport only takes 0.4% of the CPU. To fix this I am going to try using the PSoC4200M DMA to automatically transfer the buffers to the UART. Hopefully that will make my Tracealyzer PSoC streamport better. But that is for the next Article.
As always you can find all of these projects on the IotExpert GitHub site or git@github.com:iotexpert/PSoC-Tracelyzer.git
Article
Description
Percepio Tracealyzer & PSoC
An Introduction to Percepio Tracealyzer on the Cypress PSoC
Percepio Tracealyzer RTT Streamport - PSoC4200M
Make the JLINK RTT Library work with Tracealyzer
Percepio Tracealyzer PSoC UART Streamport
Creating a UART Streamport
Percepio Tracealyzer - Analyzing the PSoC Tracealyzer Streamport
Figure out what is broken in the UART Streamport
Percepio Tracealyzer - Using PSoC DMA to Fix the UART Streamport
Implementing PSoC DMA to improve the CPU Utilization
Percepio Tracealyzer - Running on PSoC6
Porting the Percepio Tracealyzer to PSoC6
2 Comments
Thank you. I am supporting legacy hardware with no DMA. Changing the UART TX buffer made huge improvements for the CPU efficiency. I am running for this data
CYBC4248LQI-583
CY8CKIT-042-BLE Pioneer Baseboard
FreeRTOS 10.0
Tracealyzer for FreeRTOS 3.3
Creator 4.1
RX buffer 64
5 – 7 seconds of data for each test
at 921600 I get
TX buffer avg CPU Low CPU High CPU
64 16.29 15.51 18.54
128 15.36 12.28 20.39
256 13.23 9.42 18.43 13.95
512 8.97 8.40 11.82 9.01
1024 5.92 5.53 8.18
2048 5.93 5.47 8.04
I can get an extra 0.5% average improvement by increasing the Rx buffer to 256,
Where there are two numbers for the highs, there was a flyer
My system doesn’t reliably connect at the lower baud rates. When using actual hardware, not an eval board I change the oversampling to 13 for a more reliable connection to my external uart bridge.
Danny
Nice work