Aurix 2G Free Entry Tool Chain Interrupt on all cores

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

cross mob
TBencher
Level 6
Level 6
25 solutions authored 25 likes received 5 questions asked
Hi there,

recently I got a Triboard with an Aurix 2G on it. Programming on all cores is really straight forward except if it comes to interrupts.
Interrupts do work only on core 0. There seems no way enabling -for example GTM- interrupts on the other cores.
Why is that? Since the examples from HighTech didn't come with multicore application examples, I've tried to just
implement a view iLLD based instructions, but only an interrupt for core 0 did work.

I've searched for nearly everything with the debugger, but it makes really no sense why cores 1 to 5 don't accept interrupts.

Further, I did not found any appropriate documentation on how to program multicore style applications without having overloaded multithreading, semaphore and other mechanisms.

I just need to run a small test multicore application where cores have there own timer like interrupts to handle core specific time constraints.

I would really appreciate your help.

Thank you.
0 Likes
34 Replies
lock attach
Attachments are accessible only for community members.
User13290
Level 5
Level 5
First like received First solution authored
Hi Jens,
JensM wrote:
Hi there,

recently I got a Triboard with an Aurix 2G on it. Programming I would really appreciate your help.

Thank you.


I have attached an example that I created at the close of last year. While it is not for 2nd generation AURIX it should not be too difficult to migrate. To use it within your project use the following steps:


  • Select 'File | Import' MENU
  • Expand 'General' group from the input sources WIZARD
  • Select 'Existing Projects into Workspace' INPUT SOURCE
  • Click 'Next' BUTTON
  • Click 'Select archive file' RADIOBUTTON
  • Click 'Browse' BUTTON and select jens.zip
  • Click 'Finish' BUTTON


The project is divided into 'bsp' and 'app' folders. The former contains system board support package code which is actually in your toolchain. The latter are the bits and pieces that I added myself. Regarding the bsp the modules that are worth exploring are cint_tc29x.c and interrupts.c. These implement a low-level and application level interrupt API that help you setup parameterised interrupt service routines. Together they implement an interrupt vector table that is shared between cores. On application level modules applproc{0,1,2}.c initialise the interrupt system via the call to main_init. Each core needs to individually enable the interrupt system on their end. There's much more that can be told about the example, but I'll leave you to explore it first. We can then discuss the finer details if there's anything that remains unclear.

Best regards,

Henk-Piet Glas
Principal Technical Specialist
0 Likes
TBencher
Level 6
Level 6
25 solutions authored 25 likes received 5 questions asked
Hi Henk,

thanks for your answer. I'm gonna try this.

Regards,

Jens
0 Likes
User13290
Level 5
Level 5
First like received First solution authored
Hi Jens,

JensM wrote:

thanks for your answer. I'm gonna try this.


Hope it works out, but let me know if you need help.

Best regards,

Henk-Piet Glas
0 Likes
TBencher
Level 6
Level 6
25 solutions authored 25 likes received 5 questions asked
Hi Henk,

unfortunately your example does not help.
What I am searching for is a straight forward way to implement interrupts on all cores with less coding effort.
Lets say for example we wanna implement a STM on each core with different frequencies.
In my understanding I just need to invoke a compare config variable and initialize it with trigger priority, comparator interrupt and type of service for example.
After this the configuration needs to be load lets say in MODULE_STM0 with the function IfxStm_initCompare.

Then comes the following:

IFX_INTERRUPT (UsrIsr_Stm_0, 0, 60);

void UsrIsr_Stm_0(void)
{
IfxStm_clearCompareFlag(&MODULE_STM0, IfxStm_Comparator_0);
IfxStm_increaseCompare(&MODULE_STM0, IfxStm_Comparator_0, IFX_CFG_STM_TICKS_PER_MS);
P33_OUT.B.P4 = ~P33_OUT.B.P4;
}

...just toggle a LED at the given frequency

The thing is that this code actually works really good on core 0.
But it does not on the other cores with different TOS.

I assume problems with the interrupt table, which normally needs to be unique to its core.
Therefore, where can I change the interrupt table configuration in the HighTech Free Toolchain configuration?

Even GTM multicore interrupt examples from other sources, which are definitely testet before, do not work inside my Free Toolchain environment.

Probably, my setup is limited to have interrupts just on core 0. Is that true?


Regards,

Jens
0 Likes
TBencher
Level 6
Level 6
25 solutions authored 25 likes received 5 questions asked
Hi Henk again,

please don't misunderstand me. I expect the full range of functionality with the FreeEntryToolChain, not anything else.
There must be a straight forward way, ideally with documentation, how to implement interrupts for more than just one core.
As an experienced developer, it would be a real shame to call the FAE for just doing this.

If you have an example which definitely works with the FreeEntryToolChain, please let me know.


Thank you.

Regards,

Jens
0 Likes
TBencher
Level 6
Level 6
25 solutions authored 25 likes received 5 questions asked
Hi Henk,

finally I did it. All cores have their own STM support.
The answer is, yes the FreeEntryToolChain does support interrupts on different cores.
Please apologize my messages before.

Thank you.

Regards,

Jens
0 Likes
User13290
Level 5
Level 5
First like received First solution authored
Hi Jens,

JensM wrote:
Hi Henk,

finally I did it. All cores have their own STM support.
The answer is, yes the FreeEntryToolChain does support interrupts on different cores.
Please apologize my messages before.

Thank you.

Regards,

Jens


No problem, and good to hear you got it sorted. Let me know if some of it still needs clarification.

Best regards,
Principal Technical Specialist
0 Likes
Not applicable
Hello,

I am working on tricore tc299tf and trying to initialize system timer interrupt. I have tried to use the examples that are explained here however my timer interrupt is still not working perfectly. I want to get tick every 1microsec. Could anyone help me with the issue ?

Thank you
Praktikant
0 Likes
User13290
Level 5
Level 5
First like received First solution authored
Hi,

Praktikant wrote:
Hello,

I am working on tricore tc299tf and trying to initialize system timer interrupt. I have tried to use the examples that are explained here however my timer interrupt is still not working perfectly. I want to get tick every 1microsec. Could anyone help me with the issue ?

Thank you
Praktikant


It's my guess that your immediate need is to experiment and get the system timer running at 1 us. While this thread does indeed focus on the system timer it also introduces an extra layer of complexity through its multi-core nature. It might be advisable to start single core at first, but it obviously depends on your need whether that's acceptable or not.

If single core is OK for now, then you should be able to get things running by means of tweaking the timedemo that I'm referring to in the other thread you also posted to. I'm referring to my posting on 30JUL2017 specifically. This example contains a function called TimerInit() which calculates at runtime the reload value based on the ratio of the system clock frequency and your desired frequency. Since you're after a 1 us tick, feeding it with 1e6, should be a step in the right direction.

You can also decide to use the iLLD library. Like our example, it also offers functions that can dynamically calculate the number of ticks that are required to trigger an interrupt every 1 us. You'd need IfxStm_getTicksFromMicroseconds() for that. This can be made to work also, although I expect it introduces an additional learning curve for getting a good grasp on the iLLD API.

It's probably best to first consider the above two choices and decide which one suits you best. My advise would be to start with the example included in the product and work from there. My posting explains how to rig it up. Obviously, since you use a different board, you'd have to select the board that applies to your case instead. Am I right you're using this one?

Best regards,

Henk-Piet Glas
Principal Technical Specialist
0 Likes
Not applicable
Hello Glas,

Thank you very much for the detailed explanation.

I have tried with your example that was posted here on feb and did some changes as my board is tc299tf . All the interrupts in all the cores are running but to get 1microsec ticks i need do some changes like you suggested.

I would also like some information regarding Remote Procedure Call in embedded systems. Do you have any suggestions regarding RPC in embedded systems?


Wish best regards
Praktikant
0 Likes
User13290
Level 5
Level 5
First like received First solution authored
Hi,

Praktikant wrote:
Do you have any suggestions regarding RPC in embedded systems?


Do you mean you're looking for advise on what RPC frameworks/protocols to use within an embedded environment? I've got no experience with that. A good starting point might be to consult this wiki and see if it contains some interesting references. What may also help is if you give us a short description of the specifications of your project. By painting us a picture, you're offering clues that might trigger someone who has worked on a similar project. That way they can share their experience and perhaps offer some tailored advise.

Best regards,

Henk-Piet Glas
Principal Technical Specialist
0 Likes
Not applicable
Hello Glas,

Thank you very much for your response.

Just a overview:
I am trying to implement RPC interface between cores(2+). So the client will be in core zero(core 0)and servers will be in other cores. For example if i want to initialize the interrupts in other cores from core zero.

It will be great if i can get some examples related to this or steps to achieve my target.

Best regards
Praktikant
0 Likes
User13290
Level 5
Level 5
First like received First solution authored
Hi,

Praktikant wrote:
Hello Glas,
It will be great if i can get some examples related to this or steps to achieve my target.


Will you be running everything on cores tc0 through tc2 of the same AURIX device? Or will several devices be communicating across a transport layer of some kind? In case of the latter RPC indeed makes sense. In case of the former things can perhaps be simplified by having the RPC handshake run through shared memory, using a simple protocol of your own design. You might optionally consider using a real time operating system that is multi-core aware and implement your project on top of that.

You also have to weigh in the factor time. An rtos might provide the abstraction you're after, but it also introduces a learning curve. So it depends on how much time has been allocated for your project. As a praktikant I suppose you have as little as 2 months to bring everything to a close. Depending on how comfortable you are with additional learning curves it can sometimes be more practical to keep things simple as suggested in the beginning.

Best regards,

Henk-Piet Glas
Principal Technical Specialist
0 Likes
Not applicable
Hi Glas,

Thank you very much for the response.

Yes, I will be running RPC on cores tc0 through tc2 of the same AURIX device. Even though I am going through some documents related to RPC but unable to get the exact picture as to how to implement for both client and server. I am quite confused in this case.

With best regards
Praktikant
0 Likes
User13290
Level 5
Level 5
First like received First solution authored
Hi,
Praktikant wrote:
I am quite confused in this case.

What might work is to use one of the general purpose interrupts and use the type of service field to make a cross-core interrupt. Using a shared memory area, the client (tc0) sets up the parameters and RP that it wishes the server (tc1) to execute. Then it interrupts the server and waits for the RP to complete. The server then services the cross-core interrupt by executing the RP and returning the results in the same shared memory area. A semaphore can be used to signal to the client that the results of the RP are ready. I'll see if I can work this into an example.

Best regards,

Henk-Piet Glas
Principal Technical Specialist
0 Likes
Not applicable
HIGHTEC.henk-piet.glas wrote:
Hi,

What might work is to use one of the general purpose interrupts and use the type of service field to make a cross-core interrupt. Using a shared memory area, the client (tc0) sets up the parameters and RP that it wishes the server (tc1) to execute. Then it interrupts the server and waits for the RP to complete. The server then services the cross-core interrupt by executing the RP and returning the results in the same shared memory area. A semaphore can be used to signal to the client that the results of the RP are ready. I'll see if I can work this into an example.


Hi Glas,

Thank you very much for the detailed explanation.

Since its a tricore so i am thinking of using spinlocks. I have wrote one small code just for an example of spinlocks. Please suggest . Not really sure if this is the correct way.

typedef int spinlock;

void init_lock(spinlock *Lock)
{
*Lock = 0;
}

void lock(spinlock *Lock)
{
while (CompareAndSwap (Lock))
STM1_Handler();

}

void unlock(spinlock *Lock)

{
*Lock = 0;
}
#endif
0 Likes
lock attach
Attachments are accessible only for community members.
User13290
Level 5
Level 5
First like received First solution authored
Hi,

I have attached an example of the suggestion that I made earlier this morning. After its import simply press build. Following the build it will be automatically simulated via TSIM (included in the product). The Pre/Postbuild console should produce the following output:

HighTec EDV-Systeme GmbH
------------------------

RPCAdd(10,20) = 30
RPCSub(10,20) = -10
RPCMul(20,10) = 200
RPCDiv(20,10) = 2
Note that sometimes you need to explicitly switch to the Pre/Postbuild console before you can actually see its output. Also note that while the example has the potential of running on multiple cores both client and server run on tc0 for now. But the principle remains the same. If the example is to your liking, you can proceed to integrate its concept into a true multi-core setup.

While the source code has been carefully documented I may have skipped a few beats here and there. So feel free to ask if anything is unclear.

Best regards,

Henk-Piet Glas
Principal Technical Specialist

0 Likes
Not applicable
HIGHTEC.henk-piet.glas wrote:
Hi,

I have attached an example of the suggestion that I made earlier this morning. After its import simply press build. Following the build it will be automatically simulated via TSIM (included in the product). The Pre/Postbuild console should produce the following output:

HighTec EDV-Systeme GmbHNote that sometimes you need to explicitly switch to the Pre/Postbuild console before you can actually see its output. Also note that while the example has the potential of running on multiple cores both client and server run on tc0 for now. But the principle remains the same. If the example is to your liking, you can proceed to integrate its concept into a true multi-core setup.


Hi Glas,

Thank you very much for the example. It is helping me a lot . I tried the example and it is working like you said.
Now if i want to implement spinlocks and use 'CompareAndSwap' , will it give me similar result ?

with best regards
Praktikant
0 Likes
User13290
Level 5
Level 5
First like received First solution authored
Hi,
Praktikant wrote:
will it give me similar result?

Based on the sample code that you listed earlier I would say no. The typedef for spinlock doesn't provide the compiler with sufficient information to know that its state may be changed by threads other than the current one. Therefore variables of type spinlock will be subject to compiler optimisations. For regular variables this is precisely what you want because it will have a positive effect on codesize and speed. For semaphores the story is a different one. Those must be explicitly written to and read from such as you code it. The way to do this is by adding the volatile keyword to your type definition. So rather than using 'typedef int spinlock' you will have to use 'typedef volatile int spinlock'.

Another advise I want to give you is to drop STM1_Handler() from your lock() function definition. To me it makes no sense to repeatedly call it while waiting to acquire the lock. The lock() function must only be used to acquire the semaphore. Once it is in your possession you become the sole owner of the resource that you're sharing. And only at that point you call the resource. Combining both remarks, this is the preferred approach:

   typedef volatile unsigned SEM_t;

SEM_t sem;

inline void P(SEM_t * const s) {
while ( __builtin_tricore_cmpswapw(s,1,0) != 0 );
}

inline void V(SEM_t * const s) {
*s = 0;
}

/* code snippet demonstrating use
*/

P(&sem);
STM1_Handler();
V(&sem);

Best regards,

Henk-Piet Glas
Principal Technical Specialist
0 Likes
Not applicable
HIGHTEC.henk-piet.glas wrote:
Hi,

The typedef for spinlock doesn't provide the compiler with sufficient information to know that its state may be changed by threads other than the current one. Therefore variables of type spinlock will be subject to compiler optimisations. For regular variables this is precisely what you want because it will have a positive effect on codesize and speed. For semaphores the story is a different one. Those must be explicitly written to and read from such as you code it. The way to do this is by adding the volatile keyword to your type definition. So rather than using 'typedef int spinlock' you will have to use 'typedef volatile int spinlock'.

Another advise I want to give you is to drop STM1_Handler() from your lock() function definition. To me it makes no sense to repeatedly call it while waiting to acquire the lock. The lock() function must only be used to acquire the semaphore. Once it is in your possession you become the sole owner of the resource that you're sharing. And only at that point you call the resource. Combining both remarks, this is the preferred approach:

   typedef volatile unsigned SEM_t;


Dear Glas,

Thank you very much for your help.
I have written my spinlock code like the you suggested and now i am planning to check if i can lock one core from another and result can be seen by blinking LED.

Do you have any suggestion regarding this ?

With best regards
Praktikant
0 Likes
User13290
Level 5
Level 5
First like received First solution authored
Hi Praktikant,

Praktikant wrote:

Do you have any suggestion regarding this?

What you may want to try first is see if you can get the multi-core example running that I created for Jens earlier in this thread. Simply add the code that you want to test to the core0_main, core1_main and core2_main placeholders. Note that the example was developed for the TC297 application kit so you may need to give it a carefull lookover when testing it on your TriBoard TC299.

Best regards,

Henk-Piet Glas
Principal Technical Specialist

p.s. What is your real name?
0 Likes
Not applicable
HIGHTEC.henk-piet.glas wrote:
Hi Praktikant,


Note that the example was developed for the TC297 application kit so you may need to give it a carefull lookover when testing it on your TriBoard TC299.



Dear Glas,

I have used your example that you developed earlier for the TC297 application kit and made some changes for my board. Everything works perfectly now. I have also initialised the locks for 1 core. Now i have to test it with the debugger to check the values.

Thank you very much for your help.

With best regards
Praktikant.
0 Likes
Not applicable
Hello Glas,
I am pretty new to Microcontrollers in generall.
Is it posible to change your code that it can be used for an TC397?
And if it is possible how can I find out what I need to change?

Thanks and best regards,
SPM
0 Likes
User13290
Level 5
Level 5
First like received First solution authored
Hi Felix,

SPM wrote:
Is it posible to change your code that it can be used for an TC397? And if it is possible how can I find out what I need to change?


This is certainly possible. I think it is a matter of replacing the board support package support code with that of your device/board and then you should be good. And you'd have to increase the amount of cores of course. At the moment I'm a bit short for time but I'll try and find a moment to do it.

Best regards,

Henk-Piet Glas
Principal Technical Specialist

0 Likes
Not applicable
HIGHTEC.henk-piet.glas wrote:
Hi Felix,

Hi,

This is certainly possible. I think it is a matter of replacing the board support package support code with that of your device/board and then you should be good. And you'd have to increase the amount of cores of course.




I have replaced the board support packages and it works.
Thank you for your reply!

Best regards,
SPM
0 Likes
Not applicable
Hello Glas,

I want to unlock a process in one core from another core which was locked. The whole process should be in loop. Do you have any suggestions ?

Best regards
Prakti
0 Likes
lock attach
Attachments are accessible only for community members.
User13290
Level 5
Level 5
First like received First solution authored
Hi Felix,

SPM wrote:
I have replaced the board support packages and it works.
Thank you for your reply!

Best regards,
SPM


Brilliant to read you got it running. For my part it took a bit longer but you'll find the results attached just in case you want to give that a go as well. Normally I try to include some comments as well but this time I have to keep it short and rely on the fact that most of it explains itself. The project is imported as follows:


  • Select 'File | Import...' MENU
  • Expand the 'General' FOLDER
  • Select 'Existing Projects into Workspace' SOURCE
  • Click 'Next'
  • Click 'Select archive file' RADIOBUTTON
  • Browse to the portable archive and press 'Open'
  • Select the example and finish import


Prior to building the project you may want to check the following menu:


  • Select 'Window | Preferences' MENU
  • Select 'HighTec Preferences | Linker Description Model'


And change the checkboxes as follows:


  • Disable 'Update model after each build' CHECKBOX
  • Disable 'Validate model before each build' CHECKBOX
  • Disable 'Generate LDF before each build' CHECKBOX
  • Enable 'Allow user defined ... in project settings' CHECKBOX


The last one is paramount, because the project uses a user defined description file rather than a generated one.

Should you have any questions, feel free to ask. There may be some delay in me replying. This week I'll be a bit short for time.

Best regards,

Henk-Piet Glas
Principal Technical Specialist
0 Likes
Not applicable
HIGHTEC.henk-piet.glas wrote:
Hi,




SEM_t sem;

inline void P(SEM_t * const s) {
while ( __builtin_tricore_cmpswapw(s,1,0) != 0 );
}

inline void V(SEM_t * const s) {
*s = 0;
}

/* code snippet demonstrating use
*/

P(&sem);
STM1_Handler();
V(&sem);


Hi Glas,

Thank you very much for the code. It really helped a lot.

With best regards
Praktikant
0 Likes
Not applicable
Hi Glas,

I am facing a problem with scratch pad memory. The spinlock is accessing the scratch pad ram but I dont want to use the Scratch pad ram. Is there any way I can avoid my code from accessing it ?

With best regards
Prakti
0 Likes
Not applicable
HIGHTEC.henk-piet.glas wrote:
Hi,

Based on the sample code that you listed earlier I would say no. The typedef for spinlock doesn't provide the compiler with sufficient information to know that its state may be changed by threads other than the current one. Therefore variables of type spinlock will be subject to compiler optimisations. For regular variables this is precisely what you want because it will have a positive effect on codesize and speed. For semaphores the story is a different one. Those must be explicitly written to and read from such as you code it. The way to do this is by adding the volatile keyword to your type definition. So rather than using 'typedef int spinlock' you will have to use 'typedef volatile int spinlock'.

Another advise I want to give you is to drop STM1_Handler() from your lock() function definition. To me it makes no sense to repeatedly call it while waiting to acquire the lock. The lock() function must only be used to acquire the semaphore. Once it is in your possession you become the sole owner of the resource that you're sharing. And only at that point you call the resource. Combining both remarks, this is the preferred approach:

   typedef volatile unsigned SEM_t;

SEM_t sem;

inline void P(SEM_t * const s) {
while ( __builtin_tricore_cmpswapw(s,1,0) != 0 );
}

inline void V(SEM_t * const s) {
*s = 0;
}

/* code snippet demonstrating use
*/

P(&sem);
STM1_Handler();
V(&sem);

[FONT



Hi Glas,

Your detailed explanation helped a lot. It is working perfectly.

Thank you very much.

best regards
Prakt
0 Likes
User13290
Level 5
Level 5
First like received First solution authored
Hi Praktikant,

Praktikant wrote:

Your detailed explanation helped a lot. It is working perfectly.


Good to hear. Am I right this means you solved the scratchpad ram posting of yours?

Best regards,

Henk-Piet Glas
Principal Technical Specialist
0 Likes
Not applicable
HIGHTEC.henk-piet.glas wrote:




Am I right this means you solved the scratchpad ram posting of yours?



Hi Glas,

Yes the scratchpad ram issue is resolved.

Thank you

Best regards
Prakti
0 Likes
User13290
Level 5
Level 5
First like received First solution authored
Praktikant wrote:
Yes the scratchpad ram issue is resolved.


Brilliant. Happy developing and good luck with your project.

Henk-Piet Glas
Principal Technical Specialist
0 Likes
Not applicable
HIGHTEC.henk-piet.glas wrote:
Brilliant. Happy developing and good luck with your project.



Thank you very much for all the help.

with best regards
Prakti
0 Likes