Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Stm32f103 USART2+DMA+485

Пн ноя 19, 2018 11:23:26

Столкнулся с проблемой, не как не могу сдать стабильную связь.
1) отправляю запрос 1 байт
2) принимаю посылку через DMA в 50 байт
Смотрю в анализаторе все нормально приходит, через 9-300 ms
А в программе почему то последний байт считывается как первый(остальные правильно, кроме последнего его нету) и из за этого вся посылка сдвигается, и контрольные байты (стартовый стоповый ) не правильные.

Работу с USART сделал через calback:
Код:
// Отправляю запрос
static void Send_responce(uint8_t data){
   if(RS485_USART->SR&USART_SR_TXE){
      RS485_USART->DR=0x11;         //запрос на пакет
      DEBUG_USART_1
      USART_CallBack(0,wait_send_responce);
   }
}
// Ожидания отправка + настройка DMA
static void wait_send_responce(uint8_t data){
   if(RS485_USART->SR&USART_SR_TC){
      //----------
      RS485_IN                     //настраиваем на выход
      delay_ms(10);            //задержка на переключение
        Debug2_1             // отладочный строб
        Debug2_0
      //
      (void)RS485_USART->DR;        // Сбрасываем флаг RXNE
                     RS485_USART->SR=0;         // Сбрасываем флаг RXNE
      //---------- DMA на прием ----------
      SetDmaUsartData(RS485_USART,0,Receive_pack,(sizeof(Resp_pack_t)));
      DMA1->IFCR|=DMA_IFCR_CGIF6;
      USART_CallBack(0,wait_start_pack);
   }
}


void SetDmaUsartData(USART_TypeDef* USARTx,uint8_t* Buf,uint8_t* receive,uint32_t len){
   if(USARTx==USART3){
      //----------
      NVIC_DisableIRQ (DMA1_Channel2_IRQn);
      //==================
      //DMA1->IFCR |= DMA_ISR_TCIF5;//очистить флаг окончания обмена.
      //==================
      BIT_BAND_PER(DMA1_Channel2->CCR, DMA_CCR1_EN) = 0;      //Отключили DMA
      BIT_BAND_PER(DMA1_Channel3->CCR, DMA_CCR1_EN) = 0;      //Отключили DMA
      //----------
      DMA1_Channel3->CNDTR=3; //Принимать по максимум, сколько есть
      DMA1_Channel3->CMAR = (unsigned int)&receive[0];
      BIT_BAND_PER(DMA1_Channel3->CCR, DMA_CCR1_EN) = 1;      //Включаем   
      //----------
      DMA1_Channel2->CNDTR= len;
      DMA1_Channel2->CMAR = (unsigned int)&Buf[0];
      BIT_BAND_PER(DMA1_Channel2->CCR, DMA_CCR1_EN) = 1;      //Включаем
      //----------
   }
   if(USARTx==USART2){
      //----------
      //NVIC_DisableIRQ (DMA1_Channel2_IRQn);
      //==================
      //DMA1->IFCR |= DMA_ISR_TCIF5;//очистить флаг окончания обмена.
      //==================
      BIT_BAND_PER(DMA1_Channel6->CCR, DMA_CCR1_EN) = 0;      //Отключили DMA
      //----------
      DMA1_Channel6->CNDTR=len;
      DMA1_Channel6->CMAR = (unsigned int)&receive[0];
      BIT_BAND_PER(DMA1_Channel6->CCR, DMA_CCR1_EN) = 1;      //Включаем         
   }
}


Такое чувство, что флаг RXNE перед включением DMA не сбрасывается и после того как DMA сразу отрабатывает запрос, и записывает в буфер то что было в регистре DR, а там как раз последний байт от предыдущей посылки.

Re: Stm32f103 USART2+DMA+485

Пн ноя 19, 2018 11:38:04

У вас винегрет какой-то...
Во первых нахрена здесь битбэнд?
Во вторых биты IFCR write only .
Код:
DMA1->IFCR |= DMA_ISR_TCIF5;


В третьих это что ?
Код:
(void)RS485_USART->DR;        // Сбрасываем флаг RXNE
 RS485_USART->SR=0;         // Сбрасываем флаг RXNE


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

Re: Stm32f103 USART2+DMA+485

Пн ноя 19, 2018 12:14:40

Как-то давно делал. Основная возня была чтобы сигнал RW вовремя дёргался.
Код:
void Send_USART2_DMA(uint8_t *tx_buf, uint32_t cnt)
{
  GPIOA->BSRR = (1<<1);  //RW=1   
  DMA1_Channel7->CMAR = (uint32_t) tx_buf;
  USART2->DR; USART2->SR;
  USART2->CR3 = USART_CR3_DMAT;
  DMA1_Channel7->CNDTR = cnt;
  DMA1_Channel7->CCR = DMA_CCR_MSIZE_8 | DMA_CCR_PSIZE_8 | DMA_CCR_DIR | DMA_CCR_MINC| DMA_CCR_TCIE | DMA_CCR_EN;
};

void Read_USART2_DMA(uint8_t *rx_buf, uint32_t cnt)

  DMA1_Channel6->CMAR = (uint32_t) rx_buf;
  while(!(USART2->SR & USART_SR_TC));
  USART2->DR; USART2->DR;
  USART2->CR3 = USART_CR3_DMAR; 
  DMA1_Channel6->CNDTR = cnt;
  DMA1_Channel6->CCR = DMA_CCR_MSIZE_8 | DMA_CCR_PSIZE_8 | DMA_CCR_MINC| DMA_CCR_TCIE | DMA_CCR_EN;
}

extern "C" void USART2_IRQHandler(void)
{
  USART2->CR1 &= ~USART_CR1_TCIE;
  GPIOA->BRR = (1<<1);  //RW=0
}

extern "C" void DMA1_Channel7_IRQHandler(void)
{
  DMA1->IFCR = DMA_IFCR_CTCIF7;
  USART2->SR = 0;
  USART2->CR1 |= USART_CR1_TCIE;
  USART2->CR3 = 0;
  DMA1_Channel7->CCR = DMA_CCR_MSIZE_8 | DMA_CCR_PSIZE_8 | DMA_CCR_DIR | DMA_CCR_MINC;
}

extern "C" void DMA1_Channel6_IRQHandler(void)
{
  DMA1->IFCR = DMA_IFCR_CTCIF6;
  USART2->CR3 = 0; 
  DMA1_Channel6->CCR = DMA_CCR_MSIZE_8 | DMA_CCR_PSIZE_8 | DMA_CCR_MINC;
  // Тут данные получены и лежат в приёмном буфере
}

Re: Stm32f103 USART2+DMA+485

Пн ноя 19, 2018 17:43:36

Если известна длина пакета - настраиваем дма и в прерывании по окончанию трансфера имеем весь пакет в буфере.

dosikus, Ну у меня почти так и сделано, только вместо прерывания смотрю флаг завершения трансфера в майне. Но вот первый байт в буфере, берется от предыдущей посылке :shock:
VladislavS, Благодарю позже по гляжу по подробнее, пока интересно:
1) в функции Read_USART2_DMA почему два раза считывание ?
Код:
 USART2->DR; USART2->DR;

2) а не лучше ли флаг DMAT, DMAR объявить при инициализации ?

Re: Stm32f103 USART2+DMA+485

Пн ноя 19, 2018 19:20:50

pokk, ты не понял смысла его манипуляций, внимательней читай. Намекну , первые два инициаторы....

Re: Stm32f103 USART2+DMA+485

Пн ноя 19, 2018 20:12:20

1) в функции Read_USART2_DMA почему два раза считывание?
Там всякой "срани" во входных буферах набирается, особенно в полудуплексе - надо хорошо "прочистить" перед приёмом.

2) а не лучше ли флаг DMAT, DMAR объявить при инициализации ?
Попробуй, может и получится. Не претендую на единственно верный алгоритм. Но в режиме DMA порт не так как ты привык реагирует на обычные воздействия.

Если честно, писал давно, с точностью до каждого бита уже не помню. Помню лишь, что обложился тогда RM, отладчиком и осциллографом и только тогда получилось.

PS: Давай я всё же поясню что там происходит. Передача:
1. Переключаем RW на передачу.
2. Даём команду DMA отправить нужное количество байт.
3. В прерывании окончания работы DMA сигнал RW ещё рано снимать, так как последний байт только лёг в DR и не передался ещё. Поэтому отключаем DMA и включаем прерывание TXC.
4. По прерыванию окончания передачи переключаем RW на приём и выключаем прерывание TXC.

С приёмом всё проще. Ждём когда закончится передача и настраиваем DMA на приём нужного количества байт.

Re: Stm32f103 USART2+DMA+485

Вт ноя 20, 2018 05:36:50

dosikus, это вы про что ?
VladislavS, С передачей у меня все нормально, да и там всего 1 байт, так что без dma отправляю, а вот с приемом беда, как-то не правильно
очищаю, dma или usart перед включением DMA :( .

В общем накидал вот такой тест
1) Переключаю на выход rw,
2) Отправляю байт и жду пока отправиться USART_SR_TC
3) переключаю на вход и настраиваю DMA
4) смотрю что считалось в буффер,

Код:
while(1){
        USART2->CR1 &=~USART_CR1_UE;
        USART2->CR1 |= USART_CR1_UE;            // USart Enable
      //----------
      RS485_OUT      //Переключил на выход
      while(!(USART2->SR&USART_SR_TXE)){}      
      USART2->DR=0x11;
      while(!(USART2->SR&USART_SR_TC)){}      
      //----------
      RS485_IN                     //настраиваем на выход
      Debug2_1
      Debug2_0         
      //----------
      DMA1_Channel6->CCR=0;
      //----------
      USART2->SR=0;   
      USART2->CR3=USART_CR3_DMAR;
      (void)USART2->DR;
      (void)USART2->DR;
      DMA1_Channel6->CNDTR=sizeof(Resp_pack_t); //Принимать по максимум, сколько есть
      DMA1_Channel6->CMAR = (uint32_t)&Receive_pack[0];
      DMA1_Channel6->CCR=DMA_CCR1_TCIE|DMA_CCR6_MINC|DMA_CCR1_EN;       
      DMA1->IFCR=DMA_IFCR_CGIF6;
      //----------
      while(Receive==0){}
      Receive=0;
      //while(!(DMA1->ISR & DMA_ISR_TCIF6)){}   
      //while(!(RS485_USART->SR&USART_SR_RXNE)){}
      Debug2_1
      Debug2_0
      //----------
      if(Receive_pack[0]==0x11){
         if(Receive_pack[49]==0x13){ //пакет принят правильно
            NOP;
                //----------
         }
      }else{
          NOP;         //!!!!!!!!!!!!!! Тут смотрю как принялся пакет
        }
   }
}
//==========================
/*
   * @Описание:   Описание функции.
   * @Параметр:   
   * @Возврат:      Нету
*/
void DMA1_Channel6_IRQHandler(void)
{
  DMA1->IFCR = DMA_IFCR_CGIF6;
  Receive=1;
  //DMA1_Channel6->CCR =DMA_CCR6_MINC;
  USART2->CR3=0;
}



Так вот если убрать, выкл вкл usart
Код:
   USART2->CR1 &=~USART_CR1_UE;
   USART2->CR1 |= USART_CR1_UE;            // USart Enable

то у меня происходит следуюшее, первый байт считываеться не коректно, и постоянно прыгает, то ноль
то последний из предыдушей поссылке, мне сдаеться что в буффере usart остаеться данные и при включении
dma, они сразу считываються и поссылка принимаеться не коректно. А если перед всем этим перезагрузить usart, то прием происходит нормально
как сбросить usart нормально без выкл/выкл его?
Вложения
TestUsart.c
(6.37 KiB) Скачиваний: 201

Re: Stm32f103 USART2+DMA+485

Вт ноя 20, 2018 06:59:10

pokk, с передачей 1 байта, конечно, dma не впирался. А вот в приёме повтори мой код. С первого взгляда, чистить DR надо до того как DMAR поставил. Я же говорил, после того как ты отдал порт dma он твои команды не так воспринимает.

Re: Stm32f103 USART2+DMA+485

Вт ноя 20, 2018 08:27:36

Благодарю всех за помощь, проблема была в том что надо было увеличить задержку после переключения на прием. + нормально переключать DMA
в итоге прием DMA получился следующий:
Код:
   DMA1_Channel6->CCR=0;
   (void)USART2->DR;(void)USART2->DR;
   DMA1_Channel6->CNDTR=sizeof(Resp_pack_t);
   DMA1_Channel6->CMAR = (uint32_t)&Receive_pack[0];
   DMA1_Channel6->CCR=DMA_CCR1_TCIE|DMA_CCR6_MINC|DMA_CCR1_EN;       
   DMA1->IFCR = DMA_IFCR_CGIF6;
   USART2->SR=0;   
   USART2->CR3=USART_CR3_DMAR;
   //----------
   while(!(DMA1->ISR & DMA_ISR_TCIF6)){}   
   DMA1_Channel6->CCR=0;
   USART2->CR3=0;

Re: Stm32f103 USART2+DMA+485

Вт ноя 20, 2018 10:27:19

А чего не по прерыванию? Смысл задействовать DMA и тупо висеть ожидая конца его работы? Можно же что-нибудь ещё поделать в это время.

Re: Stm32f103 USART2+DMA+485

Вт ноя 20, 2018 10:35:42

Ну это тестовый вариант для отладки , а так сделал как в первом посте на условиях и переключения адреса функции.
Скорости не большие, по этому можно в майне успевать мониторить флаг, + меньше вложенных прерываний, соответственно меньше коллизий.
Ответить