cancel
Showing results for 
Search instead for 
Did you mean: 

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

mwalt.3
Associate III

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
}

 

7 REPLIES 7
Andrew Neil
Super User

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
Associate III

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


@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.
mfgkw
Associate III

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
Associate III

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

mfgkw
Associate III

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 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.