Declare Static Variables of type PORT_t and TWI_t

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

Hello, I'm trying declare a copy of a struct that is static so I don't have to use defines as they haven't been reliable (see topic about define values changing). Here's the code snippet, my compiler really doesn't like the second two lines:

 

#define TWI_BAUDRATE(F_TWI) ( (F_CPU / (2000 * F_TWI) ) - 5)

static PORT_t &twi_port = PORTC;
static TWI_t &twi = TWIC;
static const uint16_t twi_freq = 400; //kHz

volatile uint8_t buffer[14];


void TWIInit(TWI_t *port)
{
	twi_port.DIRSET = 0x03;
	twi.MASTER.BAUD = TWI_BAUDRATE(twi_freq);
	twi.MASTER.CTRLA = TWI_MASTER_INTLVL_LO_gc | TWI_MASTER_RIEN_bm | TWI_MASTER_WIEN_bm | TWI_MASTER_ENABLE_bm;
	twi.MASTER.STATUS = TWI_MASTER_BUSSTATE_IDLE_gc;
}

Is there a proper way to accomplish what I'm trying to do besides using defines (#define MPU_PORT &PORTC #define MPU_TWI &TWIC will probably work)?

Or is possible to make sure the values can't be changed by the compiler when they're put in functions like TWIStart(twi, MPU_ADDRESS, true) which is declared as TWIStart(TWI_t *port, uint8_t addr, bool write);

This topic has a solution.
Last Edited: Tue. Dec 3, 2019 - 08:31 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Astray wrote:
see topic about define values changing

It's a lot easier if you just give a link!

 

You mean this:  https://www.avrfreaks.net/forum/defined-value-changing  ?

 

Astray wrote:
my compiler really doesn't like the second two lines

What, exactly, does it "not like" about them?

 

Copy & paste the error message(s).

 

EDIT

 

static PORT_t &twi_port = PORTC;
static TWI_t &twi = TWIC;

That's not legal 'C' - you can't use the '&' operator like that at all.

 

It's not to do with the PORT_t or TWI_t types!

 

EDIT 2

 

and the code is incorrect anyhow:

static PORT_t &twi_port = PORTC;;

 

The definition of PORT_t is:

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;

 

and

#define PORTC                (*(PORT_t *) 0x0640) /* I/O Ports */

 

so the assignment doesn't make sense!

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...
Last Edited: Mon. Dec 2, 2019 - 12:40 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What you are trying to do is cast the PORT_t structure onto some fixed address. As Andy just showed that's exactly what "PORTC" does in a #define (casts PORT_t type onto address 0x640) so #define is almost inevitable.

 

There are, however two way I could think of approaching this: 

 

1) One would be to use a named section so something like:

__attribute__((section(".myportc"))) PORT_t myPortC;

then later:

--section-start=.myportc=0x800640

(the 0x800000 offset says "in RAM space not flash or EEPROM space")

 

2) using a fairly new addition to the compiler. See the "address" attribute documented towards the bottom of this page:

 

https://gcc.gnu.org/onlinedocs/gcc/AVR-Variable-Attributes.html

 

So:

__attribute__((address(0x640))) PORT_t myPortC;

On reflection I think I prefer (2). It's clearly a development of (1) anyway but that cuts out the need to define an intermediate private section.

 

But this is, I'm sure you know, a complete wild goose chase as the premise on which you believe you need this is clearly flawed in the first place!

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


Later. I built this:

#include <avr/io.h>

__attribute__((section(".myportc"))) PORT_t myPortC_v1;
__attribute__((address(0x640))) PORT_t myPortC_V2;

int main(void)
{
	myPortC_v1.DIR = 0x55;
	myPortC_V2.DIR = 0xAA;
}

and got this:

00000212 <main>:
__attribute__((section(".myportc"))) PORT_t myPortC_v1;
__attribute__((address(0x640))) PORT_t myPortC_V2;

int main(void)
{
	myPortC_v1.DIR = 0x55;
 212:	85 e5       	ldi	r24, 0x55	; 85
 214:	80 93 40 06 	sts	0x0640, r24	; 0x800640 <myPortC_v1>
	myPortC_V2.DIR = 0xAA;
 218:	8a ea       	ldi	r24, 0xAA	; 170
 21a:	80 93 40 06 	sts	0x0640, r24	; 0x800640 <myPortC_v1>

So both methods work.

 

For the named section one (v1) I also set up:

 

 

As doing this is cubersome I think I'd simply go with (2).

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

awneil wrote:

Astray wrote:
see topic about define values changing

It's a lot easier if you just give a link!

 

You mean this:  https://www.avrfreaks.net/forum/defined-value-changing  ?

Yes, that is the topic I was referencing. I found out the code I was attempting to use was .cpp code so that explains a lot.

 

clawson wrote:

Later. I built this:

#include <avr/io.h>

__attribute__((section(".myportc"))) PORT_t myPortC_v1;
__attribute__((address(0x640))) PORT_t myPortC_V2;

int main(void)
{
	myPortC_v1.DIR = 0x55;
	myPortC_V2.DIR = 0xAA;
}

and got this:

00000212 <main>:
__attribute__((section(".myportc"))) PORT_t myPortC_v1;
__attribute__((address(0x640))) PORT_t myPortC_V2;

int main(void)
{
	myPortC_v1.DIR = 0x55;
 212:	85 e5       	ldi	r24, 0x55	; 85
 214:	80 93 40 06 	sts	0x0640, r24	; 0x800640 <myPortC_v1>
	myPortC_V2.DIR = 0xAA;
 218:	8a ea       	ldi	r24, 0xAA	; 170
 21a:	80 93 40 06 	sts	0x0640, r24	; 0x800640 <myPortC_v1>

So both methods work.

 

For the named section one (v1) I also set up:

 

 

As doing this is cubersome I think I'd simply go with (2).


I'll definitely give this a shot. I would like to use defines honestly, but when I tried previously with the code it would change the value of the define. I would pause the debugger and it would be stuck in a while loop that was pointing to the wrong port for TWIE.

 

When I paused the program that's running, the port* value will be reported as 0x02a0 or 0x00a0 instead of the 0x04a0 that it should be. It would happen at the while loop of the below code and I had no idea to force the compiler to treat define as untouchable:
 

unsigned char TWIStart(TWI_t *port, uint8_t addr)
{
	//address given determines read or write
	port->MASTER.ADDR = addr;

	while( !(port-> MASTER.STATUS & 0xC0) );

	if(port->MASTER.STATUS & TWI_MASTER_RXACK_bm)
	{
		port->MASTER.STATUS |= TWI_MASTER_WIF_bm;
		port->MASTER.STATUS |= TWI_MASTER_RIF_bm;
		port->MASTER.STATUS = TWI_MASTER_BUSSTATE_IDLE_gc;
		return 1;
	}
	else
	{
		return 0;
	}
}

It would be called by a line of code like this: TWIStart(MPU_TWI, (MPU_ADDRESS | TWI_WRITE)); and the value of port would change from 0x04a0 to 0x02a0 and then 0x00a0.

Last Edited: Mon. Dec 2, 2019 - 01:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

 

Astray wrote:
Is there a proper way to accomplish what I'm trying to do

I'm not sure I see what you're trying to do at all!

 

clawson wrote:
the premise on which you believe you need this is clearly flawed in the first place!

I suspect he may be right about that:

 

Remember that the PORT_t and TWI_t are just meant to give a 'C'-style description of the port registers - they are not intended for creating variables!

 

So you also need to remember that port registers are not just memory - so what you write to them is not necessarily the same as what you will read-back from them.

So trying to maintain a "shadow" copy in a variable is unlikely to be meaningful.

 

Perhaps you could explain further what it is that you are actually trying to achieve?

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

Astray wrote:

but when I tried previously with the code it would change the value of the define.

clearly nonsense.

 

A #define in C is nothing but a string substitution. If I write:

int main(void)
{
	PORTC.DIR = 0xFF;

The C compiler does not even "see" "PORTC". This text is first passed to a pre-processor and it simply does a (nested) string substitution so what the C compiler finally sees is:

# 8 ".././main.c" 3
(*(PORT_t *) 0x0640)
# 8 ".././main.c"
     .DIR = 0xFF;

or, with comments removed:

(*(PORT_t *) 0x0640).DIR = 0xFF;

There is no way the C comiler can consider this as anything else but - take the value 0x640, treat it as the base address of a PORT_t type structure, set the member offset from that base of the ".DIR" member to 0xFF. That is all this could possibly ever do. It won't write "the wrong address" or "fail to write" or anything like that.

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

clawson wrote:

Astray wrote:

 

but when I tried previously with the code it would change the value of the define.

clearly nonsense.

Indeed.

 

That was explained in the previous thread:  https://www.avrfreaks.net/forum/defined-value-changing

 

Seems the OP needs to go back there, and properly resolve that issue.

 

Maybe Astray is confusing the address with the data which gets written/read to/from that address?

 

Possibly also not realising:

 port registers are not just memory - so what you write to them is not necessarily the same as what you will read-back from them.

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...
Last Edited: Mon. Dec 2, 2019 - 01:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

 

static PORT_t &twi_port = PORTC;
static TWI_t &twi = TWIC;

That's not legal 'C' - you can't use the '&' operator like that at all.

 

It's not to do with the PORT_t or TWI_t types!

 

 

Is this C++? It would be valid ('&' as 'reference' operator, which basically creates a new name for an object).

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

good point.

 

But the point about  port registers being not just memory remains ...

 

 

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

another approach is "const PORT_t *pPORTC = &PORTC;" and use pPORTC as a pointer: pPORTC->DIR = ...

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

But that will only stop explicit writes from 'C' via the pointer.

 

Again, these are not just memory locations - they are registers connected to hardware

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: 1

MattRW wrote:
another approach is "const PORT_t *pPORTC = &PORTC;" and use pPORTC as a pointer: pPORTC->DIR = ...
But it seems yer man believes that #define's lie and "PORTC" cannot be trusted so you can't use something that is based on something he (wrongly) thinks he cannot trust.

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

#define MPU_PORT &PORTC
#define MPU_TWI &TWIC

 

These were the defines I was using but the code would get stuck at the while loop of the code of post #5:

while( !(port-> MASTER.STATUS & 0xC0) );

 

When I paused, the address in the port was said to be 0x02a0 or 0x00a0 instead of 0x04a0 when I had a watch on Port.

 

The function was called by:
TWIStart(MPU_TWI, (MPU_ADDRESS | TWI_WRITE));

 

This was the declaration of the function:
unsigned char TWIStart(TWI_t *port, uint8_t addr)

 

I have no idea why the value of port would ever change, but the watch on Port said it did.

Last Edited: Tue. Dec 3, 2019 - 03:50 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

port is your variable - so can you set a data breakpoint to see when anything writes to it?

 

To protect the pointer itself from being written - rather than the data at which it points - you would have to declare the pointer as 'const' ...

 

Again, in your other thread, there were buffer overruns - no 'const' trickery is going to help against that!

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

The buffer overrun that was pointed out in that thread didn't do anything. I removed it from the code entirely and also fixed the cause of that particular overrun and I was still getting the same issue regardless.

 

const or volatile might be useful to protect the port though, I'll experiment with those.

Last Edited: Tue. Dec 3, 2019 - 03:59 AM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am happy to report that I have gotten the code working with defines by using volatile when passing the port.

 

I don't want to post 200+ lines of code here so I'll just include them in a file below. This will get raw and scaled data off an MPU6050 using TWI for xmega.

Attachment(s): 

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

Astray wrote:
The buffer overrun that was pointed out in that thread didn't do anything.

Indeed.

 

But that was just one buffer overrun - if there was  one, there might have been others ...

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...