Jump to content
john2103

STM32F103 SPI!!! CMSIS + прерывание - 8bit - 16bit

Recommended Posts

Posted (edited)

Доброго времени суток, товарищи, пытаюсь создать функции передачи по spi с использованием cmsis и прерываний. Раньше пользовался HAL на "полу- интуитивном" уровне. Все работало. Сейчас пытаюсь все писать только на cmsis и вот возникла проблема... Я попытался сделать две функции ( Отправка по SPI - 8-битного  массива и передача 8 битная DFF = 0 и отправка 16 битного массива и передача 16 бит DFF =1 и все это через прерывания)Результат смотрю анализатором и вот в чем проблема... если сначала идет функция передачи 8 битная а потом 16 битная то мелькает лишняя передача, 8 бит 0x00 и потом идет правильная передача, 16 битная. Не могу понять откуда берется эта передача??? (0xAA 0xBB 0xCC 0x00 0xDD 0xDD 0xEE 0xEE 0xFF 0xFF) ,  если поставить передачи 8 бит 16 бит 8 бит 16 бит то получается вот это (0xAA 0xBB 0xCC 0x00 0xDD 0xDD 0xEE 0xEE 0xFF 0xFF 0xAA 0xBB 0xCC 0xFE 0xDD 0xDD 0xEE 0xEE 0xFF 0xFF), если между функциями вставить задержку 1 мс то все ок иначе тот результат о котором писал ..."головной убор Михаила Боярского"

void SPI1_STM32F1_init(void)
{

	// --- Инициализация порта для работы spi ---
		
	// ------ Настраиваем порт А --------------------------------------------------------------------------
	RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //--- Включаем тактирование порта А
	RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; //--- Включаем тактирование альтернативных функции
	RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; //--- Включаем тактированние SPI1 
	// ----------------------------------------------------------------------------------------------------
	GPIOA->CRL &= ~(GPIO_CRL_CNF5|GPIO_CRL_CNF7|GPIO_CRL_MODE5|GPIO_CRL_MODE7); //--- Обнуление первоначальных параметров порта
	GPIOA->CRL |= (
								 GPIO_CRL_MODE5			// --- |Настройка вывода SCL, на работу в режиме альтернативной функции   
								|GPIO_CRL_CNF5_1		// --- |режим output mode 11b - max 50 Мгц, CNF = 10b Альтернативная функция output push-pull  )
								|GPIO_CRL_MODE7			// --- |Настройка вывода MOSI
								|GPIO_CRL_CNF7_1		// --- |
								);
	// ----------------------------------------------------------------------------------------------------
	GPIOA->CRL &= ~(GPIO_CRL_CNF6|GPIO_CRL_CNF6); 
	GPIOA->CRL |= GPIO_CRL_MODE6;
	

	SPI1->CR1 |= SPI_CR1_BIDIMODE; // --- BIDIMODE режим работы (1 - одна линия, 0 - две линии связи)
	
	SPI1->CR1 |= SPI_CR1_BIDIOE;	 // --- BIDIOE Этот бит в сочетании с битом BIDImode выбирает направление передачи в двунаправленном режиме 
																 // --- 0: Output disabled (receive-only mode) 
																 // --- 1: Output enabled (transmit-only mode) 
	
	SPI1->CR1 &=~SPI_CR1_CRCEN;		 // --- Аппаратный расчет CRC включить
																 // --- 0: расчет CRC отключен 
																 // --- 1: Расчет CRC включен
	
	SPI1->CR1 &= ~SPI_CR1_CRCNEXT; // --- Следующая передача данных будет завершаться CRC-кодом.
																 // --- 0: Этап передачи данных
																 // --- 1: Следующая передача завершится передачей RCR
	
	SPI1->CR1 &= ~SPI_CR1_DFF;			 // --- Формат кадра данных
																 // --- 0: Размер кадра передачи 8 бит
																 // --- 1: Размер кадра передачи 16 бит
	
	SPI1->CR1 &= ~SPI_CR1_RXONLY;  // --- Этот бит совместно с BIDIMODE выбирает направление передачи в 2-х проводном (MISO и MISO) режиме.
																 // --- 0: Full duplex — передача и прием
																 // --- 1: Output disabled — только прием
	
 	SPI1->CR1 |= SPI_CR1_SSM; 		 // --- Программное управление ведомым устройством. Когда бит SSM установлен, сигнал NSS заменяется значением бита SSI.
																 // --- 0: Программное управление ведомым отключено
																 // --- 1: Программное управление ведомым включено
	
	SPI1->CR1 |= SPI_CR1_SSI;			 // --- Внутренний выбор ведомого. Этот бит работает только когда бит SSM установлен. Значение этого бита принудительно подается на NSS, а значение IO вывода NSS игнорируется.
																 // --- 1: (Master) Заменяет значение на выводе NSS
																 // --- 0; (Slave)
																 
	SPI1->CR1 &= ~SPI_CR1_LSBFIRST;// ---  Формат кадра
																 // --- 0: MSB передается первым
																 // --- 1: LSB передается первым
																 
	SPI1->CR1 |= SPI_CR1_BR;	 		 // --- BR[2:0]: Выбор скорости передачи
  																//	000: fPCLK/2 
																	//	001: fPCLK/4
																	//	010: fPCLK/8
																	//	011: fPCLK/16
																	//	100: fPCLK/32
																	//	101: fPCLK/64
																	//	110: fPCLK/128
																	//	111: fPCLK/256
																	//#define SPI_CR1_BR_Pos                      (3U)                               
																	//#define SPI_CR1_BR_Msk                      (0x7U << SPI_CR1_BR_Pos)           /*!< 0x00000038 */
																	//#define SPI_CR1_BR                          SPI_CR1_BR_Msk                     /*!< BR[2:0] bits (Baud Rate Control) */
																	//#define SPI_CR1_BR_0                        (0x1U << SPI_CR1_BR_Pos)           /*!< 0x00000008 */
																	//#define SPI_CR1_BR_1                        (0x2U << SPI_CR1_BR_Pos)           /*!< 0x00000010 */
																	//#define SPI_CR1_BR_2                        (0x4U << SPI_CR1_BR_Pos)           /*!< 0x00000020 */

	SPI1->CR1 |= SPI_CR1_MSTR;		 // --- Выбор режима работы SPI: Master/Slave
																 // --- 0: Режим Slave (ведомый)
																 // --- 1: Режим Master (ведущий)
																 
  SPI1->CR1 &= ~SPI_CR1_CPOL;		 // --- Полярность тактового сигнала
																 // --- 0: CK в 0 при простое
																 // --- 1: CK в 1 при простое
	
	SPI1->CR1 &= ~SPI_CR1_CPHA;		 // --- Фаза тактового сигнала
																 // --- 0: Первый переход тактового сигнала является краем захвата данных
																 // --- 1: Второй переход тактового сигнала является краем захвата данных


	SPI1->CR2 &= ~SPI_CR2_TXEIE;	 // --- Прерывание опустошения буфера передачи данных Tx
																 // --- 0: Прерывание TXE запрещено
																 // --- 1: Прерывание TXE разрешено. Используется для генерации прерывания когда устанавливается флаг TXE

	SPI1->CR2 &= ~SPI_CR2_RXNEIE;	 // --- Прерывание не пустого буфера приема Rx
																 // --- 0: Прерывание RXNE запрещено
																 // --- 1: Прерывание RXNE разрешено. Используется для генерации прерывания когда устанавливается флаг RXNE.

	SPI1->CR2 &= ~SPI_CR2_ERRIE;	 // --- Прерывание при возникновении ошибок передачи. Этот бит контролирует генерацию прерывания при возникновении одной из ошибок интерфейса SPI (CRCERR, OVR, MODF).
																 // --- 0: Прерывание при возникновении ошибок запрещено
																 // --- 1: Прерывание при возникновении ошибок разрешено

	SPI1->CR2 |= SPI_CR2_SSOE;		 // --- Разрешить выход SS
																 // --- 0: Выход SS отключен в режиме master (ведущий) и есть возможность работать в multimaster режиме
																 // --- 1: Выход SS включен в режиме master (ведущий), при этом нет возможности работать в multimaster режиме
																 
	SPI1->CR2 &= ~SPI_CR2_TXDMAEN;	 // --- Когда этот бит установлен, запрос DMA возникает при установке флага TXE
																 // --- 0: Tx buffer DMA disabled 
																 // --- 1: Tx buffer DMA enabled 

	SPI1->CR2 &= ~SPI_CR2_RXDMAEN;	 // --- Когда этот бит установлен, запрос DMA возникает при установке флага RXNE
																 // --- 0: Rx buffer DMA disabled 
																 // --- 1: Rx buffer DMA enabled


	SPI1_Enable;

	NVIC_EnableIRQ(SPI1_IRQn);

}

void SPI1_STM32F1_write_8bit_irq(uint8_t *data, int32_t len_8bit)
{
	 if(len_8bit<=0)
    return;
  
		//Ждем, пока SPI освободится от предыдущей передачи
		while(SPI1->SR & SPI_SR_BSY))
			;
		SPI1->CR1 &= ~SPI_CR1_SPE;			
		SPI1->CR1 &= ~SPI_CR1_DFF;
		SPI1->CR1 |= SPI_CR1_SPE;			
		
		//Настройка переменных, которые будут
		//использоваться в обработчике прерывания SPI
		tx_index_8_bit = 0;
		tx_len_8_bit = len_8bit;
		tx_data_8_bit = data;
		
		//Разрешаем прерывание TXEIE И запускаем обмен
		SPI1->CR2 |= SPI_CR2_TXEIE; 
		
}

void SPI1_STM32F1_write_16bit_irq(uint16_t *data, int32_t len_16bit)
{
	 if(len_16bit<=0)
    return;
  
		//Ждем, пока SPI освободится от предыдущей передачи
		while(SPI1->SR & SPI_SR_BSY)
			;
		SPI1->CR1 &= ~SPI_CR1_SPE;	
		SPI1->CR1 |= SPI_CR1_DFF;
		SPI1->CR1 |= SPI_CR1_SPE;
		//Настройка переменных, которые будут
		//использоваться в обработчике прерывания SPI
		tx_index_16_bit = 0;
		tx_len_16_bit = len_16bit;
		tx_data_16_bit = data;
		
		//Разрешаем прерывание TXEIE И запускаем обмен
		SPI1->CR2 |= SPI_CR2_TXEIE; 
		
}


void SPI1_IRQHandler(void)
{
  if ((SPI1->CR1&SPI_CR1_DFF) == 0)
	{
	SPI1->DR = tx_data_8_bit[tx_index_8_bit]; //Записываем новое значение в DR
  tx_index_8_bit++; //увеличиваем счетчик переданных байт на единицу
  
  //если все передали, то отключаем прерывание,
  //тем самым завершаем передачу данных
  if(tx_index_8_bit >= tx_len_8_bit)
    SPI1->CR2 &= ~(SPI_CR2_TXEIE); 
	}
		else
	{
	SPI1->DR = tx_data_16_bit[tx_index_16_bit]; //Записываем новое значение в DR
  tx_index_16_bit++; //увеличиваем счетчик переданных байт на единицу
  
  //если все передали, то отключаем прерывание,
  //тем самым завершаем передачу данных
  if(tx_index_16_bit >= tx_len_16_bit)
    SPI1->CR2 &= ~(SPI_CR2_TXEIE); 
	}
}

.............
uint8_t data_8bit[3] = 
{ 0xAA, 0xBB, 0xCC};

uint16_t data_16bit[3] = 
{ 0xDDDD, 0xEEEE, 0xFFFF};

                                                                      
                                                                      
int main(void)
{
SPI1_STM32F1_write_8bit_irq( data_8bit, 3);
//LL_mDelay(1);
SPI1_STM32F1_write_16bit_irq( data_16bit, 3);
//LL_mDelay(1);
SPI1_STM32F1_write_8bit_irq( data_8bit, 3);
//LL_mDelay(1);
SPI1_STM32F1_write_16bit_irq( data_16bit, 3);
}
                                                                      
                                                                      
                                                                      

 

Edited by john2103

Share this post


Link to post
Share on other sites
8 часов назад, john2103 сказал:

отправка по SPI - 8-битного  массива и передача 8 битная DFF = 0 и отправка 16 битного массива и передача 16 бит DFF =1 и все это через прерывания

А зачем вам нужен такой геморой , такой экстравагантный режим работы СПиАя??? Если вы считаете для себя возможным на лету менять режим работы периферии да еще и с прерываниями вы должны быть экспертом по этой периферии.

На мой взгляд вы что то перемудрили с прерываниями (как минимум) - при таком режиме работы их использование вряд ли оправдано!

Вы попробуйте изложить идею использования там прерываний и, я думаю, вам все станет намного понятнее!

Я так понимаю код который работал - работал без прерываний, правильно?

Share this post


Link to post
Share on other sites
11 минуту назад, ruhi сказал:

А зачем вам нужен такой геморой , такой экстравагантный режим работы СПиАя??? Если вы считаете для себя возможным на лету менять режим работы периферии да еще и с прерываниями вы должны быть экспертом по этой периферии.

На мой взгляд вы что то перемудрили с прерываниями (как минимум) - при таком режиме работы их использование вряд ли оправдано!

Вы попробуйте изложить идею использования там прерываний и, я думаю, вам все станет намного понятнее!

Я так понимаю код который работал - работал без прерываний, правильно?

Это все чисто в образовательных целях! Пытаюсь повысить свой уровень знаний. Просто использование HAL не дает понимания как это все работает. Вот и захотелось все ручками. У меня есть функции без прерываний, которые прекрасно работают, через while(...txe). Просто много статей читал и смотрел, где делали это с прерываниями.Я не могу понять почему проходит эта передача. Я ведь дожидаюсь флага bay, потом выключаю модуль и включаю, не заношу больше ничего в DR, почему она возникает? в какой момент? Анализатором ничего путевого не могу поймать

Share this post


Link to post
Share on other sites

Тестирование литиевых батареек Fanso в нормальных условиях

Компания Компэл, эксклюзивный дистрибьютор компании Fanso, предлагает широкий перечень ЛХИТ, позволяющий подобрать элемент питания, в наибольшей степени соответствующий конкретным требованиям. Для тестирования параметров, указанных в Datasheet, специалисты Компэл организовали в апреле 2019 г. полугодовой тест на постоянный разряд в нормальных условиях четырех наиболее популярных моделей литий-тионилхлоридных и литий-диоксидмарганцевых батареек Fanso.

Посмотреть результаты первого среза

Во-первых, что за задача, что надо щелкать туда-сюда битность? Во-вторых, ждут окончание передачи примерно так:

void SPI3_Send(uint8_t dat){
	while (!(SPI3->SR & SPI_SR_TXE));
	
	SPI3->DR = dat;

	while (!(SPI3->SR & SPI_SR_TXE));
	while ((SPI3->SR & SPI_SR_BSY));
}

В-третьих, выключать SPI перед сменой битности не требуется и делается как-то так:

void SPI3_Send16(uint16_t dat){
	SPI3->CR1 |= SPI_CR1_DFF;
	
	while (!(SPI3->SR & SPI_SR_TXE));
	
	SPI3->DR = dat;

	while (!(SPI3->SR & SPI_SR_TXE));
	while ((SPI3->SR & SPI_SR_BSY));
	
	SPI3->CR1 &= ~SPI_CR1_DFF;
}

В-четвертых, прерывание по передаче нафиг не нужно, ибо скорость передачи высокая и все очень быстро отправляется без прерываний. Прерывание удобно использовать на прием. А если надо слать большие массивы данных, то есть DMA. Ну и прежде чем отключать SPI :

In master or slave full-duplex mode (BIDIMODE=0, RXONLY=0)
1. Wait until RXNE=1 to receive the last data
2. Wait until TXE=1
3. Then wait until BSY=0
4. Disable the SPI (SPE=0) and, eventually, enter the Halt mode (or disable the peripheral
clock)

Share this post


Link to post
Share on other sites
44 минуты назад, BARS_ сказал:

Во-первых, что за задача, что надо щелкать туда-сюда битность?

Задача, сделать функции с использованием прерываний для передачи 8 битного и 16 битного массивов. Что бы была беспрерывная передача. (Использование для этого именно прерываний- это чистый интерес, поэтому этот пункт обязателен)

void SPI3_Send(uint8_t dat){
	while (!(SPI3->SR & SPI_SR_TXE));
	
	SPI3->DR = dat;

	while (!(SPI3->SR & SPI_SR_TXE)); // -- ЗАЧЕМ ЭТИ ПРОВЕРКИ ?
	while ((SPI3->SR & SPI_SR_BSY)); // ---Это трата времени 
}

 

49 минут назад, BARS_ сказал:

В-третьих, выключать SPI перед сменой битности не требуется

Из материалов, которые я читал, в разных местах пишут по разному, кто то говорит что надо, кто говорит- нет. Я четкого ответа не нашел и перестраховался.

 

57 минут назад, BARS_ сказал:

В-четвертых, прерывание по передаче нафиг не нужно, ибо скорость передачи высокая и все очень быстро отправляется без прерываний. Прерывание удобно использовать на прием. А если надо слать большие массивы данных, то есть DMA. Ну и прежде чем отключать SPI :

In master or slave full-duplex mode (BIDIMODE=0, RXONLY=0)
1. Wait until RXNE=1 to receive the last data
2. Wait until TXE=1
3. Then wait until BSY=0
4. Disable the SPI (SPE=0) and, eventually, enter the Halt mode (or disable the peripheral
clock)

Разобраться с DMA - это следующая задача. За механизм остановки спасибо. Только опять вопрос, зачем ждать остальные флаги, если BSY =0  свидетельствует о том что SPI и передачу и прием закончило ??? Или я ошибаюсь ?

Share this post


Link to post
Share on other sites

Новое бюджетное семейство микроконтроллеров STM32G0 и планы его развития

Семейство STM32G0 сочетает в себе лучшие качества представителей семейств STM32F0 и STM32L0 - относительно высокую производительность и низкое энергопотребление. Модели STM32G0 имеют упрощенную схему питания, улучшенную периферию, систему тактирования и быстрые порты в/в, доп.средства защиты ПО, повышенную устойчивость к статическим разрядам, широкий ассортимент корпусов, обновленные пакеты библиотек для STM32CubeMX. STMicroelectronics планирует развивать новое семейство.

Подробнее...

1 час назад, john2103 сказал:

Просто много статей читал и смотрел, где делали это с прерываниями

что то я сомневаюсь что существует хоть одна статья про использовании прерываний СПИАя когда переключается режим из 16-битного в 8-ми битный.

Если вы хотите изучать работу с прерываниями - уберите переключение режимов, если хотите изучать переключения режимов - уберите прерывания,

когда по отдельности разберетесь, может у вас получится сотворить какое нибудь чудо, а пока рано о чудесах грезить :) .

Share this post


Link to post
Share on other sites
Posted (edited)
25 минут назад, ruhi сказал:

что то я сомневаюсь что существует хоть одна статья про использовании прерываний СПИАя когда переключается режим из 16-битного в 8-ми битный.

В том то и дело! Много статей, где идет передача 8бит и ожиданием флагов или 16 бит и флаги. Я сам по экспериментировал и сделал переключение с 8 га 16 и обратно. Так же примеры с прерыванием и 8бит или прерывание и 16 бит. А потом я попытался сделать переключение с прерыванием, но чет есть проблемы. Видимо,чет я не совсем понимаю в логике работы модуля. Хотя в циклах все ок.(И я думал, что я разобрался)

Причем просто функция передачи по прерываниям работает отлично, если без смены битности. Но битность то я меняю когда модуль не работает ? не могу понять..(

Edited by john2103

Share this post


Link to post
Share on other sites
11 час назад, john2103 сказал:

если между функциями вставить задержку 1 мс

так это... ты говоришь модуль спи отключается при изменении битности - 

может он у тебя отключается ДО того как байт выплюнулся хотя это странно конечно - в общем надо проверить наложение момента отключения юнита на текущюю передачу,

и вот так :

SPI1_STM32F1_write_8bit_irq( data_8bit, 3);

SPI1_STM32F1_write_8bit_irq( data_8bit, 3);

SPI1_STM32F1_write_8bit_irq( data_8bit, 3);

если передавать, что будет?

Share this post


Link to post
Share on other sites
4 минуты назад, ruhi сказал:

может он у тебя отключается ДО того как байт выплюнулся хотя это странно конечно

В том то и дело. По логике... Как я думаю spi не будет отключатся раньше чем выплюнет крайний бит и не примет если есть что, т.к. я отслеживаю флаг BSY. Но ощущение, что не смотря на то, что я проверил бит BSY и вроде как модуль закончил все дела,я его остановил и изменил количество бит на передачу, он почему то считает что в DR занесено значение 0x00 и выплевывает его, хотя этого нигде нет. Может конечно и моя функция на передачу с прерыванием вообще как то не так построена.

Если передать 

SPI1_STM32F1_write_8bit_irq( data_8bit, 3);
SPI1_STM32F1_write_8bit_irq( data_8bit, 3);
SPI1_STM32F1_write_8bit_irq( data_8bit, 3);

То все норм 0xAA 0xBB 0xCC 0xAA 0xBB 0xCC 0xAA 0xBB 0xCC

 Проверил если 

SPI1_STM32F1_write_8bit_irq( data_8bit, 3);
SPI1_STM32F1_write_8bit_irq( data_8bit, 3);
SPI1_STM32F1_write_8bit_irq( data_8bit, 3);
SPI1_STM32F1_write_16bit_irq( data_16bit, 3);
SPI1_STM32F1_write_16bit_irq( data_16bit, 3);
SPI1_STM32F1_write_16bit_irq( data_16bit, 3);

То после 8 битных передач опять появляется одна передача 0x00, а потом все норм по 16 бит как положено, ничего лишнего

Share this post


Link to post
Share on other sites
12 минуты назад, john2103 сказал:

Что бы была беспрерывная передача.

Беспрерывная передача не имеет отношения к прерываниям. 

image.thumb.png.da4269ea00445cfaf017f9441b136e07.png

 

2 минуты назад, john2103 сказал:

То после 8 битных передач опять появляется одна передача 0x00, а потом все норм по 16 бит как положено, ничего лишнего

А если убрать отключение и включение SPI?

Share this post


Link to post
Share on other sites
12 часа назад, john2103 сказал:

//если все передали, то отключаем прерывание, //тем самым завершаем передачу данных if(tx_index_16_bit >= tx_len_16_bit) SPI1->CR2 &= ~(SPI_CR2_TXEIE); }

я насколько помню-знаю отключение (это же просто запрет?) прерываний НЕ отключает СПИ!

И, соответственно, я не вижу что у тебя СПИ воЩе отключается! то есть получается ты ему битность меняешь наживую - это вполне может приводить к генерации лишней посылки на шину!

Share this post


Link to post
Share on other sites
29 минут назад, ruhi сказал:

SPI1_STM32F1_write_8bit_irq( data_8bit, 3);

SPI1_STM32F1_write_8bit_irq( data_8bit, 3);

SPI1_STM32F1_write_8bit_irq( data_8bit, 3);

если передавать, что будет?

Попробовал еще 

При такой конструкции 

SPI1_STM32F1_write_8bit_irq( data_8bit, 3);
SPI1_STM32F1_write_8bit_irq( data_8bit, 3);

SPI1_STM32F1_write_16bit_irq( data_16bit, 3);
SPI1_STM32F1_write_16bit_irq( data_16bit, 3);

SPI1_STM32F1_write_8bit_irq( data_8bit, 3);
SPI1_STM32F1_write_8bit_irq( data_8bit, 3);

SPI1_STM32F1_write_16bit_irq( data_16bit, 3);
SPI1_STM32F1_write_16bit_irq( data_16bit, 3);

получается 

0xAA 0xBB 0xCC 0xAA 0xBB 0xCC 0x00 

0xDD 0xDD 0xEE 0xEE 0xFF 0xFF 0xDD 0xDD 0xEE 0xEE 0xFF 0xFF

0xAA 0xBB 0xCC 0xAA 0xBB 0xCC 0xFE

0xDD 0xDD 0xEE 0xEE 0xFF 0xFF 0xDD 0xDD 0xEE 0xEE 0xFF 0xFF

Share this post


Link to post
Share on other sites
12 часа назад, john2103 сказал:

while(SPI1->SR & SPI_SR_BSY) ; SPI1->CR1 &= ~SPI_CR1_SPE;

вообще то отключать надо после каждого из этих while -ов , конфигурировать и включать.

Share this post


Link to post
Share on other sites
15 минут назад, BARS_ сказал:

Беспрерывная передача не имеет отношения к прерываниям. 

Я знаю. И картинку смотрел. Я неправильно выразился. Если передавать большой объем данных с опросом флага, то программа "фактически" встанет, пока все не передаст все (DMA - пока в принципе не рассматриваю). С прерыванием она может выполнять какие то фоновые задачи в это время. Ну это так... для меня же пока основная задача, понять насколько хорошо я понял принципы. 

20 минут назад, BARS_ сказал:

А если убрать отключение и включение SPI?

Только что убрал, все так же не правильные передачки проскакивают. В принципе строки отключения и включения spi, появились когда я искал причину появления этих лишних передач. 

Share this post


Link to post
Share on other sites
12 часа назад, john2103 сказал:

SPI1_Enable;

вот это вот что такое? и где дизэйбл???

Share this post


Link to post
Share on other sites

На кой там нужен дизейбл?

Отправлено с моего Nexus 5 через Tapatalk

Share this post


Link to post
Share on other sites
12 минуты назад, ruhi сказал:

я насколько помню-знаю отключение (это же просто запрет?) прерываний НЕ отключает СПИ!

И, соответственно, я не вижу что у тебя СПИ воЩе отключается! то есть получается ты ему битность меняешь наживую - это вполне может приводить к генерации лишней посылки на шину!

Прерывание нет.

void SPI1_STM32F1_write_16bit_irq(uint16_t *data, int32_t len_16bit)
{
	.....
		SPI1->CR1 &= ~SPI_CR1_SPE;	
		SPI1->CR1 |= SPI_CR1_DFF;
		SPI1->CR1 |= SPI_CR1_SPE;
	....
}

В самой функции передачи происходит отключение модуля и переключение разрядности. И как писали выше, битность вроде можно менять на живую

 

3 часа назад, BARS_ сказал:

В-третьих, выключать SPI перед сменой битности не требуется 

 

15 минут назад, ruhi сказал:

вот это вот что такое? и где дизэйбл???

Забыл вставить это в шапке проги 

#define SPI1_Enable  SPI1->CR1 |= SPI_CR1_SPE

А дизэйбл не прописывал, дальше я и включал и выключал в функции передачи напрямую битами.

Share this post


Link to post
Share on other sites
46 минут назад, john2103 сказал:

То после 8 битных передач опять появляется одна передача 0x00, а потом все норм по 16 бит как положено, ничего лишнего

вот исходя из этого, например, как и по другим данным, у меня только одна гипотеза (кажется мне правдоподобной):

переключение с 8бит на 16 - приводит к тому что СПИ-ай воспринимает это расширение как то что у него появился один НЕ переданный байт который он и отправляет,

поэтому, я бы предложил, в качестве эксперимента, этот СПИ-ай выключить как то более кардинально,

что бы не было сомнений что его настройки ни как не связаны с его предыдущими настройками.

потому что если вы его просто задизейблили он все равно может запомнить что у него появился непереданный байт. который он сначала выплюнет при разрешении передачи!

Share this post


Link to post
Share on other sites
Posted (edited)
28 минут назад, ruhi сказал:

вот исходя из этого, например, как и по другим данным, у меня только одна гипотеза (кажется мне правдоподобной):

переключение с 8бит на 16 - приводит к тому что СПИ-ай воспринимает это расширение как то что у него появился один НЕ переданный байт который он и отправляет,

поэтому, я бы предложил, в качестве эксперимента, этот СПИ-ай выключить как то более кардинально,

что бы не было сомнений что его настройки ни как не связаны с его предыдущими настройками.

потому что если вы его просто задизейблили он все равно может запомнить что у него появился непереданный байт. который он сначала выплюнет при разрешении передачи!

Я вот сейчас сижу и смотрю на схему выше

 

1 час назад, BARS_ сказал:

image.thumb.png.da4269ea00445cfaf017f9441b136e07.png

И у меня тоже гипотеза почти как ваша .... Только вот думаю, а не может ли SPI "думать", что у него есть еще один, не принятый байт? и поэтому даже после флага BSY он шлет SCK, но вот почему он передает то 0x00 то 0xFE я не могу понять. (Или я немного не так понимаю смысл подписи к самой нижней картинке RX buffer)

Хотя такая версия как у вас у меня тоже была. Просто не знаю как бы ее проверить ... Рубить тактирование модуля ?

Edited by john2103

Share this post


Link to post
Share on other sites

Зайти под отладчиком и пройтись по флагами

Отправлено с моего Nexus 5 через Tapatalk

Share this post


Link to post
Share on other sites
9 минут назад, BARS_ сказал:

Зайти под отладчиком и пройтись по флагами

Пытаюсь, уже дня три, но постоянно в отладчике проскакиваю. Сейчас буду пытаться 

Share this post


Link to post
Share on other sites
Posted (edited)
17 минут назад, john2103 сказал:

что у него есть еще один, не принятый байт?

почему не принятый - не переданный? он же у вас мастер? Или ты имеешь ввиду попробовать прочитать его?

все надо пробовать - все что в голову приходит, в таких ситуациях.

Все таки, если правильно что 1мс задержки решает проблему лишнего байта, значит что задержка до переключения битности решает проблему!

АГА - вот! попробуй после бизи флага подождать еще флаг завершения передачи (есть такой? не опустошения буфера для записи следующего сампла, а именно что все выплюнули в шину!)

Точно! если ты его дизейблишь а он еще не закончил посылать последний байт и до завершения посылки не дизейблится - тут ты и попадаешь в undefined behavior.

Там может еще бит-флаг есть о том что СПИ-ай задизейблился, тогда его надо ждать после дизейбла!

23 минуты назад, john2103 сказал:

Рубить тактирование модуля ?

вряд ли - тогда наверно не получится сконфигурировать, если только выключить-включить сразу попробовать.

вот такой флаг еще посмотри:

Там может еще бит-флаг есть о том что СПИ-ай задизейблился, тогда его надо ждать после дизейбла!

Edited by ruhi

Share this post


Link to post
Share on other sites

Сейчас увеличил скорость работы spi до 

6 минут назад, ruhi сказал:

АГА - вот! попробуй после бизи флага подождать еще флаг завершения передачи (есть такой? не опустошения буфера для записи следующего сампла, а именно что все выплюнули в шину!)

Так если я правильно все понимаю, то это и есть BSY  флаг? Нет?

Сейчас увеличил скорость работы SPI, левые посылки пропали. 

первый скрин скоросьть /256, второй /32

Где то в прерываниях я косячу, что то где то не так проверяю

частота 111.jpg

частота 100.jpg

Share this post


Link to post
Share on other sites
Только что, john2103 сказал:

Так если я правильно все понимаю, то это и есть BSY  флаг? Нет?

значит он - я точные названия уже не помню.

1 минуту назад, john2103 сказал:

Сейчас увеличил скорость работы SPI, левые посылки пропали. 

Так это эквивалентно тому что ты маленькую задержку добавил! Задержка же решает проблему!

Попробуй вернуть медленную скорость и поставить 5 или 10 NOP инструкций после ожидания бизи!

Это может быть фича такая СТМ-мовского СПИ-ая что у него бизи срабатывает чуть раньше чем надо!?

8 минут назад, john2103 сказал:

Где то в прерываниях я косячу, что то где то не так проверяю

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

Share this post


Link to post
Share on other sites
Posted (edited)
9 часов назад, john2103 сказал:

Из материалов, которые я читал, в разных местах пишут по разному, кто то говорит что надо, кто говорит- нет. Я четкого ответа не нашел и перестраховался.

Потому-то нужно читать RM, а не в разных местах...

Edited by MasterElectric

Share this post


Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Similar Content

    • By В гостях у Slime
      Здравствуйте, мне нужна помощь с подключением дисплея WG12864 к STM32F103C8T6. А именно? Я не нашёл библиотек для него, лишь только ардуиновские. Может у кого есть своя? С STM32 опыта почти нет. Так мигал светодиодом и всё, но зато ардуину я уже знаю всё. Я перерос её и мне хочется освоить стм.
    • By defin
      Добрый день, имеется отладочная плата Nucleo-F411RE. Не получается настроить в CMSIS ногу PA8 для вывода частоты (MCO) с внутреннего генератора HSI. Через HAL все чётко работает. Из reference manual так и не понял как прописать источник тактирования для MCO. В инете полно примеров для F100 серии, для себя не могу их адаптировать.
      RCC->AHB1ENR|=RCC_AHB1ENR_GPIOAEN; // enable clock for port A GPIOA->MODER |= GPIO_MODER_MODER8_0; GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD8_0; GPIOA->PUPDR |= GPIO_PUPDR_PUPD8_1; GPIOA->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR8_0 | GPIO_OSPEEDER_OSPEEDR8_1); RCC->CFGR |= RCC_CFGR_SW_HSI; //вот здесь не знаю что писать, написал наугад Тактирование по умолчанию от HSI
    • By COKPOWEHEU
      Решил разобраться с модулем компаса GY-271 - одним из немногих модулей, которые вообще сумел найти. Пол-интернета заполнены утверждениями что собран данный модуль на микросхеме HMC5883L, которая общается по I2C и отзывается на адрес 0x1E (соответственно, 0x3C/0x3D для записи и чтения). На практике же посылка этого адреса натыкалась на глухой таймаут, мол знать не знаем такого адреса, и вообще мы не оно. Целенаправленные, но больше случайные поиски по интернету дали наводку что данное чудо техники, возможно, отзовется на адрес 0x0D (0x1A/0x1B для записи и чтения) и действительно, по такому адресу удалось добиться ответа, правда не совсем того, что ожидалось. К примеру, без "шаманской" (опять же, советы из "Всезнающего") записи единицы по адресу 9, ответ был нулевым. Потом более-менее осмысленные данные появились, но не с адреса 0x03, как положено по даташиту, а вовсе даже с 0x00. Очередная случайная находка дала направление, что заботливые китайцы запаяли на плату не HMC5883L, а вовсе даже QMC5883L - совсем другую микросхему с другими регистрами. И вот она действительно похожа по настройкам и адресу.
      Стал бы я создавать тему, если бы все было так хорошо... Хотя ответ от микросхемы и есть, как-то он слабо похож на нормальные данные. Теоретически, в регистрах 1:0, 3:2, 5:4 должны быть проекции магнитного поля на оси X, Y, Z. То есть вдали от магнитов и массивных железяк, геометрическая сумма значений должны быть примерно 0.5 Гс, то есть ~32000 единиц модуля, причем пока модуль лежит на столе, сильно меняться значениям не с чего. Привожу лог снятых данных (во вложении исходный код прошивки: вся работа с периферией идет руками, без автоконфигураторов и тому подобного). За все время съема этого лога модель лежал на столе в одном положении, но данные по осям скачут достаточно произвольным образом.
      I2C test FB FF 0A 00 14 00 00 A8 F5 0D 00 01 01 00 Write 0F 00 05 00 F1 FF 04 99 F5 | 15 5 -15 2337 FB FF 00 00 05 00 00 9A F5 | -5 0 5 2338 0F 00 05 00 00 00 00 8F F5 | 15 5 0 2327 E2 FF 00 00 F6 FF 00 93 F5 | -30 0 -10 2331 28 00 F6 FF FB FF 00 90 F5 | 40 -10 -5 2328 05 00 FB FF FB FF 00 99 F5 | 5 -5 -5 2337 00 00 00 00 00 00 00 97 F5 | 0 0 0 2335 00 00 0F 00 D6 FF 00 99 F5 | 0 15 -42 2337 32 00 E2 FF 00 00 00 94 F5 | 50 -30 0 2332 E7 FF EC FF 00 00 00 97 F5 | -25 -20 0 2335 05 00 F6 FF 00 00 04 92 F5 | 5 -10 0 2330 Продублирую код чтения регистра (насколько я знаю, он довольно типичный, но мало ли...). Естественно, код писался в первую очередь под конкретную задачу - оптимизация будет потом, если оно вообще заработает.
      void I2C_Read(uint8_t device, uint8_t addr, uint8_t *buf, uint8_t count){ //start I2C2->CR1 |= I2C_CR1_START; while(!(I2C2->SR1 & I2C_SR1_SB)){} (void) I2C2->SR1; //device I2C2->DR = (device<<1) &~(1<<0); while(!(I2C2->SR1 & I2C_SR1_ADDR)){} (void) I2C2->SR1; (void) I2C2->SR2; //addr I2C2->DR = addr; while(!(I2C2->SR1 & I2C_SR1_TXE)){} I2C2->CR1 |= I2C_CR1_STOP; //restart I2C2->CR1 |= I2C_CR1_START; while(!(I2C2->SR1 & I2C_SR1_SB)){} //device I2C2->DR = (device<<1) | (1<<0); while(!(I2C2->SR1 & I2C_SR1_ADDR)){} (void) I2C2->SR1; (void) I2C2->SR2; //data for(uint8_t i=0; i<count-1; i++){ //I2C2->CR1 &=~ I2C_CR1_ACK; I2C2->CR1 |= I2C_CR1_ACK; while(!(I2C2->SR1 & I2C_SR1_RXNE)){} buf[i] = I2C2->DR; } I2C2->CR1 &=~I2C_CR1_ACK; while(!(I2C2->SR1 & I2C_SR1_RXNE)){} buf[count-1] = I2C2->DR; //stop I2C2->CR1 |= I2C_CR1_STOP; } #define QMC5883L 0x0D I2C_Read(QMC5883L, 0, data, 14); for(uint8_t i=0; i<14; i++){ UART_HEX(data[i]); UART_putc(USART, ' '); } data[0] = 0x80; I2C_Write(QMC5883L, 10, data, 1); data[0] = 0x01; I2C_Write(QMC5883L, 0x0B, data, 1); data[0] = (0b00<<6) | (0b00<<4) | (0b11<<2) | (0b01<<0); //oversampling = 512 //range = 2 G //ODR = 200 Hz //mode = continuous I2C_Write(QMC5883L, 9, data, 1); UART_puts(USART, "Write\x0d\n"); while(1){ I2C_Read(QMC5883L, 0, data, 9); for(uint8_t i=0; i<9; i++){ UART_HEX(data[i]); UART_putc(USART, ' '); } i16a x,y,z,t; x.u8val[0] = data[0]; x.u8val[1] = data[1]; y.u8val[0] = data[2]; y.u8val[1] = data[3]; z.u8val[0] = data[4]; z.u8val[1] = data[5]; t.u8val[0] = data[7]; t.u8val[1] = data[8]; t.ival += 3000+2000; sprintf(str,"| %i %i %i %i", x.ival, y.ival, z.ival, t.ival); UART_puts(USART, str); Собственно, вопрос: что я делаю не так и как сделать так, чтобы модуль отдавал правильные данные магнитного поля?
      compass.rar
    • By Пентагрид
      Решил собрать источник питания с управлением через PIC16F628A (парой кнопок переключать нужные напряжения). Взял обычный импульсник на 15 В, из обратной связи выдрал TL431, оставил оптрон, его повесил на выход МК. Написал тестовую прошивку: задаётся Vref через VRCON, компаратор сравнивает и выдаёт на оптрон 1 или 0.
      Сделал два варианта прошивки: в одном проверка на срабатывание выполняется циклически, в другом - вызов прерывания при реакции компаратора. Оба варианта тестировал в Протеусе (потенциометр и светодиод), работают. На бредборде завёлся только первый (с нагрузкой и без). А с прерыванием не работает: при отсутствии нагрузки выдаёт нужное напряжение, но стоит только подключить нагрузку и даже если рукой коснуться - напряжение падает. С нагрузкой вообще не заводится.
      МК питаю отдельно (тлф. зарядка с домотанной вторичкой + 7805). Несколько раз прошёлся по прошивке, не нашёл за что зацепиться. Прошу совета.
      Схема
      В коде присутствуют рудименты для кнопок (пока не вводил).
       
      comp5nop.rar
    • By Mars36
      Доброго времени суток, второй день пытаюсь настроить отправку данных по UART для камня 407vg на плате discovery. Использую USART1 с ножками PB6(TX) и PB7(RX). Тактирование от внешнего кварца. Частота APB2 - 84MHz, соответственно BRR->0x222E.  При заливке прошивки в камень на ПК прилетает один мусорный байт и большей ничего не происходит, при ресете МК соответственно опять прилетает один мусорный байт. Пробовал подключать через USART2, там дела обстоят чуть лучше. Байты отправляются, но в виде мусора. Притом, отправлял разные символы(почти все цифры и буква алфавита) но код на терминали был либо 0xDF либо 0xFF.
      /******************************************************************************/ /* LYBRARY */ /******************************************************************************/ #include "stm32f4xx.h" /******************************************************************************/ /* USE FUNCTION */ /******************************************************************************/ void InitGPIO (void); void InitRCC(void); void InitUSART2(void); void delay (uint32_t time); /******************************************************************************/ /* MAIN */ /******************************************************************************/ int main (void){ InitGPIO (); InitRCC(); InitUSART2(); while (1){ GPIOD->BSRR |= GPIO_BSRR_BS15; while(!(USART1->SR & USART_SR_TC)); USART1->DR = 'h'; delay(200000000); GPIOD->BSRR |= GPIO_BSRR_BR15; delay(200000000); } } /******************************************************************************/ /* InitGPIO */ /******************************************************************************/ void InitUSART2(void){ RCC->APB2ENR |= RCC_APB2ENR_USART1EN; RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN; GPIOB->MODER &= ~GPIO_MODER_MODER6_0; GPIOB->MODER |= GPIO_MODER_MODER6_1; GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR6; GPIOB->OTYPER &= ~GPIO_OTYPER_OT_6; GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6; GPIOB->AFR[0] |= 0x00000700; GPIOB->MODER &= ~GPIO_MODER_MODER7; GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR7; GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7; USART1->BRR = 0x0000222E; USART1->CR1 |= USART_CR1_UE; USART1->CR1 |= USART_CR1_TE; USART1->CR1 |= USART_CR1_RE; USART1->CR1 |= USART_CR1_RXNEIE; NVIC_EnableIRQ(USART1_IRQn); } void InitRCC(void){ RCC->CR |= ((uint32_t)RCC_CR_HSEON); while (!(RCC->CR & RCC_CR_HSERDY)); FLASH->ACR = (FLASH_ACR_PRFTEN | FLASH_ACR_LATENCY| FLASH_ACR_ICEN | FLASH_ACR_DCEN); RCC->CFGR |= RCC_CFGR_HPRE_DIV1; RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; RCC->CFGR &= ~RCC_PLLCFGR_PLLSRC; RCC->CFGR &= ~RCC_PLLCFGR_PLLM; RCC->CFGR &= ~RCC_PLLCFGR_PLLN; RCC->CFGR &= ~RCC_PLLCFGR_PLLP; RCC->CFGR |= RCC_PLLCFGR_PLLSRC_HSE; RCC->CFGR |= RCC_PLLCFGR_PLLM_4; RCC->CFGR |= (RCC_PLLCFGR_PLLN_7 | RCC_PLLCFGR_PLLN_5 | RCC_PLLCFGR_PLLN_3); RCC->CR |= RCC_CR_PLLON; while((RCC->CR & RCC_CR_PLLRDY) == 0) {} RCC->CFGR &= ~RCC_CFGR_SW; RCC->CFGR |= RCC_CFGR_SW_PLL; while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_1) {} } void InitGPIO (void) { RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; GPIOD->MODER |= GPIO_MODER_MODE15_0; GPIOD->OTYPER &=~ GPIO_OTYPER_OT15; GPIOD->OSPEEDR |= GPIO_OSPEEDR_OSPEED15_0; GPIOD->MODER |= GPIO_MODER_MODE14_0; GPIOD->OTYPER &=~ GPIO_OTYPER_OT14; GPIOD->OSPEEDR |= GPIO_OSPEEDR_OSPEED14_0; GPIOD->MODER |= GPIO_MODER_MODE13_0; GPIOD->OTYPER &=~ GPIO_OTYPER_OT13; GPIOD->OSPEEDR |= GPIO_OSPEEDR_OSPEED13_0; GPIOD->MODER |= GPIO_MODER_MODE12_0; GPIOD->OTYPER &=~ GPIO_OTYPER_OT12; GPIOD->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR15_0; } void delay(uint32_t time){ uint32_t i; for (i=0; i<time;i++); }  

  • Сообщения

    • Да ну! Правда? Вот и занялся бы вместо полной дури шамана и СССР.
    • Почему на выходе , между выпрямителем и конденсатором отсутствует дроссель ?  Электролиту 47мкФ/100В вскорости поплохеет от пульсаций , по сути он сейчас работает как "нагрузка". Выход надо немного нагрузить резистором , рассчитать или подобрать его номинал , чтобы ток потребления резистором , был около 100мА , тогда напряжение на выходе в холостую не будет завышаться.
    • Щёткой по металлу почистить, если дело в окисленных ножках. У меня целая куча 6Н2П шубуршала и даже 6Н2П-ЕВ попались. У меня лампы очень старые 1960-х годов и б.у. Сейчас всё нормально, тоже с шорохами возился.
    • схема работает в железе прекрасно! собрал где то в марте, пользую каждый день, ни разу не подводил этот БП.
    • Иван, это Вы с сарказмом сказали?)))  Кстати, я так понимаю Вы разобрались с причиной фона? Что там было!?
    • Сначала  надо посчитать во сколько обойдётся это удовольствие при самостоятельной сборке и если купить. Вот цена на вскидку у нас в Перми: Зато никакой головной боли. Сейчас материалы где - то взять надо. Детали не купить, всё надо выписывать. Ладно если в крупном городе живёте и магазины есть.
    • Если это стандартный монитор, то проще купить другой. У нас например на "Авито" цена от 1000руб до 1500 руб. всего. А детали выписать, за одну доставку от 300 руб. до 1000 руб., хотя детали и недорогие. В нашем городе не купишь.  А с таким опытом ремонта можно после замены и "бах" получить. Вот объявление компьютерного комиссионного магазина у нас в городе: Даже можно плату с другого под свои напряжения подобрать. Делаю так постоянно, дешевле получается.
×
×
  • Create New...