Top.Mail.Ru
Уведомления
Очистить все

[Решено] Как при помощи CMSIS получить адрес WHO_AM_I с акселерометра LIS3DSH, который находится на STM32F407 Discovery?

 stm
(@stm)
Level 4

С HAL это делается так:

uint8_t address=0x8F; //Register address+read
uint8_t result;
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET); //Chip Select
HAL_SPI_Transmit(&hspi1,&address,1,1000);
HAL_SPI_Receive(&hspi1,&result,1,1000);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_SET); //Chip Select

А с CMSIS кажется надо 2 раза посылать данные и 2 раза получать.

sk

Пробовал так, не получается:

uint8_t address=0x8F; //Register address+read
uint8_t result;
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET); //Chip Select
SPI1->DR = address;
while((SPI1->SR & SPI_SR_BSY) != RESET);
result=SPI1->DR;
while((SPI1->SR & SPI_SR_BSY) != RESET);
SPI1->DR = 0;
while((SPI1->SR & SPI_SR_BSY) != RESET);
result=SPI1->DR;
while((SPI1->SR & SPI_SR_BSY) != RESET);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_SET); //Chip Select

Использовать флаг SPI_SR_TXE не получается, бит SPI_SR_TXE постоянно в нуле.

Цитата
Создатель темы Размещено : 20.10.2023 06:20
 stm
(@stm)
Level 4

Флаг SPI_SR_TXE принимает значение ноль после этой строчки

SPI1->DR = address;

И после этого флаг SPI_SR_TXE в единицу не становится.

ОтветитьЦитата
Создатель темы Размещено : 20.10.2023 06:48
Aveal
(@aveal)
Top level Admin

В целом механизм такой:

uint16_t SPI_TransmitReceive(uint16_t data)
{
  while(!(SPI1->SR & SPI_SR_TXE));
  SPI1->DR = data;
  while(!(SPI1->SR & SPI_SR_RXNE));
  return SPI1->DR;
}

У Эдуарда в посте есть описание обменных процедур через регистры - ссылка.

ОтветитьЦитата
Размещено : 20.10.2023 09:46
 stm
(@stm)
Level 4

SPI1->DR это 8 битный регистр. У меня так SPI1 настроен.
uint16_t data это 16 битная переменная.
Здесь идёт сохранение 16 битной переменной в 8 битный регистр. В моём случае.

SPI1->DR = data;

Наверное с 16 битным SPI1->DR легче, но у меня 8 битный.

Поэтому мне как то надо 2 раза по 8 бит передать и получить 8 битный адрес WHO_AM_I.

SPI1->DR = data;  //Здесь передаю адрес регистра WHO_AM_I
receive=SPI1->DR ;  //Получаю ненужные данные.
SPI1->DR = 0;  //Здесь посылаю пустые 8 бит
receive=SPI1->DR ;  //Здесь надо получить значение регистра WHO_AM_I
tim
ОтветитьЦитата
Создатель темы Размещено : 21.10.2023 01:42
 stm
(@stm)
Level 4

CR1->SPE не был включен.

ОтветитьЦитата
Создатель темы Размещено : 21.10.2023 03:16
 stm
(@stm)
Level 4
while(!(SPI1->SR & SPI_SR_RXNE));

Пока SR & SPI_SR_RXNE пустой, надо ждать.
Не наоборот надо?
Пока SR & SPI_SR_RXNE полный, надо ждать, когда освободится, то заполнять его.
0: Rx buffer empty
1: Rx buffer not empty

У TXE бита наоборот
0: Tx buffer not empty
1: Tx buffer empty

ОтветитьЦитата
Создатель темы Размещено : 21.10.2023 03:25
 stm
(@stm)
Level 4
Рабочий код. SPI_CR1_SPE у меня не был активирован.
 
SPI1->CR1  |= SPI_CR1_SPE; 
uint8_t address=0x8F; //Register address+read
uint8_t result;
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET); //Chip Select
while(!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = address;
while(!(SPI1->SR & SPI_SR_TXE));
while((SPI1->SR & SPI_SR_BSY) != RESET);
	
while((SPI1->SR & SPI_SR_RXNE));
result=SPI1->DR;
while((SPI1->SR & SPI_SR_RXNE));
while((SPI1->SR & SPI_SR_BSY) != RESET);
	
while(!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = 0;
while(!(SPI1->SR & SPI_SR_TXE));
while((SPI1->SR & SPI_SR_BSY) != RESET);

while((SPI1->SR & SPI_SR_RXNE));
result=SPI1->DR;
while((SPI1->SR & SPI_SR_RXNE));
while((SPI1->SR & SPI_SR_BSY) != RESET);

HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_SET); //Chip Select
ОтветитьЦитата
Создатель темы Размещено : 21.10.2023 03:48
Aveal
(@aveal)
Top level Admin
От: @stm
while(!(SPI1->SR & SPI_SR_RXNE));

Пока SR & SPI_SR_RXNE пустой, надо ждать.
Не наоборот надо?
Пока SR & SPI_SR_RXNE полный, надо ждать, когда освободится, то заполнять его.
0: Rx buffer empty
1: Rx buffer not empty

Это приемный буфер, его заполняет внешнее устройство. Ждем пока буфер пустой, когда туда что-то приходит - считываем пришедшее значение.

ОтветитьЦитата
Размещено : 21.10.2023 10:14
Aveal
(@aveal)
Top level Admin

Еще бы в целом надо добавить таймаут ожидания флагов, чтобы в случае, если флаг не выставился по какой-то причине, программа намертво там не встряла.

ОтветитьЦитата
Размещено : 21.10.2023 10:16
 stm
(@stm)
Level 4

Значит эта часть кода у меня неправильная?

while((SPI1->SR & SPI_SR_RXNE));
result=SPI1->DR;
while((SPI1->SR & SPI_SR_RXNE));
while((SPI1->SR & SPI_SR_BSY) != RESET);

Надо так?

while(!(SPI1->SR & SPI_SR_RXNE)); //Ждём когда буфер заполнится, потом читаем его
result=SPI1->DR;
while(SPI1->SR & SPI_SR_RXNE); //Ждём, если буфер ещё полный. Ждём завершениетранспортировки данных.
while((SPI1->SR & SPI_SR_BSY) != RESET);
ОтветитьЦитата
Создатель темы Размещено : 21.10.2023 17:24
 stm
(@stm)
Level 4

Мне казалось, что SPI_SR_RXNE принимает значение 1, когда RX буфер заполнен.
Регистр SPI1->DR; это ведь не RX буфер.
А здесь проверяется, когда заполнен буфер, а читается регистр SPI1->DR

while(!(SPI1->SR & SPI_SR_RXNE));
result=SPI1->DR;

Может я узнаю, что RX буфер полный

while(!(SPI1->SR & SPI_SR_RXNE));

начну читать регистр SPI1->DR

result=SPI1->DR;

а значение еще не перешло в регистр SPI1->DR из RX буфера.

ОтветитьЦитата
Создатель темы Размещено : 21.10.2023 17:39
 stm
(@stm)
Level 4

SPI_SR_RXNE принимает значение 0, когда данные переходят из RX буфера в регистр SPI1->DR
Поэтому я применил данную логику.

while((SPI1->SR & SPI_SR_RXNE));
result=SPI1->DR;
while((SPI1->SR & SPI_SR_RXNE));
while((SPI1->SR & SPI_SR_BSY) != RESET);

И эти данные уже можно забирать из регистра SPI1->DR, когда SPI_SR_RXNE находится в нуле

Правда после

result=SPI1->DR;

строка

while((SPI1->SR & SPI_SR_RXNE));

кажется бесполезна.

ОтветитьЦитата
Создатель темы Размещено : 21.10.2023 17:50
 stm
(@stm)
Level 4

SPI_SR_RXNE очищается при чтении SPI1->DR?
Мне казалось, что просто при переходе данных в регистр DR очищается SPI_SR_RXNE .
Мне сложно представить, что SPI1->DR следит, когда его читают.
Например это

result=SPI1->DR;

Прям SPI1->DR следит, что значение перешло в переменную result?

ОтветитьЦитата
Создатель темы Размещено : 21.10.2023 18:41
 stm
(@stm)
Level 4
Я провёл эксперимент.
SPI_SR_RXNE очищается и без чтения SPI1->DR.
Может я не прав, но по моему очищение SPI_SR_RXNE сигнализирует о переходе данных в регистр SPI1->DR.
 
SPI1->CR1  |= SPI_CR1_SPE; 
uint8_t address=0x8F; //Register address+read
uint8_t result;
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET); //Chip Select
while(!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = address;
while(!(SPI1->SR & SPI_SR_TXE));
while((SPI1->SR & SPI_SR_BSY) != RESET);


while((SPI1->SR & SPI_SR_RXNE));
//result=SPI1->DR;  //ДЕАКТИВИРОВАНО.
 
---------------------------------------------------------------
 
SPI1->CR1  |= SPI_CR1_SPE; 
uint8_t address=0x8F; //Register address+read
uint8_t result;
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET); //Chip Select
while(!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = address;
while(!(SPI1->SR & SPI_SR_TXE));
while((SPI1->SR & SPI_SR_BSY) != RESET);


while((SPI1->SR & SPI_SR_RXNE));
result=SPI1->DR;  //АКТИВИРОВАНО.
-------------------------------------------------------------
В обоих случаях SPI_SR_RXNE очищен
tim

Со вторым result=SPI1->DR; который дальше по коду это же делал, результат тот же.

 
ОтветитьЦитата
Создатель темы Размещено : 22.10.2023 13:21
 stm
(@stm)
Level 4
spi

SPI_SR_RXNE очищался без чтения SPI1->DR в коде, потому что SPI1->DR читал дебаггер.

ОтветитьЦитата
Создатель темы Размещено : 23.10.2023 15:43
Поделиться: