You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

271 lines
6.1 KiB

#include <stddef.h>
#include <assert.h>
#include "stm32f4xx.h"
#include "gpio.h"
#include "spi.h"
struct spi_device {
SPI_TypeDef *base;
int apb;
uint32_t rcc;
SPI_InitTypeDef conf;
uint32_t cs;
void (*setup)(struct spi_device *);
};
/* query APB1 clocks */
static uint32_t __PCLK1()
{
RCC_ClocksTypeDef clks;
RCC_GetClocksFreq(&clks);
return clks.PCLK1_Frequency;
}
static uint16_t __clk_prescale(int bps)
{
uint16_t prescale = SPI_BaudRatePrescaler_4;
uint32_t clk;
clk = __PCLK1();
if (bps >= (clk / 2)) {
prescale = SPI_BaudRatePrescaler_2;
} else if ((bps >= (clk / 4)) && (bps < (clk / 2))) {
prescale = SPI_BaudRatePrescaler_4;
} else if ((bps >= (clk / 8)) && (bps < (clk / 4))) {
prescale = SPI_BaudRatePrescaler_8;
} else if ((bps >= (clk / 16)) && (bps < (clk / 8))) {
prescale = SPI_BaudRatePrescaler_16;
} else if ((bps >= (clk / 32)) && (bps < (clk / 16))) {
prescale = SPI_BaudRatePrescaler_32;
} else if ((bps >= (clk / 64)) && (bps < (clk / 32))) {
prescale = SPI_BaudRatePrescaler_64;
} else if ((bps >= (clk / 128)) && (bps < (clk / 64))) {
prescale = SPI_BaudRatePrescaler_128;
} else if (bps < (clk / 128)) {
prescale = SPI_BaudRatePrescaler_256;
}
return prescale;
}
void spi_set_speed(spi_t spi, int bps)
{
if (bps > 0) {
SPI_Cmd(spi->base, DISABLE);
spi->conf.SPI_BaudRatePrescaler = __clk_prescale(bps);
SPI_Init(spi->base, &spi->conf);
SPI_Cmd(spi->base, ENABLE);
}
}
int spi_setup(spi_t spi, uint32_t cs, int mode, int bps)
{
uint16_t prescale = SPI_BaudRatePrescaler_4;
if (spi->setup)
spi->setup(spi);
spi->cs = cs;
if (cs > 0) {
gpio_init(spi->cs, GPIO_OUTPUT | GPIO_FLAG_PD | GPIO_FLAG_PU | GPIO_SPEED_FAST);
gpio_set(spi->cs);
}
switch (spi->apb) {
case 1:
RCC_APB1PeriphClockCmd(spi->rcc, ENABLE);
break;
case 2:
RCC_APB2PeriphClockCmd(spi->rcc, ENABLE);
break;
}
SPI_DeInit(spi->base);
SPI_StructInit(&spi->conf);
spi->conf.SPI_Mode = SPI_Mode_Master;
if (bps > 0) {
prescale = __clk_prescale(bps);
}
spi->conf.SPI_BaudRatePrescaler = prescale;
if (mode & 0x1) {
spi->conf.SPI_CPHA = SPI_CPHA_2Edge;
} else {
spi->conf.SPI_CPHA = SPI_CPHA_1Edge;
}
if (mode & 0x2) {
spi->conf.SPI_CPOL = SPI_CPOL_High;
} else {
spi->conf.SPI_CPOL = SPI_CPOL_Low;
}
spi->conf.SPI_NSS = SPI_NSS_Soft;
spi->conf.SPI_CRCPolynomial = 7;
SPI_Init(spi->base, &spi->conf);
SPI_Cmd(spi->base, ENABLE);
return 0;
}
void spi_set_mode(spi_t spi, int mode)
{
if (mode & 0x1) {
spi->conf.SPI_CPHA = SPI_CPHA_2Edge;
} else {
spi->conf.SPI_CPHA = SPI_CPHA_1Edge;
}
if (mode & 0x2) {
spi->conf.SPI_CPOL = SPI_CPOL_High;
} else {
spi->conf.SPI_CPOL = SPI_CPOL_Low;
}
SPI_Cmd(spi->base, DISABLE);
SPI_Init(spi->base, &spi->conf);
SPI_Cmd(spi->base, ENABLE);
}
void spi_close(spi_t spi)
{
switch (spi->apb) {
case 1:
RCC_APB1PeriphClockCmd(spi->rcc, DISABLE);
break;
case 2:
RCC_APB2PeriphClockCmd(spi->rcc, DISABLE);
break;
}
SPI_Cmd(spi->base, DISABLE);
SPI_DeInit(spi->base);
}
void spi_cs(spi_t spi, int cs)
{
gpio_write(spi->cs, cs);
}
uint8_t spi_txrx(spi_t spi, uint8_t data)
{
/*!< Loop while DR register in not empty */
while (SPI_I2S_GetFlagStatus(spi->base, SPI_I2S_FLAG_TXE) == RESET);
/*!< Send byte through the SPI1 peripheral */
SPI_I2S_SendData(spi->base, data);
/*!< Wait to receive a byte */
while (SPI_I2S_GetFlagStatus(spi->base, SPI_I2S_FLAG_RXNE) == RESET);
/*!< Return the byte read from the SPI bus */
return SPI_I2S_ReceiveData(spi->base);
}
uint8_t spi_send_byte(spi_t spi, uint8_t data)
{
uint8_t dt;
gpio_clear(spi->cs);
dt = spi_txrx(spi, data);
gpio_set(spi->cs);
return (dt);
}
int spi_transfer(spi_t spi, const uint8_t *tx, uint8_t *rx, int len)
{
int got = 0;
uint8_t dt;
const uint8_t *end = tx + len;
if (!tx) {
return -1;
}
if (rx)
got = 1;
gpio_clear(spi->cs);
while (tx < end) {
dt = spi_txrx(spi, *tx++);
if (got)
*rx++ = dt;
}
gpio_set(spi->cs);
return (len);
}
#if (TARGET_HAS_SPI1)
void __attribute__((weak)) target_spi1_setup()
{
GPIO_InitTypeDef conf;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //开启时钟
conf.GPIO_Mode = GPIO_Mode_AF; //引脚初始化
conf.GPIO_OType = GPIO_OType_PP;
conf.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
conf.GPIO_PuPd = GPIO_PuPd_UP;
conf.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &conf);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
}
static void spi1_setup(struct spi_device *spi)
{
target_spi1_setup();
}
struct spi_device spi0 = {
.base = SPI1,
.apb = 2,
.rcc = RCC_APB2Periph_SPI1,
.cs = 0,
.setup = spi1_setup
};
#endif
#if (TARGET_HAS_SPI2)
void __attribute__((weak)) target_spi2_setup()
{
GPIO_InitTypeDef conf;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); //开启时钟
conf.GPIO_Mode = GPIO_Mode_AF; //引脚初始化
conf.GPIO_OType = GPIO_OType_PP;
conf.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
conf.GPIO_PuPd = GPIO_PuPd_UP;
conf.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &conf);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource13, GPIO_AF_SPI2); //打开引脚的复用功能
GPIO_PinAFConfig(GPIOB,GPIO_PinSource14, GPIO_AF_SPI2);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource15, GPIO_AF_SPI2);
}
static void spi2_setup(struct spi_device *spi)
{
target_spi2_setup();
}
struct spi_device spi1 = {
.base = SPI2,
.apb = 1,
.rcc = RCC_APB1Periph_SPI2,
.cs = 0,
.setup = spi2_setup
};
#endif