[STM32] Pętla opóźniająca jako wstawka asemblerowa - błędy podczas kompilacji

0

Witam
Próbuje wykonać wstawkę asemblerową dla pętli opóźniającej.
Program podstawowy, czyli zapalanie diod, niestety kompilator (środowisko Keil uVision5), zgłasza dwa błędy.

#include "stm32f10x.h"
    
void delay_us_ASM(uint32_t us);
     
    int main(void){
   
		RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;     
    GPIOA->CRL |= GPIO_CRL_MODE7;      
    GPIOA->CRL &= ~GPIO_CRL_CNF7;
           
    GPIOA->CRL |= GPIO_CRL_MODE7;               
    GPIOA->CRL &= ~GPIO_CRL_CNF7;
   
		RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;      
   
		GPIOB->CRL |= GPIO_CRH_MODE9;              
    GPIOB->CRL &= ~GPIO_CRH_CNF9;
    
			while(1){
            GPIOA->ODR |= GPIO_ODR_ODR7;
            GPIOB->ODR |= GPIO_ODR_ODR9;
     
            delay_us_ASM (100000);
           
						GPIOA->ODR &= ~GPIO_ODR_ODR7;
						GPIOB->ODR &= ~GPIO_ODR_ODR9;
                                    }
                                                    }      
    void delay_us_ASM(uint32_t us)
        {
           asm volatile  (
                          "MOV R0,%[loops]\n\t"
                          "1:             \n\t"
                          "NOP            \n\t"
                          "NOP            \n\t"
                          "SUB R0, #1     \n\t"
                          "CMP R0, #0     \n\t"
                          "BNE 1b         \n\t" : : [loops] "r" (8*us) : "memory"
                                 );
        }

Oraz błędy:
main.c(31): error: #20: identifier "asm" is undefined
main.c(31): error: #65: expected a ";"

W poradnikach, które znalazłem wstawki wyglądają podobnie, widać jest jakiś błąd, którego ja nie widzę. Liczę, że pomożecie mi go znaleźć.

0

Spróbuj zapisać wstawkę używając

__asm
0

Zastosowałem takie coś:

_asm_volatile

Pierwszy błąd mi zniknął ale pojawił się problem ze zgodnością:
warning: implicit declaration of function "_asm_volatile" is invalid in C99
Pozostaje jeszcze drugi błąd

0

Chodziło raczej o __asm odstęp volatile.
To zależy od kompilatora jakiego używasz. Sprawdź poza __asm też __asm__

0

Samo _asm_ nie wyświetla błędów, ale wszystkie kombinację poza _asm_volatile już tak.

0

jaki masz kompilator? i jaka wersje jego

0

Keil uVision v5 (kompilator C: Armcc V5.06, kompilator Asemblera: Armasm V5.06)

0

Dokumentacja bardzo przydatna, ale coś mi się zdaje, że ta pętla jest jakaś lipna, więc jakby ktoś miał / znał pętle opóźniającą zrobioną w asemblerze i działającą to będę wdzięczny za pomoc.

    #include "stm32f10x.h"
    
		void delay_us_ASM(uint32_t us);
     
    int main(void){
   
		RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;     
    GPIOA->CRL |= GPIO_CRL_MODE7;      
    GPIOA->CRL &= ~GPIO_CRL_CNF7;
           
    GPIOA->CRL |= GPIO_CRL_MODE7;               
    GPIOA->CRL &= ~GPIO_CRL_CNF7;
   
		RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;      
   
		GPIOB->CRL |= GPIO_CRH_MODE9;              
    GPIOB->CRL &= ~GPIO_CRH_CNF9;
    
			while(1){
            GPIOA->ODR |= GPIO_ODR_ODR7;
            GPIOB->ODR |= GPIO_ODR_ODR9;
     
            delay_us_ASM (100000);
           
						GPIOA->ODR &= ~GPIO_ODR_ODR7;
						GPIOB->ODR &= ~GPIO_ODR_ODR9;
                                    }
                                                    }      
    void delay_us_ASM(uint32_t us)
        {
           _asm 
					(
                          "MOV R0,%[loops]\n\t"
                          "1:             \n\t"
                          "NOP            \n\t"
                          "NOP            \n\t"
                          "SUB R0, #1     \n\t"
                          "CMP R0, #0     \n\t"
			   "BNE 1b         \n\t" : [loops] "r" : (8*us) "memory"
				);
        }

Próbowałem nawiasy kwadratowe i komendy bez cudzysłowów, niestety wtedy jest jeszcze więcej błędów. Jak mam nawiasy okrągłe to jest cały czas jeden i ten sam:
main.c(39): error: #18: expected a ")" "BNE 1b \n\t" : [loops] "r" : (8*us) "memory"

0

Jak to ma działać, jak to musisz mieć częstotliwość taktowania procesora na sekundę i odpowiednio tyle wykonać operacji ile czasu chce się zamulić procesor.

I ogólnie to wywal te wstawki i normalnie po ludzku to zrób w oddzielnym pliku, i dołącz poprzez extern i załączenie obiektowego pliku już stworzonego do kompilacji głównego programu.

Strasznie nie czytelne są takie wstawki i ciężko cokolwiek się w takiej wstawce zmienia.

0

Mam zrobione różne warianty pętli opóźniającej od takiej przy zastosowaniu timer-a do takiej zwykłej z pętlą for. Tylko chodzi o to, że w założeniach projektu, w którym to wykorzystywałem było sterowanie wyświetlaczami np. 2x16 i sprawdzanie jak zmiana częstotliwości taktowania wpłynie na ilość pobieranego prądu. Dlatego każdy dodatkowy blok czy to timer czy coś innego, to dodatkowe zużycie prądu. Dlatego chciałem funkcje delay z pętlą for zamienić na funkcję delay zrealizowaną, jako wstawka asemblerowa (bo może uda mi się znaleźć ile każdy rozkaz zajmuje cykli w przypadku STM32). Tak masz rację, że fajnie by było to wywalić do oddzielnego pliku i potem tylko wywoływać, tylko najpierw przydałoby się żeby to działało. :D

0

Przerobiłem program, do opracowania pętli Delay wykorzystałem SysTick, wszystko działa. Ale niestety nie nauczyłem się robić wstawek asemblerowych w C. :)
Main:

#include "stm32f10x.h"
#include "hd44780.h"

int main(void){
	
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
	if (SysTick_Config(SystemCoreClock / 1000))
	{ 
    /* Przerwanie dzialania, w przypadlu bledu wpada petle */ 
    while (1);
	}
	
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;      /* uruchomienie portu A */
	GPIOA->CRL |= GPIO_CRL_MODE7;                 /* wyjscie push-pull */
GPIOA->CRL &= ~GPIO_CRL_CNF7;
	
GPIOA->CRL |= GPIO_CRL_MODE7;                 /* wyjscie push-pull */
GPIOA->CRL &= ~GPIO_CRL_CNF7;
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;      
GPIOB->CRL |= GPIO_CRH_MODE9;              
GPIOB->CRL &= ~GPIO_CRH_CNF9;
while(1){
        GPIOA->ODR |= GPIO_ODR_ODR7;
				GPIOB->ODR |= GPIO_ODR_ODR9;
				Delay(1000);
				GPIOA->ODR &= ~GPIO_ODR_ODR7;
				GPIOB->ODR &= ~GPIO_ODR_ODR9;
				Delay(1000);

Delay i obsługa przerwania SysTick:

void Delay(__IO uint32_t nTime)
{ 
  TimingDelay = nTime;
 
  while(TimingDelay != 0);
}
 
void TimingDelay_Decrement(void)
{
  if (TimingDelay != 0x00)
  { 
    TimingDelay--;
  }
}

void SysTick_Handler(void)
{
	TimingDelay_Decrement();
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1