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

 
 
> stm32+ FreeRtos семафоры для Ethernet и ADC
Acvarif
сообщение Feb 5 2012, 13:09
Сообщение #1


Знающий
****

Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850



Несколько раз перечитал мануал по FreeRTOS в части бинарных семафоров и так до конца и не понял, если имеются два прерывания (например ETH_IRQHandler и ADC_IRQHandler) то для каждого из них нужен свой бинарный семафор или бинарный семафор может быть только один на всех (или вообще только один)?

Суть задачки: Имеется готовый пример использования (FreeRTOS+LwIP) для STM32F217 http://electronix.ru/forum/index.php?showt...98347&st=30 в котором неплохо работает прием по UDP по прерываниям с использованием бинарного семафора
CODE
void ETH_IRQHandler(void)
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

/* Frame received */
if ( ETH_GetDMAFlagStatus(ETH_DMA_FLAG_R) == SET)
{
/* Give the semaphore to wakeup LwIP task */
xSemaphoreGiveFromISR( s_xSemaphore, &xHigherPriorityTaskWoken );
}

/* Clear the interrupt flags. */
/* Clear the Eth DMA Rx IT pending bits */
ETH_DMAClearITPendingBit(ETH_DMA_IT_R);
ETH_DMAClearITPendingBit(ETH_DMA_IT_NIS);

/* Switch tasks if necessary. */
if( xHigherPriorityTaskWoken != pdFALSE )
{
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}
}

сам таск выглядит так
void ethernetif_input( void * pvParameters )
{
struct pbuf *p;

for( ;; )
{
if (xSemaphoreTake( s_xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT)==pdTRUE)
{
p = low_level_input( s_pxNetIf );
if (ERR_OK != s_pxNetIf->input( p, s_pxNetIf))
{
pbuf_free(p);
p=NULL;
}
}
}
}



Имеется необходимость передавать по Ethernet выборки ADC1 (каждую выборку или накапливать небольшой буфер пока неясно)
Наверняка выгодно для этой цели создать task в заторможенном состоянии которая будет разблокироваться прерыванием
по ADC1
Код
void ADC_IRQHandler(void)
{
  portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

  /* ADC1 received */
  if (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == SET)
  {
    /* Give the semaphore to wakeup ADC1 task */
    xSemaphoreGiveFromISR( s_xSemaphore, &xHigherPriorityTaskWoken );  
  }
    
  /* Clear the interrupt flag. */
  ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
}
и затем уже в таске, которая будет разбужена семафором передавать UDP пакет с выборкой.

Вот и непонятно можно ли использовать один и тот же бинарный семафор для разных тасков? Если да то как будет выглядеть таск который будет выполнен по прерыванию ADC1? Может так?
CODE
void AdcUdpSend(void * pvParameters)
{
struct netconn *connn;
struct netbuf *buf1;
struct ip_addr addr;
static char text[2];

// create a new connection
connn = netconn_new(NETCONN_UDP);
// set up the IP address of the remote host
IP4_ADDR(&addr, DIP_ADDR0, DIP_ADDR1, DIP_ADDR2, DIP_ADDR3);
// connect the connection to the remote host
netconn_connect(connn, &addr, 7);
// create a new netbuf
buf1 = netbuf_new();

while(1)
{
test = xnetif.ip_addr.addr;
//check if IP address assigned
if (test !=0)
{
for( ;; )
{
if (xSemaphoreTake( s_xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT)==pdTRUE)
{
text[1] = ADC1ConvertedValue;
text[0] = ADC1ConvertedValue >> 8;

netbuf_ref(buf1, text, sizeof(text));
// послать Eth пакет
netconn_send(connn, buf1);
}
}
}
}
}

В этом случае
emacBLOCK_TIME_WAITING_FOR_INPUT определен как
#define emacBLOCK_TIME_WAITING_FOR_INPUT ( ( portTickType ) 100 )
(оставил так же как и для таска приема Eth пакетов)
Как лучше определить блокировку для этой задачи - задачи передачи Eth пакетов по прерыванию ADC1?
Поскольку прерывания от ADC будут приходить довольно часто (~ 10 мкс) не будет ли это тормозом для Ethernet приемника и вобще для всего приложения?

Сообщение отредактировал Acvarif - Feb 5 2012, 15:35
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
kan35
сообщение Feb 8 2012, 17:15
Сообщение #2


Знающий
****

Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594



JTAG/SWD что показывает? - доходит до части где взводится семафор?
Go to the top of the page
 
+Quote Post
Acvarif
сообщение Feb 9 2012, 06:55
Сообщение #3


Знающий
****

Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850



Цитата(kan35 @ Feb 8 2012, 21:15) *
JTAG/SWD что показывает? - доходит до части где взводится семафор?

Спасибо.
Запустил через SWD с точками останова и только тогда увидел ошибки.
Функция прерывание не взводила семафор. Вот (предварительно) верный вариант
CODE
void ADC_IRQHandler(void)
{

// Заполнение AdcBuff1
if(BuffIntCount == 0)
{
if(AdcIntCount%2 == 0)
AdcBuff1[AdcIntCount] = ADC1ConvertedValue;
else
AdcBuff1[AdcIntCount] = ADC1ConvertedValue >> 8;
// Инкремент счетчика байт
AdcIntCount++;
}
// Заполнение AdcBuff1
else if (BuffIntCount == 1)
{
if(AdcIntCount%2 == 0)
AdcBuff2[AdcIntCount] = ADC1ConvertedValue;
else
AdcBuff2[AdcIntCount] = ADC1ConvertedValue >> 8;
// Инкремент счетчика байт
AdcIntCount++;
}
// Если заполнился один из буферов
if(AdcIntCount == 100)
{
// Обнуление счетчика байт
AdcIntCount = 0;
// Смена признака буфера
if(BuffIntCount == 0) BuffIntCount = 1;
else BuffIntCount = 0;
// установка xHigherPriorityTaskWoken в pdFALSE
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

/* ADC1 received */
// if (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == SET)
// {
/* Give the semaphore to wakeup ADC task */
xSemaphoreGiveFromISR( d_xSemaphore, &xHigherPriorityTaskWoken );
// }

/* Switch tasks if necessary. */
if( xHigherPriorityTaskWoken != pdFALSE )
{
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}
}

/* Clear the interrupt flag. */
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);

}

Немного не понятно назначение этого
Код
    /* Switch tasks if necessary. */    
    if( xHigherPriorityTaskWoken != pdFALSE )
    {
      portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
    }

и в самой задачке неясно как лучше делать так (периодически разбуживать задачку)
Код
     if (xSemaphoreTake( d_xSemaphore, (250)) == pdPASS)
или так (не будить до прихода семафора)
Код
      if (xSemaphoreTake( d_xSemaphore, portMAX_DELAY )==pdTRUE)

Go to the top of the page
 
+Quote Post
LightElf
сообщение Feb 9 2012, 10:44
Сообщение #4


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

Группа: Участник
Сообщений: 180
Регистрация: 5-04-09
Пользователь №: 47 205



QUOTE
Немного не понятно назначение этого
CODE
    /* Switch tasks if necessary. */    
    if( xHigherPriorityTaskWoken != pdFALSE )
    {
      portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
    }

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

QUOTE
и в самой задачке неясно как лучше делать так (периодически разбуживать задачку)
CODE
     if (xSemaphoreTake( d_xSemaphore, (250)) == pdPASS)
или так (не будить до прихода семафора)
CODE
      if (xSemaphoreTake( d_xSemaphore, portMAX_DELAY )==pdTRUE)

В первом варианте задача просыпается, когда взведен семафор (и функция xSemaphoreTake возвращает pdTRUE) или когда пройдут 250 тиков (и возвращается pdFAIL). Во втором варианте задача просыпается только по появлению семафора.
Go to the top of the page
 
+Quote Post



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

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 03:53
Рейтинг@Mail.ru


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