#ifndef __SPI_H
#define __SPI_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stm32f10x_spi.h>
#include <stdint.h>
void SPI1_SendRecvData(const uint8_t *send_data, uint8_t *recv_data, uint16_t len);
void SPI1_SendData(const uint8_t *data, uint16_t len);
void SPI1_RecvData(uint8_t *data, uint16_t len);
#ifdef __cplusplus
}
#endif
#endif /* __SPI_H */
#include "spi.h"
#include <stm32f10x_gpio.h>
#include <stm32f10x_spi.h>
#include <stdint.h>
/**
* @brief SPI1 时序开始
*
*/
static inline void SPI1_Start(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_4); // 拉低NSS
}
/**
* @brief SPI1 时序结束
*
*/
static inline void SPI1_Stop(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_4); // 拉高NSS
}
/**
* @brief SPI1 交换一个字节
*
* @param byte 待交换的字节
* @return uint8_t 交换后的字节
*/
static uint8_t SPI1_SwapByte(uint8_t byte)
{
// 1. 等待 TXE
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET);
// 2. 发送数据
SPI_I2S_SendData(SPI1, byte);
// 3. 等待 RXNE
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET);
// 4. 读取 DR
return SPI_I2S_ReceiveData(SPI1);
}
/**
* @brief SPI1 发送一个字节
*
* @param byte 待发送的字节
*/
static void SPI1_SendByte(uint8_t byte)
{
SPI1_SwapByte(byte);
}
/**
* @brief SPI1 接收一个字节
*
* @return uint8_t 接收到的字节
*/
static uint8_t SPI1_RecvByte(void)
{
return SPI1_SwapByte(0xFF);
}
/**
* @brief SPI1 发送和接收数据
*
* @param send_data 待发送的数据
* @param recv_data 接收到的数据
* @param len 发送和接收的字节数
*/
void SPI1_SendRecvData(const uint8_t *send_data, uint8_t *recv_data, uint16_t len)
{
SPI1_Start();
for (uint16_t i = 0; i < len; i++) {
recv_data[i] = SPI1_SwapByte(send_data[i]);
}
SPI1_Stop();
}
/**
* @brief SPI1 发送数据
*
* @param data 待发送的数据
* @param len 发送的字节数
*/
void SPI1_SendData(const uint8_t *data, uint16_t len)
{
SPI1_Start();
for (uint16_t i = 0; i < len; i++) {
SPI1_SendByte(data[i]);
}
SPI1_Stop();
}
/**
* @brief SPI1 接收数据
*
* @param data 接收到的数据
* @param len 接收的字节数
*/
void SPI1_RecvData(uint8_t *data, uint16_t len)
{
SPI1_Start();
for (uint16_t i = 0; i < len; i++) {
data[i] = SPI1_RecvByte();
}
SPI1_Stop();
}
enum class Status {
Ok,
Error,
Busy,
Timeout,
};
#pragma once
#include <stm32f10x.h>
#include <cstddef>
#include <cstdint>
#include <span>
#include "main.hpp"
class SPI_Handle
{
public:
static constexpr uint32_t DefaultTimeout = 1000;
SPI_Handle(SPI_TypeDef *spi_x = nullptr);
operator bool() const;
void set_spi_handle(SPI_TypeDef *spi_x);
void set_cs_pin(GPIO_TypeDef *port, uint16_t pin);
void set_timeout(uint32_t Timeout);
auto spi_handle() const;
auto timeout() const;
auto cs_port() const;
auto cs_pin() const;
void Start();
void Stop();
Status SPI_TransmitReceive(uint8_t send_byte, uint8_t &receive_byte);
Status Transmit(uint8_t send_byte);
Status Receive(uint8_t &receive_byte);
Status SPI_TransmitReceive(std::span<const uint8_t> transmit_data, std::span<uint8_t> receive_buffer);
Status Transmit(std::span<const uint8_t> transmit_data);
Status Receive(std::span<uint8_t> receive_buffer);
protected:
SPI_TypeDef *spi_x_;
GPIO_TypeDef *cs_port_;
uint16_t cs_pin_;
uint32_t timeout_;
Status SPI_WaitFlagStatus(uint16_t SPI_I2S_FLAG);
Status SPI_SwapByte(uint8_t send_byte, uint8_t &receive_byte);
};
#include "spi_handle.hpp"
#include <stm32f10x.h>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <ranges>
#include <span>
#include "main.hpp"
SPI_Handle::SPI_Handle(SPI_TypeDef *spi_x)
: spi_x_(spi_x),
cs_port_(nullptr), cs_pin_(0),
timeout_(Defaulttimeout)
{
}
SPI_Handle::operator bool() const
{
return this->spi_x_ != nullptr and
this->cs_port_ != nullptr and
this->cs_pin_ != 0;
}
void SPI_Handle::set_spi_handle(SPI_TypeDef *spi_x) { this->spi_x_ = spi_x; }
void SPI_Handle::set_cs_pin(GPIO_TypeDef *port, uint16_t pin)
{
this->cs_port_ = port;
this->cs_pin_ = pin;
}
void SPI_Handle::set_timeout(uint32_t timeout) { this->timeout_ = timeout; }
auto SPI_Handle::spi_handle() const { return this->spi_x_; }
auto SPI_Handle::timeout() const { return this->timeout_; }
auto SPI_Handle::cs_port() const { return this->cs_port_; }
auto SPI_Handle::cs_pin() const { return this->cs_pin_; }
void SPI_Handle::Start()
{
if (this->cs_port_ != nullptr and this->cs_pin_ != 0) {
GPIO_ResetBits(this->cs_port_, this->cs_pin_);
}
}
void SPI_Handle::Stop()
{
if (this->cs_port_ != nullptr and this->cs_pin_ != 0) {
GPIO_SetBits(this->cs_port_, this->cs_pin_);
}
}
Status SPI_Handle::SPI_TransmitReceive(uint8_t send_byte, uint8_t &receive_byte)
{
return this->SPI_TransmitReceive(
std::span<const uint8_t>{&send_byte, 1},
std::span<uint8_t>{&receive_byte, 1});
}
Status SPI_Handle::Transmit(uint8_t send_byte)
{
return this->Transmit(std::span<const uint8_t>{&send_byte, 1});
}
Status SPI_Handle::Receive(uint8_t &receive_byte)
{
return this->Receive(std::span<uint8_t>{&receive_byte, 1});
}
Status SPI_Handle::SPI_TransmitReceive(std::span<const uint8_t> transmit_data, std::span<uint8_t> receive_buffer)
{
if (transmit_data.size() != receive_buffer.size()) {
return Status::Error;
}
for (auto [send, receive] : std::ranges::views::zip(transmit_data, receive_buffer)) {
auto ret = this->SPI_SwapByte(send, receive);
if (ret != Status::Ok) {
return ret;
}
}
return Status::Ok;
}
Status SPI_Handle::Transmit(std::span<const uint8_t> transmit_data)
{
static uint8_t dummy = 0xFF;
for (auto transmit_byte : transmit_data) {
auto ret = this->SPI_SwapByte(transmit_byte, dummy);
if (ret != Status::Ok) {
return ret;
}
}
return Status::Ok;
}
Status SPI_Handle::Receive(std::span<uint8_t> receive_buffer)
{
for (auto &receive_byte : receive_buffer) {
auto ret = this->SPI_SwapByte(0xFF, receive_byte);
if (ret != Status::Ok) {
return ret;
}
}
return Status::Ok;
}
Status SPI_Handle::SPI_WaitFlagStatus(uint16_t SPI_I2S_FLAG)
{
for (uint32_t i = 0; i < this->timeout_; i++) {
if (SPI_I2S_GetFlagStatus(this->spi_x_, SPI_I2S_FLAG) == SET) {
return Status::Ok;
}
}
return Status::timeout;
}
Status SPI_Handle::SPI_SwapByte(uint8_t send_byte, uint8_t &receive_byte)
{
auto ret = Status::Ok;
// 1. 等待 TXE
ret = this->SPI_WaitFlagStatus(SPI_I2S_FLAG_TXE);
if (ret != Status::Ok) {
return ret;
}
// 2. 发送数据
SPI_I2S_SendData(this->spi_x_, send_byte);
// 3. 等待 RXNE
ret = this->SPI_WaitFlagStatus(SPI_I2S_FLAG_RXNE);
if (ret != Status::Ok) {
return ret;
}
// 4. 读取 DR
receive_byte = SPI_I2S_ReceiveData(this->spi_x_);
return ret;
}