Turbo Blinky. - Page 1
Forum section: electronics / general

author: paulca
author_rank: Super Contributor
timestamp: October 19, 2022, 04:55:37 pm
content: STM32F030F4 48Mhz.HAL Toggle = 400kHzHAL Writepin*2 = 1MhzASM write *2 = 4.5MhzThere is far more in there. I'm still ADDing and SUBing my register offsets. I have enough registers to just store the absolute addresses and pro.... nevermind, hang on... 6MhzLook I was bored! I certainly beats writing blinky to check a new board is working.Code:turboBlink:push {r7, lr} // Save registers, we care why?// r0 = GPIO struct base address// r1 = GPIO pin numbermovsr3, BSRR_OS// offset in r3addsr3, r3, r0// add r0 *gpiobase to r3 offset, r3 now points to BSRRmovsr4, BRR_OS// offset in r4addsr4, r4, r0// add r0 *gpiobase to r4 offset, r4 now points to BRRreToggle:strr1, strr1, breToggle// bye bye cruel worldCode:turboBlink(LED_GPIO_Port, LED_Pin);//HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);//HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);//HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);Of course, I wonder if the hardware PWM can go higher than 6Mhz.

author: harerod
author_rank: Frequent Contributor
timestamp: October 19, 2022, 05:53:23 pm
content: In case you are still bored:Have you considered pumping GPIO BSRR values from a circular DMA buffer?A rather powerful feature of quickly writing up to 16bit in parallel to the outside world. Could be used for home-brew video signal generators, for example.

author: DavidAlfa
author_rank: Super Contributor
timestamp: October 19, 2022, 06:13:13 pm
content: Actually the compiler does pretty much the sameEdit: Basically avoid HAL for such simple stuff!Code:void toggle(GPIO_TypeDef *port, uint16_t pin) {while(1) {port->BSRR = pin;port->BSRR = pin<<16;}}8001a50:040blslsr3, r1, #168001a52:6101strr1, [r0, #16]8001a54:6103strr3, [r0, #16]8001a56:e7fcb.n8001a52 <toggle+0x2>Code:void main(){toggle(GPIOA, GPIO_PIN_1);}8001b06:2102movsr1, #28001b08:4801ldrr0, [pc, #4]; (8001b10 <main+0x18>)8001b0a:f7ff ffa1bl8001a50 <toggle>For sure, the DMA can make a true turbo blinky!

author: paulca
author_rank: Super Contributor
timestamp: October 19, 2022, 06:49:20 pm
content: LOL!Actually the STM and ESP WS2812 LED string drivers these days.... The WS2812 protocol is 24 bit PWM encoding (IIRC). They generate a bit stream which results in the same "high/low" duty cycles and flush it with DMA buffer at the right hz. and boom!

author: paulca
author_rank: Super Contributor
timestamp: October 19, 2022, 07:01:40 pm
content: In terms of learning ARM assembler, the F0 is a Cortex M0 with the minimal instruction set.The ASM I had for the F1 (M3) laughed and said, "Nope." None of the instructions were allowed, I believe because the M0 has less ability to shift long immediate values into registers (or part registers) and decode instructions accordingly. So the vast majority of immediates are impossible. It also seemed to complain about the possible values for relative offset addressing. Like ldr rx, [ ry, #offset ] is much more limited in what offset can be.Even consider something like:add r4, r0, #0x28Illegal instruction: Invalid immediate value. Basically there is no way to encode all of that into 32bits. (the solution to this, I found, was to mov the immediate into the register, then add r0 base address to it.)The amount of stuff both the arm* compilers and arm* asms are doing (with implicit immediate mov's) is remarkable.What am I on about?For example. The base GPIOA memory region begins (or this MCU) at 0x48000000In x86 you would just do:mov register, #0x48000000But that creates an instruction which is longer than 32bits, because it contains a 32bit operand. It is therefore illegal on a RISC fixed length instruction set.The bizarre thing the compiler does with this is...mov rx, #0x90lsls rx, #23Which loads hex 90 and shifts it left 23 bits.... which is in fact 0x4800000It's odd, but typically you want to avoid having to provide absolute addresses and most the ASM generated by the compiler seems to desparately trying to keep every and ALL addresses they can in registers and using small offsets from the stack register and things. Like the gcc generated functions take the data passed in the registers and moves them into some stack space, it then loads that stack offset into r7 and uses everything with offsets off r7.Such a pain the ass, but still fun!EDIT: When you look at how all the "port" registers are configured, regarding addresses. They all start on "simple" 1 or 2 significant bit addresses, then they have 1 or 2 significant bit offsets to the main arrays and so on. This, I imagine is to make it far easier and far faster to shift register those addresses into the 32bit registers as immedaites.

author: DavidAlfa
author_rank: Super Contributor
timestamp: October 19, 2022, 09:54:45 pm
content: Remember stm32 use only Thumb instructions, it's obvious that 16-bit instructions in a 32-bit system will have limitations.Compared against a 8-bit PIC with 14-bit instructions, they stored everything in a single instruction.32-bit architecture is interesting, but when instructions use 4 times more memory that's no longer so great !