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

 
 
> STM32F1 DMA USART Посылка произвольной длины
Qic
сообщение Jul 21 2016, 07:50
Сообщение #1





Группа: Участник
Сообщений: 6
Регистрация: 1-02-15
Пользователь №: 84 881



Доброго времени суток!
Делаю на stm32f103 приемопередающую часть с обработчиком произвольных команд для посылок произвольной длины.
Сейчас код выглядит так (самое важное):
CODE
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, перечитав даташит несколько раз всеравно не могу понять - может ли он корректно поймать тишину после байта? Но как видно - работает.

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

Сообщение отредактировал IgorKossak - Jul 21 2016, 08:31
Причина редактирования: [codebox] для длинного кода. [code]-для короткого!!!
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Qic
сообщение Jul 21 2016, 09:10
Сообщение #2





Группа: Участник
Сообщений: 6
Регистрация: 1-02-15
Пользователь №: 84 881



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

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

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

P.S. IgorKossak спасибо за форматирование.
Go to the top of the page
 
+Quote Post
sKWO
сообщение Jul 21 2016, 11:55
Сообщение #3


Местный
***

Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530



Цитата(Qic @ Jul 21 2016, 12:10) *
Насколько Я понимаю можно спокойно сделать и 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;
        }
    }
}

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


--------------------
нельзя недооценивать предсказуемость глупости
Go to the top of the page
 
+Quote Post



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

 


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


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