Find port/pin address by I/O peripheral

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

I like it how Arduino knows which pins to enable for which SPI/USART/TWI/etc..

But I'm using Atmel Studio and I'm writing a program to make it flexible for the user to select which USARTMSPI they want to use to interface with a display via my driver. In order to initialize USART, I need to mark the USART pins as output. That works for my fixed configuration, but there's more combinations of USARTs and multiple pinouts from multiple XMEGAs and XMEGA boards that people work on. It's not always going to be USARTC0 that's available, but to some, it will be USARTC1, to some USARTF1, etc.. So how am I going to predict which pins I need set as output?

USART_t* TermUART = &USARTE0;

void termuart_init()
{
	PORTE_OUTSET=1<<3;
	PORTE_DIRSET=1<<3;
	TermUART->BAUDCTRLA=17;
	TermUART->BAUDCTRLB=0;
	TermUART->CTRLC=USART_CMODE_ASYNCHRONOUS_gc|USART_PMODE_DISABLED_gc|USART_CHSIZE_8BIT_gc;
	TermUART->CTRLB=USART_RXEN_bm|USART_TXEN_bm;
}

Here's my code for the normal USART I use for PC communication. How am I supposed to predict which port's OUTSET and DIRSET needs to be configured for any XMEGA?

 

Is there an already written code that maps I/O pins to their pin_mask_t-s and PORT_t-s?

 

Here's how it's done in Arduino (I've removed all the #define-s that aren't of AVR)

	if(hwSPI) { // Using hardware SPI
		SPI.begin();
		SPI.setClockDivider(SPI_CLOCK_DIV4); // 4 MHz (half speed)
		SPI.setBitOrder(MSBFIRST);
		SPI.setDataMode(SPI_MODE0);
		} else {
		pinMode(_sclk, OUTPUT);
		pinMode(_sid , OUTPUT);
		clkport     = portOutputRegister(digitalPinToPort(_sclk));
		dataport    = portOutputRegister(digitalPinToPort(_sid));
		clkpinmask  = digitalPinToBitMask(_sclk);
		datapinmask = digitalPinToBitMask(_sid);
		*clkport   &= ~clkpinmask;
		*dataport  &= ~datapinmask;
	}

 

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

Foxcat385 wrote:
How am I supposed to predict which port's OUTSET and DIRSET needs to be configured for any XMEGA?

One way would be a look up table I guess? The other is to have the user specify a number of values when they instantiate the driver. (this is starting to get very C++ like!). Looking at your code you have:

USART_t* TermUART = &USARTE0;

but suppose you wrap this (which is already a complex structure into something more complex like:

typedef struct {
    USART_t * UART;
    volatile uint8_t * pPort_out;
    volatile uint8_t * pPort_dir;
    uint8_t  pin_number;
} myUARTConfig_t;

myUARTConfig_t Term = { &USARTE0, &PORTE_OUTSET, &PORTE_DIRSET, 3};

and now your config stuff is something along the lines of:

void termuart_init()
{
    *Term.pPort_out = 1 << Term.pin_number;
    *Term.pPort_dir = 1 << Term.pin_number;
    Term.UART->BAUDCTRLA=17;
    Term.UART->BAUDCTRLB=0;
    Term.UART->CTRLC=USART_CMODE_ASYNCHRONOUS_gc|USART_PMODE_DISABLED_gc|USART_CHSIZE_8BIT_gc;
    Term.UART->CTRLB=USART_RXEN_bm|USART_TXEN_bm;
}

If you did this as C++ rather than C the syntax could be nicer as:

myUARTConfig_t Term = { &USARTE0, &PORTE_OUTSET, &PORTE_DIRSET, 3};

would effectively become:

myUARTConfig_t Term = Termclass(USARTE0, PORTE_OUTSET, PORTE_DIRSET, 3};

BTW I just made all this up as I went along to illustrate my thinking. No guarantees that any of this even compiles let alone does the right thing. That's left as an easy exercise for the reader!

Last Edited: Fri. Feb 12, 2016 - 02:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Perhaps dig down into ASF to see how they might do it?

 

Foxcat385 wrote:
... I'm writing a program to make it flexible for the user to select which USARTMSPI they want to use to interface with a display via my driver.

 

IME I like to resolve all those things at build time, not at run time.  Will anyone really desire a feature to run e.g. your SPI on one channel, and then re-build the app hardware to use a different channel but require that no re-build be done? 

 

[The 'Freaks have been over and over "generic I/O" over the years.  IMO, "just say No!" on AVR8.]

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

Alright, I don't understand what that means. Should I use #define-s instead?

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

Foxcat385 wrote:
Should I use #define-s instead?

You didn't like my suggestion then?

 

(Like Lee I wouldn't do this - but if you see some merit in it then I'm fairly happy with the suggestion I made).

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

I do like your idea, but I still think about if using classes and objects is a bit unoptimized as objects require indirect addressing instead of LDS and STS opcodes. Correct me if I'm wrong, but that's just my mystification which could be true or false. The only way the display object would be most optimized is if it's declared as a global variable and not a stack variable or a heap variable. Also, it's possible to corrupt the RAM with stack overflow or buffer overflow which would cause random register activation whereas using const ports that are configurable in compile time via preprocessor would make faster and safer code execution. What do you think?

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

You are wrong. Have you tried it? Have you looked at the generated code?

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

Sorry, I haven't. I guess I was lazy. I'm sorry about that. I won't be next time.