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

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

И чего? Функции HAL_SPI_Receive_DMA на это начхать. Ей дали адрес, она туда положит (или возьмёт). Что по этому адресу ей фиолетово.

volatile должен быть буфер, адрес которого передаётся в функцию.
Реклама
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 363
Зарегистрирован: Вс мар 03, 2019 08:18:34
Откуда: Волгоград

Сообщение do-vitas »

Собрал себе копию Stlink только сам разводил ну и по максимуму вывел все порты! у кого-то подсмотрел что выводят A2 и A3 RX и TX ну и я тоже вывел! ну как говорится про запас! запустил прошил все работает все гуд! но при обновление обратил внимание что прошивка stm8+10! Вопрос такой для чего нужен rx tx и наверно нужна какая-то другая прошивка... не-знаю не сталкивался!
качество монтажа не судите строго трясущимися руками пока лучше не могу да это первое устройство на smd.
Изображение
Реклама
Друг Кота
Сообщения: 6457
Зарегистрирован: Пт сен 13, 2013 13:11:31

Сообщение a5021 »

[uquote="VladislavS",url="/forum/viewtopic.php?p=3894178#p3894178"]И чего? Функции HAL_SPI_Receive_DMA на это начхать.[/uquote]
Это и есть зашквар. А могло быть вполне достойно, случись тамошним индусам добавить volatile.
volatile должен быть буфер, адрес которого передаётся в функцию.
В том виде, как функция нынче объявлена в хале, никто никому ничего не должен. Компилятор нигде не единым варнингом не пискнет, если какой горе-программер под буфер простой массив определит. И все бы поменялось, случись правильно определить параметры функции. Но нет. Любители хала обязаны страдать. И это правильно.
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

По большому счёту, действительно, никто никому ничего не должен. Задача функции передать в контроллер DMA адрес буфера и размер принимаемых данных. Ну и пнуть DMA, наверное. Она успешно делает это без всяких volatile. Где я взял адрес буфера (с генератора случайных чисел, тригонометрическими вычислениями, шифровкой с Нибиру или взял динамически в куче в конце концов) функцию волновать не должно. Как не должно волновать что я с этим буфером делал до, после и даже во время приёма. /dev/null у меня там.
Реклама
Эиком - электронные компоненты и радиодетали
Друг Кота
Сообщения: 6457
Зарегистрирован: Пт сен 13, 2013 13:11:31

Сообщение a5021 »

[uquote="VladislavS",url="/forum/viewtopic.php?p=3894550#p3894550"]По большому счёту, действительно, никто никому ничего не должен. Задача функции передать в контроллер DMA адрес буфера и размер принимаемых данных. Ну и пнуть DMA, наверное. Она успешно делает это без всяких volatile. Где я взял адрес буфера (с генератора случайных чисел, тригонометрическими вычислениями, шифровкой с Нибиру или взял динамически в куче в конце концов) функцию волновать не должно. Как не должно волновать что я с этим буфером делал до, после и даже во время приёма. /dev/null у меня там.[/uquote]
Ваше право выстрелить себе ногу, безусловно, священно, но вожделенные мечтания, чтобы попутно отстрелились еще и яйца -- это все же чутка перебор.

Ставим мысленный эксперимент. Keil, clang 6.14, все варнинги включены:

Изображение

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

Изображение

Итого имеем: передача правильного буфера вызывает возражения компиля, в то время, как передача горбухи проходит на ура. Вы за это? И реверс ситуации простым добавлением volatile к параметру функции вас категорически не устраивает? Хм. Я конечно понимаю, что квалификация порой навязывает танцору довольно специфичные взгляды на жизнь, но зачем же выпячивать?
Вложения
2020-09-19_133528.jpg
(38.37 КБ) 1077 скачиваний
2020-09-19_132828.jpg
(21.03 КБ) 782 скачивания
Реклама
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

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

Я понимаю, что я тупой. Переведите на русский язык пожалуйста эту строку

while ((RCC->BDCR & RCC_BDCR_LSERDY) != RCC_BDCR_LSERDY)

Понятно, что ждет установки флага готовности низкочастотного резонатора, но с позиции Си плохо ее понимаю. Плоховасто доходят до меня структуры, хотя уже много где про них читал...
Станислав
Реклама
Друг Кота
Аватара пользователя
Сообщения: 3386
Зарегистрирован: Пн окт 11, 2010 19:00:08

Сообщение Мурик »

a5021 про приведение типов ничего не слышали?
СКАЗОЧНИК писал(а):while ((RCC->BDCR & RCC_BDCR_LSERDY) != RCC_BDCR_LSERDY)
Ждем пока установится бит RCC_BDCR_LSERDY в RCC->BDCR.
Но это лучше делать с таймаутом. Если не будет "часового" кварца или они неисправен, программа повиснет в этом цикле.
Друг Кота
Аватара пользователя
Сообщения: 4906
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

СКАЗОЧНИК,
Если проследить цепочку макросов (для F103 серии, в моём примере), то получается так:

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

#define PERIPH_BASE     0x40000000UL /*!< Peripheral base address in the alias region */
#define AHBPERIPH_BASE  (PERIPH_BASE + 0x00020000UL)
#define RCC_BASE        (AHBPERIPH_BASE + 0x00001000UL)
#define RCC             ((RCC_TypeDef *)RCC_BASE)
То есть, RCC_BASE - это просто число 0x40021000UL
А RCC - это указатель на структуру RCC_TypeDef, равный 0x40021000
Дальше,

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

typedef struct
{
  __IO uint32_t CR;
  __IO uint32_t CFGR;
  __IO uint32_t CIR;
  __IO uint32_t APB2RSTR;
  __IO uint32_t APB1RSTR;
  __IO uint32_t AHBENR;
  __IO uint32_t APB2ENR;
  __IO uint32_t APB1ENR;
  __IO uint32_t BDCR;
  __IO uint32_t CSR;
} RCC_TypeDef;
Отсюда следует, что RCC->BDCR - это уже содержимое регистра по адресу 0x40021000 + (sizeof(uint32_t)) * 8 (т.к. нужно сделать 8 "скачков" по 4 байта по структуре, чтобы добраться до этого поля), т.е., содержимое регистра по адресу 0x40021020.
А дальше всё просто:

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

while ((RCC->BDCR & RCC_BDCR_LSERDY) != RCC_BDCR_LSERDY)
Это не более чем "провисание" в цикле всё то время, пока бит LSERDY в этом регистре не равен единице.
Оно же:

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

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

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

Как я понимаю, то структура это некоторый последовательный набор адресов под одним именем. Чтобы обратиться конкретно к нужному адресу используется оператор ->

только не понятно, почему обращаемся к RCC->BDCR, а не к RCC_TypeDef->BDCR? А, понял, оно через дефайн объявлено.

Тогда,
RCC->BDCR & 0x02

с адресом в памяти МК делаем & 0x02? Накладываем маску? Или я гоню?

Добавлено after 2 minutes 41 second:
З.Ы. и как в том цикле сделать правильно таймаут? Стабилизируется кварц, вроде как за 6 тактов своих. Считать некую переменную до некоторого значения?

Добавлено after 4 minutes:
Ой.
RCC->BDCR это же содержимое регистра... Значит на его содержимое & 0x02

Добавлено after 39 seconds:
Вытаскиваем из него только нужный бит и делаем с ним != 0х02
Станислав
Друг Кота
Аватара пользователя
Сообщения: 3386
Зарегистрирован: Пн окт 11, 2010 19:00:08

Сообщение Мурик »

СКАЗОЧНИК писал(а):Стабилизируется кварц, вроде как за 6 тактов своих.
Может HSE, но не LSE. Ему порой и 6 секунд мало.
Друг Кота
Сообщения: 6457
Зарегистрирован: Пт сен 13, 2013 13:11:31

Сообщение a5021 »

[uquote="Мурик",url="/forum/viewtopic.php?p=3894713#p3894713"]a5021 про приведение типов ничего не слышали?[/uquote]
Вы про бузину в огороде?
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18793
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

a5021 писал(а):Итого имеем: передача правильного буфера вызывает возражения компиля, в то время, как передача горбухи проходит на ура.
имхо, проблема надуманная. программист должен не тупо следовать стандарту Си, а следовать логике работы программы. функция HAL_SPI_Receive_DMA занимается исключительно тем, что запускает аппаратуру на работу с памятью. аппаратуре же чихать с высокой колокольни на квалификатор адреса или на то, как описана память по этому адресу, ей важно численное значение этого адреса. что и делается при помощи uint8_t *pData. чтобы не было никаких варнингов, тут следовало бы использовать void*, что даже больше соответствует всей логике работы, как аппаратуры (требующей абстрактный адрес), так и программы (которой все равно, что за буфер).
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

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

Сообщение WiseLord »

СКАЗОЧНИК писал(а):Как я понимаю, то структура это некоторый последовательный набор адресов под одним именем
Нет. Структура - это переменная, которая группирует внутри себя другие переменные (поля). Эти переменные в памяти располагаются последовательно, возможно, выравниваясь при этом определённым образом (читать про упаковку структур). В случае регистров упаковка простая - там шаг равен 4 байтам (размерности указателя на STM32)
СКАЗОЧНИК писал(а):Чтобы обратиться конкретно к нужному адресу используется оператор ->
Нет, чтобы обратиться к конкретному полю ("вложенной" переменной), используется оператор "." (точка). А оператор "->" используется потому, что RCC - это не структура, а указатель на структуру - а для указателей используется именно такой "синтаксический сахар". Но можно было бы и через точку, разыменовав этот указатель: (*RCC).BDCR - но это не так "красиво" выглядит.
СКАЗОЧНИК писал(а):Вытаскиваем из него только нужный бит и делаем с ним != 0х02
Да, это типичный синтаксис в C для проверки того, установлен ли бит или нет. Скажем, проверить, что в переменной "x" бит 3 (0x04) установлен или сброшен, можно так:

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

if (x & 0x04 == 0x04) // проверка на бит=1
if (x & 0x04 != 0x04) // проверка на бит=0
Всё потому, что операция & (побитовое И) обнуляет все биты, кроме проверяемого(ых) (маски)

Добавлено after 3 minutes 28 seconds:
Мурик писал(а):Может HSE, но не LSE. Ему порой и 6 секунд мало.
Тут соглашусь. Первоначальная инициализация LSE может быть очень долгой (особенно если нет батарейного питания). Поэтому лучше в таком цикле проверки не висеть, а сделать что-то вроде конечного автомата для инициализации LSE, входя в инициализирующую функцию в основном цикле, например, раз в секунду, проверяя его состояние. То есть, инициализировать как бы "в фоне", делая / инициализируя параллельно более важные вещи.
Контактная информация:
Друг Кота
Сообщения: 6457
Зарегистрирован: Пт сен 13, 2013 13:11:31

Сообщение a5021 »

[uquote="ARV",url="/forum/viewtopic.php?p=3894757#p3894757"]
a5021 писал(а):Итого имеем: передача правильного буфера вызывает возражения компиля, в то время, как передача горбухи проходит на ура.
имхо, проблема надуманная. программист должен не тупо следовать стандарту Си, а следовать логике работы программы.[/uquote]
Стандарт, типа, подвинется, а компиль пусть заткнется? Самобытные техники посконного программирования?
функция HAL_SPI_Receive_DMA занимается исключительно тем,
Чем хочет пусть занимается. Она должна молча принять правильные параметры и взматериться на неправильные. Странно, но вы уже второй, кому захотелось подоказывать, что правильно будет наоборот. Осень?
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

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

Блин, всегда знал, что у меня с указателями и структурами беда... Не понимаю их... (((
А оператор printf используется в программировании для МК? А то про него очень много в книгах, но мне показалось, что он для вывода на экран компьютера строк нужен. А в МК не всегда есть экран. Или я опять что-то не так понимаю?
Станислав
Собутыльник Кота
Аватара пользователя
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01

Сообщение Eddy_Em »

printf на МК только абдуринщики используют: слишком уж много ресурсов он съедает.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Контактная информация:
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18793
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

a5021 писал(а):что правильно будет наоборот
с моей т.з. правильно будет void*. или volatile void* по-вашему правильнее? именно абстрактный адрес без указания того, что память там может меняться - void*.
a5021 писал(а):Осень?
не надо агрессии и хамства.
Eddy_Em писал(а):printf на МК только абдуринщики используют
глупости - используют те, кому собственное время дорого, а ресурсы МК дешевы.
СКАЗОЧНИК писал(а): А в МК не всегда есть экран
printf отлично используется для вывода в USART, для чего, собственно, он изначально и предназначался - вывод в последовательный поток.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Друг Кота
Сообщения: 6457
Зарегистрирован: Пт сен 13, 2013 13:11:31

Сообщение a5021 »

[uquote="ARV",url="/forum/viewtopic.php?p=3894778#p3894778"]с моей т.з. правильно будет void*. или volatile void* по-вашему правильнее? именно абстрактный адрес без указания того, что память там может меняться - void*.[/uquote]
То, на какой тип здесь указатель, совершенно не важно. Это ни на что не влияет. Конечная запись этого адреса в регистр будет все равно, как 32-бита без знака. Другое дело volatile. Странно, как такие простые вещи не доходят ни с первого, ни с второго раза.
Друг Кота
Аватара пользователя
Сообщения: 7059
Зарегистрирован: Сб янв 28, 2006 22:47:24

Сообщение Asmodey »

[uquote="СКАЗОЧНИК",url="/forum/viewtopic.php?p=3894771#p3894771"]Блин, всегда знал, что у меня с указателями и структурами беда... Не понимаю их... ((([/uquote]
У меня та же беда. Я вот не понимаю, почему именно структуры использованы в файлах с описанием периферии МК?

Подозреваю, для того, чтобы обращаться к отдельным группам битов в регистрах именно как к группам, а не к отдельным битам. При том не затрагивая другие биты регистра. Вместо того чтобы изменять один за другим отдельные биты некоей группы битов в регистре с помощью поразрядного ИЛИ и И (пусть, это 4 бита отвечающие за коэффициент умножения PLL ) мы присваиваем сразу необходимое значение какому-то полю структуры от 0 до 15, и таким образом вместо 4 строчек в тексте программы получаем всего одну строчку. Моя догадка верна или нет?

А примеры работы со структурами с printf для PC, которыми пестрит интернет, действительно не очень-то наглядны применительно к МК.
Астролябия-сама меряет, было бы что мерять!!!
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

[uquote="Asmodey",url="/forum/viewtopic.php?p=3894794#p3894794"]Я вот не понимаю, почему именно структуры использованы в файлах с описанием МК?.[/uquote]Потому что это удобно. Многие блоки периферии в чипе несколько раз присутствуют. Описывать надо лишь один блок. Удобно передавать в качестве параметра в какую-нибудь функцию с каким конкретно блоком работать.
[uquote="Asmodey",url="/forum/viewtopic.php?p=3894794#p3894794"]Моя догадка верна или нет?[/uquote]Нет. Структуры внутрь регистров не распространяются.
Ответить

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