# How to get data sent to a LED strip each 400 ns?

I want to send data to a LED strip. This has to be done roughly every 400 (or 800 ns), depending on the data (a 0 or 1 to be sent).

unsigned long  counter  = 0;


I did a test with my STM32F103C8T6 with this code in the loop:

while (1)
{
GPIOC->BSRR = GPIO_PIN_13; // Set GPIO
counter++;
}


I ran in debug mode, to be able to check the counter value. After roughly 10 seconds, I suspended the program and checked the value for counter. It had value 27822623. This means that each counter takes about 10 / 27822623 = 3.5942E-07 seconds / counter increment, which is 359 ns/counter increment.

However, all I do here is setting the GPIO pin which is one offset pointer, an assignment and an increment. And this takes the 'gigantic' long time of 359 ns. In my real application I need to go to the next byte, check if it is a 0 or 1, depending on that to send the above command to set, or a reset command of the pin (which takes an additional bit shift). How can I perform this within (or actually appr. around 400 ns?)

The STM32 is set to 72 MHz (maximum speed). I haven't any additional interrupt running.

How can I send data at 400 ns manually?

(I tried SPI: not reliable enough, sometimes clock pulses are skipped and resulting data). Interrupts via a timer will be even taking more time since it contains interrupt flow (via HAL).

Update

New application to test better:

unsigned long  counter  = 0;


In main:

while (1)
{
GPIOC->BSRR = GPIO_PIN_13; // SET
counter++;

if (counter == 10000000)
{
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_14);
counter = 0;
}
}


Update Below the disassembled code (more than I thought):

152                 GPIOC->BSRR = GPIO_PIN_13; // SET
0800122e:   mov.w   r2, #8192       ; 0x2000
08001232:   ldr     r3, [pc, #36]   ; (0x8001258 <main+64>)
08001234:   str     r2, [r3, #16]
158               counter++;
08001236:   ldr     r2, [pc, #36]   ; (0x800125c <main+68>)
08001238:   ldr     r3, [r2, #0]
0800123c:   str     r3, [r2, #0]
159               if (counter == 10000000)
0800123e:   ldr     r2, [pc, #32]   ; (0x8001260 <main+72>)
08001240:   cmp     r3, r2
08001242:   bne.n   0x800122e <main+22>
161                   HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_14);
08001244:   mov.w   r1, #16384      ; 0x4000
08001248:   ldr     r0, [pc, #12]   ; (0x8001258 <main+64>)
0800124a:   bl      0x80004e0 <HAL_GPIO_TogglePin>
162                   counter = 0;
0800124e:   movs    r2, #0
08001250:   ldr     r3, [pc, #8]    ; (0x800125c <main+68>)
08001252:   str     r2, [r3, #0]
08001254:   b.n     0x800122e <main+22>
08001256:   nop

• 400ns is like 2.5MHz, so you should have like 30 instructions per this period. you have (at least) 1 cycle for GPIO, 1 for loop (if compiler use plain jump) and few instructions for incrementing the counter (depends, if it is read/write from memory or resides in register, also depends on it size). What type is your counter? Is it possible, that it is just 16 bit wide, so you had it overflown many times in those 10 seconds? – gilhad Apr 14 '18 at 23:01
• @gilhad the counter is an unsigned long (since it needs to count high not to overthrown. I'm sure it doesn't overthrown. I changed the program a bit so it every 10,000,000 it flips another GPIO and I now have 438 ns/counter (including some overhead for the toggle of the extra pin). See update in my question. I wonder how they do this on an Arduino which only has 16 MHz and also should be capable of sending pulses at 2.5 MHz speed. – Michel Keijzers Apr 14 '18 at 23:04
• Don't use the wrong tool for the job. Do you need to use this MCU? Do you have to do anything else during this operation? How often do you need to transmit and how many bits at a time? – pipe Apr 14 '18 at 23:12
You might do crazily efficient stuff by not doing a manual comparison with your 0 or 1 byte, but by using conditional moves that depend on that value; that way, the fetching the value and setting the right register to the right value operations could be pipelined. If you haven't, first try different compiler flags (-O2 might be a good start) to make sure your compiler doesn't do that for you.