Accessing the Port_t associated with a SPI_t

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

So I have a function that is passed a SPI_t as a function variable.  In that function, in addition to manipulating the SPI port (SPIE.DATA = blah for example), I also need to access the port (PORTE.DIRSET = reset_pin_bm for example).

 

In the past, with libraries and such that I have written, these would have been #defined in a library header file (#define PORT  PORTE and #define SPI SPIE for example).  I am not able to do that in this case as I am trying to keep with the u8g programming model as I add atxmega functionality to it.  Because the xmega has multiple SPI ports on it, I have already modified the functions for the xmega to take an additional parameter, SPI_t SPI, so I can specify which SPI port I am talking to.  I could expand that further and pass the port as well as the SPI, but that seems redundant (SPIE is on PORTE after all).

 

My initial thought of "this will be easy to do!" appears to be false!  What I am trying to do is something along these lines (this does not work):

uint8_t foo(u8g_t *u8g, SPI_t *SPI, foo, foo, foo...) {
    PORT_t port;
    if ( &SPI == &SPIE ) {port = PORTE;}  // This assumes I should be able to get the starting address for SPIE...
    
    port.DIRSET = 0xff; // bad example but..
    SPI->DATA = 0xFA;
    blah
    blah
    blah
}

Needless to say, this will not compile.  Is there an easy way to determine the port from the SPI?  Or am I doomed to send both SPI and PORT to the function, or break the u8g model and #define it in a header somewhere?

 

Any other (BETTER would be GREAT!) ideas on how to approach this?

Thanks!

 

Clint

Last Edited: Sun. Apr 5, 2015 - 07:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
  PORT_t* port;
    if ( SPI == &SPIE ) {port = &PORTE;}
    port->DIRSET = 0xff;

But why no pass &PORTE as one of the parameters?

Last Edited: Sun. Apr 5, 2015 - 10:02 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ezharkov wrote:

  PORT_t* port;
    if ( SPI == &SPIE ) {port = &PORTE;}
    port->DIRSET = 0xff;

PORT_t* port;
if ( SPI == &SPIE ) {port = &PORTE;}
port->DIRSET = 0xff;

But why no pass &PORTE as one of the parameters?

 

Crap!  I didn't even think of that permutation!

 

The reason I don't want to pass an additional parameter is I'm trying not to mess with the u8g functions any more than I have to.  But from what I have seen, it has assumed there is only one SPI interface for any given processor, or at the very least, it only allows you to access one interface.

 

I really need to study up on pointers more.  Most of my programs tend to use them in fairly basic forms so I am definitely not as sharp on them as I need to be.

 

Clint

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

I have a function that is passed a SPI_t as a function variable.

Do you have an example from the u8g code?  If it's a pointer to a function, it's obviously not going to be "equal" to the "#define SPIE    (*(SPI_t *) 0x0AC0)"

if it IS a function, you could presumably add code to have it return the port, with very little impact in the rest of the libraries.

 

it has assumed there is only one SPI interface for any given processor, or at the very least, it only allows you to access one interface.

 I didn't look very carefully, but the code at https://code.google.com/p/u8glib/ looks like you could have separate SPI ports per display object instance.  For example, it has software SPI, which just needs several pins.

Most of the port-specific stuff is handled during the object creation.

 

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

westfw wrote:

I have a function that is passed a SPI_t as a function variable.

Do you have an example from the u8g code?  If it's a pointer to a function, it's obviously not going to be "equal" to the "#define SPIE    (*(SPI_t *) 0x0AC0)"

if it IS a function, you could presumably add code to have it return the port, with very little impact in the rest of the libraries.

 

it has assumed there is only one SPI interface for any given processor, or at the very least, it only allows you to access one interface.

 I didn't look very carefully, but the code at https://code.google.com/p/u8glib/ looks like you could have separate SPI ports per display object instance.  For example, it has software SPI, which just needs several pins.

Most of the port-specific stuff is handled during the object creation.

 

I was talking about modifying the hardware SPI initialization call to add the SPI_t argument to it.  No function pointers there.  The proper call posted earlier got that up and running it appears.

Most of what I am talking about at this time refers to hardware SPI, not software (I haven't tried to climb that mountain yet!  Not sure if I will given how many hardware SPI interfaces the xmega has).  I have not seen any way to even SPECIFY which SPI interface to use, let alone have multiple ones configured and running at the same time.  Just looking at the ARV atmega, it only uses the dedicated SPI unit and has no ability to use the USART in SPI mode. 

 

Given how different the configuration and register names are between those interfaces, that makes sense.  But with the xmega, they configuration is exactly the same between any of the SPI interfaces.  Just the interface names changes.  That makes it very easy to use any SPI interface you need by simply passing the SPI_t value to the assorted functions.  IF the firmware is designed to allow that.

 

Clint

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

Look at the addresses of the SPIs and the PORTs.  They are laid out intelligently so you can make a simple function to translate from on to the other.  I did this for TWIs:

/*!
\brief Converts a TWI_t*, TWI_MASTER_t* or TWI_SLAVE_t* to a PORT_t*

Converts &TWIC, &TWID.MASTER, &TWIE.SLAVE, &TWIF to &PORTC, &PORTD,
&PORTE, &PORTF.

CAVEAT: no error checking is performed so nonexistent or invalid TWI modules
will return an invalid PORT_t*.

\param t TWI_t*, TWI_MASTER_t* or TWI_SLAVE_t*, passed as (void*)

\return PORT_t*

*/
static inline PORT_t* get_twi_port(void* t)
{
	return (PORT_t*)((((uint16_t)t & 0x0030) << 1) + 0x0640);
}

 

Greg Muth

Portland, OR, US

Xplained/Pro/Mini Boards mostly

 

Make Xmega Great Again!

 

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

Greg, you are the man!  I suspected that could be done, but didn't dig into the datasheet and prove it.  That is simple and elegant!  Thanks for sharing it!

 

Clint