Consistently fast blink neopixel (already using the no delay method)

I have the classic problem of wanting to do 2 things at once on an arduino (in my case a wemos d1 mini).

I want to read some data. If the data is above a certain threshold I want to fast blink a neopixel.

I am basically using the BlinkWithoutDelay example to do two things at once.

Code for polling data:

I set previous to millis() instead of adding interval to it as the long call takes just over 100ms, adding the interval to previous means it could maybe come right round and poll straight away again and I can’t poll for than once every 100ms for this data.

a_interval is 150 (tried up to 333)

if (current_time - previous_a_time >= a_interval)
{
    a = long_call_for_data();
    previous_a_time = millis();

    if (a.status != SUCCESS)
    {
        print_error();
    }
}

Code for blinking neopixel:

flash_interval is 75
flash is a bool just to turn the pixel on and off

if (current_time - previous_pixel_time >= flash_interval)
{
    if (flash)
    {
        pixel.setPixelColor(0, red);
    }
    else
    {
        pixel.setPixelColor(0, pixel_off);
    }

    pixel.show();

    flash = !flash;
    previous_pixel_time = millis();
    // Have also tried previous_pixel_time += flash_interval;
}

The main loop just sets the current_time and then calls the 2 functions for the 2 code blocks above.

So my problem is that the pixel doesn’t blink consistently. Because the poll for data blocks for just over 100ms. I have written a sketch that just fast blinks the pixel and thats fine and consistent.

Is there anything I can do? I guess threads would be handy if I had multiple cores lol

Or will I have to control the pixel from another microcontroller and somehow tell the second controller when to blink? (easier said than done as I’m already using SoftwareSerial for a HC-05 for the long call, and I only have wemos chips and they don’t seem to be able to be a slave for I2C transfer :frowning: )

Just found out that an ESP32 has 2 cores, maybe I could send the blinking to the second core of one of those?

ESP32 comes in different flavours, some are single core. Not sure if it is possible to utilize both cores in code, one core may be reserved to wireless communication and other background stuff.

EDIT: Or maybe you can - if you have two cores.

Danois90:
ESP32 comes in different flavours, some are single core. Not sure if it is possible to utilize both cores in code, one core may be reserved to wireless communication and other background stuff.

EDIT: Or maybe you can - if you have two cores.

Yea have been looking up ESP32's, the 2 cores on that could work!

Strangely I already have 2 in the post coming tomorrow lol I wanted a board that had integrated bluetooth so I don't have to use the awkward to setup HC-05 for this.

I hope mine has 2 cores now, do you know how I would know?

EDIT: I bought these: https://www.ebay.co.uk/itm/5pcs-ESP-WROOM-32-ESP32-ESP32S-2-4GHz-WiFi-Bluetooth-Development-Board-Arduino/153872419764?ssPageName=STRK%3AMEBIDX%3AIT&var=453917865849&_trksid=p2057872.m2749.l2649

According to your wiki link the ESP-WROOM-32 has the ESP31B chip and has 2 cores and is also discountinued as it was a BETA board, that could be fun lol

Without the 2 cores there is also more than 1 approach to this but it depends a little on what is inlong_call_for_data(); Since the blinking really doesn't take a lot of time, you could either poll for the elapsed time within that function, or if interrupts are 'on' within that function (for most the time) you could use a timer to blink the led. Also you should consider switching to a method which is not 'bit-banged' for driving the led, since like this you may have unstable wifi connection as it is now.

Deva_Rishi:
Without the 2 cores there is also more than 1 approach to this but it depends a little on what is inlong_call_for_data(); Since the blinking really doesn't take a lot of time, you could either poll for the elapsed time within that function, or if interrupts are 'on' within that function (for most the time) you could use a timer to blink the led. Also you should consider switching to a method which is not 'bit-banged' for driving the led, since like this you may have unstable wifi connection as it is now.

That call is a library call that uses serial over bluetooth to query data and then return it. It blocks and waits and returns.

Excuse my ignorance but what do you mean bit-banged? Not currently using wifi but am I likely to have unstable wifi as the loop is consistently spinning? Most posts on here say you should use this method over delay?

EDIT:
Do you mean to use timer interrupts for the pixel? and maybe the data call too? Just googled and saw some information on them. Didn't know that was a thing, haven't had to use these before. Will do some more research on them!

Do you mean to use timer interrupts for the pixel?

yes have a look at Timerone.h which is user friendly enough (though i am not sure if it compatible with your board.

That call is a library call that uses serial over bluetooth to query data and then return it. It blocks and waits and returns.

That doesn't meant that it can not be altered to suit your needs. A library is a bit of code that can be used as a part of a bigger 'whole' but in the end it is code that gets compiled just like the rest of it. You can find the .h & .cpp files, open them in notepad++ or another editor of your choice, and create you own custom function if you want.
(best practice is to create a copy of it and edit that if that is what you want to do)

what do you mean bit-banged?

The data stream that is send to the ledstrip has a particular format and due to the speed and the timing sensitivity on the receiving end the bits are usually send by toggling the pin HIGH & LOW manually within the show() function during which interrupts are turned 'off' to assure that the timing doesn't go off. Creating a signal in this way is called a 'bit-banged' signal. Since WiFi connections rely on interrupts being turned 'on' (ideally all the time) and because ESP's are pretty powerful, there are other methods available in some addressable LED libraries, Like DMA mode & UART mode which do not require the the interrupts to be turned 'off' and therefore provide a more stable WiFi-connection. All in all if you have only a few LED's and your interrupts are only turned off momentarily, and you program has plenty of time with them turned on, you probably won't notice much, though you may all of a sudden lose WiFi for no apparent reason. How this all fits in with the 2nd core i don't know.

Deva_Rishi:
yes have a look at Timerone.h which is user friendly enough (though i am not sure if it compatible with your board.

Will have a look.

Deva_Rishi:
That doesn't meant that it can not be altered to suit your needs. A library is a bit of code that can be used as a part of a bigger 'whole' but in the end it is code that gets compiled just like the rest of it. You can find the .h & .cpp files, open them in notepad++ or another editor of your choice, and create you own custom function if you want.
(best practice is to create a copy of it and edit that if that is what you want to do)

True, was hoping there was an obvious solution that I didn't know before doing that.

Deva_Rishi:
The data stream that is send to the ledstrip has a particular format and due to the speed and the timing sensitivity on the receiving end the bits are usually send by toggling the pin HIGH & LOW manually within the show() function during which interrupts are turned 'off' to assure that the timing doesn't go off. Creating a signal in this way is called a 'bit-banged' signal. Since WiFi connections rely on interrupts being turned 'on' (ideally all the time) and because ESP's are pretty powerful, there are other methods available in some addressable LED libraries, Like DMA mode & UART mode which do not require the the interrupts to be turned 'off' and therefore provide a more stable WiFi-connection. All in all if you have only a few LED's and your interrupts are only turned off momentarily, and you program has plenty of time with them turned on, you probably won't notice much, though you may all of a sudden lose WiFi for no apparent reason. How this all fits in with the 2nd core i don't know.

Fantastic explanation thanks for taking the time to explain. I didn't know about interrupts before this post (Quite new to the hardware/electronics) side of things. I didn't realise that showing a neopixel doesn't allow these interrupts. This could cause me problems with the SoftwareSerial part getting the data from a HC-05. I think it uses interrupts? Will look into the other libraries.

This could cause me problems with the SoftwareSerial part getting the data from a HC-05. I think it uses interrupts?

For sure it does !! Even hwSerial uses interrupts but only once per byte received, swSerial does for every bit received and also turns them off during transmission. Makuna/NeoPixelBus as a DMA mode as a default for ESP, but the output pin can not be changed (and is the same as the UART-rx pin, which is a bit unfortunate if you might consider using hwSerial for the HC-05

Deva_Rishi:
For sure it does !! Even hwSerial uses interrupts but only once per byte received, swSerial does for every bit received and also turns them off during transmission. Makuna/NeoPixelBus as a DMA mode as a default for ESP, but the output pin can not be changed (and is the same as the UART-rx pin, which is a bit unfortunate if you might consider using hwSerial for the HC-05

Hardware serial means connecting to the actual RX/TX pins (that are also connected to the USB) instead of 2 other GPIO pins and using software serial?

I'm also trying to find out how this works on the ESP32, if I do built in bluetooth and bluetooth serial on core 0 and neopixel stuff on core 1 this might be ok? Or maybe the interrupts don't care what core I'm on. Still looking into this.

Hardware serial means connecting to the actual RX/TX pins (that are also connected to the USB) instead of 2 other GPIO pins and using software serial?

an ESp32 has 3 UART ports, so really there should be no need to use swSerial (i actually wonder why it would exist on that board) and any pin can be mapped for use as it says here

I'm also trying to find out how this works on the ESP32, if I do built in bluetooth and bluetooth serial on core 0 and neopixel stuff on core 1 this might be ok? Or maybe the interrupts don't care what core I'm on. Still looking into this.

Look here It is easy reading, and myself i have plenty of things to look into but i'd say it can all be done. All in all i'd switch to the Neopixelbus 's DMA mode, and use hwSerial for all. like that it probably doesn't matter to much which core does what.

Deva_Rishi:
an ESp32 has 3 UART ports, so really there should be no need to use swSerial (i actually wonder why it would exist on that board) and any pin can be mapped for use as it says hereLook here It is easy reading, and myself i have plenty of things to look into but i'd say it can all be done. All in all i'd switch to the Neopixelbus 's DMA mode, and use hwSerial for all. like that it probably doesn't matter to much which core does what.

Thanks again.
I was using SoftwareSerial as I am using/originally used a wemos d1 mini which has one UART port and it shared with the usb and I also wanted the serial monitor.

My ESP32's are in the post and were meant to be delivered today but weren't as covid is holding it up I guess. Can't wait to give the ESP32 a go, seems much better for what I want!