Passing PORT addresses

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

I am playing with some Macros and inline stuff. I have two inline functions, The reading READPIN(port,pin) works but the one that writes to the port is not compiling the passed port.

Why?

 

/*
* testmylibrary.c
*
* Created: 2/2/2021 1:20:18 PM
* Author : SysOp
*/

#include <avr/io.h>
#include <stdbool.h>


__attribute__ ((always_inline)) static inline bool Readpin(uint_farptr_t port, uint8_t pin)
{
	return port & (1 << pin);
}

__attribute__ ((always_inline)) static inline void Setpin(uint_farptr_t port, uint8_t pin)
{
	PORTB = PORTB | (1 << pin);  //this works
	port = port | (1 << pin);    // this will not work compiler ignores
}

void init(void);

uint8_t tmp = 0;


int main(void)
{

	while (1)
	{
		Setpin(PORTB,PB5);
		tmp = Readpin(PORTB,PB5);

	}
}

 

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

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You need to pass the address of PORTn, not the value of PORTn. Since PORTn is a pointer already deferenced in its define creation, you need to take a step back to get the address by using &. It is also a volatile, so need to also say so in the argument type.

 

__attribute__ ((always_inline)) static inline 
void Setpin(volatile uint8_t* port, uint8_t pin) {
    *port |= (1 << pin);
}

 

Setpin(&PORTB,PB5);

 

 

You also need to check whether your code is correct, even though it compiles-

https://godbolt.org/z/s56YrW

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

Thanks Revised these lines

 


__attribute__ ((always_inline)) static inline void Setpin(volatile uint8_t *port, uint8_t pin)
{
	*port  = *port | (1 << pin);   
    
}


// Calling Setpin 

		Setpin(&PORTB,PB5);

I modified the Read as well I suspect that is the correct way to do it, not sure how it works without using the pointer * though.

__attribute__ ((always_inline)) static inline void Setpin(volatile uint8_t *port, uint8_t pin)
{
    *port  = *port | (1 << pin);    // this will not work compiler ignores
}

 

So the usage of both use &PORTB 

 

 

 

 

 

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

Here is potentially a harder one.

 

Suppose I want to reference the physical pins, 0 .. 28 and call them PH0 .. PH28

 

Can I somehow create a Macro that would expand this

 

Setpin(PH18);

 

To this

 

Setpin(&PORTB,PIN5);

 

 

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

>not sure how it works without using the pointer * though.

 

It worked because the call was doing the reading, then the function just processed the read value passed in. One read was all that was needed, and makes no difference if was done at the call or in the function (compiler would hide the difference via optimization). Although could be done either way, you already have another similar function that has a specific requirement so you make it the same so you can use the same call format for each.

 

The write was different because there was no place to put the |= result since you told the function only about a value and not its (volatile) location. Simply setting a bit in some value that goes nowhere is useless, so the compiler optimizes it away.

 

 

>Suppose I want to

 

Assuming a mega328, or similar-

https://godbolt.org/z/xqPWeE

 

and if you want to dive into C++ -

https://godbolt.org/z/Gb9xsr

Last Edited: Wed. Feb 3, 2021 - 02:34 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

metron9 wrote:

Here is potentially a harder one.

 

Suppose I want to reference the physical pins, 0 .. 28 and call them PH0 .. PH28

 

Can I somehow create a Macro that would expand this

 

Setpin(PH18);

 

To this

 

Setpin(&PORTB,PIN5);

 

 

Well you clearly can because this is pretty much exactly what pinMode() and digitalWrite() in the Arduino world do. However the way the do it - those functions use look up tables to map some ordinal number to a port and pin number combination - can end up being hugely inefficient and considerable runtime cost. (which is why a lot of people berate the whole of Arduino as "inefficient" when on the whole it's really just these functions alone that are).

 

The clever thing is doing it in some way that maintains runtime efficiency. (Curt's first example illustrates this but also illustrates that such solutions are seldom "simple"! ;-)

 

(perhaps it's me but I actually prefer the simplicity of his #define and Setpin() rather than the Setpin_() alternative).

Last Edited: Wed. Feb 3, 2021 - 09:26 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm wrote:
You also need to check whether your code is correct, even though it compiles-

Indeed -- I'm trying to think of why this two-step is needed to get a value just written.  Or is it to do a real-world verify?  Then perhaps PINB is intended?  But then, if the compiler turns the set macro into an OUT or an SBI, then the next instruction will be an IN or an SBIS and "won't work"  [oh, wait, OP reported that it didn't work] as the value will not have propagated.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

How about this, it has no overhead, Before you posted I had already started working on that lookup idea but thought the same too much overhead. Then I remembered the include can be used anywhere and combined it with the inline function and here you go.

 

__attribute__ ((always_inline)) static inline void SetDIR18(void)
{
			#include "setdir18.h"
}

Using the code in main its just SetDIR18() 

 

where the include inserts the following code

 

Setpin(&DDRB,PB5);

Assuming the physical pin 18 on the uc is mapped to Pin 5 of PortB for example.

 

Now I wonder if there is a way to put lots of .h files in 1 .h file, or perhaps just put them all in a folder named Tiny45Pins that could have all the read pin, set port, setoutput DDR , setinput DDR for each pin.

 

The reason I am thinking about this is I get confused having to think about all the details. i usually look at the uc pins as pins 1..8 for example on the tiny45. So to program that pin I have to have the printout of the pins to find out what port and pin I need to work with.

 So Physical pin 6 on tiny45 is actually PORTB PIN1 , now I have three things to remember and the less I have to remember the more I can get done.

 

 

Last Edited: Wed. Feb 3, 2021 - 05:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is a lookup method but looks up the code to replace the call inline

By adding more if then logic only one inline macro needs to be used and it inserts the include file that has the actual c code needed for the task.

 

Example Setdir1.h has the following code. So instead of having to remember the port and pin its just Setdir(1) to set the direction pin of portB the 1 is the physical pin on the uc that is referenced .

DDRB = DDRB | (1 << PB5);
/*
* testmylibrary.c
*
* Created: 2/2/2021 1:20:18 PM
* Author : SysOp
*/

#include <avr/io.h>
#include <stdbool.h>



__attribute__ ((always_inline)) static inline void Setport(unsigned char p)
{
	if (p == 1)
	{
		#include ".\Tiny45PHY\Setport1.h"
	}
}

__attribute__ ((always_inline)) static inline void Setdir(unsigned char p)
{
	if (p == 1)
	{
		#include ".\Tiny45PHY\Setdir1.h"
	}

}


int main(void)
{

	while (1)
	{
		Setdir(1);
		Setport(1);
	}
	
}






 

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

>How about this

 

Sorry to say, but I'm afraid it would be hard to come up with something worse than that. If you don't think so, try it out for a while and see how it goes.

 

If you also want pin numbers, then simply add a define for each of them-

https://godbolt.org/z/edEvaf

then you have a choice of any you wish- pin number, pin name, or some other name created that uses either one. The harder part is avoiding already created names in existing headers, so may have to use upper/lowercase to avoid existing names (like PINB5 becomes PinB5).

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

I will answer my other question above about the .h file having all the code for all the pins or each operation , Setdir,

By using the #ifdef and #undef you can pass a variable to the header file like this

 


#ifdef phy1
	DDRB = DDRB | (1 << PB5);
	#undef phy1
#endif

#ifdef phy2
DDRB = DDRB | (1 << PB3);
 #undef phy2
#endif

The calling code defines the phy1 .. phy maximum pincount before #including the .h file so the .h file inserts the correct c code.

 

__attribute__ ((always_inline)) static inline void Setdir(unsigned char p)
{
	if (p == 1)
	{
		#define phy1
		#include ".\Tiny45PHY\Setdir.h"
	}
		if (p == 2)
		{
			#define phy2
			#include ".\Tiny45PHY\Setdir.h"
		}
}

Once I create all the .h files for each pin as curtvm thinks it won't work well, I may post on github for others to experiment and see if this ardrino type coding might be helpful.

I will give it a go though and see if it helps me, at least I may learn something new who knows!

 

Oh no! I see if you include a #define in the main program it gets defined during the postprocessor not during the execution, when I tested it I made an error.

So no single file .h would work , individual .h for each command.

 

 

 

 

Last Edited: Wed. Feb 3, 2021 - 07:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

>Sorry to say, but I'm afraid it would be hard to come up with something worse than that

 

I stand corrected.

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

You are working too hard.

Associating a set of arbitrary integers with pins can be done with an appropriate set of #defines.

Done right, all the heavy lifting will be done at compile-time.

IIRC the ternary operator will produce an lvalue if both choices are lvalues of the same type.

Thus you can do  portfrominteger, ddrfrominteger, pinfrominteger and bitpositionfrominteger.

Arduino does it differently.

Moderation in all things. -- ancient proverb