Jump to content
    

STM32F1 DMA USART Посылка произвольной длины

Доброго времени суток!

Делаю на stm32f103 приемопередающую часть с обработчиком произвольных команд для посылок произвольной длины.

Сейчас код выглядит так (самое важное):

volatile uint8_t usart1_rx_buff[255];
volatile int32_t usart1_rx_buff_lenght = 0;
volatile int32_t usart1_rx_data_ready = 0;
volatile uint8_t usart1_tx_buff[255];
volatile int32_t usart1_tx_buff_lenght = 0;

void USART1_config (void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // Enable clk APB2 -> GPIOA
GPIO_INIT_PIN(GPIOA,9,GPIO_MODE_OUTPUT50_ALT_PUSH_PULL); // USART1 PA9 TX
GPIO_INIT_PIN(GPIOA,10,GPIO_MODE_INPUT_FLOATING); // USART1 PA10 RX

USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd((RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO), ENABLE); //Разрешаем тактирование

USART_InitStructure.USART_BaudRate = 115200;// скорость
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8 бит данных
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_Rx | USART_Mode_Tx;	   // разрешаем прием и передачу

USART_Init(USART1, &USART_InitStructure); //инизиализируем

NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //канал
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //приоритет
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//приоритет субгруппы
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //включаем канал
NVIC_Init(&NVIC_InitStructure); //инициализируем

USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);

USART_Cmd(USART1, ENABLE);
}

void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) // Receive Data register not empty interrupt
{
	USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}

if(USART_GetITStatus(USART1, USART_IT_TC) != RESET) // Transmission complete interrupt
{
	USART_ClearITPendingBit(USART1, USART_IT_TC);
}

if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) // IDLE
{
	USART_ClearITPendingBit(USART1, USART_IT_IDLE); // When DMA receiving get IDLE on UART
	USART_ITConfig(USART1, USART_IT_IDLE, DISABLE); // Выключаем прерывание т.к. мы схуято тутже висим постоянно
	usart1_rx_data_ready = 1;
}
}


void DMA_for_USART1_TX_config_and_run (uint8_t buff_size)
{
// Config DMA : usart1_tx_buff -> USART1 for 255 bytes
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

DMA_InitTypeDef DMA_InitStruct;
DMA_StructInit(&DMA_InitStruct);
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t) & (USART1->DR);
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t) usart1_tx_buff;
DMA_InitStruct.DMA_BufferSize = buff_size;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_Init(DMA1_Channel4, &DMA_InitStruct);

DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
NVIC_EnableIRQ(DMA1_Channel4_IRQn);
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

DMA_Cmd(DMA1_Channel4, ENABLE); // RUN
_delay_us(10);
}

void DMA_for_USART1_RX_config_and_run (void)
{
// Config DMA : USART1 -> usart1_rx_buff for 255 bytes
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

DMA_InitTypeDef DMA_InitStruct;
DMA_StructInit(&DMA_InitStruct);
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t) & (USART1->DR);
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t) usart1_rx_buff;
DMA_InitStruct.DMA_BufferSize = 255;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_Init(DMA1_Channel5, &DMA_InitStruct);

NVIC_EnableIRQ(DMA1_Channel5_IRQn);
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);

DMA_Cmd(DMA1_Channel5, ENABLE); // RUN
}

void DMA1_Channel4_IRQHandler(void) // USART1 TX // Now ONLY transfer complete
{
DMA_Cmd(DMA1_Channel4, DISABLE);
USART_DMACmd(USART1, USART_DMAReq_Tx, DISABLE);

if(DMA1->ISR & DMA_ISR_TCIF4) // Если обмен завершен
{
	DMA_ClearITPendingBit(DMA1_IT_TC4);
}

if(DMA1->ISR & DMA_ISR_HTIF4) // Если передана половина буфера
{
	DMA_ClearITPendingBit(DMA1_IT_HT4);
}

if(DMA1->ISR & DMA_ISR_TEIF4) // Если произошла ошибка при обмене
{
	DMA_ClearITPendingBit(DMA1_IT_TE4);
}

if(DMA1->ISR & DMA_ISR_GIF4) // Если произошла ошибка при обмене
{
	DMA_ClearITPendingBit(DMA_ISR_GIF4);
}
}

void DMA1_Channel5_IRQHandler(void) // USART1 RX // Now ONLY transfer complete
{
DMA_Cmd(DMA1_Channel5, DISABLE);
USART_DMACmd(USART1, USART_DMAReq_Rx, DISABLE);

if(DMA1->ISR & DMA_ISR_TCIF5) // Если обмен завершен
{
	DMA_ClearITPendingBit(DMA1_IT_TC5);
}

if(DMA1->ISR & DMA_ISR_HTIF5) // Если передана половина буфера
{
	DMA_ClearITPendingBit(DMA1_IT_HT5);
}

if(DMA1->ISR & DMA_ISR_TEIF5) // Если произошла ошибка при обмене
{
	DMA_ClearITPendingBit(DMA1_IT_TE5);
}

if(DMA1->ISR & DMA_ISR_GIF5) // Если произошла глобальная ошибка
{
	DMA_ClearITPendingBit(DMA_ISR_GIF5);
}
}

void Execute_Command (void)
{
if (usart1_rx_data_ready == 1) //
{
	usart1_rx_data_ready = 0;
	DMA_Cmd(DMA1_Channel5, DISABLE); // Stop DMA
	usart1_rx_buff_lenght = 255 - DMA_GetCurrDataCounter(DMA1_Channel5); // Get REMAINING counter for work with usart1_rx_buff
	// Data in "usart1_rx_buff" & len of it "usart1_rx_buff_lenght" READY

	if (usart1_rx_buff_lenght != 0)
	{
		// Func FN01 "Echo"  ***************************************************************************
*************************
		//if ((usart1_rx_buff[0]=='F')&(usart1_rx_buff[1]=='N')&(usart1_rx_buff[2]=='0')&(usart1_rx_buff[3]=='1'))
		//{
			//GPIOB->BSRR = GPIO_BSRR_BS5; vTaskDelay(100); GPIOB->BSRR = GPIO_BSRR_BR5; vTaskDelay(100); // For DEBUG

			usart1_tx_buff_lenght = usart1_rx_buff_lenght;
			for (usart1_rx_buff_lenght; usart1_rx_buff_lenght>=0; usart1_rx_buff_lenght--) 
			{
				usart1_tx_buff[usart1_rx_buff_lenght] = usart1_rx_buff[usart1_rx_buff_lenght];
			};
			DMA_for_USART1_TX_config_and_run(usart1_tx_buff_lenght);
		//}
	}
	// Remain of listening
	DMA_for_USART1_RX_config_and_run();
	USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
}
}

int main(void)
{
System_RCC_config();
GPIO_config();
USART1_config();
DMA_for_USART1_RX_config_and_run();
TIM3_PWM_config_and_run();

xTaskCreate( default_task, ( signed char * ) "default_task", configMINIMAL_STACK_SIZE, NULL, 1, NULL );

__enable_irq ();
vTaskStartScheduler();

while(1){}
}

void default_task ( void *pvParameters )
{
for(;; )
{
	vTaskDelay(1);
	Execute_Command();
}
vTaskDelete( NULL );
}

В таком виде конкретно функция Execute_Command которая умеет ЭХО делает всё быстро и замечательно. На все скорости ни затыков ничего такого.

Однако когда Я раскомментирую условие "if ((usart1_rx_buff[0]=='F')&(usart1_rx_buff[1]=='N')&(usart1_rx_buff[2]=='0')&(usart1_rx_buff[3]=='1'))" начинается дичь, а именно в случайном порядке пришедший ответ короче с конца на случайное число байт.

А когда Я раскомментирую мигание светодиодиком (for debug) через несколько срабатываний фукнция перестаёт вообще чтолибо делать, т.к. приемный счётчик DMA1_Channel4 возвращает 255.

Причем еще Я использую обработку IDLE флага от USART, перечитав даташит несколько раз всеравно не могу понять - может ли он корректно поймать тишину после байта? Но как видно - работает.

 

Это мой первый опыт такого конфигурирования и в целом Я не очень хороший программист, возможно кто-нибудь свежим взглядом найдет ошибку и подскажет как сделать лучше.

Надеюсь на вашу помощь.

Edited by IgorKossak
[codebox] для длинного кода. [code]-для короткого!!!

Share this post


Link to post
Share on other sites

Однако когда Я раскомментирую условие "if ((usart1_rx_buff[0]=='F')&(usart1_rx_buff[1]=='N')&(usart1_rx_buff[2]=='0')&(usart1_rx_buff[3]=='1'))" начинается дичь, а именно в случайном порядке пришедший ответ короче с конца на случайное число байт.

 

для начала в if поменяйте "&" на "&&", т.е. на логический.

Так как по мне - это две большие разницы

 

ps

чтоб не растягивать нечитаемые по условию ифы, удобно делать так

 

int log1, log2, logN;

 

log1 = usart1_rx_buff[0]=='F';

log2 = usart1_rx_buff[2]=='0';

. . . .

logN = log1 && ( !log2 );

if( logN ) .....

 

(это пример, здесь логика вашей задаче не соответствует - перепишите как Вам надо)

лог. операторы - || && ! (или-и-NOT)

Edited by k155la3

Share this post


Link to post
Share on other sites

попробуйте так

"if ((usart1_rx_buff[0]=='F')&&(usart1_rx_buff[1]=='N')&&(usart1_rx_buff[2]=='0')&&(usart1_rx_buff[3]=='1'))"

Вам нужно не побитное "и" а логическое.

 

ps

чтоб не растягивать нечитаемые по условию ифы, удобно делать так

или так

//поиск подстроки в строке с ограничением по длине поиска
__x_z signed char my_strstr(char *pData, char __flash *pComp, int len)
{
 signed char result=-1;

 for( unsigned int i=0; i<len; i++)
 {
result=1;
for( unsigned int j=0; *(pComp+j); j++)
{
  if( ( *(pData+i+j) != *(pComp+j))  || ( !*(pComp+j)) )
  {
	result=-1;
	break;
  }
}

if(result == 1)
{
  return i; //возвращаем позицию начала подстроки в строке
}
 }

 return -1;
}

 

Доброго времени суток!

Делаю на stm32f103 приемопередающую часть с обработчиком произвольных команд для посылок произвольной длины.

Сейчас код выглядит так (самое важное):

вот вам пример для вашего контроллера с фифо и дма

хедер

#pragma once

#define UART_BUFFER_SIZE	64

#define UART1_RX_BUFFER_SIZE	256
#define UART1_TX_BUFFER_SIZE	256
#define UART2_RX_BUFFER_SIZE	128
#define UART2_TX_BUFFER_SIZE	64
#define UART3_RX_BUFFER_SIZE	256
#define UART3_TX_BUFFER_SIZE	256
#define MAX_SERIAL_PORTS		3

// FIXME this is a uart_t really.  Move the generic properties into a separate structure (serialPort_t) and update the code to use it
typedef struct {
serialPort_t port;

// FIXME these are uart specific and do not belong in here
DMA_Channel_TypeDef *rxDMAChannel;
DMA_Channel_TypeDef *txDMAChannel;

uint32_t rxDMAIrq;
uint32_t txDMAIrq;

uint32_t rxDMAPos;
bool txDMAEmpty;

USART_TypeDef *USARTx;
} uartPort_t;

extern const struct serialPortVTable uartVTable[];

serialPort_t *uartOpen(USART_TypeDef *USARTx, serialReceiveCallbackPtr callback, uint32_t baudRate, portMode_t mode);

// serialPort API
void uartWrite(serialPort_t *instance, uint8_t ch);
uint8_t uartTotalBytesWaiting(serialPort_t *instance);
uint8_t uartRead(serialPort_t *instance);
void uartSetBaudRate(serialPort_t *s, uint32_t baudRate);
bool isUartTransmitBufferEmpty(serialPort_t *s);

драйвер

/*
* This file is part of baseflight
* Licensed under GPL V3 or modified DCL - see https://github.com/multiwii/baseflight/blob/master/README.md
*
* DMA UART routines idea lifted from AutoQuad
* Copyright © 2011  Bill Nesbitt
*/
#include "board.h"

static uartPort_t uartPort1;
static uartPort_t uartPort2;
static uartPort_t uartPort3;

// USART1 - Telemetry (RX/TX by DMA)
uartPort_t *serialUSART1(uint32_t baudRate, portMode_t mode)
{
uartPort_t *s;
static volatile uint8_t rx1Buffer[uART1_RX_BUFFER_SIZE];
static volatile uint8_t tx1Buffer[uART1_TX_BUFFER_SIZE];
gpio_config_t gpio;
NVIC_InitTypeDef NVIC_InitStructure;

s = &uartPort1;
s->port.vTable = uartVTable;

s->port.baudRate = baudRate;

s->port.rxBuffer = rx1Buffer;
s->port.txBuffer = tx1Buffer;
s->port.rxBufferSize = UART1_RX_BUFFER_SIZE;
s->port.txBufferSize = UART1_TX_BUFFER_SIZE;

s->rxDMAChannel = DMA1_Channel5;
s->txDMAChannel = DMA1_Channel4;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
// USART1_TX	PA9
// USART1_RX	PA10
gpio.speed = Speed_2MHz;
gpio.pin = Pin_9;
gpio.mode = Mode_AF_PP;
if (mode & MODE_TX)
	gpioInit(GPIOA, &gpio);
gpio.pin = Pin_10;
gpio.mode = Mode_IPU;
if (mode & MODE_RX)
	gpioInit(GPIOA, &gpio);

// DMA TX Interrupt
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

return s;
}

// USART2 - GPS or Spektrum or ?? (RX + TX by IRQ)
uartPort_t *serialUSART2(uint32_t baudRate, portMode_t mode)
{
uartPort_t *s;
static volatile uint8_t rx2Buffer[uART2_RX_BUFFER_SIZE];
static volatile uint8_t tx2Buffer[uART2_TX_BUFFER_SIZE];
gpio_config_t gpio;
NVIC_InitTypeDef NVIC_InitStructure;

s = &uartPort2;
s->port.vTable = uartVTable;

s->port.baudRate = baudRate;

s->port.rxBufferSize = UART2_RX_BUFFER_SIZE;
s->port.txBufferSize = UART2_TX_BUFFER_SIZE;
s->port.rxBuffer = rx2Buffer;
s->port.txBuffer = tx2Buffer;

s->USARTx = USART2;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
// USART2_TX	PA2
// USART2_RX	PA3
gpio.speed = Speed_2MHz;
gpio.pin = Pin_2;
gpio.mode = Mode_AF_PP;
if (mode & MODE_TX)
	gpioInit(GPIOA, &gpio);
gpio.pin = Pin_3;
gpio.mode = Mode_IPU;
if (mode & MODE_RX)
	gpioInit(GPIOA, &gpio);

// RX/TX Interrupt
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

return s;
}

// USART3 - Telemetry (RX/TX by DMA + REMAP)
uartPort_t *serialUSART3(uint32_t baudRate, portMode_t mode)
{
uartPort_t *s;
static volatile uint8_t rx3Buffer[uART3_RX_BUFFER_SIZE];
static volatile uint8_t tx3Buffer[uART3_TX_BUFFER_SIZE];
gpio_config_t gpio;
NVIC_InitTypeDef NVIC_InitStructure;

s = &uartPort3;
s->port.vTable = uartVTable;

s->port.baudRate = baudRate;

s->port.rxBuffer = rx3Buffer;
s->port.txBuffer = tx3Buffer;
s->port.rxBufferSize = UART3_RX_BUFFER_SIZE;
s->port.txBufferSize = UART3_TX_BUFFER_SIZE;

// if we're only receiving, fall back to IRQ reception - workaround for spektrum sat polling
if (mode != MODE_RX)
	s->rxDMAChannel = DMA1_Channel3;
s->txDMAChannel = DMA1_Channel2;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
// USART3_TX	PB10
// USART3_RX	PB11
gpio.speed = Speed_2MHz;
gpio.pin = Pin_10;
gpio.mode = Mode_AF_PP;
if (mode & MODE_TX)
	gpioInit(GPIOB, &gpio);
gpio.pin = Pin_11;
gpio.mode = Mode_IPU;
if (mode & MODE_RX)
	gpioInit(GPIOB, &gpio);

if (mode == MODE_RX) {
	// RX Interrupt
	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

// DMA TX Interrupt
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

return s;
}

serialPort_t *uartOpen(USART_TypeDef *USARTx, serialReceiveCallbackPtr callback, uint32_t baudRate, portMode_t mode)
{
DMA_InitTypeDef DMA_InitStructure;
USART_InitTypeDef USART_InitStructure;

uartPort_t *s = NULL;

if (!USARTx)
	return NULL;

if (USARTx == USART1)
	s = serialUSART1(baudRate, mode);
if (USARTx == USART2)
	s = serialUSART2(baudRate, mode);
if (USARTx == USART3)
	s = serialUSART3(baudRate, mode);

s->USARTx = USARTx;

// common serial initialisation code should move to serialPort::init()
s->port.rxBufferHead = s->port.rxBufferTail = 0;
s->port.txBufferHead = s->port.txBufferTail = 0;
// callback for IRQ-based RX ONLY
s->port.callback = callback;
s->port.mode = mode;
s->port.baudRate = baudRate;

USART_InitStructure.USART_BaudRate = baudRate;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
if (mode & MODE_SBUS) {
	USART_InitStructure.USART_StopBits = USART_StopBits_2;
	USART_InitStructure.USART_Parity = USART_Parity_Even;
} else {
	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 = 0;
if (mode & MODE_RX)
	USART_InitStructure.USART_Mode |= USART_Mode_Rx;
if (mode & MODE_TX)
	USART_InitStructure.USART_Mode |= USART_Mode_Tx;
USART_Init(USARTx, &USART_InitStructure);
USART_Cmd(USARTx, ENABLE);

DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USARTx->DR;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

// Receive DMA or IRQ
if (mode & MODE_RX) {
	if (s->rxDMAChannel) {
		DMA_InitStructure.DMA_BufferSize = s->port.rxBufferSize;
		DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
		DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
		DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)s->port.rxBuffer;
		DMA_DeInit(s->rxDMAChannel);
		DMA_Init(s->rxDMAChannel, &DMA_InitStructure);
		DMA_Cmd(s->rxDMAChannel, ENABLE);
		USART_DMACmd(USARTx, USART_DMAReq_Rx, ENABLE);
		s->rxDMAPos = DMA_GetCurrDataCounter(s->rxDMAChannel);
	} else {
		USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);
	}
}

// Transmit DMA or IRQ
if (mode & MODE_TX) {
	if (s->txDMAChannel) {
		DMA_InitStructure.DMA_BufferSize = s->port.txBufferSize;
		DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
		DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
		DMA_DeInit(s->txDMAChannel);
		DMA_Init(s->txDMAChannel, &DMA_InitStructure);
		DMA_ITConfig(s->txDMAChannel, DMA_IT_TC, ENABLE);
		DMA_SetCurrDataCounter(s->txDMAChannel, 0);
		s->txDMAChannel->CNDTR = 0;
		USART_DMACmd(USARTx, USART_DMAReq_Tx, ENABLE);
	} else {
		USART_ITConfig(USARTx, USART_IT_TXE, ENABLE);
	}
}

return (serialPort_t *)s;
}

void uartSetBaudRate(serialPort_t *instance, uint32_t baudRate)
{
USART_InitTypeDef USART_InitStructure;
uartPort_t *s = (uartPort_t *)instance;

USART_InitStructure.USART_BaudRate = baudRate;
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 = 0;
if (s->port.mode & MODE_RX)
	USART_InitStructure.USART_Mode |= USART_Mode_Rx;
if (s->port.mode & MODE_TX)
	USART_InitStructure.USART_Mode |= USART_Mode_Tx;
USART_Init(s->USARTx, &USART_InitStructure);

s->port.baudRate = baudRate;
}

void uartSetMode(serialPort_t *s, portMode_t mode)
{
(void)s;
(void)mode;
// not implemented.
}


static void uartStartTxDMA(uartPort_t *s)
{
s->txDMAChannel->CMAR = (uint32_t)&s->port.txBuffer[s->port.txBufferTail];
if (s->port.txBufferHead > s->port.txBufferTail) {
	s->txDMAChannel->CNDTR = s->port.txBufferHead - s->port.txBufferTail;
	s->port.txBufferTail = s->port.txBufferHead;
} else {
	s->txDMAChannel->CNDTR = s->port.txBufferSize - s->port.txBufferTail;
	s->port.txBufferTail = 0;
}
s->txDMAEmpty = false;
DMA_Cmd(s->txDMAChannel, ENABLE);
}

uint8_t uartTotalBytesWaiting(serialPort_t *instance)
{
uartPort_t *s = (uartPort_t *)instance;
// FIXME always returns 1 or 0, not the amount of bytes waiting
if (s->rxDMAChannel)
	return s->rxDMAChannel->CNDTR != s->rxDMAPos;
else
	return s->port.rxBufferTail != s->port.rxBufferHead;
}

// BUGBUG TODO TODO FIXME - What is the bug?
bool isUartTransmitBufferEmpty(serialPort_t *instance)
{
uartPort_t *s = (uartPort_t *)instance;
if (s->txDMAChannel)
	return s->txDMAEmpty;
else
	return s->port.txBufferTail == s->port.txBufferHead;
}

uint8_t uartRead(serialPort_t *instance)
{
uint8_t ch;
uartPort_t *s = (uartPort_t *)instance;

if (s->rxDMAChannel) {
	ch = s->port.rxBuffer[s->port.rxBufferSize - s->rxDMAPos];
	if (--s->rxDMAPos == 0)
		s->rxDMAPos = s->port.rxBufferSize;
} else {
	ch = s->port.rxBuffer[s->port.rxBufferTail];
	s->port.rxBufferTail = (s->port.rxBufferTail + 1) % s->port.rxBufferSize;
}

return ch;
}

void uartWrite(serialPort_t *instance, uint8_t ch)
{
uartPort_t *s = (uartPort_t *)instance;
s->port.txBuffer[s->port.txBufferHead] = ch;
s->port.txBufferHead = (s->port.txBufferHead + 1) % s->port.txBufferSize;

if (s->txDMAChannel) {
	if (!(s->txDMAChannel->CCR & 1))
		uartStartTxDMA(s);
} else {
	USART_ITConfig(s->USARTx, USART_IT_TXE, ENABLE);
}
}

const struct serialPortVTable uartVTable[] = {
{
	uartWrite,
	uartTotalBytesWaiting,
	uartRead,
	uartSetBaudRate,
	isUartTransmitBufferEmpty,
	uartSetMode,
}
};

// Handlers

// USART1 Tx DMA Handler
void DMA1_Channel4_IRQHandler(void)
{
uartPort_t *s = &uartPort1;
DMA_ClearITPendingBit(DMA1_IT_TC4);
DMA_Cmd(s->txDMAChannel, DISABLE);

if (s->port.txBufferHead != s->port.txBufferTail)
	uartStartTxDMA(s);
else
	s->txDMAEmpty = true;
}

// USART3 Tx DMA Handler
void DMA1_Channel2_IRQHandler(void)
{
uartPort_t *s = &uartPort3;
DMA_ClearITPendingBit(DMA1_IT_TC2);
DMA_Cmd(s->txDMAChannel, DISABLE);

if (s->port.txBufferHead != s->port.txBufferTail)
	uartStartTxDMA(s);
else
	s->txDMAEmpty = true;
}

// USART1 Tx IRQ Handler
void USART1_IRQHandler(void)
{
uartPort_t *s = &uartPort1;
uint16_t SR = s->USARTx->SR;

if (SR & USART_FLAG_TXE) {
	if (s->port.txBufferTail != s->port.txBufferHead) {
		s->USARTx->DR = s->port.txBuffer[s->port.txBufferTail];
		s->port.txBufferTail = (s->port.txBufferTail + 1) % s->port.txBufferSize;
	} else {
		USART_ITConfig(s->USARTx, USART_IT_TXE, DISABLE);
	}
}
}

// USART2 Rx/Tx IRQ Handler
void USART2_IRQHandler(void)
{
uartPort_t *s = &uartPort2;
uint16_t SR = s->USARTx->SR;

if (SR & USART_FLAG_RXNE) {
	// If we registered a callback, pass crap there
	if (s->port.callback) {
		s->port.callback(s->USARTx->DR);
	} else {
		s->port.rxBuffer[s->port.rxBufferHead] = s->USARTx->DR;
		s->port.rxBufferHead = (s->port.rxBufferHead + 1) % s->port.rxBufferSize;
	}
}
if (SR & USART_FLAG_TXE) {
	if (s->port.txBufferTail != s->port.txBufferHead) {
		s->USARTx->DR = s->port.txBuffer[s->port.txBufferTail];
		s->port.txBufferTail = (s->port.txBufferTail + 1) % s->port.txBufferSize;
	} else {
		USART_ITConfig(s->USARTx, USART_IT_TXE, DISABLE);
	}
}
}

// USART3 Rx IRQ Handler
void USART3_IRQHandler(void)
{
uartPort_t *s = &uartPort3;
uint16_t SR = s->USARTx->SR;

if (SR & USART_FLAG_RXNE) {
	// If we registered a callback, pass crap there
	if (s->port.callback) {
		s->port.callback(s->USARTx->DR);
	} else {
		s->port.rxBuffer[s->port.rxBufferHead] = s->USARTx->DR;
		s->port.rxBufferHead = (s->port.rxBufferHead + 1) % s->port.rxBufferSize;
	}
}
}

Edited by IgorKossak
[codebox] для длинного кода, [code] - для короткого!!!

Share this post


Link to post
Share on other sites

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

Вот только все также в терминале наблюдается следующее:

post-84881-1469090861_thumb.png

Также идут проглатывания на отправке, и перестаёт работать видимо при использовании vTaskDelay, видимо особенности работы с FreeRTOS 6.4.0.

Но в первую очередь интересно почему проглатывается.

 

sKWO, Я посмотрел драйвер, но FIFO это кажется не совсем то что мне нужно. Насколько Я понимаю происходит постоянный сбор в буфер всего приемного и обработчик уже должен там самостоятельно выдёргивая по байту разбираться что это и куда. Я же хочу чтобы если что-то появлялось на входе в USART, то оно как правило будет иметь тишину, в частности позже хочу прикрутить туда modbus. Впринципе любые данные будут когда либо иметь конец и паузу, которую Я и ловлю, после чего всё что пришло анализирую.

Насколько Я понимаю можно спокойно сделать и FIFO, не понадобится перезапускать приемный DMA и по IDLE ловить конец. Но хочется разобраться где у меня косяки в DMA что при передачи глотает байты.

 

P.S. IgorKossak спасибо за форматирование.

Share this post


Link to post
Share on other sites

Насколько Я понимаю можно спокойно сделать и FIFO, не понадобится перезапускать приемный DMA и по IDLE ловить конец. Но хочется разобраться где у меня косяки в DMA что при передачи глотает байты.

Я дма использую только для передачи. Для приёма лучше ложить в фифо а дальше с очередями работать и не мучиться с дма. ДМА удобно по приёму например с АЦП но не для приема данных с серийного интерфейса, ИМХО.

Вот повтор кода который я выкладывал:

// USART3 Rx IRQ Handler
void USART3_IRQHandler(void)
{
    uartPort_t *s = &uartPort3;
    uint16_t SR = s->USARTx->SR;

   [b][/b] if (SR & USART_FLAG_RXNE) {[/b] 
        // If we registered a callback, pass crap there
        if (s->port.callback) {
            s->port.callback(s->USARTx->DR);
        } else {
            s->port.rxBuffer[s->port.rxBufferHead] = s->USARTx->DR;
            s->port.rxBufferHead = (s->port.rxBufferHead + 1) % s->port.rxBufferSize;
        }
    }
}

сначала проверили или по приему сюда попали а дальше или каллбэк на функцию или байт в фифо.

так удобнее.

Share this post


Link to post
Share on other sites

Т.е. логика работы выглядит так?:

DMA постоянно гонит данные в буфер, без остановки, когда у нас есть свободное время, мы начинаем анализировать этот самый FIFO буфер на совпадение.

Звучит быстро и просто, проверяем 64 байта на совпадение и обрабатываем.

А что будет если байт 200, или больше? Что если большой, как говорится, payload? А если система комманд исчисляется десятками? Проверять несколько раз буфер на все соответствия?

Мне кажется это расточительно по ресурсам, хочется ловить из потока нужные данные, и тратить на это минимум времени просто проверяя заголовок сразу в известном месте - в начале буфера.

Чисто логически FIFO правильное решение, но это очень много времени на проверку всего потока.

Share this post


Link to post
Share on other sites

Т.е. логика работы выглядит так?:

DMA постоянно гонит данные в буфер, без остановки, когда у нас есть свободное время, мы начинаем анализировать этот самый FIFO буфер на совпадение.

Звучит быстро и просто, проверяем 64 байта на совпадение и обрабатываем.

А что будет если байт 200, или больше? Что если большой, как говорится, payload? А если система комманд исчисляется десятками? Проверять несколько раз буфер на все соответствия?

Мне кажется это расточительно по ресурсам, хочется ловить из потока нужные данные, и тратить на это минимум времени просто проверяя заголовок сразу в известном месте - в начале буфера.

Чисто логически FIFO правильное решение, но это очень много времени на проверку всего потока.

Не совсем понимаю, в чём Вы видите проблему.

1. Есть кольцевой буфер.

2. Есть процесс "писатель" - DMA с своим указателем на память.

3. Есть процесс "читатель" - функция анализа потока, со своим указателем.

4. В каждом сеансе чтения читаются только те принятые байты, которые были приняты с момента предыдущего сеанса.

5. Размер буфера выбирается достаточным для конкретных условий.

6. Процесс "читатель" обычно ищет в потоке заголовок пакета. Затем по заголовку определяет длину пакета и ждёт, пока будет принято нужное число байт. После получения полного пакета - анализ и обработка.

7. Если используется протокол на базе временных интервалов, например ModBus RTU, то по фиксации паузы в потоке можно инициализировать указатели на кольцевой буфер.

И всё, ничего сложного, и нет лишних затрат времени CPU.

Share this post


Link to post
Share on other sites

.

 

Может так и задумано, но есть нюансы.

1. Не обрабатываются ошибки

2. Новые данные затирают старые

Edited by IgorKossak
бездумное цитирование

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...