С 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 раза получать.
Пробовал так, не получается:
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 постоянно в нуле.
Флаг SPI_SR_TXE принимает значение ноль после этой строчки
SPI1->DR = address;
И после этого флаг SPI_SR_TXE в единицу не становится.
В целом механизм такой:
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; }
У Эдуарда в посте есть описание обменных процедур через регистры - ссылка.
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
CR1->SPE не был включен.
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
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
while(!(SPI1->SR & SPI_SR_RXNE));Пока SR & SPI_SR_RXNE пустой, надо ждать.
Не наоборот надо?
Пока SR & SPI_SR_RXNE полный, надо ждать, когда освободится, то заполнять его.
0: Rx buffer empty
1: Rx buffer not empty
Это приемный буфер, его заполняет внешнее устройство. Ждем пока буфер пустой, когда туда что-то приходит - считываем пришедшее значение.
Еще бы в целом надо добавить таймаут ожидания флагов, чтобы в случае, если флаг не выставился по какой-то причине, программа намертво там не встряла.
Значит эта часть кода у меня неправильная?
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);
Мне казалось, что 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 буфера.
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));
кажется бесполезна.
SPI_SR_RXNE очищается при чтении SPI1->DR?
Мне казалось, что просто при переходе данных в регистр DR очищается SPI_SR_RXNE .
Мне сложно представить, что SPI1->DR следит, когда его читают.
Например это
result=SPI1->DR;
Прям SPI1->DR следит, что значение перешло в переменную result?
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; //АКТИВИРОВАНО.
Со вторым result=SPI1->DR; который дальше по коду это же делал, результат тот же.
SPI_SR_RXNE очищался без чтения SPI1->DR в коде, потому что SPI1->DR читал дебаггер.