最近学了stm32,转到学harmonyos开发板,网上关于H3861的资料也很少,分享一下自己学习的案例。
首先,我下载的源码是默认没有开启SPI的,编译的时候会报错,类似于这样的错误,
要使用SPI功能的话还需要在这个文件当中开启SPI的功能,
如果要开启其他的功能也是类似的方法,在这个文件随便哪个地方输入这行代码
CONFIG_SPI_SUPPORT =y
要开启其他的功能就把中间的SPI更换一下就好。
和SPI相关的函数
和SPI相关的函数都在hi_spi.h这个头文件里面,调用的时候参数类型要对应上就可以正常使用,hi_spi_slave_write()和hi_spi_slave_read()是在SPI初始化时候作为从机时的向主机写入和读取数据的函数,我这里是做主机使用,所以不涉及这两个函数,hi_spi_host_write()和hi_spi_host_read()这两个函数是作为主机,且为半双工时候的向从机写入和读取数据的函数,还有hi_spi_host_writeread(),作为主机且工作于全双工的读写数据的函数。当让还有最熟悉的hi_spi_init(),hi_spi_deinit()初始化和去初始化函数,其余的函数可以慢慢的去研究一下,不过单纯的使用SPI进行数据传输,这些函数完全够了。
代码部分
首先是SPI初始化部分,我尽量每行都给注释,少些废话。
void W25Q64_Init(void)
{
hi_u32 ret;
int i = 1;
hi_spi_idx id = HI_SPI_ID_0;//我连接的是SPI0,具体看接线图
hi_spi_deinit(id);//先去初始化
hi_spi_cfg_basic_info spi_cfg_basic_info;定义一个包含spi初始化的参数信息的结构体
spi_cfg_basic_info.cpha = 1;
spi_cfg_basic_info.cpol = 1;//这两行把spi设置为工作在模式1
spi_cfg_basic_info.data_width = HI_SPI_CFG_DATA_WIDTH_E_8BIT;//传输数据的宽度
spi_cfg_basic_info.endian = 0;//首先发送或接收的是最高有效位
spi_cfg_basic_info.fram_mode = 0;//传输途中的时钟极性
spi_cfg_basic_info.freq = 9 * 800 * 1000;//频率
hi_spi_cfg_init_param spi_init_param = {0};//这个是配置主机还是从机的结构体
spi_init_param.is_slave = 0;//0为主机,1为从机
ret = hi_spi_init(id, spi_init_param, &spi_cfg_basic_info); // 初始化
if (ret != HI_ERR_SUCCESS) {
printf("SPI init fail! %x ", ret);
}//这个是打印到串口看有没有初始化成功的
hi_io_set_func(HI_IO_NAME_GPIO_10,HI_IO_FUNC_GPIO_10_SPI0_CK);//设置gpio_10为clk模式
hi_io_set_func(HI_IO_NAME_GPIO_11,HI_IO_FUNC_GPIO_11_SPI0_RXD);//设置gpio_11为MISO模式
hi_io_set_func(HI_IO_NAME_GPIO_9,HI_IO_FUNC_GPIO_9_SPI0_TXD);//设置gpio_10为MOSI模式
hi_io_set_func(HI_IO_NAME_GPIO_12,HI_IO_FUNC_GPIO_12_GPIO);
hi_gpio_set_dir(HI_IO_NAME_GPIO_12,HI_GPIO_DIR_OUT);
hi_gpio_set_ouput_val(HI_IO_NAME_GPIO_12,HI_GPIO_VALUE1);
hi_io_set_driver_strength(HI_IO_NAME_GPIO_12, HI_IO_DRIVER_STRENGTH_2);//这四行是设置gpio_12为NSS模式
}
然后是读取W25Q64
void W25Q64_ReadID(void)
{
int ret=0;
unsigned char resultdata;
unsigned char writebuff[1] = {W25Q64_JEDEC_ID|test_num};
unsigned char readbuff[4];
hi_gpio_set_ouput_val(HI_IO_NAME_GPIO_12,HI_GPIO_VALUE0);; // 使能SPI传输
ret = memset_s(readbuff, 4, 0x00, 4);//这个是创建一个缓冲区,长度为4,全部用0填充
if (ret != EOK) {
printf("memcpy_s failed, err = %d\n", ret);
}
ret = hi_spi_host_writeread(id, &writebuff, readbuff, 4);//全双工传输
if (ret != HI_ERR_SUCCESS) {
printf("spi read[%02X] fail! %x ", readbuff[0], ret);
}
printf("readresult:[%02X][%02X][%02X]",readbuff[1],readbuff[2],readbuff[3]);
hi_gpio_set_ouput_val(HI_IO_NAME_GPIO_12,HI_GPIO_VALUE1);; // 禁止SPI传输
}
最后放一个整体的代码,还有一个BUILD.gn文件记得去做一些修改
#include "ohos_init.h"
#include <stdio.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "W25Q64_spi.h"
#include <hi_spi.h>
osThreadId_t Task1_ID = 0; // 任务1 ID
#define TASK_STACK_SIZE 1024
#define TASK_DELAY_TIME 5 // s
void GyroTask(void)
{
W25Q64_Init();
W25Q64_ReadID();
}
static void GyroControlTask(void)
{
osThreadAttr_t attr;
attr.name = "GyroCntrolDemo";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 5; // 堆栈大小为1024 stack size 1024 * 5
attr.priority = 25; // 优先级25
if (osThreadNew((osThreadFunc_t)GyroTask, NULL, &attr) == NULL) {
printf("[GyroExample] Failed to create GyroTask!\n");
}
}
APP_FEATURE_INIT(GyroControlTask);
#include <stdio.h>
#include <hi_io.h>
#include <hi_early_debug.h>
#include <hi_task.h>
#include <hi_types_base.h>
#include <hi_spi.h>
#include <hi_time.h>
#include <../platform/drivers/spi/spi.h>
#include <hi_gpio.h>
#include "hi_io.h"
#define W25Q64_JEDEC_ID 0x1F
#define W25Q64_DUMMY_BYTE 0xFF
#define test_num 0x80
void W25Q64_Init(void)
{
hi_u32 ret;
int i = 1;
hi_spi_idx id = HI_SPI_ID_0;
hi_spi_deinit(id); /* if wake_up from deep sleep, should deinit first */
hi_spi_cfg_basic_info spi_cfg_basic_info;
spi_cfg_basic_info.cpha = 1;
spi_cfg_basic_info.cpol = 1;
spi_cfg_basic_info.data_width = HI_SPI_CFG_DATA_WIDTH_E_8BIT;
spi_cfg_basic_info.endian = 0;
spi_cfg_basic_info.fram_mode = 0;
spi_cfg_basic_info.freq = 9 * 800 * 1000;
hi_spi_cfg_init_param spi_init_param = {0};
spi_init_param.is_slave = 0;
ret = hi_spi_init(id, spi_init_param, &spi_cfg_basic_info); // 基本参数配置
if (ret != HI_ERR_SUCCESS) {
printf("SPI init fail! %x ", ret);
}
hi_io_set_func(HI_IO_NAME_GPIO_10,HI_IO_FUNC_GPIO_10_SPI0_CK);
hi_io_set_func(HI_IO_NAME_GPIO_11,HI_IO_FUNC_GPIO_11_SPI0_RXD);
hi_io_set_func(HI_IO_NAME_GPIO_9,HI_IO_FUNC_GPIO_9_SPI0_TXD);
// IoSetFunc(IOT_IO_NAME_GPIO_11, IOT_IO_FUNC_GPIO_11_SPI0_RXD); // SPI MISO 数据从从发到主
// IoSetFunc(IOT_IO_NAME_GPIO_9, IOT_IO_FUNC_GPIO_9_SPI0_TXD); // SPI MOSI 数据从主发到从
hi_io_set_func(HI_IO_NAME_GPIO_12,HI_IO_FUNC_GPIO_12_GPIO);
hi_gpio_set_dir(HI_IO_NAME_GPIO_12,HI_GPIO_DIR_OUT);
hi_gpio_set_ouput_val(HI_IO_NAME_GPIO_12,HI_GPIO_VALUE1);
/* IoSetFunc(IOT_IO_NAME_GPIO_12, IOT_IO_FUNC_GPIO_12_GPIO); // GYROcs片段
IoTGpioSetDir(IOT_IO_NAME_GPIO_12, IOT_GPIO_DIR_OUT);
IoTGpioSetOutputVal(IOT_IO_NAME_GPIO_12, IOT_GPIO_VALUE1); */
hi_io_set_driver_strength(HI_IO_NAME_GPIO_12, HI_IO_DRIVER_STRENGTH_2);
}
void W25Q64_ReadID(hi_spi_idx id, unsigned char addrdata, unsigned char writedata, unsigned int writelen)
{
int ret=0;
unsigned char resultdata;
unsigned char writebuff[1] = {W25Q64_JEDEC_ID|test_num};
unsigned char readbuff[4];
hi_gpio_set_ouput_val(HI_IO_NAME_GPIO_12,HI_GPIO_VALUE0);; // 使能SPI传输
ret = memset_s(readbuff, 4, 0x00, 4);
if (ret != EOK) {
printf("memcpy_s failed, err = %d\n", ret);
}
ret = hi_spi_host_writeread(id, &writebuff, readbuff, 4);
if (ret != HI_ERR_SUCCESS) {
printf("spi read[%02X] fail! %x ", readbuff[0], ret);
}
//resultdata = readbuff[1];
printf("readresult:[%02X][%02X][%02X]",readbuff[1],readbuff[2],readbuff[3]);
hi_gpio_set_ouput_val(HI_IO_NAME_GPIO_12,HI_GPIO_VALUE1);; // 禁止SPI传输
}