Contributed by WildboarG, organized by Ai-Thinker
Ai-WB2 SPI Testing
WB2 SPI Testing
About the hosal library
When testing the WB2's SPI I kept getting overflow errors. I was using the WB2-12Fkit development board, and when running the garden director's (园长) demo to light up the WS2812, it got stuck at the SPI initialization; I also noticed on the forum that some other experts got stuck at the initialization as well.
Using the printf debugging method to trace step by step, I found that it was stuck in the GPIO initialization function.
Click to expand full code
static
void
hosal_spi_gpio_init
(
hosal_spi_dev_t
*arg)
{
if
(!arg) {
blog_error(
"arg err.\r\n"
);
return
;
}
GLB_GPIOgeng huan_Type gpiopins[
4
];
gpiopins[
0
] =
22
;
//这里注释掉就可以初始化完成
gpiopins[
1
] = arg->config.pin_clk;
gpiopins[
2
] = arg->config.pin_mosi;
gpiopins[
3
] = arg->config.pin_miso;
GLB_GPIO_Func_Init(GPIO_FUN_SPI,gpiopins,
sizeof
(gpiopins)/
sizeof
(gpiopins[
0
]));
if
(arg->config.mode ==
0
) {
GLB_Set_SPI_0_ACT_MOD_Sel(GLB_SPI_PAD_ACT_AS_MASTER);
}
else
{
GLB_Set_SPI_0_ACT_MOD_Sel(GLB_SPI_PAD_ACT_AS_SLAVE);
}
return
;
}I don't understand why the SPI GPIO initialization also initializes pin 22 besides the pins actually used. According to the manual, the 12F cannot use this pin, so I commented it out and initialized only the three pins CLK, MOSI, and MISO, after which the initialization completed normally. However, sending data still reports the overflow problem.
Not giving up, I wrote my own SPI sending demo, but it still overflowed.
Switching the SDK
After two days of struggling without a solution, I tried switching to the Bouffalo Lab SDK. The documentation says SPI is supported on the bl602/bl604 but untested, which chilled my heart halfway. I wrote a demo that sends 1234..., compiled and flashed it, and it errored again. I brought out the printf debugging method once more and traced it to this spot in the board.c file.
Click to expand full code
void
board_spi0_gpio_init
()
{
// struct bflb_device_s *gpio;
// gpio = bflb_device_get_by_name("gpio");
// bflb_gpio_init(gpio, GPIO_PIN_18, GPIO_FUNC_SPI0 | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1);
// bflb_gpio_init(gpio, GPIO_PIN_19, GPIO_FUNC_SPI0 | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1);
// bflb_gpio_init(gpio, GPIO_PIN_20, GPIO_FUNC_SPI0 | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1);
}The pins used for SPI need their initialization implemented yourself (it's commented out here, meaning you need to use the actual pins accordingly).
I checked the manual; there are quite a few supported SPI pins, so I chose IO3, IO4, IO5.
I flashed and tested again, and data could be sent successfully; the receiver also said there was no problem.
But a magical thing happened: when I used the Ai-Thinker-WB2 SDK to flash the program again, it just wouldn't flash, while with the bouffalo SDK flashing works fine. Does any expert know the reason?
Then I tried the example of lighting up the WS2812 LED:
Click to expand full code
#
include
"bflb_mtimer.h"
#
include
"bflb_spi.h"
#
include
"board.h"
#
include
"bflb_gpio.h"
#
include
<stdio.h>
#
define
SPI_MASTER_CASE 0
#
define
SPI_SLAVE_CASE 1
#
define
SPI_CASE_SELECT SPI_MASTER_CASE
// SPI数据为0的时序
#
define
SPI_NEO0 ((uint8_t)0b11000000)
// SPI数据为1的时序
#
define
SPI_NEO1 ((uint8_t)0b11111100)
#
define
BITS_PER_LED_COLOR (sizeof(color_t) * 8)
#
define
BUFF_LEN (8 * 1024)
uint32_t
tx_buff[BUFF_LEN /
4
];
uint32_t
rx_buff[BUFF_LEN /
4
];
struct
bflb_device_s
*
spi0
;
typedef
struct
{
uint8_t
r;
uint8_t
g;
uint8_t
b;
}
color_t
;
typedef
struct
{
uint16_t
led_counts;
// LED数量
uint8_t
*color_datas;
// 24位颜色数据
uint16_t
color_data_size;
// 颜色数据长度
color_t
*led_colors;
// LED颜色
bool
inited;
// 是否初始化,1表示已经初始化,0则表示未初始化
}
ws2812b_t
;
ws2812b_t
ws2812b = {
.inited =
false
,
.led_counts =
1
,
};
color_t
RED = {
255
,
0
,
0
};
color_t
GREEN = {
0
,
255
,
0
};
color_t
BLUE = {
0
,
0
,
255
};
void
ws2812b_init
(
ws2812b_t
*ws2812b)
{
if
(ws2812b ==
NULL
) {
return
;
}
// 分配24位颜色数据内存
ws2812b->color_datas = (
uint8_t
*)
malloc
(
ws2812b->led_counts * BITS_PER_LED_COLOR +
32
);
// 分配LED颜色数据内存
ws2812b->led_colors = (
color_t
*)
malloc
(
sizeof
(
color_t
) * ws2812b->led_counts);
if
(ws2812b->color_datas && ws2812b->led_colors) {
ws2812b->inited =
true
;
ws2812b->color_data_size = ws2812b->led_counts * BITS_PER_LED_COLOR;
//+32
}
else
{
ws2812b->inited =
false
;
}
}
// 生成24位颜色数据序列
void
__build_led_color_data(
ws2812b_t
*ws2812b)
{
for
(
int
i =
0
; i < ws2812b->led_counts; i++) {
uint8_t
m =
0b10000000
;
for
(
int
b =
0
; b <
8
; b++) {
ws2812b->color_datas[BITS_PER_LED_COLOR * i + b] =
ws2812b->led_colors[i].g & m ? SPI_NEO1 : SPI_NEO0;
m >>=
1u
;
}
m =
0b10000000
;
for
(
int
b =
0
; b <
8
; b++) {
ws2812b->color_datas[BITS_PER_LED_COLOR * i + b +
8
] =
ws2812b->led_colors[i].r & m ? SPI_NEO1 : SPI_NEO0;
m >>=
1u
;
}
m =
0b10000000
;
for
(
int
b =
0
; b <
8
; b++) {
ws2812b->color_datas[BITS_PER_LED_COLOR * i + b +
16
] =
ws2812b->led_colors[i].b & m ? SPI_NEO1 : SPI_NEO0;
m >>=
1u
;
}
}
}
void
ws2812b_set_color
(
ws2812b_t
*ws2812b,
uint16_t
index,
color_t
color)
{
if
(index >= ws2812b->led_counts && ws2812b->inited) {
return
;
}
ws2812b->led_colors[index] = color;
}
void
ws2812b_show
(
ws2812b_t
*ws2812b)
{
if
(!ws2812b->inited) {
return
;
}
__build_led_color_data(ws2812b);
//hosal_spi_send(&spi, ws2812b->color_datas,ws2812b->color_data_size,1000);
printf
(
"countsize=%d\r\n"
, ws2812b->color_data_size);
for
(
int
i =
0
; i < ws2812b->color_data_size; i++) {
bflb_spi_poll_send(spi0, ws2812b->color_datas[i]);
}
}
void
board_spi0_gpiomy_init
()
{
struct
bflb_device_s
*
gpio
;
gpio = bflb_device_get_by_name(
"gpio"
);
bflb_gpio_init(gpio, GPIO_PIN_3, GPIO_FUNC_SPI0 | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1);
bflb_gpio_init(gpio, GPIO_PIN_4, GPIO_FUNC_SPI0 | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1);
bflb_gpio_init(gpio, GPIO_PIN_5, GPIO_FUNC_SPI0 | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1);
}
/* poll test func */
/* main */
int
main
(
void
)
{
board_init();
board_spi0_gpiomy_init();
struct
bflb_spi_config_s
spi_cfg
=
{
#
if
(SPI_CASE_SELECT == SPI_MASTER_CASE)
.freq =
8
*
1000
*
1000
,
.role = SPI_ROLE_MASTER,
#
else
.freq =
32
*
1000
*
1000
,
.role = SPI_ROLE_SLAVE,
#
endif
.mode = SPI_MODE3,
.data_width = SPI_DATA_WIDTH_8BIT,
.bit_order = SPI_BIT_MSB,
.byte_order = SPI_BYTE_LSB,
.tx_fifo_threshold =
0
,
.rx_fifo_threshold =
0
,
};
spi0 = bflb_device_get_by_name(
"spi0"
);
bflb_spi_init(spi0, &spi_cfg);
//uint32_t mess = 0;
printf
(
"start\r\n"
);
// bflb_spi_poll_send(spi0, mess);
ws2812b_init(&ws2812b);
printf
(
"ws2812b task start...\r\n"
);
while
(
1
) {
// bflb_mtimer_delay_ms(2000); /* delay for slave device prepare ok */
// bflb_spi_poll_send(spi0, mess);
// mess++;
for
(
size_t
i =
0
; i < ws2812b.led_counts; i++) {
ws2812b_set_color(&ws2812b, i, RED);
}
ws2812b_show(&ws2812b);
bflb_mtimer_delay_ms(
1000
);
for
(
size_t
i =
0
; i < ws2812b.led_counts; i++) {
ws2812b_set_color(&ws2812b, i, GREEN);
}
ws2812b_show(&ws2812b);
bflb_mtimer_delay_ms(
1000
);
for
(
size_t
i =
0
; i < ws2812b.led_counts; i++) {
ws2812b_set_color(&ws2812b, i, BLUE);
}
ws2812b_show(&ws2812b);
bflb_mtimer_delay_ms(
1000
);
}
}Compile and flash
Click to expand: make CHIP=BL602 BOARD=bl602dk
make CHIP=BL602 BOARD=bl602dkClick to expand: make flash CHIP=BL602 COMX=/d
make flash CHIP=BL602 COMX=/dev/ttyUSB0Hey, guess what — the LED on the WB2-12F-kit is an RGB5050 LED that isn't controlled by a single-wire protocol but directly by high/low levels, so the only way is to use a logic analyzer to check whether the control logic is correct.


The WS2812 protocol has already been decoded.
ok
Miscellaneous
Actually, I drew a WB2-12f test board before, for driving an IIC device, and it happened to have a WS2812 LED connected to IO5. I wanted to flash the program above onto it for verification, but it just wouldn't flash (with the Ai-Thinker-WB2 SDK flashing works fine) — it's completely topsy-turvy. I told you, Mercury is in retrograde.
One more question: I don't understand how the Bouffalo SDK's SPI specifies GPIO pins for function pins. I'd like an expert in the comments to answer.

