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

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

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

:shock: Да, про адреснкю арифметику я сейчас и втупляю. :)))

Т.е. это не переменная, а просто объявили в файле константу и присвоили ей жестко число (адрес)?

Добавлено after 2 minutes 1 second:
Почти понял, что МК оперирует только цифрами. Т.е. в я могу написать тупо цифры адреса регистра и по этому адресу расставлять биты?

Добавлено after 27 seconds:
Как это будет выглядеть для примера?
Станислав
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Не присвоили, а сделали приведение типа из числа к указателю на структуру. Выполните все макроподстановки вручную и всё поймёте.
Реклама
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

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

(TIM_TypeDef *)0х40010000
Как-то так получается. Но все равно втупляю. Если я так сделаю в "обычном" си на компьютере, то
(TIM_TypeDef *) var
переменная var будет типа структуры?

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

Сообщение VladislavS »

Кто вам запрещает так сделать в "обычном C на компьютере"? Компилятор всё откомпилирует и получится программа. Разве что в момент выполнения операционная система не даст в защищённую область получить доступ и прихлопнет такую программу.

Добавлено after 3 minutes 17 seconds:
[uquote="СКАЗОЧНИК",url="/forum/viewtopic.php?p=4050543#p4050543"](TIM_TypeDef *) var
переменная var будет типа структуры?[/uquote]Переменная var будет тем чем и была, как вы её определили ранее. А вот (TIM_TypeDef *)var это приведение типа к указателю на структуру.

PS: В принципе, в микроконтроллерах тоже встречается модуль защиты памяти и можно сделать, чтобы так же как не компьютере, доступ куда не положено вызывал исключения.
Реклама
Эиком - электронные компоненты и радиодетали
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

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

Как везде написано и как я запомнил, что

указатель - это перменная, которая хранит адрес другой переменной (структуры, функции)... И это мне изначально вполне понятно.
А вот, когда указателем становится просто число (адрес памяти) уже туго...
Как в железе все это выглядит? Или здесь только для компилятора это важно, а в железе все равно цифры только будут.
Станислав
Реклама
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Возьмём для примера тот же TIM2. Структура, описывающая его:

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

typedef struct
{
  __IO uint32_t CR1;             /*!< TIM control register 1,                      Address offset: 0x00 */
  __IO uint32_t CR2;             /*!< TIM control register 2,                      Address offset: 0x04 */
  __IO uint32_t SMCR;            /*!< TIM slave Mode Control register,             Address offset: 0x08 */
 ...
}TIM_TypeDef;
Раскручиваем адрес TIM2:

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

#define TIM2                ((TIM_TypeDef *)TIM2_BASE)
#define TIM2_BASE             (APB1PERIPH_BASE + 0x00000000UL)
#define APB1PERIPH_BASE       PERIPH_BASE
#define PERIPH_BASE           0x40000000UL /*!< Peripheral base address in the alias region */
Получается, группа регистров TIM2 начинается с адреса 0x40000000. А регистр, например, CR2 лежит уже по адресу 0x40000004.

Поэтому к CR2 можно обратиться либо "как принято", (TIM2->CR2 = 0x5555AAAA). Либо, можно в стиле AVR:

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

#define CR1 (*(__IO uint32_t*)0x40000000)
#define CR2 (*(__IO uint32_t*)0x40000004)
#define SMCR (*(__IO uint32_t*)0x40000008)
...
// Присванивание:
CR2 = 0x5555AAAA;
Ну и да, __IO - это синоним volatile.

Добавлено after 5 minutes 7 seconds:
Грубо, можно то что выше "расшифровать" так:

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

volatile uint32_t *ptr;
ptr = 0x40000004;
*ptr = 0x5555AAAA;
Последний раз редактировалось WiseLord Пн июн 21, 2021 11:40:26, всего редактировалось 1 раз.
Контактная информация:
Реклама
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

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

Т.е и так тоже можно?
*(__IO uint32_t*)0x40000000 = 0x5555AAAA;

Получается 0x40000000 это тот адрес, который лежит в указателе, а *(__IO uint32_t*)0x40000000 это обращение по этому адресу, который лежит в указателе?
Станислав
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Да, всё верно, можно и так.
Контактная информация:
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

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

Хорошо. Тогда где сам указатель?

Добавлено after 2 minutes 25 seconds:
Просто, обычно, (как правило, во всех примерах по языку) указатель - это тоже переменная.
Станислав
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Не совсем понял, какой указатель. В Вашей записи он присутствует неявно (к нему приводится число 0x40000000), но он тут же разыменовывается. Но вообще гляньте на предыдущей странице моё последнее сообщение в конце.

Указатель - не обязательно переменная. В нашем случае он константа, численно равная 0x40000000. А уже там, по этому адресу, лежит переменная.
Контактная информация:
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

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

Да. вот эта конструкция абсолютно понятна.

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

volatile uint32_t *ptr;
ptr = 0x40000004;
*ptr = 0x5555AAAA;
Потому что здесь есть имя указателя, как обычной переменной. А в МК его нету.. Вот и путаница

Добавлено after 3 minutes 15 seconds:
[uquote="WiseLord",url="/forum/viewtopic.php?p=4050556#p4050556"]Указатель - не обязательно переменная. В нашем случае он константа, численно равная 0x40000000.[/uquote]

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

Сообщение WiseLord »

Но это имя по сути не нужно.

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

volatile uint32_t *ptr = 0x40000004;
*ptr = 0x5555AAAA;
Это абсолютно эквивалентно

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

*(volatile uint32_t*)0x40000004 = 0x5555AAAA;
Вся эта конструкция (volatile uint32_t*)0x40000004 - это и есть тот самый ptr. Отдельное имя ему выделять не обязательно. Удобнее выделить отдельное имя сразу для *ptr

Добавлено after 3 minutes 38 seconds:
СКАЗОЧНИК писал(а):Именно это никто не говорит в курсах про Си. Там явно и однозначно говорят, что указатель это такая переменная, которая.. бла бла
Вы так говорите, как будто не использовали никогда константных строк или константных массивов.

А ведь разницы никакой нет. Когда мы пишем, например, const int buf[] = {5, 3, 4, 2}; - мы ведь точно так же имеем buf - константный указатель. Просто в этом случае компилятор где-то разместит этот массив в памяти (во flash-памяти, например) и присвоит buf-у константный указатель на это место. А в наших примерах мы можем делать это руками, так как адреса периферий фиксированные.
Контактная информация:
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

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

Видимо, я очень плохо соображаю в Си. что так и есть.
Даже констаный массив, который Вы описали имеет имя. И я его вижу именно по имени, а не цифрами в виде адреса. ))))))) А то, что потом с ним сделает компилятор уже его дело.
В наших же вышеуказанных примерах, имен все равно нету. Есть конечное объявление (через дефайн) на обращение по указателю. Короче, я понял, что мне не хватает. ) Одного урока по Си, где бы были примеры и варианты использования констант как указателей. Что не обязательно задвать указателю имя, как переменной и что он вообще может не являться перменной. А может быть реальной константой и при этом без имени, а тупо само число. И компилятор все это нормально схавает.
Конечно, с учетом среды, где все это используется. Если это программирование для РС, то может и выкинут, если залезть в неразрешенный адрес, а если это МК, то адреса можно посмотреть в рефренс мануале.
Станислав
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

СКАЗОЧНИК, научитесь смотреть листинг того что делает компилятор. Проще понимать что делает код будет. Вот что делает ваш код.

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

//*(__IO uint32_t*)0x40000000 = 0x5555AAAA;
        MOVS     R0,#+128       
        LSLS     R0,R0,#+23     
        LDR      R1,??DataTable1
        STR      R1,[R0, #+0]   
             
//*((__IO uint32_t*)0x40000000+1) = 0x5555AAAA;
        STR      R1,[R0, #+4]
//*(__IO uint32_t*)0x40000004 = 0x5555AAAA;
        STR      R1,[R0, #+4]      
        
??DataTable1:
        DATA32
        DC32     0x5555aaaa  
Обратите внимание, как при доступе по адресу 0x40000004 был использован базовый адрес 0x40000000 и смещение 4 от него. Точно так же осуществляется доступ к полям структуры смещением от базового адреса.

Добавлено after 1 minute 43 seconds:
[uquote="СКАЗОЧНИК",url="/forum/viewtopic.php?p=4050565#p4050565"]А может быть реальной константой и при этом без имени, а тупо само число.[/uquote]Не тупо само число!!! Вы же делаете приведение типа от числа к указателю. Результат этого приведения и есть указатель. Тупо записать в число, конечно же, ничего нельзя.

Добавлено after 4 minutes 15 seconds:
А теперь найдите хоть одно отличие

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

//__IO uint32_t *adr = (uint32_t *)0x40000000;
//  *adr = 0x5555AAAA;
        MOVS     R0,#+128       
        LSLS     R0,R0,#+23     
        LDR      R1,??DataTable1
        STR      R1,[R0, #+0]   
           
//*(adr+1) = 0x5555AAAA;
        STR      R1,[R0, #+4]   
        
        ??DataTable1:
        DATA32
        DC32     0x5555aaaa  
Последний раз редактировалось VladislavS Пн июн 21, 2021 12:22:15, всего редактировалось 1 раз.
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

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

Приведение типа к указателю на структуру. Если до меня правильно доходит..

А можно так написать?

(__IO uint32_t*)0x40000000;
*0x40000000 = 0x5555AAAA;
Станислав
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

[uquote="СКАЗОЧНИК",url="/forum/viewtopic.php?p=4050572#p4050572"]А можно так написать?[/uquote]Да написать то что угодно можно, бумага всё стерпит. Только фигняс получается.
Последний раз редактировалось VladislavS Пн июн 21, 2021 12:24:43, всего редактировалось 1 раз.
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Так нельзя, это синтаксическая ошибка. Разыменовывать просто число нельзя.

А вот разыменовать это же число, приведённое к конкретному указателю - можно. Хотя формально и то и другое - одно и то же число, но в одном случае - это просто число, а во втором - адрес некоторой ячейки.

Кстати, в примере ниже результат будет тоже разный, несмотря на "одно и то же число"

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

*(__IO uint32_t*)0x40000000 = 0x5555AAAA;
*(__IO uint16_t*)0x40000000 = 0x5555AAAA;
*(__IO uint8_t*)0x40000000 = 0x5555AAAA;
Контактная информация:
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

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

Благодарю за помощь. ) Много нового узнал.

Добавлено after 4 minutes 4 seconds:
[uquote="WiseLord",url="/forum/viewtopic.php?p=4050577#p4050577"]Кстати, в примере ниже результат будет тоже разный, несмотря на "одно и то же число"

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

*(__IO uint32_t*)0x40000000 = 0x5555AAAA;
*(__IO uint16_t*)0x40000000 = 0x5555AAAA;
*(__IO uint8_t*)0x40000000 = 0x5555AAAA;
[/uquote]

Правильно я понмаю, что превое - это указатель на область памяти в 32 бита с адресом 0x40000000, и в эту область можно нормально записать число 0x5555AAAA, а в два других уже не влезет.? Хоть эта область расположена по этому же адресу...
Станислав
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Что значит "не влезет"? :) Константа 0x5555AAAA будет приведена к типу левого операнда и будет записана командами STR, STRH и STRB соответственно.
Идёт направо - песнь заводит, Налево - сказку говорит.
Аватара пользователя
Сообщения: 5000
Зарегистрирован: Чт апр 21, 2011 17:55:50
Откуда: Иркутск

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

Ассемблер для STM пока что сложноватая штука для меня. ) Команды не такие , как были в АВР.
Станислав
Ответить

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