Jump to content

    
Sign in to follow this  
evgen2

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

Recommended Posts

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

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

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

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

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

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

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

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

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

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

Share this post


Link to post
Share on other sites
1 час назад, evgen2 сказал:

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

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

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

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

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

Share this post


Link to post
Share on other sites
1 hour ago, haker_fox said:

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

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

Quote

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

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

Quote

User Manual на STM32F091

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

Quote

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

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

Share this post


Link to post
Share on other sites
27 минут назад, Arlleex сказал:

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

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

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

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

Share this post


Link to post
Share on other sites
3 минуты назад, jcxz сказал:

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

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

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

Share this post


Link to post
Share on other sites
25 minutes ago, jcxz said:

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

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

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

Share this post


Link to post
Share on other sites
10 minutes ago, jcxz said:

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

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

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

 

3 minutes ago, Arlleex said:

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

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

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

Share this post


Link to post
Share on other sites
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 не помогут.

Share this post


Link to post
Share on other sites
3 минуты назад, VladislavS сказал:

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

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

Share this post


Link to post
Share on other sites
1 час назад, evgen2 сказал:

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

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

Share this post


Link to post
Share on other sites
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, АЦП, таймер. Все эти периферийные блоки связаны между собой взаимодействиями (сигналами).

Share this post


Link to post
Share on other sites
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, АЦП, таймер. Все эти периферийные блоки связаны между собой взаимодействиями (сигналами).

Спасибо !

Share this post


Link to post
Share on other sites
2 hours ago, jcxz said:

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

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

2 hours ago, evgen2 said:

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

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

 

Share this post


Link to post
Share on other sites
12 минут назад, haker_fox сказал:

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

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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this