2025-06-26 3:09 AM
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
}
Solved! Go to Solution.
2025-06-27 11:01 AM
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.
2025-06-27 1:07 PM
Finally!!!!!
2025-07-03 1:31 PM
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
2025-07-07 6:50 AM
STM32Duino issues should go here: https://www.stm32duino.com/
Or here: https://github.com/orgs/stm32duino/discussions