GPIO analog timing control peripheral 1 - WS2812B

foreword

The most basic functional module of the entire board was introduced in the previous article - using the general-purpose input and output of GPIO to realize simple key input and push-pull output control functions. This article goes a step further, on the basis of only using the input and output functions of GPIO, by viewing the chip manual of the corresponding module, and simulating its corresponding communication timing to drive the corresponding module.

WS2812B

First of all, there is an internet celebrity module - WS2812B colored lights, which can be said to be the overlord in the neighborhood of RGB lights. The driver is integrated inside, which can realize the full display of three colors (255 * 255 * 255 = 16777216 colors). True color, and supports serial control, the microcontroller can control a group of lights through a GPIO. For detailed features, please refer to the introduction of the chip manual.
insert image description here
insert image description here

1. Introduction to the module

insert image description here
Through the product overview in the manual, we can see its general control logic:
1. A single light needs a 24-bit data to control;
2. When controlling multiple points at the same time, it is necessary to send the corresponding number of lights according to the number of lights connected in series. 24bit control data;
3. Its reset time needs more than 280us.
insert image description here
A 24-bit control data is mentioned above, so what is the meaning of each bit of this 24-bit data?
It is also introduced in the data sheet, as shown in the figure below: 24bit data is spliced ​​by chromaticity data of three colors: green, red and blue . When the data is 0xFF 00 00, the corresponding light will light up green. When the data is When the data is 0x 00 FF 00, the small light is red, and when the data is 0x 00 00 FF, the small light is blue. Different colors can be combined according to different values.
insert image description here
Here is a color table for everyone to find the color you want - https://tool.oschina.net/commons?type=3
insert image description here
It should be noted that the order of the 24bit data written is GRB (green red blue) , and the color data queried here is RGB (red, green and blue), and the order needs to be changed when controlling.
So at this point, can we start writing code?

2. Timing Introduction

The answer is no. In order to improve the stability of data transmission, the interference in the signal transmission process should be eliminated as much as possible; the module will adopt a special output format to distinguish between 0 and 1 of the level. In the GPIO input and output in the previous article, "0" of STM32 corresponds to low level, and "1" corresponds to high level, but for WS2812B, "0" and "1" do not correspond to simple high and low Level, but needs to be based on the following timing waveform diagram:
insert image description here
It may be a bit abstract to look at this description directly. Here, the author uses a logic analyzer to capture a section of waveform. Let’s analyze it together with the above description:
insert image description here
This is using the STM32 analog timing To control the actual sampling waveform of the blue data pin of an RGB display 113355. According to the above timing waveform diagram for comparison,
insert image description here
the data content sent by the entire waveform can be read in sequence.
0011 0011 0001 0001 0101 0101
correspond to the three colors GRB () green, red and blue respectively.
The very beginning and the end of the waveform are very The long low level is the corresponding reset signal.
The final data analyzed by the logic analyzer is shown in the figure below:
insert image description here
So far, the communication timing of the WS2812B single lamp has basically been figured out. The only data that has not yet been determined is the specific high and low level time corresponding to sending 0 and 1 respectively. The timing diagram is given as a range, and it needs to be fine-tuned in actual use. We will put this in later code writing and then decide.
After finishing the control of a single light, the next step is the serial control of multiple lights.
insert image description here
According to the data transmission logic in the above figure, it can be known that when controlling multiple lights, it is only necessary to send multiple sets of 24-bit data continuously, such as If you want to control eight lights, send eight pieces of 24-bit data at a time, continuously in the middle. When you need to modify it, just add a reset signal greater than 280us at the end.
In the figure below, the red part is the waveform of the actual sent data, and the low level end in the middle is the reset signal.
insert image description here
In order to facilitate understanding, we zoom in on the red waveform in the middle of the above figure, and it can be seen that two 24bit control data are sent at a time, and two small lights in series will be lit at this time.
insert image description here
Alright, now that we have basically figured out the idea of ​​control, let's take a look at other parameters that need attention in the manual.

3. Hardware introduction

Each lamp bead has four pins as shown below. Among them, VDD and VSS provide power, DIN is the input signal, and DOUT is the data output pin. Serial control can be realized by connecting the data output pin of one lamp with the data input pin of the latter lamp. Here we can compare the pin introduction diagram to find the corresponding pins, which is convenient for using the logic analyzer to capture waveforms and other debugging.
insert image description here
insert image description here

4. Transmission rate and frame number requirements

Most of the other content in the manual is related to hardware, so I won’t go into details here, and students who need it can check it out by themselves. There are two important parameters that need to be paid attention to in programming. One is when the speed record is greater than 30 frames per second, There must be at least 1024 lights, and we only have eight lights here, so the number of light data packets controlled within 1s cannot exceed 30.
The other is more important, the sending speed of data can reach 800Kbps

Interpolate a little knowledge: bps is bit/s, called bit rate, also called bit rate, which is the number of bits of data that can be transmitted per second,
while baud/s is baud rate, meaning bytes per second, that is, one second How many bytes of data can be transferred. (One byte equals eight data bits).
insert image description here

That is to say, the highest data packet transmission rate supported by WS2812B is to receive 800,000 binary data in 1 second, which means that each binary bit must be kept for at least 1/800,000=1.25us. Remember the previous In the timing diagram, a single data "0" or a single data "1" is composed of different high and low time periods, that is to say, the sum of the high and low time of a single data "1" or a single data "0" Cannot be less than 1250ns.
T0H+T0L>1250ns
T1H+T1L>1250ns
insert image description here
After figuring this out, you can almost start writing code.
Before that, you need to take a look at the schematic diagram to find the control pin of WS2812B in this board. It can be seen from the schematic diagram that the control pin is GPIOA_8.
insert image description here
Why choose PA8? Here, the author has made two-handed preparations. The common driving methods of WS2812B include PWM and SPI to cooperate with the high-efficiency method of DMA. This driving scheme does not occupy CPU resources; the other is to use pure GPIO analog output. In order to take into account the solution, the author chose an IO port with multiplexing function. It's just that we have few lights here, 8 lights, so it's not a big problem to choose the software simulation solution. In addition, the four timers here are used by others. In order to avoid interference, we finally choose the software simulation solution. accomplish. If you want to see the scheme of PWM+DMA or SPI+DMA, you can search it yourself. I see that many bigwigs in CSDN use these two schemes, and they are very detailed.
insert image description here
The other is the power supply part, here the author chooses 5V power supply.

the code

1. Initialization

According to the above summary, the scheme of GPIO analog timing diagram is used here. First, the output must be high and low, so GPIOA8 needs to be configured as a general push-pull output mode, which will not be repeated here.

/*********************************
函数名:RGB_Init
函数功能:RGB初始化
形参:void
返回值:void
备注:
RGB-----PA8--------通用推挽输出
**********************************/
void RGB_Init(void)
{
    
    
	GPIO_InitTypeDef  GPIO_InitStructure;//定义一个结构体的变量
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//初始化GPIOA端口的时钟
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_Out_PP;//通用推挽输出
	GPIO_Init(GPIOA,&GPIO_InitStructure );
}

For the convenience of operation, it is best to define a macro to output high output and low output. Here
we need to pay attention. Combined with the introduction in the previous article, we know that library functions can be used to control the output of GPIO, and bit band operations can also be used. There is a solution with higher execution efficiency and lower latency, which directly uses registers to drive. Here I post all three kinds of macro definitions. The reason is that this module is designed to have a delay of ns. If one more code is run, it will run through 30ns-50ns, which will seriously affect the control effect. You can choose one of the three macro definitions, the fastest is the register, and the bit band operation is similar to the library function.

//位带操作
#define RGB_H   PAout(8)=1
#define RGB_L   PAout(8)=0
//库函数
#define RGB_H   GPIO_SetBits(GPIOA,GPIO_Pin_8)
#define RGB_L   GPIO_ResetBits(GPIOA,GPIO_Pin_8)
//直接操作寄存器(最快)
#define RGB_H   GPIOA->ODR |= (1<<8)
#define RGB_L   GPIOA->ODR &= ~(1<<8)

2. Analog Timing

After the initialization is done, it's time to start the most important part. Compare the timing diagram to simulate the timing.
For this kind of modules that need to simulate timing, we must think from the bottom up, start writing from the most basic sending "0" and sending "1", and encapsulate sending 0 and sending 1 into corresponding functions; in addition It is also necessary to encapsulate the lowest-level functions such as reset and initialization according to the actual needs of the module. Here, WS2812B also needs a reset function. After encapsulating these functions, the function encapsulation of data packet sending is performed according to the timing, and then the timing code of the entire module is pieced together.

1. Reset function

Let’s start with the simplest one, the reset function. According to the data sheet, the timing of the reset circuit is to pull the signal pin low, and the pull-down time is not less than 280us. Here we give 350us. The delay here is us-level, so it can be realized by using the us delay of the system tick. The system tick is the most accurate in the delay, and the timer is not as accurate, so it is best to use the system tick here. About The introduction of the system tick is estimated to be introduced together with the part of GPIO multiplexing, which is the timer, and it will be used here first.

/*********************************
函数名:RGB_Reset
函数功能:RGB复位信号
形参:void
返回值:void
备注:
**********************************/
void RGB_Reset(void)
{
    
    
	RGB_L;
	Systick_Delay_us(350);//调用系统滴答来实现
}

2. Send 0, 1 code

The first thing that needs to be solved is the delay problem of ns. The main frequency of STM32F103C8T6 is 72MHZ, that is, it can run 72 000 000 machine instructions in 1s. System ticks and timers can only provide us-level delays, and this ns delay can only be performed by running a fixed number of machine instructions.
The calculation process is as follows:
1s can run 72 000 000 machine instructions, then
1us can run 72 machine instructions, in other words, the time it takes for the CPU to execute 72 machine instructions is 1us. Then the time spent by one machine instruction is 1us/72=13.88889ns; that is to say, every time the CPU runs a machine instruction, 13.8889ns has passed.
Then look at the specific timing diagram:
insert image description here
here the high-level time T0H of code 0 should be between 220ns~380ns, and the low-level time T0L should be controlled between 580ns-1600ns, and T0H+T0L>1250ns
Here we First set T0H, compromise, choose 300ns,
300/13.889=21.5999, round up, take 22 machine instructions,
then the question comes, we usually use C code, one C code is equal to one machine instruction?
The answer is no, there is no fixed relationship between a C code and a machine instruction, because the underlying assembly code of each C code is different. But fortunately, there is a special machine instruction __nop().
A __nop() is a machine instruction.
So the first delay is obtained:

//220-380 ns折中 300 13.89*22=305.5558
void delay_300ns(void)  //72 000 000MHZ  ==1s  72hz 1us  一个机器指令周期要耗时13.89ns
{
    
    
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();
}

Then to solve the second delay or adopt the solution of removing the intermediate value, take 1090ns,
1090/13.889=78.4, round up to 78
and get the second delay

//折中 1090 78*13.889
void delay_1090ns(void)  //72 000 000MHZ  ==1s  72hz 1us  一个机器指令周期要耗时13.8ns
{
    
    
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
}

So there is a sending code of 0 yards

/*********************************
函数名:RGB_Send0
函数功能:RGB发送0
形参:void
返回值:void
备注:
**********************************/
void RGB_Send0()
{
    
    
	RGB_H;
	delay_300ns();
	RGB_L;
	delay_1090ns();
}

By analogy, you can exit the transmission of 1 code, and you can use the above delay, but it is best to get another delay_320ns. The measured effect of delay_320 will be better.

/*********************************
函数名:RGB_Send1
函数功能:RGB发送1
形参:void
返回值:void
备注:
**********************************/
void RGB_Send1()
{
    
    
	RGB_H;
	delay_1090ns();
	RGB_L;
	delay_320ns();
}

3. Encapsulate the sending function

As mentioned earlier, the 24-bit data corresponds to the 8-bit of GRB, so here is the sending function of the entire 8-bit data, the high-order bit is sent first, so the following code can be obtained:


/*********************************
函数名:RGB_Send_Data
函数功能:RGB发送8位数据
形参:u8 data需要发送的数据
返回值:void
备注:
**********************************/
void RGB_Send_Data(u8 data) 
{
    
     
   uint8_t i;
   for(i=8;i>0;i--) 
   {
    
    
     if(data & 0x80)//按位与,为真发送1,为假发送零
     {
    
    
        RGB_Send1();
     }
     else
     {
    
    
        RGB_Send0();
     }
     data <<=1;//
   }
}

Then encapsulate a function to send 24bit

/*********************************
函数名:Send_GRB
函数功能:GRB发送24位数据
形参:u8 G,u8 R,u8 B
返回值:void
备注:
**********************************/
void Send_GRB(uint8_t G,uint8_t R,uint8_t B)
{
    
    
	RGB_Send_Data(G);
	RGB_Send_Data(R);
	RGB_Send_Data(B);
	RGB_Reset();
}

With this function, the control of a single light can already be realized,
insert image description here
insert image description here
and then in order to control the lights behind, we need to encapsulate a function that controls multiple lights. According to the timing sequence analyzed above,
the code is as follows:


/*********************************
函数名:Continuous_Set_LED
函数功能:设置n个灯为 GRB的颜色
形参:u8 G,u8 R,u8 B
返回值:uint8_t n多少个灯
,uint32_t GRB设置的颜色
备注:
**********************************/
void Continuous_Set_LED(uint8_t n,uint32_t GRB)
{
    
    
	while(n--)
	{
    
    
		RGB_Send_Data((GRB>>16)&0xFF);
		RGB_Send_Data((GRB>>8)&0xFF);
		RGB_Send_Data((GRB>>0)&0xFF);
	}
	RGB_Reset();
}

Calling this function can realize the control of the specified number of lights. Of course, it can also perform functions such as running water, scrolling, etc. If you need this, you can check the codes of other big guys.
insert image description here
insert image description here
insert image description here

Summarize

So far, the introduction of the analog driver of WS2812B is finished. If there are any deficiencies in the article, please criticize and correct me. The next article will continue to use the analog timing sequence to complete the acquisition of temperature and humidity data for DHT11. First, I will put a logical analysis of the captured data waveform analysis here for everyone. refer to.
insert image description here

insert image description here

Guess you like

Origin blog.csdn.net/qq_41954556/article/details/131140231