STM32 новичку в ARM что к чему

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Друг Кота
Аватара пользователя
Сообщения: 4906
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Подвластное:

Изображение
Контактная информация:
Реклама
Открыл глаза
Сообщения: 55
Зарегистрирован: Чт окт 18, 2018 23:58:43

Сообщение STARпёр »

Всем привет!
Подскажите по такому вопросу.
В даташите на ethernet модуль, написано что минимальный период CLK SPI = 100ns. Это значит максимальная частота SPI = 10Мгц.
В настройках SPI у МК stm32f103 задаётся скорость в Мбит как кратная частоте МК.
Но ведь один период CLK составляет 2 тика: 1 и 0. А значит частота аппаратного SPI в МК должна быть выше.
Вопрос такой: всё же, как их сопоставить?
Реклама
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2411
Зарегистрирован: Ср фев 23, 2011 12:12:31

Сообщение AndTer »

1 бит передаётся при полном периоде клока. А значит 10Мбит будут соответствовать периоду клока в 100нс или 10Мгц.
То есть 1 к 1.
Глупый не задает вопросы. Глупый и так все знает.
Друг Кота
Сообщения: 6457
Зарегистрирован: Пт сен 13, 2013 13:11:31

Сообщение a5021 »

[uquote="STARпёр",url="/forum/viewtopic.php?p=3565896#p3565896"]Но ведь один период CLK составляет 2 тика: 1 и 0. А значит частота аппаратного SPI в МК должна быть выше.[/uquote]
Не плодите сущности. Частота и период взаимно обратные величины: F = 1/T и T = 1/F, где Т -- период, а F -- частота.
Реклама
Эиком - электронные компоненты и радиодетали
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

Вопрос очередной... Больше по языку Си наверное.

Вот если есть обработчик прерывания, то выход из него как правильно делать? Надо слово return? Или он будет косячить со стеком?
Что если мне по условию надо выйти раньше из прерывания?
Станислав
Реклама
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="СКАЗОЧНИК",url="/forum/viewtopic.php?p=3566193#p3566193"]Что если мне по условию надо выйти раньше из прерывания?[/uquote]
Обработчик прерывания на кортексах - это обычная функция, единственное что если код на С++, то может потребоваться extern "C", но и этого можно избежать если стартап тоже будет на плюсах.
Реклама
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

Спасибо. )

Еще маленький.
Если мне надо в условии проверить 4 бита в порту (в регистре) на то, что они установлены. Можно сделать это одним махом? Или надо сначала переменную завести, потом в нее скопировать содержимое этого регистра, а потом уже сравнивать с каким-то значением?

Просто моя конструкция типа такой:
if (GPIOA->ODR & 0x0F)
нифига не хочет работать. Она истинна в любом случае, если в порту не ноль. А мне надо, чтобы истина была только когда первые 4 бита установлены...
Станислав
Друг Кота
Аватара пользователя
Сообщения: 4906
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

if (GPIOA->ODR & 0x000F == 0x000F) не подойдёт?
Контактная информация:
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

Блин. Решение простое и гениальное. )) Его тоже запомню. :beer:

Но, боюсь, чутка не то. Т.к. остальные биты в регистре могут тоже не равняться нулю. А мне нужно проверить только первые 4 бита. :dont_know:

Добавлено after 48 seconds:
Ой! Он же будет результат сравнивать! А там как раз уже отфильтрует все. Простите.

Добавлено after 35 seconds:
Все. Это то, что надо! Спасибо. Здоровья вам!

Добавлено after 2 minutes 13 seconds:
З.Ы. ))) Моя программа все равно не работает.

Добавлено after 1 minute 12 seconds:
Вот так надо!

if ((GPIOA->ODR & 0x0F) == 0x0F)
Станислав
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

Где-то прочитал, что если по умолчанию включить СисТик таймер, то в его настройки будут при частоте 72 МГц такие, что один круг счета таймера = 1 мс. Вчера с ним игрался.
Так вот, в документации не увидел нигде значение в регистре STK_LOAD типа 9000 или 8999. Они по умолчанию равны нулю.
Ладно, это мелочи.
Также значение его счета (круга) не точное... Сделав настройки МК работать от внешнего резонатора с ФАПЧ в 72 МГц, а тактирование таймера от шины АНВ/8. По моим подсчетам 1 тик таймера = 1 / 9 МГц = 111 нс. Умножаем это на 9000 в счетном регистре, которое мы туда грузим, получается 999000 нс = 999 мкс = 0,9 мс. А это не точно 1 мс.
Т.к. регистр счетный 24 битный, то туда можно загрузить довольно большое число. Я загрузил 9000000 (точнее по рекомендациям документов 8999999) и получил счет таймера в 1 секунду. Ну, почти.
Станислав
Друг Кота
Сообщения: 3092
Зарегистрирован: Пн апр 06, 2015 11:01:53
Откуда: москва, уфа

Сообщение arkhnchul »

[uquote="СКАЗОЧНИК",url="/forum/viewtopic.php?p=3566404#p3566404"]в документации не увидел нигде значение в регистре STK_LOAD типа 9000 или 8999. Они по умолчанию равны нулю.[/uquote]если совсем не трогать - да, нули. Он инициализируется в sysinit. SysTick с периодом 1мс - негласный де-факто стандарт, а не нечто прям технически обязательное.
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

Почему-то не хочет запускаться этот код:
Спойлер

Код: Выделить всё

//======== Start RTC ===============
	RCC->APB1ENR |= (RCC_APB1ENR_BKPEN|RCC_APB1ENR_PWREN); // ON clock для бэкап и повер 
	PWR->CR |= PWR_CR_DBP; // разрешаем работу в бэкапдомене, установив 1 в ДБП
	RCC->BDCR |= RCC_BDCR_BDRST;     //Сбросить Backup область
	RCC->BDCR &= ~(RCC_BDCR_BDRST);
	RCC->BDCR |= (RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL_LSE);        //Выбрать LSE источник (кварц 32768) и подать тактирование
	RCC->BDCR |= RCC_BDCR_LSEON;   //Включить LSE
	while ((RCC->BDCR & RCC_BDCR_LSERDY) != RCC_BDCR_LSERDY)  //Дождаться включения
	{
	} 
	while (!(RTC->CRL & RTC_CRL_RTOFF))   //проверить закончены ли изменения регистров RTC
	{
	}	
	//while (!(RTC->CRL & RTC_CRL_RSF))   //проверить флаг синхронизации регистров RTC
	//{
	//}			
	RTC->CRL |=  RTC_CRL_CNF; //Разрешить Запись в регистры RTC  
	RTC->CRL &= ~(RTC_CRL_SECF);
	RTC->PRLL = 0x7FFF;
	//RTC->PRLL  = 0x7FFF;   //Настроить делитель на 32768 (32767+1)
	RTC->CNTL  = 0x7FFF;
	
	
	
	
	RTC->CRL &=  ~(RTC_CRL_CNF); //Запретить запись в регистры RTC в этот момент идет обновление регистров
	while (!(RTC->CRL & RTC_CRL_RTOFF)) //Дождаться окончания записи
	{
	}
	RTC->CRL &= ((uint16_t)~RTC_CRL_RSF);  //Синхронизировать RTC (записываем туда ноль)
	while((RTC->CRL & RTC_CRL_RSF) != RTC_CRL_RSF)  //Дождаться синхронизации
	{
	}                  
	PWR->CR &= ~(PWR_CR_DBP);  //запретить доступ к Backup области
	
	RTC->CRH |= RTC_CRH_SECIE;   // Включить прерывания каждую секунду
	
	
	
	
	
//======== END Start RTC ===========
	
Батарейку на своей плате БлюПилл подключил, точнее, не батарейку, а кинул на 3.3 В проводок и на Vbat.
Смотрю в отладчике, а у меня все четко, все включается кроме одного, в регистр RTC_PRLL не записывается константа 0x7FFF. Вот в счетный регистр записывается, а в этот игнор. Ноль как был, так и остался.
И счтитать потом начинает не декрементом, а инкрементом. Т.е. К начальному значению 0x7FFF прибавляет по единице каждый раз. :dont_know: Как должно понять не могу. В описании РМ0008 искал, какой это регистр и как работает, но там про это не увидел.

З.Ы. и еще вопросик. Чтобы организовать прерывание от RTC надо уже про NVIC читать? Потому что СисТик прерывания работают сами, что вполне удобно. )
Станислав
Друг Кота
Аватара пользователя
Сообщения: 7383
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Сообщение uldemir »

Снова - этот регистр только на запись. Прочитать, что было записано - невозможно.

прерывание:

Код: Выделить всё

....
	NVIC_EnableIRQ(RTC_IRQn);
}

// Обработчики прерываний
//
void RTC_IRQHandler(void) {
	static uint32_t tmp;
	do {
		tmp = RTC->CNTH;
		unixtime = ((tmp << 16 ) | RTC->CNTL);
	} while(tmp != RTC->CNTH);
....
	GPIOC->ODR ^= (1 << 13);
}
Последний раз редактировалось uldemir Вс фев 10, 2019 09:58:26, всего редактировалось 1 раз.
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

Так я же не читаю... Я думал, его может отладка показывать... :dont_know:

А счет в счетном регистре RTC_CNT в какую сторону должен идти?
Почему туда записывают то число, которое по сути надо вычитать, чтобы получить секундные интервалы?

Где описана эта функция? NVIC_EnableIRQ(RTC_IRQn) А то может у меня не все библиотеки подключены...
Станислав
Друг Кота
Аватара пользователя
Сообщения: 7383
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Сообщение uldemir »

Увы, раз регистр не читается, то и отладка его не показывает. RTC_CNT считает вперед, разумеется.
Для секундных "интервалов" надо записывать в RTC_PRLL. При этом RTC_DIV считает назад. Т.е. записали PRLL получили секундные импульсы, которые уже "тикают" RTC_CNT. Вперед.

NVIC_EnableIRQ, DisableIRQ, SetPriority итд - это стандартные CMSISовские подстановки, чтобы не вычислять ручками биты итп. У моего кейла, говорит, что в core_cm3.h. Но абсолютно так же я эту "функцию" пользую в MSP432.
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

Т.е. Счетчик считает с интервалом в 1 секунду вперед. А секундные прерывания приходят не от него совсем.

Спасибо!
Станислав
Друг Кота
Аватара пользователя
Сообщения: 7383
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Сообщение uldemir »

Секундные приходят по факту update. и включаются там: RTC->CRH = RTC_CRH_SECIE; Там же можно включить прерывание по будильнику и переполнению (а вот оно нафик нужно? 136 лет спустя?).

Только есть один маленький нюанс, что прерывание происходит по перезагрузке RTC_DIV, а изменение RTC_CNT происходит спустя 1/32768 секунды.

https://radiokot.ru/forum/viewtopic.php ... 1#p3522221 <- тут я хвастался своими часиками на синей таблетке. счетчик CNT нужен, так как он работает от резервной батарейки. Хотя, можно просто читать его по включению, а дальше по прерываниям. Но мне нравится всегда использовать первичные данные, а не косвенные.
Последний раз редактировалось uldemir Вс фев 10, 2019 11:28:54, всего редактировалось 2 раза.
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

У меня мозги так сильно не соображают. И по сути для меня использование часов реального времени и сводится к тому, чтобы организовать точные секундные интервалы по прерыванию. А там уже обрабатывай как хочешь. Да и то, что в Счетном регистре таймера все происходит с задержкой тоже не принципиально, потому что я его вроде как и не использую... И пока не придумал, куда его можно применить вообще. Тем паче, что он еще и разбит на два 16 битных.

Добавлено after 31 minute 53 seconds:
З.Ы. Целый день тупил, почему у меня не работает прерывание... А оказывается внимательным надо быть и всего лишь.

RTC_IRQHandler

RCC_IRQHandler

Добавлено after 9 minutes 39 seconds:
Теперь другие чудеса. ) Выдергиваю питания от батарейки. Перезагружаю МК. А он один хрен запускается и начинает обрабатывать это прерывание, причем как и настроил 1 раз в секунду... Проверил мультиметром, на выводе куда батарею надо подключать всего 0,2 В.

В отладке в прерывание не заходит... Не знаю как проверить в отладке все это, но настраивается все как и раньше очень даже хорошо. Выполняет код, но в прерывание в отладке ниразу не зашел. Хотя все пашет.
Или после того, как МК ушел в главный цикл, отладка больше не работает?

Добавлено after 59 seconds:
Да, нет. Работает проверил. Светодиоды на плате не моргают. Ждет прерывания. Но в отладке туда заходить не хочет.
Станислав
Друг Кота
Аватара пользователя
Сообщения: 7383
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Сообщение uldemir »

У меня тоже поначалу были проблемы с написанием. Так вот, если пройтись по дефинициям, то в файле stm32f103xb.h есть typedef enum IRQn_Type. Вот эти enumы и надо поставлять в функции NVIC_. И они же, заменив "n" на конце на Handler, являются названиями обработчиков.


Моя инициализация RTC.
Спойлер

Код: Выделить всё

void rtc_init(void) {
	uint32_t tmp;
	RCC->APB1ENR |= RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN;
	PWR->CR |= PWR_CR_DBP ; // enable access Backup domain 
// здесь проверяем конфигурацию часового генератора и если есть малейшее отличие
// всё сбрасываем и начинаем по-новой
	if ((RCC->BDCR & (RCC_BDCR_RTCSEL_LSE | RCC_BDCR_RTCEN | RCC_BDCR_LSEON)) != (RCC_BDCR_RTCSEL_LSE | RCC_BDCR_RTCEN | RCC_BDCR_LSEON)) {
		restoreFromBackup();
		RCC->BDCR = RCC_BDCR_BDRST;
		RCC->BDCR = RCC_BDCR_RTCSEL_LSE | RCC_BDCR_RTCEN | RCC_BDCR_LSEON; 
// Poll the LSERDY flag in the RCC_BDCR register
		while ((RCC->BDCR & RCC_BDCR_LSERDY) == 0) continue;
		correction = 0;
		BKP->RTCCR = BKP_RTCCR_CAL & correction;

		while (!(RTC->CRL & RTC_CRL_RTOFF)) continue;
		RTC->CRL |= RTC_CRL_CNF;
		RTC->CNTH = 0x0000u;
		RTC->CNTL = 0x0000u;
		RTC->PRLL = preload;
		RTC->PRLH = 0;
		RTC->CRL &= ~RTC_CRL_CNF;
	}
//	Poll the RSF bit in the RTC_CRL register until the RTC registers are synchronized
	while ((RTC->CRL & RTC_CRL_RSF) == 0) continue;
//	Poll the RTOFF bit in the RTC_CRL register until the last operation on the RTC registers is over
	while ((RTC->CRL & RTC_CRL_RTOFF)== 0) continue;
	RTC->CRH = RTC_CRH_SECIE;
	do {
		tmp = RTC->CNTH;
		unixtime = ((tmp << 16 ) | RTC->CNTL);
	} while(tmp != RTC->CNTH);

/*
		раскомментировать одну из строк, если есть желание на PC13 получить секундные импульсы (скважность 32768!)
		или 1/64 частоты часового кварца. Иначе, там будет перекидываться уровень по прерывания от RTC
		При батарейном питании, этот выход не работает.
*/		
//BKP->RTCCR = (BKP_RTCCR_ASOS | BKP_RTCCR_ASOE);
//BKP->RTCCR = BKP_RTCCR_CCO;
	NVIC_EnableIRQ(RTC_IRQn);
}
Чтобы моргал светодиод надо PC13 настроить на вывод.
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

Сообщение СКАЗОЧНИК »

Да. у меня работает. У меня на одном порту висит 8 светодиодов, которые в двоичном коде показывают счет. Инкремент происходит порта при каждом прерывании. Сначала настроил от СисТик таймера. Но потом интереснее стало от Часов реального времени.
С отладчиком разобрался. Ему просто, чтобы натикать целую секунду при нажатой F11 надо очень долго ждать....

Остались небольшие непонятки с настройкой Бэкап домена без питания от батареи. Т.е. вообще без питания. :shock: Пока плату лапал, все таки повис. ))))))) :)))

Добавлено after 6 minutes 51 second:
И как в отладке можно быстрее сделать, чтобы дождаться прерывания не через 10 лет????
Последний раз редактировалось СКАЗОЧНИК Вс фев 10, 2019 12:09:43, всего редактировалось 1 раз.
Станислав
Ответить

Вернуться в «ARM»