Easyelectronics.ru

Электроника для всех
Текущее время: 21 окт 2018, 09:49

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



    • JLCPCB - Прототипы 10 PCBs всего за 2$ (100*100mm, 2-layer)
    • Как мы делаем платы, смотрите на YouTube
    • Крупнейшая китайская фабрика прототипов. 300000+ заказчиков и 10000+ заказов в день!
    • LCSC - Крупнейший китайский онлайн магазин комплектующих.

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

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

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
Сообщения: 2689
Там проблема в том, что DMA на SDIO умеет работать только с выровненными по 4 байта адресами, т.к оперирует длиной транзакции DMA в 4 байта. В гуглах есть код, как модицифировать, если вкратце - проверяется адрес, откуда берутся данные, если не выровнен, то копируются в промежуточный буфер до выравнивания адреса, отправляются на запись, и далее уже работаем с выровненными адресом.


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

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

Код:
#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
Сообщения: 308
Это прям шаманство какое-то! :-)
Всё сразу получилось, в исходном файле (до моих тасований) стоило вставить
__ALIGN_BEGIN uint8_t BUFDISK[70000] __ALIGN_END = {0};
с верхней шапкой и всё стало нормально записываться.
Мда, далеко мне до нормального программиста. :-(

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


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

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

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

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


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

Зарегистрирован: 16 ноя 2012, 07:47
Сообщения: 2689
Но такая фишка будет работать, только если у вас всегда известно что отправляется. К примеру, если мы что-то динамически выделяем, и затем пишем на карточку, то нет гарантии что динамически выделенная память будет выровнена (или будет? Вроде не гарантируется нигде). У меня так неспешно логгер работает, который пишет разные события на карту.
Вот, выдрал из рабочего проекта. Пишет с выравниванием и без:
Код:
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
Сообщения: 383
Откуда: дальнее надмосковье
Цитата:
К примеру, если мы что-то динамически выделяем, и затем пишем на карточку, то нет гарантии что динамически выделенная память будет выровнена (или будет? Вроде не гарантируется нигде)


Никогда не использовал, но есть функции в сишной стандартной библиотеке, например 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
Сообщения: 1313
Откуда: Китай, Пекин
поиск по проблеме сразу выдаёт


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

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


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


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

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


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

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


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

Сейчас этот форум просматривают: нет зарегистрированных пользователей


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

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

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