Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Кэширование записи в RAM в LPC2478?
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
murug
Собственно при отладке программы наблюдаю спецэффекты, из которых напрашивается вывод о наличии этого самого кэширования. Оно действительно есть? Если да, то где про него почитать?
По ARM Architecture Reference Manual у меня создалось впечатление, что кэш присутствует у процессоров c MMU либо MPU, а разве LPC2478 к таким относится? В user manual'е на сам МК ни слова не нашел про это.
aaarrr
У ARM7TDMI нет ни кэша ни буфера записи.
murug
Цитата(aaarrr @ Oct 20 2015, 14:52) *
У ARM7TDMI нет ни кэша ни буфера записи.

Ну я это подозревал. Тогда придется изложить, что же я наблюдаю.

Код такой

В *.h-файле:
Код
__no_init volatile unsigned long ForceReprogrammingSignature @ 0x40008000;


В *.cpp-файле функция:
Код
void ForceReprogramming(bool Monopoly)
{
  ForceReprogrammingSignature = 0x085D0B75;
  
//  asm("nop"); // маленькая задержка в пять ассемблерных команд - если раскомментировать, не помогает (возвращается старое значение)
//  asm("nop");
//  asm("nop");
//  asm("nop");
//  asm("nop");
  
//  volatile unsigned long x = ForceReprogrammingSignature; // чтение (в ассемблере две команды) - если раскомментировать, помогает (сохраняется записанное значение)

//  vTaskDelay(10/portTICK_RATE_MS); // большая задержка в 10 мс - если раскомментировать, помогает (сохраняется записанное значение)

  if (Monopoly)
      __disable_interrupt(); // при Monopoly == true запрещаем прерывания

  PCLKSEL0_bit.PCLK_WDT = 1; // далее взводим WDT
  WDTC = CCLK / 4 * 5;    // на 5 секунд
  WDMOD_bit.WDEN = 1;
  WDMOD_bit.WDRESET = 1;
  WDCLKSEL_bit.WDSEL = 1;
  WDFEED = 0xAA;
  WDFEED = 0x55;

  if (Monopoly) // при Monopoly == true из функции не возвращаемся
      while (1);
}


Так вот, изначально в ForceReprogrammingSignature некое значение, назовем его "старым значением". Далее разные варианты:
1. Вызываем ForceReprogramming(false), она записывает в ForceReprogrammingSignature сигнатуру 0x085D0B75, назовем это "записанное значение", запускает WDT, возвращается, через 5 секунд программа перезапускается, видим в ForceReprogrammingSignature "записанное значение", все ок, вопросов нет.
2. Вызываем ForceReprogramming(true), она записывает в ForceReprogrammingSignature сигнатуру, без задержки запрещает прерывания (тем самым в частности останавливает планировщик FreeRTOS), запускает WDT, виснет в бесконечном цикле, через 5 секунд программа перезапускается, видим в ForceReprogrammingSignature "старое значение", офигеваем.
3. Вызываем ForceReprogramming(true) с раскомментированной задержкой на 10 мс, она записывает в ForceReprogrammingSignature сигнатуру, через 10 мс запрещает прерывания, запускает WDT, виснет в бесконечном цикле, через 5 секунд программа перезапускается, видим в ForceReprogrammingSignature "сохраненное значение".
4. Вызываем ForceReprogramming(true) с закомментированной задержкой на 10 мс, но с раскомментированным чтением, она записывает в ForceReprogrammingSignature сигнатуру, тут же считывает ее (две ассемблерные команды), запускает WDT, виснет в бесконечном цикле, через 5 секунд программа перезапускается, видим в ForceReprogrammingSignature "сохраненное значение".
5. Вызываем ForceReprogramming(true) с закомментированными задержкой на 10 мс и чтением, но с раскомментированной задержкой из пяти nop'ов, она записывает в ForceReprogrammingSignature сигнатуру, выполняет 5 пустых команд, запускает WDT, виснет в бесконечном цикле, через 5 секунд программа перезапускается, видим в ForceReprogrammingSignature "старое значение".

Вот и создается такое впечатление, как будто оператор
Код
ForceReprogrammingSignature = 0x085D0B75;
пишет физически в кэш, и если после этого сразу отключить прерывания, то значение из кэша не успевает сброситься в "настоящий" RAM, поэтому после перезагрузки по WDT снова читаем оттуда старое значение. Звучит бредово, поэтому ищу другую версию )
aaarrr
Цитата(murug @ Oct 20 2015, 15:34) *
Вот и создается такое впечатление, как будто оператор
Код
ForceReprogrammingSignature = 0x085D0B75;
пишет физически в кэш, и если после этого сразу отключить прерывания, то значение из кэша не успевает сброситься в "настоящий" RAM, поэтому после перезагрузки по WDT снова читаем оттуда старое значение. Звучит бредово, поэтому ищу другую версию )

А Вы проверяли в листинге наличие записи для ситуации, когда значение не меняется?
Все это больше похоже на "потерянный" квалификатор volatile.
murug
Цитата(aaarrr @ Oct 20 2015, 15:58) *
А Вы проверяли в листинге наличие записи для ситуации, когда значение не меняется?
Все это больше похоже на "потерянный" квалификатор volatile.

Согласен, похоже. Однако проверял - и код для записи присутствует, вот такой:
Код
MOV      R1,#+1073741824                
ORR      R1,R1,#0x8000                  
LDR      R2,??DataTable8_1;; 0x85d0b75
STR      R2,[R1, #+0]

во всех вариантах.
aaarrr
Можно все же увидеть листинг? Как-то уж очень чудесато это выглядит.
murug
Цитата(aaarrr @ Oct 20 2015, 16:25) *
Можно все же увидеть листинг? Как-то уж очень чудесато это выглядит.


Целиком функция, в первом случае работает корректно (это с заплаткой в виде чтения), во втором - нет.

Код
   \                                 In section .text, align 4, keep-with-next
    127          void ForceReprogramming(bool Monopoly)
    128          {
   \                     ForceReprogramming:
   \   00000000   0xE24DD004         SUB      SP,SP,#+4
    129            ForceReprogrammingSignature = FORCE_REPROGRAMMING_SIGNATURE;
   \   00000004   0xE3A01440         MOV      R1,#+1073741824
   \   00000008   0xE3811C80         ORR      R1,R1,#0x8000
   \   0000000C   0x........         LDR      R2,??DataTable8_1 ;; 0x85d0b75
   \   00000010   0xE5812000         STR      R2,[R1, #+0]
    130            volatile unsigned long x = ForceReprogrammingSignature;    // заплатка от непонятного бага с возвращением старого значения после сброса по WDT, см. http://electronix.ru/forum/index.php?showtopic=131171
   \   00000014   0xE5911000         LDR      R1,[R1, #+0]
   \   00000018   0xE58D1000         STR      R1,[SP, #+0]
    131          
    132            if (Monopoly)
   \   0000001C   0xE3500000         CMP      R0,#+0
   \   00000020   0x0A000002         BEQ      ??ForceReprogramming_0
    133                __disable_interrupt();
   \   00000024   0xE10F1000         MRS      R1,CPSR
   \   00000028   0xE38110C0         ORR      R1,R1,#0xC0
   \   0000002C   0xE121F001         MSR      CPSR_c,R1
    134              
    135            PCLKSEL0_bit.PCLK_WDT = 1;
   \                     ??ForceReprogramming_0:
   \   00000030   0x........         LDR      R1,??DataTable8_2 ;; 0xe01fc1a8
   \   00000034   0xE5912000         LDR      R2,[R1, #+0]
   \   00000038   0xE3C22003         BIC      R2,R2,#0x3
   \   0000003C   0xE3822001         ORR      R2,R2,#0x1
   \   00000040   0xE5812000         STR      R2,[R1, #+0]
    136            WDTC = CCLK / 4 * 5;    // на 2 секунды
   \   00000044   0xE3A014E0         MOV      R1,#-536870912
   \   00000048   0x........         LDR      R2,??DataTable8_3 ;; 0x55d4a80
   \   0000004C   0xE5812004         STR      R2,[R1, #+4]
    137            WDMOD_bit.WDEN = 1;
   \   00000050   0xE5912000         LDR      R2,[R1, #+0]
   \   00000054   0xE3822001         ORR      R2,R2,#0x1
   \   00000058   0xE5812000         STR      R2,[R1, #+0]
    138            WDMOD_bit.WDRESET = 1;
   \   0000005C   0xE5912000         LDR      R2,[R1, #+0]
   \   00000060   0xE3822002         ORR      R2,R2,#0x2
   \   00000064   0xE5812000         STR      R2,[R1, #+0]
    139            WDCLKSEL_bit.WDSEL = 1;
   \   00000068   0xE5912010         LDR      R2,[R1, #+16]
   \   0000006C   0xE3C22003         BIC      R2,R2,#0x3
   \   00000070   0xE3822001         ORR      R2,R2,#0x1
   \   00000074   0xE5812010         STR      R2,[R1, #+16]
    140            WDFEED = 0xAA;
   \   00000078   0xE3A020AA         MOV      R2,#+170
   \   0000007C   0xE5812008         STR      R2,[R1, #+8]
    141            WDFEED = 0x55;
   \   00000080   0xE3A02055         MOV      R2,#+85
   \   00000084   0xE5812008         STR      R2,[R1, #+8]
    142          
    143            if (Monopoly)
   \   00000088   0xE3500000         CMP      R0,#+0
   \   0000008C   0x0A000000         BEQ      ??ForceReprogramming_1
    144                while (1);
   \                     ??ForceReprogramming_2:
   \   00000090   0xEAFFFFFE         B        ??ForceReprogramming_2
    145          }
   \                     ??ForceReprogramming_1:
   \   00000094   0xE28DD004         ADD      SP,SP,#+4       ;; stack cleaning
   \   00000098   0xE12FFF1E         BX       LR              ;; return
   \   0000009C                      REQUIRE ForceReprogrammingSignature
   \   0000009C                      REQUIRE _A_PCLKSEL0
   \   0000009C                      REQUIRE WDTC
   \   0000009C                      REQUIRE _A_WDMOD
   \   0000009C                      REQUIRE _A_WDCLKSEL
   \   0000009C                      REQUIRE _A_WDFEED



Код
   \                                 In section .text, align 4, keep-with-next
    127          void ForceReprogramming(bool Monopoly)
    128          {
    129            ForceReprogrammingSignature = FORCE_REPROGRAMMING_SIGNATURE;
   \                     ForceReprogramming:
   \   00000000   0xE3A01440         MOV      R1,#+1073741824
   \   00000004   0xE3811C80         ORR      R1,R1,#0x8000
   \   00000008   0x........         LDR      R2,??DataTable8_1 ;; 0x85d0b75
   \   0000000C   0xE5812000         STR      R2,[R1, #+0]
    130          //  volatile unsigned long x = ForceReprogrammingSignature;    // заплатка от непонятного бага с возвращением старого значения после сброса по WDT, см. http://electronix.ru/forum/index.php?showtopic=131171
    131          
    132            if (Monopoly)
   \   00000010   0xE3500000         CMP      R0,#+0
   \   00000014   0x0A000002         BEQ      ??ForceReprogramming_0
    133                __disable_interrupt();
   \   00000018   0xE10F1000         MRS      R1,CPSR
   \   0000001C   0xE38110C0         ORR      R1,R1,#0xC0
   \   00000020   0xE121F001         MSR      CPSR_c,R1
    134              
    135            PCLKSEL0_bit.PCLK_WDT = 1;
   \                     ??ForceReprogramming_0:
   \   00000024   0x........         LDR      R1,??DataTable8_2 ;; 0xe01fc1a8
   \   00000028   0xE5912000         LDR      R2,[R1, #+0]
   \   0000002C   0xE3C22003         BIC      R2,R2,#0x3
   \   00000030   0xE3822001         ORR      R2,R2,#0x1
   \   00000034   0xE5812000         STR      R2,[R1, #+0]
    136            WDTC = CCLK / 4 * 5;    // на 2 секунды
   \   00000038   0xE3A014E0         MOV      R1,#-536870912
   \   0000003C   0x........         LDR      R2,??DataTable8_3 ;; 0x55d4a80
   \   00000040   0xE5812004         STR      R2,[R1, #+4]
    137            WDMOD_bit.WDEN = 1;
   \   00000044   0xE5912000         LDR      R2,[R1, #+0]
   \   00000048   0xE3822001         ORR      R2,R2,#0x1
   \   0000004C   0xE5812000         STR      R2,[R1, #+0]
    138            WDMOD_bit.WDRESET = 1;
   \   00000050   0xE5912000         LDR      R2,[R1, #+0]
   \   00000054   0xE3822002         ORR      R2,R2,#0x2
   \   00000058   0xE5812000         STR      R2,[R1, #+0]
    139            WDCLKSEL_bit.WDSEL = 1;
   \   0000005C   0xE5912010         LDR      R2,[R1, #+16]
   \   00000060   0xE3C22003         BIC      R2,R2,#0x3
   \   00000064   0xE3822001         ORR      R2,R2,#0x1
   \   00000068   0xE5812010         STR      R2,[R1, #+16]
    140            WDFEED = 0xAA;
   \   0000006C   0xE3A020AA         MOV      R2,#+170
   \   00000070   0xE5812008         STR      R2,[R1, #+8]
    141            WDFEED = 0x55;
   \   00000074   0xE3A02055         MOV      R2,#+85
   \   00000078   0xE5812008         STR      R2,[R1, #+8]
    142          
    143            if (Monopoly)
   \   0000007C   0xE3500000         CMP      R0,#+0
   \   00000080   0x0A000000         BEQ      ??ForceReprogramming_1
    144                while (1);
   \                     ??ForceReprogramming_2:
   \   00000084   0xEAFFFFFE         B        ??ForceReprogramming_2
    145          }
   \                     ??ForceReprogramming_1:
   \   00000088   0xE12FFF1E         BX       LR              ;; return
   \   0000008C                      REQUIRE ForceReprogrammingSignature
   \   0000008C                      REQUIRE _A_PCLKSEL0
   \   0000008C                      REQUIRE WDTC
   \   0000008C                      REQUIRE _A_WDMOD
   \   0000008C                      REQUIRE _A_WDCLKSEL
   \   0000008C                      REQUIRE _A_WDFEED



aaarrr
Такое не работать просто не может, а в чудеса не очень верится. Что будет, если записать несколько чисел подряд?
jcxz
Цитата(murug @ Oct 20 2015, 18:34) *
2. Вызываем ForceReprogramming(true), она записывает в ForceReprogrammingSignature сигнатуру, без задержки запрещает прерывания (тем самым в частности останавливает планировщик FreeRTOS), запускает WDT, виснет в бесконечном цикле, через 5 секунд программа перезапускается, видим в ForceReprogrammingSignature "старое значение", офигеваем.

И что?
Очевидно, что startup инитит эту Вашу ForceReprogramming неким значением, либо эта область используется ROM-загрузчиком, либо используется самим startup на какие-то его нужды, ...
Эксперимент проведён некорректно. Читайте юзермануал на предмет: какие области используются ROM-загрузчиком. И ставьте бряк не в функции main(), а сразу после вектора сброса.
Чудес не бывает.
murug
Цитата(jcxz @ Oct 21 2015, 07:36) *
И что?
Очевидно, что startup инитит эту Вашу ForceReprogramming неким значением, либо эта область используется ROM-загрузчиком, либо используется самим startup на какие-то его нужды, ...
Эксперимент проведён некорректно. Читайте юзермануал на предмет: какие области используются ROM-загрузчиком. И ставьте бряк не в функции main(), а сразу после вектора сброса.
Чудес не бывает.

По-моему Вы невнимательно читали. В переменной ForceReprogrammingSignature восстанавливается значение, которое там было до вызова функции ForceReprogramming. Каким бы это значение не было.
Ну и помимо того:
1. переменная помечена __no_init;
2. секция, в которую она помещена, указана для линкера do not initialize;
3. бряк ставил на первые выполняемые ассемблерные команды, уже там видел в отладчике "старое" значение в ForceReprogrammingSignature;
4. пробовал размещать переменную по двум разным адресам, результат один и тот же;
5. ну и в конце концов в случае описанных заплаток-то значение сохраняется.

Цитата(aaarrr @ Oct 20 2015, 23:34) *
Такое не работать просто не может, а в чудеса не очень верится. Что будет, если записать несколько чисел подряд?

Попробую.
Кстати, вспомнил - под отладчиком видел что внутри функции сигнатура 0x085D0B75 в переменную кладется. А вот после перезагрузки в самом начале cstartup.s - уже снова старое значение.
zltigo
QUOTE (murug @ Oct 21 2015, 08:55) *
...видел в отладчике "старое" значение в ForceReprogrammingSignature;

То есть весь этот вынос мозга Вы устраиваете по причине того, что сие оказывается "видит" отладчик?!



murug
Цитата(zltigo @ Oct 21 2015, 09:00) *
То есть весь этот вынос мозга Вы устраиваете по причине того, что сие оказывается "видит" отладчик?!

Не совсем.
То, что в ячейке "старое" значение, я вижу и без отладчика, но смотрю уже не на этапе выполнения cstartup.s, а после, когда все инициализации прошли и работает графический интерфейс у программы.
zltigo
QUOTE (murug @ Oct 21 2015, 09:09) *
Не совсем.
То, что в ячейке "старое" значение, я вижу и без отладчика, но смотрю уже не на этапе выполнения cstartup.s, а после, когда все инициализации прошли и работает графический интерфейс у программы.

Тем неменее
1) Никаких отладчиков для разборок с эффектом НЕ применять.
2) Никаких отображений далеко после старта через графический интерефейс - тоже.
Тупо и просто в startup НИЧЕГО сложнее, чем изменить состояние какого-нибудь пина не предпринимать. Причем изменеие состояния пина обязательно контролировать по времени от снятия сброса с контроллера.
murug
Цитата(zltigo @ Oct 21 2015, 10:10) *
Тем неменее
1) Никаких отладчиков для разборок с эффектом НЕ применять.
2) Никаких отображений далеко после старта через графический интерефейс - тоже.
Тупо и просто в startup НИЧЕГО сложнее, чем изменить состояние какого-нибудь пина не предпринимать. Причем изменеие состояния пина обязательно контролировать по времени от снятия сброса с контроллера.

Такие рекомендации исходя из предположения, что значение в ячейке все-таки какой-то программной инициализацией меняется, правильно я Вас понимаю?


Цитата(aaarrr @ Oct 20 2015, 23:34) *
Такое не работать просто не может, а в чудеса не очень верится. Что будет, если записать несколько чисел подряд?

Попробовал писать подряд несколько разных значений. Получается, что после рестарта имеем в ячейке значение, которое записывалось предпоследней записью. Это если без последующего чтения, а если с ним - то сохраняется с последней записи. В ассемблерном листинге последняя запись безукоризненно присутствует наряду со всеми.
aaarrr
Цитата(murug @ Oct 21 2015, 10:35) *
Попробовал писать подряд несколько разных значений.

Я имел в виду запись не нескольких значений в одну ячейку памяти, а запись нескольких слов в память последовательно.

Цитата(zltigo @ Oct 21 2015, 10:10) *
1) Никаких отладчиков для разборок с эффектом НЕ применять.

Вот да, лучше отключить его вообще на это время.
gerber
Классический механизм "posted write" ("отложенная запись"), всё правильно, процессор имеет право не исполнять физическую запись в устройство (в данном случае - это оперативная память) до следующей операции с ним, перед чтением вся очередь записей должна быть исполнена. Причём чтение может быть из любого другого адреса, а не обязательно того, куда производилась запись.
С кэшированием этот механиз имеет мало общего, так как в случае с кэшем отслеживается именно адрес доступа. Поэтому процессор может не иметь механизма кэширования, но запросто иметь отложенную запись.
murug
Цитата(gerber @ Oct 21 2015, 10:45) *
Классический механизм "posted write" ("отложенная запись"), всё правильно, процессор имеет право не исполнять физическую запись в устройство (в данном случае - это оперативная память) до следующей операции с ним, перед чтением вся очередь записей должна быть исполнена.

Вот этому верю, чего-то подобного и ожидал.
Встает вопрос, однако, где можно найти так сказать официальную инфу о наличии такой штуки в ARM7TDMI?
zltigo
QUOTE (murug @ Oct 21 2015, 10:35) *
Такие рекомендации исходя из предположения, что значение в ячейке все-таки какой-то программной инициализацией меняется, правильно я Вас понимаю?

Да. Такие изменения делает какой-то конкретный кусок кода. Противное было-бы чисто чудом. Чудес в 21 веке не бывает. Я лично использую подобный подход - занесение массива данных и считывания его после перезапуска, достаточно широко. Например, в любом моем загрузчике используется область памяти для сохранения картины exception. Тоже пишется массив, записывается сигнатура наличия данных. При запуске основной программы распечатывается. Нималейших проблем, в том числе и на LPC2468.
А чем вызвано фиксированное и причем в очень странном месте - середине памяти месторасположение этой сигнатуры? Нет, это как бы не криминал, но странно. Официально нельзя располагать подобное только в прследних 32 байтах памяти, которые используются заводским загрузчиком.


QUOTE (murug @ Oct 21 2015, 11:03) *
Встает вопрос, однако, где можно найти так сказать официальную инфу о наличии такой штуки в ARM7TDMI?

Нет такой штуки у несчастного ARM7. Не говоря уже о том, что после этой записи контроллер по любому у Вас производит неоднократные записи при манипуляции с WD.
aaarrr
Цитата(murug @ Oct 21 2015, 11:03) *
Встает вопрос, однако, где можно найти так сказать официальную инфу о наличии такой штуки в ARM7TDMI?

В ядре ничего подобного нет.

Буфер записи мог бы быть у контроллера встроенной SRAM, но:
- Об этом нигде не говорится
- Нет смысла в его наличии
murug
Цитата(zltigo @ Oct 21 2015, 11:11) *
Да. Такие изменения делает какой-то конкретный кусок кода. Противное было-бы чисто чудом.

Я бы понял, если бы этот кусок какое-то фиксированное значение в ячейку заносил. Но он угадывает, что там было до последней записи... Что по-моему является еще бОльшим чудом )
Цитата(zltigo @ Oct 21 2015, 11:11) *
Я лично использую подобный подход - занесение массива данных и считывания его после перезапуска, достаточно широко.

А такая ситуация, что после последней записи и перед перезагрузкой нет обращений к on-chip static RAM, у Вас возникает?
Цитата(zltigo @ Oct 21 2015, 11:11) *
А чем вызвано фиксированное и причем в очень странном месте - середине памяти месторасположение этой сигнатуры? Нет, это как бы не криминал, но странно. Официально нельзя располагать подобное только в прследних 32 байтах памяти, которые используются заводским загрузчиком.

Это уже в процессе экспериментов туда переместил, изначально как раз перед упомянутыми 32 байтами было.
Цитата(zltigo @ Oct 21 2015, 11:11) *
Нет такой штуки у несчастного ARM7. Не говоря уже о том, что после этой записи контроллер по любому у Вас производит неоднократные записи при манипуляции с WD.

Эти записи в область AHB или APB peripherals, а не on-chip static RAM, видимо дело в этом.


Вообще вроде удалось найти инфу (несколько зыбкую), что даже и кэш имеется:

Вот здесь:
Цитата
Naming Conventions
...
ARMx2z (e.g. ARM720T) indicates cache, MMU & Process ID support


А что 2478 - это ARM720T - например вот здесь
aaarrr
Цитата(murug @ Oct 21 2015, 11:48) *
А что 2478 - это ARM720T - например вот здесь

Нет, 2478 - это именно ARM7TDMI-S.
zltigo
QUOTE (murug @ Oct 21 2015, 11:48) *
А такая ситуация, что после последней записи и перед перезагрузкой нет обращений к on-chip static RAM, у Вас возникает?

Вообще-то сама "перезагрузка" это ВХОД В ЗАВОДСКОЙ загрузчик, где этих обращений явно хватает. Это раз. А то, что Ваши чудотворно действующие нопы это никак не обращение к памяти - это два.

QUOTE
А что 2478 - это ARM720T - например вот здесь

А это ничего, что ПРОИЗВОДИТЕЛЬ конроллера пишет о своем изделии в Product data sheet - ARM7TDMI-S processor, running at up to 72 MHz
aaarrr
Цитата(zltigo @ Oct 21 2015, 12:13) *
Вообще-то сама "перезагрузка" это ВХОД В ЗАВОДСКОЙ загрузчик, где этих обращений явно хватает.

Ну, "перезагрузка" - это еще и сброс, который мог бы очистить буфер записи при его наличии.
zltigo
QUOTE (aaarrr @ Oct 21 2015, 12:24) *
Ну, "перезагрузка" - это еще и сброс, который мог бы очистить буфер записи при его наличии.

При наличии - да. Но его нет, а есть напротив куча команд - ну тот-же вечный цикл продолжающийся 5 секунд и команды в нем выпоняющиеся как-бы ничем не хуже несеольких нопов, которые типа "помогают".

Вообще-то таинственные явления в NXP есть sad.gif - я не далее месяца тому назад в старом модернизируемом изделии на LPC2103 локализовал эффект, кода при работе SPI находящемся в режиме slave и тактирующимся софтовым мастером контроллер прерываний формировал нулевой вектор раз в несколько суток. Ничего из описанного в errata под этот эффект подогнать не удалось. Пришлось предпринимать близкие к шаманским действия sad.gif

QUOTE (murug @ Oct 20 2015, 15:34) *
PCLKSEL0_bit.PCLK_WDT = 1; // далее взводим WDT
WDTC = CCLK / 4 * 5; // на 5 секунд
WDMOD_bit.WDEN = 1;
WDMOD_bit.WDRESET = 1;
WDCLKSEL_bit.WDSEL = 1;
WDFEED = 0xAA;
WDFEED = 0x55;

А если к этому добавить:
CODE
  WDFEED = 0xAA;
  WDFEED = 0x5A;

то есть перезепуск без 5 секунд?
И еще, инициализация WD и в случае Monopoly=FALSE должна производиться при запрещенном прерывании, ибо любое вкоинивание прерывания это мгновенный перезапуск.
jcxz
Цитата(zltigo @ Oct 21 2015, 15:45) *
Вообще-то таинственные явления в NXP есть sad.gif - я не далее месяца тому назад в старом модернизируемом изделии на LPC2103 локализовал эффект, кода при работе SPI находящемся в режиме slave и тактирующимся софтовым мастером контроллер прерываний формировал нулевой вектор раз в несколько суток. Ничего из описанного в errata под этот эффект подогнать не удалось. Пришлось предпринимать боизкие к шаманским действия sad.gif

Давно уже работал с LPC2378, но вроде смутно помнится, что был подобный баг в контроллере прерываний. И он был описан в еррата. И даже в соотв. порту uCOS было указано.
Если это конечно он.
Заключался он в том, что при чтении адреса вектора прерывания из VIC, мог считаться ноль - это ложное прерывание.
Фрагмент моего ISR для IRQ где это проверяется:
Код
ISRirq:         SUB      LR, LR, #4
                STMFD    SP!, {R0-R3, R12, LR}
                MVN      R1, #255            ;VICAddress
                LDR      R0, [R1]
                CMP      R0, #0        ;проверка на ложное IRQ
                STRNE    R1, [R1]            ;acknowlege IRQ
                MOVNE    LR, PC
                BXNE     R0
                CMP      R0, #0
                LDMFDEQ  SP!, {R0-R3, R12, PC}^;выйти если нет сис. вызовов
                ...
murug
Цитата(zltigo @ Oct 21 2015, 12:13) *
Вообще-то сама "перезагрузка" это ВХОД В ЗАВОДСКОЙ загрузчик, где этих обращений явно хватает. Это раз. А то, что Ваши чудотворно действующие нопы это никак не обращение к памяти - это два.

Нет, я же написал, что нопы как раз не помогают.

Цитата(zltigo @ Oct 21 2015, 12:13) *
А это ничего, что ПРОИЗВОДИТЕЛЬ конроллера пишет о своем изделии в Product data sheet - ARM7TDMI-S processor, running at up to 72 MHz

Полагал, что 720T и TDMI-S - понятия из разных классификаций, собственно из той же пдф, на которую давал ссылку - там указано, что 720T это частный случай ARM7TDMI-S. Ну я сразу написал, что инфа зыбкая.


Цитата(zltigo @ Oct 21 2015, 12:52) *
И еще, инициализация WD и в случае Monopoly=FALSE должна производиться при запрещенном прерывании, ибо любое вкоинивание прерывания это мгновенный перезапуск.

О, действительно. Спасибо!
gerber
Помимо ядра процессора с памятью может работать и периферия, посредством DMA, возможно, сразу несколько каналов. При отсутствии механизма "posted write" процессору после каждого запроса операции чтения/записи пришлось бы ожидать завершения транзакции, открытой каким-нибудь каналом DMA. С чтением ничего не поделаешь - придется ждать, т. к. продолжение программы без прочитанного значения бессмысленно. А запись на дальнейшее исполнение кода не влияет (до ближайшего чтения), поэтому глупо "стоять в очереди" и ждать, когда можно "записать и забыть".
А не описан в руководстве на процессор он, видимо, потому, что имеет отношение скорее к внутренней шине типа AHB, APB, чем к самому ядру. Также как, например, механизм posted write на шине PCI - это фича PCI, а не процессора.
aaarrr
Цитата(gerber @ Oct 21 2015, 13:26) *
А не описан в руководстве на процессор он, видимо, потому, что имеет отношение скорее к внутренней шине типа AHB, APB, чем к самому ядру.

Память, на которой наблюдаются эффект, подключена к локальной шине процессора. Периферия к ней как раз доступа не имеет. Так что смысла нет буферизировать запись.
murug
Цитата(zltigo @ Oct 24 2015, 19:26) *

Мда... есть в документации на 21xx, но нет (либо еще не найдено) на 24xx.
Ну в любом случае вопрос можно считать закрытым.
Спасибо всем, кстати )
GetSmart
Цитата(aaarrr @ Oct 20 2015, 15:52) *
У ARM7TDMI нет ни кэша ни буфера записи.

У NXP есть - LPC288x. 8K кэша.

Цитата(jcxz)
Заключался он в том, что при чтении адреса вектора прерывания из VIC, мог считаться ноль - это ложное прерывание.

Часто в векторе IRQ стоит что-то вроде LDR PC,[PC, #-xxx]. Оптимальнее будет ложный нулевой адрес "ловить" в ResetVector-е по значению младших пяти бит CPSR, равных режиму IRQ.
zltigo
QUOTE (jcxz @ Oct 21 2015, 11:55) *
Давно уже работал с LPC2378, но вроде смутно помнится, что был подобный баг в контроллере прерываний. И он был описан в еррата.

Посмотрел еще раз в свежайшие errata - увы, ничего подобного не описано.
QUOTE
И даже в соотв. порту uCOS было указано.

Очень бы хотелось взглянуть на то, что в uCOS написано. Это было просто в исходниках откомментировано, или какой то документ?
QUOTE
Если это конечно он.

Описанной ситуации соответствует.
Явную заплатку не делал - стучал в бубен в месте опроса-сброса SPI прерывания. Но хотелось-бы явного понимания что надо делать.



QUOTE (GetSmart @ Nov 16 2015, 04:53) *
Часто в векторе IRQ стоит что-то вроде LDR PC,[PC, #-xxx]. Оптимальнее будет ложный нулевой адрес "ловить" в ResetVector-е по значению младших пяти бит CPSR, равных режиму IRQ.

Делал подобное для локализации проблемы вылета, но просто возвратиться не подумал. Пожалуй это вариант.
jcxz
Цитата(zltigo @ Nov 16 2015, 18:13) *
Очень бы хотелось взглянуть на то, что в uCOS написано. Это было просто в исходниках откомментировано, или какой то документ?

Я с LPC23xx последний раз работал уже неск. лет назад, а ещё раньше я переписал весь системный обработчик IRQ на свой собственный.
Так что из оригинального там остались только комменты о проверке на ложное IRQ с соответствующим кодом. Надо старые архивы поднимать если там что-то сохранилось.
Ну или скачать порт uCOS для ARM7 и посмотреть код стандартного обработчика IRQ.
Документ, кстати, тоже был, находится гуглом по фразе "spurious interrupts":
http://www.nxp.com/documents/application_note/AN10414.pdf
zltigo
QUOTE (jcxz @ Nov 16 2015, 15:30) *
Ну или скачать порт uCOS для ARM7 и посмотреть код стандартного обработчика IRQ.

Хорошо. Посмотрю. Но если говорить об этом:
QUOTE
Документ, кстати, тоже был, находится гуглом по фразе "spurious interrupts":
http://www.nxp.com/documents/application_note/AN10414.pdf

То это НЕ ТО о чем говорим. Заглушка на VIC Default Vector Address, естественно, стоит. То, что происходит, происходит по другому механизму - вектор считывается именно нулевой, хотя Default прописан. Вылетов по запрограммированному Default тоже можно добится, это я к тому, что эта ветка работает, но на ее фоне прилетает и нулевой вектор.
Появилось при использовании SPI Slave.
zltigo
QUOTE (jcxz @ Nov 16 2015, 15:30) *
Так что из оригинального там остались только комменты о проверке на ложное IRQ с соответствующим кодом. Надо старые архивы поднимать если там что-то сохранилось.
Ну или скачать порт uCOS для ARM7 и посмотреть код стандартного обработчика IRQ.

Зашел на микриум. Скачал порт - для LPC23xx. Убийственный по объему обработчик, но в конце действительно есть "Make sure we don't have a NULL pointer", но это собственно и все из комментариев. Отчего так делают объяснений нет.
Кстати, действий при считывании нулевого вектора тоже никаких - даже ACK контроллеру не делают - просто вернулись и все. Ну и VICDefVectAddr они НЕ УСТАНАВЛИВАЮТ вообще, так что это объясняет впихивание во все их "макроме" еще и проверки вектора на NULL.
jcxz
Цитата(zltigo @ Nov 16 2015, 23:08) *
Зашел на микриум. Скачал порт - для LPC23xx. Убийственный по объему обработчик,

Ну что поделаешь - система прерываний ARM7 далеко не оптимальна для организации вытеснения задач и вложенных прерываний.
Но ISR конечно там можно хорошо оптимизировать, что я и сделал.

Цитата(zltigo @ Nov 16 2015, 23:08) *
Кстати, действий при считывании нулевого вектора тоже никаких - даже ACK контроллеру не делают - просто вернулись и все. Ну и VICDefVectAddr они НЕ УСТАНАВЛИВАЮТ вообще, так что это объясняет впихивание во все их "макроме" еще и проверки вектора на NULL.

Странно... Я по своему коду вижу, что ACK я даю на нулевой вектор также как на валидный, просто не вызываю никакой прикладной обработчик ISR. И проверка на NULL не в конце ISR, а в начале.
Тем не менее множество наших счётчиков э-энергии на LPC2378 выпускаются уже несколько лет (уже наверное многие тысячи), работают в непрерывном круглосуточном режиме и проблем с прерываниями вроде не возникает.
Сама проверка - ничего страшного - всего одна доп. команда CMP R0, #0.
zltigo
QUOTE (jcxz @ Nov 17 2015, 06:56) *
Ну что поделаешь - система прерываний ARM7 далеко не оптимальна для организации вытеснения задач и вложенных прерываний.

Прямо противоположное мнение sm.gif. Просто вытеснение задач именно uCOS сделано конкретно через анус, ну а массовые вложеные вообще не нужны при операционке, тем более есть FIQ. То, как сделано у ARM7 так-же сделано у старших "A" кортексов явно заточеных под операционки, ну а для мелких "M" кортесов в которых справедливо предположили, что народ пойдет писать после всяких восьмибитовиков и в силе восьмибитовиков, сделали "удобный" NVIC.
QUOTE
Сама проверка - ничего страшного - всего одна доп. команда CMP R0, #0.

На фоне ужасно огромого обработчика перывания, как у uCOS - несомненно да.
zltigo
Дошли руки. Заплатку на NULL вектор вставил по варианту GetSmart на вектор сброса:
CODE
__start_entry:
            push     { r0 }
            mrs        r0, cpsr
            and     r0, r0, #MODE_MASK
              cmp     r0, #IRQ_MODE
            bneq       __start
            pop     { r0 }
            b        zero_vector_handler
__start:

Пытался всеми силами сэмулировать такой вылет, но как и ранее не удалось. Удается послать по этому пути только если явно для какого либо прерывания нагло прописать NULL вектор. При прописывании NULL вектора при возниконовении прерывания на официально документированный механизм заплатки через VICDefVectAddr не выходит. Так что смысл и в такой заплатке просмаривается не смотря на то, что ARM с NXP бьют себя пяткой в грудь и обещают, что установка VICDefVectAddr яко-бы решает проблемы неведомых прерываний.
Теперь остается понаблюдать за устройством в реальных условиях, как оно будет себя более мягко себя вести.
ar__systems
EMCStaticConfig0 bit 19
zltigo
QUOTE (ar__systems @ Feb 3 2016, 01:12) *
EMCStaticConfig0 bit 19

К чему это было? Разговор не о EMC.
ar__systems
Цитата(zltigo @ Feb 2 2016, 18:19) *
К чему это было? Разговор не о EMC.

Разговор был о кэшировании записи

а.... ок. это on-chip memory... да, тогда мимо
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.