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

STM32F429 и 16-битная SDRAM 16MB /32 MB : практический опыт?

17 часов назад, Ruslan1 сказал:

Димаю, что-то не так с рефрешем при перепутанных A10/A11 и какая-то часть ячеек портится, а дальше косвенная адресация приводит к крешу. Бурст моим МК не поддерживается, так что остается рефреш банков.

При рефреше вроде как линии адреса вообще не используются. А адрес получается от внутреннего счётчика рефреша в чипе SDRAM.

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


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

5 hours ago, jcxz said:

При рефреше вроде как линии адреса вообще не используются. А адрес получается от внутреннего счётчика рефреша в чипе SDRAM.

Знаю только что с перепутанными линиями работает плохо, а если запаять A10-A11 правильно, то начинает работать корректно.

Вариантов тут всего два:

1) что-то в самой SDRAM в случае перепутанных A10-A11 работает "не так".

2) ошибка в программе: что-то такое, что при использовании 8-мегабайтной микросхемы незаметно, а при использовании первых 8 мегабайт из 32-Мб микросхемы с перепутанными A10-A11 проявляется. Например, попытка выйти за границы памяти (косвенная адресация, стек, и т.д.).

Мне важно понять, что это именно (1), а не (2) и проблема действительно решается перепайкой, а не просто становится незаметна.

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


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

3 часа назад, Ruslan1 сказал:

Например, попытка выйти за границы памяти (косвенная адресация, стек, и т.д.).

Это решается элементарно использованием MPU. Для Cortex-M использование MPU - это признак хорошего тона при написании ПО в любом случае. имхо.

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


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

17 minutes ago, jcxz said:

Это решается элементарно использованием MPU. Для Cortex-M использование MPU - это признак хорошего тона при написании ПО в любом случае. имхо.

Не понял, можете пояснить? как использование MPU может создать ошибку, которую не видно при использовании другой микросхемы памяти?

У меня в файле *.sct прописано что есть только 8 мегабайт (да и то разделено на два фрагмента):

; *************************************************************
; *** Scatter file for firmware ***
; *************************************************************

LR_IROM1 0x08020000 0x000D0000  {    ; load region size_region
  ER_IROM1 0x08020000 0x000D0000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
  RW_IRAM3 0x20020000 0x00010000  {  ; stack for FreeRTOS data
  
  }
  RW_IRAM2 0x10000000 0x00010000  {  ; CCM
    startup_stm32f4xx.o (STACK)
   *(.ccm)
  }
  RW_RAM1 0xC0000000 UNINIT 0x00700000	{ ; 7MB RAM stack for FreeRTOS
   *(.ram1)
   }
  RW_RAM2 0xC0700000 UNINIT 0x00100000	{ ; 1MB for static vars
   *(.ram)
   }
}

 

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


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

18 минут назад, Ruslan1 сказал:

Не понял, можете пояснить? как использование MPU может создать ошибку, которую не видно при использовании другой микросхемы памяти?

Внимательнее посмотрите какую часть вашего сообщения я процитировал. MPU позволяет выявить попытки выхода за границы существующих регионов памяти.

Для регионов реально существующей памяти нужно разрешить доступ (желательно - разные типы для областей data rw, data ro, исполняемого кода и пространства IO-портов), а для всего адресного пространства поставить запрет на любой доступ (фоновым регионом с низким приоритетом).

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


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

10 hours ago, jcxz said:

При рефреше вроде как линии адреса вообще не используются. А адрес получается от внутреннего счётчика рефреша в чипе SDRAM.

Заблуждение.

Address inputs: A[12:0] are sampled during the ACTIVE command (row address A[12:0]) and READ or WRITE command (column address A[9:0] and A11 for x4; A[9:0] for x8; A[8:0] for x16; with A10 defining auto precharge) to select one location out of the memory array in the respective bank. A10 is sampled during a PRECHARGE command to determine if all banks are to be precharged (A10 HIGH) or bank selected by BA[1:0] (LOW). The address inputs also provide the op-code during a LOAD MODE REGISTER command.

 

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


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

27 minutes ago, DmitryM said:

Заблуждение.

Address inputs: A[12:0] are sampled during the ACTIVE command (row address A[12:0]) and READ or WRITE command (column address A[9:0] and A11 for x4; A[9:0] for x8; A[8:0] for x16; with A10 defining auto precharge) to select one location out of the memory array in the respective bank. A10 is sampled during a PRECHARGE command to determine if all banks are to be precharged (A10 HIGH) or bank selected by BA[1:0] (LOW). The address inputs also provide the op-code during a LOAD MODE REGISTER command.

посмотрите мое сообщение от 19 декабря:
https://electronix.ru/forum/index.php?app=forums&module=forums&controller=topic&id=146583&do=findComment&comment=1600287.

Цитата оттуда:

Quote

The AutoPrecharge is not supported. FMC_A[10] must be connected to the external memory address A[10] but it will be always driven ‘low’.

 

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


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

1 hour ago, jcxz said:

Внимательнее посмотрите какую часть вашего сообщения я процитировал. MPU позволяет выявить попытки выхода за границы существующих регионов памяти.

Для регионов реально существующей памяти нужно разрешить доступ (желательно - разные типы для областей data rw, data ro, исполняемого кода и пространства IO-портов), а для всего адресного пространства поставить запрет на любой доступ (фоновым регионом с низким приоритетом).

Понял, спасибо. MPU сейчас не применяю, и даже не возникло мысли с помощью MPU вылавливать выход за границы. Отличная идея, вставлю в план работ.

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


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

5 часов назад, Ruslan1 сказал:

Понял, спасибо. MPU сейчас не применяю, и даже не возникло мысли с помощью MPU вылавливать выход за границы. Отличная идея, вставлю в план работ.

Может Вам поможет - приведу свою функцию инициализации MPU для проекта на таком же МК (STM32F429):

//Инит MPU
void MPUinit()
{
  #if MPU_ENABLE
  #define T(base, size, tex, c, b, s, ap, xn, srd)           \
    {(base##ULL) >> size << size,                            \
    (size) - 1 << 1 | (ap) << 24 | (xn) << 28 | (srd) << 8 | \
    (tex) << 19 | (c) << 17 | (b) << 16 | (s) << 18}
  struct {
    u32 addr, attr;
  } static const t[] = { //приоритет регионов возрастает сверху вниз
    //            s
    //            i   t                 s
    //            z   e           a  x  r
    //base        e   x  c  b  s  p  n  d
    #if defined(_CODE_RAM)
    T(0x00000000, 32, 0, 0, 1, 1, 3, 1, 0x59), //IO
    T(0x10000000, 16, 0, 1, 0, 0, 7, 0, 0),    //RAM_regionA (код)
    T(0x20000000, 18, 0, 1, 0, 0, 7, 0, 0xF8), //RAM_regionB (код)
    T(0x20000000, 18, 0, 1, 0, 1, 3, 1, 0xC7), //RAM_regionC (данные)
    T(0x40024000, 12, 0, 1, 0, 1, 3, 1, 0),    //RAM_regionD (данные)
    T(0xD0000000, 23, 0, 1, 1, 1, 3, 1, 0)     //SDRAM_region (данные)
    #elif defined(_CODE_SDRAM)
    T(0x00000000, 32, 0, 0, 1, 1, 3, 1, 0x59), //IO
    T(0x10000000, 16, 0, 1, 0, 1, 3, 1, 0),    //RAM_regionA (данные)
    T(0x20000000, 17, 0, 1, 0, 0, 7, 0, 0),    //RAM_regionB (код)
    T(0x20020000, 16, 0, 1, 0, 1, 3, 1, 0),    //RAM_regionB (данные)
    T(0x40024000, 12, 0, 1, 0, 1, 3, 1, 0),    //RAM_regionD (данные)
    T(0xD0000000, 23, 0, 1, 1, 1, 3, 1, 0),    //SDRAM_regionB (данные)
    T(0xD0000000, 18, 0, 1, 1, 0, 7, 0, 0)     //SDRAM_regionA (код)
    #else
    T(0x00000000, 32, 0, 0, 1, 1, 3, 1, 0x59), //IO
    T(0x08000000, 21, 0, 1, 0, 0, 7, 0, 0),    //FLASH_regionA (код)
    T(0x10000000, 16, 0, 1, 0, 1, 3, 1, 0),    //RAM_regionA (данные)
    T(0x20000000, 18, 0, 1, 0, 1, 3, 1, 0xC0), //RAM_regionB (данные)
    T(0x2002FFE0,  5, 0, 1, 0, 0, 7, 0, 0),    //RAM_regionC (код)
    T(0x40024000, 12, 0, 1, 0, 1, 3, 1, 0),    //RAM_regionD (данные)
    T(0xD0000000, 23, 0, 1, 1, 1, 3, 1, 0)     //SDRAM_region (данные)
    #endif
  };
  ASSERT_STATIC(ncell(t) < 9, 0); //кол-во регионов, определённых в t, должно быть не более 8
  __DSB();
  __ISB();
  NVIC.MPU.CTRL = 0;
  if (((volatile u8 *)&NVIC.MPU.TYPE)[1] < ncell(t)) trap(TRAP_INTERNAL);
  u32 j;
  int i = ncell(t) - 1;
  do {
    NVIC.MPU.RNR = i;
    NVIC.MPU.RGN[0].RASR_L = j = t[i].attr;
    NVIC.MPU.RGN[0].RBAR = t[i].addr;
    NVIC.MPU.RGN[0].RASR_H = j >> 16;
    NVIC.MPU.RGN[0].RASR_L = j | B0;
  } while (--i >= 0);
  NVIC.HFSR = B1 | B30; //чистим статусы fault-ов
  NVIC.CFSR = ~0;       //чистим статусы fault-ов
  NVIC.MPU.CTRL = B0;
  __DSB();
  __ISB();
  #undef T
  #endif //MPU_ENABLE
}

#if defined(_CODE_RAM) - компиляция для выполнения кода из SRAM;

#elif defined(_CODE_SDRAM) - компиляция для выполнения кода из SDRAM;

остальное - выполнение из флешь.

6 часов назад, DmitryM сказал:

Заблуждение.

precharge - это не рефреш.

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


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

11 часов назад, jcxz сказал:

ASSERT_STATIC(ncell(t) < 9, 0); //кол-во регионов, определённых в t, должно быть не более 8

Можно взглянуть на реализацию этого макроса? И ncell() тоже... Больно интересно:smile:

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


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

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

Можно взглянуть на реализацию этого макроса? И ncell() тоже... Больно интересно:smile:

А, ну да, как-то не подумал  :acute:

ncell() - это у меня стандартный макрос, возвращающий количество элементов массива, используется в куче мест кода;

ASSERT_STATIC() - макрос, из названия которого следует, что его задача аналогична задаче стандартного макроса ASSERT(), но он проверяет условие на этапе компиляции и не создаёт исполняемого кода; удобен там где хочется проверить на валидность некоторые константы заданные сложными выражениями (не вычисляемыми препроцессором - содержащими enum/sizeof() и пр.), которые невозможно вычислить внутри условного #if...#endif, но неохота генерить лишний исполняемый код, да и хочется, чтобы при неверном условии компиляция просто не происходила.

На всякий случай вставил сюда почти все свои общие макросы, вдруг ещё чего забыл :to_take_umbrage:

Спойлер

#define concatAB_(a, b) a##b
#define concatABC_(a, b, c) a##b##c
#define concatABCD_(a, b, c, d) a##b##c##d
#define concatABCDE_(a, b, c, d, e) a##b##c##d##e
#define concatABCDEF_(a, b, c, d, e, f) a##b##c##d##e##f
#define concatAB(a, b) concatAB_(a, b)
#define concatABC(a, b, c) concatABC_(a, b, c)
#define concatABCD(a, b, c, d) concatABCD_(a, b, c, d)
#define concatABCDE(a, b, c, d, e) concatABCDE_(a, b, c, d, e)
#define concatABCDEF(a, b, c, d, e, f) concatABCDEF_(a, b, c, d, e, f)
#define concatVOID
#define concat_SUBST2(a, b, c, d, e, f, g, h, i, j, k, l, ...) \
        a##b##c##d##e##f##g##h##i##j##k##l
#define concat_SUBST(...) concat_SUBST2(__VA_ARGS__)
#define concat(...) concat_SUBST(__VA_ARGS__, concatVOID, concatVOID, \
        concatVOID, concatVOID, concatVOID, concatVOID, concatVOID, concatVOID, \
        concatVOID, concatVOID)
#define selectA(a, ...) a
#define selectB(a, b, ...) b
#define selectC(a, b, c, ...) c
#define selectD(a, b, c, d, ...) d
#define selectE(a, b, c, d, e, ...) e
#define selectF(a, b, c, d, e, f, ...) f
#define lenof(var) (sizeof(var) * ((CHAR_BIT + 7) / 8))
#define ncell(m) (sizeof(m) / sizeof((m)[0]))
#define shift(a, b) (((b) > 0) ? (a) << (b): (!(b)) ? (a): (a) >> -(b))
#define ptrsizeof(m) (void *)&(m), sizeof(m)
#define offsetof(typ, member) (size_t)&(((typ *)NULL)->member)
#define sizof(typ, member) sizeof(((typ *)NULL)->member)
#define MIN(a, b) (((a) < (b)) ? (a): (b))
#define MAX(a, b) (((a) > (b)) ? (a): (b))
#define isMulti(a, b) ((a) / (b) * (b) == (a)) //a is a multiple of b?
#define divCeil(a, b) (((a) + (b) - 1) / (b))  //деление a/b с округлением до ближайшего большего целого
#define divRound(a, b) (((a) + (b) / 2) / (b)) //деление a/b с округлением до ближайшего целого
#define assert_static(x) ((x) ? 1: 1 / (x))    //проверка условия x и генерация ошибки компиляции если x==0
#define ASSERT_STATIC(x, n) enum {concatAB(ASSERT_STATIC_, n) = (x) ? 1: 1 / (uint)(x)} //аналогично assert_static(), но для вставки как строка кода, а не как выражение
#define TO_STRING_SUBST2(a) "" #a
#define TO_STRING(a) TO_STRING_SUBST2(a)
#define toSW(a, b) ((a) | (uint)(b) << 8)
#define toDW(a, b, c, d) ((a) | (u32)(b) << 8 | (u32)(c) << 16 | (u32)(d) << 24)
//Приведение x к типу UQ0.16, SQ1.15, UQ0.32, SQ1.31 соответственно.
#define toUQ16(x) ((((double)(x) * B16) >= B16) ? B16 - 1: (uint)((double)(x) * B16))
#define toSQ16(x) ((((double)(x) * B15) >= B15) ? (s16)(B15 - 1): (((double)(x) * B15) <= (s16)B15) ? 1 - (s16)B15: (int)((double)(x) * B15))
#define toUQ32(x) ((((double)(x) * B32) >= B32) ? B32 - 1: (u32)((double)(x) * B32))
#define toSQ32(x) ((((double)(x) * B31) >= B31) ? (s32)(B31 - 1): (((double)(x) * B31) <= (s32)B31) ? 1 - (s32)B31: (s32)((double)(x) * B31))
#define toSQ16s(x) ((((double)(x) * B15) >= B15) ? (s16)B15: ((double)(x) > 0) ? (s16)((double)-(x) * B15): assert_static(0))
#define toSQ32s(x) ((((double)(x) * B31) >= B31) ? (s32)B31: ((double)(x) > 0) ? (s32)((double)-(x) * B31): assert_static(0))

 

Второй аргумент ASSERT_STATIC() это просто порядковый номер этого макроса внутри данной области видимости где он используется. В приведённом коде - внутри функции MPUinit(). Если макрос используется не внутри функции, а просто в файле - то порядковый номер внутри этого файла. Я просто не смог придумать как сделать такую проверку без порядкового номера, в случае если в данной области видимости нужно использовать несколько ASSERT_STATIC(). Может кто придумает лучше, как обойтись без этого номера?

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


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

Только что, jcxz сказал:

На всякий случай вставил сюда почти все свои общие макросы, вдруг ещё чего забыл :to_take_umbrage:

Благодарю, поизучаю трюки:smile:

Сейчас просто решил для себя тоже создать некую базу удобных макросов, вот и собираю по крупицам интересные и полезные макросы для себя.

 

Только что, jcxz сказал:

Может кто придумает лучше, как обойтись без этого номера?

Использовать __LINE__? Правда, тогда ASSERT_STATIC нельзя будет использовать в одной и той же строке кода.

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


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

15 hours ago, jcxz said:

Может Вам поможет - приведу свою функцию инициализации MPU для проекта на таком же МК (STM32F429): 

Огромное спасибо! Не знаю поможет или нет, но не использовать имеющиеся в МК ресурсы, позволяющие увеличить надежность - это грех. Так что даже специальный Issue создал "задействовать MPU" в моем проекте, чтоб не забыть и не потерять. Копирайт в коде- jcxz/Omsk/Russia :)

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


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

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

Благодарю, поизучаю трюки:smile:

Я старался давать говорящие имена, но если что будет непонятно по макросам - спрашивайте.

Цитата

Использовать __LINE__? Правда, тогда ASSERT_STATIC нельзя будет использовать в одной и той же строке кода.

Спасибо!! Хорошее решение. Как то я не подумал про predefined preprocessor symbols. Проверил такое решение - работает. Только я использовал не __LINE__, а __COUNTER__. Теперь выглядит так:

#define ASSERT_STATIC(x) enum {concatAB(ASSERT_STATIC_, __COUNTER__) = (x) ? 1: 1 / (x)}

так можно и несколько их писать в одной строке (хотя я так не делаю :)

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

Копирайт в коде- jcxz/Omsk/Russia :)

:biggrin:

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


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

6 hours ago, jcxz said:

Может кто придумает лучше, как обойтись без этого номера?

Вы же используете IAR, так почему бы не использовать static_assert? Правда придётся задействовать компилятор Си++, но он же переварит сишный код.

6 hours ago, jcxz said:

#define sizof(typ, member) sizeof(((typ *)NULL)->member)

Название макроса... мммм... мягко говоря опасное:acute: Слишком коррелирует с sizeof.

21 hours ago, jcxz said:

Может Вам поможет - приведу свою функцию инициализации MPU для проекта на таком же МК (STM32F429)

Класс! Спасибо! Я думаю, для LPC4337 не слишком долго адаптировать, MPU-то всё равно платформенно независим:blum:

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


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

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

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

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

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

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

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

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

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

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