Pin Toggle Frequency Contest against C. Please Help! :)
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Re: Pin Toggle Frequency Contest against C. Please Help! :)
@Damien I recently started drafting a contribution to the docs on the subject of MicroPython speed optimisation, including the use of Viper. Should I hold fire on this for now if Viper semantics are still fluid?
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.
Re: Pin Toggle Frequency Contest against C. Please Help! :)
Docs sound great! Especial needed for viper and "how to do things fast". Feel free to document viper, but just start with the basics of using the decorator and specifying types to args. Enough to bit bang on IO.
Re: Pin Toggle Frequency Contest against C. Please Help! :)
Docs concerning viper code would be great, even if rudimentary. Thanks!
Apropos: If nobody precedes (Roberthh?) or strangles me I'd push the latest viper code to the german forum tomorrow, just for the snake of informativity and transparency. Maybe we can eventually lure that 21MHz guy from ambush
Apropos: If nobody precedes (Roberthh?) or strangles me I'd push the latest viper code to the german forum tomorrow, just for the snake of informativity and transparency. Maybe we can eventually lure that 21MHz guy from ambush
Re: Pin Toggle Frequency Contest against C. Please Help! :)
I had a closer look at this. Brief results are:
- - The 21MHz toggle frequency is feasible (given C-code) but only if code is executed from flash.
- 84MHz toggling is also possible (with loop unroll) when executing from flash, 42Mhz executing from RAM.
- Having the cbxx opcodes in @micropython.asm_thumb would be a good thing for us bit-bangers.
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Re: Pin Toggle Frequency Contest against C. Please Help! :)
You've got to be pushing assembler to its limits to need them as far as I can see. It only takes one instruction to set the condition codes, when you can use a conditional branch or an it/ite. As always there's a tradeoff between adding opcodes and keeping it 'micro'.chuckbook wrote:...Having the cbxx opcodes in @micropython.asm_thumb would be a good thing for us bit-bangers.
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.
Re: Pin Toggle Frequency Contest against C. Please Help! :)
@chuckbook
Thanks alot for investigating (and for joining the game and sorry for potential intrusiveness)!
Thanks alot for investigating (and for joining the game and sorry for potential intrusiveness)!
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Re: Pin Toggle Frequency Contest against C. Please Help! :)
Coming rather late to this party I find that this won't work here. I suspect the issue is with the ptr16 declaration as I've used this successfully where the argument is a buffer - here it is an address. Using today's firmware I'm seeing:Damien wrote:......Code: Select all
@micropython.viper def togglePerformance3b(): count = 0 stop = int(pyb.millis()) + 1000 millis = pyb.millis odr = ptr16(stm.GPIOA + stm.GPIO_ODR) while int(millis()) < stop: odr[0] ^= 1 << 13 # PA13 = LED_RED count += 1 print('Counted: {:10,} (viper2)'.format(count))
Code: Select all
/mnt/qnap2/data/Projects/MicroPython> repl
Entering REPL. Use Control-X to exit.
>
MicroPython v1.6-19-g8140772 on 2016-02-08; PYBv1.0 with STM32F405RG
Type "help()" for more information.
>>>
>>>
paste mode; Ctrl-C to cancel, Ctrl-D to finish
=== @micropython.viper
=== def togglePerformance3b():
=== count = 0
=== stop = int(pyb.millis()) + 1000
=== millis = pyb.millis
=== odr = ptr16(stm.GPIOA + stm.GPIO_ODR)
=== while int(millis()) < stop:
=== odr[0] ^= 1 << 13 # PA13 = LED_RED
=== count += 1
=== print('Counted: {:10,} (viper2)'.format(count))
>>> togglePerformance3b()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object with buffer protocol required
>>>
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.
Re: Pin Toggle Frequency Contest against C. Please Help! :)
I have a piece of code that works, submitted to the other forum under a different nickname.
With 100 Mio. cycles, the result is:
Viper: 18,618,506 toggles/s, 9.31 MHz, 18 Clock Cycles/iter
ASM: 27,929,060 toggles/s, 14 MHz, 12 Clock Cycles/iter
Since USB and SYSTICK are still enabled, the numbers are about 0.25% too low. At the moment I am chewing a little bit on the impression, that the ASM version could be 2 clocks faster.
Code: Select all
import pyb, stm
@micropython.viper
def toggleViper(cnt: int):
bsrr = ptr16(stm.GPIOA + stm.GPIO_BSRRL)
while cnt:
bsrr[0] = 1
bsrr[1] = 1
cnt -= 1
@micropython.asm_thumb
def toggleASM(r0): # r0 has loop count
movwt(r1, stm.GPIOA) # Use A0
movw(r2, 1) # r2 has mask for setting A0
# loop
label(loopstart)
strh(r2, [r1, stm.GPIO_BSRRL]) # output high
strh(r2, [r1, stm.GPIO_BSRRH]) # output low
sub(r0, 1) # r0 -= 1
bpl(loopstart)
# endloop
def main(no = 1000000):
x1_pin = pyb.Pin('X1', pyb.Pin.OUT_PP)
start = pyb.millis()
toggleASM(no)
timeA = pyb.elapsed_millis(start)
start = pyb.millis()
toggleViper(no)
timeV = pyb.elapsed_millis(start)
count = round((no * 1000) / timeV) # 2 toggles per iteration
print('Viper: {:,} toggles/s, {:6.3} MHz, {} Clock Cycles/iter'.format(count * 2, count/1e6, round(pyb.freq()[0]/count)))
count = round((no * 1000) / timeA) # 2 toggles per iteration
print('ASM: {:,} toggles/s, {:6.3} MHz, {} Clock Cycles/iter'.format(count * 2, count/1e6, round(pyb.freq()[0]/count)))
Viper: 18,618,506 toggles/s, 9.31 MHz, 18 Clock Cycles/iter
ASM: 27,929,060 toggles/s, 14 MHz, 12 Clock Cycles/iter
Since USB and SYSTICK are still enabled, the numbers are about 0.25% too low. At the moment I am chewing a little bit on the impression, that the ASM version could be 2 clocks faster.
Re: Pin Toggle Frequency Contest against C. Please Help! :)
@pythoncoder the API changed recently. Try this:
@Roberthh don't waste your time, searching for lost cycles. On F405 there exists a memory bottleneck when executing from SRAM (which is the case for MPY). That's where the cycles get lost.
Code: Select all
odr = ptr16(bytearray_at(GPIOA + GPIO_ODR,0x100))
Re: Pin Toggle Frequency Contest against C. Please Help! :)
@chuckbook: Thanks. That's what I understood from your previous post about the strh instructions. What I was wondering about is, that he unconditional branch takes 2 cycles, opposed to the conditional which seems to take 4 cycles. That looks like accessing the flags adds another timing penatly. It does not worry me at all, it's just for interest in stuff that most likely never will be important.