Jump to content

    

jeka

Свой
  • Content Count

    466
  • Joined

  • Last visited

Community Reputation

0 Обычный

About jeka

  • Rank
    Administrator
  • Birthday 06/14/1980

Контакты

  • ICQ
    Array

Recent Profile Visitors

5933 profile views
  1. STM32H743 flash bank swap

    А трассировка момента стирания не смотрели на какой инструкции валится (если по одной ассемблерной инструкции трассировать)? И что в дампе флеш памяти после ресета? Возможно, стираете текущий исполняемый код. Не уверен что меняются местами регистры между собой при переключении банков.
  2. Еще одна казалось бы мелочь. Вы сбрасываете источник прерывания так: TIM17->SR &= ~TIM_SR_CCxIF; Эта операция не атомарна и преобразовывается компилятором в 3 команды: чтение регистра, сброс бита, запись в регистр. Теперь подумайте, что произойдет если между чтением и записью таймер установит флаг какого-то другого события? Статус считан без установленного флага события, потом таймер выставил событие, и при записи флаг события сбросится. Чтобы этого не было сбрасывать события надо так: TIM17->SR = ~TIM_SR_CCxIF; Согласно даташиту, все единичные биты игнорируются, а там где ноль - будет сброс.
  3. stm32h743, hal+lwip. Очень редко заклинивает передачу при интенсивном обмене. При заклиненной передаче вижу ситуацию: не очищен бит own в дескрипторе, освобождение которого ожидает драйвер (всего 4 дескриптора, остальные 3 дескриптора при этом очищены). Если ручками бит own очищаю, передачу расклинивает. К сожалению не посмотрел какой дескриптор ожидает периферия, жду следующего появления глюка. Кеш включен, MPU регионов с дескрипторами настроены по рекомендациям ST: // ======= memory policy (ethernet tx/rx descriptors) MPU->RNR = 11;// region number MPU->RBAR = 0x3004001B;// base address MPU->RASR = (0 << MPU_RASR_XN_Pos) |// DisableExec (1 << MPU_RASR_AP_Pos) |//AccessPermission (1 - privilegied only) ((0) << MPU_RASR_TEX_Pos) |//TypeExtField (0 << MPU_RASR_S_Pos) |//IsShareable (0 << MPU_RASR_C_Pos) |//IsCacheable (1 << MPU_RASR_B_Pos) |//IsBufferable (0 << MPU_RASR_SRD_Pos) |//SubRegionDisable (MPU_REGION_SIZE_512B<< MPU_RASR_SIZE_Pos)|//Size (1 << MPU_RASR_ENABLE_Pos);//Enable Кто-нибудь сталкивался с этим? Можно конечно механизм расклинивания дескрипторов для этой ситуации сделать, но хочется найти косяк и исправить по человечески.
  4. Я получил без трансивера ~10(+-1)мбайт/сек записи, примерно столько же чтения. Без low-voltage трансивера это близко к пределу пропускной способности интерфейса sd карты. Загрузка cpu H743 порядка 10% получилась (реально меньше, ибо в загрузку еще получение по интерфейсу и предобработка данных включается). Без кеширования скорость записи была порядка 2-3МБ, но главная неприятность в том что при записи были регулярные фризы на время около 1 секунды (предполагаю, контроллер sd карты при многократной перезаписи одной области искусственно вносит задержку чтоб не истратить ресурс быстро). При кешировании ни одного фриза не заметил. В моем случае при потоковой записи такие фризы - очень неприятная штука.
  5. Разобрался. Код этот рабочий, с размером блока напортачил. Плюс IDE в дампе EEPROM не обновляет дамп в реальном времени (обновляет только при запуске отладчика) и затирает EEPROM по умолчанию при программировании.
  6. Не пойму в чем дело. Пытаюсь писать в eeprom, и никаких признаков что пишется не наблюдаю. В гугле есть аналогичный вопрос, без ответа торчит. void WriteFlash(const void* Src, void* Dst, int Len) { while (NVMCTRL.STATUS & 3) {}; uint8_t* SrcB = (uint8_t*)Src; volatile uint8_t* DstB = (uint8_t*)Dst; CPU_CCP=0x9D;// unlock for next 4 cycles. ints skipped for 4 cycles NVMCTRL.CTRLA=NVMCTRL_CMD_PAGEBUFCLR_gc; while (NVMCTRL.STATUS & 3) {}; for (int i=0; i<Len; i++) { *(DstB++) = *(SrcB++); } CPU_CCP=0x9D;// unlock for next 4 cycles. ints skipped for 4 cycles NVMCTRL.CTRLA=NVMCTRL_CMD_PAGEERASEWRITE_gc; while (NVMCTRL.STATUS & 3) {}; } #define SETTINGS_ADDR 0x1400 WriteFlash ((void*)&settings, (void*)SETTINGS_ADDR, sizeof (struct SETTINGS)); // пробовал и штатную функцию вызывать. эффект аналогичный: #include <avr/eeprom.h> eeprom_write_block ((void*)&settings, (void*)0/*SETTINGS_ADDR*/, sizeof (struct SETTINGS)); смотрел дамп в mplab x 5.50. везде ff ff...
  7. Увы, это не так. Совсем. Во-первых, модуль кеширования как раз занимается всем этим: и группировкой секторов в блоки, и умным префетчем, и отсеканием ненужных/пустых операций, и выравниванием операций по границе. Просто увеличив размер сектора до 4к мы как минимум половину из этих проблем не решаем, ибо я детально изучал какие обращения делает fatfs на каких операциях, там много избыточных обращений, которые можно вылечить либо серьезным усложнением самого fatfs, либо на порядок более простым модулем кеширования. К тому же, размер блока SD карты обычно больше 4к, со всеми вытекающими. А при работающем кеше 4к блоки у fatfs не имеют никакого практического смысла. Еще приятный бонус кеширования - можно операции чтения-записи к fatfs делать любыми удобными кусками, хоть по 5 байт, можно бустро и часто открывать-закрывать файлы без перечитывания цепочек fat и каталогов. Модуль кеширования всё это выстраивает и оптимизирует.
  8. Я с SD карточкой тоже боролся. Тоже смотрел в сторону увеличить блок данных (точнее, почему блок указан длинный, но пишется-читается все равно по 512 байт). В процессе разбора кода понял что лучше сделать модуль кеширования. В первую очередь чтобы ресурс флешки продлить - fatfs бестолково пишет некоторые сектора по многу раз в одно и то же место. В итоге немного допилил сам fatfs, ибо модулю кеширования для правильного выбора метода кеширования нужно знать какой это сектор - fat, каталога или кластер данных. Т.е. при кешировании данных модуль кеширования использует разные стратегии кеширования для кластеров, fat и каталогов. Ну и умеет буферизировать чтение и запись.
  9. После патча косяки исчезли. Вот подправленный варинат: static ETH_BufferTypeDef RxBuff[ETH_RX_DESC_CNT];// вынес в статику, чтоб при каждом пакете не инициализировать их заново. static struct pbuf * low_level_input(struct netif *netif) { struct pbuf *p = NULL; uint32_t framelength = 0; struct pbuf_custom* custom_pbuf; if (HAL_ETH_GetRxDataBuffer(&heth, RxBuff) == HAL_OK) { HAL_ETH_GetRxDataLength(&heth, &framelength); #if !defined(DUAL_CORE) || defined(CORE_CM7) // SCB_InvalidateDCache_by_Addr((uint32_t *)RxBuff->buffer, framelength); __DSB();// если кеш принимаемых пакетов отключен #endif lan_stats.rx_frames++; custom_pbuf = (struct pbuf_custom*)LWIP_MEMPOOL_ALLOC(RX_POOL); if(custom_pbuf != NULL) { custom_pbuf->custom_free_function = pbuf_free_custom; p = pbuf_alloced_custom(PBUF_RAW, framelength, PBUF_REF, custom_pbuf, RxBuff->buffer, framelength); } } return p; } extern SemaphoreHandle_t ipSemaphore; void ethernetif_input(void* argument) { struct pbuf *p; struct netif *netif = (struct netif *) argument; memset(RxBuff, 0 , ETH_RX_DESC_CNT*sizeof(ETH_BufferTypeDef)); for(int i = 0; i < ETH_RX_DESC_CNT -1; i++) RxBuff[i].next=&RxBuff[i+1]; while (ipSemaphore==NULL) osDelay(1); for( ;; ) { if (osSemaphoreAcquire(RxPktSemaphore, TIME_WAITING_FOR_INPUT) == osOK) { do { p = low_level_input( netif ); if (p != NULL) { // if (netif->input( p, netif) != ERR_OK ) if( xSemaphoreTake( ipSemaphore, ( TickType_t ) 0 ) ) { ethernet_input(p, netif); xSemaphoreGive( ipSemaphore ); } else pbuf_free(p); /* Build Rx descriptor to be ready for next data reception */ HAL_ETH_BuildRxDescriptors(&heth); } } while(p!=NULL); } } } И в tcpip.c семафор вставил: SemaphoreHandle_t ipSemaphore = NULL; static void tcpip_thread(void *arg) { struct tcpip_msg *msg; LWIP_UNUSED_ARG(arg); ipSemaphore = xSemaphoreCreateMutex(); xSemaphoreGive( ipSemaphore ); LWIP_MARK_TCPIP_THREAD(); LOCK_TCPIP_CORE(); if (tcpip_init_done != NULL) { tcpip_init_done(tcpip_init_done_arg); } while (1) { /* MAIN Loop */ LWIP_TCPIP_THREAD_ALIVE(); /* wait for a message, timeouts are processed while waiting */ TCPIP_MBOX_FETCH(&tcpip_mbox, (void **)&msg); if (msg == NULL) { LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n")); LWIP_ASSERT("tcpip_thread: invalid message", 0); continue; } if( xSemaphoreTake( ipSemaphore, ( TickType_t ) 0 ) ) { tcpip_thread_handle_msg(msg); xSemaphoreGive( ipSemaphore ); } } }
  10. Поразбирался. Самое веселое, что куда ни ставь HAL_ETH_BuildRxDescriptors, глюк не исчезает по банальной причине - пакет обрабатывается в другом потоке... Пришел пакет -> вызвалось Ethernet IRQ -> RxPktSemaphore -> завершение IRQ далее отрабатывает Ethif task: ethernetif_input -> tcpip_inpkt -> sys_mbox_trypost -> osMessageQueuePut -> xQueueSendToBack -> и в конце вызывает HAL_ETH_BuildRxDescriptors. Причем если вызов HAL_ETH_BuildRxDescriptors перенести в tcpip_thread, HAL перестанет сдвигать буфера и будет бесконечно один и тот же пакет пытаться отправить. далее, всё это принимает поток tcpip_thread. И в ней уже обрабатывается пакет, который был освобожден предыдущим потоком, со всеми вытекающими: tcpip_thread -> ethernet_input Вообщем, сделали крайне бестолково. Думаю, весь Ethif task надо убирать ибо он не нужен, а пакет из ethernetif_input сразу отдавать на обработку в ethernet_input.
  11. Как раз хотелось бы дескрипторы поменьше, например 128 байт, но общий объем буферов около 20кб. Иначе при маленьких пакетах и больших буферах эффективность использования RAM низкая, а packet rate может быть весьма высокий. И получается, если система задумалась при обработке жирного пакета, на буферизацию мелких пакетов может памяти не хватить (что собственно и происходит на практике). Сейчас смотрю реализацию езернета в порте микропитона под STM... Код явно в разы шустрей чем hal от stm. Видимо придется взять его за основу и немного доработать, ибо он на мелкие дескрипторы не заточен. Потрассировал HAL - честно разочаровывают программисты от ST. такие жирные функции крутить на каждом пакете, которые по факту ничего не делают. Вероятно, у Вас в поллинг режиме езернет работает. Мне же нужно с IRQ и RTOS.
  12. Еще не понял. HAL_ETH_GetRxDataLength(&heth, &framelength); - это размер всего пакета же, а не одного куска в дескрипторе? т.е. далее по тексту сброс DCACHE подразумевает целый пакет одним куском. Но... ведь пакет может быть в нескольких дескрипторах и не подряд идущих (переход по кругу от последнего буфера к первому), и получается хвост может потерять, если пакет не влезает в один дескриптор?
  13. При работе езернета натолкнулся на интересный глюк - содержимое пакета во время обработки может перезаписаться (на другой пакет). Причем долго работало нормально, стало проявляться только когда много коротких пакетов после задержки в роутере пачкой выплёвываются. Стал копать. Смотрю, куб из коробки генерирует такой вот код (специально обновил куб, свежий то же самое генерит): static struct pbuf * low_level_input(struct netif *netif) { struct pbuf *p = NULL; uint32_t framelength = 0, i = 0; struct pbuf_custom* custom_pbuf; ETH_BufferTypeDef RxBuff[ETH_RX_DESC_CNT]; memset(RxBuff, 0 , ETH_RX_DESC_CNT*sizeof(ETH_BufferTypeDef)); for(i = 0; i < ETH_RX_DESC_CNT -1; i++) { RxBuff[i].next=&RxBuff[i+1]; } if (HAL_ETH_GetRxDataBuffer(&heth, RxBuff) == HAL_OK) { HAL_ETH_GetRxDataLength(&heth, &framelength); HAL_ETH_BuildRxDescriptors(&heth); #if !defined(DUAL_CORE) || defined(CORE_CM7) /* Invalidate data cache for ETH Rx Buffers */ SCB_InvalidateDCache_by_Addr((uint32_t *)RxBuff->buffer, framelength); #endif lan_stats.rx_frames++; custom_pbuf = (struct pbuf_custom*)LWIP_MEMPOOL_ALLOC(RX_POOL); if(custom_pbuf != NULL) { custom_pbuf->custom_free_function = pbuf_free_custom; p = pbuf_alloced_custom(PBUF_RAW, framelength, PBUF_REF, custom_pbuf, RxBuff->buffer, framelength); } } return p; } забавно, что HAL_ETH_BuildRxDescriptors (как я понял это функция, которая помечает буфера приема как "свободно") вызывается не дожидаясь обработки пакета (которая в традиционно в процессе RTOS крутится). Подебажил - действительно, после вызова HAL_ETH_BuildRxDescriptors буфер перезаписывается свежими пакетами. Вот думаю, что разработчики имели в виду написав так... и как проще исправить.
  14. Да, lvgl уже подключил. На первый взгляд очень понравилось - документация адекватная, архитетура сделана по уму. openvg интересная наработка, будет время попробую. Откликов как-то не густо. Сложностью испугал или ценник не озвучил? платить готовы достойно, главное получить результат. Лучше конечно в перспективе рассматривать как длительное сотрудничество, а не разовую задачу.