1

It will be more convenient for me to use all the MSP430 ports as one port. I was thinking maybe to overflow the registers until the next memory address, but it's not working (or maybe i'm not doing it right).

To access BIT0 of PORT2, I tried Something like that:

P1OUT |= 0x80000000000;

because in the memory P2OUT (0x0029) is 8 addresses after P1OUT (0x0021), and those are 8bit registers in the middle. so 8x8=64.

I know I can access the P2OUT with an offset like this:

*(char *)(0x0021 + 0x0008)  |=  BIT0;

I want to define myself a list of GPIO's from 1 to 13, and turn them on and off without checking if GPIO11 is on PORT2 or on PORT1, I want one command to do it all.

is is possible?

Itay
  • 322
  • 1
  • 3
  • 15

3 Answers3

3
P1OUT |= 0x80000000000;

This does not work because

  1. you did not count bits correctly:

    P1OUT |= 0x10000000000000000;
    
  2. P1OUT is an 8-bit register, so the compiler would throw away all but the lowest eight bits. You would have to use a data type that is large enough (and the bit you want to set is the 65th bit in memory, so you'd need a type larger than 64 bits):

    *(uint128_t*)&P1OUT |= 0x10000000000000000;
    
  3. There is no 128-bit type.

You can get what you want with another layer of indirection:

volatile uint8_t * const ports[] = { &P1OUT, &P2OUT, &P3OUT };

static inline void setGPIO(unsigned int number)
{
    *ports[number / 8] |= 1 << (number % 8);
}
CL.
  • 173,858
  • 17
  • 217
  • 259
  • Wow! Thank you! I like your solution! – Itay May 22 '15 at 18:04
  • 1
    Shouldn't that be `1 << (number % 8)` or equivalently `1 << (number & 7)`? The argument to the OR operator is a bitmask, not a bit index. – Ben Voigt May 22 '15 at 18:07
  • @BenVoigt: note that this will add significant overhead to your code. Also, some MSP430 already allow to access two adjacent ports (P1/2, P3/4) by a single 16 bit read/write. Normally for embedded systems, you would use `one #define' for port and bit-number/mask instead which are named for their symbolic usage. Put that into some `hardware_config.h` you include in each affected source file and you'r fine. – too honest for this site May 22 '15 at 21:04
  • @BenVoigt, CL: This should better be either `uint16_t`/etc. or - best `size_t`. – too honest for this site May 22 '15 at 21:05
  • @Olaf The CPU used here, the G2553, does not have 16-bit ports. And where would `size_t` make sense? – CL. May 23 '15 at 06:37
  • Yeah, that would be the x5xx-family with PA/PB/... Which one does the TO use actually; did I miss that in his question?. See the rationale for size_t in the standard. Your approach would require a similar table for all other registers like `PxIN`, `PxDIR`, `PxSEL`, ...Each table costs Flash and needs at least some wrapper function. Otherwise the whole approach is just inconsistent. Not to mention the added code for the caalculations which costs clock cycles (interrupt-handler, Power!). – too honest for this site May 23 '15 at 12:16
1

No, surplus data does not overflow from one memory address to the next. If you write data to an 8-bit address, the extra (most significant) bits are truncated.

There are several ways you can approach this. You can have a set of functions for each port bit, for example

write_GPIO_11(int bitval) {             // pass 0 or 1
    if (bitval)
        P2OUT |= 0x08;
    else
        P2OUT &= 0xF7;
}

Or have separate functions set_GPIO_11 and clear_GPIO_11, which would be more efficient and better for inline functions.

You could also use macros

#define GP11_ON (P2OUT |= 0x08)

...

GP11_ON;

However since you talk about overflowing from one port to the next, I wonder if you also want to write all 13 bits with a single instruction (which would have to be 16-bit value). This can't be done with a single write, but you could have a single function call, which again could be inline.

write_GPIO_bits(unsigned int bitvals) {
    P1OUT = bitvals;
    P2OUT = bitvals >> 8;
}

And so on.

Weather Vane
  • 33,872
  • 7
  • 36
  • 56
  • thank you for your answer. I didn't want to write so many function since I have a memory limit, so I wanted to make it shorter as it can be. @CL. 's answer might fit me needs – Itay May 22 '15 at 19:29
  • Then perhaps the macro approach will suit you, since inline code executes quicker. But using functions does not necessarily use more code memory. – Weather Vane May 22 '15 at 19:32
0

I use the following approach:

"hardware_config.h":

#define CONCAT_(a, b) a##b

#define BITSET(p, m) (CONCAT(p, OUT) |= m)

#define LEDGN_PORT P1
#define LEDGN_MASK 0x01

The helper functions might better reside in a different header file.

Usage:

BITSET(LEDGN_PORT, LEDGN_MASK);

This adds no overhead to program code.

too honest for this site
  • 12,050
  • 4
  • 30
  • 52