This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

direct referrence to GPIO pins

another newbie question.

I have a piece of code that I am porting from PICC. In PICC, you can make reference to specific pins ("#define sclk GPIO5" for example), and in your code, you can write to sclk to change the pin output on GPOI5. This makes porting code or changing pin layout so much easier as you can simple redefine sclk to a different pin to make the code work.

ARM seems to prefer to change its pin output through IOSET / IOCLR.

To make the existing PICC code work, I would prefer to be able to define certain pins logically, and change their states by referencing their logic names.

how do you do that in ARM? Thanks in advance.

  • "Note once more that it is the chip manufacturer that decides what peripherials to glue to the ARM core. So you can find different chips that has the identical ARM core but different registers and functionality for GPIO, UART, ADC, ..."

    that makes sense.

    I guess then the question becomes a) which ARM chips (chips that use an ARM core) allow for PIC-styled gpio access? I haven't seen one but I have very limited experience with those chips. so others with more experience may be able to provide a few examples. b) what prompted such diverse decisions, if such chips indeed exist.

    I did read somewhere that some ARM chips have fast IO vs. regular IO but I am not entirely sure how that works.

  • It may be that no manufacturer has designed PIC-style GPIO, since that you require that they must modify the actual ARM core and insert the GPIO logic inside the core - similar to extra processor registers - instead of as external memory-mapped logic.

    Remember that the ARM core is designed to load from memory and store to memory, but perform operations on registers. If the GPIO is memory-mapped, then the ARM core is designed to read into a register, perform an operation and store back. With such a core, the fastest pin manipulations you can get is when a write operation can be done with just a memory write, without first having a memory read and a register operation. Really fast read/modify/write with such a core would indirectly require that you took one or more of the processor registers and mapped it to 32 or more GPIO pins, in which case any load into the register would represent a write to GPIO pins.

    As soon as the GPIO is outside the processor core, you further get the problem that a given process suitable for a 100MHz core is not fast enough to also manage 100MHz to external memory-mapped IO. And if you shrink the core and use a process that is fast enough for 100MHz GPIO then it would be better to instead use the advantages of such a design process and let the core run at 500MHz.

    The NXP LPC23xx is a variant with fast GPIO and normal GPIO. Fast GPIO just means that the GPIO is controlled from a high-speed local bus. But this is still outside the core - representing extra delays needed - and the instruction set of the ARM is still designed for load/store operation, where changes are done to registers and not directly to memory locations. The write-only changes you get from the set and clear registers can be pipelined and processed at full speed, even when there are several cycles of delay between core and the GPIO-controlling hardware.

    The important thing here is that the ARM chips are designed to run with quite high clock frequencies and designing it like the PIC would either hamper the allowed speed of the core, or break the existing separation between the core and the external logic that is separating one manufacturers offerings from other manufacturers offerings.

    If the GPIO was part of the core - how would then a manufactorer be able to buy a license for the core and then release 80-pin, 100-pin, 144-pin, ... variants of the chip without having to modify that core? Or should ARM sell a core supporting 400 port pins, and then leave it to the manufacturers to decide if the now much larger and energy-consuming chip should have all pads bonded or not?

  • the more I read about it, the more I am confused as to why the ARM chips don't use PIC-styled GPIO operations (aka setting bits directly).

    here is a summary of the arguments / explanations I have heard so far:

    1) it is not possible to do that because of ARM's business model of selling cores. makes sense, but how did they manage to do that with Cortex which is an ARM core and allows bit setting directly?

    2) it is not possible to do that because the architecture (the peripherals, including the GPIO?, is hang off the bus). Well, PIC has the exact same architecture - it's GPIO is off the bus. why is that PIC can do it but ARM cannot?

    3) it is possible but not preferable to do that: due to latency issues. I buy that. But if how the peripherals are handled is done by the vendors, why is that all of them came to the same decision?

    did I miss any arguments?

    "If the GPIO was part of the core - how would then a manufactorer be able to buy a license for the core and then release 80-pin, 100-pin, 144-pin, ... variants of the chip without having to modify that core? "

    I am not sure how the ARM IP is structured but I suppose that it is possible that the IP is structured around bits or ports so a manufacturer can pay on a per bit or port basis and they can add, or subtract, GPIO pins or ports as they so desire.

    whether it is actually done in reality is another story, but the point is that it is doable to include gpio in the core without compromising pin count / gpio capabilities for chip vendors.

  • btw, has anyone actually programmed cortex chips and how is the port handling different from other arm chips?

    just curious.

  • Yes.

    "how is the port handling different from other arm chips?"

    Not being familiar with other "ARM Chips" (sic), I wouldn't know!

  • Lots of people have programmed different variants of Cortex chips. They are also ARM chips, even if you may have only a variant of the Thumb instruction set.

    Because ARM sells cores, different ARM chips can have different ways to control the GPIO. If you still thing all ARM chips are identical, then you haven't read this thread, and you have not spent time looking through the datasheets for a couple of different chips.

    A number of ARM chips have registers where you can directly do writes to pins. Some ARM chips only allows t16-bit writes. Some supports 8-bit, 16-bit or 32-bit writes. The ARM core doesn't have bit-manipulating instructions, so unless a specific manufacturer has spent one byte for each bit, you can't update a single bit in a port without either:
    - use a chip that have a mask register to write-protect some bits.
    - do a read/modify/write cycle, and let the processor stall for whatever number of cycles it takes to fetch the read data.

    If you look at the NXP LPC23xx chips, the GPIO can be controlled by:
    IOSET (FIOSET)
    IOCLR (FIOCLR)
    IOPIN (FIOPIN)

    To make sure that you will not need to load the current pin state into a register before changing and writing back, you can use FIOMASK (only available with fast GPIO access) to control which of the FIOPIN bits that should be write-protected.

    "1) it is not possible to do that because of ARM's business model of selling cores. makes sense, but how did they manage to do that with Cortex which is an ARM core and allows bit setting directly?"
    Incorrect. There is no problem at all memory-mapping the GPIO latch registers. But it would be a licensing issue and potentially a skill issue if you can get the latch registers integrated into the core in a way that you will not stall the core.

    "2) it is not possible to do that because the architecture (the peripherals, including the GPIO?, is hang off the bus). Well, PIC has the exact same architecture - it's GPIO is off the bus. why is that PIC can do it but ARM cannot?"
    Having the GPIO on a bus just affects the speed. Inside a microcontroller, there are a large number of buses. Items sitting on the buses inside the core can run faster than items sittin on secondary buses. Note what I did write about external PCI or ISA boards on a fast or a slow bus. The PCI bus (especially if run at 133MHz with 64-bit width) may be quite fast, but way slower than the memory bus to the PC memory. And that bus is way slower than the interface (bus) to the secondary cache. And that interface (bus) is way slower than the interface (bus) to the primary cache. And that interface (bus) is way slower than the interface (bus) to the registers.

    Adding new peripherials to the expansion interfaces supplied by ARM means that you can debug and simulate the peripherials without worrying about the core. And Adding the peripherials will not affect timing or logic of the core. And if you do modify the core, then you need to be able to simulate the full core too.

    "3) it is possible but not preferable to do that: due to latency issues. I buy that. But if how the peripherals are handled is done by the vendors, why is that all of them came to the same decision?"
    As already mentioned several times: The different vendors have all had a chance to select their own ways to implement each and every peripherial. That includes GPIO, UART, DMA, PWM, ... If you do look, you will notice that they really are different. I don't think the STR71x chips has any set and clear registers. But the set and clear registers are a very, very good feature since they allow you to set or clear a pin without consuming time to get the state of the other pins on the port.

    "did I miss any arguments?"
    You definitely missed the argument that no two ARM chips are equal. ARM is not a company selling a large number of processors designed to be similar to each other. It is a company selling cores. ST must decide if they want their ARM releases to be similar, making it easy or hard for a user to migrate between the chips. NXP must similarly decide if their different ARM families should have any simmilarities with each other, or with any other vendors chips.

    In the end, the word ARM or Cortex will just give you a hint what compiler to use. When you select a processor, don't select to use a PIC or a PPC or an ARM. When doing the comparison, you must select a specific ARM chip. If your selection process is just ARM or not ARM, then your selection process has failed, since you should not just consider "ARM with >= 128kB flash and >= 16kB RAM". You should consider exactly what you intend to use it for, and find a cheap ARM chip that fulfill all your requirements - which may include the requirement that it is pin-compatible or code-compatible with another chip. When I say code-compatible, I don't mean able to run ARM or Thumb instructions, but having compatible peripherials too.

  • Just a footnote. The PIC has the BCF and BSF instructions, allowing single-bit clear/set. Without bitwise instructions, the best you can do is to perform 8-bit, 16-bit or 32-bit writes, in which case you either need to mask away the bits you don't want to affect, or do a load/modify/store, or create a peripherial where each bit can be written to using individual memory addresses.

    A processor vendor are not - by license - allowed to modify the instruction set, so when implementing the GPIO logic, they must base that logic on the capabilities of the instruction set of the core.

  • "Because ARM sells cores, different ARM chips can have different ways to control the GPIO."

    I thought one of the unanswered questions from the very beginning of this thread is while there are many possible different ways to control gpio, none of the many vendors decided to implement it the PIC way.

    "If you still thing all ARM chips are identical, then you haven't read this thread, and you have not spent time looking through the datasheets for a couple of different chips."

    if you still think that others think all ARM chips are identical, then you haven't read this thread. We passed that point before this thread got started. let's move on.

    "Incorrect."

    what is incorrect?

    you guys write a lot. I just don't know if your writing addresses the questions asked. But I do appreciate your time / efforts and I am learning from this conversation, bit by bit.

  • "Just a footnote. The PIC has the BCF and BSF instructions, allowing single-bit clear/set. Without bitwise instructions, the best you can do is to perform 8-bit, 16-bit or 32-bit writes, in which case you either need to mask away the bits you don't want to affect, or do a load/modify/store, or create a peripherial where each bit can be written to using individual memory addresses."

    do BFI/BFC count?

  • "do BFI/BFC count?"

    Keil documentation: "Bit Field Clear and Bit Field Insert. Clear adjacent bits in a register, or Insert adjacent bits from one register into another."

    Note that they target a register, not a memory address. So to set a bit in a memory-mapped address, you must:
    - load the memory address (GPIO latch register)
    - use your BFI/BFC instruction.
    - store back to the memory address (GPIO latch register)

    This is totally different from having the ability to set or clear bits directly in memory, since the BFC and BFI instructions are affected by the load latency. Set and clear registers on the other hand are write-and-forget. If the store buffer has room for the store, the ARM will be able to directly process the next instruction without any stalls.

  • "Note that they target a register, not a memory address. "

    OK. how about BSF/BCF? here is what Microchip has to say about them:

    "BCF Bit Clear f
    Syntax: [ label ] BCF f,b
    ...
    Description: Bit 'b' in register 'f' is cleared."

    "BSF Bit Set f
    Syntax: [ label ] BSF f,b
    ...
    Description: Bit 'b' in register 'f' is set."

    does it look like BCF/BSF also work on registers?

    wouldn't that make them identical to the ARM instructions?

  • Earlier in this thread you were referring to Cortex-M3 bit-banding. Not being familiar with PIC, I assume this would be the closest mechanism (in ARM world) to what you are looking for.

    However, bit-banding is not quite the right thing if you have to change several bits simultaneously. And by that I mean exactly at the same time. Don't know how PIC addresses that.

    To implement your example on a Cortex-M3 controller, you'd have to determine the bit address of a port in some data output register (you'll find examples all over the place). By defining a variable at that address, you can easily implement your sclk thing.

    infocenter.arm.com/.../Behcjiic.html

    Best regards
    Marcus
    http://www.doulos.com/arm/

  • But f in this case represents a register similar to the SFR in the 8051, i.e. it is a special region of memory.

    For a PIC16, f is a value between 0 and 127, specifying a memory address within this special SFR memory region. Some of these bytes will represent the status register (carry or zero bit) and some of these bytes will represent GPIO pins.

    The ARM has real hard registers. The registers in the ARM does not have a memory address, so a memory pointer can not access the ARM registers. And instructions working on registers can only modify the existing registers, not bytes or words in memory.

    In the end - if you want a processor that can declare bit-sized variables, you may consider a PIC or 8051 processor. The ARM core is not designed for bit variables. It has no bit-addressable memory, and no instructions to read or write individual bits in any such memory. Working with bytes or larger, the ARM requires either the hardware or the software to perform and/or/xor/not to modify individual bits in a memory cell - and since it separates registers from memory, the GPIO control will have to be memory-mapped.

    It would be possible to create an ARM core that either drops some of the registers, to use the name of these registers to control I/O. Or create an ARM core that keeps all registers, but defines that BFI/BFC are exception instructions that will only be able to access a subset of the registers, but instead also access GPIO. But ARM hasn't seen a reason to, since the customers has not shown any interest. And the customers can not modify an ARM core, since they will just get a hard macro cell to connect to their own logic.

    In the end, you will have to either select another processor, or live with the design choices that ARM has made for the processor core. The ARM is not a PIC and it is not a 8051. But for most users, this doesn't matter. The important thing isn't what instruction sequences you need to access a port pin. The important thing is how fast you can toggle them, and what cost it will take to run the chip at the required clock frequency and to have the required amount of flash.

    In the end, there is very few situations where the ARM can't match a 8051 in capability, cost or speed. The biggest reason for a PIC is probably if you need very, very few pins or need one of the NanoWatt series chips.

  • Ashely;
    It still appears that you are more intent on defending the PIC design than understanding the ARM when no one has challanged the PIC design. The statement is just the ARM concept is different.
    Instead of attempting to redesign the ARM core, why don't you review a few of the examples in the Keil toolset.
    What part of setting/clearing a bit troubles you?

    The GPIO register addresses are defined in the furnished header files. The Mask and Direction registers are normally set one time in a GPIO init module.

    Then:
    #define sensor_pwr_on 0x00001000
    #define sensor_pwr_off 0x00001000
    #define set_two_bit_on 0x00001001

    IOSET1 = sensor_pwr_on; //Zero bits are ignored
    IOCLR1 = sensor_pwr_off;

    IOSET1 = set_two_bits_on;

    In the MCB23xx Blinky example they use a macro definition then write:

    LED_E(0) // LED OFF
    LED_E(1) // LED ON

    So there are many different ways to get symbolic addressing of single bits.

    Bradford

  • Marcus, thank you so much.

    so GPIO A in LM3S628, per the datasheet, is at 0x4000.4000 - 0x4000.4FFF (24 bits for an 8-bit port? for compatibility reasons?). so its 0th pin / bit (0x4000.4000) should be a word at 0x4200.0000+0x4000 << 7 + 0x00<<2?

    if I want to set the 0th pin to 1, do I just set that word to anything other than 0?

    yeah, this is hugely helpful. I hope the mapping is consistent at least within the Cortex-M3 family?

    thanks a lot.