{"id":1060,"date":"2022-06-29T07:15:03","date_gmt":"2022-06-29T07:15:03","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=1060"},"modified":"2022-06-29T07:29:28","modified_gmt":"2022-06-29T07:29:28","slug":"working-with-stm32-and-addressable-led-part-2-driver-development","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=1060","title":{"rendered":"Working with STM32 and Addressable LED part 2: Driver development"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/06\/F68DRVWHOSC3N00.jpg\" alt=\"\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>In the pervious guide(<a href=\"https:\/\/blog.embeddedexpert.io\/?p=1047\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=1047\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>), we took a look at the WS2812 and they work and type of communication required.<\/p>\n\n\n\n<p>In this guide, we shall see how to use PWM in DMA mode to control those LED.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Setting up the PWM and DMA:<\/h2>\n\n\n\n<p>Since we shall use TIMER 1 of the STM32 to generate the required data signal, we shall develop everything around TIMER1.<\/p>\n\n\n\n<p>Since TIM1_CH1 is connected to PA8, we need to enable clock access to GPIOA and set PA8 to alternate function and select AF1 for PA8 as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#define AF01   (0x01)\nRCC-&gt;AHB1ENR|=RCC_AHB1ENR_GPIOAEN;\nGPIOA-&gt;MODER|=GPIO_MODER_MODE8_1;\nGPIOA-&gt;MODER&amp;=~GPIO_MODER_MODE8_0;\nGPIOA-&gt;AFR[1]|=(AF01&lt;&lt;0);<\/pre><\/div>\n\n\n\n<p>Then enable clock access to timer1<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">RCC-&gt;APB2ENR|=RCC_APB2ENR_TIM1EN; \/\/enable clock access to tim1<\/pre><\/div>\n\n\n\n<p>Set the prescaler to 0:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">TIM1-&gt;PSC=0; \/\/set prescaller to 0 (no divider)<\/pre><\/div>\n\n\n\n<p>Set the ARR to 90 (maximum value to count):<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">TIM1-&gt;ARR=90-1; \/\/set the maximum count value<\/pre><\/div>\n\n\n\n<p>Enable Capture\/Compare 1 DMA request:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">TIM1-&gt;DIER|=TIM_DIER_CC1DE;<\/pre><\/div>\n\n\n\n<p>Set CH1 as PWM mode and enable Output Compare 1 preload:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">TIM1-&gt;CCMR1|=TIM_CCMR1_OC1M_2|TIM_CCMR1_OC1M_1|TIM_CCMR1_OC1PE; \/\/configure the pin as PWM<\/pre><\/div>\n\n\n\n<p>Enable Capture\/Compare channel 1:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">TIM1-&gt;CCER|=TIM_CCER_CC1E; \/\/enable channel1<\/pre><\/div>\n\n\n\n<p>Set DMA address for full transfer to 1:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">TIM1-&gt;DMAR|=0x01;<\/pre><\/div>\n\n\n\n<p>Enable main output (For advanced timers only):<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">TIM1-&gt;BDTR=TIM_BDTR_MOE;<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Now, for DMA Setup.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Since TIM1 is connected to DMA2 Stream1 Channel 6, we shall first enable clock access to DMA2 and disable the stream as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">RCC-&gt;AHB1ENR|=RCC_AHB1ENR_DMA2EN;\nDMA2_Stream1-&gt;CR&amp;=~DMA_SxCR_EN;\nwhile((DMA2_Stream1-&gt;CR)&amp;DMA_SxCR_EN){;}<\/pre><\/div>\n\n\n\n<p>Then we shall configure the DMA as following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Channel number 6<\/li><li>Memory and peripheral 6 to half-word (16-bit)<\/li><li>Memory Increment mode.<\/li><li>Direct memory to peripheral.<\/li><li>Transfer complete interrupt.<\/li><\/ul>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#define CH6   ((0x06&lt;&lt;25))\nDMA2_Stream1-&gt;CR|=CH6|DMA_SxCR_MSIZE_0|DMA_SxCR_PSIZE_0|DMA_SxCR_MINC|DMA_SxCR_DIR_0|DMA_SxCR_TCIE;<\/pre><\/div>\n\n\n\n<p>Set the peripheral address to TIM1-&gt;CCR1<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">DMA2_Stream1-&gt;PAR=(uint32_t)(&amp;TIM1-&gt;CCR1);<\/pre><\/div>\n\n\n\n<p>Enable DMA2_Stream1 interrupt in NVIC:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">NVIC_EnableIRQ(DMA2_Stream1_IRQn);<\/pre><\/div>\n\n\n\n<p>Hence, the initializing of PWM and DMA is as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void  WS2812_init(void){\n#define CH6   ((0x06&lt;&lt;25))\n#define AF01   (0x01)\n\/\/GPIO init\nRCC-&gt;AHB1ENR|=RCC_AHB1ENR_GPIOAEN;\nGPIOA-&gt;MODER|=GPIO_MODER_MODE8_1;\nGPIOA-&gt;MODER&amp;=~GPIO_MODER_MODE8_0;\nGPIOA-&gt;AFR[1]|=(AF01&lt;&lt;0);\n\/\/init timer;\nRCC-&gt;APB2ENR|=RCC_APB2ENR_TIM1EN; \/\/enable clock access to tim1\nTIM1-&gt;PSC=0; \/\/set prescaller to 0 (no divider)\nTIM1-&gt;ARR=90-1; \/\/set the maximum count value\nTIM1-&gt;CNT=0; \/\/reset the current count\nTIM1-&gt;DIER|=TIM_DIER_CC1DE;\nTIM1-&gt;CCMR1|=TIM_CCMR1_OC1M_2|TIM_CCMR1_OC1M_1|TIM_CCMR1_OC1PE; \/\/configure the pin as PWM\nTIM1-&gt;CCER|=TIM_CCER_CC1E; \/\/enable channel1\nTIM1-&gt;DMAR|=0x01;\nTIM1-&gt;BDTR=TIM_BDTR_MOE;\n\n\/\/init dma\nRCC-&gt;AHB1ENR|=RCC_AHB1ENR_DMA2EN;\nDMA2_Stream1-&gt;CR&amp;=~DMA_SxCR_EN;\nwhile((DMA2_Stream1-&gt;CR)&amp;DMA_SxCR_EN){;}\nDMA2_Stream1-&gt;CR|=CH6|DMA_SxCR_MSIZE_0|DMA_SxCR_PSIZE_0|DMA_SxCR_MINC|DMA_SxCR_DIR_0|DMA_SxCR_TCIE;\nDMA2_Stream1-&gt;PAR=(uint32_t)(&amp;TIM1-&gt;CCR1);\nNVIC_EnableIRQ(DMA2_Stream1_IRQn);\n}<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">5. Setting up the LEDs:<\/h2>\n\n\n\n<p>In this guide, we shall use LEDs ring which has 24 LEDs. Hence, we can create symbolic name for number of LEDs as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#define  Num_of_LEDs 24<\/pre><\/div>\n\n\n\n<p>Then we shall create two two-dimensional arrays, one for GRB data and the other for brightness:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">uint8_t LED_Data[Num_of_LEDs][4];\nuint8_t LED_Mod[Num_of_LEDs][4];  \/\/ for brightness<\/pre><\/div>\n\n\n\n<p>Hence, the set led function is as following:<\/p>\n\n\n\n<p>It takes four arguments:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>LED Number.<\/li><li>Red value.<\/li><li>Green value.<\/li><li>Blue value.<\/li><\/ul>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void Set_LED (int LEDnum, int Red, int Green, int Blue)\n{\n\tLED_Data[LEDnum][0] = LEDnum;\n\tLED_Data[LEDnum][1] = Green;\n\tLED_Data[LEDnum][2] = Red;\n\tLED_Data[LEDnum][3] = Blue;\n}<\/pre><\/div>\n\n\n\n<p>For setting the brightness of all LEDs:<\/p>\n\n\n\n<p>The function takes single argument which is the brightness with a value from 0 to 45:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\nvoid Set_Brightness (int brightness)  \/\/ 0-45\n{\n#define PI 3.14159265\n\n\n\tif (brightness &gt; 45) brightness = 45;\n\tfor (int i=0; i&lt;Num_of_LEDs; i++)\n\t{\n\t\tLED_Mod[i][0] = LED_Data[i][0];\n\t\tfor (int j=1; j&lt;4; j++)\n\t\t{\n\t\t\tfloat angle = 90-brightness;  \/\/ in degrees\n\t\t\tangle = angle*PI \/ 180;  \/\/ in rad\n\t\t\tLED_Mod[i][j] = (LED_Data[i][j])\/(tan(angle));\n\t\t}\n\t}\n\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">6. Sending the data:<\/h2>\n\n\n\n<p>First we create an array with the size of number of LEDs multiplied by 24 then adding 50.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">uint16_t pwmData[(24*Num_of_LEDs)+50];<\/pre><\/div>\n\n\n\n<p>To send the data:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void WS2812_display()\n{\n\tuint32_t indx=0;\n\tuint32_t color;\n\tfor (int i= 0; i&lt;Num_of_LEDs; i++)\n\t\t{\n\t\t\tcolor = ((LED_Mod[i][1]&lt;&lt;16) | (LED_Mod[i][2]&lt;&lt;8) | (LED_Mod[i][3]));\n\n\t\t\tfor (int i=23; i&gt;=0; i--)\n\t\t\t{\n\t\t\t\tif (color&amp;(1&lt;&lt;i))\n\t\t\t\t{\n\t\t\t\t\tpwmData[indx] = 60;  \/\/ 2\/3 of 90\n\t\t\t\t}\n\n\t\t\t\telse pwmData[indx] = 30;  \/\/ 1\/3 of 90\n\n\t\t\t\tindx++;\n\t\t\t}\n\n\t\t}\n\n\tfor (int i=0; i&lt;50; i++)\n\t\t{\n\t\t\tpwmData[indx] = 0;\n\t\t\tindx++;\n\t\t}\n\n\n\tDMA2_Stream1-&gt;M0AR=(uint32_t)(&amp;pwmData);\n\tDMA2_Stream1-&gt;NDTR=indx;\n\tDMA2-&gt;LIFCR|=DMA_LIFCR_CFEIF1|DMA_LIFCR_CDMEIF1|DMA_LIFCR_CTEIF1|DMA_LIFCR_CHTIF1|DMA_LIFCR_CTCIF1;\n\tTIM1-&gt;CR1|=TIM_CR1_CEN; \/\/enable timer\n\tDMA2_Stream1-&gt;CR|=DMA_SxCR_EN;\n\twhile(finished==0);\n\tfinished=0;\n\t}<\/pre><\/div>\n\n\n\n<p>The function takes first LED and extract the color value. Then, from the color value, it will build the first 24-bit data for first LED by setting the duty cycle to 60 if the bit is 1 and 30 if the bit is zero (as seen in part 1). Then the code shall iterate for all LEDs. After finishing all the LEDs, it will add 50 extra of 0% of duty cycle to indicate the end of transmission. then launch the DMA transfer and wait for the transfer to complete.<\/p>\n\n\n\n<p>DMA2_Steam1 interrupt handler:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\nvoid DMA2_Stream1_IRQHandler(void)\n\t{\n\tif((DMA2-&gt;LISR&amp;DMA_LISR_TCIF1))\n\t\t{\n\t\tfinished=1;\n\t\tTIM1-&gt;CR1&amp;=~TIM_CR1_CEN;\n\t\tDMA2-&gt;LIFCR|=DMA_LIFCR_CTCIF1;\n\n\t\t}\n\n\t}<\/pre><\/div>\n\n\n\n<p>Hence, the entire ws2812 source file as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\n#include &lt;WS2812.h&gt;\n#include &quot;stm32f4xx.h&quot;\n#include &quot;math.h&quot;\n#include &quot;string.h&quot;\n\n\nvolatile uint8_t finished;\n\n#define  Num_of_LEDs 24\n\nvoid  WS2812_init(void){\n#define CH6   ((0x06&lt;&lt;25))\n#define AF01   (0x01)\n\/\/GPIO init\nRCC-&gt;AHB1ENR|=RCC_AHB1ENR_GPIOAEN;\nGPIOA-&gt;MODER|=GPIO_MODER_MODE8_1;\nGPIOA-&gt;MODER&amp;=~GPIO_MODER_MODE8_0;\nGPIOA-&gt;AFR[1]|=(AF01&lt;&lt;0);\n\/\/init timer;\nRCC-&gt;APB2ENR|=RCC_APB2ENR_TIM1EN; \/\/enable clock access to tim1\nTIM1-&gt;PSC=0; \/\/set prescaller to 0 (no divider)\nTIM1-&gt;ARR=90-1; \/\/set the maximum count value\nTIM1-&gt;CNT=0; \/\/reset the current count\nTIM1-&gt;DIER|=TIM_DIER_CC1DE;\nTIM1-&gt;CCMR1|=TIM_CCMR1_OC1M_2|TIM_CCMR1_OC1M_1|TIM_CCMR1_OC1PE; \/\/configure the pin as PWM\nTIM1-&gt;CCER|=TIM_CCER_CC1E; \/\/enable channel1\nTIM1-&gt;DMAR|=0x01;\nTIM1-&gt;BDTR=TIM_BDTR_MOE;\n\n\/\/init dma\nRCC-&gt;AHB1ENR|=RCC_AHB1ENR_DMA2EN;\nDMA2_Stream1-&gt;CR&amp;=~DMA_SxCR_EN;\nwhile((DMA2_Stream1-&gt;CR)&amp;DMA_SxCR_EN){;}\nDMA2_Stream1-&gt;CR|=CH6|DMA_SxCR_MSIZE_0|DMA_SxCR_PSIZE_0|DMA_SxCR_MINC|DMA_SxCR_DIR_0|DMA_SxCR_TCIE;\nDMA2_Stream1-&gt;PAR=(uint32_t)(&amp;TIM1-&gt;CCR1);\nNVIC_EnableIRQ(DMA2_Stream1_IRQn);\n}\n\nuint8_t LED_Data[Num_of_LEDs][4];\nuint8_t LED_Mod[Num_of_LEDs][4];  \/\/ for brightness\n\n\nvoid Set_LED (int LEDnum, int Red, int Green, int Blue)\n{\n\tLED_Data[LEDnum][0] = LEDnum;\n\tLED_Data[LEDnum][1] = Green;\n\tLED_Data[LEDnum][2] = Red;\n\tLED_Data[LEDnum][3] = Blue;\n}\n\n\n\n\n\nvoid Set_Brightness (int brightness)  \/\/ 0-45\n{\n#define PI 3.14159265\n\n\n\tif (brightness &gt; 45) brightness = 45;\n\tfor (int i=0; i&lt;Num_of_LEDs; i++)\n\t{\n\t\tLED_Mod[i][0] = LED_Data[i][0];\n\t\tfor (int j=1; j&lt;4; j++)\n\t\t{\n\t\t\tfloat angle = 90-brightness;  \/\/ in degrees\n\t\t\tangle = angle*PI \/ 180;  \/\/ in rad\n\t\t\tLED_Mod[i][j] = (LED_Data[i][j])\/(tan(angle));\n\t\t}\n\t}\n\n}\n\n\nuint16_t pwmData[(24*Num_of_LEDs)+50];\n\nvoid WS2812_display()\n{\n\tuint32_t indx=0;\n\tuint32_t color;\n\tfor (int i= 0; i&lt;Num_of_LEDs; i++)\n\t\t{\n\t\t\tcolor = ((LED_Mod[i][1]&lt;&lt;16) | (LED_Mod[i][2]&lt;&lt;8) | (LED_Mod[i][3]));\n\n\t\t\tfor (int i=23; i&gt;=0; i--)\n\t\t\t{\n\t\t\t\tif (color&amp;(1&lt;&lt;i))\n\t\t\t\t{\n\t\t\t\t\tpwmData[indx] = 60;  \/\/ 2\/3 of 90\n\t\t\t\t}\n\n\t\t\t\telse pwmData[indx] = 30;  \/\/ 1\/3 of 90\n\n\t\t\t\tindx++;\n\t\t\t}\n\n\t\t}\n\n\tfor (int i=0; i&lt;50; i++)\n\t\t{\n\t\t\tpwmData[indx] = 0;\n\t\t\tindx++;\n\t\t}\n\n\n\tDMA2_Stream1-&gt;M0AR=(uint32_t)(&amp;pwmData);\n\tDMA2_Stream1-&gt;NDTR=indx;\n\tDMA2-&gt;LIFCR|=DMA_LIFCR_CFEIF1|DMA_LIFCR_CDMEIF1|DMA_LIFCR_CTEIF1|DMA_LIFCR_CHTIF1|DMA_LIFCR_CTCIF1;\n\tTIM1-&gt;CR1|=TIM_CR1_CEN; \/\/enable timer\n\tDMA2_Stream1-&gt;CR|=DMA_SxCR_EN;\n\twhile(finished==0);\n\tfinished=0;\n\t}\n\n\nvoid DMA2_Stream1_IRQHandler(void)\n\t{\n\tif((DMA2-&gt;LISR&amp;DMA_LISR_TCIF1))\n\t\t{\n\t\tfinished=1;\n\t\tTIM1-&gt;CR1&amp;=~TIM_CR1_CEN;\n\t\tDMA2-&gt;LIFCR|=DMA_LIFCR_CTCIF1;\n\n\t\t}\n\n\t}\n<\/pre><\/div>\n\n\n\n<p>For the header file:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#ifndef WS2812_H_\n#define WS2812_H_\n#include &quot;stdint.h&quot;\nvoid  WS2812_init(void);\nvoid Set_Brightness (int brightness);\nvoid Set_LED (int LEDnum, int Red, int Green, int Blue);\nvoid WS2812_display(void);\n\n\n#endif \/* WS2812_H_ *\/<\/pre><\/div>\n\n\n\n<p>In the main function:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">extern void SysClockConfig(void);\n#include &quot;stm32f4xx.h&quot;\n#include &quot;delay.h&quot;\n#include &quot;math.h&quot;\n#include &lt;WS2812.h&gt;\n#include &quot;stdlib.h&quot;\n\n\n\nint main(void)\n\t{\n\n\tSCB-&gt;CPACR |= ((3UL &lt;&lt; 10*2)|(3UL &lt;&lt; 11*2)); \/*Enable floating point unit*\/\n\tSysClockConfig();\n\tsystick_init_ms(72000000);\n\tWS2812_init();\n\n\twhile(1)\n\t\t{\n\n\t\tfor (int i=0;i&lt;24;i++)\n\t\t\t{\n\t\t\t\tsrand(millis());\n\t\t\t\tSet_LED(i,random()%256,random()%256,random()%256);\n\t\t\t\tSet_Brightness(20);\n\t\t\t\tWS2812_display();\n\t\t\t\tdelay(random()%100);\n\t\t\t}\n\t\tdelay(200);\n\n\t\tfor (int i=24;i&gt;=0;i--)\n\t\t\t{\n\t\t\t\tSet_LED(i,0,0,0);\n\t\t\t\tSet_Brightness(20);\n\t\t\t\tWS2812_display();\n\t\t\t\tdelay(random()%100);\n\t\t\t}\n\t\tdelay(200);\n\n\t\t}\n\n\t}\n\n\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">7. Code:<\/h2>\n\n\n\n<p>You may download the code from here:<\/p>\n\n\n\n<div class=\"wp-block-file\"><a href=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/06\/WS2812.zip\">WS2812<\/a><a href=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2022\/06\/WS2812.zip\" class=\"wp-block-file__button\" download>Download<\/a><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">8. Demo:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"WS2812 Demo on STM32F4\" width=\"1170\" height=\"658\" src=\"https:\/\/www.youtube.com\/embed\/H6uuAXsfLwQ?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p>Happy coding \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the pervious guide(here), we took a look at the WS2812 and they work and type of communication required. In this guide, we shall see how to use PWM in DMA mode to control those LED. 4. Setting up the PWM and DMA: Since we shall use TIMER 1 of the STM32 to generate the [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,2,11,12],"tags":[],"class_list":["post-1060","post","type-post","status-publish","format-standard","hentry","category-data-structures","category-embedded-systems","category-peripheral-drivers","category-stm32"],"_links":{"self":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/1060"}],"collection":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1060"}],"version-history":[{"count":3,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/1060\/revisions"}],"predecessor-version":[{"id":1064,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/1060\/revisions\/1064"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1060"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1060"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1060"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}