STM32CubeMX по умолчанию отключает SWD для серии F1

STM32CubeMX — это генератор исходного кода для микроконтроллеров STM32. Позволяет настроить периферию с помощью графического интерфейса.

Если создать проект в STM32CubeMX, выбрать микроконтроллер серии F1 и сгенерировать исходный код, не производя никаких настроек, то этот код отключит интерфейсы программирования JTAG и SWD. Если такую программу скомпилировать и прошить, то в следующий раз прошить микроконтроллер будет затруднительно.

То есть новичок, делающий первую программу для STM32F1, гарантировано окажется в тупиковой ситуации.

Проблема проявляется только для микроконтроллеров серии F1. Для проверки использовался STM32CubeMX последней (4.17.0, на 13.11.2016) версии.

Проблема несколько раз упоминалась (раз, два, три) в 2015 году. И STM даже обещали (по третьей ссылке) ее исправить, но не исправили.

Код, отвечающий за отключение JTAG и SWD, находится в файле stm32f1xx_hal_msp.c в функции HAL_MspInit(), которая вызывается функцией HAL_Init(), и выглядит следующим образом:

 /**DISABLE: JTAG-DP Disabled and SW-DP Disabled
*/
__HAL_AFIO_REMAP_SWJ_DISABLE();

Чтобы избежать этой проблемы, нужно в STM32CubeMX на вкладке Pinout в дереве настроек найти пункт Configuration -> Peripherals -> SYS -> Debug и из выпадающего списка выбрать подходящее значение:

  • No Debug — значение по умолчанию, отключает отладочные интерфейсы JTAG и SWD.
  • Serial Wire — отключает JTAG, включает SWD, который использует только два вывода, подходит для программатора ST-Link.
  • JTAG (4 pin) — включает JTAG и SWD, используется 4 вывода (без NJTRST).
  • JTAG (5 pin) — включает JTAG и SWD, используется 5 выводов (с NJTRST), что соответствует состоянию микроконтроллера после сброса.

Как прошить микроконтроллер с отключенными JTAG и SWD

Если SWD и JTAG отключились, то не все потеряно. Уверен, что есть проекты в которых это даже необходимо.

Для начала нужно создать прошивку, которая бы не отключала SWD и JTAG.

Вариант 1

Вариант работает при прошивке через SWD с помощью ST-LINK/V2 (ST-LINK второй версии). Через JTAG тоже можно, но с ST-LINK, у которого версия прошивки V2J15Sx или новее.

В программе STM32 ST-LINK utility в настройках нужно выбрать режим (Mode) «Connect Under Reset» (подключение при сбросе). Этот режим позволяет подключиться к микроконтроллеру до начала выполнения программы.

Чтобы прошить микроконтроллер, нужно на вывод сброса микроконтроллера (NRST) подать низкий уровень (или соединить вывод с землей), запустить прошивку и сразу убрать низкий уровень с NRST.

Возможно, чтобы вручную не дергать NRST, можно соединить его с одноименным вывод ST-LINK и произвести еще какие-то настройки STM32 ST-LINK utility. Но автор эту идею не проверял. Если вы знаете, напишите в комментариях.

Вариант 2

Если у вас нет ST-LINK/V2, то микроконтроллер можно прошить через USART с помощью программы STM32 Flash loader demonstrator. Для этого понадобится переходник USB-UART, который создаст на компьютере виртуальный COM-порт.

Во флеш STM32 есть системная область, в которую на заводе зашит специальный загрузчик. Чтобы запустить выполнение программы загрузчика, нужно подать на ноги BOOT0 и BOOT1 необходимые уровни (согласно документации) и запустить микроконтроллер.

В Application note AN2606 можно уточнить какие USART с какими выводами использует загрузчик, а также необходимое состояние выводов BOOTx.

АЦП микроконтроллеров STM32F10x

АЦП микроконтроллеров STM32F10x получает опорное напряжение с внешнего источника. Если у микроконтроллера меньше 100 выводов, то к нему невозможно подключить внешний ИОН, тогда в качестве опорного напряжения используется напряжение питания.

Хотя микроконтроллеры имеют встроенный ИОН, этот ИОН нельзя использовать в качестве опоры АЦП, но зато можно измерить его напряжение. Благодаря этому мы получаем возможность хитрым способом измерить опорное напряжение АЦП (то есть, по сути напряжение питания). Делается это следующим образом:

  1. выбрать канал 17,
  2. произвести измерение,
  3. рассчитать опорное напряжение АЦП по формуле:

U_{REFADC}=\frac{2^n}{C_{REFINT}}\cdot U_{REFINT}

где:

  • UREFINT = 1,2 В — опорное напряжение внутреннего ИОН;
  • n = 12  — разрядность АЦП;
  • СREFINT — результат АЦ-преобразования.

В дальнейшем, зная UREFADC, можно производить обычные измерения, рассчитывая напряжение на входе АЦП по формуле:

U_{ADC}=\frac{C_{ADC}}{2^n}\cdot U_{REFADC}

Объединяя предыдущие формулы, получаем:

U_{ADC}=\frac{C_{ADC}}{C_{REFINT}}\cdot U_{REFINT}

Иллюстрация к вышеописанному:

Схема АЦП STM32F10x

Вычисление тактовых частот в STM32F10x

Микроконтроллеры серии STM32F10x содержат богатую периферию, которая тактируется с разными частотами. Вычислить тактовые частоты можно с помощью функции RCC_GetClocksFreq(), которая содержится в модуле RCC библиотеки STM32F10x SPL.

Функция производит вычисления на основе данных в регистрах RCC.

Прототип функции:

void RCC_GetClocksFreq(RCC_ClocksTypeDef * RCC_Clocks)

Функция заполняет структуру типа RCC_ClocksTypeDef, указатель на которую передается в функцию в качестве аргумента. Структура содержит следующие поля:

uint32_t ADCCLK_Frequency Тактовая частота АЦП в Гц
uint32_t HCLK_Frequency Тактовая частота шины AHB в Гц
uint32_t PCLK1_Frequency Тактовая частота периферии APB1 в Гц
uint32_t PCLK2_Frequency Тактовая частота периферии APB2 в Гц
uint32_t SYSCLK_Frequency Системная тактовая частота в Гц

Если используется внешнее тактирование, то функция должна знать частоту этого тактирования. Частота задается константой HSE_VALUE.

Лучше всего, определить константу опцией -D компилятора:

-DHSE_VALUE=4000000

В этом примере задается частота 4 МГц.

Если не определить константу в опциях компилятора, то она определится в файле stm32f10x.h и ей присвоится значение по умолчанию: 8000000 (8 МГц). Это значение можно отредактировать, прописав свою частоту.

Еще один способ задать собственное значение частоты: прописать в файле stm32f10x_conf.h следующие строки:

#if defined HSE_VALUE
  #undef HSE_VALUE
#endif
#define HSE_VALUE ((uint32_t)4000000) // 4 МГц

Во всех способах частота задается целым числом Герц.

Пример вызова функции RCC_GetClocksFreq():

RCC_ClocksTypeDef clocks;
RCC_GetClocksFreq(&clocks);

Кроме того, чтобы узнать источник системного тактирования микроконтроллера, можно воспользоваться функцией RCC_GetSYSCLKSource().

Прототип функции:

uint8_t RCC_GetSYSCLKSource(void)

Функция возвращает одно из значений:

  • 0x00: внутренний тактовый генератор (HSI)
  • 0x04: внешний тактовый источник (HSE)
  • 0x08: умножитель (PLL)

К сожалению библиотека SPL не имеет функций для вычисления тактовых частот конкретных периферийных устройств.
Код вычисляющий тактовые частоты таймеров:

uint32_t APB1_TIMCLK_Frequency;
uint32_t APB2_TIMCLK_Frequency;
RCC_ClocksTypeDef clocks;

RCC_GetClocksFreq(&clocks);

if (clocks.HCLK_Frequency == clocks.PCLK1_Frequency)
  APB1_TIMCLK_Frequency = clocks.PCLK1_Frequency;
else
  APB1_TIMCLK_Frequency = 2 * clocks.PCLK1_Frequency;

if (clocks.HCLK_Frequency == clocks.PCLK2_Frequency)
  APB2_TIMCLK_Frequency = clocks.PCLK2_Frequency;
else
  APB2_TIMCLK_Frequency = 2 * clocks.PCLK2_Frequency;

STM32F10x SPL в Википедии

Моими стараниями в Википедии появилась статья STM32F10x Standard Peripherals Library.

STM32F10x Standard Peripherals Library: соглашения

Соглашение об именах

  1. PPP — обозначение периферийного устройства, например ADC (аналого-цифровой преобразователь)
  2. Файлы исходного кода библиотеки начинаются с приставки stm32f10x_.
  3. Имена констант прописаны заглавными буквами. Если константа используется в единственном файле, то она определяется в этом файле. Константа, используемая в более, чем одном файле, определяются в заголовочном файле.
  4. Имена регистров, как и констант, прописаны заглавными буквами. Регистры именуются так же, как в документации на микроконтроллеры.
  5. Имена функций начинаются с PPP, после чего идет одно нижнее подчеркивание. Далее идут слитные слова, начинающиеся с заглавной буквы. Например: USART_SendData().
  6. Для настройки периферии PPP используется функция PPP_Init(), в которую передается указатель на структуру типа PPP_InitTypeDef, содержащую настройки периферии.
  7. Функция PPP_DeInit() сбрасывает регистры периферии в их начальное состояние.
  8. Функция PPP_StructInit() заполняет поля структуры типа PPP_InitTypeDef значениями по умолчанию, которые описывают начальное состояние периферии (состояние после сброса).
  9. Функция PPP_Cmd() включает или отключает периферию.
  10. Функция PPP_ITConfig() включает или отключает прерывания.
  11. Функция PPP_DMAConfig() включает или отключает DMA-интерфейс.
  12. Функции, оканчивающиеся на Config, настраивают отдельные функции периферии. Например GPIO_PinRemapConfig().
  13. Функция PPP_GetFlagStatus() служит для получения состояния флагов.
  14. Функция PPP_ClearFlag() сбрасывает флаги.
  15. Функция PPP_GetITStatus() сообщает о том произошло ли прерывание или нет.
  16. Функция PPP_ClearITPendingBit() сбрасывает бит захвата прерывания.

STM32F10x SPL: модуль GPIO

Введение

Статья написана на основе этой документации:
STM32F10x Standard Peripherals Library версии 3.5.0

В следующих разделах статьи будет представлено описание функций модуля GPIO и описание структуры GPIO_InitTypeDef.

Содержание

Обзор функций

В этом разделе, кликнув на имя функции, можно перейти к её подробному описанию.

void GPIO_AFIODeInit(void)
Сбрасывает в начальное состояние регистры альтернативных функций

void GPIO_DeInit(GPIO_TypeDef *GPIOx)
Сбрасывает в начальное состояние регистры GPIOx

void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface)
Выбирает Ethernet media interface

void GPIO_EventOutputCmd(FunctionalState NewState)
Разрешает или запрещает событийный выход (Event Output)

void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
Выбирает вывод для событийного выхода

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
Назначает вывод GPIO_PinSource порта GPIO_PortSource источником внешнего прерывания

void GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_InitStruct)
Настраивает порт GPIOx в соответствии с параметрами из структуры GPIO_InitStruct

void GPIO_StructInit(GPIO_InitTypeDef *GPIO_InitStruct)
Заполняет поля структуры GPIO_InitStruct значениями по умолчанию

void GPIO_PinLockConfig(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
Защищает настройки выводов

void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState)
Разрешает или запрещает переназначение GPIO_Remap

uint16_t GPIO_ReadInputData(GPIO_TypeDef *GPIOx)
Возвращает входные данные порта GPIOx

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
Возвращает входное состояние вывода GPIO_Pin порта GPIOx

uint16_t GPIO_ReadOutputData(GPIO_TypeDef *GPIOx)
Возвращает выходные данные порта GPIOx

uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
Возвращает выходное состояние вывода GPIO_Pin порта GPIOx

void GPIO_ResetBits(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
Присваивает лог. 0 выходному состоянию выводов GPIO_Pin порта GPIOx

void GPIO_SetBits(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
Присваивает лог. 1 выходному состоянию выводов GPIO_Pin порта GPIOx

void GPIO_Write(GPIO_TypeDef *GPIOx, uint16_t PortVal)
Присваивает значение PortVal выходным данным порта GPIOx

void GPIO_WriteBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, BitAction BitVal)
Присваивает значение BitVal выходному состоянию вывода GPIO_Pin порта GPIOx

Подробное описание функций



void GPIO_AFIODeInit(void)
Сбрасывает в начальное состояние регистры альтернативных функций порта



void GPIO_DeInit(GPIO_TypeDef *GPIOx)
Сбрасывает в начальное состояние регистры порта GPIOx
Аргументы:

  • GPIOx: Порт. Варианты значений:
    • GPIOx: где x = (A…G)


void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface)
Выбирает Ethernet media interface
Аргументы:

  • GPIO_ETH_MediaInterface: Media Interface. Варианты значений:
    • GPIO_ETH_MediaInterface_MII: Режим MII
    • GPIO_ETH_MediaInterface_RMII: Режим RMII


void GPIO_EventOutputCmd(FunctionalState NewState)
Разрешает или запрещает событийный выход (Event Output)
Аргументы:

  • NewState: Новое состояние событийного выхода. Варианты значений:
    • ENABLE: разрешен
    • DISABLE: запрещен


void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, u8 GPIO_PinSource)
Выбирает вывод для событийного выхода
Аргументы:

  • GPIO_PortSource: Порт. Варианты значений:
    • GPIO_PortSourceGPIOx: где x = (A…E)
  • GPIO_PinSource: Вывод порта. Варианты значений:
    • GPIO_PinSourceX: где X = (0…15)


void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, u8 GPIO_PinSource)
Назначает вывод GPIO_PinSource порта GPIO_PortSource источником внешнего прерывания
Аргументы:

  • GPIO_PortSource: Порт. Варианты значений:
    • GPIO_PortSourceGPIOx: где x = (A…G)
  • GPIO_PinSource: Вывод порта и одновременно номер X внешнего прерывания. Варианты значений:
    • GPIO_PinSourceX: где X = (0…15)


void GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_InitStruct)
Настраивает порт GPIOx в соответствии с параметры из структуры GPIO_InitStruct
Аргументы:

  • GPIOx: Порт. Варианты значений:
    • GPIOx: где х = (A…G)
  • GPIO_InitStruct: Структуру типа GPIO_InitTypeDef, содержащая настройки порта.


void GPIO_PinLockConfig(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
Защищает настройки выводов
Аргументы:

  • GPIOx: Порт. Варианты значений:
    • GPIOx: где х = (A…G)
  • GPIO_Pin: Выводы, одно значение или их комбинация (с помощью оператора или |):
    • GPIO_Pin_x: где x = (0…15)


void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState)
Разрешает или запрещает переназначение GPIO_Remap
Аргументы:

  • NewState: Состояние переназначения. Значения аргумента:
    • ENABLE: Разрешение
    • DISABLE: Запрет
  • GPIO_Remap: Переназначение. Значения аргумента:
    • GPIO_Remap_PPP, где PPP:
      • SPI1
      • SPI3
      • I2C1
      • USART1
      • USART2
      • USART3
      • PD01
      • TIM5CH4_LSI
      • ADC1_ETRGINJ
      • ADC1_ETRGREG
      • ADC2_ETRGINJ
      • ADC2_ETRGREG
      • ETH
      • CAN2
      • SWJ_NoJTRST
      • SWJ_JTAGDisable
      • SWJ_Disable
      • TIM2ITR1_PTP_SOF
      • PTP_PPS
      • CEC
      • TIM1_DMA
      • TIM4
      • TIM9
      • TIM10
      • TIM11
      • TIM13
      • TIM14
      • TIM15
      • TIM16
      • TIM17
      • FSMC_NADV
      • TIM67_DAC_DMA
      • TIM12MISC
    • GPIO_FullRemap_PPP, где PPP:
      • USART3
      • TIM1
      • TIM2
      • TIM3
    • GPIO_PartialRemap_PPP, где PPP:
      • TIM1
      • TIM3
    • GPIO_PartialRemap1_PPP, где PPP:
      • TIM2
      • CAN1
    • GPIO_PartialRemap2_PPP, где PPP:
      • TIM2
      • CAN1


uint16_t GPIO_ReadInputData(GPIO_TypeDef *GPIOx)
Возвращает входные данные порта GPIOx
Аргументы:

  • GPIOx: Порт. Варианты значений:
    • GPIOx: где х = (A…G)


uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
Возвращает входное состояние вывода GPIO_Pin порта GPIOx
Аргументы:

  • GPIOx: Порт. Варианты значений:
    • GPIOx: где х = (A…G)
  • GPIO_Pin: Вывод порта. Значение:
    • GPIO_Pin_x: где x = (0…15)

Возвращаемое значение: входное состояние вывода, (uint8_t)Bit_SET или (uint8_t)Bit_RESET.



u16 GPIO_ReadOutputData(GPIO_TypeDef *GPIOx)
Возвращает выходные данные порта GPIOx
Аргументы:

  • GPIOx: Порт. Варианты значений:
    • GPIOx: где х = (A…G)

Возвращаемое значение: выходные данные порта GPIOx.



uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
Возвращает выходное состояние вывода GPIO_Pin порта GPIOx
Аргументы:

  • GPIOx: Порт. Варианты значений:
    • GPIOx: где х = (A…G)
  • GPIO_Pin: Вывод порта. Варианты значений:
    • GPIO_Pin_x: где x = (0…15)

Возвращаемое значение: выходное состояние вывода, (uint8_t)Bit_SET или (uint8_t)Bit_RESET.



void GPIO_ResetBits(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
Присваивает лог. 0 выходному состоянию выводов GPIO_Pin порта GPIOx
Аргументы:

  • GPIOx: Порт. Варианты значений:
    • GPIOx: где х = (A…G)
  • GPIO_Pin: Выводы, одно значение или их комбинация (с помощью оператора или |):
    • GPIO_Pin_x: где x = (0…15)


void GPIO_SetBits(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
Присваивает лог. 1 выходному состоянию выводов GPIO_Pin порта GPIOx
Аргументы:

  • GPIOx: Порт. Варианты значений:
    • GPIOx: где х = (A…G)
  • GPIO_Pin: Выводы, одно значение или их комбинация (с помощью оператора или |):
    • GPIO_Pin_x: где x = (0…15)


void GPIO_StructInit(GPIO_InitTypeDef *GPIO_InitStruct)
Заполняет поля структуры GPIO_InitStruct значениями по-умолчанию:

GPIO_InitStruct->GPIO_Pin = GPIO_Pin_All;
GPIO_InitStruct->GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStruct->GPIO_Mode = GPIO_Mode_IN_FLOATING;

При вызове функции GPIO_Init() и передачи ей указателя на структуру, заполненную по-умолчанию, все выводы порта GPIOx, настроятся в режим плавающего входа с максимальной частотой 2 МГц.
Аргументы:

  • GPIO_InitStruct: Структура типа GPIO_InitTypeDef, содержащая настройки порта


void GPIO_Write(GPIO_TypeDef *GPIOx, uint16_t PortVal)
Присваивает значение PortVal выходным данным порта GPIOx
Аргументы:

  • GPIOx: Порт. Варианты значений:
    • GPIOx: где х = (A…G)
  • PortVal: Значение, записываемое в выходной регистр порта GPIOx


void GPIO_WriteBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, BitAction BitVal)
Присваивает значение BitVal выходному состоянию вывода GPIO_Pin порта GPIOx
Аргументы:

  • GPIOx: Порт. Варианты значений:
    • GPIOx: где х = (A…G)
  • GPIO_Pin: Вывод. Варианты значений:
    • GPIO_Pin_x: где x = (0…15)
  • BitVal: Значение, присваиваемое биту GPIO_Pin выходного регистра порта GPIOx. Варианты значений:
    • Bit_RESET: логический 0
    • Bit_SET: логическая 1

Описание структуры GPIO_InitTypeDef

GPIO_InitTypeDef — тип структуры данных для настройки выводов портов. Для настройки выводов порта необходимо вызвать функцию GPIO_Init(), передав ей указатель на переменную типа GPIO_InitTypeDef. На практике настройка выводов выглядит так:

// Объявляем структуру для настройки вывода
GPIO_InitTypeDef GPIO_InitStruct;
// Настройки: вывод 0 и 1 как двухтактный выход с частотой 50 МГц
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; // Режим
GPIO_InitStruct.GPIO_Pin = (GPIO_Pin_0 | GPIO_Pin_1); // Выводы
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // Макс. частота
// Настроить выводы порта А
GPIO_Init(GPIOA, &GPIO_InitStruct);

или, тоже самое:

GPIO_InitTypeDef GPIO_InitStruct = {GPIO_Pin_0 | GPIO_Pin_1, GPIO_Speed_50MHz, GPIO_Mode_Out_PP};
GPIO_Init(GPIOA, &GPIO_InitStruct);

Поля структуры:

  • GPIOMode_TypeDef GPIO_Mode: Режим работы порта. Варианты значений:
    • GPIO_Mode_AIN: Аналоговый вход
    • GPIO_Mode_IN_FLOATING: Плавающий вход
    • GPIO_Mode_IPD: Вход с подтяжкой к земле
    • GPIO_Mode_IPU: Вход с подтяжкой к питанию
    • GPIO_Mode_Out_OD: Выход с открытым стоком
    • GPIO_Mode_Out_PP: Двухтактный выход
    • GPIO_Mode_AF_OD: Альтернативный выход с открытым стоком
    • GPIO_Mode_AF_PP: Альтернативный двухтактный выход
  • uint16_t GPIO_Pin: Выводы порта. Поле может принимать одно из значений или их комбинацию (с помощью оператора или |):
    • GPIO_Pin_x: Вывод x, где x = (0…15)
    • GPIO_Pin_All: все выводы
  • GPIOSpeed_TypeDef GPIO_Speed: Максимальная частота выходного сигнала. Варианты значений:
    • GPIO_Speed_2MHz: 2 МГц
    • GPIO_Speed_10MHz: 10 МГц
    • GPIO_Speed_50MHz: 50 МГц

Конец статьи.

Настройка выводов STM32F10x для работы с переферийным SPI

В микроконтроллерах серии STM32F10x выводы можно настраивать индивидуально. Вывод может быть настроен программно в один из режимов:

  • Плавающий вход (Input floating);
  • Вход с подтяжкой к питанию (Input pull-up);
  • Вход с подтяжкой к земле (Input pull-down);
  • Аналоговый (Analog);
  • Выход с открытым стоком (Output open-drain);
  • Двухтактный выход (Output push-pull);
  • Двухтактный альтернативный (Alternate function push-pull);
  • Альтернативный с открытым стоком (Alternate function open-drain).

Микроконтроллеры серии STM32F10x имеют в качестве периферии пару или несколько встроенных SPI.

В таблице приведены режимы работы выводов в зависимости от режимов работы SPI.

Вывод Режим работы SPI Режим работы вывода
SPIx_SCK Ведущий (Master) Двухтактный альтернативный
Ведомый (Slave) Плавающий вход
SPIx_MOSI Ведущий, полный дуплекс Двухтактный альтернативный
Ведомый, полный дуплекс Плавающий вход или вход с подтяжкой к питанию
Ведущий с двунаправленной линией данных Двухтактный альтернативный
Ведомый с двунаправленной линией данных SPI в этом режиме не использует вывод.
SPIx_MISO Ведущий, полный дуплекс Плавающий вход или вход с подтяжкой к питанию
Ведомый (точка-точка), полный дуплекс Двухтактный альтернативный
Ведомый (среди нескольких ведомых), полный дуплекс Альтернативный с открытым стоком
Ведущий с двунаправленной линией данных SPI в этом режиме не использует вывод.
Ведомый (точка-точка) с двунаправленной линией данных Двухтактный альтернативный
Ведомый (среди нескольких ведомых) с двунаправленной линией данных Альтернативный с открытым стоком
SPIx_NSS Ведущий или ведомый с аппратным управлением выбором ведомого Плавающий вход или вход с подтяжкой к питанию или к земле
Ведущий с аппратным управлением выбором ведомого, NSS-выход Двухтактный альтернативный
Программное управление выбором ведомого SPI в этом режиме не использует вывод.

Источник: справочное руководство RM0008 от STMicroelectronics.