STM32 DMA. Инициализация

Инициализация контроллера DMA (как и любого переферийного устройства) начинается с подачи на него тактовых импульсов. Делается это следующим образом:

if ((RCC->AHBENR & RCC_AHBENR_DMA1EN) != RCC_AHBENR_DMA1EN)
RCC->AHBENR |=RCC_AHBENR_DMA1EN;

НАСТРОЙКА АДРЕСОВ ИСТОЧНИКА И ПРИЕМНИКА

Необходимо указать адрес регистра переферии с которым будет работать канал DMA:

DMA1_Channel4->CPAR = (uint32_t)&USART1->DR; //адрес регистра переферии

Теперь определимся с тем, откуда брать данные. Пусть это будет массив unsigned char BuffTxd[64]:

DMA1_Channel4->CMAR = (uint32_t)&BuffTxd[0]; //адрес буфера в памяти

И, наконец, укажем сколько байт хотим передать:

DMA1_Channel4->CNDTR = 64; //количество данных для обмена

Вот так выполняется настройка адресов источника и приемника канала DMA. Ничего сложного.
А вот для настройки режима работы канала придется немного попотеть .

НАСТРОЙКА РЕЖИМОВ ВЫБРАННОГО КАНАЛА

Эту работу можно разделить на три части: настройка режима связи с переферийным у-вом; настройка режима связи с памятью; настройка канала в целом.

Настройка режима  связи с переферийным устройством подобна настройке режима с памятью.
Необходимо задать два параметра — размерность данных и необходимость инкремента указателя.
Размерность данных:   8бит, 16 бит или 32 бита (все просто  понятно).
А вот зачем (и когда) используется инкремент указателя?
В нашем примере данные будут перемещаться из буфера памяти в регистр данных USARTа.
Для этого необходимо взять первый байт из буфера и поместить в регистр данных, затем второй и так далее до конца буфера. Получается, что инкремент указателя на память выполнять надо а инкремент указателя на переферийное устройство – нет.
Настройки канала в целом включают в себя:
1) Задание режима цикличности (однократный или циклический обмен);
2) Направление чтения (из памяти или перефирии);
3) Задание уровня приоритета канала (4 уровня);
4) Включение при необходимости прерываний.
Эти настройки выполняются манипуляцией битов регистра управления канала CCR.
В этом регистре используется 14 битов, назначение которых приведено ниже:

14 MEM2MEM Режим обмена память-память (0 – отключен, 1 – включен)
13,12 PL Уровень приоритета канала  (00 – низкий, 01 – средний, 10 – высокий, 11 – очень высокий)
11,10 MSIZE Размер элемента данных в памяти (0 – 8 бит, 1 – 16 бит, 2 – 32 бита)
9,8 PSIZE Размер элемента данных в переферии (0 – 8 бит, 1 – 16 бит, 2 – 32 бита)
7 MINC Режим инкремента указателя в памяти (0 – отключен, 1 – включен)
6 PINC Режим инкремента указателя в переферии (0 – отключен, 1 – включен)
5 CIRC Режим цикличности (0 – отключен, 1 – включен)
4 DIR Направления обмена данными (0 – чтение из переферии, 1 – из памяти)
3 TEIE Разрешение прерывания при возникновении ошибки при обмене
2 HTIE Разрешение прерывания по  завершении половины обмена
1 TCIE Разрешение прерывания по  завершении обмена (1 – разрешен, 0 — запрещен)
0 EN Разрешение канала   (0 — выключен,  1 — включен)

В первой колонке этой таблицы указаны номера разрядов регистра CRC, во второй — их названия, в третей — назначение.

Занесение данных в управляющий регистр можно выполнять побитно, а можно записать сразу весь регистр. Для наглядности будет приведен пример побитного занесения данных.
Чтобы это было возможно, выполним предварительную очистку управляющего регистра:

DMA1_Channel4->CCR   =  0;                        //предочистка регистра конфигурации

Конструкция DMA1_Channel4->CCR означает, что происходит обращение к регистру CCR четвертого канала.
Дальше поработаем с параметрами этого регистра.

Задаем размер   элемента данных в памяти:

DMA1_Channel4->CCR  &= ~DMA_CCR4_MSIZE;           //размерность данных 8 бит
DMA1_Channel4->CCR  |=  DMA_CCR4_MSIZE_0;         //размерность данных 16 бит
DMA1_Channel4->CCR  |=  DMA_CCR4_MSIZE_1;         //размерность данных 32 бита

Выбираем из перечисленного выше нужное. В нашем случае нужен первый вариант (будем передавать через передатчик восьмиразрядное слово).

Задаем размер   элемента данных в переферии:

DMA1_Channel4->CCR  &= ~DMA_CCR4_PSIZE;           //размерность данных 8 бит
DMA1_Channel4->CCR  |=  DMA_CCR4_PSIZE_0;         //размерность данных 16 бит
DMA1_Channel4->CCR  |=  DMA_CCR4_PSIZE_1;         //размерность данных 32 бита

Выбираем из перечисленного выше нужное. В нашем случае нужен первый вариант (будем  передавать через передатчик восьмиразрядное слово).

Задать режим инкремента указателя в памяти:

DMA1_Channel4->CCR  |=  DMA_CCR4_PINC;        //инкремент указателя

Инкремент выполнять надо, ведь будем передавать не один байт, а весь буфер.

Задать режим инкремента указателя в переферии:

DMA1_Channel4->CCR  |=  DMA_CCR4_MINC;        //использовать инкремент указателя
DMA1_Channel4->CCR  &= ~DMA_CCR4_PINC;        //неиспользовать инкремент указателя

Выбираем второй вариант (что инкрементировать-то ?! Ведь регистр данных USARTa один).

Дошли до конфигурирования режима цикличности. Что это за зверь?

В обычном режиме DMA выполнил обмен (переместил данные) и все, остановился.
Чтобы инициировать следующий цикл обмена необходимо выполнить ряд действий :

  1. Выключить DMA-канал (перед выполнением всех манипуляций необходимо отключать канал);
  2. Перезагрузить регистр CNDTR (загрузить количество данных к пересылке);
  3. Включить DMA-канал;

А вот если задать режим циклического обмена, тогда многое упростится. Контроллер DMA по   окончании передачи автоматически начнет новый цикл и так до бесконечности. Короче, циклический обмен. Для этого необходимо выполнить следующее:

DMA1_Channel4->CCR  |=  DMA_CCR4_CIRC;     //включить циклический режим

Направления обмена данными. Если передаем из памяти в устройство (как в нашем примере):

DMA1_Channel4->CCR  |=  DMA_CCR4_DIR;      //направление: чтение из памяти

Разряд EN позволяет «пнуть канал  DMA». Он разрешает/запрещает  работу канала:

DMA1_Channel4->CCR  |=  DMA_CCR4_EN;      //разрешить работу канала
DMA1_Channel4->CCR  &= ~DMA_CCR4_EN;      //запретить работу канала

Помимо этого необходимо разрешить работу переферии через DMA.
Это указано в описании перефирийного устройства, которое нужно подключить к DMA.
В нашем примере подключаем USART, поэтому используем следующий код:

USART1->CR3 |= USART_CR3_DMAT;           //разрешить передачу USART1 через DMA

Разряды TEIE, HTIE и TCIE пока не трогаем. Они нужны для прерываний – об этом позже.
Также MEM2MEM пока проигнорируем. В них должны быть нули. Пока нули.
Как узнать об окончании процесса обмена через DMA? Нет ничего проще. Для этого существуют флаги в регистре ISR. По четыре флага на каждый канал:

  1. TEIF  — ошибка обмена в канале;
  2. HTIF – передана половина буфера;
  3. TСIF  —  передан весь буфер, т.е. обмен завершен;
  4. GIF   — общий флаг прерывания в канале, устанавливается если установлен TEIF  |  HTIF  |  TSIF.

Чтобы проверить соответствующий флаг канала №4 необходимо выполнить:

if (DMA1->ISR & DMA_ISR_TCIF4) {}    //проверить флаг окончания обмена
if (DMA1->ISR & DMA_ISR_HTIF4) {}    //проверить флаг передачи половины буфера
if (DMA1->ISR & DMA_ISR_TEIF4) {}    //проверить флаг ошибки обмена

Чтобы сбросить установленный флаг канала 4  существует регистр IFCR. Очистка выполняется так :

DMA1->IFCR |= DMA_ISR_TCIF4;        //очистить флаг окончания обмена
DMA1->IFCR |= DMA_ISR_HTIF4;        //очистить флаг передачи половины буфера
DMA1->IFCR |= DMA_ISR_TEIF4;        //очистить флаг ошибки обмена

Подводя итог всему выше сказанному приведу пример кода настройки DMA для работы с USART1_TX.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
unsigned char BuffTxd[32];        //буфер передатчика (с него родимого и будем брать данные)
//********************************************************************************
//Function: инициализация DMA1 для работы с USART1 (передача данных)            //
//********************************************************************************
void USART1_TX_DMA_Init(void)
{
 //Включить тактирование DMA1
 if ((RCC->AHBENR & RCC_AHBENR_DMA1EN) != RCC_AHBENR_DMA1EN)
 RCC->AHBENR |= RCC_AHBENR_DMA1EN;
 //Задать адрес источника и приемника и количество данных для обмена
 DMA1_Channel4->CPAR  =  (uint32_t)&USART1->DR;   //адрес регистра перефирии
 DMA1_Channel4->CMAR  =  (uint32_t)&BuffTxd[0];   //адрес буфера в памяти
 DMA1_Channel4->CNDTR =  32;                      //количество данных для обмена
 //----------------- Манипуляции с регистром конфигурации  ----------------
 //Следующие действия можно обьединить в одну команду (разбито для наглядности)
 DMA1_Channel4->CCR   =  0;                       //предочистка регистра конфигурации
 DMA1_Channel4->CCR  &= ~DMA_CCR4_CIRC;           //выключить циклический режим
 DMA1_Channel4->CCR  |=  DMA_CCR4_DIR;            //направление: чтение из памяти
 //Настроить работу с переферийным устройством
 DMA1_Channel4->CCR  &= ~DMA_CCR4_PSIZE;          //размерность данных 8 бит
 DMA1_Channel4->CCR  &= ~DMA_CCR4_PINC;           //неиспользовать инкремент указателя
 //Настроить работу с памятью
 DMA1_Channel4->CCR  &= ~DMA_CCR4_MSIZE;          //размерность данных 8 бит
 DMA1_Channel4->CCR  |=  DMA_CCR4_MINC;           //использовать инкремент указателя
 USART1->CR3         |=  USART_CR3_DMAT;          //разрешить передачу USART1 через DMA
}
//********************************************************************************
//Function: проверка флага окончания обмена в канале "память-DMA-USART1"        //
//Result  : 0 - обмен не закончен; 1 - обмен закончен;                          //
//********************************************************************************
unsigned char GetStateDMAChannel4(void)
{
  if(DMA1->ISR & DMA_ISR_TCIF4) return 1;   //обмен окончен
  return 0;                                 //обмен продолжается
}
//********************************************************************************
//Function: старт обмена в канале "память-DMA-USART1"                           //
//Argument: количество данных к обмену                                          //
//********************************************************************************
void StartDMAChannel4(unsigned int LengthBufer)
{
  DMA1_Channel4->CCR  &= ~DMA_CCR4_EN;      //запретить работу канала
  DMA1_Channel4->CNDTR =  LengthBufer;      //загрузить количество данных для обмена
  DMA1->IFCR          |=  DMA_IFCR_CTCIF4;  //сбросить флаг окончания обмена
  DMA1_Channel4->CCR  |=  DMA_CCR4_EN;      //разрешить работу канала
}

Попробуем использовать эти ф-ии чтобы два раза передать “HELLO,WORD”. Предполагаем, что инициализация USARTа уже выполнена.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
USART1_TX_DMA_Init();
BuffTxd[0] = ‘H’;
BuffTxd[1] = ‘E’;
BuffTxd[2] = ‘L’;
BuffTxd[3] = ‘L’;
BuffTxd[4] = ‘O’;
BuffTxd[5] =,;
BuffTxd[6] = ‘W’;
BuffTxd[7] = ‘O’;
BuffTxd[8] = ‘R’;
BuffTxd[9] = ‘D’;
StartDMAChannel4(10);                 //запустить первую передачу
while(GetStateDMAChannel4()==0) {};   //ждать окончания передачи
StartDMAChannel4(10);                 //запустить вторую передачу
while(GetStateDMAChannel4()==0) {};   //ждать окончания передачи

Вот как-то так. Здорово, правда?
Но сразу виден один недостаток – необходимо постоянно проверять флаг окончания передачи, а это весьма утомительно. Выход есть – использовать прерывания от канала DMA.

Комментарии (16) на “STM32 DMA. Инициализация”

  • info_ua:

    Пробовал пример на Keil, не работал…
    Постоянно регистр CCR4 изменял конфигурацию DMA канала (0×00003090) при выполнении
    «DMA1_Channel4->CCR = ~DMA_CCR4_EN;» на (0x00007AFE) — меняя при этом все ранее заложенные в него данные.
    После того как порылся в библиотеках StdPeriph_Driver
    Переписал функцию «StartDMAChannel4″

    void StartDMAChannel4(unsigned int LengthBufer)
    {
    DMA1_Channel4->CCR &= (uint16_t)(~DMA_CCR1_EN);
    DMA1_Channel4->CNDTR = LengthBufer;
    DMA1->IFCR = DMA1_FLAG_TC4;
    DMA1_Channel4->CCR |= DMA_CCR1_EN;
    }
    И все заработало.
    Спасибо за пример, очень помогло при освоении DMA + USART.

    • Кот:

      «DMA1_Channel4->CCR = ~DMA_CCR4_EN;» — оно и не могло работать. В 16-ти (?) битный регистр записывается число, полученное инвертированием того, что лежит в константе. А нам нужно сбросить бит, номер которого равен числу в константе, а это делается весьма просто, DMA1_Channel4->CCR &= ~DMA_CCR1_EN; Т.е. был просто пропущен значок имперсанда. Приводить к типу uint16_t это число тоже не требуется.

    • Михаил:

      Приветствую! Разобрался в данном примере. Попробовал на своей отладочной плате его применить.. не работает. И USART настроен правильно. Микроконтроллер как будто просто зависает и реагирует только на внешние прерывания. Перерыл кучу всего.. вроде все правильно и должно работать. Я не так давно с микроконтроллерами имею дело поэтому могу чего то не понимать. В чем может быть проблема?

  • Victor:

    Замечательная статья! Спасибо.

  • Саня:

    Доброе время суток! подскажите пожалуйста! использую код примера, но при работе с ПДП возникли трудности. блок ЮСАРТа работает, проверил в обычном режиме. при переключении на ПДП, и его использования работать отказуется. либо передача вообще не осуществляется, либо при передачи одного байта он зацикливается. при использовании прерываний ПДП МК начинает тупо висеть в канале 4, что используется на передачу.

    RCC->APB2ENR |= RCC_APB2ENR_USART1EN;////enable clock usart1

    //USARTDIV = fck / (16*baud) = 72000000/(16 * 9600) = 468.75
    // DIV_Mantissa = 0d468 = 0x1D4;
    // DIV_Fraction = 0.75 * 16 = 12;
    USART1->BRR =0X1d4c;

    USART1->CR2 &= ~USART_CR2_STOP;//STOP BIT 0

    USART1->CR1 = USART_CR1_RE | USART_CR1_TE | USART_CR1_UE;

    if ((RCC->AHBENR & RCC_AHBENR_DMA1EN) != RCC_AHBENR_DMA1EN)
    RCC->AHBENR |=RCC_AHBENR_DMA1EN;

    DMA1_Channel4->CPAR = (uint32_t)&USART1->DR;
    DMA1_Channel4->CMAR = (uint32_t)&TxBuff[0];
    DMA1_Channel4->CNDTR = 1;

    DMA1_Channel4->CCR = 0;
    //DMA1_Channel4->CCR=~DMA_CCR4_CIRC;
    DMA1_Channel4->CCR |= DMA_CCR4_DIR;
    //Íàñòðîèòü ðàáîòó ñ ïåðåôåðèéíûì óñòðîéñòâîì
    DMA1_Channel4->CCR = ~DMA_CCR4_PSIZE;
    DMA1_Channel4->CCR = ~DMA_CCR4_PINC;
    //Íàñòðîèòü ðàáîòó ñ ïàìÿòüþ
    DMA1_Channel4->CCR = ~DMA_CCR4_MSIZE;
    DMA1_Channel4->CCR |= DMA_CCR4_MINC;

    USART1->CR3 |= USART_CR3_DMAT;

    DMA1->IFCR |= DMA_IFCR_CTCIF4;
    DMA1_Channel4->CCR |= DMA_CCR4_EN;

    вот таким методом вышло передать байт, но после передачи остается какаето еще передача, ну ШИМ сигнал 20% скважности с частотой 960 Гц, он исчезает только лишь при отключении ПДП.

    заранее спасибо! :)))

    • kontroller:

      Как выглядит код обработчика прерывания от DMA?

      • Саня:

        void DMA1_Channel4_IRQHandler (void)
        {
        //Åñëè îáìåí çàâåðøåí
        if(DMA1->ISR & DMA_ISR_TCIF4)
        {
        DMA1->IFCR |= DMA_ISR_TCIF4;

        menu++;
        }

        //Åñëè ïåðåäàíà ïîëîâèíà áóôåðà
        if(DMA1->ISR & DMA_ISR_HTIF4)
        {
        DMA1->IFCR |= DMA_ISR_HTIF4;
        menu++;
        }

        //Åñëè ïðîèçîøëà îøèáêà ïðè îáìåíå
        if(DMA1->ISR & DMA_ISR_TEIF4)
        {
        DMA1->IFCR |= DMA_ISR_TEIF4;

        menu++;

        }
        }
        вот код! да, но перед прерыванием передача данных должна прекратится, а потом возникнуть прерывание!? циклический режим выключен.

        • Саня:

          С передачей вроди разобрался! вышло отправить несколько байт и увидить их на осцилле! :) ошибка была в настройке регистра CCR! просмотрел в отладчике побитно и нашел ошибки их установки. а вот с приемом? настраиваю приемник и отправляю несколько байт (10), приемник сначала принимал 1-й, через несколько раз 2-й, а потом вовсе перестал принимать! прием шел только при первом включении, в последующии разы в отладчике неудавалось принять байт. возможно это причина отладки?
          код настройки:

          DMA1_Channel5->CPAR = (uint32_t) &USART1->DR;
          DMA1_Channel5->CNDTR = 4;
          DMA1_Channel5->CCR=0;

          DMA1_Channel5->CCR&=~DMA_CCR5_CIRC;
          DMA1_Channel5->CCR|=DMA_CCR5_DIR;

          DMA1_Channel5->CCR&=~DMA_CCR5_PSIZE;
          DMA1_Channel5->CCR&=~DMA_CCR5_PINC;

          DMA1_Channel5->CCR&= ~DMA_CCR5_MSIZE;
          DMA1_Channel5->CCR|=DMA_CCR5_MINC;

          NVIC_EnableIRQ (DMA1_Channel5_IRQn);
          DMA1_Channel5->CCR |= DMA_CCR5_TEIE;
          DMA1_Channel5->CCR |= DMA_CCR5_TCIE;

          DMA1_Channel5->CMAR = (uint32_t) &RxBuff[0];

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

          • Саня:

            DMA1_Channel5->CCR|=DMA_CCR5_DIR; выключил! изменений не произошло! также пробывал изменять инкрименты памяти и периферии! также изменений не произошло!

          • kontroller:

            Пока помочь Вам не могу-немного занят. Позже освобожусь — роверю на отладочной плате.
            А Вы пробовали использовать «Генератор кода» ?

          • Саня:

            DMA1_Channel5->CNDTR=4;
            DMA1_Channel5->CCR=0;

            //DMA1_Channel5->CCR=DMA_CCR5_CIRC;

            DMA1_Channel5->CCR&=~DMA_CCR5_PSIZE;
            DMA1_Channel5->CCR&=~DMA_CCR5_PINC;
            //Íàñòðîèòü ðàáîòó ñ ïàìÿòüþ
            DMA1_Channel5->CCR&=~DMA_CCR5_MSIZE;
            DMA1_Channel5->CCR|=DMA_CCR5_MINC;

            // DMA1_Channel4->CCR |= DMA_CCR4_THIE;
            NVIC_EnableIRQ (DMA1_Channel5_IRQn);
            DMA1_Channel5->CCR |= DMA_CCR5_TEIE;
            DMA1_Channel5->CCR |= DMA_CCR5_TCIE;

            DMA1->IFCR|=DMA_IFCR_CTCIF5;
            DMA1_Channel5->CCR|=DMA_CCR5_EN;

            С горем пополам настроил! заработало! вот обработчик прерывания:

            void DMA1_Channel5_IRQHandler (void)
            {

            if(DMA1->ISR & DMA_ISR_TCIF5) //÷òî-òî äåëàåì
            {
            DMA1_Channel5->CCR&=~DMA_CCR5_EN;
            DMA1->IFCR |= DMA_ISR_TCIF5;

            if(RxBuff[0]==116)
            if(RxBuff[1]==101)
            if(RxBuff[2]==115)
            if(RxBuff[3]==116)
            testsvet=1;

            //DMA1->IFCR|=DMA_IFCR_CTCIF5;
            DMA1_Channel5->CNDTR=4;
            DMA1_Channel5->CCR|=DMA_CCR5_EN;
            }

            if(DMA1->ISR & DMA_ISR_TEIF5)
            {
            DMA1->IFCR|=DMA_ISR_TEIF5;

            }
            }

            но как-то стремно он работает! проверял через терминал! отправка идет нормально (по нажатию клавиши выкидываю 4 байта). при приеме все хорошо, все переданные и принятые байты успешно доставлены и обработаны, ошибок не возникает. Но когда количество принятых байт соответствует количеству байт написанных в настройках ПДП. если передавать больше,возникают странные аномалии вплоть до отключения модуля приема до перезагрузки МК! при отправке количества байт меньше, то обработчик будет ждать приема до полного заполнения.

          • Саня:

            «Генератор кода» не использовал!!! может так и быстрее, но я предпочитаю настраивать все руками! так и с аппаратной частью подробнее ознакомится можно. ну а алгоритмы работы оптимизирую для себя, дабы в дальнейшем использовать.
            пробовал работать с еепромкой (24lc128) через I2C. на частоте 100кГц нормально все запустилось, а вот с 400 не разобрался! правда работаю пока по самому минимуму, только запись и чтение, без всяких дополнительных проверок. но ошибок пока нету.

  • Pasha32:

    Доброго дня! Працюю з STM32 + DMA + USART і тут виникають дивні глюки. ПДП налаштований на передачу з буфера в памяті на УСАРТ2. При запуску ПДП на швидкості 9600 весь буфер передається. При зміні швидкості УСАРТ до 19200 в посилці губляться символи і при чому весь час оді і тіж. Прийом працює нормально при цих же швидкостях. Може знає хтось що може бути? Викладаю код.

    #include «stm32l1xx.h»
    #include

    uint8_t ReciverBuff[69];
    //const «HI_my_name_if_Pavlo.I_am_radioengeneer.I_work_in_ECOTEST_company.»;
    uint8_t SAMPLE[] = «USART DMA Example: Communication between two USART using DMA»;
    USART_InitTypeDef USART_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;

    int main(void)
    {
    GPIO_DeInit(GPIOA);

    //Дозволяємо тактування переферії
    RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOA|RCC_AHBPeriph_DMA1, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    //DMA_DeInit(DMA1_Channel6);
    DMA_DeInit(DMA1_Channel7);
    //Ініціалізуємо Reciver
    /*
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2); */
    //Ініціалізуємо Transmitter

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);

    //ініціалізуємо USART2
    USART_DeInit(USART2);
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx;
    USART_Init(USART2,&USART_InitStructure);

    DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t)&USART2->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr =(uint32_t)&SAMPLE[0];
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = 84;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel7,&DMA_InitStructure);

    USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
    USART_Cmd(USART2, ENABLE);
    USART_ClearFlag(USART2,USART_FLAG_TC);
    DMA_Cmd(DMA1_Channel7, ENABLE);

    while (1)
    {

    }
    }

  • Pasha32:

    Доброго дня! Працюю з STM32 + DMA + USART і тут виникають дивні глюки. ПДП налаштований на передачу з буфера в памяті на УСАРТ2. При запуску ПДП на швидкості 9600 весь буфер передається. При зміні швидкості УСАРТ до 19200 в посилці губляться символи і при чому весь час оді і тіж. Прийом працює нормально при цих же швидкостях. Може знає хтось що може бути? Викладаю код.

    #include «stm32l1xx.h»
    #include

    uint8_t ReciverBuff[69];
    //const
    uint8_t SAMPLE[] = «USART DMA Example: Communication between two USART using DMA»;
    USART_InitTypeDef USART_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;

    int main(void)
    {
    GPIO_DeInit(GPIOA);

    //Дозволяємо тактування переферії
    RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOA|RCC_AHBPeriph_DMA1, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    //DMA_DeInit(DMA1_Channel6);
    DMA_DeInit(DMA1_Channel7);
    //Ініціалізуємо Reciver
    /*
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2); */
    //Ініціалізуємо Transmitter

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);

    //ініціалізуємо USART2
    USART_DeInit(USART2);
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx;
    USART_Init(USART2,&USART_InitStructure);

    DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t)&USART2->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr =(uint32_t)&SAMPLE[0];
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = 84;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel7,&DMA_InitStructure);

    USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
    USART_Cmd(USART2, ENABLE);
    USART_ClearFlag(USART2,USART_FLAG_TC);
    DMA_Cmd(DMA1_Channel7, ENABLE);

    while (1)
    {

    }
    }

    • Паша, ты же понимаешь, что тебе смогут помочь только те, кто еще и украинский знает?

      Автору спасибо за наводку на DMA, но большой негативный ФЕ за ошибки в коде. Я час промучился, пока заметил недостачу амперсандов &=~ !!!!!!!

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

Spam Protection by WP-SpamFree