Ярлыки

_GetPixelIndex (1) _SetPixelIndex (1) 3-phase (1) 800x480 (1) АЦП (1) генератор (1) синхронный усилитель (2) структура (1) учебный курс (1) шаговый двигатель (1) ШИМ (2) accert (1) AD7608 (1) AD8429 (1) ADC (5) amplifer (1) arccos (1) arcsin (1) arctang (2) arctg (3) ARM (2) arm_sqrt_q15 (2) assembler (6) ASSERT (1) atan (2) bit (1) Bitband (1) boot (3) bootlloader (1) BUTTON (1) C (5) C# (1) CAN (2) CC2530 (5) CMSIS (4) command (1) Cordic (1) Core746I (1) CubeMX (4) DBGMCU (2) debug (2) debug.ini (1) delegate (1) Digital Potentiometers (1) DigitalPOT (1) Discovery (1) DMA (9) DMA2D (1) DSP (1) DSP library (1) DWT (1) EFM32 (5) EmWin (9) EXTI (1) FATFS (1) FMC (2) FreeRTOS (2) gl868-dual cmux (1) GPIO (4) GUI (2) GUIBuilder (1) GUIDRV_CompactColor_16 (1) HAL (3) HappyGecko (1) Hard Fault (2) heap (1) I2C (1) ID (1) ILI9320 (1) ILI9325 (1) Initialisation (1) InitLTDC (1) Instrumentithion (1) Interrupt (4) ITR (1) JTAG (1) Keil (5) LCDConf (2) lock-in (1) LTCD (1) LTDC (3) main (1) memory (1) MINI_STM32 Revision 01 (1) nBoot0 (1) NVIC (1) OnePulse (2) OSAL (4) pack (1) phase (1) printf (3) Pulse (1) PWM (12) RCC (2) RCR (1) Register (1) RESET (2) RS232 (3) RSS (1) RTC (3) RTOS-RTX (1) RTT (1) RTX-RTOS (1) SDCard (1) SDRAM (6) Segger (2) SPI (3) sqrt (3) SSD1298 (1) SSD1963 (1) Standart Peripherial Library (3) STANDBAY (1) startup (1) STemWin (8) stepper motor (1) STlink (2) STM32 (17) STM32429ZI (1) STM32Cube (1) STM32DBG.IN (1) STM32F (28) STM32F0 (4) STM32F1 (13) STM32F4 (10) STM32F4 Discovery (1) STM32F407ZG (1) STM32F429 (2) STM32F746 (1) STOP (1) string (1) struct (1) SWD (1) SWD JTAG (1) Synhronization (1) system_stm32f4xx.c (1) SystemInit (1) SysTick (1) task (4) telit (1) TIM (27) typedef (1) UART (1) USART (9) viewer (2) WM_PAINT (1) Z-stack (5) ZigBee (5)

пятница, 10 февраля 2012 г.

STM32F4 Assembler Subroutine

В функциях LedOn и LedOff в начале и в конце есть команды:
PUSH {LR} ; Сохранить регистр LR в стеке.
; Полезный код
POP {PC} ; Поместить адрес возврата в PC. Выход из подпрограммы.

Вообще, необходимо придерживаться следующего соглашения о вызовах для удобства и совместимости с функциями, написанными на Си.
Аргументы передаются в регистрах R0-R3, первый в R0 и так далее. Если аргументов больше, то они передаются уже через стек.
Содержимое остальных регистров общего назначения, которые в процедуре используются, надо сохранить на стеке же. В том числе и LR, если есть вложенные процедуры.
Вообще, необходимо придерживаться следующего соглашения о вызовах для удобства и совместимости с функциями, написанными на Си.
Аргументы передаются в регистрах R0-R3, первый в R0 и так далее. Если аргументов больше, то они передаются уже через стек.
Содержимое остальных регистров общего назначения, которые в процедуре используются, надо сохранить на стеке же. В том числе и LR, если есть вложенные процедуры.
Сравните:

; Подпрограмма без вложенных вызовов подпрограмм
Func0   PROC
; бла-бла-бла
BX LR
ENDP

; Подпрограмма с возможностью вложенного вызова подпрограмм
Func1   PROC
PUSH {LR}
; бла-бла бла
BL Func0
; бла-бла-бла
POP {PC}
ENDP

Адрес вершины стека в кортексах записан первым числом в таблице векторов! Регистр SP инициализируется при сбросе именно этим числом.

_Vectors       DCD     __initial_sp               ; Вершина стека!
                DCD     Reset_Handler              ; Таблица векторов, первым идёт вектор сброса
                DCD     NMI_Handler
...
Локальные метки можно использовать с помощью директивы ROUT, но наименование жуть какое неудобное, мне не нравится.

Пример программы

; Test STM32F4-Assembler project
; Ня
    AREA    |.text|, CODE, READONLY
RCC_AHB1ENR           EQU 0x40023830
RCC_AHB1ENR_GPIODEN   EQU 0x00000008 ; 3 бит
GPIOD_BASE           EQU 0x40020C00
GPIO_MODER_OFFSET     EQU 0x00000000
GPIO_MODER_MODER12_0 EQU 0x01000000
GPIO_MODER_MODER13_0 EQU 0x04000000
GPIO_MODER_MODER14_0 EQU 0x10000000
GPIO_MODER_MODER15_0 EQU 0x40000000
GPIO_PUPDR_OFFSET     EQU 0x0000000C
GPIO_PUPDR_PUPDR12_0 EQU 0x01000000
GPIO_PUPDR_PUPDR13_0 EQU 0x04000000
GPIO_PUPDR_PUPDR14_0 EQU 0x10000000
GPIO_PUPDR_PUPDR15_0 EQU 0x40000000
GPIO_BSRRL_OFFSET     EQU 0x00000018 ; Сброс
GPIO_BSRRH_OFFSET     EQU 0x0000001A ; Установка
DELAY_COUNTER         EQU 0x000F4240 ; 1000000UL
GPIO_BSSR_PIN12       EQU 0x00001000 ; 12 бит
GPIO_BSSR_PIN13       EQU 0x00002000 ; 13 бит
GPIO_BSSR_PIN14       EQU 0x00004000 ; 14 бит
GPIO_BSSR_PIN15       EQU 0x00008000 ; 15 бит
; Инициализация системы тактирования
;            EXPORT SystemInit
;SystemInit  PROC
;           
;            BX LR ; Возвращаемся обратно
;           
;            ENDP
ROUT
; Получить маску для зажигания светодиода по его номеру
; R0 - номер светодиода, от 0 до 3
; Результат: R0.
; Если номер не верный, в R0 будет 0.
GetPinMask  PROC
            ; Другой способ выбора:
            CMP  R0, #0
            BEQ  GetPinMask_led0
           
            CMP  R0, #1
            BEQ  GetPinMask_led1
           
            CMP  R0, #2
            BEQ  GetPinMask_led2
           
            CMP  R0, #3
            BEQ  GetPinMask_led3
           
            ; Ошибка
            B    GetPinMask_error
           
GetPinMask_led0 ; Светодиод 0
            MOV  R0, #GPIO_BSSR_PIN12 ; 12 бит
            B    GetPinMask_return
GetPinMask_led1 ; Светодиод 1
            MOV  R0, #GPIO_BSSR_PIN13 ; 13 бит
            B    GetPinMask_return
           
GetPinMask_led2 ; Светодиод 2
            MOV  R0, #GPIO_BSSR_PIN14 ; 14 бит
            B    GetPinMask_return
           
GetPinMask_led3 ; Светодиод 3
            MOV  R0, #GPIO_BSSR_PIN15 ; 15 бит
            B    GetPinMask_return
GetPinMask_error ; Ошибка
            MOV   R0, #0
           
GetPinMask_return
            BX    LR
            ENDP
; Погасить светодиод по его номеру
; R0 - номер светодиода, от 0 до 3
LedOff      PROC
            ; Сохраним в стеке адрес возврата
            PUSH {LR}
            ; Получить маску
            BL   GetPinMask
           
            ; Если 0, то выходим
            CMP  R0, #0
            BEQ  LedOff_return
           
            ; В R0 теперь маска
            ; Погасить выбронный светодиод
            LDR R1, =GPIOD_BASE
            STR R0, [R1, #GPIO_BSRRH_OFFSET]
           
LedOff_return
            ; Возврат из процедуры
            POP  {PC}
            ENDP
           
; Зажечь светодиод по его номеру
; R0 - номер светодиода, от 0 до 3
LedOn       PROC
            ; Сохраним в стеке адрес возврата
            PUSH {LR}
            ; Получить маску
            BL   GetPinMask
           
            ; Если 0, то выходим
            CMP  R0, #0
            BEQ  LedOn_return
           
            ; В R0 теперь маска
            ; Зажечь выбронный светодиод
            LDR R1, =GPIOD_BASE
            STR R0, [R1, #GPIO_BSRRL_OFFSET]
           
LedOn_return
            ; Возврат из процедуры
            POP  {PC}
            ENDP
; Программная задержка
; R0 - величина задержки
delay       PROC
            ; Вычитаем единицу
            SUBS R0, R0, #1
            ; Пока не обнулилась, крутим дальше
            BNE delay
           
            BX LR
            ENDP
            EXPORT __main
__main      PROC
           
            ; Разрешим тактирование порта D
           
            ; Загрузим в регистр R0 адрес регистра RCC_AHB1ENR
            LDR R0, =RCC_AHB1ENR
            ; Прочитаем в регистр R1 его содержимое
            LDR R1, [R0]
            ; Установим бит тактирования порта D
            ORR R1, R1, #RCC_AHB1ENR_GPIODEN
            ; Запишем обратно
            STR R1, [R0]
           
            ; Установим режим работы выводов (выход)
            LDR R0, =GPIOD_BASE
            ; Прочитаем в регистр R1 его содержимое
            LDR R1, [R0, #GPIO_MODER_OFFSET]
           
            ; Установим необходимые биты для выводов 12-15
            ORR R1, R1, #GPIO_MODER_MODER12_0
            ORR R1, R1, #GPIO_MODER_MODER13_0
            ORR R1, R1, #GPIO_MODER_MODER14_0
            ORR R1, R1, #GPIO_MODER_MODER15_0
           
            ; Запишем обратно
            STR R1, [R0, #GPIO_MODER_OFFSET]
           
            ; Подтяжка к питанию
            LDR R0, =GPIOD_BASE
            LDR R1, [R0, #GPIO_PUPDR_OFFSET]
           
            ; Установим необходимые биты для выводов 12-15
            ORR R1, R1, #GPIO_PUPDR_PUPDR12_0
            ORR R1, R1, #GPIO_PUPDR_PUPDR13_0
            ORR R1, R1, #GPIO_PUPDR_PUPDR14_0
            ORR R1, R1, #GPIO_PUPDR_PUPDR15_0
           
            ; Запишем обратно
            STR R1, [R0, #GPIO_PUPDR_OFFSET]
           
            ; В регистр R2 запишем величину задержки
            LDR R4, =DELAY_COUNTER
           
__mainloop
            ; Зажжём светодиод 0
            MOV R0, #0
            BL  LedOn
           
            ; Задержка
            MOV R0, R4
            BL  delay
           
            ; Погасим светодиод 0
            MOV R0, #0
            BL  LedOff
           
            ; Зажжём светодиод 1
            MOV R0, #1
            BL  LedOn
           
            ; Задержка
            MOV R0, R4
            BL  delay
           
            ; Погасим светодиод 1
            MOV R0, #1
            BL  LedOff
           
            ; Зажжём светодиод 2
            MOV R0, #2
            BL  LedOn
           
            ; Задержка
            MOV R0, R4
            BL  delay
           
            ; Погасим светодиод 2
            MOV R0, #2
            BL  LedOff
           
            ; Зажжём светодиод 3
            MOV R0, #3
            BL  LedOn
           
            ; Задержка
            MOV R0, R4
            BL  delay
           
            ; Погасим светодиод 3
            MOV R0, #3
            BL  LedOff
           
            ; На очередной круг
            B __mainloop
            ENDP
    END

Комментариев нет:

Отправить комментарий