FreeRTOS context switch time

Greetings,

I was going to measure the time it took for a context switch on an AT91SAM7S256 by toggling a port pin. My meaning was to set a port pin high when entering vPreemptiveTick and setting it low again just before exiting. The result was that port pin didn't toggle.

I found another way around the problem so the result is in hand - I am just wondering : Is it not possible to have direct port pin access in a naked interrupt routine ?

/RaceMouse

Reply to
RaceMouse
Loading thread data ...

RaceMouse,

I assume you've made a pre-emptive build.

I don't see why your approach wouldn't work. My guess at this point is either the code wasn't executed or the IRQ happened quicker than your test equipment was able to measure.

Whether the routine was naked or not - meaning a complete register save and restore wasn't necessary shouldn't matter.

Is your IRQ in assembly? If not, then do the pin toggle with inline assembly and try again. Also - you may try putting a delay loop in after you set the pin high and pin low just for debug purposes to confirm that your test eq. is able to measure the pulse. If you don't see it - and you know the code is executing - then the test eq. isn't fast enough to measure it.

HTH, John W. ======

Greetings,

I was going to measure the time it took for a context switch on an AT91SAM7S256 by toggling a port pin. My meaning was to set a port pin high when entering vPreemptiveTick and setting it low again just before exiting. The result was that port pin didn't toggle.

I found another way around the problem so the result is in hand - I am just wondering : Is it not possible to have direct port pin access in a naked interrupt routine ?

/RaceMouse

--------------= Posted using GrabIt =----------------

------= Binary Usenet downloading made easy =---------

-= Get GrabIt for free from

formatting link
=-

Reply to
John W.

If you are accessing the port directly it should be ok provided no other tasks are also accessing the port when the interrupt interrupts. In any case don't use the Set or Toggle LED functions that come in the demo as these may suspend the scheduler or enter a critical section to get exclusive access to the port and this should not be done in an interrupt.

Reply to
Jaba

Well..

The test equipment is fast enough - it's a 200MHz Scope.

The code I've tried:

void vPreemptiveTick( void ) __attribute__((naked)); void vPreemptiveTick( void ) { /* This was my plan : Set pin A3*/ AT91C_BASE_PIOA->PIO_SODR = 8;

/* Save the context of the current task. ASSEMBLY */ portSAVE_CONTEXT();

/* Increment the tick count - this may wake a task. */ vTaskIncrementTick();

/* Find the highest priority task that is ready to run. */ vTaskSwitchContext();

/* End the interrupt in the AIC. */ AT91C_BASE_AIC->AIC_EOICR = AT91C_BASE_PITC->PITC_PIVR;;

/* Restore the context of the current task. ASSEMBLY */ portRESTORE_CONTEXT();

/* This was my plan : Clear pin A3*/ AT91C_BASE_PIOA->PIO_CODR = 8; }

The idea was to measure the pulse generated on Pin 3. That should be an expression for the time a context switch would take to complete.

Did that shed some light over the matter ?

/RaceMouse

Jaba wrote:

Reply to
RaceMouse

Make sure the port is declared as "volatile". Otherwise the compiler may recognize that the value set in the first assignment is not used before being overwritten by the second, and it will optimize-out the first one altogether.

You could also disable all optimizations, but this will change the timing you are trying to measure. Roberto Waltman

[ Please reply to the group, return address is invalid ]
Reply to
Roberto Waltman

ARGHH!! you are setting it to 8 in both places!. Roberto Waltman

[ Please reply to the group, return address is invalid ]
Reply to
Roberto Waltman

Sorry, I did not read your code carefully enough. I guess the names _SODR and _CODR imply separate registers for setting and clearing a port. Then my previous answer does not apply.

Reply to
Roberto Waltman

Ok - but it was a good guess.

I have just started using an ARM7 (coming from 8-bit uC) so my knowledge about this particular arch is quite limited. Anyone else with some ideas ?

/RaceMouse

Roberto Waltman wrote:

Reply to
RaceMouse

On Thu, 13 Jul 2006 09:39:26 +0200, RaceMouse wrote in comp.arch.embedded:

First idea, don't top post. Material you add to a thread belongs interspersed with or after quoted material you are replying to.

Have you properly set the configuration register for that port so that the bit is configured as an output? Normally, all GPIO pins default to high impedance inputs on power up or reset.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
Reply to
Jack Klein

Assuming that your compiler is not broken, if code works only with optimisations disabled then your source code is wrong. Disabling optimisations completely on many compilers leads to such terrible code that it is extremely difficult to see what is going on.

If you want to understand the generated assembly code and easily debug your code, you are normally better off with light optimisation (-O1, or similar, depending on your compiler). Heavy optimisations such as automatic inlining can make it hard to follow the generated code, but can be useful too - if the compiler has "optimized-out" your code, you've forgotten a "volatile" somewhere.

Reply to
David Brown

Normally, on pio ports, the same address is used to set or clear a bit, whereas your code example looks like its using 2 separate addresses:

AT91C_BASE_PIOA->PIO_SODR = 8; and AT91C_BASE_PIOA->PIO_CODR = 8;

Typically, the ops would be:

base_address -> register |= 8;

then

base_address -> register &= (~8);

The or / and set and clear only the bit of interest, leaving the rest alone. You might also check that the register overlay pointer actually does point to the base address and that the structure defs are correct in terms of offsets, padding etc.

The other thing to consider is the scope - It obviously needs to trigger from the rising edge, but if it's not storage scope, you may not see anything on the display. For example, a 1 uS pulse at a rep rate of 10 or 20 mS may not be seen on the scope because the duty cycle is too low for the phosphor. Area under the curve etc. A logic analyser may be a better choice...

Chris

Greenfield Designs Ltd

----------------------------------------------------------- Embedded Systems & Electronics: Research Design Development Oxford. England. (44) 1865 750 681

Reply to
Chris Quayle

Slightly off topic, but ... there are several nice things about having separate set and clear registers where bits written to either register as zero are ignored and bits written as one cause the set or clear action.

o Only a single (write) bus cycle is required instead of two (a read followed by a write).

o A single write action is atomic, and thus no interrupt disable is required to provide mutual exclusion from interrupt service routines when the processor has no read-modify-write bit instruction. Typical of RISC architectures.

o In shared bus architectures where multiple bus masters must access the same register, the bus does not need to provide indivisible read-modify-write locking.

o Mutexes are not required for two threads accessing the same register in a multi-threaded or multi-processor system.

--
Michael N. Moran           (h) 770 516 7918
5009 Old Field Ct.         (c) 678 521 5460
Kennesaw, GA, USA 30144    http://mnmoran.org

"So often times it happens, that we live our lives in chains
  and we never even know we have the key."
The Eagles, "Already Gone"

The Beatles were wrong: 1 & 1 & 1 is 1
Reply to
Michael N. Moran

Interesting - if you visualise a typical port, it's just a D style latch with output fed back via a transceiver so you can read it. Using two addresses effectively means that the latch is probably an rs latch or similar and precludes the use of rmw instructions, even if available. Perhaps using a 3rd address to read back the port value just to make things even more untidy. One of the advantages of having memory mapped io is that all the instructions applicable to main memory work with i/o, but it's not that usefull if ports don't work like memory. You could argue that the risc designers were forced to adopt such measures to get round the lack of rmw instructions, thus making a virtue from necessity. It makes the i/o port architecture and driver code more complex and probably needs a change of mindset and extra care when writing the drivers as well. Normally, if you have a variable shared between an isr and mainline code, you just disable interrupts in the critical section, which is straightforward and inexpensive in terms of compute time.

Off topic again, but was just looking at the freescale site - have been working on a backburner project using the Dragonball for over a year, but it's now not recommended for new designs. The upgrade path looks like Dragonfire = Coldfire + built in lcd controller at the low end. Browsing round further and the original 68000, now cmos, is still current production. Unbelievable - an architecture that first saw the light of day circa 1983 but must still be shipping serious volume. It has of course, a test and set instruction...

Chris

--
Greenfield Designs Ltd
-----------------------------------------------------------
Embedded Systems & Electronics: Research Design Development
Oxford. England. (44) 1865 750 681
Reply to
Chris Quayle

I don't know if the 68000 is still shipping in "serious" volume, but it certainly still seems to be available. The ColdFire ISA is almost identical to that of the original 68000, bar a few addressing modes and instructions here and there. The implementation is completely different, of course, but from the programmer's viewpoint it is mostly the same. The TAS (test and set instruction) was dropped from the ColdFire (it was mostly used in multi-processor systems, which were not supported by the original ColdFire cores, and was a little awkward to implement in the RISC-style core). It came back with the ColdFire v4 core, however.

Reply to
David Brown

Frequently, however, there is no need for the program to read-back the value from the interesting "bit" of the port. The program simply needs to set its state as desired.

Of course, I/O ports are rarely "simply memory" without side effects. This difference gives rise to the need for the volatile keyword in C/C++. Sure, you can use the same instructions, but that by itself does not ensure guarantee the ordering or timing of their execution. These sort of assumptions can really cause pain when applied to multi-threading, multi-processing (including SMP), write buffers, cache and out-of-order RISC systems.

As a PowerPC jocky, a few interesting instructions in this vein include:

o sync o isync o eieio (I love this one ;-) o lwarx/stwcx

RISC was developed as a way to take advantage of compiler technology to improve execution time performance.

I dont' find this to be true (of the set-reset style I/O ports). It actually allows easier driver decoupling and synchronization once you get used to the idea.

This is "normal" only in single processor systems, and does not scale to multi processor systems.

--
Michael N. Moran           (h) 770 516 7918
5009 Old Field Ct.         (c) 678 521 5460
Kennesaw, GA, USA 30144    http://mnmoran.org

"So often times it happens, that we live our lives in chains
  and we never even know we have the key."
The Eagles, "Already Gone"

The Beatles were wrong: 1 & 1 & 1 is 1
Reply to
Michael N. Moran

Agreed.

But the interrupts might already be disabled... so you have to test for this first, then disable them, (if they are not already, remembering whether they were disabled or not), then read the current port value, or/and with your bitmask, write the port, then re-enable interrupts (if they in fact had to be disabled). And you have to do this every time you toggle a port pin.

It is *much* faster and nicer to be able to simply write a value to a "set" or "reset" register. That is why the newer control-orientated processors do it this way.

--

John Devereux
Reply to
John Devereux

That's making a lot of assumptions and I don't remember any situation which needed a mutex on a i/o port bit, but ymmv :-). A more common situation would be a uart driver, where the interrupt handler feeds or reads a circular buffer, with byte count as the shared variable. Only one task has the line open at any time, so it doesn't need to second guess interrupt state. A simple disable / enable interrupt sequence provides a bulletproof and tidy solution.

The other point is that if you can't use a rmw instruction on a port, succinct C constructs like &=, |= can't be used, which means you are limited to a subset of C when programming such ports. Just one more thing to get in the way of the process. It's more generalised to be able to view device registers and ports as memory objects.

I guess you just get used to programming what the device gives you, limitations and all...

Chris

--
Greenfield Designs Ltd
-----------------------------------------------------------
Embedded Systems & Electronics: Research Design Development
Oxford. England. (44) 1865 750 681
Reply to
Chris Quayle

Perhaps not, but I wonder how many of today's processors will even be remembered after 20 odd years, never mind still in production.

I do hear the call to arm(s), but not quite there yet :-)...

Chris

--
Greenfield Designs Ltd
-----------------------------------------------------------
Embedded Systems & Electronics: Research Design Development
Oxford. England. (44) 1865 750 681
Reply to
Chris Quayle

Agreed, but if you need port state, having to keep a copy in memory adds book keeping.

Haven't played with ppc, but can see the problems that could result from ooo execution. What do you do to get round the problem - look at the compiler output and hand optimise, or have compiler extensions to disable features ?.

Real world example would help here.

What percentage of embedded designs need multiprocessing ?. Workstation size os's seem to be finding their way into more embedded projects which can = multiprocessing, but it does take system design to new level of abstraction. Fine for consumer electronics, but would you use it for serious work ?. Call it paranoia if you like, but whole system visibility is a key thing here and there are also doubts about efficiency. Cynics might say Windows style code bloat and reliability comes to the world of embedded...

Chris

--
Greenfield Designs Ltd
-----------------------------------------------------------
Embedded Systems & Electronics: Research Design Development
Oxford. England. (44) 1865 750 681
Reply to
Chris Quayle

But you can't generally *assume* that C compilers generate single rmw instructions for those operators anyway. Of course anything goes if your not writing portable code.

Just beware of those assumptions should you change compilers or processors.

Sure ... just do get stuck in the rut ... ;-)

--
Michael N. Moran           (h) 770 516 7918
5009 Old Field Ct.         (c) 678 521 5460
Kennesaw, GA, USA 30144    http://mnmoran.org

"So often times it happens, that we live our lives in chains
  and we never even know we have the key."
The Eagles, "Already Gone"

The Beatles were wrong: 1 & 1 & 1 is 1
Reply to
Michael N. Moran

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.