Взаимодействие WavGat Pro mini с другим МК
- Войдите на сайт для отправки комментариев
Помогите разобраться новичку.
1) С прерываниями не знаком, что-то не получается найти толковой документации, поэтому пытался решить поставленную задачу в лоб. Тем более что мой МК (WavGat Pro mini) заведомо мощнее того, с которым его нужно подружить. Так же, возможно, неправильно выбрал на какие ноги что цеплять, но в результате даже с расширителями портов цифровые входы/выходы закончились.
2) Задача почти решена, но остались "артефакты", с которыми можно мериться, но лучше побороть, а тут уже не хватает знаний и опыта в этой сфере.
Подзадача:
Устройство посылает сигнал (LATCH), после которого нужно начать вывод данных. Здесь неплохо было бы использовать прерывания, но я не знаю как это делается. В принципе я этот сигнал отлавливаю в цикле и тут проблем нет. По сигналу CLOCK нужно выдать следующий пин (сигнал на линии CLOCK появляется только после LATCH) - обычная последовательная передача данных. Задача усложняется тем, что линии CLOCK две штуки (назовём их CLOCK1 и CLOCK2), соответственно линии, куда нужно посылать данные - тоже 2 штуки. LATCH - общий, а CLOCK1 и CLOCK2 приходят не синхронно, CLOCK2 немного запаздывает относительно CLOCK1 (примерно на пол цикла), но иногда приходят только CLOCK1, тогда на вторую линию ничего выводить не нужно. У меня к моменту появления сигнала LATCH уже подготовлены переменные для вывода в порт.
Проблема: иногда теряются сигналы CLOCK, из-за чего нарушается порядок вывода битов. При переключении микроконтроллера на 32 МГц ошибок стало меньше.
Часть кода (в среде Arduino), которая отвечает за вывод информации (взаимодействие с вторым МК):
while(1) { if ( PINC & 1 ) { // ловим LATCH PORTB = (PINB | 24) & DataOut_7; // Начинаем вывод сразу на две линии (первый бит обеих линий) while ( PINC & 2 ) {}; // Ждём CLOCK 1 // Меняем значение на следующее PORTB = (PINB | 8) & DataOut1_6; // Так как CLOCK-и приходят не синхронно, то выводим следующий бит (второй) только на первую линию byte ReadPortC = 255; // Переменная используется для определения CLOCK1 или CLOCK2 пришёл. delayMicroseconds(3); // Нужна небольшая задержка на восстановление линии CLOCK, чтобы не среагировать на один и тот же сигнал 2 раза while ( (ReadPortC & 6) == 6) {ReadPortC = PINC;}; // Ждём CLOCK2 или CLOCK1 if (ReadPortC & 2) { // CLOCK1 в норме, значит пришёл CLOCK 2 PORTB = (PINB | 16) & DataOut2_6; // Выводим следующий бит (второй) второй линии while ( PINC & 2 ) {}; // На этот раз ждём CLOCK1 }; ... // и так далее };
Вопросы:
1) Я читаю с аналоговых входов, используя их как цифровые. Если перекинуть провода на цифровые входы, будет ли происходить чтение быстрее или нет? Например while ( PIND & 2 ) {}; вместо while ( PINC & 2 ) {}; Провода уже запаяны и лишний раз лезть туда паяльником, чтобі проверить, не хочется.
2) Если я правильно понимаю, то можно использовать аналоговый компаратор (а их в LGT8F328P как раз 2), чтобы отлавливать CLOCK-и, так как он работает вне зависимости от рабочего цикла программы. Но тут мне не хватает знаний, а гугление не помогает (что-то я не так ищу).
Пните в нужном направлении... Для ясности добавлю еще пару картинок с логического анализатора
Пояснения: LATCH по умолчанию в LOW, остальные линии в HIGH
LATCH сейчас припаян к А0 (PC0), CLOCK1 к А1 (PC1), CLOCK2 к А2 (PC3).
Вывожу данные через 11 цифровой выход (PB3) и 12 цифр. выход (PB4).
А чем SPI не нравится? Специально создан для высокоскоростных интерфейсов. А про расширение портов посмотрите в сторону мультиплексоров.
Порты уже расширил при помощи CD4053. А SPI нужно сразу 2 штуки, причём в параллель. Не уверен, что стандартные библиотеки Arduino c этим справятся. В общем случае картина (с двумя линиями) примерно такая:
[quote=WavGat]
А SPI нужно сразу 2 штуки, причём в параллель. Не уверен, что стандартные библиотеки Arduino c этим справятся.
/quote]
При чем здесь библиотеки? Это аппаратная вещь. И вообще - разговор ни о чем - какие скорости предполагаются? И зачем?
А вообще в параллель смотри в сторону многопроцессорных систем или к Б.Гейтсу. Один кристалл всегда выполняет одну задачу.
Ну тогда извините, глупость сморозил по незнанию.
Частота процессора, с которым нужно общаться 1.66 MHz. А у меня 32 MHz. Скорость я не знаю, так как описание протокола, которое я нашёл на просторах интернета, отличается от реальной ситуации. Логический анализатор между двумя соседними сигналами CLOCK показал 25,7 KHz, но в зависимости от загруженной программы в тот процессор частота может немного отличаться от этой. На некоторых программах у меня таких артефактов нет, видимо там длительность сигнала на линии CLOCK немного больше.
Т.е. нужно использоватьshiftOut(DATA, CLOCK, MSBFIRST, digits); ? И SPI вроде только один, а мне 2 нужно
А вообще в параллель смотри в сторону многопроцессорных систем или к Б.Гейтсу. Один кристалл всегда выполняет одну задачу.
На одноядерных процессорах паралельные задачи тоже последовательно выполняются, причем не только и Билла. Да и у меня параллельный вывод в две линии почти получился (при минимальных знаниях).
На одноядерных процессорах паралельные задачи тоже последовательно выполняются, причем не только и Билла. Да и у меня параллельный вывод в две линии почти получился (при минимальных знаниях).
Бредим?
Немного о SPI
WavGat - в дешевых Stm32 ака "блюпилл" как раз 2 SPI.
и программируются в Ардуино ИДЕ
Бредим?
ну почему. Если через ДМА - вполне возможно делать вывод на SPI _асинхронно_ - то есть одновременно с другими действиями в программе
ну почему. Если через ДМА - вполне возможно делать вывод на SPI _асинхронно_ - то есть одновременно с другими действиями в программе
Прошу прощения - был неправ.
По приведённой Вами ссылке читаю: "Для Arduino написана специальная библиотека, которая реализует протокол SPI.". (это к моему 3 сообщению).
Может я неправильно выразился, попробую перефразировать: У меня задача считать параллельные данные и выдать их в последовательном виде. Фактически я одним микроконтроллером эмулирую два устройства, т.е. мне нужно чтобы микроконтроллер был не Master, а ДВУМЯ Slave! И да, у меня получилось написать работающую программу для WavGat Pro mini в среде Arduino, которая справляется с поставленной задачей, но при определённых условиях даёт небольшие сбои. Они не критичны, но хочется избавиться от них.
Нужно задействовать SPI? Хорошо, но как сразу в две линии писать?
Мне кажется, что нужно использовать прерывания, но тут я нуб, а за целый день поисков так и не нашёл ничего понятного. Есть конечно готовые примеры, но что за что там отвечает - не понятно. В моём случае в этом микроконтроллере есть 2 встроенных компаратора. Как их задействовать? Есть 4 встроенных опорных напряжения. Как их задействовать в коде? Даташиты скачал, читаю. Голова уже плавится, но пока не могу ничего понять.
Пните в документацию с примерами. Или помогите строчкой кода.
Давайте так - 28кГц для ардуинки - это ничто. Паралельно не считываем - считываем последовательно. Прерывания нужны если Вы работаете на скорости работы 1/10 скорости процессора. Или в остальных особенных случаях. Еще раз - 28кГц для ардуинки это не о чем. Выдаем паралельно :) Не получилось? Да хер с ним - последовательно. 28кГц
Конечно же последовательно.
Паралельно - это я в том смысле, что два байта нужно паралельно выдать в 2 порта (1 байт в 1 порт, другой байт в другой порт).
Проблема у меня в том, что вот этот цикл
while(PINC & 2) {}; // Ждём CLOCK 1
иногда пропускает момент тактирования. Закономерности нет. Может первый бит растянуть на 2 такта, а может пятый... Длительность импульса, котрый "теряется" при чтении с порта, на картинке:
Конечно же последовательно.
Паралельно - это я в том смысле, что два байта нужно паралельно выдать в 2 порта (1 байт в 1 порт, другой байт в другой порт).
А последовательно - религия не позволяет? Сначала туда спросил, потом сюда. Скорости никакие. Это аппаратка
Так я же и говорю, что последовательно.
Вот весь алгоритм выдачи двух байт ( для второго байта некоторые биты ничего не значат, поэтому они просто пропущены)
А вот картина того, что мы имеем на выходе ( в случае сбоя) для двух линий:
if(ReadPortC & 1) goto LATCH; - это костыль, который позволяет заново переслать байт, если пришёл новый сигнал на линии LATCH, когда из-за сбоя передача данных затянулась...
В моём случае SPI не подходит по нескольким причинам:
1) В моем микроконтроллере их 2, но 2-ой на USART0, т.е. я потеряю возможность его потом перепрошить и отслеживать в мониторе что не так. Или я опять чего-то не знаю?
2) Смотрим первые две картинки в начале темы (а также читаем, что я писал): сигнал LATCH всё время находится в LOW, и только перед тем как читать данные поднимается в HIGH на короткое время.
Копаю в сторону прерываний, но тут пока для меня дремучий лес с кустарниками.
Попробовал включить прерывания по изменению уровня на порту. LATCH отлавливается, а вот CLOCK-и - нет. Что я не так сделал?
В консоли только 7-ки.
Изменил код и нашёл ответ на предыдущий вопрос.
В момент, когда подпрограмма прерываний доходит до чтения порта, сигнал уже поменялся обратно.
Вывод: прерывание по LATCH можно оставить, но проблему с потерей CLOCK-ов они не решают, так как понять по какой из двух линий пришел CLOCK просто не получится!