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

STM32F105 и кривой Malloc

В общем, писал я себе, писал прогу, а тут на тебе старый знакомый USBD_malloc. Думал раньше, что обойду его, а нет, настиг проклятый. Данная тема является продолжением Эпопеи в двух частях - Как меня задрали USB дрова от разработчиков STM.

А теперь ближе к делу.

Разбираясь в неполадках передачи по USB(висит в выделенном цикле, хотя в первый цикл проходит(повезло?)) в нижепоказанной функции, узрел что TxState содержит какое то невероятное число.

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
  USBD_CDC_HandleTypeDef *pCDC =
           (USBD_CDC_HandleTypeDef *)hUsbDevice_0->pClassData;
 uint16_t offset = 0;
 while (offset < Len)
 {
   if ((Len-offset)<TX_BUFF_SIZE)
   {
     while(pCDC->TxState);
     USBD_CDC_SetTxBuffer(hUsbDevice_0, Buf + offset, Len-offset);
     if (USBD_CDC_TransmitPacket(hUsbDevice_0) != USBD_OK)
         return USBD_FAIL;
while(pCDC->TxState);
     break;
   }
   while(pCDC->TxState);
   USBD_CDC_SetTxBuffer(hUsbDevice_0, Buf + offset, TX_BUFF_SIZE);
   if (USBD_CDC_TransmitPacket(hUsbDevice_0) != USBD_OK)
       return USBD_FAIL;
   while(pCDC->TxState);
   offset+=0x40;
 }
 return USBD_OK;}

Думаю, что это неправильная инициализация указателя pClassData. Скорее всего он указывает на кусок мусора. Потому что собственно он инициализируется вот так(для тех кто в танке и не стал читать ссыль на предыдущую часть Эпопеи):

  pdev->pClassData = USBD_malloc(sizeof (USBD_CDC_HandleTypeDef));

Сам малок выглядит вот так:

#define USBD_malloc               (uint32_t *)USBD_static_malloc
void *USBD_static_malloc(uint32_t size)
{
  static uint8_t mem[sizeof(USBD_CDC_HandleTypeDef)];
  return mem;
}

Как все успели заметить - это гавнокод(КО не дремлет). В связи с этим, хочу решить проблему иным способом, так чтобы работало всё.

Попробовал создать статическую переменную типа структуры USBD_CDC_HandleTypeDef(на нестатическую компилятор ругается при линковке, дескать узрел где то чуть ли не сотню дубликатов этого типа там, где он и не используется даже - явный тупняк):

typedef struct
{
 uint32_t data[CDC_DATA_HS_MAX_PACKET_SIZE/4];      /* Force 32bits alignment */
 uint8_t  CmdOpCode;
 uint8_t  CmdLength;    
 uint8_t  *RxBuffer;  
 uint8_t  *TxBuffer;   
 uint32_t RxLength;
 uint32_t TxLength;    

 __IO uint32_t TxState;     
 __IO uint32_t RxState;    
}
USBD_CDC_HandleTypeDef; 

static USBD_CDC_HandleTypeDef  USBD_CDC_Handle;

Также убрал малок:

 pdev->pClassData = &USBD_CDC_Handle;

Работать это конешно не стало, как и предполагалось, всё тоже самое что и до замены малока.

Как бы решить эту проблему, подскажите)

P.s. На буржуйском форуме пишут про баги для STM32F4 Discovery. Якобы явное приведение типа указателя к void* и расширение heap поможет. Сомнительно. Но я к сожалению до понедельника не смогу удостовериться, так как прибор на работе

 

Update

И кто-нибудь сможет ответить на вопрос, почему если я создам глобальную (не статическую как показано выше) переменную типа USBD_CDC_HandleTypeDef, то вылетают такие ошибки:

Error[Li006]: duplicate definitions for "USBD_CDC_Handle"; in "G:\Работа\FirmWare0.02\EWARM\FirmWare0.02 Configuration\Obj\ADC.o", and "G:\Работа\FirmWare0.02\EWARM\FirmWare0.02 Configuration\Obj\M25P128.o"
Error[Li006]: duplicate definitions for "USBD_CDC_Handle"; in "G:\Работа\FirmWare0.02\EWARM\FirmWare0.02 Configuration\Obj\ADC.o", and "G:\Работа\FirmWare0.02\EWARM\FirmWare0.02 Configuration\Obj\main.o" 
Error[Li006]: duplicate definitions for "USBD_CDC_Handle"; in "G:\Работа\FirmWare0.02\EWARM\FirmWare0.02 Configuration\Obj\ADC.o", and "G:\Работа\FirmWare0.02\EWARM\FirmWare0.02 Configuration\Obj\usb_device.o" 
Error[Li006]: duplicate definitions for "USBD_CDC_Handle"; in "G:\Работа\FirmWare0.02\EWARM\FirmWare0.02 Configuration\Obj\ADC.o", and "G:\Работа\FirmWare0.02\EWARM\FirmWare0.02 Configuration\Obj\usbd_cdc.o" 
Error[Li006]: duplicate definitions for "USBD_CDC_Handle"; in "G:\Работа\FirmWare0.02\EWARM\FirmWare0.02 Configuration\Obj\ADC.o", and "G:\Работа\FirmWare0.02\EWARM\FirmWare0.02 Configuration\Obj\usbd_cdc_if.o" 
Error[Li006]: duplicate definitions for "USBD_CDC_Handle"; in "G:\Работа\FirmWare0.02\EWARM\FirmWare0.02 Configuration\Obj\ADC.o", and "G:\Работа\FirmWare0.02\EWARM\FirmWare0.02 Configuration\Obj\usbd_conf.o" 
Error while running Linker

что за хрень? в данных файлах нету никакого объявления USBD_CDC_Handle и уж тем более не подключены хедеры с файлами, где эта переменная объявлена.

Изменено пользователем Still Enemy

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


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

Скорее всего он указывает на кусок мусора.
Это как раз вполне нормально. Любое выделение памяти вернет память с мусором. Заполнить его после этого разумными данными - задача программиста.

Попробовал создать статическую переменную типа структуры USBD_CDC_HandleTypeDef(на нестатическую компилятор ругается при линковке, дескать узрел где то чуть ли не сотню дубликатов этого типа там, где он и не используется даже - явный тупняк):
Ругань была совершенно справедливой, это явный ваш тупняк. Вы пытались определить переменную в заголовочном файле. Заголовочный файл включается в несколько исходных файлов (единиц копиляции) методом тупой текстовой подстановки. Получилось, что вы определили одну и ту же переменную в нескольких единицах компиляции. Компилятор понятия не имеет о существовании других единиц компиляции, поэтому честно создал такую переменную в каждой единице. И линкер получил кучу переменных с одинаковым именем. Когда вы добавили static, вы получили еще более веселый результат - вы получили в каждой единице компиляции свою переменную, которая не видна из других единиц компиляции. То есть каждая единица компиляции работала со своей копией переменной. Если смотреть углубленно - то ваш код при этом должен был работать, поскольку прямое обращение к этой переменной у вас происходит только в одном файле, там, где ее адрес присваивается указателю. В остальных местах обращение идет только через указатель и попадает в ту же самую переменную. Остальные копии этой переменной выкинул оптимизатор. Но в общем случае это говнокод еще похуже исходного.

 

Выкиньте ваше

static USBD_CDC_HandleTypeDef  USBD_CDC_Handle;

. В том файле, где находится строка

  pdev->pClassData = USBD_malloc(sizeof (USBD_CDC_HandleTypeDef));

объявите глобальную переменную

USBD_CDC_HandleTypeDef  USBD_CDC_Handle;

и присвойте ее адрес

  pdev->pClassData = &USBD_CDC_Handle;

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

 

Однако это скорее всего не поможет. Проблема не здесь. Исходный код с USBD_static_malloc() должен работать, если из него выкинуть free(p).

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


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

Это как раз вполне нормально. Любое выделение памяти вернет память с мусором. Заполнить его после этого разумными данными - задача программиста.

Ну я же не такой тупой) я посмотрел, что далее в этой же функции, после разименования указателя, идёт заполнение горемычной структуры.

static uint8_t  USBD_CDC_Init (USBD_HandleTypeDef *pdev, 
                              uint8_t cfgidx)
{
 uint8_t ret = 0;
 USBD_CDC_HandleTypeDef   *hcdc;

 if(pdev->dev_speed == USBD_SPEED_HIGH  ) 
 {  
   /* Open EP IN */
   USBD_LL_OpenEP(pdev,
                  CDC_IN_EP,
                  USBD_EP_TYPE_BULK,
                  CDC_DATA_HS_IN_PACKET_SIZE);

   /* Open EP OUT */
   USBD_LL_OpenEP(pdev,
                  CDC_OUT_EP,
                  USBD_EP_TYPE_BULK,
                  CDC_DATA_HS_OUT_PACKET_SIZE);

 }
 else
 {
   /* Open EP IN */
   USBD_LL_OpenEP(pdev,
                  CDC_IN_EP,
                  USBD_EP_TYPE_BULK,
                  CDC_DATA_FS_IN_PACKET_SIZE);

   /* Open EP OUT */
   USBD_LL_OpenEP(pdev,
                  CDC_OUT_EP,
                  USBD_EP_TYPE_BULK,
                  CDC_DATA_FS_OUT_PACKET_SIZE);
 }
 /* Open Command IN EP */
 USBD_LL_OpenEP(pdev,
                CDC_CMD_EP,
                USBD_EP_TYPE_INTR,
                CDC_CMD_PACKET_SIZE);


 pdev->pClassData = &USBD_CDC_Handle;//USBD_malloc(sizeof (USBD_CDC_HandleTypeDef));

 if(pdev->pClassData == NULL)
 {
   ret = 1; 
 }
 else
 {
 hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;

   /* Init  physical Interface components */
   ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Init();

   /* Init Xfer states */
   hcdc->TxState =0;
   hcdc->RxState =0;

   if(pdev->dev_speed == USBD_SPEED_HIGH  ) 
   {      
     /* Prepare Out endpoint to receive next packet */
     USBD_LL_PrepareReceive(pdev,
                            CDC_OUT_EP,
                            hcdc->RxBuffer,
                            CDC_DATA_HS_OUT_PACKET_SIZE);
   }
   else
   {
     /* Prepare Out endpoint to receive next packet */
     USBD_LL_PrepareReceive(pdev,
                            CDC_OUT_EP,
                            hcdc->RxBuffer,
                            CDC_DATA_FS_OUT_PACKET_SIZE);
   }
 }
 return ret;
}

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

А разве код(нижеприведённый) не должен спасать ситуацию?

#ifndef __USB_CDC_H
#define __USB_CDC_H
#endif

Но в общем случае это говнокод еще похуже исходного.

Согласен, просто сделал первое, что пришло на ум)

 

Однако это скорее всего не поможет. Проблема не здесь. Исходный код с USBD_static_malloc() должен работать, если из него выкинуть free(p).

Херога. Если при разыменование указателя всё нормально происходит, значит указатель портится в процессе выполнения проги. Это осложняет дело.

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


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

А разве код(нижеприведённый) не должен спасать ситуацию?

#ifndef __USB_CDC_H
#define __USB_CDC_H
#endif

Нет. Он не позволяет повторное включение заголовочного файла в одну единицу трансляции. От включения в разные единицы трансляции он защитить не может и не должен.

 

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


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

Кароч это дно полное. Оказывается указатель pCDC в функции CDC_Transmit_FS "уничтожается" (не знаю даже как назвать это) знаете кем? Не угадали. ОПТИМИЗАТОРОМ. На Hige - Size.

Пруфф.

76514bbee264.jpg

Картинка вообще зачётная, такого оптимизирования я еще не видел. Я могу конешно посетовать на то, что я и сам гавнокодер и оптимизатор на мой гавнокод реагирует однозначным гавнодействием. Но так чтобы игнорировать банальное создание указателя и разыменование, на такое я в осадок выпал. Более того скажу, иногда оптимизировался код на столько отлично, что указатель pCDC указывал вообще на левую структуру, жаль не смог запечатлеть этот момент)

Вывод: снизил оптимизацию на Medium и радуюсь. НО если кому не сложно, объясните где я накосячил с кодом, что всё пошло именно по такому пути( у меня есть конешно один вариант на этот счёт: я указатель hUsbDevice_0 не передаю в функцию аргументом, а беру его извне(он объявлен в том же хедаре как глобальный указатель, что и данная функция) и собственно из-за этого оптимизатор указатель "уничтожает")? Всё таки оптимизатором нужно считаться, хоть чуть-чуть.

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


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

Картинка вообще зачётная, такого оптимизирования я еще не видел.

 

Добро пожаловать в реальный мир. Суть его такова, что отладчик корректно показывает буковки-цифирки только при низких уровнях оптимизации.

Правильно написанный код при этом работает с любой оптимизацией. Понимать, как именно он работает, приходится по асм-листингу.

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


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

А какое содержимое отладчик показывает в h_UsbDevice_0->pClassData? И отлаживаться нужно бродя по дизассемблерному тексту, да.

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


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

А какое содержимое отладчик показывает в h_UsbDevice_0->pClassData? И отлаживаться нужно бродя по дизассемблерному тексту, да.

pCDC заменил на pTrans

282216afd71e.jpg

Изменено пользователем Still Enemy

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


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

И? Вы же видите, что никто эти данные не затер. Когда понадобится, этот указатель окажется в pCDC. pCDC будет размещен в R7. Сейчас R7 пока занят чем-то другим. Включите оконо дизассемблера, не бойтесь. Походите по шагам в нем.

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


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

И? Вы же видите, что никто эти данные не затер. Когда понадобится, этот указатель окажется в pCDC. pCDC будет размещен в R7. Сейчас R7 пока занят чем-то другим. Включите оконо дизассемблера, не бойтесь. Походите по шагам в нем.

В том то и дело, что я не боюсь) Прошел я по шагам на дизасемблере эту строчку(если я вас правильно понял конешно).

Пруф

ad3598bab3ac.jpg

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


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

Прошел я по шагам на дизасемблере эту строчку(если я вас правильно понял конешно).
Не, нужная строчка дальше. После текущей строчки в R7 будет жить offset, сейчас в ней мусор а в конце этого цикла окажется, вероятно, pTrans. pCDC в этот момент еще просто не существует.

 

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


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

Не, нужная строчка дальше. После текущей строчки в R7 будет жить offset, сейчас в ней мусор а в конце этого цикла окажется, вероятно, pTrans. pCDC в этот момент еще просто не существует.

Я извиняюсь, что ввел вас в заблуждение. Но я pCDC заменил на pTrans(я об этом отписывался ранее)

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


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

Я извиняюсь, что ввел вас в заблуждение. Но я pCDC заменил на pTrans(я об этом отписывался ранее)
В таком случае, вероятно, ошибся отладчик. По приведенному отрывку мне кажется, что pTrans он загрузил в R8, а показывает R7.

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


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

Советую перейти на libopencm3, там таких косяков нет.

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


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

Советую перейти на libopencm3, там таких косяков нет.

Дайте подумать,пожалуй, нет. Сдача проекта в конце сентября, проект не больно маленький. Разбираться во всех этих вещах по новой мне удовольствия не доставит. Да и вообще, нет уверенности, что в вашем libopencm3 не будет других проблем.

Изменено пользователем Still Enemy

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


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

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

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

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

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

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

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

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

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

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