Skip to main content
mwalt.3
Associate III
June 26, 2025
Solved

WeAct BluePill + : SPI1 does not work (works with older generic BluePills !)

  • June 26, 2025
  • 9 replies
  • 856 views

Hi all 

I made a little program under arduino IDE (but I write directly into the registers), in order to test the command of WS2812b chips via the SPI1 MOSI pin : It worked perfectly with older BluPill boards I have got.

Tried the same thing with BluePill + from WeAct  official store , it does not work. Even the SPI1->CR1 register is not set properly : it must be 0b1100111 , but it is actually 0b100011 : which is wrong , the Master Mode and SPI enable bits can not be set ...

Any idea , please ? thanks !

/* spi_dma_ws.h */

#define ws_chips 8 // number of RGB chips

void spi_dma_transmit();

extern SPI_HandleTypeDef hspi1;
extern uint16_t adc_pa5;

// some colours
const uint8_t ws_black[3] = { 0, 0, 0 };
const uint8_t ws_green[3] = { 25, 0, 0 };
uint8_t ws_green_adc[3] = { 0, 0, 0 };
const uint8_t ws_red[3] = { 0, 25, 0 };
const uint8_t ws_blue[3] = { 0, 0, 25 };
const uint8_t ws_white[3] = { 25, 25, 25 };
const uint8_t ws_purple[3] = { 0, 25, 25 };
const uint8_t ws_yell[3] = { 25, 25, 0 };
const uint8_t ws_turc[3] = { 25, 0, 25 };


uint8_t ws3[ws_chips][3]; // has the 3 colours of each RGB chip
uint8_t ws33[ws_chips * 3 * 3]; // has the 3 SPI bytes for each the 3 colours of each RGB chip
// example with some colours
void ws_3() {
 for (int c = 0; c < 3; c++) {
 ws3[0][c] = ws_green_adc[c];
 ws3[1][c] = ws_red[c];
 ws3[2][c] = ws_blue[c];
 ws3[3][c] = ws_white[c];
 ws3[4][c] = ws_black[c];
 ws3[5][c] = ws_yell[c];
 ws3[6][c] = ws_turc[c];
 ws3[7][c] = ws_purple[c];
 }
}


// 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
// |‾|_._|‾|_._|‾|_._|‾|_._|‾|_._|‾|_._|‾|_._|‾|_._ // 146 73 36
// 128 64 32 16 8 4 2 1
// |‾.‾|_|‾.‾|_|‾.‾|_|‾.‾|_|‾.‾|_|‾.‾|_|‾.‾|_|‾.‾|_ // 219 109 182
void ws_33() {
 uint8_t p = 0, w;
 ws_3();
 ws_green_adc[0] = adc_pa5 / 4;
 for (int ws = 0; ws < sizeof(ws3) / 3; ws++) {
 for (int c = 0; c < 3; c++) {
 w = ws3[ws][c];
 ws33[p] = 0b10010010;
 if (w & 128) ws33[p] += 0b01000000;
 if (w & 64) ws33[p] += 0b00001000;
 if (w & 32) ws33[p] += 1;
 p++;
 ws33[p] = 0b01001001;
 if (w & 16) ws33[p] += 0b00100000;
 if (w & 8) ws33[p] += 0b00000100;
 p++;
 ws33[p] = 0b00100100;
 if (w & 4) ws33[p] += 0b10000000;
 if (w & 2) ws33[p] += 0b00010000;
 if (w & 1) ws33[p] += 0b00000010;
 p++;
 }
 }
}


void send_ws() {
 ws_33();
 spi_dma_transmit();
}


void spi_dma_init() {
 // Enable Port A clock // Enable SPI Clock
 RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_SPI1EN;
 // Mode: Output, Speed: 10MHz // Alternate function push-pull
 GPIOA->CRL &= ~(GPIO_CRL_CNF7 | GPIO_CRL_MODE7); // MOSI = PA7
 GPIOA->CRL |= (GPIO_CRL_CNF7_1 | GPIO_CRL_MODE7_0); // 10.01

 // SPI Mode: Master
 SPI1->CR1 |= SPI_CR1_MSTR;
 // 100: BaudRate = fPCLK/32 // + CPOL + CPHA
 SPI1->CR1 |= SPI_CR1_BR_2 | SPI_CR1_CPOL | SPI_CR1_CPHA;
 // Set TXDMA bit in CR2 → enable DMA transmit
 SPI1->CR2 |= SPI_CR2_TXDMAEN;
 // SPI Enable
 SPI1->CR1 |= SPI_CR1_SPE;

 // DMA Configuration // Enable DMA Clock
 RCC->AHBENR |= RCC_AHBENR_DMA1EN;
 // Priority Level = 0b10 → High
 DMA1_Channel3->CCR |= DMA_CCR_PL_1;
 // Memory Increment mode + Direction Read from Memory
 DMA1_Channel3->CCR |= DMA_CCR_MINC | DMA_CCR_DIR; // no need for interrupt
 // Set Memory Address → Peripheral Address
 DMA1_Channel3->CMAR = (uint32_t)ws33;
 DMA1_Channel3->CPAR = (uint32_t)&SPI1->DR;
}

void spi_dma_transmit() {
 // stop DMA to refill CNDTR
 DMA1_Channel3->CCR &= ~DMA_CCR_EN;
 DMA1_Channel3->CNDTR = sizeof(ws33);
 // launch DMA
 DMA1_Channel3->CCR |= DMA_CCR_EN;
 ///Serial.print(sizeof(ws33));
}
/* spi_dma_ws.ino */

#include "spi_dma_ws.h"

uint16_t adc_pa5;

void setup() {
	Serial.begin(115200);
	spi_dma_init();
	pinMode(PB2, OUTPUT);
	delay(2000);
}

void loop() {
	delay(444);
	send_ws();
	adc_pa5 = analogRead(PA_5);

	Serial.print("GPIOA->CRL "); /// debug
	Serial.println(GPIOA->CRL, BIN);
	Serial.print("SPI1->CR1 ");
	Serial.println(SPI1->CR1, BIN);
	Serial.print("SPI1->CR2 ");
	Serial.println(SPI1->CR2, BIN);
	HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_2); // BluePill+ LED
}

 

Best answer by mwalt.3

suite :
(finally I had the same problem with my older bluepills)

I did some tests , and realized that at the start , the thing works fine , the config of SP1->CR1 is ok , and the pin outputs the right signals , but after having put the bluepill on my PCB , or after having touched some pin of the naked bluepill with a finger , things were going wrong : SPI1->CR1 takes the wrong value , and only a reset can make it ok again ; what a mess !

I then realized that the problem occurs when I touch a given pin , which is PB4 aka SPI1 NSS : on my PCB , this pin is reused as an ADC input , and LOW level because of a shunt resistor to the GND. My thought was then that the problem is because this pin is tied to LOW , so I tried to configure it as OUTPUT HIGH ... and the problem disappeared.!

I had then to find another way , because I don't want to change my PCBs : I  put the pin as analog input , and tried to set the SSOE bit , and prayed : gotcha !

the line #87 of my code is :
SPI1->CR2 |= SPI_CR2_TXDMAEN ;
it must be :
SPI1->CR2 |= SPI_CR2_TXDMAEN | SPI_CR2_SSOE ;

If I get an official STM32F103 board , I will investigate and let you know

Bit 2 SSOE: SS output enable
0: SS output is disabled in master mode and the cell can work in multimaster configuration
1: SS output is enabled in master mode and when the cell is enabled. The cell cannot work
in a multimaster environment.

9 replies

Andrew Neil
Super User
June 26, 2025

A Blue Pill will (almost?) certainly have a fake STM32.

Different batches may well have different fakes.

 

Have you tested on a genuine ST board; eg, a Nucleo?

 

PS:

You could try this to identify what's actually on your boards:

https://mecrisp-stellaris-folkdoc.sourceforge.io/bluepill-diagnostics-v1.6.html#diags-1-6

 

But, seriously, save yourself all the grief - get a genuine STM32.

A Nucleo even comes complete with a genuine ST-Link.

 

PPS:

Some examples of fake/clone STM32s here: https://www.richis-lab.de/STM32.htm

These two, specifically, are from Blue Pills:

https://www.richis-lab.de/STM32_01.htm

https://www.richis-lab.de/STM32_04.htm

 

More clones: https://mecrisp-stellaris-folkdoc.sourceforge.io/clones-stm32-mcus.html#index-0

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
mwalt.3
mwalt.3Author
Associate III
June 26, 2025

Thanks Andrew

I wasn't able to make the diagnostic to work , the chip didn't appear as an working USB device

But after having made a full chip erase with CubeProgrammer , the SPI begun to work , ie. correct register value , and correct signal on the pin !

Nevertheless , I am still facing somme "funny" behaviour : after some unplugging or plugging things , the chip lasts teh SPI config ... and recovers it after a manual reset

So I am not sure all this is the chip's fault , I have look at and to test more things , hope I will understand what is the problem

Andrew Neil
Super User
June 26, 2025

@mwalt.3 wrote:

hope I will understand what is the problem


The basic problem is that you have an unknown chip, so there's no telling how it's supposed to work - or even if it works at all!

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
Associate II
June 26, 2025

Bluepill boards are probably near to 100% faked meanwhile.

You should have more luck with black pill (STM32F401CCU6 or STM32F411CEU6). These seem to be useable up to now (and have a bit more memory and power).

 

But as mentioned a Nucleo board offers a built in ST-Link and works 100% as expected.

mwalt.3
mwalt.3Author
Associate III
June 26, 2025

WeAct is known as a trusted maker I don't know what happens , I will tell them

Black pill does not have PB11 nor USART3 , and unfortunately , I need this features for most of my projects

Andrew Neil
Super User
June 26, 2025

@mwalt.3 wrote:

Black pill does not have PB11 nor USART3


Both STM32F401CCU6 and STM32F411CEU6 have 3 UARTs, with a number of choices for which pins they use

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
mwalt.3
mwalt.3Author
Associate III
June 26, 2025

yes , but on the blackpill board , PB11 , which has some alternate functions , is replaced by PB2 , which has nothing.

This is te raison why I have to stay by F103 instead of F4 , or even H503

Associate II
June 26, 2025

If you want to find out what you have got:

https://community.st.com/t5/stm32-mcus-products/how-to-spot-fake-stm32-mcu/td-p/147180

 

(I never tried it, but stored the the link when I got a misbehaving blue pill some time ago)

mwalt.3
mwalt.3Author
Associate III
June 26, 2025

Hi , AP_IDR register is unknown at STM32duinio , nor in the RM , nor by CubeProgrammer : how can read it ?

mwalt.3
mwalt.3AuthorBest answer
Associate III
June 27, 2025

suite :
(finally I had the same problem with my older bluepills)

I did some tests , and realized that at the start , the thing works fine , the config of SP1->CR1 is ok , and the pin outputs the right signals , but after having put the bluepill on my PCB , or after having touched some pin of the naked bluepill with a finger , things were going wrong : SPI1->CR1 takes the wrong value , and only a reset can make it ok again ; what a mess !

I then realized that the problem occurs when I touch a given pin , which is PB4 aka SPI1 NSS : on my PCB , this pin is reused as an ADC input , and LOW level because of a shunt resistor to the GND. My thought was then that the problem is because this pin is tied to LOW , so I tried to configure it as OUTPUT HIGH ... and the problem disappeared.!

I had then to find another way , because I don't want to change my PCBs : I  put the pin as analog input , and tried to set the SSOE bit , and prayed : gotcha !

the line #87 of my code is :
SPI1->CR2 |= SPI_CR2_TXDMAEN ;
it must be :
SPI1->CR2 |= SPI_CR2_TXDMAEN | SPI_CR2_SSOE ;

If I get an official STM32F103 board , I will investigate and let you know

Bit 2 SSOE: SS output enable
0: SS output is disabled in master mode and the cell can work in multimaster configuration
1: SS output is enabled in master mode and when the cell is enabled. The cell cannot work
in a multimaster environment.

Visitor II
June 27, 2025

Finally!!!!!

mwalt.3
mwalt.3Author
Associate III
July 3, 2025

yes , I also had problems to make timer3 to work , but it was more related to stm32duino : it worked when I wrote directly into the registers

Andrew Neil
Super User
July 7, 2025
A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.