Easyelectronics.ru

Электроника для всех
Текущее время: 20 июн 2018, 20:07

Часовой пояс: UTC + 5 часов



    • JLCPCB - Платы прототипов всего за 2$ c бесплатной доставкой (при первом заказе)
    • 10 PCBs за $2 для 2 слоев, $15 для 4 слойной, $74 для 6 слойной платы.
    • Крупнейший китайский производитель прототипных плат. 290000+ клиентов & 8000+ заказов в день!
    • LCSC - Крупнейший китайский онлайн магазин радиодеталей.

Начать новую тему Ответить на тему  [ Сообщений: 10 ] 
Автор Сообщение
 Заголовок сообщения: как правильно размещать массивы?
СообщениеДобавлено: 06 июн 2018, 15:54 
Старожил

Зарегистрирован: 13 июл 2016, 11:05
Сообщения: 248
Здесь как-то попадалось что-то с "круглостью" адресов.
Проблема вот в чем.
Есть функция записи массива в файл:

f_write(&testFile, BUFDISK, BYTEFLASH, &testBytes)

У меня здесь массив BUFDISK - сюда складываю всё, что хочу в файл.
BYTEFLASH - сколько всего байт.

При определенном наборе разных переменных и массивов BUFDISK компилятор размещает в памяти с разных мест.

BUFDISK 0x20000a94 Data 70000 main.o(.bss)
BUFDISK 0x200023c4 Data 70000 main.o(.bss)

Но при этом в одном случае файл пишется нормально при любом размере, а в другом только до 512 байт.
Если больше, то файл - 0 байт.
Вот только что тасовал переменные, пока не добился.

Вот конкретно - не пишет:

BUFDISK 0x20002c22 Data 70000 main.o(.bss)

Пишет нормально:

BUFDISK 0x20000a94 Data 70000 main.o(.bss)
BUFDISK 0x200023c4 Data 70000 main.o(.bss)

Но окончание на 4 - не есть гарантия, были варианты, что и с ней тоже не пишет больше 500.

Есть какие требования у функции f_write?
Ну или можно как-то менять расположение массивов принудительно простым способом?

Забыл указать :

uint8_t BUFDISK[70000];


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: как правильно размещать массивы?
СообщениеДобавлено: 06 июн 2018, 16:11 
Старожил

Зарегистрирован: 16 ноя 2012, 07:47
Сообщения: 2621
Там проблема в том, что DMA на SDIO умеет работать только с выровненными по 4 байта адресами, т.к оперирует длиной транзакции DMA в 4 байта. В гуглах есть код, как модицифировать, если вкратце - проверяется адрес, откуда берутся данные, если не выровнен, то копируются в промежуточный буфер до выравнивания адреса, отправляются на запись, и далее уже работаем с выровненными адресом.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: как правильно размещать массивы?
СообщениеДобавлено: 06 июн 2018, 16:25 
Старожил

Зарегистрирован: 07 авг 2014, 17:15
Сообщения: 353
Откуда: дальнее надмосковье
Это куда-нибудь в заголовочные файлы (если уже нет)

Код:
#if defined   (__GNUC__)        /* GNU Compiler */
    #define __ALIGN_END    __attribute__ ((aligned (4)))
    #define __ALIGN_BEGIN         
#else                           
    #define __ALIGN_END
    #if defined   (__CC_ARM)      /* ARM Compiler */
        #define __ALIGN_BEGIN    __align(4) 
    #elif defined (__ICCARM__)    /* IAR Compiler */
        #define __ALIGN_BEGIN
    #elif defined  (__TASKING__)  /* TASKING Compiler */
        #define __ALIGN_BEGIN    __align(4)
    #endif /* __CC_ARM */ 
#endif /* __GNUC__ */


А так использовать:

Код:
__ALIGN_BEGIN uint8_t BUFDISK[70000] __ALIGN_END  = {0};


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: как правильно размещать массивы?
СообщениеДобавлено: 06 июн 2018, 16:36 
Старожил

Зарегистрирован: 13 июл 2016, 11:05
Сообщения: 248
Это прям шаманство какое-то! :-)
Всё сразу получилось, в исходном файле (до моих тасований) стоило вставить
__ALIGN_BEGIN uint8_t BUFDISK[70000] __ALIGN_END = {0};
с верхней шапкой и всё стало нормально записываться.
Мда, далеко мне до нормального программиста. :-(

Огромнейшее спасибо!


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: как правильно размещать массивы?
СообщениеДобавлено: 06 июн 2018, 16:54 
Старожил

Зарегистрирован: 07 авг 2014, 17:15
Сообщения: 353
Откуда: дальнее надмосковье
serglg писал(а):
...Мда, далеко мне до нормального программиста. :-(

Ну что же Вы так, немного опыта, побольше курить доки и подглядывать в работающие открытые проекты - и знания накапливаются.

А по теме - как уже Hold сказал - для корректной работы DMA контроллеру нужно чтобы данные в памяти были выровнены по "слову" - так удобнее/легче реализовать эти фичи в камне. Информация об этом есть в доках. Но так как в стандарте С не учтена такая возможность, то авторы компиляторов придумали разные заклинания, чтобы программисты могли распоряжаться выравниванием при необходимости. Чем мы и пользуемся.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: как правильно размещать массивы?
СообщениеДобавлено: 06 июн 2018, 17:54 
Старожил

Зарегистрирован: 16 ноя 2012, 07:47
Сообщения: 2621
Но такая фишка будет работать, только если у вас всегда известно что отправляется. К примеру, если мы что-то динамически выделяем, и затем пишем на карточку, то нет гарантии что динамически выделенная память будет выровнена (или будет? Вроде не гарантируется нигде). У меня так неспешно логгер работает, который пишет разные события на карту.
Вот, выдрал из рабочего проекта. Пишет с выравниванием и без:
Код:
int   SDIO_disk_read( BYTE *buff, DWORD sector, BYTE count )
{
   SD_Error Status;
   SDTransferState State;

   if (SD_Detect() != SD_PRESENT)   return(RES_NOTRDY);
   if ((DWORD)buff & 3) // DMA Alignment failure, do single up to aligned buffer
   {
      DRESULT res = RES_OK;
      DWORD scratch[512 / 4]; // Alignment assured, you'll need a sufficiently big stack

      while(count--)
      {
         res = (DRESULT)SDIO_disk_read((void *)scratch, sector++, 1);
         if (res != RES_OK)   break;
         memcpy(buff, scratch, 512);
         buff += 512;
      }
      return(res);
   }
   Status = SD_ReadMultiBlocksFIXED(buff, sector, 512, count); // 4GB Compliant
   if (Status == SD_OK)
   {
      Status = SD_WaitReadOperation();                     // Check if the Transfer is finished
      while((State = SD_GetStatus()) == SD_TRANSFER_BUSY);      // BUSY, OK (DONE), ERROR (FAIL)
      if ((State == SD_TRANSFER_ERROR) || (Status != SD_OK))   return(RES_ERROR);
      else   return(RES_OK);
   }
   else   return(RES_ERROR);
}


int   SDIO_disk_write( const BYTE *buff, DWORD sector, BYTE count )
{
   SD_Error Status;
   SDTransferState State;

   if (SD_Detect() != SD_PRESENT)   return(RES_NOTRDY);
   if ((DWORD)buff & 3) // DMA Alignment failure, do single up to aligned buffer
   {
      DRESULT res = RES_OK;
      DWORD scratch[512 / 4]; // Alignment assured, you'll need a sufficiently big stack
      while(count--)
      {
         memcpy(scratch, buff, 512);
         res = (DRESULT)SDIO_disk_write((void *)scratch, sector++, 1);
         if (res != RES_OK)
         break;
         buff += 512;
      }
      return(res);
   }
   Status = SD_WriteMultiBlocksFIXED((uint8_t *)buff, sector, 512, count); // 4GB Compliant
   if (Status == SD_OK)
   {
      Status = SD_WaitWriteOperation();                     // Check if the Transfer is finished
      while((State = SD_GetStatus()) == SD_TRANSFER_BUSY);      // BUSY, OK (DONE), ERROR (FAIL)
      if ((State == SD_TRANSFER_ERROR) || (Status != SD_OK))   return(RES_ERROR);
      else   return(RES_OK);
   }
   else   return(RES_ERROR);
}


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: как правильно размещать массивы?
СообщениеДобавлено: 06 июн 2018, 18:06 
Старожил

Зарегистрирован: 07 авг 2014, 17:15
Сообщения: 353
Откуда: дальнее надмосковье
Цитата:
К примеру, если мы что-то динамически выделяем, и затем пишем на карточку, то нет гарантии что динамически выделенная память будет выровнена (или будет? Вроде не гарантируется нигде)


Никогда не использовал, но есть функции в сишной стандартной библиотеке, например memalign (и еще начиная с С11 - aligned_alloc, и posix_memalign в стандарте POSIX):

http://man7.org/linux/man-pages/man3/po ... ign.3.html

В newlib (популярная С библиотека для GNU arm-none-eabi-gcc) вроде есть memalign, так что, думаю, под STM32 можно это использовать.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: как правильно размещать массивы?
СообщениеДобавлено: 06 июн 2018, 18:27 
Старожил
Аватара пользователя

Зарегистрирован: 11 апр 2016, 18:04
Сообщения: 1056
Откуда: Китай, Пекин
поиск по проблеме сразу выдаёт


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: как правильно размещать массивы?
СообщениеДобавлено: 07 июн 2018, 09:20 
Старожил

Зарегистрирован: 13 июл 2016, 11:05
Сообщения: 248
cheblin писал(а):


Спасибо, буду на будущее иметь в виду.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: как правильно размещать массивы?
СообщениеДобавлено: 08 июн 2018, 00:03 
Только пришел

Зарегистрирован: 05 дек 2017, 18:17
Сообщения: 20
Я с fat_fs решил чуть иначе. У меня запись буфера, мультиблоком. Чтобы не ждать окончания записи, я отправляю буфер в DMA, запускаю передачу и ставлю флаг. И на этом заканчиваю. Флаг снимается в прерывании и там же отправляю команду карте "стоп" мультиблока.
Так вот, оказалось, что fat_fs успевает что-то записать в буфер раньше, чем DMA закончит передачу. Вообщем выделил еще один буфер, выровненный как надо и просто копирую в него memcpy перед отправкой буфера DMA.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 10 ] 

Часовой пояс: UTC + 5 часов


Кто сейчас на конференции

Сейчас этот форум просматривают: Eddy_Em, goreprogrammist, mChel


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB