реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> STM32F2xx - USART+DMA
athlon64
сообщение Apr 26 2012, 12:30
Сообщение #1


Частый гость
**

Группа: Свой
Сообщений: 156
Регистрация: 10-03-10
Из: Уфа
Пользователь №: 55 882



Проект на STM32F217, FreeRTOS
Реализовал работу с портом (передача с DMA, приём по прерываниям). В таком режиме всё работает прекрасно. Не стал делать приём с DMA сразу, т.к. думал что аппаратно определить конец кадра в STM32 нельзя.
Но недавно заметил что в регистре SR есть флажок IDLE, который по идее для этого и предназначен. Проверил, флажок действительно выставляется в конце каждого фрейма и прерывание генерируется.
Но при реализации приёма с DMA возникли проблемы. Принимается первый пакет, обрабатывается и отсылается ответ корректно. Далее приём обламывается, т.к. регистр NDTR не переустанавливается при возобновлении приёма. А по этому регистру считается размер принятого фрейма.
Добавил DMA2_Stream1->CR = 0; перед началом нового приёма, т.к. настроечные регистры DMA недоступны для изменения пока активен стрим. Но сразу после обнуления CR попадаю в HardFault_Handler().

Инициализация порта:
Код
void COM0_init(unsigned int BaudRate)
{
  // Тут инициализация пинов и BaudRate //

  // 1 Stop bit, LIN OFF
  USART6->CR2 = 0x00000000;
  // UART enable, TX,RX enable
  USART6->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_IDLEIE;
  USART6->CR3 = USART_CR3_DMAT | USART_CR3_DMAR;   // Включаем DMA на передачу и на приём UART6
  USART6->CR1 |= USART_CR1_UE;
  NVIC->ISER[2] = (1 << (USART6_IRQn & 0x1F)); // Разрешаем прерывания от USART6
  NVIC->ISER[1] = (1 << (DMA2_Stream1_IRQn & 0x1F)); // Разрешаем прерывания от DMA

  ReceiveFromCOM0_DMA();
}


Обработчики прерываний:
Код
extern xSemaphoreHandle semCOM1pak;

void USART6_IRQHandler(void)
{
  signed long Test;
  int status = USART6->SR;

  if ((status & USART_SR_TC) && (USART6->CR1 & USART_CR1_TCIE)) // Передача окончена (последний байт полностью передан в порт)
  {
    USART6->SR &= ~USART_SR_TC;   // Снимаем флаг
    USART6->CR1 &= ~USART_CR1_TCIE;
    ReceiveFromCOM0_DMA();
  }
  else if (status & USART_SR_IDLE)
  {
    USART6->DR; // Снимаем флаг

    Test = DMA2_Stream1->NDTR;
    
    GPIOE->ODR ^= (1<<6);
    
    PtrInCOM0 = COM_InBuffSize - DMA2_Stream1->NDTR;
    xSemaphoreGiveFromISR(semCOM1pak, &Test);
    vPortYieldFromISR();
  }
}

// Прерывание от DMA2_Stream1 при приёме из UART6
void DMA2_Stream1_IRQHandler(void)
{
  if (DMA2->LISR & DMA2_LO_TCIF1)   // Работа DMA при приёме окончена
    DMA2->LIFCR |= DMA2_LO_TCIF1;   // Снимаем флаг
  
  if (DMA2->LISR & DMA2_LO_TEIF1)   // Ошибка при приёме
    DMA2->LIFCR |= DMA2_LO_TEIF1;   // Снимаем флаг
  
  ReceiveFromCOM0_DMA();
}


Процедуры приёма и отправки:
Код
void ReceiveFromCOM0_DMA(void)
{
  DMA2_Stream1->CR = 0;
  
  DMA2_Stream1->PAR = (uint32_t) &(USART6->DR); // Указатель на регистр-приёмник
  DMA2_Stream1->M0AR = (uint32_t) COM0_InBuff;         // Указатель на буфер источник
  DMA2_Stream1->NDTR = COM_InBuffSize;                    // Размер передаваемого буфера
  
  // 5 канал (CHSEL=101), Memsize=8bit, Mem increment ON, Per2Mem mode, TCIE ON, TEIE ON,  
  DMA2_Stream1->CR = DMA_SxCR_CHSEL_0 | DMA_SxCR_CHSEL_2 | DMA_SxCR_MINC | DMA_SxCR_TCIE | DMA_SxCR_TEIE;
  // Переключаем RS485 на приём
  Tx485_OFF();
  // Начинаем передачу
  DMA2_Stream1->CR |= DMA_SxCR_EN;
}

// Отправить пакет в COM0 с DMA2 (Stream 6/7, канал 5).
void SendToCOM0_DMA(char *Buff, unsigned short Size)
{
  DMA2_Stream1->CR = 0;
  DMA2_Stream6->CR = 0;
  DMA2->LIFCR |= (DMA2_HI_TCIF6 | DMA2_HI_TEIF6);   // Снимаем флаг

  DMA2_Stream6->PAR = (uint32_t) &(USART6->DR); // Указатель на регистр-приёмник
  DMA2_Stream6->M0AR = (uint32_t) Buff;         // Указатель на буфер источник
  DMA2_Stream6->NDTR = Size;                    // Размер передаваемого буфера
  
  // 5 канал (CHSEL=101), Memsize=8bit, Mem increment ON, Mem2Per mode, TCIE ON, TEIE ON,  
  DMA2_Stream6->CR = DMA_SxCR_CHSEL_0 | DMA_SxCR_CHSEL_2 | DMA_SxCR_MINC | DMA_SxCR_DIR_0;
  // Переключаем RS485 на передачу
  Tx485_ON();
  // Начинаем передачу
  DMA2_Stream6->CR |= DMA_SxCR_EN;
  
  USART6->CR1 |= USART_CR1_TCIE;
}


Сообщение отредактировал athlon64 - Apr 26 2012, 12:36


--------------------
Руслан
Go to the top of the page
 
+Quote Post
athlon64
сообщение Apr 27 2012, 04:45
Сообщение #2


Частый гость
**

Группа: Свой
Сообщений: 156
Регистрация: 10-03-10
Из: Уфа
Пользователь №: 55 882



DMA2_StreamY->CR = 0 заменил на DMA2_StreamY->CR &= ~DMA_SxCR_EN и перед новым чтением с DMA добавил сброс флагов стрима. Вроде зашевелилось.
Рабочий вариант выкладываю, может кому-то пригодится


Сообщение отредактировал athlon64 - Apr 27 2012, 04:48
Прикрепленные файлы
Прикрепленный файл  uart.c.txt ( 5.8 килобайт ) Кол-во скачиваний: 321
 


--------------------
Руслан
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 27 2012, 05:04
Сообщение #3


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Спасибо, навернное пригодится.
Кстати, вот эта вот хитрая конструкция:
Код
  apbclock = 60000000;

  // Считаем делитель для заданного BaudRate
  IntValue = ((apbclock * 25 / 4) / BaudRate);
  Mantissa = (unsigned short int) (IntValue / 100);
  Fraction = (unsigned short int) (IntValue - Mantissa*100);
  Fraction = (Fraction*4)/25;
  USART6->BRR = (Mantissa << 4) | Fraction;

полностью эквивалентна вот такой простой записи:
Код
USART6->BRR = apbclock / BaudRate;

sm.gif


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Apr 27 2012, 05:43
Сообщение #4


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(AHTOXA @ Apr 27 2012, 09:04) *

Все-таки, наверно лучше с поправкой на целочисленное деление:
Код
USART6->BRR = (apbclock + BaudRate/2) / BaudRate;


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 26th June 2025 - 18:45
Рейтинг@Mail.ru


Страница сгенерированна за 0.01389 секунд с 7
ELECTRONIX ©2004-2016