Page 1 of 1

Problems with WS2812 on our F0 varient. (clock issue)

Posted: Mon Sep 02, 2024 1:22 pm
by Mangy_Dog
Im having a real PITA problem with one of our projects.
We have a string of ws2812's in our project and I just cant get them to display anything correctly. (they just go white)
I've pretty much found why, but No idea how to fix it.

Basically the datarate is only going out at 250khz. Way too slow for the leds to react properly to.
This should be 800khz.

For testing I have used Adafuits neopixel library both as its default, but also with setting the tick delay values to:

Code: Select all

    
    uint32_t top = (60);       // 1.25µs
    uint32_t t0 = top - (20); // 0.4µs
    uint32_t t1 = top - (40); // 0.8µs
    
This based is based on an expected cpu frequency of the 48mhz that the stm32f030rct6 should be running at.
But its just not getting above 250khz...

I'm assuming now I've got something wrong with the clock settings or part of the setup of this variant putting in bad clocks somewhere...

The MCU works and I2C works so it cant all be wrong. But something is running this data very slow for some reason.

My current generated clock settings are...

Code: Select all

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Configure LSE Drive Capability
  */
  HAL_PWR_EnableBkUpAccess();
  __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_HIGH);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI14|RCC_OSCILLATORTYPE_HSE
                              |RCC_OSCILLATORTYPE_LSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  RCC_OscInitStruct.HSI14State = RCC_HSI14_ON;
  RCC_OscInitStruct.HSI14CalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6;
  RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_I2C1
                              |RCC_PERIPHCLK_RTC;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_SYSCLK;
  PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_SYSCLK;
  PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}
And I set
uint32_t SystemCoreClock = 48000000;
In the system_stm32f0xx.c file.

Am I missing anything else?

For a test I ran:

Code: Select all

  // Enable the GPIOC clock
  RCC->AHBENR |= RCC_AHBENR_GPIOCEN; // Enable clock for GPIOC

  // Configure PC4 as output
  GPIOC->MODER &= ~(GPIO_MODER_MODER4); // Clear the mode bits for PC4
  GPIOC->MODER |= GPIO_MODER_MODER4_0;  // Set PC4 to general-purpose output mode

  GPIOC->OTYPER &= ~GPIO_OTYPER_OT_4;   // Set PC4 to push-pull

  while (1) {
          GPIOC->ODR |= GPIO_ODR_4;   // Set PC4 high
          GPIOC->ODR &= ~GPIO_ODR_4;  // Set PC4 low
      }
To see how fast the pin would toggle... And it would only go 1.7mhz.
ChatGPT says the instruction count is 4 in the loop. So it should be 12mhz (ish)

What am I missing?

Re: Problems with WS2812 on our F0 varient. (clock issue)

Posted: Mon Sep 02, 2024 3:25 pm
by ag123
I've some ws2812 that I wanted to play with, but has been sitting on them and not started with them.

among the things ws2812
https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf

I think some are driven from 5v
it may take like a 74lvc1g17
https://www.ti.com/lit/ds/symlink/sn74lvc1g17.pdf

to bridge 3.3v to 5v signals

but I've also once read/stumbled into (i think) that some of the more recent ws2812 may work with 3v not sure about it though and about where is the reference.

the rest would be timing issues, I think if you want to drive it from a timer, it may take driving it from dma given the sub 1 us timing.
it may be feasible to 'bit bang' the timer by setting registers but I'm not too sure if the cpu may lag behind the timing requirements, e.g. to drive from interrupts.

I think Adafruit's Neopixel library's implementation
https://github.com/adafruit/Adafruit_NeoPixel
is driven using SPI, which makes it feasible to send those as a bit stream, possibly simplier and I'm not sure if dma is after all needed to reach those speeds. SPI may work without DMA if the processor etc is fast enough e.g. cache / run from msram etc.

Re: Problems with WS2812 on our F0 varient. (clock issue)

Posted: Mon Sep 02, 2024 4:08 pm
by Mangy_Dog
It looks like adafruits library uses system tick delays, but FastLED uses SPI. Going to move this to an SPI pin in a later revision.
the 3.3V signal "Should" work... By that I mean I think I read it needs to be above 0.7V to read as high...

But even if the logic level is an issue... It wouldnt account for the slow 250-260khz data rate. I think thats the real issue here.

I have confirmed with MCO that the sysclock is running at 48mhz at least.
Just not sure what else is going wrong.