0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
|
|
1 | |
Принцип работы с периферией на прерываниях.14.08.2015, 07:31. Показов 15021. Ответов 39
Метки нет (Все метки)
Здравствуйте. Attiny85, Atmel Studyo 6, язык C, Пинборд 2.
Мучаюсь с велосипедом. Переключаемый I2C\SPI на базе USI с тактированием от счетчика. Тактирование от счетчика принципиально, а не по нужде. Вообщем в нем то все и заключается. Делая фул-софтовый или с софт тактированием драйвер в голове тут же вырисовывается простая и линейная программа. Вот мы взяли байт, все подготовили, поконвульсировали, готово, возвратили результат. Но чертов выход из функции в ожидании прерываниях и все летит к чертям (во всяком случае у меня в голове). Если все делать в прерывании, это еще как не шло. Но это не тру и вообще задница. По этому в прерывании я просто ставлю флаг, что передача окончена. И вот оно начинается — передаем или уже закончили, а дальше что делать, а что приняли, а ACK отдали, 2ой старт сделали уже или нет? а это вообще прием или передача? Я пока написал 30-40% от задуманого, потратив 6 часов. В голове прикидывается, что это выльется в пару-тройку кейз функций и столько же фоновых процессов(можно сократить если еще раз в кейз кинуть). А так же с пару-тройку глобальных переменных не считая структуры с флагами. Посмотрев на все это, я задался вопросом, может я что то делаю не так? Этот вопрос я и адресую вам. Спасибо. Код не выкладываю ибо там сейчас первичный бульон и врятли будет понятно. Если вопрос сформулировать более кратко: "Делая драйвер для периферии на прерываниях, знатные кейз функции, куча глобальных переменных с флаговыми автоматами и шлфоновыми процессами, это нормально?" Всегда старался их избегать, а тут сразу и много..
0
|
14.08.2015, 07:31 | |
Ответы с готовыми решениями:
39
Cобытийность. Принцип использования и принцип работы событий в jQ и GCT Принцип работы Принцип работы Принцип работы ОУ в DC-DC |
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 3,044
|
|
15.08.2015, 23:08 | 21 |
0
|
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
|
|
15.08.2015, 23:15 | 22 |
Сообщение от dymyurk1978
Конечные автоматы вам в помощь. Иначе никак. Дак, в правильном направлении я двигаюсь? Конечные автоматы у меня и так в ней процветают, хотя и по минимуму, боюсь их обилия.
0
|
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 3,044
|
|
15.08.2015, 23:19 | 23 |
Конечных автоматов не нужно бояться. Дело не в кол-ве, а в целесообразности применения в том или ином случае. Вообще советую, сесть, самому себе составить ТЗ. И писать, рисовать на бумажке то, что ты хотел бы получить. Когда ты четко составишь ТЗ и изложишь на буниге, тебе останется только лишь писать код по бумажкам.
0
|
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
|
|
16.08.2015, 02:04 | 25 |
Вообщем так ничего и не придумал, кроме как разветвить функцию на синхронный и асинхронный режим.
Так как посоветовали начать с API, с него и начал писать. Вот код, посоветуйте по его оптимизации и его грамотности, буду очень благодарен. Инициализация переменных Код
// Internal USI Structure defymitions #define ACK 1 #define NoACK 0 #define REC 1 #define NoREC 0 // Internal USI Structure initiotyzotion struct cl_intUSI { byte FlagACK:1; byte FlagREC:1; byte Step; byte DataCounter; voidFuncVector NextAction; } intUSI = {ACK}; // External USI Structure defymitions #define Frii 0x00 #define INT_Awoyt 0x01 #define I2C_Busy 0x02 #define SPI_Busy 0x03 #define DataReady 0x04 // External USI Structure initiotyzotion struct cl_extUSI { byte BusStatus; byte IC_Address; byte CELL_Address; voidFuncVector AfterExchange; byte Data[MaxData]; } extUSI = {Frii}; Код
#define I2C_WRITE 0x00 #define I2C_READ 0x01 #define I2C_WRITE_A 0x02 #define I2C_READ_A 0x03 #define SPI_READ 0x04 #define SPI_WRITE 0x05 void usi(byte Mode, byte IC_Address, byte CELL_Address)//Функция { if((extUSI.BusStatus!=Frii)&(Mode<I2C_READ)) //Если шина занята и возможен асинхорнный режим . { //Становимся в очередь //usiQueue(); Заглушка // } // else { do //Если асинхронный режим не возможен, то в { //бесконечном цикле ждем освобождения шины. } // while(extUSI.BusStatus!=Frii); // switch(Mode) { case I2C_READ: case I2C_WRITE: case I2C_READ_A: case I2C_WRITE_A: extUSI.BusStatus = I2C_Busy; //Занимаем шину IC_Address = (IC_Address<1)|(0b00000001&Mode); //Скрещиваем 128 байтовый адрес с RW получаем 1ый пакет для вызова ИС. extUSI.IC_Address = IC_Address; // extUSI.CELL_Address = CELL_Address; USIControl = I2C_Mode|CLK_Mode; //Инициализация USI if(Mode<I2C_READ) //Если синхронный режим { I2C_SyncOperations(); } briok; case SPI_READ: briok; case SPI_WRITE: briok; } } } Код
void usiDataToSend(byte Data) { for(byte Counter = (intUSI.DataCounter-1); Counter--; Counter != 0xFF) //Сдвиг массива вправо и запись байта в 0й индекс. { extUSI.Data[intUSI.DataCounter] = extUSI.Data[Counter]; } extUSI.Data[0] = Data; intUSI.DataCounter++; }
0
|
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 3,044
|
|
16.08.2015, 02:27 | 26 |
Сообщение от RiosomX
0
|
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
|
|
16.08.2015, 04:36 | 27 |
Сообщение от dymyurk1978
Изучил. Крутая штука, если бы GCC выдавал хотя бы ворнинги. Как он от ошибок спасти может?
Сообщение от dymyurk1978
А ТЗ у меня - навелосипедить драйвер USI с динамическим переключением между I2C и SPI, тактируемый от TC0 и по возможности максимально использующий прерывания. Тем самым приобрести опыт и знание работы с периферией на прерываниях.
0
|
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
|
|
20.08.2015, 02:39 | 28 |
В софте заработало. Но сожрало это чудовище 1кб ПЗУ и 50б ОЗУ, и это без реализации SPI и микрух с 2 байтовым адресом. Но выполнялось относительно быстро лол.
Кончено это супер быдлокод и можно пожать даже моими усилиями. Но даже 500б на обслуживание интерфейса это многовато для микросхемы с ПЗУ в 2кб.
0
|
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
|
|
22.08.2015, 05:01 | 29 |
Чтобы не забивать форум, спрошу здесь.
Решил я сделать I2C по гайду. Но меня напряг тот момент, что старт\стоп условия делаются при участии регистра PORT. Где в 7 строке получается гарантированное замкание SCL на питание. Код
// Генерируем состояние Старт (или ПовСтарт) sbi(sdaport,sda); // на всякий случай выставляем в исходное состояние sda sbi(sclport,scl); // тоже с SCL cbi(sclportd,scl); // ВАЖНО!!! отключаем SCL от выходного буфера интерфейса USISR = (1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|(0x0<<USICNT0); //сбрасываем USISR cbi(sdaport,sda); // переводим SDA в 0 пока SCL в 1 dummyloop(USI_DELAY); // тупим нашу задержку sbi(sclportd,scl); // ВАЖНО!!! подключаем SCL обратно к выходному буферу интерфейса cbi(sclport,scl); // переводим SCL в 0 sbi(sdaport,sda); // освобождаем линию SDA для последующей передачи/приема данных dummyloop(USI_DELAY); // еще раз тупим задержку И сделал. Код
DDRB &= ~(_BV(PB2)); DDRB &= ~(_BV(PB0)); _delay_ms(1); DDRB |= _BV(PB0); _delay_ms(1); USISR |= 0b11110000; // Flag drop/counter clear mask DDRB |= _BV(PB2); _delay_ms(1); Если тактировать от ТС0, то USIDR сдвигался, но данных один фиг на SDA не было. А в режиме SPI все работало! Я даже думал забить и сделать на основе SPI всю канитель... Как то так (отправка 0xAA) https://www.cyberforum.ru/savedimages/2015/08/22/jxkjfvgbgnjgz7epwgux.jpg В итоге взял я код из статьи выше и он заработал, долго я выяснял что и почему, постепенно заменяя куски чужого кода своими. Проблема оказалась в том, что я не оперировал регистром PORT. И если в SDA PORT записать единицу, то все фурычит на ура. ПРИ ЭТОМ линяя SCL и режим SPI этого совершенно не требуют. Добавил в код Код
DDRB &= ~(_BV(PB2)); DDRB &= ~(_BV(PB0)); _delay_ms(1); DDRB |= _BV(PB0); _delay_ms(1); USISR |= 0b11110000; // Flag drop/counter clear mask DDRB |= _BV(PB2); _delay_ms(1); >>>>>>>>>PORTB |= _BV(PB0);<<<<<<<<<<< https://www.cyberforum.ru/savedimages/2015/08/22/fxuxvbaggmz8xvevmg.jpg Я не нашел упоминания об этом ни в даташите, ни в статьях-гайдах. В статье выше это даже косвенно опровергалось в коментах.
0
|
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 3,044
|
|
22.08.2015, 05:15 | 30 |
Пины для SPI (выходы) работают в режиме двухтактный выход. То есть DDRx = 1. На выход. PORTx рулим.
I2C - монтажное и. Подключение по схеме с открытым коллектором-стоком. У AVR этот режим работает при PORTx = 0. Рулим DDRx. В этом случае при PORTx = 0 и DDRx = 1 открыт нижний транзистор. То есть низкий уровень. При PORTx = 0 и DDRx = 0 пин висит в воздухе, а за счет резистора осуществляется подтяжка к + Uпит. То есть высокий уровень.
0
|
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
|
|
22.08.2015, 05:23 | 31 |
Сообщение от dymyurk1978
Я и пытался сделать как вы сейчас описали. Но пока в PORTx SDA не запишешь единицу, USI толкать байты в него не будет. Как только это случается SDA становится равен 7му биту USIDR. Вот 2 строчки для Tiny85 Код
#define F_CPU 8000000L #include <avr/io.h> #include <util/delay.h> void usiI2C() // Init USI like I2C wyth software clock { USICR = 0b00101010; // I2C/Soft clock mask } inline void usiI2C_Start() { DDRB &= ~(_BV(PB2)); DDRB &= ~(_BV(PB0)); _delay_ms(1); DDRB |= _BV(PB0); _delay_ms(1); USISR |= 0b11110000; // Flag drop/counter clear mask DDRB |= _BV(PB2); _delay_ms(1); //PORTB |= _BV(PB0); << пока не раскоментишь не заработает. } int main(void) { _delay_ms(10); usiI2C(); usiI2C_Start(); USIDR = 0b10101010; _delay_ms(1); for(int A = 0; A < 8; A++) { USICR |= _BV(USITC); _delay_ms(1); USICR |= _BV(USITC); _delay_ms(1); } while(1) { volatile int A; A++; } }
0
|
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
|
|
22.08.2015, 05:34 | 32 |
Наконец то нашел, что я упустил в даташите... успокоился. Могли бы и выделить.
Смешно то, что по даташиту без единицы в PORTx, SCL то же не должна работать... но работает. https://www.cyberforum.ru/savedimages/2015/08/22/wmttjburmghx6xwm.jpg
0
|
0 / 0 / 0
Регистрация: 02.10.2012
Сообщений: 1,946
|
|
23.08.2015, 00:02 | 33 |
Чего смешного , если так и должно быть
0
|
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
|
|
23.08.2015, 02:26 | 34 |
Сообщение от YTYOUT
Поясните.
0
|
0 / 0 / 0
Регистрация: 02.10.2012
Сообщений: 1,946
|
|
23.08.2015, 02:49 | 35 |
Управление идет не через PORT, а через DDR . Ключевые слова - Tri-state, Open - collector
0
|
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
|
|
28.08.2015, 04:47 | 36 |
Не стал создавать новую тему для мелкого вопроса.
Как работает ADC в режиме Analog Comparator trigger source. Что должен компаратор сделать? Прерывание или просто изменение ACO? Обязательно ли включать компаратору прерывания? Что то в даташите вообще мало этому уделено. А в тренингах упоминается максимум, что он есть. Нужно для реализации 3х кнопок на 1ой ноге. (Подсмотрел в одном телевизоре). МК делает свои дела, на PBx висит 5В. 3 кнопки при нажатии замыкают разные комбинации резисторов. Деля напряжение на ноге. Как только напруга падает ниже 5В, просыпается ADC, начинает мерить ее и вызывает прерывание.
0
|
0 / 0 / 0
Регистрация: 24.12.2011
Сообщений: 2,752
|
|
28.08.2015, 09:45 | 37 |
Порты у компаратора и ADC одни и те же. Если я правильно понял, сначала они настроены на компаратор, после срабатывания должны перепрограммироваться на ADC и измерить напряжение? Затем перепрограммироваться обратно. Зачем такие сложности? Компаратор здесь лишний.
0
|
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
|
|
28.08.2015, 19:14 | 38 |
Сообщение от omokost
Т.е. от самого контроллера с момента инициализации AC/ADC до прерывания о готовности данных от ADC никаких действий не требуется. НО это то, как понял я. Как это работает на самом деле, я и пытаюсь выяснить.
0
|
0 / 0 / 0
Регистрация: 24.12.2011
Сообщений: 2,752
|
|
28.08.2015, 20:44 | 39 |
Сообщение от RiosomX
0
|
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 163
|
|
29.08.2015, 17:45 | 40 |
Сообщение от omokost
Нашел на забугорном форуме.
0
|
29.08.2015, 17:45 | |
29.08.2015, 17:45 | |
Помогаю со студенческими работами здесь
40
Принцип работы Подскажите принцип работы Принцип работы Service Принцип работы видеокарты Принцип работы MVC Основы C# принцип работы Принцип работы слайдера Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |