Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F107RCT6 + KSZ8721 (ethernet)
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
remixx
Пытаюсь запустить эзернет на МК. В качестве внешнего PHY использую KSZ8721. Задача следующая: сформировать пакет определенной структуры (т.е. условно 20-28 байт параметр1, 29-36 байт параметр2, 37-50 параметр3 и т.д.), записать в эти параметры значения с АЦП и передать определенное количество пакетов в секунду.
Подключение MII, режим full duplex.
Собственно в связи с вышеизложенным следующие вопросы:
1. Каким образом можно сформировать произвольную структуру пакета?
2. Будет ли достаточно для данных целей обычной инициализации эзернета в кубе и передачи пакетов функцией HAL_ETH_TransmitFrame()? Код функции представлен ниже.
Код
/**
  * @brief  Sends an Ethernet frame.
  * @param  heth: pointer to a ETH_HandleTypeDef structure that contains
  *         the configuration information for ETHERNET module
  * @param  FrameLength: Amount of data to be sent
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_ETH_TransmitFrame(ETH_HandleTypeDef *heth, uint32_t FrameLength)
{
  uint32_t bufcount = 0U, size = 0U, i = 0U;
  
  /* Process Locked */
  __HAL_LOCK(heth);
  
  /* Set the ETH peripheral state to BUSY */
  heth->State = HAL_ETH_STATE_BUSY;
  
  if (FrameLength == 0U)
  {
    /* Set ETH HAL state to READY */
    heth->State = HAL_ETH_STATE_READY;
    
    /* Process Unlocked */
    __HAL_UNLOCK(heth);
    
    return  HAL_ERROR;                                    
  }  
  
  /* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */
  if(((heth->TxDesc)->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET)
  {  
    /* OWN bit set */
    heth->State = HAL_ETH_STATE_BUSY_TX;
    
    /* Process Unlocked */
    __HAL_UNLOCK(heth);
    
    return HAL_ERROR;
  }
  
  /* Get the number of needed Tx buffers for the current frame */
  if (FrameLength > ETH_TX_BUF_SIZE)
  {
    bufcount = FrameLength/ETH_TX_BUF_SIZE;
    if (FrameLength % ETH_TX_BUF_SIZE)
    {
      bufcount++;
    }
  }
  else
  {  
    bufcount = 1U;
  }
  if (bufcount == 1U)
  {
    /* Set LAST and FIRST segment */
    heth->TxDesc->Status |=ETH_DMATXDESC_FS|ETH_DMATXDESC_LS;
    /* Set frame size */
    heth->TxDesc->ControlBufferSize = (FrameLength & ETH_DMATXDESC_TBS1);
    /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
    heth->TxDesc->Status |= ETH_DMATXDESC_OWN;
    /* Point to next descriptor */
    heth->TxDesc= (ETH_DMADescTypeDef *)(heth->TxDesc->Buffer2NextDescAddr);
  }
  else
  {
    for (i=0U; i< bufcount; i++)
    {
      /* Clear FIRST and LAST segment bits */
      heth->TxDesc->Status &= ~(ETH_DMATXDESC_FS | ETH_DMATXDESC_LS);
      
      if (i == 0U)
      {
        /* Setting the first segment bit */
        heth->TxDesc->Status |= ETH_DMATXDESC_FS;  
      }
      
      /* Program size */
      heth->TxDesc->ControlBufferSize = (ETH_TX_BUF_SIZE & ETH_DMATXDESC_TBS1);
      
      if (i == (bufcount-1U))
      {
        /* Setting the last segment bit */
        heth->TxDesc->Status |= ETH_DMATXDESC_LS;
        size = FrameLength - (bufcount-1U)*ETH_TX_BUF_SIZE;
        heth->TxDesc->ControlBufferSize = (size & ETH_DMATXDESC_TBS1);
      }
      
      /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
      heth->TxDesc->Status |= ETH_DMATXDESC_OWN;
      /* point to next descriptor */
      heth->TxDesc = (ETH_DMADescTypeDef *)(heth->TxDesc->Buffer2NextDescAddr);
    }
  }
  
  /* When Tx Buffer unavailable flag is set: clear it and resume transmission */
  if (((heth->Instance)->DMASR & ETH_DMASR_TBUS) != (uint32_t)RESET)
  {
    /* Clear TBUS ETHERNET DMA flag */
    (heth->Instance)->DMASR = ETH_DMASR_TBUS;
    /* Resume DMA transmission*/
    (heth->Instance)->DMATPDR = 0U;
  }
  
  /* Set ETH HAL State to Ready */
  heth->State = HAL_ETH_STATE_READY;
  
  /* Process Unlocked */
  __HAL_UNLOCK(heth);
  
  /* Return function status */
  return HAL_OK;
}
haker_fox
Я не знаю куб, но вопрос: вы хотите данные гнать на канальном уровне? Т.е. TCP/IP или UDP вам не нужен?

QUOTE (remixx @ May 11 2018, 12:24) *
2. Будет ли достаточно для данных целей обычной инициализации эзернета в кубе и передачи пакетов функцией HAL_ETH_TransmitFrame()? Код функции представлен ниже.

Это низкоуровневая функция передачи ETHERNET-фрейма через среду (витую пару в вашем случае). Конечно, можно гнать данные на этом уровне, но как вы будете доставлять их адресату? Или как кто-то будет запрашивать их у вашей железки? Ведь адресация в таком случае будет возможно только по mac-адресу. А в локальных сетях принято использовать что-то повыше уровнем, например IPv4. Значит вам нужен TCP/IP стек, пусть и не полный. Всё зависит от ваших требований? Чего вы хотите? Что за прибор, куда будет подключаться, кто будет обмениваться с ним данными?

Рекомендую познакомиться хотя бы бегло с 7-уровневой моделью OSI. Затем почитать про TCP/IP стеки. Я использовал lwip. Прикручиватеся не совсем просто, если нет опыта. У меня ушло недели полторы на адаптацию драйвера MAC+PHY, и портирование стека на свою платформу (LPC4337 + внешний фиттер).

P.S. Судя по вашим постам на форуме, вы методично и последовательно ваяете что-то измерительное с выходом в сеть)))

P.S.S. Логический анализатор вам и здесь может понадобиться. У вас kszшка-то хоть ответила по MDC?
remixx
Цитата(haker_fox @ May 11 2018, 05:38) *
Я не знаю куб, но вопрос: вы хотите данные гнать на канальном уровне? Т.е. TCP/IP или UDP вам не нужен?


Это низкоуровневая функция передачи ETHERNET-фрейма через среду (витую пару в вашем случае). Конечно, можно гнать данные на этом уровне, но как вы будете доставлять их адресату? Или как кто-то будет запрашивать их у вашей железки? Ведь адресация в таком случае будет возможно только по mac-адресу. А в локальных сетях принято использовать что-то повыше уровнем, например IPv4. Значит вам нужен TCP/IP стек, пусть и не полный. Всё зависит от ваших требований? Чего вы хотите? Что за прибор, куда будет подключаться, кто будет обмениваться с ним данными?

Рекомендую познакомиться хотя бы бегло с 7-уровневой моделью OSI. Затем почитать про TCP/IP стеки. Я использовал lwip. Прикручиватеся не совсем просто, если нет опыта. У меня ушло недели полторы на адаптацию драйвера MAC+PHY, и портирование стека на свою платформу (LPC4337 + внешний фиттер).

P.S. Судя по вашим постам на форуме, вы методично и последовательно ваяете что-то измерительное с выходом в сеть)))

P.S.S. Логический анализатор вам и здесь может понадобиться. У вас kszшка-то хоть ответила по MDC?

Функционал устроства верный biggrin.gif. Это мой дипломный проект, по сути представляет из себя некий измерительный блок, который оцифровывает показания датчика температуры и передает их по ethernet.
Вообще задача сформулирована следующим образом: необходимо передать 1000 ethernet пакетов с определенной структурой в секунду. В каждом пакете должны содержаться: значение измеренной температуры, время, дата и еще несколько параметров. Сам блок подключается к компьютеру, к нему никаких обращений не требуется, т.е. она просто гонит данные и все.

Читаю про TCP/IP стек, но теория без практики воспринимается сложно. Пытаюсь найти примеры с реализацией lwip.
Пробовал пинговать плату при обычной инициализации ethernet (без lwip), результата нет.
haker_fox
QUOTE (remixx @ May 14 2018, 11:36) *
еобходимо передать 1000 ethernet пакетов

Здесь неоднозначность терминов: ethernet-пакте, это фрейм канального уровня. На этом уровне нет ip-адреса. Только mac-адрес, служебные данные, контрольная сумма и пакет полезных данных. Чтобы это всё на компьютере получить и использовать, нужна специальная самописаня софтина.
QUOTE (remixx @ May 14 2018, 11:36) *
Читаю про TCP/IP стек, но теория без практики воспринимается сложно. Пытаюсь найти примеры с реализацией lwip.

Их много в сети. Вопрос, какой вам подойдёт.
QUOTE (remixx @ May 14 2018, 11:36) *
Пробовал пинговать плату при обычной инициализации ethernet (без lwip), результата нет.

И никогда не будет. На пинг отвечает кусочек стека, а у вас его нет. "Чистый" ethernet ни на что отвечать не умеет. по-сути это uart (ооочень грубо, но по смыслу верно). Только этот uart передаёт данные не по-байтно, а минимум пакетом (сколько точно не помню). И длина этого пакета варьируется от минимума до максимума. Вот внутрь уже можно положить нечто похожее на протокол, например tcp/ip.


QUOTE (remixx @ May 14 2018, 11:36) *
Это мой дипломный проект

Вообще задача для дипломного проекта вполне решаема, но времени нужно этак полгода. И это при том, что вам читали (а вы не пропускали) соответствующие дисциплины. Ну, а так... до года может уйти, в зависимости от подготовки и желания.
XVR
Если вам нужно просто передать пакеты, то можно сделать отправку в виде UDP, никакого стека (даже lwip) для этого не понадобится.

Но пинговаться ваш прибор при этом не будет sad.gif
jcxz
Цитата(remixx @ May 14 2018, 06:36) *
Вообще задача сформулирована следующим образом: необходимо передать 1000 ethernet пакетов с определенной структурой в секунду.

Ну если препод хотел сказать именно то, что написал, то Вам остаётся только посочувствовать. laughing.gif
Уже знаете как будете из под винды добираться до уровня ETHERNET-фреймов? biggrin.gif Это будет посложнее, чем полное изучение TCP-стека.
Совет: срочно бежать к преподу и переформулировать задачу на "передачу через UDP" или через TCP-сокет. А ещё лучше: "через любой сетевой протокол работающий поверх ETHERNET".
Даже если препод не понимает разницы между ETHERNET-кадрами и TCP/UDP-кадрами, то достаточно в приёмной комиссии оказаться одному человеку, кто понимает и можете смело ставить крест на защите. Если бы я был в комиссии, а Вы с таким ТЗ притащили проект сделанный на TCP/UDP, то я бы завалил. biggrin.gif

Цитата(remixx @ May 11 2018, 07:24) *
2. Будет ли достаточно для данных целей обычной инициализации эзернета в кубе и передачи пакетов функцией HAL_ETH_TransmitFrame()? Код функции представлен ниже.

Думаю что не будет. Ибо как докажете, что что-то вообще передаётся?
А значит: на стороне приёмной стороны нужно писать что-то, что будет принимать эти пакеты и отображать инфу из них.

Цитата(remixx @ May 14 2018, 06:36) *
Сам блок подключается к компьютеру, к нему никаких обращений не требуется, т.е. она просто гонит данные и все.

И как доказать, что компьютер эти данные принимает?

Цитата(XVR @ May 14 2018, 14:51) *
никакого стека (даже lwip) для этого не понадобится.

Да ладно!? А какой МК умеет передавать UDP-кадры самостоятельно, без TCP/IP-стека?
iosifk
Цитата(remixx @ May 14 2018, 06:36) *
Функционал устроства верный biggrin.gif. Это мой дипломный проект, по сути представляет из себя некий измерительный блок, который оцифровывает показания датчика температуры и передает их по ethernet.
Вообще задача сформулирована следующим образом: необходимо передать 1000 ethernet пакетов с определенной структурой в секунду. В каждом пакете должны содержаться: значение измеренной температуры, время, дата и еще несколько параметров. Сам блок подключается к компьютеру, к нему никаких обращений не требуется, т.е. она просто гонит данные и все.

Для справки. Термина "Функционал" в русском техническом языке нет вообще...
И вот, чисто по жизни, есть вопрос. "Температура" - она что так быстро меняется? Это что температура плазмы или газовой струи в ракетном сопле? Какова масса объекта, у которого измеряют температуру?
А сам датчик, какая у него постоянная времени по температуре? Ну пусть десятая доля секунды... Тогда у Вас что, имеются тысячи датчиков, если в задании "1000 ethernet пакетов в секунду"... Или же это сказано так, для балды? Но ведь сказано, что "блок" находится "рядом", т.е не далее 300 метров, потому как не факт, что такие кадры пройдут по сетевому оборудованию...
Вот...
haker_fox
QUOTE (jcxz @ May 14 2018, 22:33) *
Ну если препод хотел сказать именно то, что написал, то Вам остаётся только посочувствовать. laughing.gif

Да и так уже понятно, что задание выдано от балды rolleyes.gif
Интересно, а автору топика это действительно интересно и нужно, или это всего лишь желание только защитить диплом?
remixx
Мне действительно интересно этим заниматься, в будущем планирую работать в сфере, где требуется представление о программировании хотя бы на таком уровне. Опыта без практики не получить.
Задача сама по себе не связана с реальным применением, просто некий теоретический вариант, для реализации которого требуется работа с основной перефирией МК, что и является главной целью в данной работе.
Пары не прогуливал biggrin.gif , большинство курсов в основном были связаны с элементной базой, принципом работы ИМС, их проектированием и т.п.
На единственном курсе, связанным с программированием, мы по-этапно выводили символ нажатой кнопки на ЖКИ в течение 3-х лаб, писалось все на ассемблере. Поэтому "уровень" соответствующий.
Вообще специальность называется микроэлектроника, поэтому прямой связи с программированием и уж тем более работой с сетями нету.
Собственно вот с таким "багажом" я и подошел к работе над вышеупомянутой задачей), поэтому возникает куча вопросов на каждом шагу.

Ну ладно, это небольшое лирическое отступление biggrin.gif

По теме:
под пакетом преподаватель имел ввиду фрейм (IEEE 802.3), структуру представил ниже.

Нажмите для просмотра прикрепленного файла

То есть насколько я понял, преамбула, header mac, длина и LLC формируются автоматически при отправке, с указанными значениями при инициализации, а в блок данных (data unit), необходимо завести требуемые значения измерений. Думаю это удобно сделать через struct, пример:

Код
struct Data {
int32_t temperature;
uint8_t time;
uint8_t date;
}

Перед каждой отправкой приравниваю переменные к полученным значениям измерений и отправляю их.
После чего некая задержка, ну из первого что пришло в голову 1 сек / 1000 = 1 мс, соответственно её и беру.
И снова измерение, формирование фрейма, отправка. И так 1000 раз.

По вашим советам стал искать информацию, как осуществить передачу, используя lwip.
Наткнулся вот на такой пример. С помощью куба он инициализирует ethernet и подключает lwip. В коде добавляет функции для udp и отправляет тестовый фрейм.
Вроде бы это то что нужно)

Кстати для анализа полученных пакетов использую wireshark.
jcxz
Цитата(remixx @ May 15 2018, 08:58) *
Перед каждой отправкой приравниваю переменные к полученным значениям измерений и отправляю их.
После чего некая задержка, ну из первого что пришло в голову 1 сек / 1000 = 1 мс, соответственно её и беру.

Тупых "задержек" быть не должно. Не знаю как там работает куб или lwip (не пользовал никогда), но в любом случае формировать следующий кадр для отправки нужно только после получения уведомления о завершении отправки предыдущего кадра.
Например простейший алгоритм: завести цикл (прерывание) работающий с частотой 1 кГц, при каждом проходе цикла проверять стоит ли флаг завершения отправки предыдущего ETHERNET-кадра и только если стоит - формировать следующий кадр.
Ещё лучше добавить FIFO кадров на несколько позиций и писать в него если в FIFO есть место (и стартовать передачу, если предыдущее завершение отправки произошло при пустом FIFO). В обработчике события "завершения отправки кадра" ETHERNET-драйвера отправлять следующий кадр из FIFO ели там есть хотя-бы один кадр.

Цитата(remixx @ May 15 2018, 08:58) *
И снова измерение, формирование фрейма, отправка. И так 1000 раз.

Измерение должно идти независимо от отправки. В своей задаче RTOS или ISR. Измерение и передача в сеть должны быть связаны через механизм FIFO. Иначе не получите ожидаемой частоты (вообще никакой стабильной частоты преобразования не получите - она будет плавать).

Цитата(remixx @ May 15 2018, 08:58) *
По вашим советам стал искать информацию, как осуществить передачу, используя lwip.
С помощью куба он подключает lwip. В коде добавляет функции для udp и отправляет тестовый фрейм.

Определитесь уже что Вам всё-таки нужно - описанные выше Вами ETHERNET-кадры или всё-же UDP?

Цитата(remixx @ May 15 2018, 08:58) *
Кстати для анализа полученных пакетов использую wireshark.

Если на защите достаточно будет показать приём в шарке, то наверное можно и так.
haker_fox
QUOTE (remixx @ May 15 2018, 13:58) *
Мне действительно интересно этим заниматься, в будущем планирую работать в сфере, где требуется представление о программировании хотя бы на таком уровне. Опыта без практики не получить.

ОК, это радует! rolleyes.gif
QUOTE (remixx @ May 15 2018, 13:58) *
По теме:
под пакетом преподаватель имел ввиду фрейм (IEEE 802.3), структуру представил ниже.

Стандартная картинка из документа rolleyes.gif Опять таки здесь можно двусмысленно толковать. В data payload можно положить как произвольные данные, тогда прнимающая сторона должна будет уметь их принять и расшифровать. На этом уровне у вас не будет ip-адреса, следовательно пакеты будут находить адресата только по mac-адресу. Следовательно, что с ними сделает более-менее умный маршрутизатор - я не знаю, тут у меня опыта нет. Также в data payload можно положить данные, которые сгенерирует любой tcp/ip-стек. А вот уже в данные udp или tcp можно положить снова ваши произвольные данные. Но при этом пакеты будут "настоящие". Смогут ходить к адресату по ip-адресу. Более того, вы можете обращаться к железке более-менее стандартными способами (web, ftp, tftp, telnet) и получать свои данные, например, браузером.
QUOTE (remixx @ May 15 2018, 13:58) *
Вообще специальность называется микроэлектроника, поэтому прямой связи с программированием и уж тем более работой с сетями нету.

Ну тогда ваш диплом не по теме. Даже мне с некоторым опытом в данной области понадобилось бы около месяца на выполнения этой работы (я имею в виду ацп, сеть, отладка, тестирование образца). Хотя тут всё индивидуально, уверен, кто-то и за день сделает rolleyes.gif
QUOTE (remixx @ May 15 2018, 13:58) *
И снова измерение, формирование фрейма, отправка. И так 1000 раз.

Тут надо смотреть как работает MAC-модуь микроконтроллера. Это всё-таки не uart в прямом смысле. И по завершению отправки пакета он должен генерировать прерывание, либо выставлять флаг в аппаратном регистре. К сожалению, STM для работы с сетью не использовал, ничего не подскажу. Но поищите в сети проекты связки stm + lwip. Наверно можно как-то вытащить исходники драйверов mac, и подкорректировать их под себя.
QUOTE (remixx @ May 15 2018, 13:58) *
Кстати для анализа полученных пакетов использую wireshark.

Крайне полезная программа! Без неё никак. У вас что-нить приходит? Опять же вайршарк - хорошо, но чем будете данные в готовой железке смотреть?
XVR
Цитата(jcxz @ May 14 2018, 17:33) *
Да ладно!? А какой МК умеет передавать UDP-кадры самостоятельно, без TCP/IP-стека?
Любой, у которого есть MAC. Минимальный UDP протокол простой как бревно - формируем образ Eth фрейма с UDP Payload в памяти (в виде структуры) и отправляем это в качестве Eth пакета наружу. Это всё. lwip для этого не нужен.

Если нужна полная поддержка IP стека (включая ICMP и ARP, а так же что угодно на приём), то тут уже как минимум lwip потребуется.

mcheb
Посмотрите здесь https://github.com/ntruchsess/arduino_uip и в гугле есть описание фреймов. Ключевые слова Arduino & ENC28J60
jcxz
Цитата(XVR @ May 15 2018, 11:24) *
Любой, у которого есть MAC. Минимальный UDP протокол простой как бревно - формируем образ Eth фрейма с UDP Payload в памяти (в виде структуры) и отправляем это в качестве Eth пакета наружу. Это всё. lwip для этого не нужен.

Чтобы засрать широковещательными UDP всю сеть?

Цитата(XVR @ May 15 2018, 11:24) *
Если нужна полная поддержка IP стека (включая ICMP и ARP, а так же что угодно на приём), то тут уже как минимум lwip потребуется.

Как минимум lwip избыточен. Есть гораздо более лёгкие стеки. Даже в примерах IAR-а имелись.

Цитата(haker_fox @ May 15 2018, 09:42) *
Но поищите в сети проекты связки stm + lwip. Наверно можно как-то вытащить исходники драйверов mac, и подкорректировать их под себя.

Лучше взять примеры из IAR для работы с Ethernet.
XVR
Цитата(jcxz @ May 15 2018, 12:09) *
Чтобы засрать широковещательными UDP всю сеть?
А кто заставляет посылать широковещательные? Можно MAC адрес приёмника забить прямо в пакет. Для сдачи задания вполне достаточно.

jcxz
Цитата(XVR @ May 15 2018, 14:46) *
А кто заставляет посылать широковещательные? Можно MAC адрес приёмника забить прямо в пакет. Для сдачи задания вполне достаточно.

Вы предлагали UDP. А там кроме MAC вообще-то есть и IP-адреса если что. Какие туда адреса забивать прикажете если ARP не реализован?
haker_fox
QUOTE (jcxz @ May 15 2018, 20:56) *
Вы предлагали UDP. А там кроме MAC вообще-то есть и IP-адреса если что. Какие туда адреса забивать прикажете если ARP не реализован?

Мне кажется можно статично вбить ip-адреса железки (задать самому любой свободный), и адрес приёмника. Нужно будет считать контрольные суммы. Но я не уверен за результат, т.к. никогда так не делал, и не стал бы советовать кому-либо делать. Хотя для диплома - пойдёт. Но ещё раз повторюсь: диплом довольно сложен. Преподаватель обязан консультировать студента. Но я думаю, что преподаватель не очень компетентен.
jcxz
Цитата(haker_fox @ May 15 2018, 17:23) *
Преподаватель обязан консультировать студента. Но я думаю, что преподаватель не очень компетентен.

Да судя по формулировке задачи я бы сказал, что преподаватель вообще не копенгаген laughing.gif
Alex11
Цитата
Мне кажется можно статично вбить ip-адреса железки (задать самому любой свободный), и адрес приёмника.

Работать будет, если в одной подсети. Проверено.
haker_fox
QUOTE (Alex11 @ May 16 2018, 00:26) *
Работать будет, если в одной подсети. Проверено.

Ну в общем для диплома действительно пойдёт. Но для реального проекта - только с большим количеством ограничений)))
XVR
Цитата(jcxz @ May 15 2018, 15:56) *
Вы предлагали UDP. А там кроме MAC вообще-то есть и IP-адреса если что. Какие туда адреса забивать прикажете если ARP не реализован?

Так же, как и MAC - руками (статически). И даже работать будет. rolleyes.gif
remixx
В указанном примере как раз таки MAC и ip адреса вбиваются вручную, все хидеры lwip проставляет автоматически, все что остается это засунуть данные в payload.
По советам jcxz решил, что надо добавлять в проект и RTOS.
Из той информации, которую изучил на данный момент, имею следующее представление:
1. Создаю 2 задачи. В первой провожу инициализацию АЦП и в бесконечном цикле отправляю запрос на единичное преобразование, записывая результат в соответствующий элемент структуры и ставя её в очередь.
Примерный код:
Код
// Добавляю глобальную переменную для очереди //
osMailQId strout_Queue

// Указываю размер очереди //
#define MAIL_SIZE (uint32_t) 1 // Насколько я понимаю, чтобы гарантированно передать по ethernet значение преобразования, в очереди должен быть всего 1 элемент, соответственно если она заполнена, то первая задача находится в блокированном состоянии

// Задаю структуру с данными //
typedef data_t {
   int32_t temperature;
   uint8_t time;
   uint8_t date;
} data;

// Создаю задачу RTOS //
osThreadDef(ADC, StartTaskADC, osPriorityNormal, 0, 128);
ADCHandle = osThreadCreate(osThread(ADC), NULL);

// Создаю очередь //
osMailQDef(stroutqueue, MAIL_SIZE, data;
strout_Queue = osMailCreate(osMailQ(stroutqueue), NULL);

// Создаю функцию первой задачи //
void StartTaskADC(void const * argument)
{
  /* USER CODE BEGIN StartTaskADC */
  struct_out *qstruct; // добавляю переменную типа передаваемой в очереди структуры
  ADC_Init; // выполняю инициализацию АЦП (отправляю набор команд по SPI, использую функцию HAL_SPI_Transmit, можно ли взять её или для таких применений нужно с DMA каким-нибудь?)
  /* Infinite loop */
  for(;;)
  {
    qstruct = osMailAlloc(strout_Queue, osWaitForever); // выделяю память под очередь
    qstruct->temperature = ADC_ReadValue; // записываю в элемент структуры temperature полученное значение из АЦП (посылаю команду единичного преобразования через HAL_SPI_Transmit, аналогичный вопрос)
    qstruct->time = 1 // записываю в элемент структуры time рандомное значение (пока не важно)
    qstruct->date = 2 // записываю в элемент структуры date рандомное значение (пока не важно)
    osMailPut(strout_Queue, qstruct); // отправляю структуру в очередь
    osDelay(1);
  }
  /* USER CODE END StartTaskADC */
}


2. Создаю вторую задачу, которая будет инициализировать UDP, получать измеренное значение температуры из очереди и отправлять его.
Код
// Создаю глобальные переменные структур, требующихся для передачи по ethernet //
extern struct netif gnetif;
static struct udp_pcb *udp_Pcb1_p;

// Создаю задачу RTOS //
osThreadDef(ETH, StartTaskETH, osPriorityNormal, 0, 128);
ETHHandle = osThreadCreate(osThread(ETH), NULL);

// Создаю функцию второй задачи //
void StartTaskETH(void const * argument)
{
  /* USER CODE BEGIN StartTaskETH */
  osEvent event; // добавляю переменную типа структуры состояния очереди
  struct_out *qstruct; // добавляю переменную типа передаваемой в очереди структуры
  UDP_Init; // выполняю инициализацию UDP (в ней создается новое подключение UDP (udp_new), вручную записывается mac и ip адрес компа, биндится соединение (udp_bind) и проверяется на наличие ошибок)
  /* Infinite loop */
  for(;;)
  {
    static const char packet[]; // создаю переменную для данных, которые буду класть в payload
    event = osMailGet(strout_Queue, osWaitForever); // забираю данные из очереди
    if (event.status == osEventMail) // проверяю состояние очереди
    qstruct = event.value.p; // присваиваю переменной типа структуры очереди указатель на элемент очереди
    packet[] = qstruct->temperature, qstruct->time, qstruct->date; // записываю полученные данные в переменную для payload
    SendPacket; // вызываю функцию отправки udp (здесь указывается ip адрес клиента, создается буффер для передачи по eth, в который заносим вышеуказанный packet[], заносим все это в payload и отправляем (udp_sendto)
    ethernetif_input(&gnetif); // вписываю стандартный код для обеспечения постоянной работы стека
    sys_check_timeouts; // продолжение... (говорят, что эти 2 строки можно заменить MX_LWIP_Process() тогда и extern struct netif gnetif не нужно, но пока попробую запуститься так)
    osDelay(1);
  }
  /* USER CODE END StartTaskETH */
}


Где-то что-то упустил или вообще все кардинально неправильно?))
haker_fox
Я бы рекомендовал не использовать ось. Я не знаю ваши строки, но вы можете закопаться и не успеть. ОС - это не просто многозадачность, это ещё и особый подход к проектированию ПО. Например, передача данных между процессами, обработка прерываний и т.п. Если у вас, конечно, есть опыт работы с операционными системами, тогда другой вопрос)
remixx
Цитата(haker_fox @ May 16 2018, 07:52) *
Я бы рекомендовал не использовать ось. Я не знаю ваши строки, но вы можете закопаться и не успеть. ОС - это не просто многозадачность, это ещё и особый подход к проектированию ПО. Например, передача данных между процессами, обработка прерываний и т.п. Если у вас, конечно, есть опыт работы с операционными системами, тогда другой вопрос)

на крайняк сделаю с "тупыми" задержками biggrin.gif
посмотрю еще сегодня ISR.
jcxz
Цитата(remixx @ May 16 2018, 09:59) *
По советам jcxz решил, что надо добавлять в проект и RTOS.
...
osDelay(1);
...
osDelay(1);
...
Где-то что-то упустил или вообще все кардинально неправильно?))

А что кардинально изменилось? Точно так же всё на задержках сделали. laughing.gif
"Использовать ОС" - это не просто рассовать функции по задачам. Это в первую очередь означает, что работа должна производиться event-driven.
Т.е. - Ваши задачи должны не всё время долбить что-то (и зачем тогда вообще многозадачность?), а должны обрабатывать события.
Т.е. - в задаче АЦП дали старт преобразования и после этого задача должна ждать завершения преобразования, после чего считать данные, обработать их, и запустить следующее преобразование. Ждать она должна, ожидая готовности какого-либо элемента синхронизации ОС (мэйлбокса, семафора и т.п.). Этот мэйлбокс переводиться в сигнальное состояние может например из ISR завершения преобразования АЦП (а лучше конечно из ISR завершения DMA-пересылки блока данных АЦП->ОЗУ).
То же самое и с задачей отправки данных в ETHERNET.

Если у Вас задачи всё время что-то долбят, то тут никакой многозадачности нет, одна фикция, пыль в глаза.
Наберите в гугле "event-driven programming".
В упрощённом виде работа с АЦП должна выглядеть так:
CODE
void AdcReadyIsr()
{
AdcConfirm();
OSMboxPost(mboxAdcReady);
}
void AdcTask()
{
AdcInit();
ClearAndEnableIrqAdcReady();
while (1) {
AdcStart();
OSMboxPend(mboxAdcReady);
DataQueueWrite(AdcRead());
PingEthernetSendTask();
}
}

Это если время преобразования АЦП == необходимому периоду измерений (или можно так сконфигурить АЦП).
Если нет, то чуть сложнее (с использованием таймера):
CODE
void AdcReadyIsr()
{
AdcConfirm();
OSMboxPost(mboxAdcReady);
}
void TimerPeriodicIsr()
{
TimerConfirm();
OSMboxPost(mboxTimerPeriodic);
}
void AdcTask()
{
AdcInit();
TimerInit(DESIRED_FREQUENCY);
ClearAndEnableIrqAdcReady();
ClearAndEnableIrqTimerPeriodic();
while (1) {
OSMboxPend(mboxTimerPeriodic);
AdcStart();
OSMboxPend(mboxAdcReady);
DataQueueWrite(AdcRead());
PingEthernetSendTask();
}
}
remixx
В рбщем поговорил с преподавателем, решили т.к. времени мало организовать всю работу на таймерах/счетчиках. Дальше уже буду сам разбираться laughing.gif
Но вот на деле уже 2 дня так и не могу пропинговать плату)
В настройках LWIP пробую забивать как статический ip так и выставлять DHCP. Реакции 0.
Варианта 2: либо я что-то неправильно подключил (схему приложил)
Нажмите для просмотра прикрепленного файла
либо подозрение упало на PHYADR, в дш написано что по дефолту он 1, собственно 1 в настройках LWIP я и выставляю, но у меня вывод PHYAD0 вообще не подключен, а 1-4 включены т.к. это RXD. Получается у меня PHY адрес 30 или все таки дефолтный 1?
Нажмите для просмотра прикрепленного файла
haker_fox
QUOTE (remixx @ May 23 2018, 00:42) *
Но вот на деле уже 2 дня так и не могу пропинговать плату)

ИМХО, не тем путём вы идёте rolleyes.gif У вас может не работать канальный уровень, а вы ждёте пинга. Для начала - увас фиттер (ksz8721) ответила? Т.е. вы можете прочитать из её регистров её ID-номер? Если нет, или он не совпадает с даташитовским, то дальше вообще нет смысла ничего со стеком делать, кроме как решать проблему драйвера фиттера. Если id читатете. То следующий вопрос. У вас wireshark видит исходящие пакеты с платы? Любые. А плата принимает пакеты на канальном уровне? Когда заработает канальный уровень. вам нужно подключить стек. Как это делается, читатйте в документации. В том же lwip, я уже плохо помню, но надо поправить шаблон файла ethernetif.c под свои драйвера. После этого оно у меня сразу заработало.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.