Microblaze Trace …

Hi, I have download “Tracealyzer for FreeRTOS” to do some testing on Microblaze CPU. I have used “FreeRTOS Snapshot Recorder v3.0.9.zip”. I followed the guide but I somehow doubt from this point on: I have create a project with one task that flashes a LED. The program runs smoothly with no integrated trace. FreeRTOS v9.0.0 with Microblaze CPU + Snapshot Recorder v3.0.9 from Percepio I have add this code at the end of “FreeRTOSConfig.h”: ~~~ /* Include the FreeRTOS+Trace FreeRTOS trace macro definitions. */

define TRACEENTERCRITICALSECTION() portENTERCRITICAL()

define TRACEEXITCRITICALSECTION() portEXITCRITICAL()

include “trcKernelPort.h”

~~~ The compilation is successful, but if I start the program this crash. In debug I noticed that after three, four calls to the Trace functions, the program crash. I then decided to change code in “FreeRTOSConfig.h” with this: ~~~ /* Include the FreeRTOS+Trace FreeRTOS trace macro definitions. */

define TRACEENTERCRITICALSECTION() /* portENTERCRITICAL() */

define TRACEEXITCRITICALSECTION() /* portEXITCRITICAL() */

include “trcKernelPort.h”

~~~ I basically removed the definitions of “ENTER” and “EXIT” from critical section, In this way the program runs quietly and I can generate the trace in memory statically and then be discharged after a few minutes of operation. The thing is very strange, but how can I check ? I would be confident about this, because I would buy the tool, but I would try the real utility before proceeding. Thanks very much. debugasm

Microblaze Trace …

A couple of questions: Did you call vTraceInitTraceData(); before calling uiTraceStart()? Did you see
How to define critical sections for the trace recorder?
?

Microblaze Trace …

Yes, I have call both functions before start scheduler. I have follow the FreeRTOs example for Win32 : “FreeRTOSPlusCLIwithTraceWindowsSimulator” but with the appropriate changes for Microblaze. The function: ~~~ portENTERCRITICAL() portEXITCRITICAL() ~~~ Already allows nested interrupts, right ? I also followed the guidance for Zynq: ~~~
Getting started with Tracealyzer on Xilinx Zynq
~~~ debugasm

Microblaze Trace …

I don’t think interrupt nesting is supported on the Microblaze (not to be confused with critical section nesting, which is supported). The Microblaze macros make use of the Xilinx library function microblazedisableinterrupts() to disable interrupts, and that does not appear to support nesting.

Microblaze Trace …

It’s true but FreeRTOS have this : ~~~ /* Critical section macros. */ void vPortEnterCritical( void ); void vPortExitCritical( void );

define portENTER_CRITICAL(){

extern volatile UBaseType_t uxCriticalNesting;      
microblaze_disable_interrupts();                    
uxCriticalNesting++;                                
}

define portEXIT_CRITICAL() {

extern volatile UBaseType_t uxCriticalNesting;      
/* Interrupts are disabled, so we can */            
/* access the variable directly. */                 
uxCriticalNesting--;                                
if( uxCriticalNesting == 0 )                        
{                                                   
    /* The nesting has unwound and we                 
          can enable interrupts again. */                   
           portENABLE_INTERRUPTS();                       
}                                                   
} ~~~ So it can not be used with FreeRTOS+Trace on Microblaze ?

Microblaze Trace …

Microblaze is the Xilinx softcore, Zynq is an ARM CortexA9. Dont follow the instructions for a totally different part!

Microblaze Trace …

Sorry, I know Zynq and Microblaze very well, I have used and use both long enough. Before you start writing a line of code I have documented “on principle of operation of trace”. Know that Zynq and Microblaze are different, and that are not compatible. But understand the principle, you can work on any cpu. I followed the examples and guides:
  • FreeRTOSPlusCLIwithTraceWindowsSimulator
  • FreeRTOS-Plus-Trace
  • FreeRTOSPlusTrace_Recorder
  • http://percepio.com/2016/09/13/tracealyzer-for-freertos-on-xilinx-zynq/
  • Snapshot Recorder on Traceanalyzer guide:
~~~ To integrate the recorder trace library in an existing FreeRTOS project, the following steps are suggested: (1) Check that your FreeRTOS version is v7.3 or later. (2) Locate the Snapshot recorder library package via the Help menu in Tracealyzer and extract its contents. (3) Add the .c files from GenericRecorderLibSrc in your build project. (4) Add GenericRecorderLibSrc/Include to your compiler’s include path (i.e., in the project settings). (5) Copy GenericRecorderLibSrc/ConfigurationTemplate/trcConfig.h to GenericRecorderLibSrc/Include. (6) Open trcConfig.h and…
    - Set SELECTED_PORT to match your target processor.
    - Verify that the FREERTOS_VERSION setting matches your 
        version of FreeRTOS.
    - Check the N[Type] settings (e.g., NTask, NQueue, etc.). 
        They define the maximum allowed number of simultaneously
        active objects, i.e., objects that have been created by 
        not deleted.
    - Check the other settings, especially TRACE_RECORDER_STORE_MODE
        and EVENT_BUFFER_SIZE. You don't need to change them, but we
        recommend you have a look. 
(7) In your FreeRTOSConfig.h, make sure you have the following setting.
    - #define configUSE_TRACE_FACILITY 1
(8) Add the following line in the very end of your FreeRTOSConfig.h
    #ifndef __ASSEMBLER__
        #if configUSE_TRACE_FACILITY == 1
            #define TRACE_ENTER_CRITICAL_SECTION() portENTER_CRITICAL()
            #define TRACE_EXIT_CRITICAL_SECTION() portEXIT_CRITICAL()
            #include "trcKernelPort.h"
        #endif
   #endif
(9) In your main() routine, call vTraceInitTraceData() as early as possible. It must be placed before any other calls to the recorder or FreeRTOS. (10) Call uiTraceStart() at the point you wish to begin recording, in the startup or at some later point in the application code. Remember to check the return value. A value of 1 indicates that the recorder configuration was OK. Otherwise an error message is found in RecorderDataPtr->systemInfo. ~~~ Compilation successful, but FreeRTOs crash. After comment “portENTERCRITICAL()” and “portEXITCRITICAL()” all work but I can not say if properly although the trace buffer is filled normally. Other ideas ? debugasm

Microblaze Trace …

I posted this yesterday, but for some reason it has not shown up. It might show up twice now… I’m reading the page I just linked to and can’t see why you are coming to that conclusion. From the page: “If you are using a FreeRTOS port that doesn’t implement portSETINTERRUPTMASKFROMISR and portCLEARINTERRUPTMASKFROMISR, you need to define TRACEENTERCRITICALSECTION and TRACEEXITCRITICALSECTION yourself (see trcKernelPortFreeRTOS.h.). However, in such FreeRTOS ports there are no nested interrupts, so critical sections are only needed in task-context. In this case, a generic solution is:
#define TRACE_ENTER_CRITICAL_SECTION() if (IN_TASK_CONTEXT) portENTER_CRITICAL()
#define TRACE_EXIT_CRITICAL_SECTION()  if (IN_TASK_CONTEXT) portEXIT_CRITICAL()
Another solution is to implement a something like the portSETINTERRUPTMASKFROMISR solution above. That design is required if your chip allows for nested interrupts.” So it looks like you just need to implement INTASKCONTEXT for the Microblaze, in other words, find a way of knowing if you are inside a critical section or not, and only call portENTER/EXIT_CRITICAL() when you are. Is there a register you can read in the Microblaze that tells you if you are in an interrupt or not? Normally there would be such a thing. …just looking now. The mfmsr() function returns the ‘machine status register’ which has a Exception In Progress bit (EIP, bit 22). If that is 1 then a hardware exception is in process. I’m not sure if it is also set to 1 when a standard interrupt, rather than an error exception, is in process but you can check that. So INTASKCONTEXT would then become:
#define IN_TASK_CONTEXT ( ( mfmsr() & ( 1 << 22 ) ) == 0 )
NOTE: I have not checked if the bit is set inside an interrupt, as well as an exception, so please check that and find an alternative if it isn't. These are not FreeRTOS questions though, but hardware questions, so I will leave that to you ;o)

Microblaze Trace ...

As always with your help, you reach always the goal. I thought that FreeRTOS+Trace was already integrated enough, but from what you've made me read, not for all CPUs. Taking a cue from what you have written, I have documented better. Basically: ~~~ Machine Status Register (MSR) EIP = bit 22
Exception In Progress

0 = No hardware exception in progress
1 = Hardware exception in progress
Only available if configured with exception support
Hardware Exceptions (EIP) trap the following internal error conditions:
illegal instruction
instruction and data bus error
unaligned access
with hardware divider
divide exception
with hardware floating point unit:
underflow
overflow
float division-by-zero
invalid operation
denormalized operand error
with a hardware Memory Management Unit:
Illegal Instruction Exception
Data Storage Exception
Instruction Storage Exception
Data TLB Miss Exception
Instruction TLB Miss Exception
~~~ This bit remain untouched during interrupt therefore it can not be used for the purpose. Documenting best I found this: ~~~ Machine Status Register (MSR) IE = bit 30
Interrupt Enable

0 = Interrupts disabled
1 = Interrupts enabled
The processor disables future interrupts by clearing the IE bit in the MSR. The IE bit is automatically set again when executing the RTID instruction. ~~~ So during any interrupts in the processor clear MSR "IE" (bit 30) to prevent others interrupts (prevents nesting). So I modified the code suggested by you in this way: ~~~ /* During any interrupts in the processor clear MSR "IE" (bit 30) */

define INTASKCONTEXT ( ( mfmsr() & ( 1 << 30 ) ) == 1 )

define TRACEENTERCRITICALSECTION() if (INTASKCONTEXT) portENTERCRITICAL()

define TRACEEXITCRITICALSECTION() if (INTASKCONTEXT) portEXITCRITICAL()

~~~ Compiling again with these changes and restarting the debugging, now everything works perfectly. I also modified version of "Trace-Streaming" using a serial port and it works perfectly well with this. I do other tests, if not finding other problems, I would say that everything works fine. Inspecting the first recorded Trace would say that the tool is amazing, you can see many things more. Really nice. Thanks very much. debugasm

Microblaze Trace ...

Many thanks for documenting your Microblaze fix. Since FreeRTOS is available for so many architectures, we have not yet been able to provide official ports for all. The current Microblaze port is tagged as "unofficial", meaning that we have received it from a third party but not yet verified it ourselves. But we will take this opportunity integrate your fix, verify and provide it as an official port. I hope this can be done by the Tracealyzer v3.1.1 release, probably in december. The upcoming release v3.1.0 is in code freeze now, a shame I didn't see this earlier... For questions regarding the FreeRTOS trace recorder, I recommend contacting support (at) percepio.com, where our friendly support engineer Niclas will help you out.

Microblaze Trace ...

The working code is this: ~~~

if (SELECTEDPORT == PORTXILINX_MICROBLAZE)

#define TRACE_SR_ALLOC_CRITICAL_SECTION() int __irq_status;

/* Byte Order */
#if XPAR_MICROBLAZE_ENDIANNESS
    /* 
     * MicroBlaze Little-Endian Working
     *
     * If interrupt enable, interrupt clearing the IE bit in the MSR 
     */
    #define IN_TASK_CONTEXT ( ( mfmsr() & ( 1 << 1 ) ) != 0 )
#else
    /* 
     * MicroBlaze Big-Endian Not Tested !!! 
     *        
     * If interrupt enable, interrupt clearing the IE bit in the MSR
     */
    #define IN_TASK_CONTEXT ( ( mfmsr() & ( 1 << 30 ) ) != 0 )
#endif

#define TRACE_ENTER_CRITICAL_SECTION() __irq_status = IN_TASK_CONTEXT; if (__irq_status) portENTER_CRITICAL()
#define TRACE_EXIT_CRITICAL_SECTION() if (__irq_status) portEXIT_CRITICAL()

endif

~~~ Add this at the end of "FreeRTOSConfig.h" ~~~ /* Prevent the function prototypes being included from asm files. */

ifndef ASSEMBLER

#if configUSE_TRACE_FACILITY == 1
    #include "trcKernelPort.h"
#endif

endif

~~~ If user want same address for recordi data use linker script to place recorder data on section of memory: ~~~ RecorderDataType RecorderData attribute((section(".trace"))); ~~~ On Linker script: ~~~ MEMORY { ... TRACE_BASEADDR : ORIGIN = 0x84000000, LENGTH = 0x00400000 ... } .trace (NOLOAD) : { . = ALIGN(8); trace = .; } > TRACEBASEADDR ~~~ I did not forget anything, I think. debugasm