|
STM32F107RCT6 + KSZ8721 (ethernet) |
|
|
|
May 16 2018, 06:59
|
Участник
Группа: Участник
Сообщений: 25
Регистрация: 19-10-16
Пользователь №: 93 818
|
В указанном примере как раз таки 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 */ } Где-то что-то упустил или вообще все кардинально неправильно?))
Сообщение отредактировал remixx - May 16 2018, 07:03
|
|
|
|
|
May 17 2018, 02:35
|
Участник
Группа: Участник
Сообщений: 25
Регистрация: 19-10-16
Пользователь №: 93 818
|
Цитата(haker_fox @ May 16 2018, 07:52) Я бы рекомендовал не использовать ось. Я не знаю ваши строки, но вы можете закопаться и не успеть. ОС - это не просто многозадачность, это ещё и особый подход к проектированию ПО. Например, передача данных между процессами, обработка прерываний и т.п. Если у вас, конечно, есть опыт работы с операционными системами, тогда другой вопрос) на крайняк сделаю с "тупыми" задержками посмотрю еще сегодня ISR.
|
|
|
|
|
May 17 2018, 06:35
|
Гуру
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713
|
Цитата(remixx @ May 16 2018, 09:59) По советам jcxz решил, что надо добавлять в проект и RTOS. ... osDelay(1); ... osDelay(1); ... Где-то что-то упустил или вообще все кардинально неправильно?)) А что кардинально изменилось? Точно так же всё на задержках сделали. "Использовать ОС" - это не просто рассовать функции по задачам. Это в первую очередь означает, что работа должна производиться 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(); } }
|
|
|
|
|
May 22 2018, 16:42
|
Участник
Группа: Участник
Сообщений: 25
Регистрация: 19-10-16
Пользователь №: 93 818
|
В рбщем поговорил с преподавателем, решили т.к. времени мало организовать всю работу на таймерах/счетчиках. Дальше уже буду сам разбираться Но вот на деле уже 2 дня так и не могу пропинговать плату) В настройках LWIP пробую забивать как статический ip так и выставлять DHCP. Реакции 0. Варианта 2: либо я что-то неправильно подключил (схему приложил)
либо подозрение упало на PHYADR, в дш написано что по дефолту он 1, собственно 1 в настройках LWIP я и выставляю, но у меня вывод PHYAD0 вообще не подключен, а 1-4 включены т.к. это RXD. Получается у меня PHY адрес 30 или все таки дефолтный 1?
Сообщение отредактировал remixx - May 22 2018, 16:43
|
|
|
|
|
May 23 2018, 00:28
|
Познающий...
Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125
|
QUOTE (remixx @ May 23 2018, 00:42) Но вот на деле уже 2 дня так и не могу пропинговать плату) ИМХО, не тем путём вы идёте У вас может не работать канальный уровень, а вы ждёте пинга. Для начала - увас фиттер (ksz8721) ответила? Т.е. вы можете прочитать из её регистров её ID-номер? Если нет, или он не совпадает с даташитовским, то дальше вообще нет смысла ничего со стеком делать, кроме как решать проблему драйвера фиттера. Если id читатете. То следующий вопрос. У вас wireshark видит исходящие пакеты с платы? Любые. А плата принимает пакеты на канальном уровне? Когда заработает канальный уровень. вам нужно подключить стек. Как это делается, читатйте в документации. В том же lwip, я уже плохо помню, но надо поправить шаблон файла ethernetif.c под свои драйвера. После этого оно у меня сразу заработало.
--------------------
Выбор.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|