Skocz do zawartości

Kurs STM32 - #8 - DMA, czyli bezpośredni dostęp do pamięci


Pomocna odpowiedź

Napisano
html_mig_img
W części 6 kursu STM32 poznaliśmy możliwości przetwornika ADC. Uruchamiane przykłady były jednak niedoskonałe.Teraz poznamy nową, efektywną metodę. Zamiast aktywnie czekać na odczyt, wykorzystamy moduł DMA, który będzie robił to w tle.

UWAGA, to tylko wstęp! Dalsza część artykułu dostępna jest na blogu.

Przeczytaj całość »

Poniżej znajdują się komentarze powiązane z tym wpisem.

Witam

Sprawdziłem działanie kodu szybkości kopiowania CPU vs DMA u siebie i nie mogę zrozumieć pewnej rzeczy. Gdy program jest skompilowany w DEBUG czasy pokrywają się z tymi z fotki z artykułu. Natomiast gdy skompiluję jako RELEASE, wówczas sytuacja jest całkiem inna.

Czy jest mi ktoś w stanie to wyjaśnić ?

Na załączonej fotce - 2 pierwsze wpisy - kompilacja DEBUG, kolejne 2 - kompilacja RELEASE

Pozdrawiam

Problem z optymalizatorem jest taki, że może uznać pewne fragmenty programu za niepotrzebne... Prawdopodobnie uznał, że kopiujesz dane, ale ich nie używasz, więc można ten fragment programu usunąć... W przypadku typowych programów pracujących na komputerze stacjonarnym takie optymalizacje mogą oszczędzać sporo czasu procesora. Jednak w przypadku mikrokontrolerów są często źródłem problemów. Właśnie dlatego zmienne modyfikowane w przerwaniach powinny być oznaczane jako volatile. Inaczej optymalizator może uznać, że skoro wartości nie są zmieniane, to można zupełnie usunąć dostęp do nich.

  • 10 miesiące później...
  • 1 miesiąc później...

Zad 8.1

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "stm32f10x.h"

#define        BUFFER_SIZE            32

uint8_t        src_buffer[BUFFER_SIZE];
uint8_t        dst_buffer[BUFFER_SIZE];

/*---------------------------------------------------------------*/

void copy_cpu()
{
   int i;
   for (i = 0; i < BUFFER_SIZE;i++)
       dst_buffer[i] = src_buffer[i];
}

void copy_dma()
{
   DMA_Cmd(DMA1_Channel1, ENABLE);
   while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
}

/*---------------------------------------------------------------*/

void send_char(char c)
{
   while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
   USART_SendData(USART2, c);
}

int __io_putchar(int c)
{
if (c=='\n')
send_char('\r');
send_char(c);
return c;
}

int main(void)
{
   USART_InitTypeDef uart;
   GPIO_InitTypeDef gpio;

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

GPIO_StructInit(&gpio);
gpio.GPIO_Pin = GPIO_Pin_2;
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &gpio);

gpio.GPIO_Pin = GPIO_Pin_3;
gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &gpio);


   USART_StructInit(&uart);
   uart.USART_BaudRate = 115200;
   USART_Init(USART2, &uart);

   USART_Cmd(USART2, ENABLE);

   int i;
   DMA_InitTypeDef dma;

   DMA_StructInit(&dma);
   dma.DMA_PeripheralBaseAddr = (uint32_t)src_buffer;
   dma.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
   dma.DMA_MemoryBaseAddr = (uint32_t)dst_buffer;
   dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
   dma.DMA_BufferSize = BUFFER_SIZE;
   dma.DMA_M2M = DMA_M2M_Enable;
   DMA_Init(DMA1_Channel1, &dma);

   // wypelniamy bufor przykladowymi danymi
   for (i = 0; i < BUFFER_SIZE; i++)
       src_buffer[i] = 100 + i;

   //copy_cpu();
   copy_dma();


        printf("Hello World!\n");

        if(strncmp ((const char*)src_buffer, (const char*)dst_buffer, BUFFER_SIZE) == 0)
        {
            printf("ALL OK\n");
        }
        else
        {
            printf("try again\n");
        }

   while(1)
   {

   }
}
  • Pomogłeś! 1
  • 6 miesiące później...

TTakitani, raczej nie (? - może ktoś bardziej doświadczony powie, że tak) 🙂 Osobiście nie miałem nigdy takich problemów, ale robiłem zawsze to po kolei "na logikę". Czyli zanim konfigurowałem GPIO upewniałem się, że peryferia są uruchomione i odpowiednio taktowane itd.

  • 5 miesiące później...

/*http://infocenter.arm.com/help/topic/com.arm.doc.ddi0337e/DDI0337E_cortex_m3_r1p1_trm.pdf*/ //pp.233

typedef uint32_t uint; //this is "the unsigned int" or "the unsigned" variable type ;D

uint t1 = *( uint* )0xE0001004; //DWT_CYCCNT

uint t2 = *( uint* )0xE0001004;

uint elapsedClkTics = t2 - t1; //divide by HSI freq. to obtain elapsed seconds

  • 2 tygodnie później...

Mam kłopot z obsługą DMA.

Mianowicie potrzebuję zapisać (szybkie) odczyty z jednego wejścia analogowego do tablicy 256-elementowej. Następnie przetwarzanie danych i kolejne odczyty w nieskończonej pętli.

W kursie jest kopiowanie dwóch tablic, albo zapis odczytu z każdego wejścia analogowego do 1 elementu tablicy. Ale czy można z wielu odczytów zrobić tablicę nie opóźniając kolejnych odczytów? Po serii 256 odczytów może być już "zwykłe" kopiowanie itd.

Konkretnie chodzi mi implementację FFT i zależy mi na szybkich odczytach.

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...