Jump to content
john2103

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

Recommended Posts

Posted (edited)
8 часов назад, john2103 сказал:

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

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

Боже что за бред...

Посмотрите вначале NarodSream у него как раз последние темы про SPI в 103C8. В уроках он все грамотно рассказывает, вначале посмотрите видео, поучитесь. И если ты так будешь писать на CMSIS, то мой тебе совет используй HAL. 

Edited by MasterElectric

Share this post


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

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

Когда используешь перывния и так идет непрерывная передача, хоть по 8, хоть по 16 (кроме особых случаев)

Немного офтоп. Конечно Ваш ответ, просто лучший! Хоть кто то помог! Какие прерывания? dma? по завершению приема? передачи ? что значит непрерывная? Просто включил прерывание и все само волшебным образом передается? Если вы хотели помочь, то информативность Вашего сообщения 0! Если поиздеваться, то зачем, я не говорю что я ас! 

И я читал RF, но мне тяжело, темболее на английском, вот и смотрел попутный материал, где был

Share this post


Link to post
Share on other sites
Posted (edited)

@john2103 Ок, тогда вопрос зачем переключать с 8 на 16 какая цель?

@john2103Я ж и пишу посмотри NarodSream, последние уроки, там поток данных от мастера непрерывный, так как тебе и нужно реализовать. Говорят он сансей по МК в русском сегменте ютуба уроков уже больше сотни.

Edited by MasterElectric

Share this post


Link to post
Share on other sites

Технология Maxim Integrated nanoPower: когда малый IQ имеет преимущества

При разработке устройств с батарейным питанием важно выбирать компоненты не просто с малым потреблением, но и с предельно малым током покоя. При этом следует обратить внимание на линейку nanoPower производства компании Maxim Integrated. В статье рассмотрено их применение на примере системы датчиков беспроводной оконной сигнализации.

Подробнее

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

@john2103 Ок, тогда вопрос зачем переключать с 8 на 16 какая цель?

в самом начале топика озвучил! Изучаю! Можно так сделать или нет? Судя по всему прочитанному, это можно сделать, по факту не получилось! Стало просто интересно, этого вообще сделать нельзя или я что то не то делаю. Если есть опыт подскажите, буду очень благодарен. На практике я бы нашел рабочее решение, более простое, но тут чисто интерес, можно или нет

9 минут назад, MasterElectric сказал:

@john2103 Ок, тогда вопрос зачем переключать с 8 на 16 какая цель?

@john2103Я ж и пишу посмотри NarodSream, последние уроки, там поток данных от мастера непрерывный, так как тебе и нужно реализовать. Говорят он сансей по МК в русском сегменте ютуба уроков уже больше сотни.

Его уроки, я все давно пересмотрел и не по одному разу, но если ты заметил, он использует hal и ll. А я говорю про cmsis.

Share this post


Link to post
Share on other sites

для того чтобы использовать прерывания в SPI нужно чтобы объем данных был существенным, а передавать 4 байта прерываниями нет смысла. А если передаем буфер зачем переключать битность? поток и так непрырывный при использовании прерываний.

Share this post


Link to post
Share on other sites
                     

Платы Nucleo на базе STM32G0: чего можно добиться с помощью связки Nucleo и Arduino

Платы Nucleo и платы расширения X-NUCLEO от STMicroelectronics можно интегрировать в платформу Arduino с помощью библиотеки STM32duino. Связка плат Nucleo и платформы Arduino, и наличие готовых библиотек – представляет удобный инструмент для создания прототипов и конечных приложений в условиях ограниченного времени. Статья содержит пошаговые инструкции по установке библиотек и запуску примеров для Nucleo.

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

28 минут назад, MasterElectric сказал:

И если ты так будешь писать на CMSIS, то мой тебе совет используй HAL. 

В чем проблема с моим cmsis, что я делаю не так?

Share this post


Link to post
Share on other sites
Posted (edited)

@john2103 В этом:

	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;		 // --- Фаза тактового сигнала

я такое вижу впервые...

@MasterElectric Смотри как бы сделал я. Выдели ногу для тестового сигнала и момент когда ты переключаешь битность дерни ногой и посмотри потом что покажет ЛА.

Edited by MasterElectric

Share this post


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

для того чтобы использовать прерывания в SPI нужно чтобы объем данных был существенным, а передавать 4 байта прерываниями нет смысла. А если передаем буфер зачем переключать битность? поток и так непрырывный при использовании прерываний.

А если я сейчас для примера возьму и изменю объем массива на 300 элементов 1000 или еще больше??? Это что изменить? У вас появиться решение? Я понял, на счет битности и согласен, что битф все равно идут подрят, ну предположим, вот задачу поставили именно так, реализовать именно смену битности! Вы можете, что подсказать конкретное по этому поводу?

Share this post


Link to post
Share on other sites

@john2103 Если есть время попробуй то что я предложил и покажите что там будет решение я вам дам. Сам занимаюсь SPI только на L0

Share this post


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

 

я такое вижу впервые...

Развернутые коментарии??? Так это я для себя, что бы запомнить какие регистры, какие биты, как называются, для чего служат!

 

10 минут назад, MasterElectric сказал:

 

@MasterElectric Смотри как бы сделал я. Выдели ногу для тестового сигнала и момент когда ты переключаешь битность дерни ногой и посмотри потом что покажет ЛА.

А за этот совет, спасибо, обязательно попробую!

Edited by john2103

Share this post


Link to post
Share on other sites

Доброго времени суток, товарищи! Для тех, кому все же интересно! Наконец добрался до компа и провел тесты. Можно сказать выяснил в чем проблема... (но все же это условно). По совету @MasterElectric добавил несколько контрольных пинов и с помощью ЛА отслеживал изменения. Весь перечень того что делал не привожу, нет смысла, самое интересно:

#define A0_true  GPIOA->BSRR |= GPIO_BSRR_BS0
#define A0_false  GPIOA->BSRR |= GPIO_BSRR_BR0

#define A1_true  GPIOA->BSRR |= GPIO_BSRR_BS1
#define A1_false  GPIOA->BSRR |= GPIO_BSRR_BR1

#define A2_true  GPIOA->BSRR |= GPIO_BSRR_BS2
#define A2_false  GPIOA->BSRR |= GPIO_BSRR_BR2

#define A3_true  GPIOA->BSRR |= GPIO_BSRR_BS3
#define A3_false  GPIOA->BSRR |= GPIO_BSRR_BR3

#define A4_true  GPIOA->BSRR |= GPIO_BSRR_BS4
#define A4_false  GPIOA->BSRR |= GPIO_BSRR_BR4

.........

void SPI1_STM32F1_write_8bit_irq(uint8_t *data, int32_t len_8bit)
{
A1_true;
	
	if(len_8bit<=0)
    return;
A4_true;
	while(SPI1->SR & SPI_SR_BSY)
	;
A4_false;

A3_true;
	  SPI1->CR1 &= ~SPI_CR1_SPE;
		
A0_true;
		SPI1->CR1 &= ~SPI_CR1_DFF;
A0_false;
		
      SPI1->CR1 |= SPI_CR1_SPE;
A3_false;
		
		flag =0;
		tx_index_8_bit = 0;
		tx_len_8_bit = len_8bit;
		tx_data_8_bit = data;
		SPI1->CR2 |= SPI_CR2_TXEIE; 

A1_false;		
}

void SPI1_STM32F1_write_16bit_irq(uint16_t *data, int32_t len_16bit)
{
A2_true;

	if(len_16bit<=0)
    return;
		
	A4_true;
		while(SPI1->SR & SPI_SR_BSY)
			;
	A4_false;
		
		

		
A3_true;
		SPI1->CR1 &= ~SPI_CR1_SPE;
	
      A0_true;
		SPI1->CR1 |= SPI_CR1_DFF;
	  A0_false;

		SPI1->CR1 |= SPI_CR1_SPE;
A3_false;

		flag =1;
		tx_index_16_bit = 0;
		tx_len_16_bit = len_16bit;
		tx_data_16_bit = data;
		SPI1->CR2 |= SPI_CR2_TXEIE; 

A2_false;

}

A1_true / A1_false - Начало / конец Передачи 8 бит

A2_true / A2_false - Начало / конец Передача 16 бит

A4_true / A4_false - Ожидание флага BSY

A3_true / A3_false - Откл SPE =0,  Вкл SPE = 1

A0_true / A0_false - Включение (или отключение ) бита DFF

  При том коде, что записан выше, интересны флаги A4_false, A0_false и A3_false, относительно последнего CLOCKа! Видно что BSY срабатывает, когда реально еще идет "крайний CLOCK", происходит смена бита DFF(еще время уходит на переключение флага A3_true) и заканчивается раньше чем крайний КЛОК, но при этом включение SPE = 1 происходит после него. (А1 - А2 А самое главное более 0,25 мкс после "крайнего клока") и код работает как надо, никаких лишних передач!

1.thumb.jpg.e0cc0876b83b20111d03a50b2c8d1322.jpg

Если убрать флаги переключения DFF, но при этом оставить включение и отключение SPI (SPE = 0, SPE = 1), то получим:

....  

     A3_true;
SPI1->CR1 &= ~SPI_CR1_SPE;
//        A0_true;
SPI1->CR1 &= ~SPI_CR1_DFF;
//        A0_false;

SPI1->CR1 |= SPI_CR1_SPE;
        A3_false;
.....

A3_true;
SPI1->CR1 &= ~SPI_CR1_SPE;
//        A0_true;
SPI1->CR1 |= SPI_CR1_DFF;
//        A0_false;

SPI1->CR1 |= SPI_CR1_SPE;
        A3_false;

.....

Несмотря на смену DFF при отключенном модуле (SPE = 0), время выполнения откл SPI смены DFF и вкл SPI меньше чем выполнение крайнего клока. (Есть ненужная передача 0x00) Предыдущий код работал потому что переключение флагов, вносило своего рода задержки. Когда я убрал эти переключения, время на выполнение всех операций сократилось и стало меньше чем окончание передачи. Поэтому и пошли ошибки. 

3.thumb.jpg.c899d67374bd49a4b563c976cfa4cc0e.jpg

 

После этого я закоментил строки:
 

//A3_true;
//SPI1->CR1 &= ~SPI_CR1_SPE; 

....

//SPI1->CR1 |= SPI_CR1_SPE;

//A3_false;

Видно, что бит DFF меняется во время крайнего КЛОКА, отключение SPI вообще не происходит, есть лишний бит 0x00. 

2.thumb.jpg.25244384217d02ef7c9f8780a3fa4cf5.jpg

После этого я просто добавил несколько __NOP(); перед сменой DFF. (Экспериментально, я нашел), что бы пропала лишня передача 0х00 и код стал правильно работать, смена DFF должна заканчиваться через ~0,25 мкс после крайнего клока, что бы все правильно работало (При том что сам модуль я не отключаю SPE =1 и я его не трогаю)

void SPI1_STM32F1_write_8bit_irq(uint8_t *data, int32_t len_8bit)
{
        A1_true;
    
    if(len_8bit<=0)
    return;
  
    
        A4_true;
        while(SPI1->SR & SPI_SR_BSY)
            ;
        A4_false;
__NOP();        __NOP();     __NOP();      __NOP();       __NOP();     __NOP();   __NOP();  __NOP();       __NOP();      __NOP();        

.....

.....

__NOP();        __NOP();      __NOP();      __NOP();    __NOP();       __NOP();     __NOP();   __NOP();   __NOP();  __NOP();        
            
//        A3_true;
//SPI1->CR1 &= ~SPI_CR1_SPE;
//        
        A0_true;
SPI1->CR1 &= ~SPI_CR1_DFF;
        A0_false;

//SPI1->CR1 |= SPI_CR1_SPE;
//        A3_false;
        
        flag =0;
        tx_index_8_bit = 0;
        tx_len_8_bit = len_8bit;
        tx_data_8_bit = data;
        SPI1->CR2 |= SPI_CR2_TXEIE; 

    A1_false;        
}

4.thumb.jpg.46bc764d34cb3a14122b5e9f1716dbbd.jpg

Как видно, все работает правильно, никаких лишних передач нет, все работает как надо. При этом сам модуль я не отключал (SPE =1 и я его не трогал).

ИТОГИ:

На самом деле было много экспериментов, я рассказал об основном. Сделать вывод можно такой.... Битность "на лету" менять можно, но смена должна заканчиваться не раньше, чем ~0,25мкс после крайнего тика(всего массива!!!!)! И даже если битность менять, только во время отключения модуля, то включать его тоже нельзя раньше чем ~0,25 мкс после крайнего тика, иначе (чисто моя теория) модуль думает, что до этого он передавал 16 битные данные, 8 передал и надо еще 8. Отсюда и появлялись "лишние" передачи. Вот такая особенность.

Это все было про кварц 8 Мгц, частота ядра 72 Мгц, частота SPI /256

Надеюсь это кому то пригодиться =)  

@MasterElectric Спасибо за совет!

Share this post


Link to post
Share on other sites

Ок тогда дам еще один в BSRR можно просто писать он только для записи. Но я таки смысла так и не понял с этим DFF. Некоторые процессы в модулях происходят на тактовой частоте передачи данных, Например USART передает данные с задержкой в байт после разрешения передатчика лично с этим столкнулся.

Share this post


Link to post
Share on other sites
В 10.06.2019 в 03:09, john2103 сказал:

Битность "на лету" менять можно, но смена должна заканчиваться не раньше, чем ~0,25мкс после крайнего тика

Может не заканчиваться, а начинаться смена битности должна не раньше чем? Так этот период зависит от частоты СПИ-ая?

Какая все таки частота СПИ-ая: что /256? 8МГц?  тогда один такт СПИ значит = 8000/256 => 32 мксек - и получается 0,25мкс больше чем в десять раз меньше чем длительность бита на СПИ-ай?

Share this post


Link to post
Share on other sites
Posted (edited)
В 10.06.2019 в 20:59, MasterElectric сказал:

Ок тогда дам еще один в BSRR можно просто писать он только для записи.

Я знаю, это просто что бы выработать привычку установки нужного бит.  А то потом пропускаю в нужных местах.

В 10.06.2019 в 20:59, MasterElectric сказал:

Например USART передает данные с задержкой в байт после разрешения передатчика 

Опять же, буду знать, когда буду с ним разбираться! Спасибо!

Что касается DFF 

Нас интересует последний клок передачи 8 битного массива:

1.thumb.jpg.2c782b3bdf7823ed1a73c45234c100c8.jpg

Его длительность

5d00d7a6389f3_.jpg.27d4796098c47f06a92b7b40db3116c3.jpg

На следующим скрине, импульс изменения DFF флага:

DFF1.jpg.dcb9e2f01b81db50ef51fda27b9c9948.jpg

Функция передачи при этом имеет вид:

void SPI1_STM32F1_write_16bit_irq(uint16_t *data, int32_t len_16bit)
{
	if(len_16bit<=0)
    return;
		while(SPI1->SR & SPI_SR_BSY)
			;
A3_true;
SPI1->CR1 |= SPI_CR1_DFF;
A3_false;		
		
		flag =1;
		tx_index_16_bit = 0;
		tx_len_16_bit = len_16bit;
		tx_data_16_bit = data;
		SPI1->CR2 |= SPI_CR2_TXEIE; 
}

Как видно изменение бита DFF произошло, раньше чем закончился крайний клок. Это произошло потому, что выбранная мной скорость работы SPI модуля (

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
						

на много меньше, чем скорость работы ядра контроллера.Флаг BSY опускается в 0 раньше, чем SCK опускает линию на крайнем импульсе и программа успевает выполнить смену DFF за это время. Как это видно на рис 3    Длительность этого импульса (3 рисунок) намного меньше чем длительность клока (2 рисунок)  0.5 мкС. 

Если в функцию передачи добавить включение и отключение SPI (SPE = 0 ... SPE = 1) перед и после DFF соответственно, функция будет иметь вид:

void SPI1_STM32F1_write_16bit_irq(uint16_t *data, int32_t len_16bit)
{
if(len_16bit<=0)
    return;
		while(SPI1->SR & SPI_SR_BSY)
			;
	A3_true;
SPI1->CR1 &= ~SPI_CR1_SPE;
SPI1->CR1 |= SPI_CR1_DFF;
SPI1->CR1 |= SPI_CR1_SPE;
	A3_false;		
      	flag =1;
		tx_index_16_bit = 0;
		tx_len_16_bit = len_16bit;
		tx_data_16_bit = data;
		SPI1->CR2 |= SPI_CR2_TXEIE; 
}

На рис 4, видно что длительность увеличилась, но все еще меньше чем конец SCK

SPE0DFF1SPE1.jpg.5a2e75d89cdbf14aee26adafe3019d1c.jpg

Поэтому, все равно есть лишняя передача.

Как только длительность этого импульса выходит за пределы крайнего клока минимум на больше чем 0,25 мкС, все начинает работать правильно.

Как я понял, что бы все работало правильно, изменение DFF не должно начинаться и заканчиваться пока идет клок сигнал (И как видно вкл и откл модуля на это не влияет)

На рисунке 5 показано, когда модуль начинает правильно работать:

5d023bd9b8429_.jpg.035e172ac5d0de29ca9950a64a33db93.jpg

Как видно пропала лишняя передача.

 

В 11.06.2019 в 10:39, ruhi сказал:

тогда один такт СПИ значит = 8000/256 => 32 мксек - и получается 0,25мкс больше чем в десять раз меньше чем длительность бита на СПИ-ай?

Не понял вопроса ?

В 11.06.2019 в 10:39, ruhi сказал:

Какая все таки частота СПИ-ая: что /256? 8МГц?

8Мгц - это внешний кварц который установлен на отладочной плате.

72 Мгц - это частота с которой работает контроллер (с 8 Мгц частота через PLL увеличивается до 72 Мгц) 

/256 - это предделитель выставленный для SPI

Частота работы  SPI 281.25 Кбит/с

Edited by john2103

Share this post


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

Не понял вопроса ?

ну да, как то я коряво сформулировал, но вы все ответили! Вот такую работу с осцилографом я очень люблю и уважаю!

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++); }  

  • Сообщения

    • Последняя попытка избавиться от хлама. BQ24040 2500+шт. За 10500р.
    • Спасибо,хорошо,что не заказал.Тогда 0,25 возьму.Она как раз 0,3 по лаку. А на вторички 0,71 возьму она по лаку 0,79.
    • Я собирал на макете простой ЛБП на TL431и кетайский набор. Сделал в железе  модернизированный ПиДБП и высоковольтный ЛБП по схеме Шелестова. Много времени потратил на улучшение сх. Шелестова и сейчас делаю низковольтный ЛБП по мотивам Шелестова. Из своего опыта и предрассудков могу своим оценочным суждением ранжировать эти схемы по качеству, функциональным возможностям, повторяемости, выбросам и пр.. 1. Самые сырые, кривые и не доработанные ЛБП - на TL431.  TL431 сама по себе склонна к возбудам. а в многокаскадных схемах с ней, охваченных ООС, возбуд гарантирован, на возможность у ЛБП на TL431, хоть какого нибудь запаса устойчивости, у меня нет никаких надежд. Схема на TL431, что я делал, железно была в возбуде при срабатывании канала ограничения тока. Автор посмотрел ее на ослике, и написал, что возбуд также при увеличении выходного тока. Сам автор 5 лет занимался эквилибристикой в симуляторе, без отладки в реале, и честно пишет, что некоторые варианты не рабочие, у некоторых проблемы с повторяемостью. Варианты на TL431 нуждаются в прополке заведомо нерабочих и кривых схем ЛБП, а если какая схема и покажется рабочей,  то ее нужно наладить и проверить, я не помню осциллограм в темах по проверке возбудов и устойчивости. Из гипотетических возможных плюсов для начинающих паяльщиков, у ЛБП на TL431, могло бы быть отсутствие ОУ и БП для них, но в схемах на TL431 стоит отдельная обмотка для питания TL431. Лично я бы не тратил время на TL431. 2. На 2 месте по неинтересности - схема из кетайского набора, впервые была опубликована в 1978г. Выходное напряжение ограничено напряжением питания ОУ. Схему с тех пор никто не измерял и не пытался наладить, все лепят номиналы 1978г. Недавно давал ссылку с аглицкого форума, там народ заметил у этой схемы выбросы 18V, и не очень успешно пытался бороться с этими выбросами. 3. Была схема ПиДБП симуляторного вида на 60V, у меня она называется 60В 6А_dbokov_.pdf. Из минусов у ПиДБП - наличие каскада с ОЭ, который снижает устойчивость и быстродействие ЛБП и отсутствие нормального питания ОУ по минусу, из-за чего нужно ставить тормозные ОУ с однополярным питанием. 4. Самые совершенные варианты ЛБП - сх. Шелестова и множество популярных ЛБП с названиями HY305... HY3010. ЛБП Арктика в данной теме тоже вариант HY3003. Масштабируется на любые вольты, хоть на 1000V. У Шелестова надо выкинуть эммитерные повторители, это сильно улучшит устойчивость, а у всяких схем типа HY30ХХ они уже выкинуты. При использовании приличных ОУ можно получить очень хорошие параметры. Последний мой вариант такого ЛБП, с прекрасной переходной характеристикой и отсутствием выбросов при вкл. и откл. ЛБП - https://forum.cxem.net/index.php?/topic/103115-модернизация-лбп-hy3010/&do=findComment&comment=3219538  Если делать ЛБП по максимуму, то нужно делать коммутатор обмоток и БП для ОУ, который исключит несинхронность подачи и снятия питания с ОУ. Такая несинхронность - основная причина выбросов при вкл. и откл. ЛБП. В моей схеме питания ОУ выбросы при вкл. не возможны, из-за задержки подачи +12V на ОУ, а выбросы при выкл. просто не успевают возникнуть, VT9 закрывает полевик за 10мс, это половина периода 50Гц. Лучшее время закрытия полевика из проектов в инете - 50мс. PS Тут народ недавно пытался улучшить ПиДБП, но результаты грустные https://www.eevblog.com/forum/beginners/lm324-power-supply-with-variable-voltage-and-current/725/  https://www.eevblog.com/forum/projects/linear-lab-power-supply/375/  
    • там колодка с зажимами   написано выход для наушников и все, но китайцы чего угодно могут написать. то есть если узнать, что она для наушников, то может быть как полноценная замена и даже будет лучше? я, конечно, сначала еще попробую lm4610n подключить к усилителю.
×
×
  • Create New...