Page 3 of 5

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Posted: Wed Feb 03, 2016 4:00 pm
by mad474
Am I understanding this correctly? The 21MHz toggle assertion isn't confirmed yet? Dave, have you got the setup to check that C-Program? Sorry, but I haven't.

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Posted: Wed Feb 03, 2016 4:07 pm
by dhylands
So far, I haven't been able to confirm it. gcc doesn't seem to produce code which would go that fast (I even tried -O3). However, that's not to say that one of the other compilers can't do it (gcc isn't known for producing the tightest code - especially on ARM). From what I've heard, IAR does a better job, but I don't have anything other than gcc installed.

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Posted: Wed Feb 03, 2016 4:16 pm
by mad474
Thanks Dave! That guy claims

Code: Select all

Auf dem STM32F407VG Discovery Board ausgeführt, bei 168MHz Taktfrequenz, 
mit GCC und -Os kompiliert.
Mit dem Debugger "result" ausgelesen: 21000001
which is self explaining. If nobody stops me here I'm going to ask for (accountable) confirmation over there.

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Posted: Wed Feb 03, 2016 5:08 pm
by dhylands
I think it's plausible. Getting the .elf file would allow disassembly.

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Posted: Wed Feb 03, 2016 9:00 pm
by Roberthh
Hello Folks, since this is all very interesting, I did a test. I took the function togglePerformance3D and hooked up an oscilloscope to red LED: It shows a period of 298 ns and a frequency of 3,356 MHz. The output of the script is:.

Counted: 6,700,168 (viper4) (time=597ms)

where the time and the 2 million cycle count match the 3.3 MHz measurement. Pyboard runs at it's default settings, pyb.freq() shows 168 MHz.
It#s a Pyboard V1.0.
For the first Assembler version I get a period time of 166 ns or 6 MHz.
The second Assembler version did not change the level at the LED, so I could not take a sample.
The factor of 2 should result from the way of counting. In each period the LED is toggled twice (On and Off).

Update: I've just seen why the second assembler version did not toggle the led. In the seccond instructon to switch the output, the offset should be 2. For timing purposes, this is irrelevant, but on a scope there is no change.

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Posted: Wed Feb 03, 2016 9:20 pm
by mad474
Yay! Thanks Roberthh! Was too shy to ask for a scope validation. All I can say is that I get about the same output running togglePerformance3d(). But my mechanical stopwatch isn't really useful for this sort of time measurement :D

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Posted: Wed Feb 03, 2016 9:52 pm
by chuckbook
@dhylands, just out of curiosity. Did you try the asm test on a STM32F7xx board? I got 72MHz on PA13 at 216 MHz core freq.
Can you confirm that? Thanks!

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Posted: Thu Feb 04, 2016 7:26 am
by Roberthh
With a slightly changed loopPerformance3d() the results are a little bit better, using Port A0. I get

Counted: 3,565,062 (viper4) (time=561ms)

which would be 7.130.124 toggles. For comparison, I made a single endless loop toggling X1 (Port A0). The loop period is 82 ns or 12 MHz, the shortest time between slopes is 23 ns. In May last year, as part of the trial that brought me to PyBoard, I made the same tests with varios board, just to see how fast & short pulses can be generated. The endless loop test on a Teensy3.1 resulted in 53 ns period time. The code looked like C, but the Macros in the Teensy package generate direct port instructions out of that. I had to add a "DSB" instruction between the two port commands to allow the I/O bus to settle. Maybe that instruction could be added to Micropython assembly. I saw that dhylands added an instruction between the two port commands, maybe for that purpose.

Code: Select all

@micropython.viper
def togglePerformance3d():
    x1_pin = pyb.Pin('X1', pyb.Pin.OUT_PP)
    bsrrl = ptr16(stm.GPIOA + stm.GPIO_BSRRL)
    bsrrh = ptr16(stm.GPIOA + stm.GPIO_BSRRH)
    start = pyb.millis()
    for _ in range(2000000):
        bsrrl[0] = 1
        bsrrh[0] = 1
    time = pyb.elapsed_millis(start)
    count = round(2e9 / time) # 2 toggles per iteration
    print('Counted: {:10,} (viper4) (time={}ms)'.format(count, time))

@micropython.viper
def loopPerformance():
    x1_pin = pyb.Pin('X1', pyb.Pin.OUT_PP)
    bsrrl = ptr16(stm.GPIOA + stm.GPIO_BSRRL)
    bsrrh = ptr16(stm.GPIOA + stm.GPIO_BSRRH)
    while True:
        bsrrl[0] = 1
        bsrrh[0] = 1
I use A0, so I can simply use 1 instead of 1 << 13. The bsrrl[0] = 1 causes the rising slope, so I have to check the definitions of the constants, or the data sheet. Maybe the output is inverted. For the moment, this is not important. The interrupts are still enabled, which add a little bit of jitter, but allows to stop the code with Ctrl-C.
Update: I just looked into the CPU manuals (last resort). Since the processor uses a little endian format the definitions of BSSRL and BSSRH have to be swapped. The lower address sets the bit.
Update 2: The loop above written in assembly give a period of 59 ns or 16.9 MHz, and a high pulse of 23 ns. The slope time are below 2 ns. So no idea where the 84 MHz claim of the data sheet comes from. Here's the endless loop code. X1 was set to output. No bus barrier instruction required.

Code: Select all

@micropython.asm_thumb
def loop():    # r0 has address of run_buf
    movwt(r1, stm.GPIOA)    # Use A0
    add(r1, stm.GPIO_BSRRL)
    movw(r2, 1)       # r2 has mask for setting A0

# loop
    label(loop)
    strb(r2, [r1, 0])  # output high
    strb(r2, [r1, 2])  # output low
    b(loop)
# endloop

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Posted: Thu Feb 04, 2016 11:37 am
by Damien
I use A0, so I can simply use 1 instead of 1 << 13
The "1 << 13" should be optimised by the compiler to a single constant (although loading 0x1000 into a register might take more instructions than simply loading 0x1).

Maybe the IO can go faster if the peripheral bus frequency is increased (if it's not already at its maximum)?

@Roberthh, regarding your question about viper docs: there are none at the moment, and this forum topic is probably one of the better places to start learning! You can look at the tests in tests/micropython/viper* to see some of the features that viper has.

I have intentionally not provided docs for viper mode because it's still work-in-progress and hence may change semantics. I don't want people to rely on it just yet. But it's really important to test viper and get ideas for making it better, so that's why I'm taking an interest in this discussion.

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Posted: Thu Feb 04, 2016 12:26 pm
by Roberthh
Thanks. I'm very exited about this discussion, because it gives very helpful information for two applications of PyBoard, where I thought it would be too slow. But the viper mode and direct addressing of peripheral registers is just the right combination of speed and code readability.