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

Arlleex

Свой
  • Постов

    6 330
  • Зарегистрирован

  • Посещение

  • Победитель дней

    19

Весь контент Arlleex


  1. Однако я тогда не совсем понимаю, какая у Вас гарантия того, что данные успешно передадутся, да еще в нужное время. Если в Вашем устройства (на макете) замкнуть SCL на SDA пинцетом, затем убрать - связь восстановится? Если восстановится - то не понимаю, какая магия у Вас мониторит, что нужные флажки не взвелись через определенное время и сбрасывает автомат. Ведь идеологически любая конструкция while(ожидание флага); должна сопрягаться с установкой таймаута ожидания (не важно, средствами ОС или же аппаратным таймером). Ведь слова ставят встречный вопрос - каким же образом можно узнать результат транзакции? Ведь после установки битов управления (тот же START-бит), нужно некоторое время, чтобы в регистре статуса этот бит был выставлен и сгенерировалось прерывание. Если, как было указано выше, бесконечно ожидать, то получится полная лажа при какой-либо помехе на I2C-шине. Таймаут-то по-любому нужен, как без него...
  2. Я тоже ничего не понял про ACK во время START... Вообще таких вещей протокол не предусматривает. Есть четкая последовательность выдачи сигналов на линии. Да, бывают сбои по различным причинам - от мощных переключателей вне устройства, например, происходит рассинхронизация приемника и передатчика путем вставки "лишнего" clock-а. Я, например, всегда придерживаюсь стратегии следующего рода: если процессор очень шустрый, периферия медленная, но есть DMA - я всегда работаю с DMA. I2C в STM32F429 также поднимал с обработкой всех ошибок. Я делал так: // HW_ExchangeTransmitData - функция отправки данных по внешнему каналу обмена. // Параметры: // Buffer - указатель на буфер передаваемых данных; // Size - объем данных в байтах. // Возвращаемое значение: // HW_EXCHANGE_TRANSMIT_OK - отправка успешно запущена; // HW_EXCHANGE_TRANSMIT_ERROR_TIMEOUT - канал обмена занят транзакцией данных. unsigned int HW_ExchangeTransmitData(void *Buffer, unsigned int Size) { HW_EXCHANGE_TIMER_START(65535); while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) && !ExchangeBusyStatus); HW_EXCHANGE_TIMER_STOP(); unsigned int PhysicalBusy = ExchangeBusyStatus; ExchangeBusyStatus = 0; if(PhysicalBusy) return HW_EXCHANGE_TRANSMIT_ERROR_TIMEOUT; else { ExchangeTxDataQuantity = Size; DMA_MemoryTargetConfig(DMA1_Stream6, (unsigned int)Buffer, DMA_Memory_0); DMA_SetCurrDataCounter(DMA1_Stream6, ExchangeTxDataQuantity); I2C_GenerateSTART(I2C1, ENABLE); HW_EXCHANGE_TIMER_START(1); return HW_EXCHANGE_TRANSMIT_OK; } } При отправке я сначала смотрю, а не занят ли модуль I2C прошлой транзакцией. Чтобы вечно не тупить в цикле ожидания BUSY, покрываю проверку аппаратным таймером на максимальную длину посылки через DMA. Если занят - говорю что вышел таймаут ожидания и выхожу из функции. Чуть позже добавлю сюда просто ожидание семафора, чтобы освободить задачу (эта функция крутится в составе ОСРВ). После того как I2C освободился, заполняю служебные переменные размера передаваемого сообщения, настраиваю DMA, но не включаю его. Формирую условие START и запускаю контролирующий таймер на минимальный интервал передачи одного байта. Теперь выхожу из функции - вся остальная работа будет сделана в прерывании. void I2C1_EV_IRQHandler(void) { if(I2C_GetITStatus(I2C1, I2C_IT_SB) == SET) { ExchangeDirection = HW_EXCHANGE_DIRECTION_TRANSMITTER; HW_EXCHANGE_TIMER_STOP(); I2C_Send7bitAddress(I2C1, HW_EXCHANGE_I2C_ADDRESS_ABONENT, I2C_Direction_Transmitter); HW_EXCHANGE_TIMER_START(1); return; } if(ExchangeDirection == HW_EXCHANGE_DIRECTION_RECEIVER) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; if(I2C_GetITStatus(I2C1, I2C_IT_ADDR) == SET) { if(!ExchangeOverrunStatus) { ExchangeOverrunStatus = 1; DMA_MemoryTargetConfig(DMA1_Stream0, ExchangeRxDataBuffer, DMA_Memory_0); DMA_SetCurrDataCounter(DMA1_Stream0, ExchangeRxBufferSize); DMA_ClearFlag(DMA1_Stream0, DMA_FLAG_TCIF0); DMA_Cmd(DMA1_Stream0, ENABLE); } else System.ExchangeStatus |= SYSTEM_EXCHANGE_STATUS_RX_ERROR_DATA_OVERRUN; (void)I2C_GetFlagStatus(I2C1, I2C_FLAG_TRA); } if(I2C_GetITStatus(I2C1, I2C_IT_BTF) == SET) { (void)I2C_ReceiveData(I2C1); System.ExchangeStatus |= SYSTEM_EXCHANGE_STATUS_RX_ERROR_BUFFER_OVERFLOW; } if(I2C_GetITStatus(I2C1, I2C_IT_STOPF) == SET) { if(DMA_GetCmdStatus(DMA1_Stream0) == ENABLE) DMA_Cmd(DMA1_Stream0, DISABLE); if(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == SET) { (void)I2C_ReceiveData(I2C1); System.ExchangeStatus |= SYSTEM_EXCHANGE_STATUS_RX_ERROR_BUFFER_OVERFLOW; } *ExchangeRxDataQuantity = ExchangeRxBufferSize - DMA_GetCurrDataCounter(DMA1_Stream0); xSemaphoreGiveFromISR(ExchangeRxSemaphoreHandle, &xHigherPriorityTaskWoken); I2C_GenerateSTOP(I2C1, DISABLE); } portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } else { BaseType_t xHigherPriorityTaskWoken = pdFALSE; if(I2C_GetITStatus(I2C1, I2C_IT_ADDR) == SET) { HW_EXCHANGE_TIMER_STOP(); DMA_ClearFlag(DMA1_Stream6, DMA_FLAG_TCIF6); DMA_Cmd(DMA1_Stream6, ENABLE); (void)I2C_GetFlagStatus(I2C1, I2C_FLAG_TRA); HW_EXCHANGE_TIMER_START(ExchangeTxDataQuantity + 1); } else if(I2C_GetITStatus(I2C1, I2C_IT_BTF) == SET) { HW_EXCHANGE_TIMER_STOP(); I2C_GenerateSTOP(I2C1, ENABLE); ExchangeDirection = HW_EXCHANGE_DIRECTION_RECEIVER; xSemaphoreGiveFromISR(ExchangeTxSemaphoreHandle, &xHigherPriorityTaskWoken); } portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } В прерывании обрабатываются все события I2C в зависимости от приема или передачи, при этом каждый шаг контролируется защитным временным интервалом в зависимости от количества передаваемых данных. Таким образом, все сошлось к следующему: 1. Настроить DMA. 2. Выдать на линию START-условие. 3. Ждать в прерывании установки события START (SB). 4. Запустить передать физический адрес устройства. 5. Ждать в прерывании установки события окончания передачи адреса (ADDR). 6. Запустить DMA. 7. Ожидать в прерывании установки события BTF. 8. Выдать на линию STOP-условие. На почти каждый шаг накладывается штрафной таймер, контролирующий выполнение текущего шага. Этот код работает очень долго и стабильно. Обработка ошибок возложена на вышестоящие функции, как видно, в системный журнал ошибок (структура System) постоянно сваливаются нужные флаги.
  3. На полке лежит отладка с SIM800C, китайская с Aliexpress. Как раз на нее были планы с Bluetooch поиграться, GSM был вторичен. Но jcxz прям подлил масла в огонь ненависти к продукции SIMCOM Давно наслышан о лютых багах в работе модулей этой компании... Причем действительно не совсем понятно, откуда ТАКОЕ количество ошибок и недокументированных ситуаций. Куда у них смотрит отдел тестирования?
  4. Да вот элементарный пример, решение которого полностью решило бы такую проблему. Возможно ли в STM32F4 настроить периодическую отправку в SPI по DMA? Я бы настроил событие по совпадению таймера 5000 раз в секунду пинать DMA, чтобы он положил данные в SPI->DR. Началась бы передача, по завершении которой выставился флаг RXNE, который пинал бы другой канал DMA, и тот складировал данные в буфер и говорил мне когда нужный объём данных наберётся для передачи по другому интерфейсу разом. DMA устроен же так, что в режиме память-регистр я могу указывать только адрес регистра только того модуля, который пнул этот канал DMA, а как было бы здорово по запросу DMA от таймера сделать пересылку в SPI-DR, то есть в модуль, который не пинал этот DMA. Периодические вещи, например, отправки или прием данных по разным интерфейсам, в том числе SPI, стали бы возможны вовсе без участия процессора!
  5. Ну программируемой логикой можно все, конечно, поправить, но видится аппаратным костылем (перфекционист детектед). Да, не дергается ножка у него... Хотел сделать хитросплетенную логику на механизмах совпадения в таймерах, DMA и SPI, и все равно уперся в другую неприятную особенность, склеившей ласты на задумке. Чем меня привлекают STM32 - в плане частот ядер они вроде как всегда впереди... Да и самих ядер. Если ARM что-то выпускает, они тут же подхватывают это и делают новые микроконтроллеры. Ну а по периферии - не агонь. Все-таки присматриваюсь к XMC4, LPC пока что даже не смотрел. Вообще думаю проштудировать получше рынок МК на базе Cortex-M. А вообще некоторое время назад на глазах промелькнул некий Renesas-овский процессор RZ-A1 Cortex-A9. 10МБайт встроенного ОЗУ выглядят очень внушительными.
  6. jcxz, как раз листаю референс на XMC4800. Общее впечатление - на днях сделаю себе отладку и попробую разобраться в новой для себя стилистике документации :rolleyes:
  7. Атмел точно умеет - проверял лично. Но камешки некоторые (на которых и проверял, собственно) морально устарели. Никто не заставляет, на самом деле :laughing: Просто было закуплено на лабораторию ведра STM32 разных калибров для как раз задач широкого применения, не требующих внушительной производительности. Когда задача описана словами "надо дискретизировать сигнал 5000 выборок/сек и передать отсчеты наружу...", невольно понимаешь, что STM32 тут за глаза. И вот лишь когда начинаешь детальнее входить в архитектуру программы, понимаешь, что программа будет сущий костыль... Видимо, этот CS у SPI не дает мне покоя Пожалуй, нужно будет ознакомиться, благодарю.
  8. На что бы перейти...

    С практикой работы с STM32 у меня пополняется чаша больше ненависти к этим камням, нежели положительных эмоций. Вот элементарно - есть АЦП внешний, управляется через SPI, CS-ом дергать обязательно. В STM32 CS не дергается аппаратно при транзакциях SPI, не понимаю, почему эти говноразработчики из STMicroelectronics не могут сделать это уже в какой реализации своих линеек микроконтроллеров? Из-за такого намеренного "косяка", который они вроде как и не пытаются исправить, невозможно запустить DMA на этот SPI, приходится запускать чертов таймер, дергать лапой в прерывании и там же запускать транзакцию (одиночную), потом снова выжидать нужное время и поднимать CS обратно, формируя нужные длительности между CS и первым/последним клоком SCLK... Помню в AT91SAM7X512 (и младших по памяти моделях) была возможность не то что аппаратно лапкой CS дергать, так даже время задавалось в количествах тактов вот этих самых задержек. А тут фигу. С ходу даже не придумал как аппаратным таймером ножку аппаратно дергать так, чтобы еще после опускания CS выжидалось время небольшое и затем осуществлялась транзакция по SPI без прерываний, по DMA , например. И, чувствую, такой возможности тупо нет. Хотя, казалось бы, банальная вещь - что сложного было реализовать полностью аппаратный CS? Урезали половину функциональности DMA<->SPI... И вот знаете, косяков все больше и больше обнаруживается с каждым детальным разбором. Какие камни наиболее гибкие в этом плане? ПЛИС не в расчет, знаю что там проще сделать такое и т.д. но интересует возня именно с Cortex-M профиля. Раньше немного работал с ARM7TDMI, но это уже устаревший камень, Cortex-ы для меня более привлекательны, хотелось бы что-то действительно с хорошей периферией. Прокомментируйте, пожалуйста.
  9. И действительно, ответ на вопрос был ближе, чем я мог думать. Большое спасибо всем, кто откликнулся :beer:
  10. Стало интересно разобраться с Cortex-M3 поглубже, так сказать. У ARM есть презентационный pdf-файлик, в котором есть следующая картинка: Ну, в общем-то, криво-косо, но примерно оно так укладывается на реализованную систему команд и диаграмму работы конвейера. Криво-косо, наверное потому, что рисунок выше не претендует на полноту информации и, в общем-то, часть, возможно, важной информации не отражена. В общем, есть вот на рисунке Write Data Register и Read Data Register. И вот они заходят на один из портов чтения/записи регистрового файла. Данные регистры, насколько моя логика смогла представить, необходимы для реализации команд Load/Store. Дальше я был удивлен, что шины данных (именно данных) реально две - первая шина данных записи, вторая - шина данных чтения. И действительно, Cortex-M3 реализует шинную инфраструктуру согласно протоколу AMBA 3 AHB-Lite Protocol. В ней действительно шин данных две: Буквально наискосок пролистав данный документ, стало понятно (а может плохо смотрел?), что сигнал RW физически один - то есть подчиненное устройство (Slave, см. документ), например, встроенная SRAM-память микроконтроллера, всего лишь осуществляет запись и чтение по различным шинам, и в один момент времени этого делать не могут (нельзя поставить двухпортовую память, например). Ну вот и какой выигрыш тогда от двух раздельных шин? Ведь это как-то достаточно жирно выглядит, протащить 32 бита до каждого Slave и еще потом замультеплексировать все это... В голове, конечно, много разных мыслей на этот счет, но все это лишь догадки. Гуру, отзовитесь, пожалуйста :rolleyes:
  11. На самом деле интересная идея, но не совсем понятно, как именно отслеживается зависание. Ну не ответила задача - вполне может быть, что у неё время выполнения большое. Не совсем понял Вашего механизма, если честно. Да и период пингуюшей задачи, не понятно, должен ли как-то зависеть от периодов задач, которые подвергаются контролю?
  12. К Вашему сведению: в формате Little-Endian младший байт располагается по младшему адресу, старшее - по старшему.
  13. Теперь понял, большое спасибо :rolleyes: А то пишут в статьях всяких что ограничитель имеет низкие емкости (бла-бла покупайте ставьте в сигналы и т.д.), отсюда и непонимание пошло... Кстати вот тут пишут, что схема "ограничитель с диодами" просто экономичнее - ведь по сути нужен всего лишь один ограничитель на все линии, вместо ограничителей на каждую линию. А диоды просто "стравливают" излишнее напряжение на один ограничитель. По сути прикрутить к корпусу прибора (он металлический и заземлен).
  14. С этим да, понял. Понял, что Вы имели в виду - что есть просто ограничители: а есть сборка диодов "rail-to-rail" с такими же ограничительными TVS-диодами: Тот аппноут, который я привел выше, не приводит основных характерных признаков, при которых я должен применять ту или другую схему защиты, в связи с этим слова вносят мне небольшой когнитивный диссонанс. С чем связана такая необходимость применения второго варианта (именно сборка диодов и ограничителя)? С этим, в общем-то, ясность некоторая была, только лишь не понятно, по какой цепи потечет в этом случае ток помехи (той самой, которую породила молния на линии).
  15. Ну на самом деле у Analog Devices есть и многоканальные цифровые изоляторы, применение которых будет существенно дешевле, чем одиночных... На самом деле я лишь ищу максимально грамотного решения, ведь если у меня в полевых условиях сломается блок - огребу больших проблем :smile3046: Прошу прощения за возможную некомпетентность в данном вопросе, просто я, прочитав статьи и вот такой Application Note, пришел к выводу, что сборка TVS диодов как раз и выполняют роль ограничителя, ну разве нет? Ограничивают же напряжение на уровне обратного пробоя, м? :) По поводу разрядника я все же не понимаю, хоть убейте. Если линия якобы "защищена" уже трансилами TVS, зачем ее защищать еще и разрядником? Нашел где-то в Интернете вот такое типовое решение, похоже это то, о чем Вы говорите: Искренне желаю докопаться до истины, разобравшись раз и на всегда, как говорится. Также по поводу приведенного выше цифрового изолятора: у него еще и входная цепь имеет собственное питание. Питание получается тоже ведь защищать надо каким-то образом, ведь думаю, что если я искрану на любую из линий кабеля (данные или вход питания) - что-то явно повредится. Также не менее важным вопросом является влияние на защищаемый сигнал (емкость тех же TVS-диодов или разрядника). Спасибо, этих тараканов удобно хоть разводить на плате будет :rolleyes:
  16. Я бы посмотрел, как Вы "HAL stm-овский проект, который активно развивается и его вылизывают на сотнях, тысячах проектов..." на самолетный блок поставили бы, и если ни дай бог оно откажет или вывалится в HardFault... Тенденция лепить говно везде, я смотрю, очевидно набирает обороты. В общем, с Вами мне все понятно, обсуждать тут и нечего. Всего Вам наилучшего :laughing:
  17. Гальваническая развязка в моем случае обеспечит защиту дорогих ПЛИС и МК на плате. Если же входной буфер только пострадает - то и пусть лучше так... Поэтому если ваши слова "защита ради защиты" - сарказм, то я его не понял Вот, так мне более понятно, потому что это почти так, как у меня на схеме выше. Правда, если честно, не совсем понял про разрядник (как Вы имели ввиду его подключить), и какую роль он будет выполнять (ведь по входам будет стоять ограничитель (в моем понимании это сборка диодов TVS)).
  18. Как бы эту тему перетащить в обсуждение давно созданной темы... При этом, все-таки, схема остается не развязанной. Хочется, все-таки, совершенно отвязаться от внешнего мира. 1. Насколько я понял, гальваническая развязка защищает устройство лишь от попадания внешних высоких напряжений непосредственно на входы МК. Вот, например, есть вот такой цифровой изолятор. Пишут, что 3кВ RMS у него изоляционный барьер держит. Однако это ведь, по факту, означает, что при попадании 3кВ разряда на входы микросхемы, изолированная сторона останется целой, а сгорит лишь изолирующая сторона. 2. Поэтому для защиты изолирующего входа нужно как-то ограничить попадание статики (даже с пальцев, когда в свитере ходишь) на входы данного цифрового изолятора. Параллельно линиям ставим защитные низковольтные защитные варисторы/tvs-диоды/супрессоры. Таким образом будет обеспечена развязка сигналов от внешнего мира (3кВ) микросхемой цифрового изолятора, а сами ее входы защищены ESD-протекторами (варисторы, либо tvs-диоды, либо супрессоры). Видел еще схемы, где статика через конденсатор на корпус прибора стекала, однако у меня есть и дискретные входы, для которых такое, возможно, и сгодится, и сигнальные интерфейсные линии, где с таким конденсатором фронты сигналов загнутся и это будет хрен пойми что Схему прилагаю, как я это вижу... Верно ведь? :laughing:
  19. Пардон, в глазу бревна не заметил к своему стыду
  20. Добрый день! Как правильно защитить входы устройства от статического напряжения и повреждения элементов управления (микроконтроллер, ПЛИС и т.д.)? Есть длинный кабель с дискретными сигналами, его могут подключить "на горячую", либо без заземления, либо совместно (делаю защиту от дурака, так сказать, не хочется навредить устройству вот такими манипуляциями). Правильна ли следующая цепочка: Кабельная шина -> вход устройства -> защита ESD -> оптическая развязка -> микроконтроллер/плис?
  21. Для этого и существует форум, ИМХО, для обмена опытом и т.д. Между прочим, такие вещи в книгах особо и не описываются, поэтому даже грамотные специалисты могут и не знать не помнить каких-то подводных камней... Отдельное спасибо jcxz за пример оптимизирующего решения. Я же все никак до ассемблера кортексов не доберусь...
  22. Привел код. Скомпилировал на C++ Builder 2010 и в DevC++. Думаю, пояснения не нужны :laughing:
  23. Не знаю что за CppCheck, но он тут молодец, что предупредил. А Keil не молодец. Хотя может и молодец, что схавал, полагаясь на компетентность программиста (а иногда так и хочется наорать на компилятор "я знаю что я делаю, тварь!" ). Хотя и не молодец, хотя бы warning бы кинул... Ассемблер тут совершенно ни при чем. Это полностью зависит от компилятора. Реализовано ли в системе команд постинкремент или нет, совершенно не важно, компилятор может спокойно разбить постинкремент на несколько инструкций. Я не понимаю одного - если в стандарте четко написано о таких вещах, зачем намеренно создавать себе проблему "кодированием через пробы и ошибки"? Ведь даже элементарное включение оптимизации может привести совершенно к другому порядку инструкций, и гарантировать равнозначное поведение в данном случае невозможно.
  24. А окружение этой команды можно привести? До и после... Можно сказать, Вам повезло :)
  25. Нет, не так. Постинкремент переменной не определён внутри выражения. Рассмотрим пример: int m[10]; int i = 0; m[i++] = i; // неопределенное поведение m[i] = i++; // неопределенное поведение По стандарту операция присваивания не является точкой следования, соответственно неизвестно, в каком порядке будут вычислены стороны выражения. Рассмотрим первый пример. Для него порядок вычисления может быть одним из следующих: 1) m[0] = 0; // i == 1 2) m[0] = 1; // i == 1 Аналогично и в Вашем случае.
×
×
  • Создать...