Electronics > Microcontrollers

possible to synch digital out puts so they turn on or off at the same time?

<< < (9/10) > >>

Nominal Animal:

--- Quote from: SiliconWizard on October 10, 2023, 01:31:42 am ---As a peripheral for a soft core, I've written a pretty useful kind of GPIO register (IMO) which allows to modify given bits of a GPIO port to an arbitrary value (0 or 1) according to a mask (for which a given bit = 1 means: modify the corresponding GPIO, = 0 means: don't modify it), so the register is split into a mask part and a value part (rather than the set and clear parts of the BSRR registers). Very handy to modify just a set of GPIOs within a port in a single cycle.

--- End quote ---
Yes, but it does limit the number of pins to half the register width.

In any case, these are excellent examples of the techniques one can use to minimize the timing differences when changing parallel bus states, depending on the exact MCU capabilities, without using external circuitry like latches.

If OP and others are wondering about how much time they can spend in changing the parallel bus pin states (i.e., how long can one spend to change the state of all the pins in a parallel bus), for typical parallel buses with a separate 50% duty cycle clock or read/write strobe signal, the answer is "almost half a bus clock cycle".  The "almost" is because the triggering edge is not instantaneous (it is a slope, and thus takes a measurable time to transition), and there is a bit of latency between writing to the port data registers and the pins changing state, and these too need to happen well within the half clock cycle of the parallel bus.

Typically, that means that even if the parallel bus pins are spread into two or three GPIO banks, but you can use a shared DMA trigger (with 50% duty cycle, so you can use the opposite edge of that compared to what the other end uses), the bus will work just fine.  For some buses, even an interrupt handler might be fast enough, if it keeps the data for the next transfer prepared beforehand.

Often, the "hard" part is generating the exact desired number of clock cycles or read/write strobes especially at higher frequencies.  My trick there is to use SPI SCK (clock) if the number of transfers is a multiple of SPI transfer size (often programmable), or SPI MOSI/DO with 8-bit transfers and double (0b01010101), quadruple (0b00110011), or octuple (0b00001111) clock frequency, allowing one to specify the pulse count as a multiple of 4, 2, and 1, respectively.  This often takes two or more external pins (one for the SCK or MOSI/DO, plus the DMA trigger pin) wired together, though.
Many MCUs allow a DMA to use the same source and target addresses but a variable count, so using (part of) one SPI and one DMA channel, one can often generate the desired clock, especially since on Cortex-M's the SPI cores can often go to pretty high frequencies (dozens of MHz).

On some MCUs, you can even use the SPI in slave mode, dividing the incoming clock by 2/4/8 (and even different dividers if the SPI subsystem supports transfer sizes other than 8 bits); if the SPI data register defaults to all zeros or all ones in the absence of (DMA) writes, you can still control the pulse count (to a multiple of 4, 2, or 1, respectively).

Siwastaja:

--- Quote from: Nominal Animal on October 10, 2023, 06:14:01 am ---Yes, but it does limit the number of pins to half the register width.

--- End quote ---

Yeah. Since address space (on 32-bit MCUs) and simple logic gates are cheap, I would like to see more different options to access the same peripherals, e.g. 32-bit wide registers which can set/reset 16 bits at once in any combination (BSRR or SiliconWizard's mask/value, basically the same thing expressed differently), or write 32 pin values at once, or set 32 pin values, or reset 32 pin values.

Interestingly, while STM32 offers combined/atomic set-reset for 16 bits, nRF52 offers atomic set OR reset for 32 bits, but you can't do combined set-reset. Seeing both options at once would be great so one could choose based on application requirements. Full free-routable IO matrix, as in nRF52, is highly helpful as you can arrange the pins you need to switch simultaneously into the same IO register, without causing a PCB routing nightmare or painting yourself into corner with other peripherals sharing the same pins.

SiliconWizard:

--- Quote from: Nominal Animal on October 10, 2023, 06:14:01 am ---
--- Quote from: SiliconWizard on October 10, 2023, 01:31:42 am ---As a peripheral for a soft core, I've written a pretty useful kind of GPIO register (IMO) which allows to modify given bits of a GPIO port to an arbitrary value (0 or 1) according to a mask (for which a given bit = 1 means: modify the corresponding GPIO, = 0 means: don't modify it), so the register is split into a mask part and a value part (rather than the set and clear parts of the BSRR registers). Very handy to modify just a set of GPIOs within a port in a single cycle.

--- End quote ---
Yes, but it does limit the number of pins to half the register width.

--- End quote ---

Of course, no free lunch here. But it can prove much better than having to use set/reset registers when dealing with arbitrary values that can't be statically defined (so that a static approach such as set/reset will require extra cycles to define at run-time which should be used for which bits.)

ST's BSRR registers are also half-half, but other implementations use separate SET and CLEAR registers. Of course which approach is more efficient depends on your use case exactly.

The usual implementation approach when using these single registers is to restrict GPIO "ports" to half the native register size (so 16 GPIOs per port for a 32-bit CPU), which is what ST does.
An alternative (which is what I did for flexibility) is to implement N-bit ports (N = native width) that can be read/written in a single cycle entirely (like the ODR registers), and the value/mask registers can only act on half of the port, with the half being configurable in another register. In practice, that gives a ton of flexibility.

newbrain:

--- Quote from: Nominal Animal on October 09, 2023, 11:17:53 pm ---one can do
    GPIOx_BSRR = bus_lookup[new_bits & BUS_MASK] | (bus_lookup[(~new_bits) & BUS_MASK] << 16);
to set and clear the bits corresponding to the new bus state

--- End quote ---
A nice thing with STM32 BSRR is that setting bits takes priority on resetting them, so one can have slightly more efficient code with:
    GPIOx_BSRR = bus_lookup[new_bits & BUS_MASK] | (bus_lookup[BUS_MASK] << 16);
The bits set in the higher word of BSRR will have no effect if the corresponding bit is set in the lower word.

Siwastaja:
But quite frankly, the most usual case why you have to do non-atomic modification in two or more steps is not because you are switching too many (say 17) pins at a time, but because you are switching maybe three or four pins which stupidly happen to reside in different ports. Having a full routing matrix on other peripherals, so that you can get all those UARTs and SPIs etc. out of the way instead of having them in fixed positions (or two-three choices only), pretty much solves this issue, and is hugely helpful in many other ways, too. This has proved an excellent feature in nRF52 and it can't be that expensive to implement. Peripherals with special analog requirements would still need fixed mappings, of course.

Navigation

[0] Message Index

[#] Next page

[*] Previous page

There was an error while thanking
Thanking...
Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod