Реклама на сайте English version  DatasheetsDatasheets

KAZUS.RU - Электронный портал. Принципиальные схемы, Datasheets, Форум по электронике

Новости электроники Новости Литература, электронные книги Литература Документация, даташиты Документация Поиск даташитов (datasheets)Поиск PDF
  От производителей
Новости поставщиков
В мире электроники

  Сборник статей
Электронные книги
FAQ по электронике

  Datasheets
Поиск SMD
Он-лайн справочник

Принципиальные схемы Схемы Каталоги программ, сайтов Каталоги Общение, форум Общение Ваш аккаунтАккаунт
  Каталог схем
Избранные схемы
FAQ по электронике
  Программы
Каталог сайтов
Производители электроники
  Форумы по электронике
Помощь проекту


 
Опции темы
Непрочитано 22.05.2018, 12:10  
Alcest
Прописка
 
Регистрация: 27.01.2015
Сообщений: 225
Сказал спасибо: 46
Сказали Спасибо 24 раз(а) в 23 сообщении(ях)
Alcest на пути к лучшему
По умолчанию PIC16F1829, I2C, ACKSTAT

Какое-то время назад сообразил, типа, функцию для аппаратной передачи данных по I2C в режиме мастера. Получилось такое вот:
Код:
void itwoc(){
        SSP1BUF=data;
        while(SSP1IF==0){
        }
        SSP1IF=0;
        while(SSP1CON2bits.ACKSTAT==1){
        }
        SSP1CON2bits.ACKSTAT=1;
}
Условия START и STOP формировались в функции main, а между ними в функцию I2C передается значение переменной data, в которую последовательно записывались адрес чипа, адрес регистра, старший и младший байты для передачи в 16-битные регистры ведомого устройства. Работало вроде нормально, не жаловался. А недавно решил подрихтовать это дело, избавившись от лишних движений в main(). Натворил следующее:
Код:
void itwoc(){
        
        //---Старт передачи-----------------------------------------------------
        SSP1CON2bits.SEN=1; // Формирование условия START на линиях SCL, SDA
        while(SSP1IF==0){ // Ожидание формирования условия START. Если флаг SSP1IF равен нулю, тогда продолжать ждать
        }
        SSP1IF=0; // Сброс флага SSP1IF после поднятия его по выполнению условия START
        
        //---Передача адреса чипа и направления передачи
        SSP1BUF=ADCHIPTX; // Загрузка в буфер адреса чипа и направления передачи
        while(SSP1IF==0){ // Проверка отправки данных - опустошения буфера...
        }                 //...цикл ожидания повторяется, пока данные не будут отправлены и не поднимется флаг SSP1IF
        SSP1IF=0;         // Сброс флага SSP1IF
        while(SSP1CON2bits.ACKSTAT==1){ // Ожидание ACK - сигнала подтверждения приема данных ведомым...
        }                               //...цикл ожидания повторяется пока не будет получен сигнал подтверждения приема - сброс в ноль бита ACKSTAT
        SSP1CON2bits.ACKSTAT=1;         //Установить бит ACKSTAT в 1 для следующей передачи
        
        //---Передача адреса 16-разрядного регистра-----------------------------
        SSP1BUF=ADREGTX;    // Загрузка в буфер адреса регистра
        while(SSP1IF==0){ // Проверка отправки данных - опустошения буфера...
        }                 //...цикл ожидания повторяется, пока данные не будут отправлены и не поднимется флаг SSP1IF
        SSP1IF=0;         // Сброс флага SSP1IF
        while(SSP1CON2bits.ACKSTAT==1){ // Ожидание ACK - сигнала подтверждения приема данных ведомым...
        }                               //...цикл ожидания повторяется пока не будет получен сигнал подтверждения приема - сброс в ноль бита ACKSTAT
        SSP1CON2bits.ACKSTAT=1;         //Установить бит ACKSTAT в 1 для следующей передачи
        
        //---Передача первого (старшего) байта----------------------------------
        SSP1BUF=REGTXH;   // Загрузка в буфер первого байта
        while(SSP1IF==0){ // Проверка отправки данных - опустошения буфера...
        }                 //...цикл ожидания повторяется, пока данные не будут отправлены и не поднимется флаг SSP1IF
        SSP1IF=0;         // Сброс флага SSP1IF
        while(SSP1CON2bits.ACKSTAT==1){ // Ожидание ACK - сигнала подтверждения приема данных ведомым...
        }                               //...цикл ожидания повторяется пока не будет получен сигнал подтверждения приема - сброс в ноль бита ACKSTAT
        SSP1CON2bits.ACKSTAT=1;         //Установить бит ACKSTAT в 1 для следующей передачи
        
        //---Передача второго (младшего) байта----------------------------------
        SSP1BUF=REGTXL;   //загрузка в буфер второго байта
        while(SSP1IF==0){ // Проверка отправки данных - опустошения буфера...
        }                 //...цикл ожидания повторяется, пока данные не будут отправлены и не поднимется флаг SSP1IF
        SSP1IF=0;         // Сброс флага SSP1IF
        while(SSP1CON2bits.ACKSTAT==1){ // Ожидание ACK - сигнала подтверждения приема данных ведомым...
        }                               //...цикл ожидания повторяется пока не будет получен сигнал подтверждения приема - сброс в ноль бита ACKSTAT
        SSP1CON2bits.ACKSTAT=1;         //Установить бит ACKSTAT в 1 для следующей передачи
        
        //---Стоп передачи------------------------------------------------------
        SSP1CON2bits.PEN=1; // Формирование условия STOP на линиях SCL, SDA
        while(SSP1IF==0){ // Ожидание формирования условия STOP. Если флаг SSP1IF не равен нулю, тогда продолжать ждать
        }
        SSP1IF=0; // Обнуление флага SSP1IF после поднятия его по выполнению условия STOP
}
ADCHIPTX, ADREGTX, REGTXH, REGTXL, это адрес чипа, адрес регистра, старший и младший байты данных соответственно.

Работать это отказалось. Полез разбираться. Оказалось, зависает на проверке состояния ACKSTAT в ходе передачи адреса регистра. Полез глубже, и узнал, что ACKSTAT у меня вообще не шевелится и всегда находится в состоянии 1. И совсем ничего не шевелится в регистре SSP1CON2 при наблюдении в окне Variables, ни один бит...

Причем, как оказалось, он и в предыдущем коде точно так же себя вел, не сбрасываясь в 0. Но, при этом все работало Рабочая точка программы просто проскакивала мимо while(SSP1CON2bits.ACKSTAT==1){} как будто его там и не было. ACKSTAT так же всегда в состоянии 1, как в регистре SSP1CON2, так и в переменной SSP1CON2bits.

Как думаете, что за чертовщина? Чего мне делать-то со всем этим? MPLAB X, компилятор XC8, PIC16F1829 и PICkit3.

P.S. Если все проверки ACKSTAT во втором коде закомментировать ваще, тогда передача по I2C работает. Но, такое положение дел определенно не может быть нормальным.

P.P.S. Со вторым кодом еще странность была. Удалил ненужные комменты, и запустил на отладку. И заработало даже с проверками ACKSTAT, но не надолго, до следующего запуска только. Больше не работало.
Реклама:
Alcest вне форума  
Непрочитано 22.05.2018, 20:27  
mimuh64
Прописка
 
Регистрация: 29.10.2008
Сообщений: 272
Сказал спасибо: 0
Сказали Спасибо 102 раз(а) в 95 сообщении(ях)
mimuh64 на пути к лучшему
По умолчанию Re: PIC16F1829, I2C, ACKSTAT

Напиши следующее... под свой синтаксис


char ACK;
char DATA;

//Старт
pir1.SSP1IF=0;
ssp1con2.SEN=1;
while(ssp1con2.SEN);

//Передача байта
pir1.SSP1IF=0;
ssp1buf=Data;
while(pir1.SSPIF == 0);
ACK=ssp1con2.ACKSTAT; // читаем ответ
.....

//Стоп
pir1.SSP1IF=0;
ssp1con2.PEN=1;
while(ssp1con2.PEN);
mimuh64 вне форума  
Сказали "Спасибо" mimuh64
Alcest (23.05.2018)
Непрочитано 22.05.2018, 22:41  
Alcest
Прописка
 
Регистрация: 27.01.2015
Сообщений: 225
Сказал спасибо: 46
Сказали Спасибо 24 раз(а) в 23 сообщении(ях)
Alcest на пути к лучшему
По умолчанию Re: PIC16F1829, I2C, ACKSTAT

У меня практически то же самое сейчас. Только SSPIF обнуляю сразу после его установки в 1. Попробую сбрасывать его в ноль перед загрузкой данных в SSPBUF.

Тут еще вопросы назрели. После проверки подтверждения ACKSTAT нужно что-то делать с битом ACKSTAT? Устанавливать в 1 или сбрасывать в 0? В примерах из интернета увидел, как люди пытались установить ACKSTAT в 1 после аппаратного сброса его в 0 при подтверждении. И сам сделал так же. А сейчас посмотрел даташит подробно, там для ACKSTAT четко указано - R. Выходит, что не должен бит писаться?

P.S. Попробовал переставить сбросы SSPIF перед загрузками в буфер. Стало еще хуже, стало виснуть уже на отправке адреса чипа в ведомый. Вернул назад - поставил сбросы сразу после проверки SSPIF на установку в 1. Теперь виснет на проверке ACKSTAT после отправки адреса регистра в ведомый.

Если убрать проверки ACKSTAT (кроме первой), тогда вроде нормально работает, пишет что нужно куда нужно. Начинаю подозревать, что ведомый чип вообще не передает подтверждение приема кроме как после отправки адреса в него, хотя на диаграмме указано подтверждение ACK после отправки адреса чипа, адреса регистра и обоих байтов.

Или я чего не учел? Кстати, если убрать проверки SSPIF сразу после записи данных в буфер, тогда проверка ACKSTAT проходит на всех этапах передачи данных в ведомого. То ли ACK не успевает в 1 встать, то ли наоборот, за время проверки SSPIF что-то зависает в ведомом и он не выдает 0 в бит ACKSTAT контроллера.

Последний раз редактировалось Alcest; 22.05.2018 в 23:33. Причина: добавление
Alcest вне форума  
Непрочитано 23.05.2018, 00:05  
Alcest
Прописка
 
Регистрация: 27.01.2015
Сообщений: 225
Сказал спасибо: 46
Сказали Спасибо 24 раз(а) в 23 сообщении(ях)
Alcest на пути к лучшему
По умолчанию Re: PIC16F1829, I2C, ACKSTAT

Вот что я подумал. А оно нужно, проверять флаг прерывания SSPIF после загрузки данных в буфер SSPBUF? Разве подтверждения приема от ведомого путем сброса в 0 бита ACKSTAT недостаточно для того, чтобы стало ясно, что данные отправлены, а значит буфер пуст?

В даташите на PIC16F87x нашел описание процедуры передачи данных по I2C в режиме ведущего.
В пунктах 2 и 12 (подчеркнуто красным) четко указано "ждать прерывания или установки флага SSPIF". В пунктах 6 и 10 (подчеркнуто синим) пишется только, что поднимается флаг SSPIF после отправки данных и подтверждения ведомым приема сигналом ACK. То есть, ничто не указывает на необходимость проверки SSPIF после загрузки данных в буфер, тем более до проверки бита ACKSTAT. Отмечается только, что флаг поднимается. Мало ли где еще может пригодится состояние этого флага.
Миниатюры:
Нажмите на изображение для увеличения
Название: ACK&SSPIF.JPG
Просмотров: 0
Размер:	298.3 Кб
ID:	129253  
Alcest вне форума  
Непрочитано 23.05.2018, 01:19  
Alcest
Прописка
 
Регистрация: 27.01.2015
Сообщений: 225
Сказал спасибо: 46
Сказали Спасибо 24 раз(а) в 23 сообщении(ях)
Alcest на пути к лучшему
По умолчанию Re: PIC16F1829, I2C, ACKSTAT

Попробовал убрать задержки на проверку флага SSPIF кроме как в формировании условий START и STOP. Зависания прекратились, но данные в ведомый чип не передаются, он молчит как рыба об лед. Походу, сигналы ACK игнорируются MSSP модулем микроконтроллера, и он гонит данные в слейв напропалую, не интересуясь, слушает он его или нет. А может я чего не учел. Но что именно?

Попытался поставить проверки на поднятие флага SSPIF после проверок ACK. Снова начались зависания. Теперь на передаче первого байта данных зависает прожка...

Вот рекомендованная последовательность действий из даташита на PIC16F1829. Вроде все сделал как там написано, а в результате нихрена...

1. Пользователь генерирует условие запуска, установив бит SEN регистра SSPxCON2.
2. SSPxIF устанавливается аппаратным обеспечением после завершения запуска.
3. SSPxIF очищается программным обеспечением.
4. Модуль MSSPx будет ожидать требуемое время начала до начала любой другой операции.
5. Пользователь загружает SSPxBUF с подчиненным адресом для передачи.
6. Адрес сдвигается на вывод SDAx до тех пор, пока все восемь бит не будут переданы. Передача начинается, как только SSPxBUF записывается.
7. Модуль MSSPx сдвигается в бит ACK от подчиненного устройства и записывает его значение в бит ACKSTAT регистра SSPxCON2.
8. Модуль MSSPx генерирует прерывание в конце девятого тактового цикла, устанавливая бит SSPxIF.
9. Пользователь загружает SSPxBUF с восемью битами данных.
10. Данные сдвигаются с вывода SDAx до тех пор, пока не будут переданы все восемь бит.
11. Модуль MSSPx сдвигается в бит ACK от подчиненного устройства и записывает его значение в бит ACKSTAT регистра SSPxCON2.
12. Шаги 8-11 повторяются для всех переданных байтов данных.
13. Пользователь генерирует условие Stop или Restart, устанавливая биты PEN или RSEN регистра SSPxCON2. Прерывание генерируется после завершения состояния Stop / Restart.

Последний раз редактировалось Alcest; 23.05.2018 в 01:23.
Alcest вне форума  
Непрочитано 23.05.2018, 02:04  
Alcest
Прописка
 
Регистрация: 27.01.2015
Сообщений: 225
Сказал спасибо: 46
Сказали Спасибо 24 раз(а) в 23 сообщении(ях)
Alcest на пути к лучшему
По умолчанию Re: PIC16F1829, I2C, ACKSTAT

Дошло до смешного, и одновременно грустного. Вспомнив, что раньше передача данных работала, когда данные в буфер передавались через переменную из функции main(), и записывались в буфер в функции передачи по I2C, решил, что корявая в принципе прожка работала из-за временных задержек между загрузкой данных в буфер.

Закомментировал в проге все проверки приема данных ACK ведомым чипом (проверку флага SSPIF убрал еще раньше) и понатыкал задержек по 100 микросекунд между загрузками данных в буфер SSPBUF. И что думаете? Заработало...

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

Чего теперь делать? Ведь то что ниже, это же позор... не знаю уж чей: мой, Микрочипа или компании KT Micro, чью микросхему тюнера я юзаю в качестве ведомого устройства.

Код:
void itwoc(){
        
        //---Старт передачи-----------------------------------------------------
        SSP1CON2bits.SEN=1; // Формирование условия START на линиях SCL, SDA
        while(SSP1IF==0){ // Ожидание формирования условия START. Если флаг SSP1IF равен нулю, тогда продолжать ждать
        }
        SSP1IF=0; // Сброс флага SSP1IF после поднятия его по выполнению условия START
        
        __delay_us(100);
        
        //---Передача адреса чипа и направления передачи
        SSP1BUF=ADCHIPTX;
//        while(SSP1CON2bits.ACKSTAT==1){ 
//        }
        
        __delay_us(100);
        
        //---Передача адреса 16-разрядного регистра-----------------------------
        SSP1BUF=ADREGTX;
//        while(SSP1CON2bits.ACKSTAT==1){ 
//        }
        
        __delay_us(100);
        
        //---Передача первого (старшего) байта----------------------------------
        SSP1BUF=REGTXH;
//        while(SSP1CON2bits.ACKSTAT==1){ 
//        }
        
        __delay_us(100);
        
        //---Передача второго (младшего) байта----------------------------------
        SSP1BUF=REGTXL;
//        while(SSP1CON2bits.ACKSTAT==1){ 
//        }
        
        __delay_us(100);
        
        //---Стоп передачи------------------------------------------------------
        SSP1CON2bits.PEN=1; // Формирование условия STOP на линиях SCL, SDA
        while(SSP1IF==0){ // Ожидание формирования условия STOP. Если флаг SSP1IF не равен нулю, тогда продолжать ждать
        }
        SSP1IF=0; // Обнуление флага SSP1IF после поднятия его по выполнению условия STOP
}
Alcest вне форума  
Непрочитано 23.05.2018, 08:57  
mimuh64
Прописка
 
Регистрация: 29.10.2008
Сообщений: 272
Сказал спасибо: 0
Сказали Спасибо 102 раз(а) в 95 сообщении(ях)
mimuh64 на пути к лучшему
По умолчанию Re: PIC16F1829, I2C, ACKSTAT

Зачем так много писать, если достаточно было сделать как я написал...
Контроль освобождения буфера SSP1BUF через while(SSP1CON2bits.ACKSTAT==1) и тем более так контролировать его наличие - это бред, в ACKSTAT как правило (при корректной работе) всегда 0, поэтому тебе и понадобилось __delay_us(100); иначе переполнение буфера и зависание модуля... Контроль отправки - через while(pir1.SSP1IF == 0); Таким образом контролируем освобождение SSP1BUF и формирование девятого импульса на SCL для чтения ACK.

И это - ACK=ssp1con2.ACKSTAT; // читаем ответ - не совсем то что ты пишешь "как у тебя"...
При малейшем сбое появление 1 в ACKSTAT - зависание и все... ACKSTAT - просто читают, и делают с ним что хотят, хотят контролируют, хотят нет...
Если не хочешь делать как пишут.... продолжай выдумывать велосипед....

Последний раз редактировалось mimuh64; 23.05.2018 в 09:37.
mimuh64 вне форума  
Сказали "Спасибо" mimuh64
Alcest (23.05.2018)
Непрочитано 23.05.2018, 10:14  
Alcest
Прописка
 
Регистрация: 27.01.2015
Сообщений: 225
Сказал спасибо: 46
Сказали Спасибо 24 раз(а) в 23 сообщении(ях)
Alcest на пути к лучшему
По умолчанию Re: PIC16F1829, I2C, ACKSTAT

Сообщение от mimuh64 Посмотреть сообщение
Если не хочешь делать как пишут.... продолжай выдумывать велосипед....
Меня инфа из даташитов и описаний I2C заставила думать, что без проверки ACKSTAT ваще никуда. Оказалось, в ней нет особой необходимости. Спасибо, помогли избавится от заблуждения

Я ведь уже удалял проверки ACK из проги, ограничиваясь проверкой SSPIF после каждой загрузки в буфер, и все работало. Но мне казалось, что это неправильно, в даташитах везде долбят про проверку ACKSTAT. Получилось же так, что в общем случае проверка ACK нафик не нужна.

Последний раз редактировалось Alcest; 23.05.2018 в 10:25.
Alcest вне форума  
Непрочитано 23.05.2018, 10:46  
mimuh64
Прописка
 
Регистрация: 29.10.2008
Сообщений: 272
Сказал спасибо: 0
Сказали Спасибо 102 раз(а) в 95 сообщении(ях)
mimuh64 на пути к лучшему
По умолчанию Re: PIC16F1829, I2C, ACKSTAT

Сообщение от Alcest Посмотреть сообщение
в даташитах везде долбят про проверку ACKSTAT.
Всего лишь рекомендуют... дабы быть уверенным что "Ведомый" прочел байт. Но у тебя и ранее не было условий контроля - что делать если АСК равен 1. Что касаемо инфы, которая, "заставила думать"... Смотрим рисунок FIGURE 25-28 из ДШ (для мастера в режиме "записи") и видим что контроль "Старт" и "Стоп" можно делать через биты SEN или SSP1IF и PEN или SSP1IF, соответственно... Я контролирую их через SEN и PEN. Контроль выдачи из SSP1BUF можно делать через SSP1IF или через R/W, рекомендуют через SSP1IF, это заменит твои __delay_us(100);...
mimuh64 вне форума  
Непрочитано 23.05.2018, 11:14  
Alcest
Прописка
 
Регистрация: 27.01.2015
Сообщений: 225
Сказал спасибо: 46
Сказали Спасибо 24 раз(а) в 23 сообщении(ях)
Alcest на пути к лучшему
По умолчанию Re: PIC16F1829, I2C, ACKSTAT

Сообщение от mimuh64 Посмотреть сообщение
Всего лишь рекомендуют...
Из фрагментов даташитов приведенных мною выше видно, что рекомендуют они проверку SSPIF, а проверку ACK делать чуть ли не приказывают. Не знаю, может это одна из трудностей англо-русского перевода. ХЗ, чего там англоязычные считают советом, а что прямым указанием.

Так или иначе я оставил только проверку SSPIF, как в вашем примере. Чтение ACK делать не стану, за ненадобностью на данное время.
Alcest вне форума  
 

Закладки
Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Контроль SDA и SCL на шине I2C pifa AVR 6 17.02.2015 01:35
Не работает I2C в ATMega128 pifa AVR 1 05.09.2014 19:45
Atmega, i2c и CodeVision deeman30rus AVR 3 21.01.2013 15:48
Подскажите микросхему LED-драйвера с I2C Archer07 Микроконтроллеры, АЦП, память и т.д 10 17.03.2011 11:41
Запись в I2C EEPROM yel Микроконтроллеры, АЦП, память и т.д 8 07.03.2007 16:08


Часовой пояс GMT +4, время: 05:31.


Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot