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

 
 
 
Reply to this topicStart new topic
> FreeRTOS. Не нравится как работает очередь.
inventor
сообщение Dec 8 2015, 14:29
Сообщение #1


Знающий
****

Группа: Свой
Сообщений: 524
Регистрация: 25-12-08
Из: Москва
Пользователь №: 42 748



Переделываю прогу во FreeRTOS - взял в качестве примера работу с портом
мне нужно передвать и принимать данные с модуля SIM900
сначала у меня было сделано со "своим" круговыми буферами на прием и передачу
все работало на ура, потом переделал как в примере - работает через пень колоду.
такое ощущение что просто не успевает принять все символы.
В чем может быть проблема, подскажите?

С очередями как в примере freertos
CODE

/**
* Прерывание от USART2
*/
void USART2_IRQHandler(void)
{
char byte;
volatile u32 status;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

status = USART2->SR;

/* Read one byte from the receive data register */
if (status & USART_FLAG_RXNE) {
byte = USART_ReceiveData(USART2);
xQueueSendFromISR(qRxGsmQueue, &byte, &xHigherPriorityTaskWoken);
}

/* Write one byte to the transmit data register */
if (status & USART_FLAG_TXE) {
/* Берем байт из очереди */
if (xQueueReceiveFromISR(qTxGsmQueue, &byte, &xHigherPriorityTaskWoken) == pdTRUE) {
/* A character was retrieved from the queue so can be sent to the THR now. */
USART_SendData(USART2, byte);
} else {
USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
}
}
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}

/**
* Прием строки из кольцевого буфера
*/
int gsm_get_str(char *str, int len)
{
int i = 0;
u8 byte;

/* Get the next character from the buffer. Return false if no characters are available, or arrive before xBlockTime expires. */
while (xQueueReceive(qRxGsmQueue, &byte, 0) && i < len) {
str[i++] = byte;
}

str[i] = 0; /* Занулим строку */
return i;
}



Вот это вариант работает
CODE
void USART2_IRQHandler(void)
{
char byte;
volatile u32 status;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

status = USART2->SR;

/* Read one byte from the receive data register */
if (status & USART_FLAG_RXNE) {
byte = USART_ReceiveData(USART2);
// xQueueSendFromISR(qRxGsmQueue, &byte, &xHigherPriorityTaskWoken);
gsm_read_byte_isr(byte);
}

/* Write one byte to the transmit data register */
if (status & USART_FLAG_TXE) {
gsm_write_byte_isr();
/* Disable the USART2 Transmit interrupt */
/* USART_ITConfig(USART2, USART_IT_TXE, DISABLE); */
}
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}

/* Передача строки по-прерываниям - заталкиваем в кольцевой буфер данные */
int gsm_send_buf(u8 * buf, int len)
{
int i = 0;
u8 byte;

/* Пока буфер не заполница */
while (!cb_is_full(&cb_tx) && i < len) {
byte = buf[i++];
cb_write(&cb_tx, &byte);
}

/* Включаем прерывание */
USART_ITConfig(USART2, USART_IT_TXE, ENABLE);
return i;
}

/* Передать один байт, когда передавать нечего - выключить передатчик */
void gsm_write_byte_isr(void)
{
volatile u8 byte;

/* Передаем, пока буфер не пустой. Иначе - выключаем прерывания. */
if (!cb_is_empty(&cb_tx)) {
cb_read(&cb_tx, (ElemType *) & byte);
USART_SendData(USART2, byte);
} else {
USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
}
}

/* Прием строки из кольцевого буфера */
int gsm_get_str(char *str, int len)
{
int i = 0;
u8 byte;

while (!cb_is_empty(&cb_rx) && i < len) {
cb_read(&cb_rx, (ElemType *) & byte);
str[i++] = byte;
}
str[i] = 0; /* Занулим строку */
return i;
}

/**
* Обслуживание GPRS модема - прием ответа
* Записываем символ в кольцевой буфер
*/
void gsm_read_byte_isr(u8 rx_byte)
{
cb_write(&cb_rx, &rx_byte);
}
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Dec 9 2015, 05:20
Сообщение #2


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



Кладите в очередь порции байт. А лучше - уже готовые пакеты (к примеру можно бить по \n)
Go to the top of the page
 
+Quote Post
Valentine Logino...
сообщение Dec 9 2015, 07:01
Сообщение #3


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

Группа: Участник
Сообщений: 78
Регистрация: 7-04-10
Из: Пушкино
Пользователь №: 56 462



А еще лучше вернитесь к своим кольцевым буферам и добавьте к ним потокобезопасность (критические секции/мьютекс).
Очереди FreeRTOS очень медленные, даже в официальной документации где-то упоминалось, что это просто пример реализации и лучше стараться так не делать.
Go to the top of the page
 
+Quote Post
den_po
сообщение Dec 9 2015, 07:05
Сообщение #4


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

Группа: Участник
Сообщений: 139
Регистрация: 9-11-12
Из: Санкт-Петербург
Пользователь №: 74 315



Цитата(inventor @ Dec 8 2015, 17:29) *
/* Get the next character from the buffer. Return false if no characters are available, or arrive before xBlockTime expires. */
while (xQueueReceive(qRxGsmQueue, &byte, 0) && i < len) {

0?
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Dec 9 2015, 07:07
Сообщение #5


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



Цитата(Valentine Loginov @ Dec 9 2015, 10:01) *
А еще лучше вернитесь к своим кольцевым буферам и добавьте к ним потокобезопасность (критические секции/мьютекс).
Очереди FreeRTOS очень медленные, даже в официальной документации где-то упоминалось, что это просто пример реализации и лучше стараться так не делать.


Мьютексы там - просто доп макросы, за которыми скрыта та же очередь
Go to the top of the page
 
+Quote Post
SMaster
сообщение Dec 9 2015, 09:44
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 9-03-06
Пользователь №: 15 099



1. Какой контроллер, на какой частоте работает, какой бодрейт у USARTа? Чтобы понимать сколько ресурсов требуется.
2. Какой длины очереди?

Если бодрейт не более 115200, то очень странно, что контроллер не успевает отработать очередь. Для увеличения производительности можно попробовать применить т.н. уведомления, которые появились во FreeRTOS сравнительно недавно. http://www.freertos.org/RTOS_Task_Notifica...As_Mailbox.html

Код будет приблизительно такой:

CODE
void USART2_IRQHandler(void)
{
char byte;
volatile u32 status;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

status = USART2->SR;

/* Read one byte from the receive data register */
if (status & USART_FLAG_RXNE) {
byte = USART_ReceiveData(USART2);
xTaskNotifyFromISR(receive_task_handler, (uint32_t)byte, eSetValueWithOverwrite, &xHigherPriorityTaskWoken); // receive_task_handler - хэндлер задачи, принимающей данные
}

/* Write one byte to the transmit data register */
if (status & USART_FLAG_TXE) {
/* Берем байт из очереди */
if (xQueueReceiveFromISR(qTxGsmQueue, &byte, &xHigherPriorityTaskWoken) == pdTRUE) {
/* A character was retrieved from the queue so can be sent to the THR now. */
USART_SendData(USART2, byte);
} else {
USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
}
}

portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);

}

void receive_task(void * param) {

uint32_t data;

while (1) {

xTaskNotifyWait(0, 0, &data, portMAX_DELAY); // Время ожидания бесконечность

// Do something
// ...

}

}


И вообще, интересно взглянуть на вашу задачу, из которой вызывается gsm_get_str(). Как верно заметил den_po время ожидания элемента из очереди = 0. Какой-то не RTOSовский подход - функция будет вызываться вхолостую, вместо того, чтобы выполнение задачи блокировалось до появления данных на входе USART. В моем примере время ожидания бесконечно (при INCLUDE_vTaskSuspend равном 1).

Отправку тоже можно упростить (в вычислительном плане), заюзав DMA. Судя по вызову USART_ITConfig, контроллер серии STM32 => DMA на борту имеется.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Dec 9 2015, 16:14
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



QUOTE (inventor @ Dec 8 2015, 16:29) *
В чем может быть проблема, подскажите?

Исходники не читал, но и из преамбулы ясно что причина, в непонимании того, что такое очередь. Ее, конечно, можно использовать, как и пушку для стрельбы по воробьям, но может и не получиться из-за накладных расходов. То, что вы сделали это свели очередь к байтовому буферу с дерганием системы на обработку каждого пришедшего байта.
Для Вашего случая логично помещать в собственный буфер (и необязательно кольцевой) пришедшие байты, отслеживать начало-конец информационного фрейма и по получении фрейма
помещать в очередь указатель на этот фрейм. По получении сообщения из очереди задача будет подниматься и обрабатывать целый фрейм.




--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
inventor
сообщение Dec 9 2015, 19:49
Сообщение #8


Знающий
****

Группа: Свой
Сообщений: 524
Регистрация: 25-12-08
Из: Москва
Пользователь №: 42 748



Цитата(SMaster @ Dec 9 2015, 12:44) *
1. Какой контроллер, на какой частоте работает, какой бодрейт у USARTа? Чтобы понимать сколько ресурсов требуется.
2. Какой длины очереди?

Если бодрейт не более 115200, то очень странно, что контроллер не успевает отработать очередь. Для увеличения производительности можно попробовать применить т.н. уведомления, которые появились во FreeRTOS сравнительно недавно. http://www.freertos.org/RTOS_Task_Notifica...As_Mailbox.html

Код будет приблизительно такой:

CODE
void USART2_IRQHandler(void)
{
char byte;
volatile u32 status;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

status = USART2->SR;

/* Read one byte from the receive data register */
if (status & USART_FLAG_RXNE) {
byte = USART_ReceiveData(USART2);
xTaskNotifyFromISR(receive_task_handler, (uint32_t)byte, eSetValueWithOverwrite, &xHigherPriorityTaskWoken); // receive_task_handler - хэндлер задачи, принимающей данные
}

/* Write one byte to the transmit data register */
if (status & USART_FLAG_TXE) {
/* Берем байт из очереди */
if (xQueueReceiveFromISR(qTxGsmQueue, &byte, &xHigherPriorityTaskWoken) == pdTRUE) {
/* A character was retrieved from the queue so can be sent to the THR now. */
USART_SendData(USART2, byte);
} else {
USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
}
}

portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);

}

void receive_task(void * param) {

uint32_t data;

while (1) {

xTaskNotifyWait(0, 0, &data, portMAX_DELAY); // Время ожидания бесконечность

// Do something
// ...

}

}


И вообще, интересно взглянуть на вашу задачу, из которой вызывается gsm_get_str(). Как верно заметил den_po время ожидания элемента из очереди = 0. Какой-то не RTOSовский подход - функция будет вызываться вхолостую, вместо того, чтобы выполнение задачи блокировалось до появления данных на входе USART. В моем примере время ожидания бесконечно (при INCLUDE_vTaskSuspend равном 1).

Отправку тоже можно упростить (в вычислительном плане), заюзав DMA. Судя по вызову USART_ITConfig, контроллер серии STM32 => DMA на борту имеется.


контроллер на 24 Мгц, скорость порта 115200
я вместо нуля ставил 10 постепенно снижал - никакого эфекта
такое ощущение что принимает каждый второй или 3-й байт
а со своими буферами -все очень хорошо
Go to the top of the page
 
+Quote Post
uriy
сообщение Dec 10 2015, 04:50
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 2 429
Регистрация: 30-11-05
Из: Ижевск
Пользователь №: 11 606



В STM32 есть удобная штука - прерывание UART по IDLE. Настраиваете UART для работы через DMA и прерывание по этому событию. В прерывании передаете в о чередь указатель на этот принятый блок данных.
Go to the top of the page
 
+Quote Post
Valentine Logino...
сообщение Dec 10 2015, 06:00
Сообщение #10


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

Группа: Участник
Сообщений: 78
Регистрация: 7-04-10
Из: Пушкино
Пользователь №: 56 462



Цитата(Непомнящий Евгений @ Dec 9 2015, 10:07) *
Мьютексы там - просто доп макросы, за которыми скрыта та же очередь

Ну не совсем ведь та самая. А из одного элемента. И используется лишь как разграничитель доступа, а не как хранилище, ведь за одно взятие мютекса можно записать сразу несколько байт в свой буфер.
Go to the top of the page
 
+Quote Post

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

 


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


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