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

 
 
> 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
Ответов
unkier
сообщение Feb 7 2012, 14:37
Сообщение #2


Участник
*

Группа: Участник
Сообщений: 24
Регистрация: 20-01-08
Пользователь №: 34 249



понял вроде правильно. количество семафоров (как впрочем и любых других ресурсов) определяется только возможностями конкретного железа и настройками оси.
Go to the top of the page
 
+Quote Post
kan35
сообщение Feb 8 2012, 04:42
Сообщение #3


Знающий
****

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



Цитата(unkier @ Feb 7 2012, 18:37) *
понял вроде правильно. количество семафоров (как впрочем и любых других ресурсов) определяется только возможностями конкретного железа и настройками оси.

Можно свести количество семафоров к тому - сколько позволяет ОЗУ.

По поводу "как сделать": я советую сделать работу ADC по DMA в циклическом режиме. И при заполнении буфера на 50% отправлять (из прерывания HT DMA) в queue первую половину буфера DMA, а при наполнении до 100% (из TC DMA) - вторую, затем опять первую половину и так далее. Размер пакета по умолчанию у TCP-ethernet - 1500 байт, по UDP - не знаю. Вот и прикидывайте, чтобы одна посылка примерно столько занимала.
При этом можно сделать queue на несколько буферов, чтобы избежать переполнения и потерь данных.
Go to the top of the page
 
+Quote Post
Acvarif
сообщение Feb 8 2012, 08:55
Сообщение #4


Знающий
****

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



Цитата(kan35 @ Feb 8 2012, 07:42) *
Можно свести количество семафоров к тому - сколько позволяет ОЗУ.

По поводу "как сделать": я советую сделать работу ADC по DMA в циклическом режиме. И при заполнении буфера на 50% отправлять (из прерывания HT DMA) в queue первую половину буфера DMA, а при наполнении до 100% (из TC DMA) - вторую, затем опять первую половину и так далее. Размер пакета по умолчанию у TCP-ethernet - 1500 байт, по UDP - не знаю. Вот и прикидывайте, чтобы одна посылка примерно столько занимала.
При этом можно сделать queue на несколько буферов, чтобы избежать переполнения и потерь данных.


Спасибо. Про DMA тоже была мысль. Если хоть как-то заработает на двух буферах попробую и с DMA.
Пока пытаюсь сделать сделать на двух буферах. Типа так
Прерывания по ADC1 (~ 7 мкс)
CODE

extern xSemaphoreHandle d_xSemaphore;

extern unsigned char AdcBuff1[100];
extern unsigned char AdcBuff2[100];
extern uint8_t AdcIntCount = 0;
extern uint8_t BuffIntCount = 0;
extern __IO uint16_t ADC1ConvertedValue;

void ADC_IRQHandler(void)
{
STM_EVAL_LEDToggle(LED2);

// Заполнение 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;

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 );
}

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

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

А это задачка которая должна получать семафор d_xSemaphore и выплевывать по UDP 100 байт данных из очередного буфера
CODE
#define UDPADC_THREAD_PRIO ( tskIDLE_PRIORITY + 4 )

static struct netconn *conn1;
static struct netbuf *buf1;
static struct ip_addr addr1;
//static unsigned short port;

unsigned char AdcBuff1[100];
unsigned char AdcBuff2[100];
extern uint8_t BuffIntCount;

xSemaphoreHandle d_xSemaphore;

/*-----------------------------------------------------------------------------------*/
static void udpadc_thread(void *arg)
{
LWIP_UNUSED_ARG(arg);

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

for( ;; )
{

// vTaskDelay(1000);
STM_EVAL_LEDToggle(LED2);

if (xSemaphoreTake( d_xSemaphore, ( portTickType ) 100)==pdTRUE)
// if (xSemaphoreTake( d_xSemaphore, portMAX_DELAY )==pdTRUE)
{
if(BuffIntCount == 1)
netbuf_ref(buf1, AdcBuff1, sizeof(AdcBuff1));
else
netbuf_ref(buf1, AdcBuff2, sizeof(AdcBuff2));
// послать Eth пакет
netconn_send(conn1, buf1);
netbuf_delete(buf1);
}
}
}

/*-----------------------------------------------------------------------------------*/
void udpadc_init(void)
{
sys_thread_new("udpadc_thread", udpadc_thread, NULL, DEFAULT_THREAD_STACKSIZE,UDPADC_THREAD_PRIO );
}


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



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

 


RSS Текстовая версия Сейчас: 25th July 2025 - 17:13
Рейтинг@Mail.ru


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