# WS2812

## Defines
#define | WS2812_SUPPORTED 0
#define | WS2812_TIM_OUT_PORT GPIOB
#define | WS2812_TIM_OUT_PIN GPIO_Pin_6
#define | WS2812_TIM TIM4
#define | WS2812_TIM_CCR WS2812_TIM->CCR1
#define | WS2812_TIM_DMA_TRG TIM_DMA_CC1
#define | WS2812_TIM_REMAP_FUNC { GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_TIM4); }
#define | WS2812_TIM_CLK_FUNC { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); }
#define | WS2812_TIM_PERIOD ((MIOS32_SYS_CPU_FREQUENCY/2) / 800000)
#define | WS2812_TIM_CC_RESET 0
#define | WS2812_TIM_CC_IDLE WS2812_TIM_PERIOD
#define | WS2812_TIM_CC_LOW (u16)((WS2812_TIM_PERIOD - 1) * 0.28)
#define | WS2812_TIM_CC_HIGH (u16)((WS2812_TIM_PERIOD - 1) * 0.74)
#define | WS2812_DMA_PTR DMA1_Stream0
#define | WS2812_DMA_CHN DMA_Channel_2
#define | WS2812_BUFFER_SIZE ((WS2812_NUM_LEDS+2)*24)
## Functions
s32 | WS2812_Init (u32 mode)
s32 | WS2812_LED_SetRGB (u16 led, u8 colour, u8 value)
s32 | WS2812_LED_GetRGB (u16 led, u8 colour)
s32 | WS2812_LED_SetHSV (u16 led, float h, float s, float v)
s32 | WS2812_LED_GetHSV (u16 led, float *h, float *s, float *v)

## Detailed Description

WS2812 LED strip driver

This driver allows to control an (almost) unlimited number of WS2812 based RGB LEDs connected in a chain. Only the available RAM limits the number!

Unfortunately the WS2812 protocol can't be serviced by a regular serial peripheral without causing a high CPU load. But there are various methods to overcome this problem, a nice overview can be found at this (german) page: http://www.mikrocontroller.net/articles/WS2812_Ansteuerung

In this driver, the PWM based approach is used. A timer is running at 800 kHz (1.25 uS period time), and the high time will be set to 0.35 uS or 0.90 uS in order to send a logic-0 or logic-1

This approach is inspired from: http://mikrocontroller.bplaced.net/wordpress/?page_id=3665

In order to avoid that the CPU is loaded with switching the duty cycle for each bit during the serial transfer, we just use the DMA controller to perform the register write operations in background. This results into a high memory consumption, because for each bit a 16bit number has to be stored in memory, resulting into 48 bytes per RGB LED.

But the advantages are clearly that the CPU is not involved and can run other (more useful) tasks. Since the DMA is configured in circular mode, the LED strip will be periodically loaded with the current RGB values which are stored in the memory buffer.

Currently this driver is only supported for the MBHP_CORE_STM32F4 module. We take TIM4, since it isn't used by MIOS32 (yet), and pin PB6 (available at J4B.SC) since the second IIC port is normally not used by applications. This pin has already a 2.2k pull-up resistor on the MBHP_CORE_STM32F4 board, which is required to pull the output to 5V (the pin is configured in open-drain mode)

Note that the power-supply pins of the LED strip shouldn't be connected to J4B, because it can consume a lot of power depending on the LED brightness. Each RGB LED can draw up to 20 mA! Hence, for the MBHP_CORE_STM32F4 module, an external 5V PSU is recommended, which is either only used for the LED strip, or for the entire module.

## Define Documentation

#define WS2812_BUFFER_SIZE ((WS2812_NUM_LEDS+2)*24)

#define WS2812_DMA_CHN DMA_Channel_2

#define WS2812_DMA_PTR DMA1_Stream0

#define WS2812_SUPPORTED 0

#define WS2812_TIM TIM4

#define WS2812_TIM_CC_HIGH (u16)((WS2812_TIM_PERIOD - 1) * 0.74)

#define WS2812_TIM_CC_IDLE WS2812_TIM_PERIOD

#define WS2812_TIM_CC_LOW (u16)((WS2812_TIM_PERIOD - 1) * 0.28)

#define WS2812_TIM_CC_RESET 0

#define WS2812_TIM_CCR WS2812_TIM->CCR1

#define WS2812_TIM_CLK_FUNC { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); }

#define WS2812_TIM_DMA_TRG TIM_DMA_CC1

#define WS2812_TIM_OUT_PIN GPIO_Pin_6

#define WS2812_TIM_OUT_PORT GPIOB

#define WS2812_TIM_PERIOD ((MIOS32_SYS_CPU_FREQUENCY/2) / 800000)

#define WS2812_TIM_REMAP_FUNC { GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_TIM4); }

## Function Documentation

s32 WS2812_Init | ( | u32 | mode | ) |

Initializes WS2812 driver Should be called from Init() during startup

Parameters:

  `[in]` | mode | if 0, the entire driver will be configured, if 1 only the LEDs will be cleared

Returns:
  < 0 if initialisation failed

s32 WS2812_LED_GetHSV | ( | u16 | led,
|  | float * | h,
|  | float * | s,
|  | float * | v |
| ) |  |  |

Returns the HSV values of the LED (derived from RGB parameters)

Parameters:

  `[in]` | led | should be in the range 0..WS2812_NUM_LEDS-1
  `[out]` | h | the hue (0..360.0)
  `[out]` | s | the saturation (0.0..1.0)
  `[out]` | v | the brightness (0.0..1.0)

Returns:
  < 0 if invalid LED

Here is the call graph for this function:

s32 WS2812_LED_GetRGB | ( | u16 | led,
|  | u8 | colour |
| ) |  |  |

Returns a single colour of the RGB LED

Parameters:

  `[in]` | led | should be in the range 0..WS2812_NUM_LEDS-1
  `[in]` | colour | 0=R, 1=G, 2=B

Returns:
  < 0 if invalid LED or colour

s32 WS2812_LED_SetHSV | ( | u16 | led,
|  | float | h,
|  | float | s,
|  | float | v |
| ) |  |  |

Configures the LED according to a HSV value (Hue/Saturation/Value)

Parameters:

  `[in]` | led | should be in the range 0..WS2812_NUM_LEDS-1
  `[in]` | h | the hue (0..360.0)
  `[in]` | s | the saturation (0.0..1.0)
  `[in]` | v | the brightness (0.0..1.0)

Returns:
  < 0 if invalid LED

Here is the call graph for this function:

s32 WS2812_LED_SetRGB | ( | u16 | led,
|  | u8 | colour,
|  | u8 | value |
| ) |  |  |

Sets a single colour of the RGB LED

Parameters:

  `[in]` | led | should be in the range 0..WS2812_NUM_LEDS-1
  `[in]` | colour | 0=R, 1=G, 2=B
  `[in]` | value | 0..255

Returns:
  < 0 if invalid LED or colour