工程文件参考——CubeMX+LL库+SPI主机 阻塞式通用库


前言

SPI,想了很久没想明白其DMA或者IT比较好用的方法,可能之后也会写一个
我个人使用场景大数据流不多,如果是大批量数据交互自然是DMA更好用,但考虑到多从机通讯,感觉还是阻塞式更灵活一些,毕竟大部分通讯片选延时1us,但一个数据传进去也就不到1us。
以后有时间改个DMA或者IT升级版

spix = new_SPI_Driver(SPIx_Port, CS_GPIOx, CS_Pin);//完成初始化
RxData = spix->tr16(spix, TxData);//数据传递
spix->cs_l(spix);;//CS拉低
spix->cs_h(spix);;//CS拉搞

SPI的多从机任务可以自己挂CS,并在上层实现数据流读取
上层实现可以参考工程文件参考——ADS1118多从机驱动(base on spi_driver)
需要8位传输的可以自己改


CubeMX配置

开了就能用,注意匹配下,数据长度,8bit还是16bit。MSB是先高位还是先低位,以及CPOL与CPHA的设置。NSS硬件片选没什么用,包括从机的NSS,感觉不如外部触发中断。
在这里插入图片描述
CS直接开GPIO,根据自己从机数量需求设计
在这里插入图片描述

SPI驱动实现

spi_driver.h

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __SPI_DRIVER_H
#define __SPI_DRIVER_H
/* =================================================================================
File name:       __SPI_DRIVER_H
Author: Mr.NoFish
===================================================================================*/

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/

#include "main.h"

#include "spi.h"

typedef struct SPI_Driver_ SPI_Driver;

typedef void (*SPIfptrCS_H)(SPI_Driver*);
typedef void (*SPIfptrCS_L)(SPI_Driver*);
typedef uint16_t (*SPIfptrTranRecv16)(SPI_Driver*, uint16_t);
typedef void (*SPIfptrTran16)(SPI_Driver*, uint16_t);

struct SPI_Driver_
{
	SPI_TypeDef* SPIx;
	GPIO_TypeDef* CS_GPIOx;
	uint32_t CS_Pin;
	
	uint16_t TxData;
	uint16_t RxData;
	
	SPIfptrCS_H cs_h;
	SPIfptrCS_L cs_l;
	SPIfptrTranRecv16 tr16;
	SPIfptrTran16 tran16;
};


SPI_Driver* new_SPI_Driver(SPI_TypeDef* SPIx_Port, GPIO_TypeDef* CS_GPIOx, uint32_t CS_Pin);

void spi_chip_select_set(SPI_Driver* const pSPIObj);
void spi_chip_select_reset(SPI_Driver* const pSPIObj);
void spi_transmit_16(SPI_Driver* const pSPIObj, uint16_t TxData);
uint16_t spi_transmit_receive_16(SPI_Driver* const pSPIObj, uint16_t TxData);
#endif


spi_driver.c

/* =================================================================================
File name:       __SPI_DRIVER_C
Author: Mr.NoFish
===================================================================================*/
#include "spi_driver.h"

SPI_Driver* new_SPI_Driver(SPI_TypeDef* SPIx_Port, GPIO_TypeDef* CS_GPIOx, uint32_t CS_Pin)
{
	SPI_Driver* pObj = NULL;
	uint8_t i = 0;
	pObj = (SPI_Driver*)malloc(sizeof(SPI_Driver));
	if (pObj == NULL)
	{
		printf("WARN: SPI_Driver initialization failed.\r\n");
		return NULL;
	}
	

	pObj->SPIx = SPIx_Port;
	pObj->CS_GPIOx = CS_GPIOx;
	pObj->CS_Pin = CS_Pin;

	pObj->cs_h = spi_chip_select_set;
	pObj->cs_l = spi_chip_select_reset;
	pObj->tran16 = spi_transmit_16;
	pObj->tr16 = spi_transmit_receive_16;
	
	pObj->cs_h(pObj);
	//LL_SPI_Enable(pObj->SPIx);
	printf("INFO: SPI_Driver initialization succeeded.\r\n");
	return pObj;			
}

void spi_chip_select_set(SPI_Driver* const pSPIObj)
{
	LL_GPIO_SetOutputPin(pSPIObj->CS_GPIOx, pSPIObj->CS_Pin);
}

void spi_chip_select_reset(SPI_Driver* const pSPIObj)
{
	LL_GPIO_ResetOutputPin(pSPIObj->CS_GPIOx, pSPIObj->CS_Pin);
}

void spi_transmit_16(SPI_Driver* const pSPIObj, uint16_t TxData)
{	
	pSPIObj->TxData = TxData;
	
	while(!LL_SPI_IsActiveFlag_TXE(pSPIObj->SPIx));
	LL_SPI_TransmitData16(pSPIObj->SPIx, pSPIObj->TxData);
}

uint16_t spi_transmit_receive_16(SPI_Driver* const pSPIObj, uint16_t TxData)
{	
	pSPIObj->TxData = TxData;
	
	while(!LL_SPI_IsActiveFlag_TXE(pSPIObj->SPIx));
	LL_SPI_TransmitData16(pSPIObj->SPIx, pSPIObj->TxData);
	
	while(LL_SPI_IsActiveFlag_BSY(pSPIObj->SPIx));
	while(!LL_SPI_IsActiveFlag_RXNE(pSPIObj->SPIx));
	pSPIObj->RxData =  LL_SPI_ReceiveData16(pSPIObj->SPIx);
		
  return pSPIObj->RxData;
}

额外的接口补充

LL_SPI_Enable(SPIx);别忘记自己加一下,但留意别在初始化之前Enable。
SPI每个设备的实现方式都不同,所以需要根据数据手册进一步实现上层设计。
这个库设计用来提供给多从机控制,一些范例的应用可以参考如下文章。
工程文件参考——ADS1118多从机驱动(base on spi_driver)

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值