12
\$\begingroup\$

Q: Can individual pins of different port of a micro-controller be mapped to a register and their values be changed when changing the register value?

Scenario: I have used up some pins from each port(8-bits) of the micro-controller. Now I want to interface a device which needs an 8-bit bus (suppose D0 to D7 IN SEQUENCE) that is to say I need 8 pins from controller so that I can connect them in one-to-one fashion

portx0  -> D0 // x is the name of port followed by bit location on that port
portx1  -> D1
...
portx7  -> D7

but I don't have a whole port of 8 pins which I can connect with this device, rather I have some pins from portx, some from porty and some pins from portz. The new connection scenario is as (connection from micro-controller to device respectively )

portx0  -> D0
portx1  -> D1
portx2  -> D2
porty4  -> D3
porty5  -> D4
porty6  -> D5
porty7  -> D6
portz1  -> D7

In this condition if I want to send a value say

unsigned char dataReg = 0xFA;

to my device from controller I have to perform bit wise operations on the value to be sent and set each pin according to the value in the register individually. For example

portx0 = ((dataReg & 0x01) >> 0 );  // Masking and shifting as bit position
portx1 = ((dataReg & 0x02) >> 1 );
portx2 = ((dataReg & 0x04) >> 2 );
porty4 = ((dataReg & 0x08) >> 3 );
porty5 = ((dataReg & 0x10) >> 4 );
porty6 = ((dataReg & 0x20) >> 5 );
porty7 = ((dataReg & 0x40) >> 6 );
portz1 = ((dataReg & 0x80) >> 7 );

Now, coming to the main question, to avoid these individual calculations on each bit on different ports, can individual pins of different port of a micro-controller be mapped to a register and their values be changed when changing the register value?

\$\endgroup\$
  • 1
    \$\begingroup\$ I had the same idea a while ago. With PICs, this isn't possible: microchip.com/forums/tm.aspx?high=&m=696277 - I don't think it's possible with any micro, but listing your device would be helpful. \$\endgroup\$ – user17592 Feb 22 '13 at 10:05
6
\$\begingroup\$

It appears your question comes down to having a 8 bit value in the firmware, and wanting to read and write that from and to a arbitrary collection of port pins.

There is no direct hardware way to do this. You have to write two routines, one to read the 8 bit value and one to write it. Others have mentioned using unions, but that is a bad idea. With unions, you have to deal with every bit separately, and the code becomes dependent on the bit order of the micro. This might be the way to go anyway if all the 8 bits are scattered completely independently. If so, there is little you can do but to make special code for each bit.

The better way to do this, especially if you can group the bits in a few contiguous chunks on the physical ports is to use masking, shifting, and ORing. For example, if the low three bits of the internal byte are on bits <6-4> of a port, right shift that port value by 4 and AND it with 7 to get those bits into their final position. Shift and mask (or mask and shift) bits from other ports into place and assemble the final 8 bit byte by ORing the results into it.

This kind of low level bit twiddling is easier to do in assembler than C. I'd probably put the byte read and write routines in a single assembler module and make the interface callable from C.

\$\endgroup\$
  • 6
    \$\begingroup\$ My answer would be almost identical to yours, except that I would not use assembly at all; the bit manipulations are trivial in C. I think it'd be more of a headache (re)learning the specific C calling convention for the compiler and how to run the linker. Depends really on the compiler and how difficult it makes things. :-) \$\endgroup\$ – akohlsmith Feb 22 '13 at 13:41
  • \$\begingroup\$ @Andrew: Seriously? The calling conventions are clearly spelled out in any compiler manual I've seen where there might be a need to interface with assembly code. The bit manipulation may be "trivial" to write in C, but this is a area where compilers can produce horrendous code. If speed or code space doesn't matter, use whatever you are more comfortable with. I'm more comfortable with assembler for low level bit twiddling, so I'd use that. If this is a low level speed-crictical routine you should do it in assembler. It really should be easy. \$\endgroup\$ – Olin Lathrop Feb 22 '13 at 15:39
  • 1
    \$\begingroup\$ What I'm saying is that having to putz around with that for something as trivial as bit manipulation isn't something I'd do unless there was a very good reason for it. We don't know the specifics of his parallel bus but most buses have strobe signals that eliminate the need for "near atomic" updates of all bus pins, so dropping to assembly is likely an unnecessary optimization and an unneeded complexity (even if it is straightforwardish). \$\endgroup\$ – akohlsmith Feb 22 '13 at 15:52
  • \$\begingroup\$ @Andrew: It's only putzing around or complex if you don't know what you're doing. I think the real problem is that some people are afraid of assembler and don't know it well. That's a mistake. It needs to be a ready tool in your toolbox. If you don't know it well or are uncomfortable with it, you'll always be justifying how things should be done some other way. Some things are easier in assembler if you know it and the HLL equally well. Most people don't, but that's a problem with them, not with using assembler. \$\endgroup\$ – Olin Lathrop Feb 22 '13 at 16:49
  • 2
    \$\begingroup\$ I'm well-versed in assembly language on a number of microcontrollers/microprocessors. I disagree that it should be a ready tool; it should be used sparingly and only when necessary, usually for very low-level initialization, timing- or size-critical code or in the more common case, optimization of an area you have already determined to be a bottleneck. I find that projects where authors who jump to assembly because it's there often write less clear code or don't recognize when an algorithm is being misapplied. I'm not specifically saying that is you, but rather in the more general case. \$\endgroup\$ – akohlsmith Feb 23 '13 at 0:07
4
\$\begingroup\$

In general this is not possible. As far as I know, it's not possible with PICs.

There is only one microcontroller I know which can do this, the Cypress PSoC. It's a highly configurable system on chip. Of the many things it allows you to do is to literally define your own register (1-8 bits) and connect it to any pins you like, or even to internal circuits.

PSoC Wiring

For example, here I have created a 6-bit control register. 5 of the bits go straight to pins, while the 6th bit I'm using to XOR with the input from a 7th pin.

PSoC Pins

On the chip, I can choose to allocate these pins to any of the available GPIO pins. (It's the grey ones one the image)

\$\endgroup\$
  • 1
    \$\begingroup\$ LPC800 should also be able to do it, as functions can be assigned freely to pins. \$\endgroup\$ – starblue Feb 22 '13 at 16:09
-1
\$\begingroup\$

You may try the following. Write a structure of your own which maps to respective pins of the 2 ports(which are to be used) Now updating the value in this register shall set/reset the pins of those 2ports. Just try and let us know if it worked !!

I am confident this should work.

\$\endgroup\$
  • 2
    \$\begingroup\$ In C you can map a structure to a memory location, and you can map bits of your structure (bit fields) to bit offsets, but there is no way to prevent the compiler from messing with the 'inbetween' bits, and there is now way to view the 'overall' structure a single integer value. This won't work. \$\endgroup\$ – Wouter van Ooijen Feb 22 '13 at 15:07
-1
\$\begingroup\$

If I've understood the question correctly, it's easy enough in C:

Generic type declaration, can be re-used for any register:

typedef union    // Generic 8-bit register Type
{
  uint8 reg; // Whole register
  struct
  {
    unsigned  bit7     : 1;  // Bit 7 
    unsigned  bit6     : 1;  // Bit 6 
    unsigned  bit5     : 1;  // Bit 5 
    unsigned  bit4     : 1;  // Bit 4 
    unsigned  bit3     : 1;  // Bit 3 
    unsigned  bit2     : 1;  // Bit 2 
    unsigned  bit1     : 1;  // Bit 1 
    unsigned  bit0     : 1;  // Bit 0 
  } bit;
} typ_GENERIC_REG8;

So, to define a port we want to address:

#define MCU_GPO_PORTx   (*(volatile typ_GENERIC_REG8 *)(0x12345678)) // Number is address

And to directly twiddle a pin on that port:

#define MCU_PORTx_PINn  (MCU_GPO_PORTx.bit.bit0)

In code:

MCU_PORTx_PINn = 1; // Set pin high

Entire register:

MCU_GPO_PORTx.reg = 0xF; // All pins high

Well worth reading up on structs, unions, typedefs and enums - all of these make life so much nicer in embedded & in general!

\$\endgroup\$
  • \$\begingroup\$ OP wants to combine several bits from different ports into 'one byte'. I don't see how this would do that? Olin Lathrop explains why it isn't possible. \$\endgroup\$ – user17592 Feb 22 '13 at 13:34
  • \$\begingroup\$ This doesn't actually address the issue, and depending on how "smrt" your compiler is, could generate a whole new set of troubles to debug. \$\endgroup\$ – akohlsmith Feb 22 '13 at 13:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.