ARM. Учебный Курс. Порты GPIO

Над портами инженеры STM поубивались знатно. Такой прорвы настроек и возможных режимо я, честно говоря, даже не ожидал. Порты у STM32F1xx могут работать в режиме*:
 

  • Вход Hi-Z
  • Вход с подтяжкой вверх
  • Вход с подтяжкой вниз
  • Аналоговый вход (для каналов АЦП)
  • Выход с открытым коллектором (стоком, если быть точным)
  • Выход тяни-толкай (push-pull)
  • И альтернативные функции, т.е. работа от периферии. Тут у нас формируется выход вида вида тяни-толкай или открытый коллектор.

 

С железной части порты бывают двух видов стандартные и устойчивые к напряжению в 5 вольт. При том, что напряжение питания у STM32 максимум 3.3 вольта. Разница у портов в схемотехнике. А точнее в том, что у 5V tolerant входов защитные диоды видут на какую то особую шину питания Vdd_ft. Полагаю, что там стоит нечто вроде небольшого повышателя, накачивающего напругу до 5 вольт.
 


Стандартный вывод


Вывод 5V Tolerant

Остальное все более менее стандартно. Сигнал на выход может вывалиться либо с периферии (стрелочка Alternate function Output) либо с выходного регистра. В который мы вольны записывать биты напрямую, либо же воспользоваться служебными регистрами установки/снятия битов.
 

Входной сигнал с ноги попадает в Data register и в Alternate Function Input. Причем селектора там нет, а значит можно по ходу дела считывать и глядеть что там творит периферия.
 

Т.к. RM0008 это общий документ, сразу на все семейство STM32F10x то распиновку выводов конткретного чипа в конкретном корпусе надо смотреть в конкретном даташите. Для STM32F103C8T6, что стоит на Pinboard II она выглядит следующим образом *:

Но этого недостаточно, тут только названия GPIO. А есть же еще альтернативные функции, т.е. периферия. Там же, в даташите, вы найдете такую большую и страшную таблицу, показывающую привязку выводов к периферии, а также разные свойства выводов.

Вот примерный кусок того, что вы должны найти*:

 

Разберем ее чуть подробней.
 

  • Pins — тут все просто. Это номера пинов в выбраном нами корпусе. Тут сразу все, от BGA до TQFP. Если в вашем чипе меньше выводов, то будут стоять прочерки. Т.е. в ядре то пин есть, но наружу не торчит. Печаль…
  • Pin Name — собственно имя GPIO по его основному назначению. То самое, что вы видели на картинке с распиновкой. Помогает ориентироваться.
  • Type — тип вывода. I — только вход, I/O вход-выход, как настроишь, S — supply, т.е. питание по нашенски. Через эти выводы контроллер получает разное ЖРАТ. Сюда входят разные питания (ядра, периферии, АЦП и мало ли еще чего) и земли.
  • I/O Level допустимый уровень напряжения на пине. Собственно бывает только обычный (т.е. 3.3V) и устойчивый к 5 вольтам. Пятивольтовые обозначаются как FT.
  • Main Function — главная функция, то как настроен вывод по дефолту, после сброса питания. Обратите внимание на то, что там не все выводы ведут себя как GPIO, хотя и большинство. Всякие JTAG/SWD любят быть включенными по дефолту. А также тактовые для разных дополнительных кварцев, вроде часовых.
  • Alternate Functions/Defaults — дополнительные периферийные функции. В отличии от тех же AVR, где стоило только включить какой-нибудь UART, так сразу же выводы под UART становились в нужные режимы, тут все по другому. Вывод переводится в режим управления от периферии ручками. Записью битов в регистры. И вот то каким он станет после включения альтернативного режима и указано в колонке Defaults
  • Alternate Functions/Remap —А еще там есть бит ремапа. Позволяющий взять и перебросить многие выводы периферии на другие ноги. Т.е. у того же UART1, например, вывод TX1 может быть либо на PA9 либо на PB6, в зависимости от бита ремапинга порта. Это удобно, легче разводить плату. Цепляешь вывод туда, где удобней, но изрядно взрывает мозг :) Вот в этой колонке и указывается куда что ремапится при выставлении этого бита. Правда надо учитывать, что биты периферии ремапятся не по одному, а сразу все. Т.е. если это UART то сразу RX и TX. Врочем бывают исключения. Подробней надо смотреть в описании регистров ремапинга. Там портянка на три страницы с комбинациями куда что.*

 

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

Конфигурация
Управляется все это хозяйство прорвой регистров. Под которые в User Manual отведена целая глава. Инфы, как минимум, на час вдумчивого вдупления в макулатуру.
 

Итак, портом управляют следующие регистры
 

Пара GPIOx_CRH:GPIOx_CRL
Т.к. порты в STM32 шестнадцати разрядные, а на конфигурацию одной ноги выделено аж четыре бита, то на 16 выводов надо 64 бита. Т.е. два регистра. В CRL хранятся конфиги выводов от 0 до 7, а в CRH с 8 до 15го.
 

Выглядит внутри так:
 

Красными блоками я выделил группы битов, отвечающих за одну ножку. Тут конфигурируются выводы от 0 до 7. Это CRL. В CRH то же самое, но настраиваются пины от 8го до 15го.
 

Все возможные состояния описываются в таблице 18 и 19 из User Manual
 

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

Какой режим выставить зависит от того, что мы хотим получить. Если для ручного дрыганья портами все просто и ясно, то для периферии возможны затупы. Т.к. тут надо вручную выставлять нужные режимы портов для периферии. А кому какой? Ответ на это дает пачка таблиц с 20 по 31 из User Manual * Там таблицы такого вида:
 

Где сказано для какого режима периферии какой режим порта надо поставить. Так что курите документацию. Это вам не AVR, тут ее просто горы :)
 

Также есть такая вещь как ремапинг, позволяющая выводы периферии кидать на другие ножки. За ремапинг отвечает регистр AFIO_MAPR и AFIO_MAPR2 Он один на все GPIO и там описана вся периферия и разные комбинации ремапа портов. Описывать это все не буду, там ОЧЕНЬ много таблиц и разных ссылок. Укажу лишь куда смотреть если что.
 
 

  • Файл RM0008 STM32 User Manual. Раздел 8.3 Alternate function I/O and debug configuration (AFIO) стр. 161
  • Файл RM0008 STM32 User Manual. Раздел 8.4.2 AF remap and debug I/O configuration register (AFIO_MAPR) стр. 170 и далее.

 
Искать там просто — находишь нужную периферию в таблице в разделе 8.3 и смотришь куда ее можно перекинуть. Затем идешь в раздел 8.4.2 и смотришь какие биты для этого нужно записать в регистр AFIO_MAPR.
 
 

Дрыгаем портами вручную
Для ручного дрыгания портами у нас есть регистр GPIOx_ODR в режимах работы порта на выход, все что туда попало вылезает наружу. Если стоит режим тяни-толкай, то запись 1 поднимает вывод вверх, к питанию, а запись нуля прижимает в землю. В режиме открытого коллектора запись 1 переводит ногу в HiZ, т.е. она повисает в воздухе, а запись 0 — прижимает к земле.
 
Структура регистра ODR проста — первые биты от 0 до 15 отвечают за соответствующий вывод, а старшие, от 16 и до 31го не используются вообще.
 

Все же, что на ноге появилось, вылезает во входном регистре GPIOx_IDR. Это аналог регистра PINx в AVR. Т.е. в каком логическом уровне находится вывод МК, такое значение в этом регистре. Даташит говорит, что данные считываются на каждом такте шины APB2.
Структура регистра GPIO_IDR похожая на ODR. Т.е. первые 16 бит отвечают за соответствующие выводы, а старшие не используются.
 

Также там есть регистры атомарных действий. Позволяющие менять значения битов в ODR без использования операций чтение-модификация-запись.
 

Это регистры GPIOx_BSRR и GPIOx_BRR
 

С BRR все просто. Его младшие 16 бит отвечают за сброс бита в ODR.
 

Т.е. надо тебе, например, сбросить бит 3 в ODR, не трогая остальные. Без BRR регистра, надо было бы сначала считать ODR, потом по маске загасить нужный бит, не трогая остальные, а потом вернуть его обратно в ODR в уже измененном виде. Как минимум тут будет три команды. Между которыми может вломиться прерывание и обгадить нам всю малину. C регистром сброса все упрощается до одной команды. Нам нужно только лишь записать «адын» в третий бит GPIOx_BRR и усе, бит 3 в ODR будет сброшен. На нули же никакой реакции не будет. Таким образом можно сбрасывать и несколько битов.
 

Регистр BSRR работает аналогично, только на установку. Т.е. записал ты единичку в третий разряд BSSR и она автоматом выставилась в ODR.
 

Разница лишь в том, что в BRR старшие биты (т.е. 16 до 31) не влияют ни на что, а в BSSR они активны и сбрасывают бит. Записал в бит 0 BSRR единичку — бит 0 в ODR выставился. Записал в бит 16 BSRR единичку — бит 0 в ODR сбросился. Потому то он и зовется Bit Set/Reset Register.
 

 

Блокировка портов.
Есть такой регистр как GPIOx_LCKR записал в него хитрым образом нужный бит и все, этот бит порта блокируется и больше его никак нельзя перенастроить или как либо изменить — группа битов в CRH:CRL блокируется. Только сбросить контроллер через reset.
 

Каждый бит регистра LCKR отвечает за один бит порта. А 16й бит регистра LCKR (LCKK) служит ключиком. Для того, чтобы заблочить порт нужно:
 

Выставить в регистре GPIO_LCKR биты выводов которые мы хотим заблокировать.

  • Записать в бит LCKK 1
  • Записать в бит LCKK 0
  • Записать в бит LCKK 1
  • Считать из LCKK 0
  • Считать из LCKK 1 (этот шаг опциональный, но считывание 1 будет означать, что блокировка установилась)

 
В процессе записи ключевой последовательности нельзя модфицировать биты регистра LCKR кроме 16го, ключевого. Иначе замок не сработает.
 

Тактирование портов
 
Порты GPIO сидят на шине APB2 и тактируются оттуда. По умолчанию тактирование ВЫКЛЮЧЕНО! сделано это скорей ради экономии энергии. Нет тактов — нет потребления. Вообще вся периферия изначально отключена от тактирования. Поэтому то часто возникают непонятки — порты все настроил, а нифига не работает.
 

Такты включаются в регистре RCC_APB2ENR Там такая вот картина:


 

Как видишь, тут каждой периферийной шняге, что висит на шине APB2 присвоен битик. Каждому из портов (от А до G) тоже. Также отдельный бит присвоен альтернативному использованию портов. Бит AFIO. Вот выставляешь эти битики и поехало.
 

Подведем итог. Что нам надо сделать, чтобы помигать таки этим чертовым диодиком?
 

  • Выставить тактирование нужного порта на APB2
  • Сконфигурировать порты в CRH:CRL регистрах на выход «тяни-толкай»
  • Записать/стереть нужный бит в ODR или воспользоваться регистрами BRR или BSRR.

 

Просто как раз-два-три! И чего я тут распинаюсь ;)
 

CMSIS
Теперь поглядим на представление наших портов через призму CMSIS и попробуем написать кусочек кода для мигания. Мигать будем битом на B05.
 

1
2
3
4
5
6
7
8
9
// Выставляем тактирование в APB2
RCC->APB2ENR 	|= RCC_APB2ENR_IOPBEN;
 
// Конфигурируем CRL регистры. 
GPIOB->CRL	&= ~GPIO_CRL_CNF5;	// Сбрасываем биты CNF для бита 5. Режим 00 - Push-Pull 
GPIOB->CRL 	|= GPIO_CRL_MODE5_0;	// Выставляем бит MODE0 для пятого пина. Режим MODE01 = Max Speed 10MHz
 
GPIOB->BSRR = GPIO_BSRR_BR5;		// Сбросили бит. 
GPIOB->BSRR = GPIO_BSRR_BS5;		// Установили бит.

 
Сброс и запись мы делаем через один и тот же регистр BSRR. А записываем в него разное число.

GPIO_BSRR_BR5 = 0x00200000
GPIO_BSRR_BS5 = 0x00000020

Разница лишь в половине в которую идет запись бита. Также можно и напрямую пинать данные в ODR.
 

Набросал простенький примерчик в Keil и запустил на Pinboard II
  Видео уж прикладывать не буду. Что вы, в самом деле, мигающий диод не видели? ;) Уж, надеюсь, поверите мне на слово :)

 
 
to do… тут надо дописать ту же самую портянку, но про LPC1343… когда нибудь.

102 thoughts on “ARM. Учебный Курс. Порты GPIO”

  1. а нафига тогда этот режим??? чем он отличается от обычного нуля на выходе. тот же открытый нижний транзистор, и закрытый верхний.
    или может защитные диоды все же как то отрубаются от пина, и там настоящий ОК выходит )))

    1. Два транзистора. Верхний и нижний. Между ними вывод. Верхний ведет на шину питания, нижний на землю. Открываем верхний — вывод жестко прижимается к питанию. Открываем нижний — к земле.

    2. Нормально push-pull называется двухтактным выходом, что в цифровой, что в аналоговой (усилители) технике. А тяни-толкай это, как пошутил аффтар, из доктора Айболита

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

  2. А как насчет bit-band?
    Есть там такая фраза в даташите как «These bits can be read and written by software and can be accessed in Word mode only.», под описанием регистра ODR. Однако гугление показало что народ вроде как делал и оно работало. Еще пытался найти набор удобных дефайнов для всех пинов(вида PORTA8, например), но не нашел, впрочем тут можно заморочится и самому сенерить, посмотрев по каким адресам там чего лежит.

    Кстати, получается атомарно инвертировать бит нельзя? Жалко, например у xmega если память не изменяет есть такая функция(спец регистр типа BSRR). Интересен самый простоый и/или быстрый способ инвертировать бит в регистре.

      1. У LPC1343 есть битовый доступ через MASKED_ACCESS. Причем это не отдельная команда, область в адресном пространстве (массив по сути). Более того доступ ко всему порту идет через эту же область (где маска == все выводы).

  3. Ну еще хорошо бы добавить что на Remap тоже такты давать надо.

    Что имеется в виду в вопросе про Bit-Band? если руление битами через область памяти в которой каждый байт соответствует своему биту — то да, оно работает, во всяком случае на STM32. Разве что несколько геморно высчитывать адреса.

    А про дефайны типа AVR-овских PORTA, PORTB — каждый порт дефайнится ала GPIOx, а бит этого порта дефайнится как GPIO_Pin_х , где x — буква порта в первом случае и номер пина во втором. Это при использовании CMSIS.

      1. Немного неправильно выразился. Там врубаются такты на регистры управления альтернативными функциями, регистр ремапа тоже относится к этой группе.
        У меня для ремапа SPI1 в коде идут 2 команды:

        // alternative func enable
        RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
        AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_JTAGDISABLE; // disable JTAG

        // remap SPI1 to port B
        AFIO->MAPR |= AFIO_MAPR_SPI1_REMAP;

        Ну и отрубание JTAGа тут докучи

          1. http://tmp.avr.net.ru/bit.zip
            Нате.
            Там два файла, один с дефайнами для F100 (для F10x тоже скорее всего подойдет, не смотрел даташит, пока что 100RBT6 ковыряю). Вид дефайнов
            PORTx_y (пример PORTA_12) и PINx_y (пример PINA_12). Это соответственно биты регистра ODR и IDR.

            Второй файлик — программа для генерации первого. Написана на коленке за 5 минут, лишь бы генерило. Изменять под свой вкус. Вообще было бы круто написать такое для всех битов всей переферии, но это придется повозиться.

          2. Вообще на мой взгляд бит-банд во много раз удобнее использования битовых масок и уж точно нагляднее.
            А уж если хочется помигать светодиодиком, то вообще сказка :)
            PORTC_9 = !PORTC_9;

            Было бы интересно найти/сгенерить для всех регистров переферии(а они в стм32 как я понял ВСЕ попадают в зону битбанда). Тогда можно будет
            GPIOA->CRH |= GPIO_CRH_MODE9_0 | GPIO_CRH_MODE9_1;
            Заменить на
            GPIOA_MODE9_0 = 1;
            GPIOA_MODE9_1 = 1;
            Как по мне, так вторая запись нагляднее и удобнее

      1. Есть в СooCox IDE в
        #include «stm32f10x_gpio.h»

        #define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected */
        #define GPIO_Pin_1 ((uint16_t)0x0002) /*!< Pin 1 selected */
        #define GPIO_Pin_2 ((uint16_t)0x0004) /*!< Pin 2 selected */
        #define GPIO_Pin_3 ((uint16_t)0x0008) /*!< Pin 3 selected */
        #define GPIO_Pin_4 ((uint16_t)0x0010) /*!< Pin 4 selected */
        #define GPIO_Pin_5 ((uint16_t)0x0020) /*!< Pin 5 selected */
        #define GPIO_Pin_6 ((uint16_t)0x0040) /*!< Pin 6 selected */
        #define GPIO_Pin_7 ((uint16_t)0x0080) /*!< Pin 7 selected */
        #define GPIO_Pin_8 ((uint16_t)0x0100) /*!< Pin 8 selected */
        #define GPIO_Pin_9 ((uint16_t)0x0200) /*!< Pin 9 selected */
        #define GPIO_Pin_10 ((uint16_t)0x0400) /*!< Pin 10 selected */
        #define GPIO_Pin_11 ((uint16_t)0x0800) /*!< Pin 11 selected */
        #define GPIO_Pin_12 ((uint16_t)0x1000) /*!< Pin 12 selected */
        #define GPIO_Pin_13 ((uint16_t)0x2000) /*!< Pin 13 selected */
        #define GPIO_Pin_14 ((uint16_t)0x4000) /*!< Pin 14 selected */
        #define GPIO_Pin_15 ((uint16_t)0x8000) /*!< Pin 15 selected */
        #define GPIO_Pin_All ((uint16_t)0xFFFF) /*!< All pins selected */

        И ёще много итересного…

  4. на асме зажечь светики на STM32 value line discovery

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    
    	.syntax unified
    	.cpu cortex-m3
    	.fpu softvfp
    	.thumb
     
    	.section  .isr_vector,"a",%progbits
    	.type  Vectors, %object
    	.size  Vectors, .-Vectors
     
    Vectors:
    	.word  _eram 		@ Вершина Стека
    	.word  main 		@ Reset
     
    main:
    	.include "macros.s"				@ стандартные макросы
    	.include "st32f100rbt6b.s"		@ настройки и имена для контроллера
     
    					MOV		R10, 0			@ для bitbang
    					MOV		R11, 1			@ для bitbang
     
    				# подключаем тактирование к порту С
    					MOV32	R0	, RCC_APB2ENR
    					MOV32	R1	, RCC_APB2ENR_IOPCEN
    					STR		R1	, [R0]
     
    				# конфигурируем пины 8 и 9 порта С (на них сидят диоды)
    					MOV32	R0	, GPIOC+GPIO_CRH
    					MOV		R1	, GPIO_CRH_MODE8 + GPIO_CRH_MODE9
    					STR		R1	, [R0]
     
    				# зажигаем оба диода (пины 8 и 9 устанавливаем в 1)
    					SET_BIT_IO 	GPIOC, GPIO_ODR, 8
    					SET_BIT_IO 	GPIOC, GPIO_ODR, 9
     
    loop:				b loop

    последние (SET_BIT_IO GPIOC, GPIO_ODR, 8 и SET_BIT_IO GPIOC, GPIO_ODR, 9) как раз макрос битбанда

    вот такой

    1
    2
    3
    4
    5
    6
    7
    8
    
    @ макрос установки бита в периферии при помощи bitbang
    		@ использование:
    		@ SET_BIT_IO	GPIOA, GPIO_CRL	, 0  /* установка нулевого бита GPIOA_CRL */
    		@
    		.macro SET_BIT_IO base, reg, bit
            MOV32	R0 , (0x42000000 + (\base + \reg - 0x40000000) * 32 + \bit * 4)
            STR		r11 , [r0]
            .endm
  5. Биты CNF[1:0] изначально выставлены в единицы? Просто в АРМах новичок и не совсем понятны операции &= ~. По отдельности норм. В мануале ничего не нашел. Или просто не там ищу. Хотелось бы узнать что к чему. И еще вопрос? Как определяется битовая маска? В даташнике где то?

    1. Не помню, сбрасываю для верности, чтобы битмаски сразу накладывать по OR. Обращай внимание на звездочки в конце предложений. Наведешь на них — увидишь сноску на конкретную страницу даташита или юзермануала.

      Битмаски все прописаны в CMSIS читай описание библиотеки CMSIS

  6. За звездочки спасибо. По аналогии с подсвеченными пунктами мануала нахожу одноименные у себя. А вот с библиотекой сложнее. Пишу в ИАРе. Зашел в дереве проекта в библиотеку CMSIS там куча .h файлов. Подскажите как бит маски там описываются? Пробовал по поиску ничего определенного нет.

  7. Хорошо. После прочтенного (смотрю пример в статье Keil+CMSIS):
    1. Выражение GPIOA->CRL &= ~GPIO_CRL_CNF3;
    Бит маска GPIO_CRL_CNF3 согласно хидеру 0x0000C000.
    2. После операции ~ она становится 0хFFFF3FFF.
    3. Т.к. 3 бит надо обнулить выполняем операцию 0хFFFF3FFF & 0x00000000.
    Может я что то упустил?

    1. Так, давайте разберемся по порядку, чтобы не было вопросов.

      GPIOA->CRL &= ~GPIO_CRL_CNF3;
      Это эквивалентно
      GPIOA->CRL = GPIOA->CRL & (~GPIO_CRL_CNF3); (написание выше используется для сокращения).
      Дальше, подставляем значение битмаски
      GPIOA->CRL = GPIOA->CRL & (~0x0000C000);
      Теперь побитово инвертируем и получаем фактически это:
      GPIOA->CRL = GPIOA->CRL & 0хFFFF3FFF;

      Таким образом, что мы имеем — в регистр CRL порта А записывается он же, помноженный на 0хFFFF3FFF. Так как умножение Х на 1 дает Х, то везде где в полученном числе стоят 1 — останется то значение которое до этого было в регистре. Так как умножение Х на 0 дает 0, то везде где в полученном числе стоят 0 — получится 0.

      Тоесть этим действием мы обнуляем в регистре CRL те биты, которые соответствуют 1 в изначальной маске GPIO_CRL_CNF, при этом все остальные биты остаются в таком же состоянии, в каком и были до этого.

  8. di halt, это конечно интересно, но хотелось бы почитать статьи для полных новичков, — например как работает кварц, подробный разбор небольших схем с транзистором, как куда идет сигнал и тп.

  9. DI HALT, посоветуйте транзистор для электронного ключа (лучше импортный, рос. не смогу достать, никогда ничего не паял, появилась потребность сделать тросик к фотоаппарату, управляемый с платы), сигнал с вывода STM32l152 на плате STM32L-discovery. Вывод как понимаю нужно переводить в режим тяни-толкай?

  10. Доброго времени суток, вот собрался разбираться с данным семейством, однако, руки не доходили до знакомства с ним, до сегодняшнего дня, пока не предложили преобрести отладочный комплект STM32VLDISCOVERY. И по сему возник вопрос, могу ли я с данным комплектом в основе, которого мк STM32F100RBT6B, пользоваться данными уроками , где, как я понял, рассматривается 103 серия ( и вообще есть ли существенная разница между этими сериями). Прошу сильно не бить за столь глупый вопрос, т.к. семейство абсолютно не знакомое и новое для меня и времени на раздумья 1 — 2 дня, нет времени разбираться. И прошу прощения если вопрос не туда адресован и если гдето уже был задан подобный вопрос

    1. вопрос цены, возможностей и целей, для многих задач этой платы «за глаза»

      раньше в авр начинали с меги8 или 16 — так вот F100RB быстрее обоих, флеша больше (128 кб), озу больше и так далее..
      более чем достаточно чтобы начать! да и продолжить тоже :-)

  11. DI HALT, добрый день. Знаю что вы работали с модулями Radiocrafts RC1240, прочитал вашу статью, но т.к. там последний коммент датируется 2010 годом, решил написать сюда, в надежде на вашу помощь)

    Не подскажете, в чем может быть проблема — три модуля закупил (из одной партии, явно, даже в одной ленте были), подключаю по даташиту — никакого отклика, даже тестового меандра с 20го пина нет.

    Соединял как в даташите — Vcc — 3.3В (пробовал также и с 5.0В), все пины GND, понятное дело, на землю, CTS, RTS, CONFIG — подключены к пину Vdd. On/Off пин подключен к Vcc.
    Reset — висит в воздухе, пробовал также коснуться им Gnd и потом бросить в воздухе, а также — коснуться им Gnd и потом подключить к Vdd.
    Антену пока не паял.
    На выходе Vdd присутствуют искомые 2.7В, замеры потребляемого модулем тока соответствуют даташитовским — после включения показывает 20.5 мА, когда On/Off подключаю к земле — 0 мА, когда CTS, RTS на землю — 9 мА. Но меандра нет. И уарт молчит. Никаких реакций на
    CONFIG->LOW нет.
    Уже все перепробовал, даже с оф. дистрибютерами связался — те почесали голову и сказали «свяжемся позже».

  12. Пустяшное дело: подключение к Discovery (VL) четарех разрядного семисегментного LCD, вылилось в познавательную прогулку по даташиту. При 16ти разрядных портах можно, одной посылкой в порт, подавать код сегмента и знакомест, в которых эти сегменты встречаються. О целесообразности такого подхода можно поспорить, основным мотивом был тот , что в этом случае, нагрузкой на пин будут не боле 4х сегментов (традиционно — 8). Итого нужно 8 пин (с учетом запятой) и 4 пина под знакоместа. Смотрим на Discover и видим что порт «А» создан для поставленной цели, там подряд разведены по 8 младшие и старшие разряды этого порта. Под сегменты берем РА8-РА15, под знакоместа: РА0-РА3. Индикатор таков , что для зажигания сегмента требуеться плюс не знако место и корпус на сегмент. Отсюда: РА8-РА15 ставим в режим OD (Open-drin), а РА0-РА3 в РР.
    С портами оказалось понятней без структур. Инициализация выглядит так:
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
    GPIOA->CRL=0x33333333;// Режим РР,Выход, 50МГц порт А младший байт
    GPIOA->CRH=0x77777777;//Режим OD,Выход, 50МГц порт «А» старший байт
    Начинаешь играться с сегментами, запуская вариации : GPIOA->ODR=0xEFFF; // Здесь горит один сегмент во всех знакоместах.
    ОДНАКО сегменты на РА13 РА14 горят постоянно.Находим в мануалах табицу 5(так она звучит в обсуждаемой статье) и видим ,что на этих пирах висит отладчик, и действительно,стоит снять джамперы отладчика -сегменты гаснут. Гаснут но зажечь то их не удаётся.Читаем. Похоже по умолчанию это и не порты вовсе, и надо покурить,чтобы они стали таковыми. Ultrin в этом форуме от 7го февраля, оказывается очень кстати. Пишем инициализацию.
    RCC->APB2ENR|=RCC_APB2ENR_AFIOEN;// Remapingu это надо
    AFIO->MAPR|=AFIO_MAPR_SWJ_CFG_DISABLE;//Глушим JTAG и SW,
    GPIOA->CRL=0x33333333;// Режим РР,Выход, 50МГц порт А младший байт
    GPIOA->CRH=0x77777777;//Режим OD,Выход, 50МГц порт «А» старший байт,
    Снимаем перемычки программатора,иначе сегменты на РА13,РА14 не гаснут.Заработало.
    Небольшой стресс, Отключив JTAG и SW залить следующую программу не удастся, если не держать кнопку RESET пока не начнет мигать диод заливки. Такой вот экскурс.
    while (1)
    {
    GPIOA->ODR=0xF7F1;
    Delay(0x00FFF);
    GPIOA->ODR=0xBFF2;
    Delay(0x00FFF);
    GPIOA->ODR=0xDFF4;
    Delay(0x00FFF);
    GPIOA->ODR=0xEFF8;
    Delay(0x00FFF);
    }
    Горят четыре разных сегмента, по одному в знакоместе….

  13. Добрый вечер всем! Возник вопрос про 7 сегментный индикатор. На индикацию ничего не выводит, прошиваю — тишина (точнее «темнота») хотя JTAGом смотрю все биты в порядке. Может в коде что не так.
    #include «stm32f10x.h»
    #define SYSCLK_FREQ_72MHz 72000000

    void Delay_ms(unsigned long takt)
    {
    unsigned long clk=(SYSCLK_FREQ_72MHz/1000000)*takt;

    for(; clk != 0; clk—);

    }

    unsigned char chisla[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
    unsigned char schet = 0;

    void main(void)
    {

    RCC->APB2ENR |= RCC_APB2ENR_IOPEEN;

    GPIOE->CRH &= ~GPIO_CRH_CNF8;
    GPIOE->CRH &= ~GPIO_CRH_CNF9;
    GPIOE->CRH &= ~GPIO_CRH_CNF10;
    GPIOE->CRH &= ~GPIO_CRH_CNF11;
    GPIOE->CRH &= ~GPIO_CRH_CNF12;
    GPIOE->CRH &= ~GPIO_CRH_CNF13;
    GPIOE->CRH &= ~GPIO_CRH_CNF14;
    GPIOE->CRH &= ~GPIO_CRH_CNF15;

    GPIOE->CRH |= GPIO_CRH_MODE8_0;
    GPIOE->CRH |= GPIO_CRH_MODE9_0;
    GPIOE->CRH |= GPIO_CRH_MODE10_0;
    GPIOE->CRH |= GPIO_CRH_MODE11_0;
    GPIOE->CRH |= GPIO_CRH_MODE12_0;
    GPIOE->CRH |= GPIO_CRH_MODE13_0;
    GPIOE->CRH |= GPIO_CRH_MODE14_0;
    GPIOE->CRH |= GPIO_CRH_MODE15_0;

    while(1)
    {

    GPIOE->ODR = chisla[schet];
    schet++;

    if (schet == 10) schet=0;

    Delay_ms(100);

    }
    }

  14. ПРивет! Вопрос следующий. Как обратно ремапнуть порты в состояние дефолта? Камень stm32f107. Выводы РС10 и РС11 настроены как ТХ и RX USART3. Почитал даташит — думаю это делается с помощью регистра Event control register (AFIO_EVCR). Нужно уточнение правильно ли или нет. Спасибо!

  15. А не подскажите как бы замапить порты, скажем для выдачи 32 бит разом для stm32F4 ?
    Скажем есть переменная (x) 32 бит (uint32_t) с каким-либо значением, допустим 0x11111111
    И нужно одной командой типа PORTx = x выдать значение в порт. Возможно это сделать ?

    1. Одной командой не получится. Т.к. порты 16ти разрядные. Но думаю можно будет накорячить через указатели и привязать разные половинки к одному значению. Порты то замаплены в память.

  16. А как заставить порт работать на те вот 50 мгц на STM32F10xxx, пробовал через библиотеки, пробовал писать в сам регистр. Все равно максимум что получилось, это 84 нано сек(10Мгц где то). Сильно не копался в системе тактирования, но может там есть что то такое. Или эти порты могут работать только на вход ? с такой частотой.

  17. Подскажите, пожалуйста, только начал тут разбираться с программированием STMок несколлько раз перечитал раздел статьи о GPIOx_LCKR (блокировкой порта) и так толком не понял зачем он нужен, я думал бит LCKK блокирует весь порт от изменений а нифига! :)
    Вот кусок кода (STM32F103C8):
    http://easyelectronics.ru/repository.php?act=view&id=99

    PS:
    1) хотелось бы поподробней про этот момент.
    2) Почему приходится делать столько телодвижений для блокировки? Не проще ли просто записать 1 в бит LCKK?

    1. А у тебя вообще блокировка включилась? Может ты из таймингов выбился? Бит установился в реале?

      Так сделано, чтобы случайно не включилась блокировка. Например, при срыве стека. Это очень серьезная фича, потом через такой форватер прогоняется.

  18. Зачем регистр BSRR и записывает и сбрасывает порты? Если сразу запишу в него вот это значение BSRR=0x00010001, что с выходом произойдет? И раз такой уж универсальный регистр этот BSRR, то зачем тогда еще один BRR который только сбрасывает биты? Может какие-то особенности его применения есть?

    1. Вот уж не знаю, надо спросить у разработчиков. Он либо сбросится либо вставится. По моему там сброс более приоритетный. Но не помню, в ДШ было написано, что там приоритетней.

      Никаких особенностей я не заметил. Вообще складывается ощущение, что имея такое огромное адресное пространство разработчики изголялись кто во что горазд. Мол а я и так могу и так могу и этак могу.

  19. Растолкуйте пожалуйста такую вещь:
    Есть ли разница между режимами входа с подтяжкой к питанию и с подтяжкой к земле? При наличии входного сигнала результат все равно одинаков. У меня только такое объяснение: при отсутствии входного сигнала в одном случае на входе будет +Uп а в другом 0, другого смысла не вижу.
    И в чем смысл выхода с открытым стоком, с физической точки зрения? Какое применение этого режима?

    1. Именно так, разное поведение при отсутствии сигнала. А открытый сток это выход позволяющий коротить сигнал на землю и только так. Полезен при работе на шину с подтяжкой. Вроде i2c или 1-wire.

      1. Нигде не нашел информации о нагрузочной способности портов ввода вывода. Какой ток могут выдавать обычные пины и толерантные к 5в? На PB2 если я подключу к линейке светодиодов, ничего не попалю? Там 200 Ом резисторы, т.е. ток ~ 15 — 20 мА.

        1. Все зависит от количества светодиодов. Я подключал 8 каждый через 220ом но они чуть тускловато светились.

          Смотришь даташит, и там есть глава Absolute maximum ratings

          Output current sunk by any I/O and control pin = 25 mA.

          Хоть в даташите написано что any, то есть на любую ногу. Но вот кажется, что это на все ноги. По крайне мере на мегу можно повесить 4х разрядный 7 сегментный индикатор(3смХ1.5см), и все разряды будут светиться нормально. А тут вешаешь 2 разряда, нормально а если еще 2 то уже тусклое свечение на всех разрядах.

          1. Проверил только что, 8 светодиодов каждый с своими резисторами в 220ом, при питании 3.3V => 35.05mA через светодиод ток течет где то 4.2-4.4 мА.

            Спасибо DIHALT, обратил внимание на Total current into VDD/VDDA power lines (source) = 150мА

            Это и есть максимальный ток, который можно прогнать через микроконтроллер на порты ввода вывода.

          2. А как ты проверил? Амперметром что ли?
            Если по расчетам, то выходит, что:
            I = (Uп — Uд)/R = (3.3 — 0.5) / 220 = 12,3 мА
            где Uд — падение на диоде.. взял от балды
            У тебя на диоде ~2,3 В падает?

  20. Подскажите только начал изучать контроллеры этого семейства поэтому не судите строго. Из того что я пока вычитал управляю ножками порта так :
    GPIO_SetBits(GPIOE, GPIO_Pin_12);
    GPIO_ResetBits(GPIOE, GPIO_Pin_12);
    а если мне надо включить сразу несколько ножек это аж прописывать каждую :
    GPIO_SetBits(GPIOE, GPIO_Pin_8);
    GPIO_SetBits(GPIOE, GPIO_Pin_9);
    GPIO_SetBits(GPIOE, GPIO_Pin_12);
    есть ли другие варианты управления, например в как в AVR контроллерах PORTA=0b01011001;

  21. Настраиваю CAN на f103. Выводы CANRX = PA11, CANTX = PA12 оставляю по умолчанию без ремапинга. РА11 настроил согласно RM008 как Input with pull-up / pull-down, а РА12 как alternate push-pull 50 МГц.
    1. После этого CAN автоматом подключается к указанным выводам?
    2. В RM008 говорится что по умолчанию к этим выводам подключаются и другие альтернативные функции. Они не включатся одновременно (если вдруг понадобится настроить)?
    3. Требуется ли включать тактирование AFIO и его настраивать если и так все по умолчанию выставлено как надо? Или без тактирования AFIO альтернативные функции не будут работать?

  22. 1. По идее должен. Надо смотреть ДШ может что еще забыл.
    2. Нет ,если ты не включишь эти блоки. Ну и у каждого там свои заморочки же, кому то надо push-pull кому то OpenDrain и так далее.
    3. Да, обязательно.

  23. Начал потихоньку изучать stm32 (отладочная плата STM dyscovery F3). Наткнулся на такой глюк. Конфигурирую порт на вход с подтяжкой вниз:
    buttoninit.GPIO_Mode = GPIO_Mode_IN; // направление — выход
    buttoninit.GPIO_PuPd = GPIO_PuPd_DOWN; // подтяжка вниз
    buttoninit.GPIO_Speed = GPIO_Speed_Level_2; // Скорость низкая
    buttoninit.GPIO_Pin = BUTTONPIN; // кнопка на 0м выводе
    GPIO_Init(BUTTONPORT, &buttoninit);
    При подаче питания на контроллер он считает что кнопка нажата. После сброса всё норм, если ввести задержку между инициализацией и бесконечным циклом (где опрашивается кнопка) тоже всё норм. Кнопка находится на PA0, кроме неё там ничего нет. Я так понимаю что подтягивающий резистор к общему подключается далеко не сразу, или я что то упускаю.

Добавить комментарий