Pin toggle with minimal codeq

Go To Last Post
15 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear all,

 

I am writing an extremely time critical program and perceive a significant delay when I want to toggle an IO.

I first made use of the ASF which calls the following function when I want to toggle a pin (pin 43):

 

gpio_toggle_pin(41);

/** \brief Toggles a GPIO pin.
 *
 * \param pin The pin number.
 *
 * \note The function \ref gpio_configure_pin must be called before.
 */
void gpio_toggle_pin(uint32_t pin)
{
    volatile avr32_gpio_port_t *gpio_port = &AVR32_GPIO.port[pin >> 5];
    
    /* Toggle the I/O line. */
    gpio_port->ovrt  = 1 << (pin & 0x1F);
}

 

 

How am I able to simplify this as much as possible?

 

I know the OVRT register (which toggles the pin when a 1 is written to it) has adress 0xFFFF225C.

If I would be able to write the value 0x00000200 to it, the pin toggles.

I am able to do this manually via the I/O view in Atmel Studio;

 

But i can't figure out how to do this in code:

 

This is my attempt (knowing it is incorrect!):

 

volatile *target_register=  0xFFFF225C ;
    
    if (switcher==1)
    {

     (target_register) = 0x00000200;
      switcher = 0;
    }
    else
    {
     target_register= 0x00000200;
      switcher = 1;
        
    }

 

I want to write 0x00000200 to the content of "target_register" which is located at 0xFFFF225C

&target_register= 0x00000200; is also not correct.

 

What should be the correct syntax?

 

Last Edited: Wed. Jan 3, 2018 - 11:06 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think I found the solution... but not entirely sure if I understand what I have done :)

 

	unsigned short volatile *const target_register = (unsigned short*)0xFFFF225C;
	
	//volatile *worst =  0xFFFF225C ; 
	
  	//LED_Toggle(LED1);  
	//gpio_toggle_pin(41);
	if (switcher==1)
	{

	 (*target_register) = 0x00000200;
	  switcher = 0;
	}
	else
	{
	 *target_register = 0x00000200; 
	  switcher = 1;
		
	}

 

I have created a unsigned short volatile constant pointer which contains the location of the memory register 0xFFFF225C.

Then I simply state that i write a value to the register which is located at the adress defined in the target_register.

 

Correct or not?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why not just use a #define?

 

#define TARGET_REGISTER (unsigned short volatile*)0xFFFF225C

 

But doesn't ASF already have such #defines ?

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You want direct access to a memory mapped register?

Usually a #define is used:

 

#define TOGGLE_REG (*(volatile uint32_t *) 0xFFFF225C)

TOGGLE_REG = 0x00000200;

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

Why not just use a #define?

 

#define TARGET_REGISTER (unsigned short volatile*)0xFFFF225C

 

But doesn't ASF already have such #defines ?

 

 

El Tangas wrote:

You want direct access to a memory mapped register?

Usually a #define is used:

 

#define TOGGLE_REG (*(volatile uint32_t *) 0xFFFF225C)

TOGGLE_REG = 0x00000200;

 

 

 

 

Dear both,

 

Thanks for your comments!

I agree, a define statement is better.

 

For my understanding

 

What are we doing here (in english :) ) -->

 

(*(volatile uint32_t *) 0xFFFF225C) = 0x00000200;

 

Why are there two pointer signs?

Is it to let the application know the value that can be written in the adress is of size uint32_t?

Sorry... basic question but want to make sure I understand this now!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

luc_V wrote:
I agree, a define statement (sic) is better.

Note that #define is not a statement - it is a preprocessor directive.

 

Why are there two pointer signs?

One is casting the number to be a pointer; the other is dereferencing that pointer

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

luc_V wrote:

I agree, a define statement (sic) is better.

 

Note that #define is not a statement - it is a preprocessor directive.

 

Clear!

 

awneil wrote:

Why are there two pointer signs?

One is casting the number to be a pointer; the other is dereferencing that pointer

Not 100% clear...

 

First we state

#define TARGET_REGISTER (unsigned short volatile*)0xFFFF225C

Which means that Target_register is a pointer (size unsigned short) which points to the start of memory location 0xFFFF225C.

 

Next;

*TOGGLE_REG = 0x00000200;

Would alter the content of the memory location at which Toggle_reg is pointing to (dereferencing).

 

Correct?

 

Thanks for the help; Much appreciated.
).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1
#define TARGET_REGISTER (unsigned short volatile*)0xFFFF225C

0xFFFF225C is just a plain number

 

(unsigned short volatile*) is a cast; ie, it tells the compiler to treat the number as a pointer to a volatile unsigned short

 

 

Which means that Target_register is a pointer

Remember that 'C' is case sensitive - so TARGET_REGISTER is not the same as Target_register

 

Also note that this is a preprocessor define; not a variable.

 

so TARGET_REGISTER is not a pointer as such - it is purely a text substitution for  (unsigned short volatile*)0xFFFF225C - but the effect here is much the same.

 

I guess the correct term would be, "pointer expression"

 

*TOGGLE_REG = 0x00000200;

So the * here dereferences the pointer expression; ie, it accesses what it points to.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Awneil,

 

Thanks for the detailed explanation.

Completely clear now!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I hope it actually works ...

 

EDIT

 

probably should have a further set of parentheses:

 

#define TARGET_REGISTER ((unsigned short volatile*)0xFFFF225C)
Last Edited: Wed. Jan 3, 2018 - 03:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am writing an extremely time critical program and perceive a significant delay when I want to toggle an IO.

For further increase in speed and more deterministic toggling see the CPU Local Bus Mapping chapter in the controller's manual.

BR,

M

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

I hope it actually works ...

 

EDIT

 

probably should have a further set of parentheses:

 

#define TARGET_REGISTER ((unsigned short volatile*)0xFFFF225C)

Menahem wrote:

I am writing an extremely time critical program and perceive a significant delay when I want to toggle an IO.

For further increase in speed and more deterministic toggling see the CPU Local Bus Mapping chapter in the controller's manual.

BR,

M

 

 

The code is working, but the difference in execution time is only limited.

When below codes are compared (the first one being from ASF), the execution time differs about 400ns.

 

LED_Toggle(LED1) 

versus 

*TARGET_REGISTER = 0x00000200;

I run a PWM signal with a period time of 200us and an ON time of 5us.

The PWM is based on the CPU clock which runns at 64MHz.

This PWM signal is connected (externally) to a random pin on the CPU.

Via this pin, the PWM edges (both positive and negative) generate an interrupt.

Within this interrupt I start and stop a timer to measure the ON_time of the PWM signal.

(This is just an example but required for my application).

 

The results are accurate and the readings show an ON_time of about 4.9us.

 

If I also toggle a PIN (enable/disable an STK600 LED) I am able to measure this signal with my scope.

The signal going to the LED should have a simular timing compared to the PWM signal.

Unfortunately I perceive a difference..

 

The Time between the toggling of the LED is indeed about ~5us, but the signal is shifted 2us compared to the PWM signal.

First I thought it had to do with the execution time of the LED toggling; but after these optimisation I realize it is something else.

I am not sure what it is, but I expect it is some background process in the ASF which handles the interrupt.

I have no idea what the controller writes on the stack and how many cycles it takes for it.

2us would mean it takes about 128 cycles (including the toggling of the pin)!

 

For now I solved the time critical issue differently (hardware) but I am still suprised it takes 2us to handle the interrupt (which has highest prio).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

luc_V wrote:
The code is working, but the difference in execution time is only limited.

That's not very surprising: the original code you showed wasn't doing much at all - no great bloat to cut out.

 

Via this pin, the PWM edges (both positive and negative) generate an interrupt.

Within this interrupt I start and stop a timer to measure the ON_time of the PWM signal.

Can't you do that directly in hardware?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Unfortunately I'm not familiar with AVR32, but 128 cycles to handle an interrupt cannot be right. I'm sure the datasheet says somewhere what is the interrupt latency.

If it's taking so long, it must be some kind of overhead from ASF.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

El Tangas wrote:
128 cycles to handle an interrupt cannot be right

Discussion of that point continues here: http://www.avrfreaks.net/forum/at32uc3c0512-100-cycles-interrupt-handling-delay