Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

ARM Cortex

Status
Not open for further replies.
Jason:

two ways, depending on what chip you use.

1) set / clear the pins: for most arm chips, you don't have the pin by pin control you do on the pic. you will have to set or clear pins. IOSET = 0x0F (or its variants, depending on your chips again) for example would set the last 8 bits (0-7) high; and IOCLR = 0x0F will clear the last 8 bits. You obviously will need to configure PINSEL and IODIR registers (or their equivalent, again depending on the chip).

on some chips, you can use mask, or fast IO (FIOSET for example) to speed up the process.

2) bit-by-bit: there is available on Cortex (M3 at least and likely others). I am learning this right now so I may not be 100% correct. In Cortex M3, each register has an address and associated memory alias. You can thus define a word in the alias area to correspond to a bit on the register. Once you change the word in the alias area, the bit in the register would change - in theory anyway, :). This will make programming bits almost identical to that on the pic.

Hope it helps.
 
The ARM7's have a 32 pin wide port and have separate set and clear peripheral register, so if you wanted to set pins 0 to 7 with 0x03, you would have to clear all those pins first CLR_PORTA_REGISTER = 0x00FF, then set what you wanted, SET_PORTA_REGISTER = 0x0003.

It's a little confusing, because in order to clear a pin, you have to write a 1 to it's associated bit in the clear register.

With a port that's 32 pins wide, you don't need to fiddle around, if some of the pins you have are on one port or another, unless your running a 100pin chip, they are likely all to be on one PORT.

EDIT: I'd say I was ninja posted, but 9 minutes between post times, I guess I just had this page sitting here for a while.
 
Last edited:
the fact that they use two instructions, IOSET to set and IOCLR to clear, to change a pin / port raises some interesting questions, especially for high-speed parallel IO.

say that you want to output i=0b10101010 on pin0...7, which has value now of 0b01010101. you will have to 1) set those 1 pins per i - now the port outputs 0b1111111, and 2) then clear those 0 pins per i - now the port outputs 0b10101010. so between step 1) and 2), there is actually an intermediate output (0b11111111 in our case) on the port where all the 1 pins in i has been set, but all the 0 pins in i retains their earlier state.

for 32-bit ports, the problem is even more complicated because you will have to read the port's value via IOPIN and then mask off those pins you don't want to change (pin8..31 in this case).

how do they solve this problem?
 
You don't have to do anything with the other pins, 8 to 31 in this case. Setting a 0 in either the clear or set register essentially mean ignore those pins and they are untouched. You can see in my earlier example, which I screwed up a bit, setting 0x000F clears pin 0 thru 7 of PORTA, all other pins are untouched. Setting 0x0003 to PORTA, will set the pins that you want set. It has it's advantages and disadvantages.

Taking a quick look at the Stellaris Cortex-M3 datasheet, I'm dissappointed to see they chose to implement 8bit ports. They also do not have set and clear registers, but a GPIODATA register that works like the standard port register on most 8bits. They expanded its functionality with a mask register that allows you to specify which bits are actually updated with a write to the GPIODATA register.
 
yeah i was reading the datasheet. That is why they have :

IOSET = only sets does not clear
IOCLR = clear only no set.

i see... so do you think it would be easier to just make a function and pass it a variable like 0x03 and have it loop through the bits and set the pins as i wish?

Something like:
PORTA would be for me P0.0---to---P0.7
Code:
void ChangePortA(unsigned char NewVal){
if(NewVal & 0x01)
    IO0SET = 0x0000 0001 ;//P0.0 goes HIGH
else
    IOCLR = 0xFFFF FFFE    ;//P0.0 goes LOW

NewVal >>= 1;

if(NewVal & 0x01)
    IO0SET = 0x0000 0002 ;//P0.1 goes HIGH
else
    IOCLR = 0xFFFF FFFD    ;//P0.1 goes LOW
..............
.............
..........
}

or in binary
Code:
void ChangePortA(unsigned char NewVal){
if(NewVal & 0x01)
    IO0SET = 0b00000000000000000000000000000001;  //P0.0 goes HIGH
else
    IOCLR =   0b11111111111111111111111111111110;  //P0.0 goes LOW

NewVal >>= 1;

if(NewVal & 0x01)
    IO0SET = 0b00000000000000000000000000000010;  //P0.1 goes HIGH
else
    IOCLR =   0b11111111111111111111111111111101;  //P0.1 goes LOW

NewVal >>= 1;

if(NewVal & 0x01)
    IO0SET = 0b00000000000000000000000000000100;  //P0.2 goes HIGH
else
    IOCLR =   0b11111111111111111111111111111011;  //P0.2 goes LOW
.............
..........
}
Im trying to make my own PORT basically
 
Last edited:
Jason:

you can use a loop or for statement for that. But what it doesn't do is the flexibility of NOT setting / clearing any of the pins.

IOSET = 0b10 for example doesn't change the value of the 0th pin. with your function, it will set the 0th pin to 0.

now, that may or may not be the way you want it to be. for your code to work, you will have to know a) the pins you want to change, and b) the current value of the pins you do NOT wish to change.

that means you need a read, an operation, and then your port write. it may be more pain than it is worth, :).
 
"IOSET = 0b10 for example doesn't change the value of the 0th pin. with your function, it will set the 0th pin to 0."

That wont change the 0th pin.
 
Wouldnt this just set or clear the pins from p0.0 to p0.7
Code:
void ChangePortA(unsigned char NewVal){
char x;
char y;

    for(x=0;x<8;x++){
        y = 0x00000001 << x;

        if(NewVal & 0x01)
            IO0SET = y;     //P0.y goes HIGH
        else
            IOCLR =  y;     //P0.y goes LOW

        NewVal >>= 1;
    }
}
 
Last edited:
millwood:
Writing to IOSET/IOCLR .vs. IOPIN
Write to the IOSET/IOCLR register allows easy change of the port’s selected output pin(s)
to high/low level at a time. Only pin/bit(s) in the IOSET/IOCLR written with 1 will be set to
high/low level, while those written as 0 will remain unaffected. However, by just writing to
either IOSET or IOCLR register it is not possible to instantaneously output arbitrary binary
data containing mixture of 0s and 1s on a GPIO port.

maybe you where talking about :
Write to the IOPIN register enables instantaneous output of a desired content on the
parallel GPIO. Binary data written into the IOPIN register will affect all output configured
pins of that parallel port: 0s in the IOPIN will produce low level pin outputs and 1s in IOPIN
will produce high level pin outputs. In order to change output of only a group of port’s pins,
application must logically AND readout from the IOPIN with mask containing 0s in bits
corresponding to pins that will be changed, and 1s for all others. Finally, this result has to
be logically ORred with the desired content and stored back into the IOPIN register.
Example 2 from above illustrates output of 0xA5 on PORT0 pins 15 to 8 while preserving
all other PORT0 output pins as they were before.
 
"That wont change the 0th pin."

you are right and i was wrong: it would set the 1st pin to 1 and do nothing to the 0th pin.

yes, the port latency (from the time you write tot he port to the time the port actually changes value) is about 14+ cycles, as I read somewhere.
 
yeah so i was reading more and found out i can do this:
Code:
void ChangePortA(char port, unsigned char NewVal){
    if(port == 0)
        IO0PIN = (IO0PIN && 0xFFFFFF00 ) || NewVal;

    if(port == 1)
        IO0PIN = (IO0PIN && 0xFFFF00FF ) || NewVal;

    if(port == 2)
        IO0PIN = (IO0PIN && 0xFF00FFFF ) || NewVal;

    if(port == 3)
        IO0PIN = (IO0PIN && 0x00FFFFFF ) || NewVal;
}

And doing that i can split the port into 4...

Page 92 : "8.5.2 Example 2: an immediate output of 0s and 1s on a GPIO port"

LPC214x manual
 
Last edited:
Wouldnt this just set or clear the pins from p0.0 to p0.7
Code:
void ChangePortA(unsigned char NewVal){
char x;
char y;

    for(x=0;x<8;x++){
        y = 0x00000001 << x;

        if(NewVal & 0x01)
            IO0SET = y;     //P0.y goes HIGH
        else
            IOCLR =  y;     //P0.y goes LOW

        NewVal >>= 1;
    }
}

yea. you meant to use IO0CLR, I think.
 
I can also just do this for faster:
Code:
void ChangePortA(char port, unsigned long NewVal){
    if(port == 0){
        FIO0MASK = 0xFFFFFF00;
        FIO0PIN = NewVal;
    }

    if(port == 1){
       FIO0MASK = 0xFFFF00FF;
       FIO0PIN = (NewVal << 8);
    }

    if(port == 2){
       FIO0MASK = 0xFF00FFFF;
       FIO0PIN = (NewVal << 16);
    }

    if(port == 3){
       FIO0MASK = 0x00FFFFFF;
       FIO0PIN = (NewVal << 24);
    }
}

clipboard02-jpg.30661
 

Attachments

  • Clipboard02.jpg
    Clipboard02.jpg
    70.4 KB · Views: 591
Last edited:
The SAM7 has got different names for everything, but ya, you can directly set the GPIO pins as well, as long as you manage the associated mask not to set anything else as well.
 
i tried this for the 2106 but no luck i get a CPU error in Protues:
Code:
#include <LPC210x.h>

void ChangePortA(char port, unsigned long NewVal){
    if(port == 0)
        IOPIN = (IOPIN && 0xFFFFFF00 ) || NewVal;

    if(port == 1)
        IOPIN = (IOPIN && 0xFFFF00FF ) || (NewVal << 8);

    if(port == 2)
        IOPIN = (IOPIN && 0xFF00FFFF ) || (NewVal << 16);

    if(port == 3)
        IOPIN = (IOPIN && 0x00FFFFFF ) || (NewVal << 24);
}
void DelayUs(int us) {
	for (; us>0; us--);
}

void DelayMs(int ms) {
	for (; ms>0; ms--)
		DelayUs(1000);
}
int main(void){
	unsigned char x;
	PINSEL0=0x00;
	IODIR=0xff;

	while(1){
		for(x=0;x<8;x++){
			ChangePortA(0,x);
			DelayMs(1000);
		}
	
	}

}

but doent seem to do anything...
 
Last edited:
This works nice!
Code:
		for(x=0;x<31;x++){
			IOPIN  = (0x00000001 << x);
			DelayMs(500);
		}

im so dumb lol this works 100% ( i had it like "&&" and "||" lol
Code:
void ChangePortA(char port, unsigned long NewVal){
    if(port == 0)
        IOPIN = ((IOPIN & 0xFFFFFF00 ) | NewVal);

    if(port == 1)
        IOPIN = (IOPIN & 0xFFFF00FF ) | (NewVal << 8);

    if(port == 2)
        IOPIN = (IOPIN & 0xFF00FFFF ) | (NewVal << 16);

    if(port == 3)
        IOPIN = (IOPIN & 0x00FFFFFF ) | (NewVal << 24);
}

This is nice because you can ultimately define and create your own ports. if you have a LCD with 6 pins then you can create the port with that and then not worry about OR'ing later :D
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top