STM32 включить ADXL345 через SPI

#stm32 #spi

Вопрос:

Я пытаюсь подключиться к ADXL345, который находится на другой плате с подключенными к нему графическими процессорами (PA5, PA6, PA7, PA12). Кроме того, я использую PulseViewer из [sigrok] [1] Программное обеспечение показывает, что датчик НЕ включен, но, похоже, функциональность верна. Я чего-то не понимаю?

 #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 amp;= ~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 amp;= ~SPI_CR1_LSBFIRST;
/* Receive only mode enable (0 = full-duplex (Transmit and receive)) */
SPI1->CR1 amp;= ~SPI_CR1_RXONLY;
/* Data frame format 8 */
SPI1->CR1 amp;= ~SPI_CR1_DFF;

//SPI1->CR2 = SPI_CR2_SSOE | SPI_CR2_RXNEIE;
SPI1->CR2 = 0;


/* Set AF,OUTPUT modes */
/* MISO AF*/
GPIOA->MODER amp;= ~GPIO_MODER_MODE6_0;
GPIOA->MODER |= GPIO_MODER_MODE6_1;
/* MOSI AF*/
GPIOA->MODER amp;= ~GPIO_MODER_MODE7_0;
GPIOA->MODER |= GPIO_MODER_MODE7_1;
/* SCLK AF*/
GPIOA->MODER amp;= ~GPIO_MODER_MODE5_0;
GPIOA->MODER |= GPIO_MODER_MODE5_1;

// TODO: PUPDR for PA4
// /* CS OUTPUT*/
GPIOA->MODER |= GPIO_MODER_MODE12_0;
GPIOA->MODER amp;= ~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 amp; SPI_SR_TXE))
{
    /* wait untill TXE is empty */
}

for (uint8_t i = 0; i < size; i  )
{
    SPI1->DR = buf[i];
}

while (!(SPI1->SR amp; SPI_SR_TXE))
{
    /* mandatory wait until TXE is set */
}
/* detect the end of a transfer */
while ((SPI1->SR amp; 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. Как именно Sensor is NOT being enabled ? nCS / PA12 остается высоким / низким? Кстати, в spi_init_adxl345 функции PA12 должно быть установлено значение high, поскольку nCS активен на низком уровне.

2. Он остается низким. Я устанавливаю максимум PA12 с помощью GPIOA->BSRR |= GPIO_BSRR_BR_12;

Ответ №1:

  1. Линии NCS SPI обычно активны -низкий уровень, поэтому при запуске платы необходимо установить PA12. В вашем коде всегда выбран ADXL345.

Это GPIOA->BSRR |= GPIO_BSRR_BR_12; сброс ( BR = сброс бита, BS = набор бита). Кроме того, нет необходимости использовать |= оператор, поскольку BSRR — это регистр только для записи, предназначенный для изменения состояния порта без использования последовательности чтения-изменения-записи.

  1. SPE Бит в SPI_CR1 regisger не установлен, SPI отключен и ничего не передает. spi_txrx застрял бы во втором SPI_SR_TXE цикле while.
  2. Не имеет отношения к вопросу, но все же spi_txrx выглядит ориентированным на FIFO, однако SPI серии STM32L0 имеют только регистр переключения и DR, и обмен должен быть реализован на байтовой основе или с помощью DMA. Возможно, этот код будет работать для передачи длиной 1 или 2 байта, и вы даже получите правильный результат RX, если значение имеет только последний байт. Но, как правило, это запах кода.

Ответ №2:

Мне кажется, что вы выбираете неправильные альтернативные функции для 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);