Using STM32F103C8T6 PWM pin to drive ws2812b Neopixel Ring in arduino IDE
-
- Posts: 10
- Joined: Wed Jun 10, 2020 4:10 pm
Using STM32F103C8T6 PWM pin to drive ws2812b Neopixel Ring in arduino IDE
So, I've been trying to use pwm pin of STM32F103C8T6 board (bluepill) to drive WS2812b RGB ring, but i'm not such a pro to achive that. Firstly I tried to use this: https://github.com/adafruit/Adafruit_NeoPixel library, but it seems to work only on arduino board. Then I tried this: https://github.com/rogerclarkmelbourne/ ... 2_Libmaple , but it uses SPI1 port, which i'm using to drive NRF24L01 module, and i think that it's impossible to drive them both like I2C bus devices. I though about using second SPI line which STM32F103C8T6 provides, like in this post: https://github.com/rogerclarkmelbourne/ ... 2/pull/536 , but again this doesn't seem to be possible to change default SPI1 line in https://github.com/rogerclarkmelbourne/ ... 2_Libmaple library. I also tried to set PWM line to 800kHz like :
HardwareTimer timer(1);
void setup() {
pinMode(PA10, PWM);
timer.setPrescaleFactor(1);
timer.setOverflow(90);
}
void loop() {
pwmWrite(PA10, 90);
}, which also didn't work.
So what would be really helpful is: help me to drive it somehow with PWM signal, use second SPI line to drive WS2812b Neopixels, use one SPI line to drive NRF24L01 and WS2812b Neopixels. I hope for your help
HardwareTimer timer(1);
void setup() {
pinMode(PA10, PWM);
timer.setPrescaleFactor(1);
timer.setOverflow(90);
}
void loop() {
pwmWrite(PA10, 90);
}, which also didn't work.
So what would be really helpful is: help me to drive it somehow with PWM signal, use second SPI line to drive WS2812b Neopixels, use one SPI line to drive NRF24L01 and WS2812b Neopixels. I hope for your help
Re: Using STM32F103C8T6 PWM pin to drive ws2812b Neopixel Ring in arduino IDE
Hi @Jakub_Szubzda
First, avoid to create 4 times the same topic!
About the Adafruit_Neopixel it works with the STM32 core. I don't know for LibMaple core.
First, avoid to create 4 times the same topic!
About the Adafruit_Neopixel it works with the STM32 core. I don't know for LibMaple core.
-
- Posts: 10
- Joined: Wed Jun 10, 2020 4:10 pm
Re: Using STM32F103C8T6 PWM pin to drive ws2812b Neopixel Ring in arduino IDE
Thank you for your answer!
-
- Posts: 502
- Joined: Fri Dec 27, 2019 4:53 pm
- Location: Munich, Germany
- Contact:
Re: Using STM32F103C8T6 PWM pin to drive ws2812b Neopixel Ring in arduino IDE
SPI2 supports only 18MHz, while SPI1 supports 36MHz.
You can use SPI2 instead of SPI1 if you use
before the calls of NRF and WS library functions.
Example:
The correct handling of timers requires this sequence:
You can use SPI2 instead of SPI1 if you use
Code: Select all
SPI.setModule(x);
Example:
Code: Select all
SPI.setModule(1);
// call here functions related to NRF module using SPI1
...
SPI.setModule(2);
// call here functions related to WS using SPI2
Code: Select all
timer.pause(); // stop the timer - this allows to set timer parameters
pinMode(PA10, PWM);
timer.set...
...
timer.resume(); // this will start the timer
-
- Posts: 10
- Joined: Wed Jun 10, 2020 4:10 pm
Re: Using STM32F103C8T6 PWM pin to drive ws2812b Neopixel Ring in arduino IDE
I tried this, but all it does is lights leds full white and nothing more, some suggestions?stevestrong wrote: ↑Thu Jun 11, 2020 9:40 am SPI.setModule(1);
// call here functions related to NRF module using SPI1
...
SPI.setModule(2);
// call here functions related to WS using SPI2
Here is code i use:
Code: Select all
#include <WS2812B.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#define NUM_LEDS 16
RF24 radio(PB0, PA4);
const uint64_t address = 0xF0F0F0F0E1LL;
/*
* Note. Library uses SPI1
* Connect the WS2812B data input to MOSI on your board.
*
*/
WS2812B strip = WS2812B(NUM_LEDS);
// Note. Gamma is not really supported in the library, its only included as some functions used in this example require Gamma
uint8_t LEDGamma[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
void setup()
{
/*Serial.begin(115200);
SPI.setModule(1);
radio.begin(); //Starting the Wireless communication
radio.openWritingPipe(address); //Setting the address where we will send the data
radio.setPALevel(RF24_PA_MIN); //You can set it as minimum or maximum depending on the distance between the transmitter and receiver.
radio.stopListening(); //This sets the module as transmitter
Serial.println("Successfully opened");
Serial.println("Set as transmitter");*/
SPI.setModule(2);
strip.begin();// Sets up the SPI
strip.show();// Clears the strip, as by default the strip data is set to all LED's off.
strip.setBrightness(35);
}
void loop()
{
/*const char text[] = "Your Radio is working";
radio.write(&text, sizeof(text)); //Sending the message to receiver
Serial.println("Sent");*/
pulseWhite(10);
}
void pulseWhite(uint8_t wait) {
for(int j = 0; j < 256 ; j++){
for(uint16_t i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color(LEDGamma[j],LEDGamma[j],LEDGamma[j] ) );
}
delay(wait);
strip.show();
}
for(int j = 255; j >= 0 ; j--){
for(uint16_t i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color(LEDGamma[j],LEDGamma[j],LEDGamma[j] ) );
}
delay(wait);
strip.show();
}
}
Re: Using STM32F103C8T6 PWM pin to drive ws2812b Neopixel Ring in arduino IDE
So, you are still using Roger's core and WS2812B library?
I lifted up your code and tried it - I commented out the nRF24L01 and RF24 because I don't have those.
When I run it, I have no LED string connected, but I can see output on SPI2 - PB15. However, the timing is not as expected. It is in the 1/3 2/3 ratio as expected, but the "0" pulse is just under 900ns and the "1`" pulse just under 1800ns. An 800kHz LED might interpret both of those as "1" so might explain why you get all white.
I ripped out the " SPI.setModule(2) " and now there is output on SPI1 - PA7, but the timing is different: "0" pulse around the expected 440ns, and the "1" pulse double that. I suspect the WS2812B library is maybe setting the "baud rate" divider in the wrong SPI when you try to use SPI2. Maybe that would be easy to fix, I did not try to find it.
Otherwise, I did not see that you had some reason to not try the ST core and the Adafruit library for the LEDs?
I lifted up your code and tried it - I commented out the nRF24L01 and RF24 because I don't have those.
When I run it, I have no LED string connected, but I can see output on SPI2 - PB15. However, the timing is not as expected. It is in the 1/3 2/3 ratio as expected, but the "0" pulse is just under 900ns and the "1`" pulse just under 1800ns. An 800kHz LED might interpret both of those as "1" so might explain why you get all white.
I ripped out the " SPI.setModule(2) " and now there is output on SPI1 - PA7, but the timing is different: "0" pulse around the expected 440ns, and the "1" pulse double that. I suspect the WS2812B library is maybe setting the "baud rate" divider in the wrong SPI when you try to use SPI2. Maybe that would be easy to fix, I did not try to find it.
Otherwise, I did not see that you had some reason to not try the ST core and the Adafruit library for the LEDs?
-
- Posts: 10
- Joined: Wed Jun 10, 2020 4:10 pm
Re: Using STM32F103C8T6 PWM pin to drive ws2812b Neopixel Ring in arduino IDE
Yes i'm using Roger's library, because when i try to use adafruit neopixels library it just doesn't work.
It makes sense, and i think that this part of WS2812B library sets some kind of dividerozcar wrote: ↑Sat Jun 13, 2020 7:17 am When I run it, I have no LED string connected, but I can see output on SPI2 - PB15. However, the timing is not as expected. It is in the 1/3 2/3 ratio as expected, but the "0" pulse is just under 900ns and the "1`" pulse just under 1800ns. An 800kHz LED might interpret both of those as "1" so might explain why you get all white.
// Set the SPI clock divisor to as close to 400ns as we can;
// the WS2812 spec allows for +/- 150ns
#if F_CPU == 72000000L
#define WS2812B_SPI_DIVISOR SPI_CLOCK_DIV32 // 444ns
#elif F_CPU == 64000000L
#define WS2812B_SPI_DIVISOR SPI_CLOCK_DIV32 // 500ns
#elif F_CPU == 48000000L
#define WS2812B_SPI_DIVISOR SPI_CLOCK_DIV16 // 333ns
#elif F_CPU == 40000000L
#define WS2812B_SPI_DIVISOR SPI_CLOCK_DIV16 // 400ns
#elif F_CPU == 36000000L
#define WS2812B_SPI_DIVISOR SPI_CLOCK_DIV16 // 444ns
#elif F_CPU == 24000000L
#define WS2812B_SPI_DIVISOR SPI_CLOCK_DIV8 // 333ns
#elif F_CPU == 16000000L
#define WS2812B_SPI_DIVISOR SPI_CLOCK_DIV8 // 500ns
#elif F_CPU == 8000000L
#define WS2812B_SPI_DIVISOR SPI_CLOCK_DIV4 // 500ns
#else
#error No clock divisor available for this F_CPU
#endif
but i don't know how to modify it, and in what "if", to achive around 400ns, so maby you have some advice how to do that?
Re: Using STM32F103C8T6 PWM pin to drive ws2812b Neopixel Ring in arduino IDE
I found I was using the WS2812B library included with the core, instead of WS2812B_STM32_Libmaple-master, and it turns out they are not the same (your guess is better than mine why). The version in the core does not have those #defines depending F_CPU , it just assumes F_CPU is 72MHz, but since my F_CPU is 72MHz, that make no difference, so I still get the same, SPI1 works, but with SPI2 the pulses are twice the length that they should be.
So, looking at it, I think the problem is not that it is setting the rate in the wrong SPI (my wild guess yesterday), but just setting the wrong rate. That means if you could swap your usage of the two SPIs, it would probably be OK.
Otherwise, assuming your F_CPU is 72Mhz, another circumvention is to change the #define to:
That should make it work on SPI2 (but will cause trouble for WS2812B on SPI1, but OK for you).
I believe the problem arises because SPI1 is on APB2, which is running at same frequency as F_CPU, while SPI2 is on APB1, running at F_CPU/2. But I'm no expert on how the core hangs together, so I'll leave it to somebody else to figure the best way to properly fix this.
What problem did you have with the ST core and the Adafruit library? fpiSTM said it works, but I have not tried it.
So, looking at it, I think the problem is not that it is setting the rate in the wrong SPI (my wild guess yesterday), but just setting the wrong rate. That means if you could swap your usage of the two SPIs, it would probably be OK.
Otherwise, assuming your F_CPU is 72Mhz, another circumvention is to change the #define to:
Code: Select all
#if F_CPU == 72000000L
#define WS2812B_SPI_DIVISOR SPI_CLOCK_DIV16 // 444ns
...
I believe the problem arises because SPI1 is on APB2, which is running at same frequency as F_CPU, while SPI2 is on APB1, running at F_CPU/2. But I'm no expert on how the core hangs together, so I'll leave it to somebody else to figure the best way to properly fix this.
What problem did you have with the ST core and the Adafruit library? fpiSTM said it works, but I have not tried it.
-
- Posts: 502
- Joined: Fri Dec 27, 2019 4:53 pm
- Location: Munich, Germany
- Contact:
Re: Using STM32F103C8T6 PWM pin to drive ws2812b Neopixel Ring in arduino IDE
As I mentioned above, on SP2 you can only get max 18MHz, that is why the pulses are twice as long.
-
- Posts: 10
- Joined: Wed Jun 10, 2020 4:10 pm
Re: Using STM32F103C8T6 PWM pin to drive ws2812b Neopixel Ring in arduino IDE
I don't really know what's wrong with it, but no matter what i try to do it just doesn seem to light leds.
Can you propose some solution?stevestrong wrote: ↑Mon Jun 15, 2020 6:53 am As I mentioned above, on SP2 you can only get max 18MHz, that is why the pulses are twice as long.