Storing ports and pins in struct...

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

I have simple struct,

 

typedef struct strDSIC
{
	uint8_t *DS_DATADIR;
	uint8_t *DS_PORT;
	uint8_t *DS_INC;
	uint8_t *DS_CS;
	uint8_t *DS_UD;
	uint8_t DS_STEPS;
}StrDSIC;

That I wanted to use to store details for couple of same ICs conencted to micro in a way that I can just pass a struct and in turn actions will be performed on that specific port, pin etc.

 

I taught I can store them as pointers but something is not working correctly because when I pass to some function my structure for example:

 

void ds_init(struct strDSIC *dsIC)
{
	_delay_ms(50);
	_delay_us(600);
	
	dsIC->DS_DATADIR |= (1<<dsIC->DS_INC);
	dsIC->DS_DATADIR |= (1<<dsIC->DS_CS);
	dsIC->DS_DATADIR |= (1<<dsIC->DS_UD);
	
	dsIC->DS_PORT |= (1<<dsIC->DS_INC);
	dsIC->DS_PORT |= (1<<dsIC->DS_CS);
	dsIC->DS_PORT |= (1<<dsIC->DS_UD);
}

It does not really work. It might be just programming issue I havent used C in quite a while but since I'm not sure 100% I decided to post here, sorry if this should go somewhere else.

 

Essentially what I get when I pass struct to this function is:

 

invalid operands to binary << (have 'int' and 'uint8_t * {aka unsigned char *}') 

 

Thanks for the help.

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

You need to assign the address of the ports to the struct members the write THROUGH the pointers, not into them.
.
Of course doing this is going to create monstrous code but perhaps you don't care?
.
The fact is that port addresses do not change at run time so why use indirection?

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

Your struct fields for the ports needs to be

volatile uint8_t *

For the details of this, see http://www.nongnu.org/avr-libc/u... .

 

Here's a minimal example that compiles clean. I had no setup handy for actually testing this, but I'd expect it to work:

 

#include <avr/io.h>

// A struct type that holds (a pointer to the) port and a pin number
typedef struct {
	volatile uint8_t * port;
	uint8_t pin;
} iostruct_t;

// A function that sets up values in such a struct
void setup(iostruct_t * iostruct) {
	iostruct->port = &PORTD;
	iostruct->pin = 4;
}

// A function that does an operation using the values in the struct
void setPinHigh(iostruct_t * iostruct) {
	*(iostruct->port) |= 1<<(iostruct->pin);
}

void main(void) {
	iostruct_t iostruct;
	setup(&iostruct);
	setPinHigh(&iostruct);
}

 

Advice: Always test/prototype with the absolute minimal test case you can come up with. You don't want any more complications than absolutely necessary when in unknown territory.

"He used to carry his guitar in a gunny sack, or sit beneath the tree by the railroad track. Oh the engineers would see him sitting in the shade, Strumming with the rhythm that the drivers made. People passing by, they would stop and say, "Oh, my, what that little country boy could play!" [Chuck Berry]

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

The way to deal with compiler messages is to just read what they are telling you:

 

listener wrote:
invalid operands to binary << (have 'int' and 'uint8_t * {aka unsigned char *}') 

So let's break that down:

 

invalid operands

"Operands" are the things on which an operator acts;

"Invalid" means that the ones you have supplied in your code are not valid; ie not allowed.

 

binary << 

In the 'C' programming language, '<<' is an operator;

it is called a binary operator because it takes two operands - one on each side.

 

So the message is telling you that one or both of the operands you have supplied is invalid (not valid; not allowed)  for the '<<' operator.

 

have 'int' and 'uint8_t * 

Is telling you what operands you have supplied.

I guess it could be more helpful and say specifically which one(s) it considers invalid - but you can check that in a 'C' reference.

 

However, just consider the meanign of the '<<' operator:

 

it requires two operands. It shifts each bit in its left operand to the right.

The number following the operator decides the number of places the bits are shifted

 

https://en.wikipedia.org/wiki/Bi...

So, clearly, the second (right-hand) operand has to be a number - but you have supplied a pointer.

 

 

{aka unsigned char *}

Is just telling you, for information, that uint8_t* is a synonym for char*

 

#DecodeCompilerMessage

 

Last Edited: Sat. Oct 21, 2017 - 11:23 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes that is ugly.... Well to my object oriented brain this seemed like nice and elegant way but having to deal with all of this given its static I can of course just nail them down.

 

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

The complexity will be there - somewhere in the code. But since you said

listener wrote:
to my object oriented brain

have you considered moving to C++?

 

For someone used to OO "notation and look" it might offer you the possibility to have, arguably, very neat and OO-like "main code".

"He used to carry his guitar in a gunny sack, or sit beneath the tree by the railroad track. Oh the engineers would see him sitting in the shade, Strumming with the rhythm that the drivers made. People passing by, they would stop and say, "Oh, my, what that little country boy could play!" [Chuck Berry]

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Thanks guys this is very helpful.

 

I might try C++ also thanks for suggestion.

 

@awneil thanks for the breakdown appreciate it.

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

The include files for the XMEGA have already done this for you.  Perhaps you should switch chips..?wink
 

/* I/O Ports */
typedef struct PORT_struct
{
    register8_t DIR;  /* I/O Port Data Direction */
    register8_t DIRSET;  /* I/O Port Data Direction Set */
    register8_t DIRCLR;  /* I/O Port Data Direction Clear */
    register8_t DIRTGL;  /* I/O Port Data Direction Toggle */
    register8_t OUT;  /* I/O Port Output */
    register8_t OUTSET;  /* I/O Port Output Set */
    register8_t OUTCLR;  /* I/O Port Output Clear */
    register8_t OUTTGL;  /* I/O Port Output Toggle */
    register8_t IN;  /* I/O port Input */
    register8_t INTCTRL;  /* Interrupt Control Register */
    register8_t INT0MASK;  /* Port Interrupt 0 Mask */
    register8_t INT1MASK;  /* Port Interrupt 1 Mask */
    register8_t INTFLAGS;  /* Interrupt Flag Register */
    register8_t reserved_0x0D;
    register8_t REMAP;  /* I/O Port Pin Remap Register */
    register8_t reserved_0x0F;
    register8_t PIN0CTRL;  /* Pin 0 Control Register */
    register8_t PIN1CTRL;  /* Pin 1 Control Register */
    register8_t PIN2CTRL;  /* Pin 2 Control Register */
    register8_t PIN3CTRL;  /* Pin 3 Control Register */
    register8_t PIN4CTRL;  /* Pin 4 Control Register */
    register8_t PIN5CTRL;  /* Pin 5 Control Register */
    register8_t PIN6CTRL;  /* Pin 6 Control Register */
    register8_t PIN7CTRL;  /* Pin 7 Control Register */
} PORT_t;
.
.
.
.
.
#define PORTA    (*(PORT_t *) 0x0600)  /* Port A */
#define PORTB    (*(PORT_t *) 0x0620)  /* Port B */
#define PORTC    (*(PORT_t *) 0x0640)  /* Port C */
#define PORTD    (*(PORT_t *) 0x0660)  /* Port D */
#define PORTE    (*(PORT_t *) 0x0680)  /* Port E */
#define PORTF    (*(PORT_t *) 0x06A0)  /* Port F */
#define PORTH    (*(PORT_t *) 0x06E0)  /* Port H */
#define PORTJ    (*(PORT_t *) 0x0700)  /* Port J */
#define PORTK    (*(PORT_t *) 0x0720)  /* Port K */
#define PORTQ    (*(PORT_t *) 0x07C0)  /* Port Q */
#define PORTR    (*(PORT_t *) 0x07E0)  /* Port R */

 

Greg Muth

Portland, OR, US

Atmel Studio 7.0 on Windows 10

Xplained/Pro/Mini Boards mostly

 

 

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

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

@clawson said:

Or use this...

Sweet!  I see changes coming to the ATmega328PB project I am working on.

Greg Muth

Portland, OR, US

Atmel Studio 7.0 on Windows 10

Xplained/Pro/Mini Boards mostly

 

 

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

Of course my Python script just produces "one big struct" with the structs for all the peripherals gathered together in a layout that (hopefully)  reflects the entire SFR layout so it's not quite the same as PORT_t type for Xmega (but that could easily be done).