Jump to content

    
nanorobot

А может быть Holtek?

Recommended Posts

12 hours ago, Eddy_Em said:

И жутко жрет ресурсы МК...

А так ли часто нужно опрашивать устройства на 1-wire? Если это, конечно, не ключ DS1990. Другое дело, что если используется ОСРВ (Эдди, я знаю, это грех!) то, нужно обрамлять критическими секциями доступ к шине или опрашивать её в высокоприоритетном программном прерывании. Но я использую датчики температуры DS18B20 которые можно опросить раз в полминуты. Плюс, нагрузку на процессор можно посчитать.

Share this post


Link to post
Share on other sites
5 часов назад, haker_fox сказал:

если используется ОСРВ (Эдди, я знаю, это грех!) то, нужно обрамлять критическими секциями доступ к шине или опрашивать её в высокоприоритетном программном прерывании.

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

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

Если это, конечно, не ключ DS1990.

Тоже никаких проблем, достаточно отслеживать presense и только по ответу начинать обмен данных..

Share this post


Link to post
Share on other sites
On 10/12/2021 at 11:52 AM, adnega said:

Несколько раз сталкивался с обратной ситуацией, когда код становился быстрее и все переставало работать: например, включение АЦП в некоторых STM32 (F051, емнип).

Пользуясь этим замечанием, вернусь к моим баранам: GD32F. Тут @majorka65 заметил, что от темы Holtek ушли в HAL (хоть и тоже на "H"), но если мы об альтернативах, поговорим дальше о GD32F.

 

Мои изыскания по несовместимости I2C в STM32F1xx и GD32F1xx/3xx нарыли следующее.

 

Проблемы с GD32F возникают, когда мастер (процессор) делает транзакцию чтения; с записью (write only) все в порядке.

Изначально мой "драйвер" I2C писался под STM32F. Начиная со страницы 732 мануала Doc ID 13902 Rev 14 описаны различные методы транзакций с выделением особых случаев приема только одного или двух байтов, или же когда осталось принять три последних байта, если изначально надо было принимать больше. Все эти особые случаи и составляют всю сложность алгоритма при работе по прерываниям. Это усугубляется еще и тем, что уже в процессе приема (тактирования по SCL) в особых случаях нужно успевать снимать ACK или предварительно делать STOP, откуда идет рекомендация либо дать прерыванию по I2C наивысший приоритет в системе, либо обрамить критические участки запретом прерываний (чего я очень не люблю).

 

Я делал анализ предстоящей транзакции на предмет особый случаев в прерывании по биту SB (старт сгенерирован) перед передачей адреса ведомого с битом на чтение. При этом либо выставлялся бит POS для приема строго 2-х байтов, либо разрешалось прерывание BUFIE для остальных количеств. BUFIE генерирует прерывание по TXE, RXNE и/или BTF. Это все работало, пока не появился GD32F, который в отличие от STM32F, похоже, НЕ передает адрес, если выставлен бит BUFIE! Это приводило к тому, что бит SB залипал (он сбрасывается при записи адреса в DR), а бит ADDR не устанавливался вообще, и прерывание зацикливалось по SB. Как только я перенес принятие решения об особых случаях в ветвь обработки прерывания от уже установленного бита ADDR, все завелось, как на STM32F, так и GD32F.

 

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

Не могу вынести приговор, какой из процессоров ведет себя неправильно. С одной стороны, STM32F1 более старый, и может чего не досмотрели еще тогда, а в GD32F исправили. С другой стороны, почему GD32F физически не передает адрес, если уже установлено прерывание по буферу, которое реагирует на совсем другие биты, тоже не ясно.

 

Однако, я не случайно тут процитировал @adnega

 

Пока отлаживался, все работало. Затем собрал release с оптимизацией -O2, и... I2C на GD32F перестало работать, хотя на STM32F1 по-прежнему без проблем! Ничто не зацикливается, вылетает по ошибке неопределенного состояния, но делает что-то так, что периферия (не могу сказать, EEPROM или часы RV-3028-C7) садит SDA на ноль, пока не передернешь питание. Та же хрень на оптимизации -O1. Посмотрел на всякие переменные (управляющие структуры). Они volatile... Пока как workaround запретил оптимизацию самого файла драйвера I2C (всегда -O0), и тогда все работает.

 

Такi справи, малята...

 

Edited by KnightIgor

Share this post


Link to post
Share on other sites
3 minutes ago, KnightIgor said:

Затем собрал release с оптимизацией -O2, и... I2C на GD32F перестало работать, хотя на STM32F1 по-прежнему без проблем!

Абсолютно аналогичная ситуация у меня в проекте с CAN. Но некогда да и лень копать, оставил оптимизацию -O1, на ней все тип-топ.

Share this post


Link to post
Share on other sites
1 minute ago, Forger said:

Абсолютно аналогичная ситуация у меня в проекте с CAN. Но некогда да и лень копать, оставил оптимизацию -O1, на ней все тип-топ.

По какой оболочкой? Имел проблемы с -O2 оптимизированным кодом под CubeIDE, но тот же абсолютно код, собраный под KEIL с -O2, работает без проблем!

Share this post


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

Однако, я не случайно тут процитировал @adnega

Конкретно мой случай описан в ES:

Цитата

2.4.2 ADEN bit cannot be set immediately after the ADC calibration
Description:
At the end of the ADC calibration, an internal reset of ADEN bit occurs four ADC clock cycles after the ADCAL bit is cleared by hardware. As a consequence, if the ADEN bit is set within those four ADC clock cycles, it is reset shortly after by the calibration logic and the ADC remains disabled.
Workaround:
1. Keep setting the ADEN bit until the ADRDY flag goes high.
2. After the ADCAL is cleared, wait for a minimum of four ADC clock cycles before setting the ADEN bit.

Все очень долго работало в большом количестве изделий, но потом начали проявляться очень редкие события неинициализации АЦП,

видимо, после смены компилятора или ключей компиляции.

Сначала долго пытался отловить сам факт, затем пытался локализовать причину. Но подогнали образец, где вероятность глюка была высокая.

Затем нашел причину в ES.

В копилку историй "вчера-сегодня":

Сейчас бьюсь со старым проектом, исходник там "так-себе" - полно наглых приведений типа. В итоге сейчас получаю HF при использовании инструкции ldrd

на невыровненных данных. До этого у меня была устойчивая иллюзия, что Cortex-M3 и выше на невыровненных данных теряют такт, и на этом проблемы заканчиваются.

Это так, но не для всех команд! Видимо, старый компилятор не оптимизоровал до использования ldrd, и все работало.

Share this post


Link to post
Share on other sites
20 minutes ago, adnega said:

Все очень долго работало в большом количестве изделий, но потом начали проявляться очень редкие события неинициализации АЦП,

В последнем даташите на GD32F103C8 вычитал про 14 тактов после включение АЦП, причем именно тактов генератора АЦП, не ядра!

Исправил, сразу заработало. Для сравнения в ST нужно выдержать вроде всего пару тактов, причем ядра, не АЦП.

Quote

1. Ensure that ADCON=1.
2. Delay 14 ADCCLK to wa
3. Set RSTCLB (optional).
4. Set CLB=1.
5. Wait until CLB=0

 

 

Share this post


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

Для сравнения в ST нужно выдержать вроде всего пару тактов, причем ядра, не АЦП.

Цитата

four ADC clock cycles

Четыре клока АЦП (на F051). Кста, у других (F103) может быть по другому.

Share this post


Link to post
Share on other sites
2 minutes ago, adnega said:

Кста, у других (F103) может быть по другому.

STM32F103:

Quote

Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) for at least two ADC clock cycles.

Про такты ядра перепутал ) Речь о тактах АЦП

Share this post


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

По какой оболочкой? Имел проблемы с -O2 оптимизированным кодом под CubeIDE, но тот же абсолютно код, собраный под KEIL с -O2, работает без проблем!

То что "работает с определёнными ключами компиляции" не говорит ни о чём. Баг скорей всего в программе.

У меня драйвер на I2C на STM32 работает с любыми уровнями оптимизации (IAR) хоть с DMA хоть по прерываниям. Правда - на STM32F4. Работает интенсивно - на I2C висит пучок разных устройств, в том числе FRAM=32КБ.

Можно для пробы во всех ответственных местах, где в регистры управления I2C что-то пишется, добавить последующие обратное чтение этих регистров. Во многих случаях на регистрах периферии STM32 это помогает. У меня ранее при полной оптимизации по скорости и включении обоих кешей некоторая периферия начинала глючить. Добавил обратные чтения в эти места и всё исправилось. Правда эти глюки наблюдались не в медленном I2C, а в SPI и таймерах.

Например (часть ISR SPI):

    case IS_CMD_ARG:
      spiU->CR[0] = SPI_CR0(W) | B14 | B15;
      spiU->CR[1] = B1 | B5 | B6;
      spiU->CR[0] = SPI_CR0(W) | B14 | B15 | B6;
      RDMB(spiU->CR[0]);
      tdmaS->CR = 1 << DMA_CR_EN | 1 << DMA_CR_TEIE | 1 << DMA_CR_TCIE |
        1 << DMA_CR_DIR | 1 << DMA_CR_MINC |
        0 << DMA_CR_PSIZE | 0 << DMA_CR_MSIZE | DMAPRI_SPI_TX << DMA_CR_PL |
        concat(DMAREQ_S, nDMASTR_lcd_mems_TX, _SPI, nSPI_lcd_mems, _TX) << DMA_CR_CHSEL;
      isrStep = IS_DMATX;
      return;

где: spiU - указатель на блок регистров одного из SPI; а tdmaS - на блок регистров DMA-потока для него;

и:

#define DMB_READ        1   //==0 - квитировать записи в регистры периферии командой DMB; ==1 - ... обратным чтением регистра периферии; ==2 - выполнять 1-е + 2-е


#if DMB_READ == 0
#define RDMB(r) __DMB()
#elif DMB_READ == 1
#define RDMB(r) do { u32 dummy = r; } while (0)
#else
#define RDMB(r) do { __DMB(); u32 dummy = r; } while (0)
#endif

DMB_READ выставлен сейчас ==1.

Ранее, без этого обратного чтения (RDMB(spiU->CR[0])), при полной оптимизации и включении кешей, похоже на то, что запись в tdmaS->CR успевала выполниться раньше (физически), чем записываемое перед ним значение в spiU->CR[0] успевало доползти до цели (ведь SPI - на APB, а DMA - на AHB). Видимо из-за этого и происходили глюки. Выключение кеша и уменьшение уровня оптимизации до medium хотя-бы - проблема пропадала. Но это плохой костыль.

В таких местах (где сперва записывается значение в регистр одной периферии, а за ним - в другой (но при этом они в работе взаимосвязаны)) я обычно всегда ставил инструкцию DMB. Но на STM32 она не помогает почему-то в таких случаях. Потому завёл себе макрос RDMB(). В таком виде работает стабильно.

При работе с I2C у меня RDMB() нигде не используется, но возможно у меня в нём просто другой порядок работы с регистрами периферии чем у вас.

 

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

Сейчас бьюсь со старым проектом, исходник там "так-себе" - полно наглых приведений типа. В итоге сейчас получаю HF при использовании инструкции ldrd

Если IAR, то достаточно в таких местах приводить не к u64, а к __packed u64 - и всё наладится.  :wink:

Share this post


Link to post
Share on other sites

Мужики, ну если у вас код при разных степенях оптимизации по-разному работает, проблема только в вас самих. Где-то у вас в коде косяк: volatile пропустили, пустой цикл воткнули или еще что…

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.