Jump to content

    

Чтение состояния порта в массив, inline assembler gcc stm32f4xx

Здравствуйте, уважаемые товарищи!

В си-коде, для проверки состояния порта используется вставка на ассемблере, приведенная ниже.

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

Возможно, я что-то недопонимаю и делаю не так, как надо.

Хотелось бы услышать идеи, с помощью которых можно было бы починить код...

 

void f(unsigned int* peg)
{
   __ASM volatile
   (

       ".equ PERIPH_BASE, 0x40000000 \n \t"
       ".equ AHB1PERIPH_BASE, 0x00020000 \n \t"
       ".equ GPIOD_BASE, 0x0C00 \n \t"
       ".equ GPIOB_BASE, 0x0400 \n \t"
       ".equ GPIO_IDR, 0x10 \n \t"
       ".equ GPIO_BSRRL, 0x18 \n \t"
       ".equ GPIO_BSRRH, 0x1A \n \t"

       ".equ GPIO_BSRR_BS_5, 0x20 \n \t"


       "LDR r0, =(GPIO_BSRR_BS_5) \n \t"
       "LDR r1, =(PERIPH_BASE + AHB1PERIPH_BASE + GPIOB_BASE + GPIO_BSRRH) \n\t"
       "LDR r2, =(PERIPH_BASE + AHB1PERIPH_BASE + GPIOB_BASE + GPIO_BSRRL) \n\t"
       "LDR r3, =(PERIPH_BASE + AHB1PERIPH_BASE + GPIOD_BASE + GPIO_IDR) \n\t"

       "LDR r4, [%[data_ptr], 0x00] \n \t"

       //0
       "STRH r0,  [r2, 0x00]  \n \t" // set clock
       "LDR  r5,  [r3, 0x00] \n \t"   // считываем GPIOD->IDR
       "STRH r0,  [r1, 0x00] \n \t"   // reset clock
       "STR  r5,  [r4, 0] \n \t"   // записываем то, что было в GPIOD->IDR, в память со смещением

       //1
       "STRH r0,  [r2, 0x00] \n \t"
       "LDR  r5,  [r3, 0x00] \n \t" 
       "STRH r0,  [r1, 0x00] \n \t" 
       "STR  r5,  [r4, 4] \n \t" 

       //2
       "STRH r0,  [r2, 0x00] \n \t" 
       "LDR  r5,  [r3, 0x00] \n \t" 
       "STRH r0,  [r1, 0x00] \n \t"
       "STR  r5,  [r4, 8] \n \t"

       /* Множество раз повторяется. */

       //681
       "STRH r0,  [r2, 0x00] \n \t"
       "LDR  r5,  [r3, 0x00] \n \t"
       "STRH r0,  [r1, 0x00] \n \t"
       "STR  r5,  [r4, #2724] \n \t"

       :
       : [data_ptr] "r" (peg)
       : 
   );
}

Share this post


Link to post
Share on other sites

Не уверен насчет "сообразительности" инлайн ассемблера gcc:

"LDR r0, =(GPIO_BSRR_BS_5) \n \t"

здесь peg может быть затерт.

 

И почему не оформить код в виде нормального ассемблерного модуля?

Share this post


Link to post
Share on other sites
Здравствуйте, уважаемые товарищи!

В си-коде, для проверки состояния порта используется вставка на ассемблере, приведенная ниже.

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

Возможно, я что-то недопонимаю и делаю не так, как надо.

Хотелось бы услышать идеи, с помощью которых можно было бы починить код...

 

void f(unsigned int* peg)
{
   __ASM volatile
   (

       ".equ PERIPH_BASE, 0x40000000 \n \t"
       ".equ AHB1PERIPH_BASE, 0x00020000 \n \t"
       ".equ GPIOD_BASE, 0x0C00 \n \t"
       ".equ GPIOB_BASE, 0x0400 \n \t"
       ".equ GPIO_IDR, 0x10 \n \t"
       ".equ GPIO_BSRRL, 0x18 \n \t"
       ".equ GPIO_BSRRH, 0x1A \n \t"

       ".equ GPIO_BSRR_BS_5, 0x20 \n \t"


       "LDR r0, =(GPIO_BSRR_BS_5) \n \t"
       "LDR r1, =(PERIPH_BASE + AHB1PERIPH_BASE + GPIOB_BASE + GPIO_BSRRH) \n\t"
       "LDR r2, =(PERIPH_BASE + AHB1PERIPH_BASE + GPIOB_BASE + GPIO_BSRRL) \n\t"
       "LDR r3, =(PERIPH_BASE + AHB1PERIPH_BASE + GPIOD_BASE + GPIO_IDR) \n\t"

       "LDR r4, [%[data_ptr], 0x00] \n \t"

       //0
       "STRH r0,  [r2, 0x00]  \n \t" // set clock
       "LDR  r5,  [r3, 0x00] \n \t"   // считываем GPIOD->IDR
       "STRH r0,  [r1, 0x00] \n \t"   // reset clock
       "STR  r5,  [r4, 0] \n \t"   // записываем то, что было в GPIOD->IDR, в память со смещением

       //1
       "STRH r0,  [r2, 0x00] \n \t"
       "LDR  r5,  [r3, 0x00] \n \t" 
       "STRH r0,  [r1, 0x00] \n \t" 
       "STR  r5,  [r4, 4] \n \t" 

       //2
       "STRH r0,  [r2, 0x00] \n \t" 
       "LDR  r5,  [r3, 0x00] \n \t" 
       "STRH r0,  [r1, 0x00] \n \t"
       "STR  r5,  [r4, 8] \n \t"

       /* Множество раз повторяется. */

       //681
       "STRH r0,  [r2, 0x00] \n \t"
       "LDR  r5,  [r3, 0x00] \n \t"
       "STRH r0,  [r1, 0x00] \n \t"
       "STR  r5,  [r4, #2724] \n \t"

       :
       : [data_ptr] "r" (peg)
       : 
   );
}

 

Ну а под JTAGом пошагово почему не посмотреть что в регистры грузится? И не нужны будут ничьи идеи.

Share this post


Link to post
Share on other sites
Хотелось бы услышать идеи, с помощью которых можно было бы починить код...

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

Share this post


Link to post
Share on other sites
Не уверен насчет "сообразительности" инлайн ассемблера gcc:

"LDR r0, =(GPIO_BSRR_BS_5) \n \t"

здесь peg может быть затерт.

 

И почему не оформить код в виде нормального ассемблерного модуля?

 

R0 должен содержать 0x20

Share this post


Link to post
Share on other sites
Возможно, я что-то недопонимаю и делаю не так, как надо.

Где сохранение разрушаемых R4,R5?

 

Хотелось бы услышать идеи, с помощью которых можно было бы починить код...

Вынести функцию в асм-файл. И читать документацию компилятора насчёт соглашений вызова.

Share this post


Link to post
Share on other sites
        :
        : [data_ptr] "r" (peg)
        :

1) Тут должны быть перечислены все используемые во вставке регистры и память ("=m", если правильно помню)

2) лучше дать возможность компилятору самому выделить наиболее подходящие регистры, т.е. задать там [имя] "+r" и во вставке использовать %[имя] вместо имени конкретного регистра - это развяжет ему руки.

3) аналогично peg можно заставить компилятор передавать во вставку адреса GPIOB->BSRRH, GPIOB->BSRRL, GPIOD->IDR чтобы брать их из заголовочного файла, а не прибивать гвоздями внутри вставки.

4) можно сэкономить регистр, занеся в регистр адрес GPIOB, а для обращений к BSRRH, BSRRL использовать разные смещения в командах.

Share this post


Link to post
Share on other sites
И почему не оформить код в виде нормального ассемблерного модуля?

 

Наверно, можно оформить и в виде отдельного модуля...

Но я не понимаю пока, какие преимущества я из этого смогу извлечь?

 

Share this post


Link to post
Share on other sites
Наверно, можно оформить и в виде отдельного модуля...

Но я не понимаю пока, какие преимущества я из этого смогу извлечь?

А я думаю многие тут не понимают: какие преимущества Вы извлекаете нагородив этот огород с инлайн-ассемблером вместо простой си-функции?

При этом даже не понимаете как взаимодействует Ваш асм-код с телом си-функции в которую его впихнули.

Share this post


Link to post
Share on other sites

Поэтому и обратился на форум, чтоб направили в правильном направлении, разъяснили основные моменты...

 

В итоге, сделал вот так, в какой-то степени работает...

 

void ClockAsm(unsigned int *peg)
{
   __ASM volatile
   (

       //"LDR r3, 0x4002041A \n \t"
       //"LDR r1, 0x40020418 \n \t"

       //"LDR r2, 0x40020C10 \n \t"

       //"MOV r3, 0x00000020 \n \t"
       ".equ PERIPH_BASE, 0x40000000 \n \t"
       ".equ AHB1PERIPH_BASE, 0x00020000 \n \t"
       ".equ GPIOD_BASE, 0x0C00 \n \t"
       ".equ GPIOB_BASE, 0x0400 \n \t"
       ".equ GPIO_IDR, 0x10 \n \t"
       ".equ GPIO_BSRRL, 0x18 \n \t"
       ".equ GPIO_BSRRH, 0x1A \n \t"

       ".equ GPIO_BSRR_BS_5, 0x20 \n \t"

       "LDR r3, [%[data_ptr], 0x00] \n \t"

       "LDR v1, =(GPIO_BSRR_BS_5) \n \t"
       "LDR v2, =(PERIPH_BASE + AHB1PERIPH_BASE + GPIOB_BASE + GPIO_BSRRH) \n \t"
       "LDR v3, =(PERIPH_BASE + AHB1PERIPH_BASE + GPIOB_BASE + GPIO_BSRRL) \n\t"
       "LDR v6, =(PERIPH_BASE + AHB1PERIPH_BASE + GPIOD_BASE + GPIO_IDR) \n\t"

       //0
       "STRH v1,  [v3, 0x00]  \n \t"
       "LDR  v5,  [v6, 0x00] \n \t" 
       "STRH v1,  [v2, 0x00] \n \t"
       "STR  v5,  [r3, 0] \n \t"

       //1
       "STRH v1,  [v3, 0x00]  \n \t"
       "LDR  v5,  [v6, 0x00] \n \t"
       "STRH v1,  [v2, 0x00] \n \t"
       "STR  v5,  [r3, 4] \n \t"

       ...

       //338
       "STRH v1,  [v3, 0x00]  \n \t"
       "LDR  v5,  [v6, 0x00] \n \t"
       "STRH v1,  [v2, 0x00] \n \t"
       "STR  v5,  [r3, #1352] \n \t"
       :
       : [data_ptr] "r" (&peg)
       : "r3", "v1", "v2", "v3", "v5", "v6", "memory"
);
}

 

Теперь, следующая проблема: мне необходима выборка длиной 600 семплов, а, при увеличении шагов до 339, например, компилятор ругается: "Error: offset out of range"...

Подскажите, возможно есть еще какая-то очевидная ошибка?

Share this post


Link to post
Share on other sites
Поэтому и обратился на форум, чтоб направили в правильном направлении, разъяснили основные моменты...

Правильное направление: пишите на си.

Асм уместен только там, где реально нужен (очень редко!). И то - очень не советую использовать инлайн-асм. Лучше отдельный асм-файл.

Share this post


Link to post
Share on other sites

Пусть тренируется человек, вон уже дошёл до факта, что смещение в виде константы [Rx, #(+-)N] имеет весьма ограниченный диапазон.

 

ARM® and Thumb®-2 Instruction Set:

QRC0001_UAL.pdf

 

Если не надоест много занятного и полезного узнает.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this