Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Combining I/O Pins from different port

Status
Not open for further replies.

pubo

Newbie level 4
Newbie level 4
Joined
Feb 15, 2012
Messages
5
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,336
Hi there.

I'm doing a project using pic 16F chips and was just wondering if its possible for me to "stitch" some scattered I/O pins into a new custom port?

For example, I have bit 1, 3 5, 7 of Port A; and bit 0, 2, 4, 6 of Port B spares.

Effectively, I'm looking to "stitch" them into a new 8 bit port, lets call it Port Z which will have port structure of [RA1 RA3 RA5 RA7 RB0 RB2 RB4 RB6]; with RA1 being the MSB and RB6 being the LSB

If so, any idea how to implement it? I'm coding in MPLab using HiTech C btw.

Any inputs would be great. :smile:
 

No way to do this. In C++ you could overload operators and create functions to simulate it, but not in C. You could write functions that simulate it, but again it's non-ideal.
 

Hello!

No way to do this. In C++ you could overload operators and create functions to simulate it, but not in C.
You could write functions that simulate it, but again it's non-ideal.

There is nothing, absolutely nothing that you can do in C++ and that you cannot do in C. The reason is that
basically C++ IS C. The behavior you are describing is encapsulated somewhere, but at the very low level
the process will happen in 2 times separated by a few clocks. And as you say, there would be a way to
"simulate" it, not really do it.

Example of putting a value a in a stitched port. Bits 1, 3, 5, 7 are on port A and bits 0, 2, 4, 6 are on port B.

Code:
#define S_PORT_A_MASK 0xAA // Stitched port bits 1, 3, 5, 6
#define S_PORT_B_MASK 0x55 // Stitched port bits 0, 2, 4, 6

void SetStitchedPortVal(uint8 val) {
    uint8 val_a;
    uint8 val_b;
    val_a = val & S_PORT_A_MASK;
    val_b = val & S_PORT_B_MASK;
    setportA(val_a);
    setportB(val_b);
}

If you overload an operator in C++, then you will end up writing the same kind of code, there is no magic.

Dora.
 
  • Like
Reactions: pubo

    pubo

    Points: 2
    Helpful Answer Positive Rating
My third sentence is for C.
I didn't say there was any magic. It's messy (it's almost a 'simulation' [or 'emulation'?], not real for either C or C++) either way.
It's just a lot messier in C.

To take your logic to another extreme - There is nothing you can do in C++ that you cannot do in op-codes. That doesn't mean I would want to do it in op-codes either.

Your sentence "C is C++" is not quite true. There are people who write C and compile with a C++ compiler, granted, yet the whole point of C++ is to embrace the 'things' that you cannot _easily_ do in pure C. Granted that _anything_ you can do in any language is possible in C or assembler or raw op-codes...
As much as I love C, if I was starting from scratch I wouldn't want to create a _large_ (and maintainable) project in C any more than I would create it in assembler. I'd use C++ or another language. Even though it would technically be possible in C or assembler.
 
Last edited:
  • Like
Reactions: pubo

    pubo

    Points: 2
    Helpful Answer Positive Rating
Haven't been coding much in C++, no comments on the difference between the two.

doraemon, interesting way you have there of masking the untargeted bits.

Was just wondering, will this affect the outcome if those other bits are used for other purposes, eg. RA0 is already designated for ADC input and I define a mask for that bit. Anyway, this gave me abit of idea to work on for now.

Will run some test and try it out. Thanks for the inputs guys.
 

It might work, but for certain processors it might not work. The reason is, that chances are that you've got scattered I/O pins because you're using integrated peripheral devices inside the chip. In some cases, actually writing (or reading) an entire port may cause that peripheral to have certain behavior (e.g. to reset a counter or something), and that would be undesired behavior. I don't know what the SetPort function does, but it might (say) be implemented as a function that reads the entire port, and then writes to the entire port. If it did that, it may have an interaction with the peripheral even though you are not manipulating those specific bits that are being used by the peripheral. Processors can have specific bit-setting instructions (i.e. just to set/clear bits, and not to read and write the entire port) so you may be ok, but basically your best bet is to read the user docs for the microcontroller carefully to ensure there is no interaction to the peripheral caused by a read, and by a write that would not modify the bits related to the peripheral, and just be careful to write only specific bits, and never to the entire port if you can help it.
 
  • Like
Reactions: pubo

    pubo

    Points: 2
    Helpful Answer Positive Rating
thanks for the warning. Since I'm using a C compliler, I'm hoping theres a way to "create" a shodow port and link the bits to the actual desired I/O pins in the background.

Guess it'll be too much fussing around to make it worth while. lol..
 

Hello!

Back to your post, you were saying "you could overload operators and create functions to simulate it, but not in C".
That's all the meaning of what I said : you can do it in C.

Just for info: I am using C++ all the time and I think I'm aware of its advantages.

It's just a lot messier in C.

Could you write it in your own clean way in C++? That would be useful for everybody.
Usually what is clean and what is messy is just a matter of taste.

doraemon, interesting way you have there of masking the untargeted bits.

The untargeted bits are used for some other purposes (if they were available, I guess you wouldn't need all that mess).
That's why I don't want to change their values). In fact, the seaport (and B) functions depend on the chip and should be
understood : set only the relevant bits and ignore the others). That can be done like this:
PortA &= ~S_PORT_A_MASK; // Reset all the bits used for the stitched port
PortA |= val_a;

Dora.

---------- Post added at 07:39 ---------- Previous post was at 07:27 ----------

Hello!

Sorry for the trouble, I posted this morning and my message appeared twice. I tried to erase one,
but both were erased.

No way to do this. In C++ you could overload operators and create functions to simulate it, but not in C. You could write functions that simulate it, but again it's non-ideal.

So basically what I was saying here is that there is nothing that you can do in C++ and not in C and that C++
cannot do magic any more than C. And since my code was lost in the process, here is a retry:

Code:
#define SPORT_A_MASK 0xAA  // Bits 1, 3, 5, 7 of stitched port
#define SPORT_B_MASK 0x55  // Bits 0, 2, 4, 6 of stitched port

void SetStitchedPortVal(uint8 val) {
    uint8 val_a;
    uint8 val_b;
    val_a = val & SPORT_A_MASK;
    val_b = val * SPORT_B_MASK;
    PortA &= ~SPORT_A_MASK;
    PortA |= val_a;
    PortB &= ~SPORT_B_MASK;
    portB |= val_b;
}

Dora.
 

Could you write it in your own clean way in C++? That would be useful for everybody.
Usually what is clean and what is messy is just a matter of taste.

Actually _usually_ it is not "just a matter of taste". Cleaner code is more readable, maintainable, less likely to be buggy. You sound intelligent so
I think you know that.
And stop with the 'magic' comments, nobody implied anything was magic, so stop creating an argument, it's not clever
on a forum, it's just juvenile.

Anyway, for those that might want to do it in C++ (academic at this stage since it's possibly unlikely that anyone might do
that on a small microcontroller), your main code would end up looking like this, which is certainly cleaner:

Code:
  SPort myporta;
  // set my port to any value, e.g. 0xff:
  myporta=0xff;

To get there, you'd create a class called SPort, which could contain something like:

Code:
class SPort
{
  public:
    SPort()
    {
      pA=&PORTA;
      pB=&PORTB;
    }
  
    SPort & operator=(const char &val)
    {
    	*pA=val & 0x55;
    	*pB=val & 0xAA;
    }
    
  private:
    char* pA;
    char* pB; 
      
    
};

(replace the 0x55 and 0xAA with your correct bitmasks).

You can argue that using a class is "just a matter of taste", and others may argue it is not 'less messier', but I'm not going to be the one to
continue that argument.
 

Hello!

your main code would end up looking like this, which is certainly cleaner:
Code:
SPort myporta;
  // set my port to any value, e.g. 0xff:
  myporta=0xff;

Yes, and in plain C the main code would just be a single line:
Code:
SetStitchedPortVal(0xFF);

And that's why I am saying it's a matter of taste. C++ hides the implementation in an object's method
or operator, C hides it in a function. There can be clean and messy C code, and there can be clean and
messy C++ code.
You can keep the implementation in StitchPort.c / .h with functions or StitchPort.cpp / .h in a class,
the core of the implementation will be just the same.

By the way, in your example:
Using *pA = val&0x55; to set bits 0, 2, 4, 6 will erase bits 1, 3, 5, 7 which is probably not what you
want because they are used for something else. If you correct the bug, you may notice that the
implementation you suggest is exactly the same as mine.

I'm using exclusively C++ in all my developments and you don't have to convince me of its
advantages, I'm already convinced.
Some of my customers don't want to hear about C++, they just want plain C. That's their taste, not mine,
but I have to comply because they pay for it.

Note that a good trick for these customers is to write C++ code in plain C. Call your objects structures,
and the customers will not notice it's just object oriented code.

Code:
typedef struct MyStruct {
    int mMember1;
    char * mMember2;
    void (*setMember1)(int m1);
    void (*setMember2)(char * m2);
};

And then after implementing the functions, I can have the exact same behavior as if the program had been
written in C++. The only restriction is that I don't have public, protected, private members.

You can argue that using a class is "just a matter of taste", and others may argue it is not 'less messier',

If I argue this and other argue differently, this is precisely a good proof that it's a just matter of taste.

Dora.
 

In my view, the problem is mainly referring to hardware properties of a respective processor family and performance of bit operations. Of course, there's an aspect of presenting or possibly abstracting the "split port" in C or other languages. But you don't need to think about it unless you verified, that the hardware provides the intended functionality.

There are many software libraries, e.g. for LCD module control, that provide split port features. To not depend on specific pins assignments, they usually perform a bit test and a conditionally bit set for each port pin, both on read and write. Operation speed will be respectively low but typically suffcient for a character LCD.

A specific problem with PIC processors is read-modify-write behaviour. The previous state is read from the port rather than the output register, this brings up problems with special pins like I2C and also heavily loaded pins.
 

Please stop this argument, it is getting nowhere.
If you have something constrictive to say in order to help the original posted then you are welcome to post it but no more arguing each other.

Alex
 

I wonder, if the following code might work.
Members comment please.

PORTA pins 1,3,5,7 and PORTB 2,4,6 need configuration as input/output .

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
volatile unsigned char           PORTZ ;             
 
volatile bit RZ0                 @ ((unsigned)&PORTA*8)+1;
volatile bit RZ1                 @ ((unsigned)&PORTA*8)+3;
volatile bit RZ2                 @ ((unsigned)&PORTA*8)+5;
volatile bit RZ3                 @ ((unsigned)&PORTA*8)+7;
volatile bit RZ4                 @ ((unsigned)&PORTB*8)+0;
volatile bit RZ5                 @ ((unsigned)&PORTB*8)+2;
volatile bit RZ6                 @ ((unsigned)&PORTB*8)+4;
volatile bit RZ7                 @ ((unsigned)&PORTB*8)+6;
 
volatile union {
    struct {
        unsigned    RZ0                 : 1;
        unsigned    RZ1                 : 1;
        unsigned    RZ2                 : 1;
        unsigned    RZ3                 : 1;
        unsigned    RZ4                 : 1;
        unsigned    RZ5                 : 1;
        unsigned    RZ6                 : 1;
        unsigned    RZ7                 : 1;
    };
} PORTZbits;

 

I wonder, if the following code might work.
PIC I/O SFRs are byte registers and can't be accessed by bit addresses as your code apparently assumes. All accesses to individual pins or pin groups have to rely on bit masks. All high level methods will reflect this somehow.
 

Hi everyone, thanks for all the inputs.

I've managed to acheived the desired operation by redefining the ports.

Its a pretty hectic process compared to the bit masking method but its doing what I'm looking for and have yet to give me any trouble.

I've pretty much changed the header file for the chip I'm using (as16F877.h file) but I think you could redefine the ports inside your main C file easily.
The example below is what I've changed.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//orginal PORT B declaration
 
PORTB                                  equ 0006h
#define RB0                            BANKMASK(PORTB), 0
#define RB1                            BANKMASK(PORTB), 1
#define RB2                            BANKMASK(PORTB), 2
#define RB3                            BANKMASK(PORTB), 3
#define RB4                            BANKMASK(PORTB), 4
#define RB5                            BANKMASK(PORTB), 5
#define RB6                            BANKMASK(PORTB), 6
#define RB7                            BANKMASK(PORTB), 7
#ifndef _LIB_BUILD
#endif
 
//new declaration
 
PORTB                                  equ 0006h
#define RZ3                            BANKMASK(PORTB), 0           //new RZ3
#define RB1                            BANKMASK(PORTB), 1
#define RZ2                            BANKMASK(PORTB), 2           //new RZ2
#define RB3                            BANKMASK(PORTB), 3
#define RZ1                            BANKMASK(PORTB), 4           //new RZ1
#define RB5                            BANKMASK(PORTB), 5
#define RZ0                            BANKMASK(PORTB), 6           //new RZ0
#define RB7                            BANKMASK(PORTB), 7
#ifndef _LIB_BUILD
#endif



I've yet to fully test the system out but up till now calling the new PORTZ have been able to let me write to the desired bits. Do comment if this method will post any reliability issues etc.
 
Last edited by a moderator:

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top