STM32 новичку в ARM что к чему
- Реклама
- Сообщения: 55
- Зарегистрирован: Чт окт 18, 2018 23:58:43
Всем привет!
Подскажите по такому вопросу.
В даташите на ethernet модуль, написано что минимальный период CLK SPI = 100ns. Это значит максимальная частота SPI = 10Мгц.
В настройках SPI у МК stm32f103 задаётся скорость в Мбит как кратная частоте МК.
Но ведь один период CLK составляет 2 тика: 1 и 0. А значит частота аппаратного SPI в МК должна быть выше.
Вопрос такой: всё же, как их сопоставить?
Подскажите по такому вопросу.
В даташите на ethernet модуль, написано что минимальный период CLK SPI = 100ns. Это значит максимальная частота SPI = 10Мгц.
В настройках SPI у МК stm32f103 задаётся скорость в Мбит как кратная частоте МК.
Но ведь один период CLK составляет 2 тика: 1 и 0. А значит частота аппаратного SPI в МК должна быть выше.
Вопрос такой: всё же, как их сопоставить?
- Сообщения: 2411
- Зарегистрирован: Ср фев 23, 2011 12:12:31
1 бит передаётся при полном периоде клока. А значит 10Мбит будут соответствовать периоду клока в 100нс или 10Мгц.
То есть 1 к 1.
То есть 1 к 1.
Глупый не задает вопросы. Глупый и так все знает.
- Сообщения: 6457
- Зарегистрирован: Пт сен 13, 2013 13:11:31
[uquote="STARпёр",url="/forum/viewtopic.php?p=3565896#p3565896"]Но ведь один период CLK составляет 2 тика: 1 и 0. А значит частота аппаратного SPI в МК должна быть выше.[/uquote]
Не плодите сущности. Частота и период взаимно обратные величины: F = 1/T и T = 1/F, где Т -- период, а F -- частота.
Не плодите сущности. Частота и период взаимно обратные величины: F = 1/T и T = 1/F, где Т -- период, а F -- частота.
Вопрос очередной... Больше по языку Си наверное.
Вот если есть обработчик прерывания, то выход из него как правильно делать? Надо слово return? Или он будет косячить со стеком?
Что если мне по условию надо выйти раньше из прерывания?
Вот если есть обработчик прерывания, то выход из него как правильно делать? Надо слово return? Или он будет косячить со стеком?
Что если мне по условию надо выйти раньше из прерывания?
Станислав
- Реклама
- Сообщения: 2089
- Зарегистрирован: Вс июн 19, 2016 09:32:03
[uquote="СКАЗОЧНИК",url="/forum/viewtopic.php?p=3566193#p3566193"]Что если мне по условию надо выйти раньше из прерывания?[/uquote]
Обработчик прерывания на кортексах - это обычная функция, единственное что если код на С++, то может потребоваться extern "C", но и этого можно избежать если стартап тоже будет на плюсах.
Обработчик прерывания на кортексах - это обычная функция, единственное что если код на С++, то может потребоваться extern "C", но и этого можно избежать если стартап тоже будет на плюсах.
Спасибо. )
Еще маленький.
Если мне надо в условии проверить 4 бита в порту (в регистре) на то, что они установлены. Можно сделать это одним махом? Или надо сначала переменную завести, потом в нее скопировать содержимое этого регистра, а потом уже сравнивать с каким-то значением?
Просто моя конструкция типа такой:
if (GPIOA->ODR & 0x0F)
нифига не хочет работать. Она истинна в любом случае, если в порту не ноль. А мне надо, чтобы истина была только когда первые 4 бита установлены...
Еще маленький.
Если мне надо в условии проверить 4 бита в порту (в регистре) на то, что они установлены. Можно сделать это одним махом? Или надо сначала переменную завести, потом в нее скопировать содержимое этого регистра, а потом уже сравнивать с каким-то значением?
Просто моя конструкция типа такой:
if (GPIOA->ODR & 0x0F)
нифига не хочет работать. Она истинна в любом случае, если в порту не ноль. А мне надо, чтобы истина была только когда первые 4 бита установлены...
Станислав
if (GPIOA->ODR & 0x000F == 0x000F) не подойдёт?
Блин. Решение простое и гениальное. )) Его тоже запомню.
Но, боюсь, чутка не то. Т.к. остальные биты в регистре могут тоже не равняться нулю. А мне нужно проверить только первые 4 бита.
Добавлено after 48 seconds:
Ой! Он же будет результат сравнивать! А там как раз уже отфильтрует все. Простите.
Добавлено after 35 seconds:
Все. Это то, что надо! Спасибо. Здоровья вам!
Добавлено after 2 minutes 13 seconds:
З.Ы. ))) Моя программа все равно не работает.
Добавлено after 1 minute 12 seconds:
Вот так надо!
if ((GPIOA->ODR & 0x0F) == 0x0F)
Но, боюсь, чутка не то. Т.к. остальные биты в регистре могут тоже не равняться нулю. А мне нужно проверить только первые 4 бита.
Добавлено after 48 seconds:
Ой! Он же будет результат сравнивать! А там как раз уже отфильтрует все. Простите.
Добавлено after 35 seconds:
Все. Это то, что надо! Спасибо. Здоровья вам!
Добавлено after 2 minutes 13 seconds:
З.Ы. ))) Моя программа все равно не работает.
Добавлено after 1 minute 12 seconds:
Вот так надо!
if ((GPIOA->ODR & 0x0F) == 0x0F)
Станислав
Где-то прочитал, что если по умолчанию включить СисТик таймер, то в его настройки будут при частоте 72 МГц такие, что один круг счета таймера = 1 мс. Вчера с ним игрался.
Так вот, в документации не увидел нигде значение в регистре STK_LOAD типа 9000 или 8999. Они по умолчанию равны нулю.
Ладно, это мелочи.
Также значение его счета (круга) не точное... Сделав настройки МК работать от внешнего резонатора с ФАПЧ в 72 МГц, а тактирование таймера от шины АНВ/8. По моим подсчетам 1 тик таймера = 1 / 9 МГц = 111 нс. Умножаем это на 9000 в счетном регистре, которое мы туда грузим, получается 999000 нс = 999 мкс = 0,9 мс. А это не точно 1 мс.
Т.к. регистр счетный 24 битный, то туда можно загрузить довольно большое число. Я загрузил 9000000 (точнее по рекомендациям документов 8999999) и получил счет таймера в 1 секунду. Ну, почти.
Так вот, в документации не увидел нигде значение в регистре STK_LOAD типа 9000 или 8999. Они по умолчанию равны нулю.
Ладно, это мелочи.
Также значение его счета (круга) не точное... Сделав настройки МК работать от внешнего резонатора с ФАПЧ в 72 МГц, а тактирование таймера от шины АНВ/8. По моим подсчетам 1 тик таймера = 1 / 9 МГц = 111 нс. Умножаем это на 9000 в счетном регистре, которое мы туда грузим, получается 999000 нс = 999 мкс = 0,9 мс. А это не точно 1 мс.
Т.к. регистр счетный 24 битный, то туда можно загрузить довольно большое число. Я загрузил 9000000 (точнее по рекомендациям документов 8999999) и получил счет таймера в 1 секунду. Ну, почти.
Станислав
[uquote="СКАЗОЧНИК",url="/forum/viewtopic.php?p=3566404#p3566404"]в документации не увидел нигде значение в регистре STK_LOAD типа 9000 или 8999. Они по умолчанию равны нулю.[/uquote]если совсем не трогать - да, нули. Он инициализируется в sysinit. SysTick с периодом 1мс - негласный де-факто стандарт, а не нечто прям технически обязательное.
Почему-то не хочет запускаться этот код:
Батарейку на своей плате БлюПилл подключил, точнее, не батарейку, а кинул на 3.3 В проводок и на Vbat.
Смотрю в отладчике, а у меня все четко, все включается кроме одного, в регистр RTC_PRLL не записывается константа 0x7FFF. Вот в счетный регистр записывается, а в этот игнор. Ноль как был, так и остался.
И счтитать потом начинает не декрементом, а инкрементом. Т.е. К начальному значению 0x7FFF прибавляет по единице каждый раз.
Как должно понять не могу. В описании РМ0008 искал, какой это регистр и как работает, но там про это не увидел.
З.Ы. и еще вопросик. Чтобы организовать прерывание от RTC надо уже про NVIC читать? Потому что СисТик прерывания работают сами, что вполне удобно. )
Спойлер
Код: Выделить всё
//======== 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 ===========
Смотрю в отладчике, а у меня все четко, все включается кроме одного, в регистр RTC_PRLL не записывается константа 0x7FFF. Вот в счетный регистр записывается, а в этот игнор. Ноль как был, так и остался.
И счтитать потом начинает не декрементом, а инкрементом. Т.е. К начальному значению 0x7FFF прибавляет по единице каждый раз.
З.Ы. и еще вопросик. Чтобы организовать прерывание от RTC надо уже про NVIC читать? Потому что СисТик прерывания работают сами, что вполне удобно. )
Станислав
Снова - этот регистр только на запись. Прочитать, что было записано - невозможно.
прерывание:
прерывание:
Код: Выделить всё
....
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 раз.
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
Так я же не читаю... Я думал, его может отладка показывать...
А счет в счетном регистре RTC_CNT в какую сторону должен идти?
Почему туда записывают то число, которое по сути надо вычитать, чтобы получить секундные интервалы?
Где описана эта функция? NVIC_EnableIRQ(RTC_IRQn) А то может у меня не все библиотеки подключены...
А счет в счетном регистре RTC_CNT в какую сторону должен идти?
Почему туда записывают то число, которое по сути надо вычитать, чтобы получить секундные интервалы?
Где описана эта функция? NVIC_EnableIRQ(RTC_IRQn) А то может у меня не все библиотеки подключены...
Станислав
Увы, раз регистр не читается, то и отладка его не показывает. RTC_CNT считает вперед, разумеется.
Для секундных "интервалов" надо записывать в RTC_PRLL. При этом RTC_DIV считает назад. Т.е. записали PRLL получили секундные импульсы, которые уже "тикают" RTC_CNT. Вперед.
NVIC_EnableIRQ, DisableIRQ, SetPriority итд - это стандартные CMSISовские подстановки, чтобы не вычислять ручками биты итп. У моего кейла, говорит, что в core_cm3.h. Но абсолютно так же я эту "функцию" пользую в MSP432.
Для секундных "интервалов" надо записывать в RTC_PRLL. При этом RTC_DIV считает назад. Т.е. записали PRLL получили секундные импульсы, которые уже "тикают" RTC_CNT. Вперед.
NVIC_EnableIRQ, DisableIRQ, SetPriority итд - это стандартные CMSISовские подстановки, чтобы не вычислять ручками биты итп. У моего кейла, говорит, что в core_cm3.h. Но абсолютно так же я эту "функцию" пользую в MSP432.
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
Т.е. Счетчик считает с интервалом в 1 секунду вперед. А секундные прерывания приходят не от него совсем.
Спасибо!
Спасибо!
Станислав
Секундные приходят по факту update. и включаются там: RTC->CRH = RTC_CRH_SECIE; Там же можно включить прерывание по будильнику и переполнению (а вот оно нафик нужно? 136 лет спустя?).
Только есть один маленький нюанс, что прерывание происходит по перезагрузке RTC_DIV, а изменение RTC_CNT происходит спустя 1/32768 секунды.
https://radiokot.ru/forum/viewtopic.php ... 1#p3522221 <- тут я хвастался своими часиками на синей таблетке. счетчик CNT нужен, так как он работает от резервной батарейки. Хотя, можно просто читать его по включению, а дальше по прерываниям. Но мне нравится всегда использовать первичные данные, а не косвенные.
Только есть один маленький нюанс, что прерывание происходит по перезагрузке RTC_DIV, а изменение RTC_CNT происходит спустя 1/32768 секунды.
https://radiokot.ru/forum/viewtopic.php ... 1#p3522221 <- тут я хвастался своими часиками на синей таблетке. счетчик CNT нужен, так как он работает от резервной батарейки. Хотя, можно просто читать его по включению, а дальше по прерываниям. Но мне нравится всегда использовать первичные данные, а не косвенные.
Последний раз редактировалось uldemir Вс фев 10, 2019 11:28:54, всего редактировалось 2 раза.
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
У меня мозги так сильно не соображают. И по сути для меня использование часов реального времени и сводится к тому, чтобы организовать точные секундные интервалы по прерыванию. А там уже обрабатывай как хочешь. Да и то, что в Счетном регистре таймера все происходит с задержкой тоже не принципиально, потому что я его вроде как и не использую... И пока не придумал, куда его можно применить вообще. Тем паче, что он еще и разбит на два 16 битных.
Добавлено after 31 minute 53 seconds:
З.Ы. Целый день тупил, почему у меня не работает прерывание... А оказывается внимательным надо быть и всего лишь.
RTC_IRQHandler
RCC_IRQHandler
Добавлено after 9 minutes 39 seconds:
Теперь другие чудеса. ) Выдергиваю питания от батарейки. Перезагружаю МК. А он один хрен запускается и начинает обрабатывать это прерывание, причем как и настроил 1 раз в секунду... Проверил мультиметром, на выводе куда батарею надо подключать всего 0,2 В.
В отладке в прерывание не заходит... Не знаю как проверить в отладке все это, но настраивается все как и раньше очень даже хорошо. Выполняет код, но в прерывание в отладке ниразу не зашел. Хотя все пашет.
Или после того, как МК ушел в главный цикл, отладка больше не работает?
Добавлено after 59 seconds:
Да, нет. Работает проверил. Светодиоды на плате не моргают. Ждет прерывания. Но в отладке туда заходить не хочет.
Добавлено after 31 minute 53 seconds:
З.Ы. Целый день тупил, почему у меня не работает прерывание... А оказывается внимательным надо быть и всего лишь.
RTC_IRQHandler
RCC_IRQHandler
Добавлено after 9 minutes 39 seconds:
Теперь другие чудеса. ) Выдергиваю питания от батарейки. Перезагружаю МК. А он один хрен запускается и начинает обрабатывать это прерывание, причем как и настроил 1 раз в секунду... Проверил мультиметром, на выводе куда батарею надо подключать всего 0,2 В.
В отладке в прерывание не заходит... Не знаю как проверить в отладке все это, но настраивается все как и раньше очень даже хорошо. Выполняет код, но в прерывание в отладке ниразу не зашел. Хотя все пашет.
Или после того, как МК ушел в главный цикл, отладка больше не работает?
Добавлено after 59 seconds:
Да, нет. Работает проверил. Светодиоды на плате не моргают. Ждет прерывания. Но в отладке туда заходить не хочет.
Станислав
У меня тоже поначалу были проблемы с написанием. Так вот, если пройтись по дефинициям, то в файле stm32f103xb.h есть typedef enum IRQn_Type. Вот эти enumы и надо поставлять в функции NVIC_. И они же, заменив "n" на конце на Handler, являются названиями обработчиков.
Моя инициализация RTC.Чтобы моргал светодиод надо PC13 настроить на вывод.
Моя инициализация 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);
}А люди посмотрят и скажут: "Собаки летят. Вот и осень."
Да. у меня работает. У меня на одном порту висит 8 светодиодов, которые в двоичном коде показывают счет. Инкремент происходит порта при каждом прерывании. Сначала настроил от СисТик таймера. Но потом интереснее стало от Часов реального времени.
С отладчиком разобрался. Ему просто, чтобы натикать целую секунду при нажатой F11 надо очень долго ждать....
Остались небольшие непонятки с настройкой Бэкап домена без питания от батареи. Т.е. вообще без питания.
Пока плату лапал, все таки повис. )))))))
Добавлено after 6 minutes 51 second:
И как в отладке можно быстрее сделать, чтобы дождаться прерывания не через 10 лет????
С отладчиком разобрался. Ему просто, чтобы натикать целую секунду при нажатой F11 надо очень долго ждать....
Остались небольшие непонятки с настройкой Бэкап домена без питания от батареи. Т.е. вообще без питания.
Добавлено after 6 minutes 51 second:
И как в отладке можно быстрее сделать, чтобы дождаться прерывания не через 10 лет????
Последний раз редактировалось СКАЗОЧНИК Вс фев 10, 2019 12:09:43, всего редактировалось 1 раз.
Станислав


