Stm32f103 USART2+DMA+485

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
pokk
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Stm32f103 USART2+DMA+485

Сообщение pokk »

Столкнулся с проблемой, не как не могу сдать стабильную связь.
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, а там как раз последний байт от предыдущей посылки.
Реклама
Аватара пользователя
dosikus
Друг Кота
Сообщения: 3604
Зарегистрирован: Пн июл 28, 2008 22:12:01

Re: Stm32f103 USART2+DMA+485

Сообщение dosikus »

У вас винегрет какой-то...
Во первых нахрена здесь битбэнд?
Во вторых биты IFCR write only .

Код: Выделить всё

DMA1->IFCR |= DMA_ISR_TCIF5;
В третьих это что ?

Код: Выделить всё

(void)RS485_USART->DR;        // Сбрасываем флаг RXNE 
 RS485_USART->SR=0;         // Сбрасываем флаг RXNE 
Если известна длина пакета - настраиваем дма и в прерывании по окончанию трансфера имеем весь пакет в буфере.
А здесь уже перезапускаем канал дма и выставляем флаг готовности пакета, в основном цЫкле разгребаем.
Реклама
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Stm32f103 USART2+DMA+485

Сообщение VladislavS »

Как-то давно делал. Основная возня была чтобы сигнал 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;
  // Тут данные получены и лежат в приёмном буфере
}
pokk
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Re: Stm32f103 USART2+DMA+485

Сообщение pokk »

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

Код: Выделить всё

 USART2->DR; USART2->DR;
2) а не лучше ли флаг DMAT, DMAR объявить при инициализации ?
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
dosikus
Друг Кота
Сообщения: 3604
Зарегистрирован: Пн июл 28, 2008 22:12:01

Re: Stm32f103 USART2+DMA+485

Сообщение dosikus »

pokk, ты не понял смысла его манипуляций, внимательней читай. Намекну , первые два инициаторы....
Реклама
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Stm32f103 USART2+DMA+485

Сообщение VladislavS »

[uquote="pokk",url="/forum/viewtopic.php?p=3508009#p3508009"]1) в функции Read_USART2_DMA почему два раза считывание?[/uquote]Там всякой "срани" во входных буферах набирается, особенно в полудуплексе - надо хорошо "прочистить" перед приёмом.

[uquote="pokk",url="/forum/viewtopic.php?p=3508009#p3508009"]2) а не лучше ли флаг DMAT, DMAR объявить при инициализации ?[/uquote]Попробуй, может и получится. Не претендую на единственно верный алгоритм. Но в режиме DMA порт не так как ты привык реагирует на обычные воздействия.

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

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

С приёмом всё проще. Ждём когда закончится передача и настраиваем DMA на приём нужного количества байт.
Реклама
pokk
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Re: Stm32f103 USART2+DMA+485

Сообщение pokk »

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 КБ) 226 скачиваний
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Stm32f103 USART2+DMA+485

Сообщение VladislavS »

pokk, с передачей 1 байта, конечно, dma не впирался. А вот в приёме повтори мой код. С первого взгляда, чистить DR надо до того как DMAR поставил. Я же говорил, после того как ты отдал порт dma он твои команды не так воспринимает.
pokk
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Re: Stm32f103 USART2+DMA+485

Сообщение pokk »

Благодарю всех за помощь, проблема была в том что надо было увеличить задержку после переключения на прием. + нормально переключать 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;
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Stm32f103 USART2+DMA+485

Сообщение VladislavS »

А чего не по прерыванию? Смысл задействовать DMA и тупо висеть ожидая конца его работы? Можно же что-нибудь ещё поделать в это время.
pokk
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Re: Stm32f103 USART2+DMA+485

Сообщение pokk »

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

Вернуться в «ARM»