Назначение выводов STM32F446RET6


Тактовые генераторы


Частоты тактовых генераторов

HSI - 16 МГц. Внутренний высокочастотный RC-генератор

HSE - 4...25 МГц. Внешний кварцевый резонатор или тактовый высокочастотный сигнал с внешнего генератора.

LSI - 32 кГц. Внутренний низкочастотный RC-генератор.

LSE - 32,768 кГц. Внешний кварцевый "часовой" резонатор или тактовый низкочастотный сигнал с внешнего генератора.

После сброса в качестве источника тактовой частоты по умолчанию выбирается внутренний высокочастотный RC-генератор (HSI). Точность настройки частоты HSI-генератора составляет 1% (при +25 С). Программа пользователя может выбрать в качестве источника тактовой частоты внешний высокочастотный генератор с кварцевым резонатором (HSE crystal) или отдельный внешний генератор, подключаемый ко входу OSC_IN (HSE bypass).

Стабильность частоты HSE-генератора контролируется. В случае ошибки система автоматически переключается на внутренний HSI-генератор и, если разрешено, то генерируется прерывание.

Генератор с кварцевым резонатором (HSE crystal)

Преймущество этого способа тактирования в высокой точности и стабильности тактовой частоты.

Работа (вкл/выкл) HSE-генератора управляется битом HSEON в регистре управления тактовой частотой RCC_CR.

Флаг HSERDY в регистре RCC_CR показывает, что частота HSE-генератора стабилизировалась и его сигнал можно использовать в качестве источника системных тактовых импульсов (SYSCLK).

Прерывание по факту стабилизации частоты HSE может быть сгенерировано, если оно включено в регистре управления прерываниями RCC - RCC_CIR.

Внешний высокочастотный источник тактовых импульсов (HSE bypass)

Этот способ тактирования выбирается путём установки битов HSEBYP и HSEON в регистре управления тактовой частотой RCC_CR.

Внешний тактовый сигнал может быть прямоугольной, синусоидальной или треугольной формы со скважностью примерно 0,5. Сигнал подаётся на вывод OSC_IN (вместо подключения кварцевого резонатора). Второй вывод OSC_OUT остаётся неподключенным в высокоимпедансном (высокоомном) состоянии (HI-Z- или Z-состоянии).


Внутренние продвинутые шины

SYSCLK - max 180 МГц

AHB - max 180 МГц

APB2 - max 90 МГц

APB1 - max 450 МГц

Иногда при работе с данными нужно разобрать 16-ти или 32-х битную переменную на байты. Или наоборот, собрать слово из отдельныых байтов. Для этого используют:

-  сдвиг переменной и наложение маски

-  доступ к байтам переменной по указателю


Разбор слова на байты при помощи сдвига и наложения маски

Использует свойство неявно сужающего преобразования (приведения) беззнакового целого длинного типа при присваивании в более короткий: всё что не влезло - отбрасывается. Например: uint32_t  b = 0x12345678;. В результате неявного преобразования при присваивании: uint8_t  a = b; получим результат: a = 0x78;. Старшие байты слова были отброшены. Сдвигая слово вправо на байт (8 бит), готовим второй байт для присваивания. И так далее...


#include <stdio.h>
#include <conio.h>
#include <stdint.h>

int main()
{
	uint8_t a[4] = {};

	uint32_t b = 0x12345678;

	a[0] = b;
	a[1] = b>>8;
	a[2] = b>>16 & 0xff;
	a[3] = (uint8_t)(b>>24 & 0xff);

	printf("a[0] = %x \n", a[0]);
	printf("a[1] = %x \n", a[1]);
	printf("a[2] = %x \n", a[2]);
	printf("a[3] = %x \n", a[3]);
	
	getch();
}

Для элемента a[2] используется наложение маски 0xFF (обнуляется всё кроме младшего байта). Компилятору это необязательно, но показывает другому программисту, что сужающее преобразование сделано сознательно. Для элемента a[3] используется явное приведение типа к uint8_t. При отсутствии явного указания компилятор неявно приведёт тип к нужному.


Сборка 32-х битной переменной из отдельных байтов

Для сборки переменной используются операции сдвига влево и побитового сложения.


#include <stdio.h>
#include <conio.h>
#include <stdint.h>

int main()
{
    uint8_t a[4] = {0x12, 0x34, 0x56, 0x78};

    uint32_t b = 0;

    b = (uint32_t)a[0]<<24 | (uint32_t)a[1]<<16 | (uint32_t)a[2]<<8 | a[3];

    printf("b = %x \n", b);
	
    getch();
}

Явное преобразование типа (uint32_t) может не использоваться для определённых компиляторов. Например: clang в C++ Builder/Win10-64 при любом сдвиге влево неявно расширяет однобайтную переменную до 4-х байтов (до int, но не более).


Доступ к байтам переменной по указателю

Суть этого метода: представить многобайтовую переменную в виде массива байтов и получить доступ к этим элементам массива при помощи оператора [ ] - индекс массива (доступ к элементам массива по индексу).

Пусть есть некоторая 32-х битная переменная типа беззнаковое целое: uint32_t  a = 0x12345678.

1)  Возьмем адрес переменной a: &a. Этот адрес указывает на первый байт 32-х битного беззнакового целого.

2)  Приведём этот адрес к типу указатель на байт (8-ми битное беззнаковое целое) (uint8_t *)&a.

3)  Теперь при помощи оператора доступа к элементам массива по индексу [ ] можно получить доступ к любому байту 4-х байтной (32-х битной) исходной переменной: ((uint8_t *)&a)[0]. В нашем случае индекс массива находится в диапазоне от 0 до 3. Дополнительные круглые скобки, объединяющие преобразование адреса, необходимы для соблюдения порядка операций, т.к. оператор индекса массива имеет приоритет над преобразованием типа переменной.

Пример программы на языке C для Windows в C++ Builder:


#include <stdio.h>
#include <conio.h>
#include <stdint.h>

int main()
{
	uint32_t b = 0x12345678;

	printf("b[0] = %x \n", ((uint8_t *)&b)[0]);
	printf("b[1] = %x \n", ((uint8_t *)&b)[1]);
	printf("b[2] = %x \n", ((uint8_t *)&b)[2]);
	printf("b[3] = %x \n", ((uint8_t *)&b)[3]);

	getch();
}

Подключаемые библиотеки: <stdio.h> - для функции printf(), <conio.h> - для функции getch() (окно терминала с результатом выполнения программы не закрывается сразу, а ждет ввода любого символа с клавиатуры), <stdint.h> - содержит определение типов целых чисел фиксированной длины, не зависящей от аппаратной платформы, в частности: uint32_t.

Результат выполнения программы:

 
b[0] = 78
b[1] = 56
b[2] = 34
b[3] = 12

Видно, что в начале массива с нулевым индексом (с меньшим адресом в памяти) содержится младший байт слова. А старший байт слова имеет больший адрес в памяти. Такой порядок байтов (endianness) в данном случае (на х86 компьютере) называется little-endian. Факт разного порядка байтов в слове необходимо учитывать при разработке.

Пример программы на Си для определения порядка байтов:


#include <stdio.h>
#include <conio.h>
#include <stdint.h>

int main()
{
	uint16_t b = 0x0001;

	printf("%s-endian\n", *((uint8_t *)&b) ? "little" : "big");

	getch();
}

В этом примере оператор доступа к первому элементу массива с индексом 0: ((uint8_t *)&a)[0] заменён на оператор разыменовывания указателя на массив: *((uint8_t *)&a), что по определению является одним и тем же.


Сборка 32-х битной переменной из отдельных байтов при помощи указателей

При "сборке" 32-х битной переменной из отдельных байтов делаем "всё так же, только наоборот".


#include <stdio.h>
#include <conio.h>
#include <stdint.h>

int main()
{
	uint8_t a[4] = {0x12, 0x34, 0x56, 0x78};

	uint32_t b;

	((uint8_t *)&b)[0] = a[0];
	((uint8_t *)&b)[1] = a[1];
	((uint8_t *)&b)[2] = a[2];
	((uint8_t *)&b)[3] = a[3];

	printf("b = %x \n", b);
	
	getch();
}

Каков ожидаемый результат выполнения этой программы? Для порядка следования байтов litte-endian младший байт слова b[0] имеет меньший адрес и располагается справа при выводе на экран. Ожидаемый результат: 0x78563412. Проверим:

 
b = 78563412