cancel
Showing results for 
Search instead for 
Did you mean: 

STM32103 bluepill bare-metal WS2812b neopixel driver no libraries

mytechnotalent
Associate II

I have spent a few weeks reviewing HAL related and LL related neopixel libs however I would love if there was someone who had a working version of literally just the ability to set up a neopixel on any port and simply light it or light a few neopixels in an array.

I have found several with HALs but it really does not give a good understanding of how this is done from scratch.

To be clear I am not looking for a HAL solution. I am looking for a bare-metal no library solution.

Thank you in advance.

15 REPLIES 15
gbm
Lead II

The first snippet was for SPI, the second is for timer PWM output - it's written in the text. Some convenient #defines from my own header files are used in the code to make it easier to read - they are quite easy to guess.

#define WSDMA	DMA1
#define WSDMACH	DMA1_Channel1
#define	DMA_IFCR_CGIF_WS	DMA_IFCR_CGIF1
#define WSTIM_CCR	TIM1->CCR1

DMA_IFCR_CGIF1 I assume this is SPI1?

TIM1->CCR1 I assume this is PWM?

#define WSDMA	DMA1
#define WSDMACH	DMA1_Channel1
#define	DMA_IFCR_CGIF_WS	DMA_IFCR_CGIF1
#define WSTIM_CCR	TIM1->CCR1

I assume DMA_Channel1 is SPI1? I do not see where you are selecting a specific SPI and PWM output.

It is not obvious what pin you are using as I know in the datasheet I have to see where SPI1 can be mapped to but I do not see it here.

Nevermind I got it to work. Just took some time. Thank you!

namero999
Associate

I know this is an old thread, but I'm struggling to get anything to work on a STM32G030J6M6, I want to drive a number of smd ws2812. Is there maybe any code you could share if you got it working? Or maybe could you share the many HAL examples that you mentioned?

 

Thanks!!

This is my code for G030 using UART with 7-bit frames, MSB first, used in my Christmas star.

 

int main(void)
{
	RCC->PLLCFGR = RCC_PLLCFGR_PLLMV(1) | RCC_PLLCFGR_PLLNV(9) | RCC_PLLCFGR_PLLRV(3)
	| RCC_PLLCFGR_PLLREN | RCC_PLLCFGR_PLLSRC_HSI;	// 
	RCC->CR |= RCC_CR_PLLON;	// turn PLL on
	while (!(RCC->CR & RCC_CR_PLLRDY));	// wait for PLL lock
	FLASH->ACR |= FLASH_ACR_PRFTEN | 1;	// enable prefetch, 1 wait state
	RCC->CFGR |= RCC_CFGR_SW_PLLRCLK;	// switch to PLL clock
	
	RCC->IOPENR |= RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN;
	RCC->AHBENR |= RCC_AHBENR_DMA1EN;
	RCC->APBENR2 = RCC_APBENR2_USART1EN;
	
	// the UART may also work with 8-bit frames, this requires shifting the data by one to the left (verified)
	WS_UART->BRR = (HCLK_FREQ + WSBAUD / 2) / WSBAUD;
	WS_UART->CR2 = USART_CR2_TXINV | USART_CR2_MSBFIRST | USART_CR2_DATAINV | USART_CR2_SWAP;
	WS_UART->CR3 = USART_CR3_DMAT;
	WS_UART->CR1 = USART_CR1_M1 | USART_CR1_TE | USART_CR1_UE;
	
	WS_DMACH->CPAR = (uint32_t)&WS_UART->TDR;
	
	GPIOB->MODER = BF2(7, GPIO_MODER_AF);	// USART1
	
	DMAMUX1_Channel0->CCR = DMAREQ_ID_USART1_TX;
	
	SysTick_Config(HCLK_FREQ / SYSTICK_FREQ);
	
	for (;;)
		__WFI();
}

struct rgb_ {
	uint8_t r, g, b;
};

struct rgb_ lc[NLEDS];
static uint8_t txbuf[NLEDS * 8];

void encode(uint8_t *encbuf, const struct rgb_ *img, uint16_t nleds)
{
	// MSB-first encoding table
	static const uint8_t uenc[] = {
		0000 | 022, 0001 | 022, 0010 | 022, 0011 | 022,
		0100 | 022, 0101 | 022, 0110 | 022, 0111 | 022
	};

	for (uint16_t i = 0; i < nleds; i++)
	{
		uint32_t v = img[i].r | img[i].g << 8 | img[i].b << 16;
		for (uint8_t b = 0; b < 8; b++)
		{
			*encbuf++ = uenc[v >> 21 & 7];
			v <<= 3;
		}
	}
}

void ws_start(void)
{
	encode(txbuf, lc, NLEDS);
	
	WS_DMACH->CCR = 0;
	WS_DMACH->CMAR = (uint32_t)txbuf;
	WS_DMACH->CNDTR = sizeof(txbuf);
	WS_DMACH->CCR = DMA_CCR_DIR_M2P | DMA_CCR_MINC | DMA_CCR_EN;
}