Linux应用层SPI驱动WS2812_RGB灯
在F1C100S上调试的,原本打算用GPIO来驱动RGB灯的,使用GPIOD这个库来操作GPIO,实测下来翻转速度还到不了1MHZ,这肯定是不行。于是就用SPI来驱动了
首先是在设备树添加SPI1,这样系统启动后应用层才可以操作SPI设备,注意这里并没有匹配“spi-dev”,因为启动时会有错误提示,但是spi是可以用的,这里为了去除那个错误就匹配的下边这个,用起来是一样的。
1
2
3
4
5
6
7
8
9&spi1{
status = "okay";
spidev@0{
compatible = "rohm,dh2228fv";
spi-max-frequency = <50000000>;
reg = <0>;
status = "okay";
};
};系统启动后,查看/dev是否有spidev1.0。
另外虽然SPI初始化后有4个脚,但是实际测试依然可以做为普通GPIO使用,也即只使用MOSI这一个引脚即可
一切做准备就绪,首先就是要初始化SPI,这里的mode并无多大关系,任意一种都可以的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
int spi_init(char *spi_dev, int mode, int bits, int speed)
{
fd = open(spi_dev, O_RDWR);
if (fd < 0)
{
printf("[%s]:[%d] open spi file error\r\n", __FUNCTION__, __LINE__);
return -1;
}
//设置模式
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1)
printf("can't set spi mode");
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1)
printf("can't get spi mode");
//设置一次多少位
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
printf("can't set bits per word");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
printf("can't get bits per word");
//设置最大速度
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
printf("can't set max speed hz");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
printf("can't get max speed hz");
printf("spi mode: %d\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed / 1000);
return 0;
}我用的灯的时序如下图所示,数据格式为RGB888
a.从下图可以看到是通过高电平和低电平时间来确认发送的是0还是1
b.高0.3us低0.9us代表0,高0.9us低0.3us代表1
c.总时间约1.2us士0.16us 1.04us-1.36us 这里按1Mhz进行计算,F1C100S 可以设置的时钟 1M 2M 4M 8M .......
d. 这里采取8个时钟输出1位灯的数据,经过计算可知0xf8(1111 1100=0.125us*7=750us)就可代表1,0xc0(1100 0000=0.125us*2=250us)就代表0.
e. 由以上可知,一个RGB灯是由24Bit组成,SPI一次需要发送24个字节才能控制一个灯
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15for (uint8_t j = 0; j < 3; j++)
{
for (uint8_t i = 0; i < 8; i++)
{
if ((data & 0x80) > 0)
{
temp->data[i + j * 8] = 0xfc; // 1
}
else
{
temp->data[i + j * 8 ] = 0xc0; // 0
}
data = data << 1;
}
}

最后就是关于亮度调整的问题,要想调整亮度需要把RGB数据转换到HSV姿色空间下才好调整亮度
以下是关于RGB<—>HSV互转的代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
void led_strip_rgb2hsv(color_rgb_t *rgb,color_hsv_t *hsv)
{
uint8_t max, min, delta = 0;
rgb->b = (uint8_t)(rgb->color);
rgb->g = (uint8_t)((rgb->color)>>8);
rgb->r = (uint8_t)((rgb->color)>>16);
max = max3(rgb->r, rgb->g, rgb->b);
min = min3(rgb->r, rgb->g, rgb->b);
delta = (max - min);
if (delta == 0)
{
hsv->h = 0;
}
else
{
if (rgb->r == max)
{
hsv->h = ((rgb->g - rgb->b) * 60 / delta);
}
else if (rgb->g == max)
{
hsv->h = 120 + (((rgb->b - rgb->r) * 60 / delta));
}
else if (rgb->b == max)
{
hsv->h = 240 + (((rgb->r - rgb->g) * 60 / delta));
}
if (hsv->h < 0)
{
hsv->h += 360;
}
}
if (max == 0)
{
hsv->s = 0;
}
else
{
hsv->s = (delta*100 / max);
}
hsv->v = max;
}
void led_strip_hsv2rgb(color_hsv_t *hsv,color_rgb_t *rgb)
{
hsv->h %= 360; // h -> [0,360]
uint32_t rgb_max = hsv->v * 2.55f;
uint32_t rgb_min = rgb_max * (100 - hsv->s) / 100.0f;
uint32_t i = hsv->h / 60;
uint32_t diff = hsv->h % 60;
// RGB adjustment amount by hue
uint32_t rgb_adj = (rgb_max - rgb_min) * diff / 60;
switch (i)
{
case 0:
rgb->r = rgb_max;
rgb->g = rgb_min + rgb_adj;
rgb->b = rgb_min;
break;
case 1:
rgb->r = rgb_max - rgb_adj;
rgb->g = rgb_max;
rgb->b = rgb_min;
break;
case 2:
rgb->r = rgb_min;
rgb->g = rgb_max;
rgb->b = rgb_min + rgb_adj;
break;
case 3:
rgb->r = rgb_min;
rgb->g = rgb_max - rgb_adj;
rgb->b = rgb_max;
break;
case 4:
rgb->r = rgb_min + rgb_adj;
rgb->g = rgb_min;
rgb->b = rgb_max;
break;
default:
rgb->r = rgb_max;
rgb->g = rgb_min;
rgb->b = rgb_max - rgb_adj;
break;
}
rgb->color = rgb->r;
rgb->color = (rgb->color << 8) | rgb->g;
rgb->color = (rgb->color << 8) | rgb->b;
//printf("color:%x %x %x %x\n", rgb->color,rgb->r, rgb->g, rgb->b);
}
评论