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

GPIO interrupt: Rising & Falling Edge два в одном

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

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

В смысле? Если Вы разрешили прерывания и по фронту и по спаду, то вроде бы очевидно, что будут регистрироваться и те и другие.

Вы ожидали чего-то другого?  :wacko2:

13 часов назад, AlexandrY сказал:

А так есть известная бага связанная с медлительностью периферии портов по отношению к ядру у Сortex-ов 
Помогает __DSB();  на выходе из прерывания.   

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

По-крайней мере у меня в куче проектов на разных МК на Cortex-M нет ни одной DSB поставленной с этой целью. И тем не менее - всё прекрасно работает.

Да: иногда для корректного сброса какого-то флага в регистрах периферии, необходимо после записи в регистр (сбрасывающего значения) затем ещё и прочитать обратно этот регистр. Но что характерно - такое я встречал часто в периферии STM32. И причём это никак не оговаривалось в документации. Встречал такую необходимость и в некоторых регистрах периферии других МК других производителей, но там (в таких случаях) это явно указано в мануале (где это нужно).

Но DSB к этому случаю тоже никаким боком не относится, так как если заменить обратное чтение такого регистра командой DSB, то работа нарушается. Проверено неоднократно на разных регистрах STM32F4.

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


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

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

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

Пишут про механизм активизации прерывания и постановку прерывания в ожидание.

Вам уже правильно сказали - естественно, периферия не формирует флаги одновременно.
Может быть несколько различных ситуаций, при котором можно будет наблюдать такое поведение.
С концевика, понятное дело, может идти "гармошка" от дребезга контактов. Причем импульсы абсолютно разной ширины.
И, например, может получиться ситуация, когда период импульса меньше времени распространения сигнала от периферии в NVIC.
Но сами по себе фронты вполне различимы входными схемами синхронизации на GPIO. Будет сформировано 1 прерывание, а на GPIO будет установлено оба флага.
Другая ситуация, когда, например, находясь в высокоприоритетном прерывании от какой-то другой периферии, пришел импульс на GPIO. Будет такой же результат.

А может NVIC засекает и оба прерывания, но в момент обработки первого прерывания он видит и флаг второго на периферии.
В этом случае статус прерывания по GPIO на NVIC будет "активно и ожидает обработки". Можно сделать проверку на входе в прерывание перед очисткой флага.

А еще это зависит много от чего - например, как реализована конкретная линия запроса прерывания в NVIC - по импульсу или по уровню и т.д.

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


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

1 hour ago, haker_fox said:

Что готовое? Набросайте эскиз, как подключен датчик к ножке МК. Не забудьте указать длину кабеля, наличие экранов, как выполняется преобразование уровней.

готовая плата с разведенными ногами, клеммами и разъемами, в идеале с показометром и передатчиком в вышестоящую систему. 

Quote

Насколько я знаю, периферия может выставлять флаги, даже если прерывания не разрешены. Иначе бы поллинг флагов никогда не был бы возможен.User Manual на STM32F091.

В любом случае одновременное выставление двух противоположных флагов несколько нетривиально. Во всяком случае для меня.

Quote

User Manual на STM32F091

хм, в LPX мануалах такие подробности не описаны.  Если судить по описанию используется  логическое сравнение битов с маской, можно конечно это назвать фильтрацией, но ИМХО это будет натяжкой

Quote

Вы же сказали, что у вас конвейер, а это и искрящие двигатели/контакторы, помехи в сеть и т.п.

ну да. Только проблема в том, что когда все это гудит и крутится - с осциллографом не подлезть, а когда остановлено, то и этих двойных прерываний не приходит. В лабораторных условиях другое питание, земля и вообще все замечательно, а в боевых "получается как всегда". 

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


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

27 минут назад, Arlleex сказал:

Вполне естественный результат взаимодействия доменов с различными частотами и шинной инфраструктурой.

Я как правило, если в коде нужно произвести запись в регистры периферии, находящейся на разных шинах (доменах тактирования), при условии что эта периферия как-то взаимодействует между собой, использую команду DMB.

Например: Если нужно включить тактирование какого-то блока, а потом сконфигурить его регистры, то включаю тактирование, DMB, пишу в регистры. Или: инит DMA для обслуживания какой-то периферии, DMB, инит регистров периферии.

Ну или если есть возможность, то вместо DMB в данном случае можно использовать обратное чтение регистров, которые писал первыми.

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


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

3 минуты назад, jcxz сказал:

Я как правило, если в коде нужно произвести запись в регистры периферии...

Аналогично поступаю. Правда DSB использую. В некоторых исходниках вовсе видел последовательность DMB/DSB.

Честно говоря, ARM отдает реализацию интерфейса периферийной шины на откуп производителю МК, а тот в свою очередь неохотно пишет об особенностях.
В том числе, на какие регионы памяти периферии (атрибут Device, вроде как, согласно спецификации) распространяется буфер записи. И есть ли он вообще.

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


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

25 minutes ago, jcxz said:

В смысле? Если Вы разрешили прерывания и по фронту и по спаду, то вроде бы очевидно, что будут регистрироваться и те и другие.

Вы ожидали чего-то другого?  :wacko2:

Я ж говорю - неочевидно для меня, бестолкового. И в примерах эта ситуация старательно обойдена. Во многих других случаях неочевидные вещи описаны и в мануале и в примерах

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


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

10 minutes ago, jcxz said:

Я как правило, если в коде нужно произвести запись в регистры периферии, находящейся на разных шинах (доменах тактирования), при условии что эта периферия как-то взаимодействует между собой, использую команду DMB.

Например: Если нужно включить тактирование какого-то блока, а потом сконфигурить его регистры, то включаю тактирование, DMB, пишу в регистры. Или: инит DMA для обслуживания какой-то периферии, DMB, инит регистров периферии.

Ну или если есть возможность, то вместо DMB в данном случае можно использовать обратное чтение регистров, которые писал первыми.

 

3 minutes ago, Arlleex said:

Аналогично поступаю. Правда DSB использую. В некоторых исходниках вовсе видел последовательность DMB/DSB.

Честно говоря, ARM отдает реализацию интерфейса периферийной шины на откуп производителю МК, а тот в свою очередь неохотно пишет об особенностях.
В том числе, на какие регионы памяти периферии (атрибут Device, вроде как, согласно спецификации) распространяется буфер записи. И есть ли он вообще.

Можно фрагмент кода в качестве примера ?

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


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

7 минут назад, dimka76 сказал:

Можно фрагмент кода в качестве примера ?

void can_Init(void)
{
  rb_Init(&CANRxQ);
  
  EnCANClk(CAN_CAN_NUM);
  
  __DMB();
  __DSB();
  
  PCAN->MCR = B16 | CAN_MCR_INRQ;
  while(~PCAN->MSR & CAN_MSR_INAK);
  PCAN->MCR |= CAN_MCR_ABOM |
               CAN_MCR_RFLM |
               CAN_MCR_TXFP;
#define DIV  9
#define BS1 13
#define BS2  2
#define SJW  1
  PCAN->BTR = (SJW - 1) << 24 |
              (BS2 - 1) << 20 |
              (BS1 - 1) << 16 |
              (DIV - 1);
#undef DIV
#undef BS1
#undef BS2
#undef SJW
  PCAN->IER = CAN_IER_FMPIE0;
  NVIC_EnableIRQ(CANRX0IRQ);
  NVIC_SetPriority(CANRX0IRQ, 2);
  
  InitFilters();
  
  EnGPIOClk(CAN_GPIO_RX);
  EnGPIOClk(CAN_GPIO_TX);
  
  __DMB();
  __DSB();
  
  DefPinInPDis(CAN_GPIO_RX);
  DefPinAltPP(CAN_GPIO_TX);
  
  PCAN->MCR &= ~CAN_MCR_INRQ;
  while(PCAN->MSR & CAN_MSR_INAK);
}

 

Однако, бывает, что мануал просит выдержать какое-то количество тактов после включения периферии. Тут DMB/DSB не помогут.

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


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

36 минут назад, Arlleex сказал:

Тут DMB/DSB не помогут.

Нужны не DMB/DSB, а тупо любая задержка.

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


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

3 минуты назад, VladislavS сказал:

Нужны не DMB/DSB, а тупо любая задержка.

Может и так. Но в случае, если в RM нет требований по тактам, то вполне можно опираться на аппаратные средства AMBA.
А конкретно - использовать инструкции барьеров. Они сами знают, сколько тактов требуется для гарантированной записи.

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


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

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

хм, в LPX мануалах такие подробности не описаны. 

Там просто сказано, что их УАПП - клон 16С550. Подробности ищите в документации на оригинал.

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


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

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

Можно фрагмент кода в качестве примера ?

Фрагмента рестарта АЦП->DMA (АЦП тактируется от нескольких таймеров):

  fdmaU->CHEN = (1 << (nDMALINE_adc_fast & 7)) * 0x100;  //выключить fastADC DMA
...
  fdmaC->DAR = (u32)adcFastData[i1];
  fdmaC->SAR = (u32)&VADC.G[0].RES[8];
  fdmaC->CTL[1] = ncell(adcFastData[0][0].raw);
  __DMB();
  AtomicOr(&DLR.LNEN, 1 << nDMALINE_adc_fast);            //Включить DLR линию, сбрасывая ожидающий запрос
  __DMB();
  fdmaU->CHEN = (1 << (nDMALINE_adc_fast & 7)) * 0x101;   //Включить fastADC DMA
  __DMB();
  VADC.G[3].VFR = VADC.G[2].VFR = VADC.G[1].VFR = VADC.G[0].VFR = B16 - 1;
  __DMB();
  CCU_ADCF_S.TCSET = B0;                                  //start the fastADC timer
...

Здесь идут операции с IO-регистрами в последовательности: DMA, DLR (DMA Line Router), DMA, АЦП, таймер. Все эти периферийные блоки связаны между собой взаимодействиями (сигналами).

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


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

54 minutes ago, Arlleex said:
Spoiler


void can_Init(void)
{
  rb_Init(&CANRxQ);
  
  EnCANClk(CAN_CAN_NUM);
  
  __DMB();
  __DSB();
  
  PCAN->MCR = B16 | CAN_MCR_INRQ;
  while(~PCAN->MSR & CAN_MSR_INAK);
  PCAN->MCR |= CAN_MCR_ABOM |
               CAN_MCR_RFLM |
               CAN_MCR_TXFP;
#define DIV  9
#define BS1 13
#define BS2  2
#define SJW  1
  PCAN->BTR = (SJW - 1) << 24 |
              (BS2 - 1) << 20 |
              (BS1 - 1) << 16 |
              (DIV - 1);
#undef DIV
#undef BS1
#undef BS2
#undef SJW
  PCAN->IER = CAN_IER_FMPIE0;
  NVIC_EnableIRQ(CANRX0IRQ);
  NVIC_SetPriority(CANRX0IRQ, 2);
  
  InitFilters();
  
  EnGPIOClk(CAN_GPIO_RX);
  EnGPIOClk(CAN_GPIO_TX);
  
  __DMB();
  __DSB();
  
  DefPinInPDis(CAN_GPIO_RX);
  DefPinAltPP(CAN_GPIO_TX);
  
  PCAN->MCR &= ~CAN_MCR_INRQ;
  while(PCAN->MSR & CAN_MSR_INAK);
}

 

 

Однако, бывает, что мануал просит выдержать какое-то количество тактов после включения периферии. Тут DMB/DSB не помогут.

 

8 minutes ago, jcxz said:

Фрагмента рестарта АЦП->DMA:

Spoiler


...
  fdmaC->DAR = (u32)adcFastData[i1];
  fdmaC->SAR = (u32)&VADC.G[0].RES[8];
  fdmaC->CTL[1] = ncell(adcFastData[0][0].raw);
  __DMB();
  AtomicOr(&DLR.LNEN, 1 << nDMALINE_adc_fast);            //Включить DLR линию, сбрасывая ожидающий запрос
  __DMB();
  fdmaU->CHEN = (1 << (nDMALINE_adc_fast & 7)) * 0x101;   //Включить fastADC DMA
  __DMB();
  VADC.G[3].VFR = VADC.G[2].VFR = VADC.G[1].VFR = VADC.G[0].VFR = B16 - 1;
  __DMB();
  CCU_ADCF_S.TCSET = B0;                                  //start the fastADC timer
...

 

Здесь идут операции с IO-регистрами в последовательности: DMA, DLR (DMA Line Router), DMA, АЦП, таймер. Все эти периферийные блоки связаны между собой взаимодействиями (сигналами).

Спасибо !

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


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

2 hours ago, jcxz said:

Да: иногда для корректного сброса какого-то флага в регистрах периферии, необходимо после записи в регистр (сбрасывающего значения) затем ещё и прочитать обратно этот регистр.

А вы это опытным путём установили? Просто интересно, я бы не догадался до такого)

2 hours ago, evgen2 said:

В лабораторных условиях другое питание,

Я уже говорил ни один раз - ЭМС. Или вы недооцениваете такие проверки? Неужели вы вообще не испытываете своё устройство на промышленные помехи??? Я вам уже подсказали и другой путь - генератор произвольных сигналов. Без такого рода испытаний - ваш прибор фикция. И место ему на свалке. Если вы такие испытания провели, то почему-то молчите об этом. При этом уже битых три страницы идут какие-то удивления о работе периферии, о методах фильтрации и ничего больше по делу. Как будто бы это нам, а не вам надо.

 

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


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

12 минут назад, haker_fox сказал:

А вы это опытным путём установили? Просто интересно, я бы не догадался до такого)

Примерно так. Сначала как во всех других МК поставил DMB, то потом обнаружил, что при полной оптимизации и выполнении из флешь с включённым кешем оно стало иногда сбоить (непериодически, но так как я только что сделал такие модификации кода, то сразу заметил связь). (При полной оптимизации и выполнении из ОЗУ, или выполнении из флешь, но с выключенным кешем 0 всё ок - год так работало без сбоев).

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


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

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

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

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

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

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

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

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

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

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