Включить GPIO на ARM STM32G030K6 - PullRequest
       140

Включить GPIO на ARM STM32G030K6

2 голосов
/ 17 января 2020

Я пытаюсь научиться программировать STM32G030K6, напрямую манипулируя регистрами (не полагаясь на CubeMX). Моя программа предназначена для установки высокого уровня на вывод PA5.

// Target:  STM32G030K6T6
// Goal:    Set pin PA5 to high

#include "stm32g0xx.h"          // Device header

int main(void)
{
    RCC->IOPENR |= 1;           // Enable GPIOA Clock
    GPIOA->MODER |= 0x400;      // Set GPIOA MODE5 to a general purpose output
    GPIOA->ODR = 0x20;          // Set PA5 high

    while(1)
    {

    }
}

Программа вообще не влияет на PA5. Я успешно протестировал установку с помощью программы мигания CubeMX, чтобы доказать, что это не аппаратная проблема.

STM32G030K6: Технические данные

STM32G030K6: Справочное руководство

1 Ответ

2 голосов
/ 18 января 2020

Итак, что я выяснил у вас до сих пор, так это то, что вы купили / приобрели эту часть, положили ее на разделочную доску. Подайте питание и заземление, добавьте светодиод и резистор и подключите stlink. Могу использовать CubeMX и заставить его работать, используя Kiel.

Так что я сделал так, что многие разделительные доски поместили светодиоды и тому подобное на плату, потому что мне надоело подключать элементы отдельно. Части, которые я использовал, вам понадобились, чтобы убедиться, что VDD и VDDA были подключены, но у вас один и тот же контакт, проверьте. VDD и VSS без сомнения, если у вас это работает. NRST подтянулся для хорошей меры, хотя я думаю, что не требуется, поскольку есть внутреннее подтягивание, но BOOT0 действительно требовал понижения, но это STM32G, и вы указали, что SWCLK и BOOT0 имеют один и тот же вывод. ST, к сожалению, уходит от встроенного загрузчика чипа или, по крайней мере, отключен на заводе

ST. Производственное значение: 0xDFFF E1AA

Бит 24 nBOOT_SEL

0 : Сигнал BOOT0 определяется значением контакта BOOT0 (традиционный режим)

1: Сигнал BOOT0 определяется параметром nBOOT0, бит

Таким образом, при поставке новая деталь BOOT0 не является чем-то, что вы можете положитесь на загрузчик и используйте решение uart для загрузки кода во флаг sh, и при этом вы не можете использовать его для того, чтобы не быть лишенным кирпича при выполнении этого уровня работы.

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

У меня нет Киля под рукой, но каждый может получить кросс-компилятор GNU или собрать его из исходников.

apt-get install binutils-arm-linux-gnueabi  gcc-arm-linux-gnueabi

Приведенный ниже код не заботится о вариациях arm-non-eabi- vs arm- linux -gnueabi- кросс-компилятора, он не зависит от этих различий, ему просто нужен компилятор компилятора и компоновщик . * 1 022 *

Теперь это, вероятно, снова приведет к личной битве с некоторыми другими пользователями SO. Работайте сквозь шум. Я специально избегаю CMSIS, я видел реализацию, и вы должны проверить ее, так как сейчас вы не хотите добавлять этот риск в свой код, удалите его и добавьте его позже по желанию. Это мой стиль, он специально контролирует инструкции, используемые для доступа, все основано на большом опыте, даже если вы этого не видите, и создан для того, чтобы читатель имел большие шансы на успех. Сделайте свой собственный, если / когда вы заставите это работать и / или побочные комментарии, которые являются моей настоящей целью, могут помочь вам изучить бинарный файл, который вы строите с помощью своего собственного инструмента, чтобы устранить распространенные ловушки.

Это не просто случай получения кода C в main () для правильного использования кода без кода, вам нужно, чтобы все было от перезагрузки до правого.

Fla sh основанная версия:

fla sh .s

.cpu cortex-m0
.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
.word hang

.thumb_func
reset:
    bl notmain
    b hang
.thumb_func
hang:   b .

.thumb_func
.globl PUT32
PUT32:
    str r1,[r0]
    bx lr

.thumb_func
.globl GET32
GET32:
    ldr r0,[r0]
    bx lr

.thumb_func
.globl dummy
dummy:
    bx lr

notmain. c

void PUT32 ( unsigned int, unsigned int );
unsigned int GET32 ( unsigned int );
void dummy ( unsigned int );

#define RCC_BASE        0x40021000
#define RCC_IOPENR      (RCC_BASE+0x34)

#define GPIOA_BASE      0x50000000
#define GPIOA_MODER     (GPIOA_BASE+0x00)
#define GPIOA_OTYPER    (GPIOA_BASE+0x04)
#define GPIOA_BSRR      (GPIOA_BASE+0x18)

#define DCOUNT 2000000

int notmain ( void )
{
    unsigned int ra;
    unsigned int rx;

    ra=GET32(RCC_IOPENR);
    ra|=1<<0; //enable port a
    PUT32(RCC_IOPENR,ra);

    ra=GET32(GPIOA_MODER);
    ra&=~(3<<(5<<1)); //clear bits 10,11
    ra|= (1<<(5<<1)); //set bit 10
    PUT32(GPIOA_MODER,ra);

    ra=GET32(GPIOA_OTYPER);
    ra&=~(1<<5); //clear bit 5
    PUT32(GPIOA_OTYPER,ra);

    for(rx=0;;rx++)
    {
        PUT32(GPIOA_BSRR, (1<<(5+ 0)) );
        for(ra=0;ra<DCOUNT;ra++) dummy(ra);
        PUT32(GPIOA_BSRR, (1<<(5+16)) );
        for(ra=0;ra<DCOUNT;ra++) dummy(ra);
    }

    return(0);
}

fla sh .ld

MEMORY
{
    rom : ORIGIN = 0x08000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
}

build

arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m0 flash.s -o flash.o
arm-none-eabi-gcc -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding  -mcpu=cortex-m0 -mthumb -c notmain.c -o notmain.o
arm-none-eabi-ld -o notmain.elf -T flash.ld flash.o notmain.o
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy notmain.elf notmain.bin -O binary

Опять вы можете заменить arm-none-eabi на arm- linux -gnueabi, если это то, что у вас есть / найдено. Этот код не заботится о различиях.

Дело в том, что процессор загружается:

Disassembly of section .text:

08000000 <_start>:
 8000000:   20001000    andcs   r1, r0, r0
 8000004:   08000011    stmdaeq r0, {r0, r4}
 8000008:   08000017    stmdaeq r0, {r0, r1, r2, r4}
 800000c:   08000017    stmdaeq r0, {r0, r1, r2, r4}

08000010 <reset>:
 8000010:   f000 f808   bl  8000024 <notmain>
 8000014:   e7ff        b.n 8000016 <hang>

08000016 <hang>:
 8000016:   e7fe        b.n 8000016 <hang>

Приложение fla sh начинается с 0x08000000 в области памяти ARM, называется Main Fla sh Memory в справочном руководстве. В зависимости от настроек загрузочного ремешка 0x08000000 будет зеркально отображаться в 0x00000000, как указано в руководствах по ARM, именно здесь находится таблица векторов. Первое слово - это значение, загружаемое в указатель стека при сбросе, слово по адресу 0x00000004 (которое будет зеркально отображено на 0x08000004) - это вектор сброса.

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

Если предположить, что мы можем получить инструменты для помещения этого двоичного файла во флаг sh в нужном месте, то

08000000 <_start>:
 8000000:   20001000    value loaded into sp on reset
 8000004:   08000011    reset vector

Вектор сброса - это адрес кода, который должен быть выполнен для этого исключения с lsbit, установленным для указания режима большого пальца, lsbit удаляется, он не go в p c. Таким образом, адрес вектора сброса здесь равен 0x08000010, что является правильным:

08000010 <reset>:
 8000010:   f000 f808   bl  8000024 <notmain>
 8000014:   e7ff        b.n 8000016 <hang>

И может следовать за этим, чтобы не существовать, имя точки входа C не важно, и некоторые инструменты добавят дополнительный материал, который он видит label main (), не видел ни одного из них в течение многих лет, но продолжайте делать это, чтобы также доказать, что это не имеет значения.

Так что, если это помещено в main fla sh по адресу arm 0x08000000, тогда этот код будет загружаться и запускаться до кода C.

Примечание. Sram начинается с 0x20000000, а RM показывает, что эта часть имеет 32 МБайт sram, поэтому у него есть по крайней мере 0x1000 байт, чтобы покрыть этот проект большим количеством дополнительной комнаты.

 8000026:   481b        ldr r0, [pc, #108]  ; (8000094 <notmain+0x70>)
 8000028:   f7ff fff8   bl  800001c <GET32>
 800002c:   2101        movs    r1, #1
 800002e:   4301        orrs    r1, r0
 8000030:   4818        ldr r0, [pc, #96]   ; (8000094 <notmain+0x70>)
 8000032:   f7ff fff1   bl  8000018 <PUT32>
...
 8000094:   40021034    andmi   r1, r2, r4, lsr r0

Будь то, как я запрограммировал или через вашу программу и заголовки CMSIS или HAL, вы должны увидеть, что 0x40021034 используется в той или иной форме. Обратите внимание, что эта ваша часть - cortex-m0 +, поэтому она имеет только ограниченное количество расширений thumb2. Обратите внимание, что bl - это две отдельные 16 инструкций, которые могут быть разнесены, но почти всегда находятся в паре, это две инструкции, Остальные инструкции должны быть 16-битными, если вы видите что-то .w в разборке или в инструкциях, отличных от bl 32 или 16 * 2 битами, то это может быть инструкция thumb2, которая не будет работать на этом процессоре и может быть некоторые настройки, которые вы использовали при создании этого кода, вы можете увидеть с помощью этой цепочки инструментов, которую я специально назвал m0, которая фактически совпадает с m0 + с точки зрения набора команд (архитектура armv6-m). Вам не нужен armv7-m для этого чипа, он не будет работать, в armv7-m примерно 100 инструкций, которые не будут работать на чипах на базе armv6-m.

Орринг бит в регистре разрешения ввода-вывода должен напоминать чтение (ldr) из 0x40021034, модификацию чтения значения и запись (str) по тому же адресу.

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

Сброс:

0xEBFF FFFF для порта A

0xFFFF FFFF для других портов

, поэтому вы не можете просто установить один из двух битов, чтобы изменить режим, если биты начинаются с 0b00, тогда можно установить его в 0b01, но для этой части вы можете либо просто сбросьте бит 11, либо лучше управляйте обоими битами и не полагайтесь на состояние сброса, поэтому очистите два бита и установите один из них или сбросьте один и установите другой

5 << 1 означает 5 смещенных влево на один 0b101 сдвиг нуля справа дает 0b1010, который является 0xA, который равен 10, это визуальный способ увидеть, что я связываюсь с PA5, и число 5 есть, но для этого регистра настройки режима вывода вывода 5 - это биты 10 и 11 . 3 << (5 << 1) означает 3 << 10, что является битами 10 и 11. Тильда означает инвертирование всего, поэтому 00000C00 - это инверсия 3 << 10, в результате которой вы получите FFFFF3FF, который с нулевым значением модера будет равен нулю. немного s 10 и 11. теперь orr с 00000400 1 << 10 для установки бита 10. </p>

Мы хотим, чтобы выход хотя бы на данный момент был пу sh -пулл не открытым стоком, так что даже при значении сброса это уже пу sh -пул, я проясняю это для хорошей меры. Теперь я обычно не беспокоюсь о подтягивании или другом регистре настройки gpio, я связываюсь с этими двумя MODER и OTYPER для частей STM32, которые используют это периферийное устройство GPIO (вы увидите, что не все части STM32 используют один и тот же IP, STM32F103 например, используйте другой.

Таким образом, каким-то образом убедитесь, что CMSIS или нет, что созданный код работает с этими регистрами. Из документации GPIOA начинается с 0x50000000, поэтому регистры 0x50000000 и 0x50000004.

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

Пустышка l oop сжигает время, так что в этом случае светодиод мигает, и вы должны настроить DCOUNT на основе тактовых импульсов, используемых для процессора, когда вы работаете не слишком быстро, не слишком медленно, просто правильно. Делая это таким образом с внешней функцией, это уже не мертвый код (для (ra = 0; ra

Нет, код на самом деле не возвращает return (0); некоторые компиляторы не настолько умны и недовольны. (Некоторые настолько умны) и жалуйтесь, что вы не можете туда добраться, YMMV) * ​​1089 *

Все эти части должны быть на месте, чтобы иметь хотя бы половину шансов на эту работу. Это не просто несколько строк кода C.

С помощью stlink инструменты kiel в порядке, и я надеюсь, что есть способ проверить объем памяти, вы захотите изучить 0x08000000 и сравнить его с двоичным файлом, сгенерированным инструментом, и, надеюсь, есть способ проверить вывод инструмента, а также посмотреть, что он построил, это легко сделать с помощью gnu.

вы можете использовать openocd вместо kiel для загрузки и изучения вещей из командной строки, это будет что-то в форме

openocd -f stlink.cfg -f target.cfg

и затем в другом окне

telnet localhost 4444

GDB добавляет намного больше неизвестных ...

тогда вы можете использовать

mdw 0x08000000 40 

В те lnet ветер Теперь мы увидим, что находится в этом главном флаге sh, а затем сравним его с загружаемой частью двоичного файла, чтобы увидеть, действительно ли ваша программа находится там, если вашей программы на самом деле нет, то независимо от того, что вы делаете с C код не заставит его мигать.

Есть способы использовать openocd для указания sh деталей, но это очень специфично для поставщика / детали c, так как они должны добавить эту возможность в openocd, и вы должны иметь правильную версию, из памяти это что-то вроде

flash write_image erase notmain.elf

, если используется «двоичный» с адресной информацией в нем, если вы используете образ памяти, то вам нужно поставить адрес на эта командная строка 0x08000000

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

Если у вас работает openocd и gnu, вы также можете попробовать использовать sram, не имея изначально поддержки fla sh.

sram.s

.cpu cortex-m0
.thumb

.thumb_func
.global _start
_start:
    ldr r0,=0x20001000
    mov sp,r0
    bl notmain
    b .

.thumb_func
.globl PUT32
PUT32:
    str r1,[r0]
    bx lr

.thumb_func
.globl GET32
GET32:
    ldr r0,[r0]
    bx lr

.thumb_func
.globl dummy
dummy:
    bx lr

sram.ld

MEMORY
{
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
    .text : { *(.text*) } > ram
    .rodata : { *(.rodata*) } > ram
    .bss : { *(.bss*) } > ram
}

, так как эта часть использует таблицу векторов, и то, что собирается описать, использует отладчик для размещения и запустить программу в sram, volatile, поэтому при сбросе / перезагрузке она теряется, но она дает возможность экспериментировать без необходимости писать fla sh.

мы скажем отладчику начать выполнение в 0x20000000, поэтому мы хотим, чтобы там была инструкция, а не таблица векторов.

arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m0 sram.s -o sram.o
arm-none-eabi-ld -o notmain.elf -T sram.ld sram.o notmain.o
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy notmain.elf notmain.bin -O binary

всегда проверяйте свой двоичный файл на новом проекте перед запуском

Disassembly of section .text:

20000000 <_start>:
20000000:   4804        ldr r0, [pc, #16]   ; (20000014 <dummy+0x2>)
20000002:   4685        mov sp, r0
20000004:   f000 f808   bl  20000018 <notmain>
20000008:   e7fe        b.n 20000008 <_start+0x8>

2000000a <PUT32>:
2000000a:   6001        str r1, [r0, #0]
2000000c:   4770        bx  lr

2000000e <GET32>:
2000000e:   6800        ldr r0, [r0, #0]
20000010:   4770        bx  lr

20000012 <dummy>:
20000012:   4770        bx  lr
20000014:   20001000    andcs   r1, r0, r0

20000018 <notmain>:
20000018:   b570        push    {r4, r5, r6, lr}

, и это выглядит хорошо.

с openocd теперь вы можете

сбросить остановку load_image notmain.elf резюме 0x20000000

для запуска программы (может потребоваться путь, если вы запустите openocd в каталоге, где находится elf файл и / или вы копируете файл elf в каталог, в котором вы запустили openocd (не te lnet, openocd), тогда вам обычно не нужно указывать путь.

это в sram, а не fla sh так может работать быстрее и может захотеть большее значение задержки l oop.

Если вы просто хотите сделать вывод высоким или низким, тогда просто используйте нужную строку bsrr и избавьтесь от циклов, этот код, как написано, помещает вас в безопасное бесконечное l oop, когда вы возвращаетесь из notmain тот, который не будет мешать работе порта gpio. В рамках вашего исследования бинарного файла, который вы строите с помощью своего инструмента, вам нужно подтвердить, что хотя размещенный вами l oop на самом деле не мертвый код и был реализован (clang имеет было известно, что это мертвый код, так что другие тоже могут это сделать), и некоторые песочницы отменяют вещи, когда вы возвращаетесь из main, поэтому может случиться так, что ваш код теперь в порядке, но выходит из main, и bootstrap отменяет то, что вы сделали с PA5 быстрее, чем Вы можете видеть это.

Это все, что я могу сделать до сих пор, у меня есть часть stm32 cortex-m0 + с работающей конфигурацией openocd, если это помогает, это другая часть, но ядро ​​такое же, если нет другого касания, тогда он должен просто работать, но Вы никогда не знаете.

Может изменить этот ответ, основываясь на дополнительной информации от вас или результатах экспериментов.

Короткий ответ, ваш код модера не сработал бы, иначе он выглядел бы хорошо, но C Код это только часть истории, необходимой для успеха. В этом длинном ответе освещаются основные моменты, которые необходимо учитывать при загрузке и настройке светодиодов. Возможно, что мы оба пропустили дополнительное включение, у меня нет этой части специально, поэтому я не могу на самом деле вытащить один и запустить этот код на нем. Пу sh подходит, чтобы засунуть, я мог бы получить один и сделать доску, и т. Д. c, но это было бы через несколько недель ...

...