STM32通过SPI启用ADXL345



我正在尝试连接到ADXL345,它位于另一个连接了GPIO的板上(PA5、PA6、PA7、PA12(。此外,我正在使用[sigrok][1]中的PulseViewer软件显示,传感器未启用,但功能似乎是正确的。我缺了什么吗?

#include "stm32l0xx.h"
#include "pmi_stddefs.h"
int32_t spi_init_adxl345(void)
{
/* enable SPI1 clock */
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
/* Enable clock for port A */
//RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
RCC->IOPENR |= RCC_IOPENR_IOPAEN;
/* CPHA at 1, CPOL at 1 */
SPI1->CR1 |= SPI_CR1_CPOL;
SPI1->CR1 |= SPI_CR1_CPHA;
/* enable master mode */
SPI1->CR1 |= SPI_CR1_MSTR;
/* baud rate Maximum (5MHZ ADXL = 011) */
// SPI1->CR1 &= ~SPI_CR1_BR_0;
// SPI1->CR1 |= SPI_CR1_BR_1;
// SPI1->CR1 |= SPI_CR1_BR_2;
SPI1->CR1 |= (SPI_CR1_BR_0)| (SPI_CR1_BR_1);
/* Internal Slave Select */    
/* soft. slave management */
SPI1->CR1 |= SPI_CR1_SSM;
/* select slave */
SPI1->CR1 |= SPI_CR1_SSI;
/* Frame Format MSB */
SPI1->CR1 &= ~SPI_CR1_LSBFIRST;
/* Receive only mode enable (0 = full-duplex (Transmit and receive)) */
SPI1->CR1 &= ~SPI_CR1_RXONLY;
/* Data frame format 8 */
SPI1->CR1 &= ~SPI_CR1_DFF;
//SPI1->CR2 = SPI_CR2_SSOE | SPI_CR2_RXNEIE;
SPI1->CR2 = 0;

/* Set AF,OUTPUT modes */
/* MISO AF*/
GPIOA->MODER &= ~GPIO_MODER_MODE6_0;
GPIOA->MODER |= GPIO_MODER_MODE6_1;
/* MOSI AF*/
GPIOA->MODER &= ~GPIO_MODER_MODE7_0;
GPIOA->MODER |= GPIO_MODER_MODE7_1;
/* SCLK AF*/
GPIOA->MODER &= ~GPIO_MODER_MODE5_0;
GPIOA->MODER |= GPIO_MODER_MODE5_1;
// TODO: PUPDR for PA4
// /* CS OUTPUT*/
GPIOA->MODER |= GPIO_MODER_MODE12_0;
GPIOA->MODER &= ~GPIO_MODER_MODE12_1;
/* Set I/O output speed (11=very high speed) */
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEED5;
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEED6;
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEED7;
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEED12;
/* Alternate Function Low Register 9.3.2*/
/* Pin 5,6,7 (in AFRL) */
GPIOA->AFR[0] |= GPIO_AFRL_AFSEL5;
GPIOA->AFR[0] |= GPIO_AFRL_AFSEL6;
GPIOA->AFR[0] |= GPIO_AFRL_AFSEL7;
return RC_SUCC;
}
int32_t spi_txrx (uint8_t *buf, uint32_t size)
{
GPIOA->BSRR |= GPIO_BSRR_BR_12;
/* TXE == 1 : the buffer is empty */
while (!(SPI1->SR & SPI_SR_TXE))
{
/* wait untill TXE is empty */
}
for (uint8_t i = 0; i < size; i++)
{
SPI1->DR = buf[i];
}
while (!(SPI1->SR & SPI_SR_TXE))
{
/* mandatory wait until TXE is set */
}
/* detect the end of a transfer */
while ((SPI1->SR & SPI_SR_BSY) != 0)
{
/* 1:busy, 0:not busy */
}
/* random noise */
uint8_t temp = SPI1->DR;
temp = SPI1->SR;

/* Disable sensor */
GPIOA->BSRR |= GPIO_BSRR_BS_12;
/* Diable the SPI <-- No need (Master in full-duplex or transmit 
only mode can finish any transaction when it stops providing data
for transmission. In this case, the clock stops after the last
data transaction.*/
return RC_SUCC;
}

我在这个问题上坚持了一段合理的时间,但我没有找到这个问题的答案。有什么想法吗?提前感谢![1] :https://www.sigrok.org/wiki/PulseView

  1. SPI nCS线路通常处于低激活状态,因此在板启动期间必须设置PA12。在您的代码中,始终选择ADXL345

GPIOA->BSRR |= GPIO_BSRR_BR_12;被重置(BR=位重置,BS=位设置(。此外,不需要使用|=运算符,因为BSRR是只写寄存器,设计用于在不使用读-修改-写序列的情况下更改端口状态。

  1. SPI_CR1寄存器中的SPE位未设置,SPI被禁用且不传输任何内容。当循环时CCD_ 7将卡在第二个CCD_。

  2. 与问题无关,但仍然-spi_txrx看起来是FIFO排序的,然而STM32L0系列SPI只有移位器和DR寄存器,并且交换必须在逐字节的基础上实现,或者使用DMA。也许这个代码适用于1或2字节长的传输,如果最后一个字节是有价值的,你甚至会得到正确的RX结果。但总的来说,这是一种代码气味。

在我看来,您为PA5、PA6和PA7选择了错误的备用函数。请注意,GPIO_AFRL_AFSEL5被定义为(0xFUL << GPIO_AFRL_AFSEL5_Pos),因此当您将其写入AFR[0]寄存器时,您选择的是备用函数15(不可用(。但是,您要为SPI1选择的是备用函数1。

你可以试试

GPIOA->AFR[0] |= (1 << GPIO_AFRL_AFSEL5_Pos);
GPIOA->AFR[0] |= (1 << GPIO_AFRL_AFSEL6_Pos);
GPIOA->AFR[0] |= (1 << GPIO_AFRL_AFSEL7_Pos);

最新更新