Перейти к содержанию
    

Обработка глобальных массивов в прерывании

STM32F7 (RAM: 512Кбайт). Среда CubeIDE.

Есть функция в которой принятые UDP пакеты складываются в кольцевые буферы.

Буферы - это глобальный трехмерный массив: udp_rxbuf[snum][128][256], где snum - количество сокетов.

Т.е. для каждого сокета можно сохранить до 128 пакетов по 256 байт.

При количестве сокетов до 3-х все работает корректно. Как только увеличиваю размер массива до работы с 4-мя сокетами (snum=4), все ломается.

Работа с сокетами происходит следующим образом:

Есть таймер. В его обработчике прерывания вызываются функции:

ethernetif_input(&gnetif);
sys_check_timeouts();

При получении udp пакета программа прыгает в в связанную с сокетом функцию  void udp_receive_handler(void *arg, struct udp_pcb *upcb, struct pbuf *p, const struct ip4_addr *addr, u16_t port), где полученный пакет укладывается в буффер.

Хотя массив буферов и большой - 160 кбайт, но линкер показывает, что памяти RAM еще вполне достаточно, больше половины свободно. Понимаю, что где то, что то нехватает, или что то на что то налазиет, но не знаю что.

Т.к. данный массив глобальный, он ведь никак не должен забивать стек, но что то происходит и все ломается.

Подскажите, что я делаю не так.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Похоже затыкается LWIP.

А именно в файле stm32f7xx_hal_eth.c условие
 

/* Check if segment is not owned by DMA */

if(((heth->RxDesc->Status & ETH_DMARXDESC_OWN) == (uint32_t)RESET))

никогда не срабатывает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В чем затык то?

Перестает МАС принимать пакеты?

Перестает вызываться udp_receive_handler?

Может приходит два пакета, а ваша программа воспринимает их как один? 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1. Не жирно ли вызывать ethernetif_input() в прерывании?:shok:
2. udp_rxbuf находится в одном физическом регионе ОЗУ?
3. Корректно ли обрабатываются буферы совместно с L1?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

42 minutes ago, Arlleex said:

1. Не жирно ли вызывать ethernetif_input() в прерывании?:shok:

А каким образом тогда обеспечить регулярную проверку входящих пакетов? В основном цикле с необходимой частотой этого не сделать.

Quote

2. udp_rxbuf находится в одном физическом регионе ОЗУ?
3. Корректно ли обрабатываются буферы совместно с L1?

Здесь я, к сожалению, не совсем понимаю о чем речь.

56 minutes ago, viakon said:

В чем затык то?

Перестает МАС принимать пакеты?

Перестает вызываться udp_receive_handler?

Может приходит два пакета, а ваша программа воспринимает их как один? 

 

Не заходит в udp_receive handler по причине того, что не проходит условие в строчке указанной выше.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 минут назад, Dec_NN сказал:

А каким образом тогда обеспечить регулярную проверку входящих пакетов? В основном цикле с необходимой частотой этого не сделать.

В прерывании (ETH_IRQHandler) по окончании DMA обмена с MAC выставить флажочек. В основном цикле проверять этот флаг и по появлении вызывать ethernetif_input

void ETH_IRQHandler(void)
{
    ETH_receive_pack = 1;
    // сброс  Eth DMA Rx IT pending флагов
    ETH_DMAClearITPendingBit(ETH_DMA_IT_R);
    ETH_DMAClearITPendingBit(ETH_DMA_IT_NIS);
}
в основном цикле так

        if(ETH_receive_pack)
        {
            ETH_receive_pack = 0;
            /* Handles all the received frames */
            while(ETH_GetRxPktSize() != 0)
            {
                LwIP_Pkt_Handle();
            }
        }

void LwIP_Pkt_Handle(void)
{
  /* Read a received packet from the Ethernet buffers and send it to the lwIP for handling */
  ethernetif_input(&netif);
}
 

Работает еще со времен до HAL.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

40 minutes ago, viakon said:

В прерывании (ETH_IRQHandler) по окончании DMA обмена с MAC выставить флажочек. В основном цикле проверять этот флаг и по появлении вызывать ethernetif_input

 

Я пробовал делать похожим образом, но дело в том, что в основном цикле есть куски надолго блокирующие выполнение кода. Например функция вывода статистики в консоль и т.д. и пока дело дойдет до проверки флага, часть пакетов просто теряется. Поэтому решил сделать прерывание по таймеру, чтобы гарантированно забирать пришедшие пакеты.

 

Upd: Сейчас попробовал убрать прерывание и делать вызов ethernetif_input() из основного цикла. Ничего не изменилось.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, Dec_NN сказал:

Я пробовал делать похожим образом, но дело в том, что в основном цикле есть куски надолго блокирующие выполнение кода.

Очевидно - давно пора было научиться работать под РТОС. Уже M7, а до сих пор ездиете на телеге супер-лупе....

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, jcxz said:

Очевидно - давно пора было научиться работать под РТОС. Уже M7, а до сих пор ездиете на телеге супер-лупе....

Это первый ARM с которым работаю, так уж досталось по наследству, и опыта работы с ними нет. RTOS обязательно буду осваивать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

45 минут назад, Dec_NN сказал:

Это первый ARM с которым работаю, так уж досталось по наследству, и опыта работы с ними нет. RTOS обязательно буду осваивать.

Под РТОС просто разносите в разные задачи код, имеющий "надолго блокирующие куски" и код работающий с потоком UDP-кадров. Задаче, работающей с UDP-кадрами, даёте бОльший приоритет.

И дело в шляпе.  :hi:

 

PS: Подозреваю, что тогда и не понадобятся такие дикие массивы по 128 UDP-кадров.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 часов назад, Dec_NN сказал:

А каким образом тогда обеспечить регулярную проверку входящих пакетов?
В основном цикле с необходимой частотой этого не сделать...

Как отметили уже выше, например, разрабатывая на базе RTOS. Она не кусается, ресурсы почти не потребляет.

Цитата

Здесь я, к сожалению, не совсем понимаю о чем речь...

Вы взяли МК с полноценным аппаратным L1-кэшем внутри. Вот и вопрос - драйвер в курсе, что он написан под STM32F7?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Отключил DCache. Все стало работать. Почему включение кеша данных вызывает мою проблему пока не понимаю. Буду разбираться.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Dec_NN said:

Отключил DCache. Все стало работать. Почему включение кеша данных вызывает мою проблему пока не понимаю. Буду разбираться.

Потому что ядро работает в Кэшем, а периферия с ОЗУ.

Вам надо либо отключить Кэшь не для всего ОЗУ, а для вашего буфера  udp_rxbuf[snum][128][256], либо вызывать SCB_InvalidateCash после записи данных в ваш буфер  udp_rxbuf[snum][128][256].

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Dec_NN сказал:

Почему включение кеша данных вызывает мою проблему пока не понимаю. Буду разбираться

Гляньте сюда. Там собраны основные проблемы с драйверами эзернета из куба.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...