LINUX.ORG.RU

разработка STM32 + asm

 , ,


1

3

Всем доброго времени суток! Недавно начал розбиратся с микроконтроллером stm32f103c8t6.

Код прошивки решено было писать на ассемблере.

@ Compiler settings
.syntax unified
.thumb
.cpu cortex-m3

@ Global Variables

.equ TIMER_FREQUENCY ,0x00001500

@ Libs

.include "libs/stm32f10x.inc"
.include "libs/stm32.inc"
.include "libs/time.inc"


@ Program

.section .text


.word	0x20005000		@ Стек
.word	Reset+1		@ Адрес перехода при сбросе.


Reset:
	RCC_CLOCK_SET	RCC_APB2ENR, RCC_APB2Periph_GPIOC
	GPIO_MODE_SET	GPIOC_BASE, GPIO_CRH, 0x22222222

BLINK_LOOP:
	GPIO_STATE_SET	GPIOC_BASE, 0x0000FFFF

	DELAY	1000

	GPIO_STATE_SET	GPIOC_BASE, 0xFFFF0000

	DELAY	1000
	
	B	BLINK_LOOP

FUNC_DELAY:
		MOV32	R2, TIMER_FREQUENCY
		MUL	R2, R3
DELAY_LOOP:	SUBS	R2, R2, 1
		BNE	DELAY_LOOP
		BX	LR

time.inc

.macro	DELAY time
	MOV32	R3, \time
	BL	FUNC_DELAY
.endm

stm32.inc

.macro	MOV32 regnum,number
	MOVW \regnum,:lower16:\number
	MOVT \regnum,:upper16:\number
.endm

.macro	RCC_CLOCK_SET RCC_APB, RCC_APBPeriph
	MOV32	R0, RCC_BASE + \RCC_APB     	@ адрес
	MOV32   R1, \RCC_APBPeriph       	@ значение
	LDR	R2, [R0]			@ прочитали значение регистра
	ORR	R1, R1, R2			@ логическое, побитовое ИЛИ : R1= R1 ИЛИ R2
	STR	R1, [R0]			@ запись R1 по адресу указанному в R0
.endm

.macro	GPIO_MODE_SET GPIO_BASE, GPIO, GPIO_PIN
	MOV32	R0, \GPIO_BASE + \GPIO
	MOV32   R1, \GPIO_PIN
	LDR   	R2, [R0]
	ORR	R1, R1, R2
	STR	R1, [R0]
.endm

.macro	GPIO_STATE_SET GPIO_BASE, GPIO_PIN
	MOV32	R0, \GPIO_BASE + GPIO_BSRR
	MOV32   R1, \GPIO_PIN
	STR   	R1, [R0]
.endm

stm32f10x.inc

@ <MEMORY>

.equ FLASH_BASE            ,0x08000000
.equ SRAM_BASE             ,0x20000000
.equ PERIPH_BASE           ,0x40000000

@ <Peripheral memory map>

.equ APB1PERIPH_BASE       ,PERIPH_BASE
.equ APB2PERIPH_BASE       ,PERIPH_BASE + 0x10000
.equ AHBPERIPH_BASE        ,PERIPH_BASE + 0x20000

@ <GPIO>

.equ GPIO_BSRR		   ,0x10

.equ GPIO_CRL		   ,0x00	@ pin 0-7
.equ GPIO_CRH		   ,0x04	@ pin 8-15

.equ GPIO_IDR		   ,0x08
.equ GPIO_ODR		   ,0x0C

.equ GPIO_BRR		   ,0x14
.equ GPIO_LCKR		   ,0x18

.equ GPIOA_BASE            ,APB2PERIPH_BASE + 0x0800
.equ GPIOB_BASE            ,APB2PERIPH_BASE + 0x0C00
.equ GPIOC_BASE            ,APB2PERIPH_BASE + 0x1000
.equ GPIOD_BASE            ,APB2PERIPH_BASE + 0x1400
.equ GPIOE_BASE            ,APB2PERIPH_BASE + 0x1800
.equ GPIOF_BASE            ,APB2PERIPH_BASE + 0x1C00
.equ GPIOG_BASE            ,APB2PERIPH_BASE + 0x2000

@ <RCC>

.equ RCC_BASE              ,AHBPERIPH_BASE + 0x1000

.equ RCC_APB1RSTR	   ,0x10
.equ RCC_APB2RSTR	   ,0x0C

.equ RCC_AHBENR		   ,0x14
.equ RCC_APB1ENR	   ,0x1C
.equ RCC_APB2ENR	   ,0x18

.equ RCC_RCC_CIR	   ,0x08
.equ RCC_BDCR	   	   ,0x20

@ <RCC_PERIPH>

.equ RCC_AHBPeriph_DMA1               ,0x00000001
.equ RCC_AHBPeriph_DMA2               ,0x00000002
.equ RCC_AHBPeriph_SRAM               ,0x00000004
.equ RCC_AHBPeriph_FLITF              ,0x00000010
.equ RCC_AHBPeriph_CRC                ,0x00000040

.equ RCC_APB2Periph_AFIO              ,0x00000001
.equ RCC_APB2Periph_GPIOA             ,0x00000004
.equ RCC_APB2Periph_GPIOB             ,0x00000008
.equ RCC_APB2Periph_GPIOC             ,0x00000010
.equ RCC_APB2Periph_GPIOD             ,0x00000020
.equ RCC_APB2Periph_GPIOE             ,0x00000040
.equ RCC_APB2Periph_GPIOF             ,0x00000080
.equ RCC_APB2Periph_GPIOG             ,0x00000100
.equ RCC_APB2Periph_ADC1              ,0x00000200
.equ RCC_APB2Periph_ADC2              ,0x00000400
.equ RCC_APB2Periph_TIM1              ,0x00000800
.equ RCC_APB2Periph_SPI1              ,0x00001000
.equ RCC_APB2Periph_TIM8              ,0x00002000
.equ RCC_APB2Periph_USART1            ,0x00004000
.equ RCC_APB2Periph_ADC3              ,0x00008000
.equ RCC_APB2Periph_TIM15             ,0x00010000
.equ RCC_APB2Periph_TIM16             ,0x00020000
.equ RCC_APB2Periph_TIM17             ,0x00040000
.equ RCC_APB2Periph_TIM9              ,0x00080000
.equ RCC_APB2Periph_TIM10             ,0x00100000
.equ RCC_APB2Periph_TIM11             ,0x00200000

.equ RCC_APB1Periph_TIM2              ,0x00000001
.equ RCC_APB1Periph_TIM3              ,0x00000002
.equ RCC_APB1Periph_TIM4              ,0x00000004
.equ RCC_APB1Periph_TIM5              ,0x00000008
.equ RCC_APB1Periph_TIM6              ,0x00000010
.equ RCC_APB1Periph_TIM7              ,0x00000020
.equ RCC_APB1Periph_TIM12             ,0x00000040
.equ RCC_APB1Periph_TIM13             ,0x00000080
.equ RCC_APB1Periph_TIM14             ,0x00000100
.equ RCC_APB1Periph_WWDG              ,0x00000800
.equ RCC_APB1Periph_SPI2              ,0x00004000
.equ RCC_APB1Periph_SPI3              ,0x00008000
.equ RCC_APB1Periph_USART2            ,0x00020000
.equ RCC_APB1Periph_USART3            ,0x00040000
.equ RCC_APB1Periph_UART4             ,0x00080000
.equ RCC_APB1Periph_UART5             ,0x00100000
.equ RCC_APB1Periph_I2C1              ,0x00200000
.equ RCC_APB1Periph_I2C2              ,0x00400000
.equ RCC_APB1Periph_USB               ,0x00800000
.equ RCC_APB1Periph_CAN1              ,0x02000000
.equ RCC_APB1Periph_CAN2              ,0x04000000
.equ RCC_APB1Periph_BKP               ,0x08000000
.equ RCC_APB1Periph_PWR               ,0x10000000
.equ RCC_APB1Periph_DAC               ,0x20000000
.equ RCC_APB1Periph_CEC               ,0x40000000

@ <BSSR>

.equ GPIO_BSRR_BS0                        ,0x00000001    @< Port x Set bit 0
.equ GPIO_BSRR_BS1                        ,0x00000002    @< Port x Set bit 1
.equ GPIO_BSRR_BS2                        ,0x00000004    @< Port x Set bit 2
.equ GPIO_BSRR_BS3                        ,0x00000008    @< Port x Set bit 3
.equ GPIO_BSRR_BS4                        ,0x00000010    @< Port x Set bit 4
.equ GPIO_BSRR_BS5                        ,0x00000020    @< Port x Set bit 5
.equ GPIO_BSRR_BS6                        ,0x00000040    @< Port x Set bit 6
.equ GPIO_BSRR_BS7                        ,0x00000080    @< Port x Set bit 7
.equ GPIO_BSRR_BS8                        ,0x00000100    @< Port x Set bit 8
.equ GPIO_BSRR_BS9                        ,0x00000200    @< Port x Set bit 9
.equ GPIO_BSRR_BS10                       ,0x00000400    @< Port x Set bit 10
.equ GPIO_BSRR_BS11                       ,0x00000800    @< Port x Set bit 11
.equ GPIO_BSRR_BS12                       ,0x00001000    @< Port x Set bit 12
.equ GPIO_BSRR_BS13                       ,0x00002000    @< Port x Set bit 13
.equ GPIO_BSRR_BS14                       ,0x00004000    @< Port x Set bit 14
.equ GPIO_BSRR_BS15                       ,0x00008000    @< Port x Set bit 15

.equ GPIO_BSRR_BR0                        ,0x00010000    @< Port x Reset bit 0
.equ GPIO_BSRR_BR1                        ,0x00020000    @< Port x Reset bit 1
.equ GPIO_BSRR_BR2                        ,0x00040000    @< Port x Reset bit 2
.equ GPIO_BSRR_BR3                        ,0x00080000    @< Port x Reset bit 3
.equ GPIO_BSRR_BR4                        ,0x00100000    @< Port x Reset bit 4
.equ GPIO_BSRR_BR5                        ,0x00200000    @< Port x Reset bit 5
.equ GPIO_BSRR_BR6                        ,0x00400000    @< Port x Reset bit 6
.equ GPIO_BSRR_BR7                        ,0x00800000    @< Port x Reset bit 7
.equ GPIO_BSRR_BR8                        ,0x01000000    @< Port x Reset bit 8
.equ GPIO_BSRR_BR9                        ,0x02000000    @< Port x Reset bit 9
.equ GPIO_BSRR_BR10                       ,0x04000000    @< Port x Reset bit 10
.equ GPIO_BSRR_BR11                       ,0x08000000    @< Port x Reset bit 11
.equ GPIO_BSRR_BR12                       ,0x10000000    @< Port x Reset bit 12
.equ GPIO_BSRR_BR13                       ,0x20000000    @< Port x Reset bit 13
.equ GPIO_BSRR_BR14                       ,0x40000000    @< Port x Reset bit 14
.equ GPIO_BSRR_BR15                       ,0x80000000    @< Port x Reset bit 15

На этапе компиляции никаких ошибок не возникает. Прошивка нормально заливается в микроконтроллер. Светодиод на плате моргает, но проверка пинов мультиметром показывает что питание на порты не подается(напряжение на порту C13(порт встроеного светодиода) скачет в приделах от 0 до 2 вольт, при чем 2 вольта появляется когда светодиод гаснет).

Подозрения в параметрах, передаваемых компилятору или линковщику

Makefile

all:
	arm-none-eabi-as -o 'bin/main.o' main.asm
	arm-none-eabi-ld -T stm32f103c8t6.ld -o 'bin/main.elf' 'bin/main.o'
	arm-none-eabi-objcopy -O binary 'bin/main.elf' 'bin/output.bin'
	rm -rf 'bin/main.o' 'bin/main.elf'
	st-flash write 'bin/output.bin' 0x8000000

Буду рад любой помощи

Мозохист штоле. Писать для стмок на си - тот ещё баттхёрт, а ассемблер так уж совсем что-то не совместимое с жизнью.

Скорее всего ты не настроил питание МК. Посмотри даташит внимательнее - там что-то было про это. Ещё проверь осциллографом ножки. Мб просто он у тебя мигает.

И да, бери HAL и пиши на си. ассемблером ты ничего не выиграешь. Тактовая частота всё-равно в разы выше возможностей IO. И есть DMA и куча переферии.

SL_RU ★★★★
()
Ответ на: комментарий от SL_RU

Хорошо, перечитаю даташит может что-то полезное найду

По поводу си: заливал код написаный на си - все работало замечательно но уж больно люблю ассемблер и то что код не захотел правильно работать меня немного разстроило(я по ходу мазохист).

maxissmax
() автор топика
Ответ на: комментарий от SL_RU

Зойчем ты человеку кал советуешь? Что он тебе сделал?

anonymous
()
Ответ на: комментарий от maxissmax

А логического анализатора у тебя нет случаем? Или осциллографа? У мя подозрения, что ножка просто дёргается оч быстро.

А с питанием точно всё норм?

SL_RU ★★★★
()

Почему скрипт линкера не показываешь? Я бы для начала попробовал посмотреть отладчиком, сравнить значения в регистрах в обоих вариантах программы. А правильно ли ты настраиваешь порт? Как я понял, ты в макросе GPIO_MODE_SET пишешь в регистр GPIOС_CRH значение 0x22222222, но это вроде бы соответствует альтернативной функции. Хотя может я ошибаюсь.

anonymous
()
Ответ на: комментарий от anonymous

Вот скрипт линкера:

/*
 * STM32103C8T6 Linker Script
 * Now based on CMSIS 3.01 example
 */

__estack = 0x20005000;

MEMORY
{
  FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
  RAM (xrw)  : ORIGIN = 0x20000000, LENGTH = 20K
}
SECTIONS
{

  .text :
  {
    KEEP(*(vectors))
    *(.text*)

    KEEP(*(.init))
    KEEP(*(.fini))

    /* .ctors */
    *crtbegin.o(.ctors)
    *crtbegin?.o(.ctors)
    *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
    *(SORT(.ctors.*))
    *(.ctors)

    /* .dtors */
    *crtbegin.o(.dtors)
    *crtbegin?.o(.dtors)
    *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
    *(SORT(.dtors.*))
    *(.dtors)

    *(.rodata*)
    
    KEEP(*(.eh_frame*))
  } >FLASH

  .ARM.extab : 
  {
    *(.ARM.extab* .gnu.linkonce.armextab.*)
  } > FLASH

  __exidx_start = .;
  .ARM.exidx :
  {
    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
  } > FLASH
  __exidx_end = .;

  __etext = .;

  .data : AT (__etext)
  {   
    __sdata = .;
    *(vtable)
    *(.data*)

    . = ALIGN(4);
    /* preinit data */
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP(*(.preinit_array))
    PROVIDE_HIDDEN (__preinit_array_end = .);

    . = ALIGN(4);
    /* init data */
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP(*(SORT(.init_array.*)))
    KEEP(*(.init_array))
    PROVIDE_HIDDEN (__init_array_end = .);

    . = ALIGN(4);
    /* finit data */
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP(*(SORT(.fini_array.*)))
    KEEP(*(.fini_array))
    PROVIDE_HIDDEN (__fini_array_end = .);

    . = ALIGN(4);
    __edata = .;
  } > RAM

  .bss :
  {
    __sbss = .;
    *(.bss)
    __ebss = .;
  } > RAM

}

Значение 0x22222222 -> 2(в шестнадцатеричной) = 0010(в десятичной): 00 - push-pull мод 10 - частота 2MHz (изходя из даташита по данному контроллеру)

maxissmax
() автор топика
Ответ на: комментарий от SL_RU

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

maxissmax
() автор топика
Ответ на: комментарий от Dron

Я здесь уже отметился. Повторюсь: ни в коем случае никакого калокуба, но и ассемблер на мой взгляд - крутовато! Реализовать стек usb или tcp/ip на асме - тот будет еще гемор!

Libopencm3 тоже не советую: у нее разрабы - наркоманы! Только свой набор снипетов + cmsis + кое какие библиотеки вроде usb (чтобы уж совсем все руками не писать).

anonymous
()

Может быть я сейчас скажу какую-нибудь глупость, но гцц умеет выводить листинг на асме. Посмотри как компилируется из це без оптимизации или с -O1 и поправь свою программу. Если думаешь, что проблема как-то связана с линковкой, в чём я глубоко сомневаюсь, то можешь линковать тоже через гцц. И зечем тебе все эти crt, если ты пишешь на асме? В твоём случае, как мне кажется, достаточно просто обозначить расположение кода во флеше через -Ttext -Tdata или даже через .org в асме и всьо.

anonymous
()
Ответ на: комментарий от anonymous

Как то так?

arm-none-eabi-gcc -x assembler -O1 main.asm -o 'bin/main.o'

Вот вывод:

/usr/lib/gcc/arm-none-eabi/5.4.1/../../../arm-none-eabi/lib/libc.a(lib_a-exit.o): In function `exit':
/home/tin/projects/debian/arm-toolchain/collab-maint/newlib/newlib.git/build/arm-none-eabi/newlib/libc/stdlib/../../../../../newlib/libc/stdlib/exit.c:70: undefined reference to `_exit'
/usr/lib/gcc/arm-none-eabi/5.4.1/../../../arm-none-eabi/lib/crt0.o: In function `_start':
/home/tin/projects/debian/arm-toolchain/collab-maint/newlib/newlib.git/build/arm-none-eabi/libgloss/arm/../../../../libgloss/arm/crt0.S:425: undefined reference to `main'
collect2: error: ld returned 1 exit status
Makefile:2: ошибка выполнения рецепта для цели «all»
make: *** [all] Ошибка 1

maxissmax
() автор топика
Ответ на: комментарий от maxissmax

undefined reference to `main'

гцц тебе либы свои навязывает по умолчанию, используй аргумент -nostdlib или, если либы-таки нужны, то определи main в коде. Линкер использует символ _start в качестве точки входа, но ты можешь указать свой любой через -Wl,-e.

Я тебе, конечно, сейчас насоветую ) Я с стм32 ни разу не связывался.

Вывести листинг на асме из Си -S.

anonymous
()

Вы некорректно настраиваете регистр GPIOC_CRH.

Ваш макрос пишет в регистр результат ИЛИ того, что там было и нового значения:

	MOV32	R0, \GPIO_BASE + \GPIO
	MOV32   R1, \GPIO_PIN
	LDR   	R2, [R0]
	ORR	R1, R1, R2
	STR	R1, [R0]

Состояние регистра после сброса, 4-битная группа, для каждой ноги: 0100, т.е. плавающий вход. Вы пишете туда по факту 0110 - выход с открытым коллектором, а вам нужен, вероятно, push-pull выход (но это зависит от схемы включения светодиода). Попробуйте LDR и ORR убрать, оставить только STR R1, [R0].

anonymous
()
Ответ на: комментарий от anonymous

Добавил аргумент -nostdlib:

arm-none-eabi-gcc -nostdlib -x assembler -O1 main.asm -o 'bin/main.o'

Откомпилировалось нормально, залилось без ошибок, но контроллер молчит. Прозвон ножек показал что на пины не подается питание.

Скрипт линковщика урезал:

MEMORY
{
  FLASH (RX) : ORIGIN = 0x08000000, LENGTH = 64K
}
SECTIONS { 
       .text : { *(.text); } > FLASH
}

По моему для начала и этого хватит

maxissmax
() автор топика
Ответ на: комментарий от anonymous

Огромнейшее спасибо! Дейстительно убрал эти две злощастные строчки и все заработало как надо.

Сложно догадатся что ошибка в том месте где все как бы в приоре должно работать

maxissmax
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.