|
STM32F050 I2C, не работает |
|
|
|
Jun 17 2014, 18:14
|

Профессионал
    
Группа: Свой
Сообщений: 1 202
Регистрация: 26-08-05
Из: Донецк, ДНР
Пользователь №: 7 980

|
Привет всем. Пытаемся завести на данном проце термодатчик LM75. Собственно до датчика дело не доходит. Не работает сам I2C. Инициализация: CODE RCC->APB1ENR = RCC_APB1ENR_PWREN | RCC_APB1ENR_TIM2EN | RCC_APB1ENR_I2C1EN; GPIOA->MODER |= GPIO_MODER_MODER9_1 | GPIO_MODER_MODER10_1; //MODER 32 разрядный // 00 - по умолчанию вход, 01(GPIO_MODER_MODER0_0) - выход, 10(GPIO_MODER_MODER0_1) - альтернативная функция // 11(GPIO_MODER_MODER0) - аналоговый режим GPIOA->AFR[1] |= 0x00000440;//здесь i2c GPIOA->OTYPER |= GPIO_OTYPER_OT_9 | GPIO_OTYPER_OT_10; //OTYPER 16 разрядный если 1(GPIO_OTYPER_OT_0) - открытый коллектор, а если 0 - обычный выход(по умолчанию) GPIOA->PUPDR = GPIO_PUPDR_PUPDR9_0 | GPIO_PUPDR_PUPDR10_0; //OPUPDR 32 разрядный // 00 - без подтяжки(по умолчанию), 01(GPIO_PUPDR_PUPDR0_0) - подтяжка к "+", 10(GPIO_PUPDR_PUPDR0_1) - подтяжка к "-"
I2C1->CR1|=I2C_CR1_PE; //включить I2C I2C1->CR1&=~I2C_CR1_PE; //выключить I2C while(I2C1->CR1&I2C_CR1_PE); //ждём пока выключится I2C //I2C1->TIMINGR|=(PRESC << 28)|(SCLL<<0)|(SCLH<<8)|(SCLDEL<<20)|(SDADEL<<16); //PRESC=11, SCLL=199, SCLH=195, SCLDEL=4, SDADEL=2 это для 10кГц //PRESC=11, SCLL=19, SCLH=15, SCLDEL=4, SDADEL=2 это для 100кГц //PRESC=5, SCLL=9, SCLH=3, SCLDEL=3, SDADEL=3 это для 400кГц //PRESC=5, SCLL=3, SCLH=1, SCLDEL=1, SDADEL=0 это для 1000кГц I2C1->TIMINGR|=(11 << 28)|(199<<0)|(195<<8)|(4<<20)|(2<<16); //конфигурируем тайминги I2C1->CR1|=I2C_CR1_PE; //включить I2C I2C1->CR2 = I2C_CR2_AUTOEND | (1<<16) | I2C_CR2_RD_WRN | (0x90<<1);
Чтение температуры: CODE // LM75 address = 0x90 #define LM75_Addr 0x90 // Temperature Register of LM75 #define LM75_TEMP_Reg 0x00 uint16_t I2C_LM75_Temp_Read ( uint8_t addr ) { uint16_t RegValue = 0;
// 1. Послать в LM75 адрес регистра - 0x00 // Конфигурирование адреса ведомого; количество байтов, которые будут запрограммированы (переданы); перезагрузки и генерировать старт I2C_TransferHandling ( I2C1, addr, 1, I2C_Reload_Mode, I2C_Generate_Start_Write );
// Подождите, пока ISR.TXIS флаг не будет установлен // TXIS==1 - TXDR empty while ( I2C_GetFlagStatus ( I2C1, I2C_ISR_TXIS ) == RESET );
// Отправить адрес (LM75_TEMP_Reg) I2C_SendData ( I2C1, LM75_TEMP_Reg );
// Подождите, пока ISR.TCR флаг не будет установлен // TCR == 1 - Заданное кол-во байт передано while ( I2C_GetFlagStatus ( I2C1, I2C_ISR_TCR ) == RESET );
// 2. Читать ответ LM75 // Конфигурирование адреса ведомого; количество байтов, которые будут считаны; перезагрузки и генерировать старт I2C_TransferHandling ( I2C1, addr, 2, I2C_Reload_Mode, I2C_Generate_Start_Read );
// ждать приёма байта // ISR.RXNE == 1 - byte received while ( I2C_GetFlagStatus ( I2C1, I2C_ISR_RXNE ) == RESET ); RegValue = I2C_ReceiveData ( I2C1 ); RegValue <<= 8;
// ждать приёма байта // ISR.RXNE == 1 - byte received while ( I2C_GetFlagStatus ( I2C1, I2C_ISR_RXNE ) == RESET ); RegValue |= I2C_ReceiveData ( I2C1 );
// Сгенерировать STOP I2C_TransferHandling ( I2C1, addr, 0, I2C_Reload_Mode, I2C_Generate_Stop );
// Подождите, пока ISR.STOPF флаг не будет установлен // STOPF == 1 - а шине действует STOP while ( I2C_GetFlagStatus ( I2C1, I2C_ISR_STOPF ) == RESET);
// Очистить флаг STOPF // ICR.STOPF := 1 1 - очистка флага ISR.STOPF I2C_ClearFlag ( I2C1, I2C_ICR_STOPCF );
return RegValue; }
Результат - I2C труп полный, на осцилле обе ноги единицы (pull-up-ы 10кил). Ничего не шевелится  . Кто-то с I2C на том проце работал? Он там вообще рабочий? Или я где-то ошибся? В ДШ на ногах I2C PA9, PA10 есть странный коммент: "This alternate feature is available on standard dies only." Стандарт умер, да здравствует стандарт Спасибо.
--------------------
Чтобы возить такого пассажира, необходим лимузин другого класса. (с) Мария Эдуарда
|
|
|
|
|
 |
Ответов
(30 - 44)
|
Jun 19 2014, 13:13
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(glags @ Jun 19 2014, 14:49)  Вы имеете "логическое ИЛИ" ?. Так я это делаю чтоб SWD порт не потерять. А если в битах для конфигурируемых ног уже были единицы в ненужных местах? Некоторые ноги при включении питания содержат отнюдь не нули в этих регистрах. Вы их пытаетесь перевести в режим альтернативной функции, но если он был перед этим настроен на вывод - вы переведете его в аналоговый режим. То есть даже если сейчас все и заработает, то потом дописав настройку этой ноги на вывод где-то в начале (не знаю зачем - например для организации сброса зависшего автомата ведомого выдачей 9 тактов ручным маханием ногами) вы получите эффект отваливания I2C в совершенно другом, никак не связанном с этим дописанным кодом месте. Мы ведь не знаем, что у вас там в начале программы творится, просто видим лежащую на ровном месте граблю, которую подложил себе человек, съевший собаку. Я, честно говоря, не понимаю - что мешает прописать весь регистр один раз целиком, задав одной записью необходимое состояние сразу всех ног? Аналогично и с остальными регистрами при инициализации - вы же знаете, что было записано в этот регистр (или вам не нужно предыдущее состояние в начале инициализации). Так запишите еще раз этот регистр полностью, но с измененными нужными битами. А вот если потребовалось изменить группу битов в регистре, состояние которого не может быть известно точно - тогда надо позаботиться о правильном состоянии всех битов. И не двумя операциями - сбросом и установкой, ведь в этом случае вы между этими операциями переводите регистр в совершенно ненужное состояние, а считыванием во временную переменную, изменением группы бит в этой переменной и записью назад в регистр за один раз уже конечного результата.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jun 19 2014, 13:38
|
Участник

Группа: Участник
Сообщений: 58
Регистрация: 9-05-13
Из: Львов, Украина
Пользователь №: 76 782

|
Цитата(Сергей Борщ @ Jun 19 2014, 16:13)  А если в битах для конфигурируемых ног уже были единицы в ненужных местах? Некоторые ноги при включении питания содержат отнюдь не нули в этих регистрах. Вы их пытаетесь перевести в режим альтернативной функции, но если он был перед этим настроен на вывод - вы переведете его в аналоговый режим. То есть даже если сейчас все и заработает, то потом дописав настройку этой ноги на вывод где-то в начале (не знаю зачем - например для организации сброса зависшего автомата ведомого выдачей 9 тактов ручным маханием ногами) вы получите эффект отваливания I2C в совершенно другом, никак не связанном с этим дописанным кодом месте. Мы ведь не знаем, что у вас там в начале программы творится, просто видим лежащую на ровном месте граблю, которую подложил себе человек, съевший собаку. Я, честно говоря, не понимаю - что мешает прописать весь регистр один раз целиком, задав одной записью необходимое состояние сразу всех ног? Аналогично и с остальными регистрами при инициализации - вы же знаете, что было записано в этот регистр (или вам не нужно предыдущее состояние в начале инициализации). Так запишите еще раз этот регистр полностью, но с измененными нужными битами. А вот если потребовалось изменить группу битов в регистре, состояние которого не может быть известно точно - тогда надо позаботиться о правильном состоянии всех битов. И не двумя операциями - сбросом и установкой, ведь в этом случае вы между этими операциями переводите регистр в совершенно ненужное состояние, а считыванием во временную переменную, изменением группы бит в этой переменной и записью назад в регистр за один раз уже конечного результата. Здесь я с Вами полностью согласен и поддерживаю. Я раньше так и делал, но пару раз по ошибке запорол SWD и после этого я делаю инит всех устройств в начале проги учитывая состояние регистров по умолчанию из даташита. При чём я не пользуюсь при этой методе сторонними библиотеками, а всегда пишу свои. По этому я знаю какой бит в каком регистре установлен. И в своих библиотеках я не делаю инициализации устройств, она у меня всегда в начале программы и если мне надо что-то с устройствами сделать, то я лезу туда.
|
|
|
|
|
Jun 19 2014, 19:26
|
Участник

Группа: Участник
Сообщений: 58
Регистрация: 9-05-13
Из: Львов, Украина
Пользователь №: 76 782

|
Интерфейс наконец то ожил. Но стопор получается после передачи номера регистра. Код uint_fast16_t I2C(void) { uint32_t i; while ((I2C1->ISR & I2C_ISR_TXE)==0); //while TXE ==0, buffer is full // Задать адрес приёмника и длину данных i=I2C1->CR2; i &= (uint32_t)~((uint32_t)(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN | I2C_CR2_START | I2C_CR2_STOP)); i |= ((0x90 & I2C_CR2_SADD) | ((1 << 16 ) & I2C_CR2_NBYTES) | I2C_CR2_RELOAD | I2C_CR2_START); I2C1->CR2=i; while ( (I2C1 -> ISR & I2C_ISR_TXIS) == 0); I2C1->TXDR = 0;//Передача номера регистра для чтения из STLM75 while ((I2C1->ISR & I2C_ISR_TCR)==0);//ждём окончание передачи i=I2C1->CR2; i &= (uint32_t)~((uint32_t)(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN | I2C_CR2_START | I2C_CR2_STOP)); i |= ((0x90 & I2C_CR2_SADD) | ((2 << 16 ) & I2C_CR2_NBYTES) | I2C_CR2_RELOAD | I2C_CR2_RD_WRN | I2C_CR2_START); I2C1->CR2=i; while ( ( I2C1 -> ISR & I2C_ISR_RXNE ) == 0);//Виснет ТУТ!!!!!!!!!!!! i=I2C1->RXDR; i<<=8; while ( ( I2C1 -> ISR & I2C_ISR_RXNE ) == 0); i |=I2C1->RXDR; I2C1->CR2|=(90<<0)|(1<<16)| I2C_CR2_RELOAD; //address SLAVE 7bits I2C1->CR2 &=~ I2C_CR2_RD_WRN; //write I2C1->CR2 |= I2C_CR2_STOP; // Stop Transmit while ( ( I2C1 -> ISR & I2C_ISR_STOPF ) == 0 ); I2C1 -> ICR = I2C_ICR_STOPCF; return i;} Ниже привожу осцилограмку жёлтый данные, а синий синхро.
Сообщение отредактировал glags - Jun 19 2014, 19:27
|
|
|
|
|
Jun 19 2014, 19:50
|
Участник

Группа: Участник
Сообщений: 58
Регистрация: 9-05-13
Из: Львов, Украина
Пользователь №: 76 782

|
Цитата(smalcom @ Jun 19 2014, 22:33)  >> Но стопор получается после передачи номера регистра. все статусы проверяете. не догоню жёлтый луч - это датчик ACK не дал? угу http://www.st.com/web/en/catalog/tools/PF257884# => http://www.st.com/st-web-ui/static/active/...dperiph_lib.zipСиний лучь в конце в низу это датчик синхру не отпускает. Я проверял отпаивая датчик. Расшифровывая осцилограмку передаётся 0х90-адрес устройства и вслед 00-номер регистра. Точнее 0х9000. А дальше *опа, датчик держит линию синхронизации.
|
|
|
|
|
Jun 20 2014, 03:59
|
Участник

Группа: Участник
Сообщений: 58
Регистрация: 9-05-13
Из: Львов, Украина
Пользователь №: 76 782

|
Цитата(smalcom @ Jun 20 2014, 00:09)  >> Ниже привожу осцилограмку жёлтый данные, а синий синхро. оказывается я очень внимательный человек.
хм, а точно датчик держит? Ну я ж написал, что точно. Я его отпаял и синхра поднялась. Как мне ещё объяснить?
|
|
|
|
|
Jun 20 2014, 07:05
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Сейчас почитаю описание датчика, а пока небольшое замечание по стию. Вот такую конструкцию Цитата(glags @ Jun 19 2014, 22:26)  Код while ((I2C1->ISR & I2C_ISR_TXE)==0); //while TXE ==0, buffer is full я всегда пишу так: Код while ((I2C1->ISR & I2C_ISR_TXE)==0) //while TXE ==0, buffer is full ; Это и нагляднее и гораздо меньше вероятность допустить ошибку добавляя в этот цикл, скажем, тестовое махание ногой. Точка с запятой в вашем варианте не бросается в глаза (а именно она является ключевым моментом этого цикла), ее можно забыть поставить или убрать и в цикл случайно попадет следующее выражение или наоборот оно случайно окажется за циклом. Цитата(glags @ Jun 19 2014, 22:26)  Интерфейс наконец то ожил. И в чем была причина? Во-первых нам любопытно, а во вторых, возможно, когда-нибудь на это обсуждение набредет кто-то с точно такой же проблемой и, разумеется, будет рад за вас, но ему информация "наконец-то ожил" не поможет никак. А ведь он будет тратить время, читать ветку... Представляете как ему будет обидно за потраченное на бесполезное чтение время? Цитата(hd44780 @ Jun 20 2014, 07:00)  Да. Датчик. Когда его убирали физически, этого нет, обе линии в 1 возвращаются. Этого не может быть, потому что не может быть никогда: Цитата The LM75 operates as a slave on the I2C bus, so the SCL line is an input (no clock is generated by the LM75) and the SDA line is a bi-directional serial data path. Вы случаем на датчике SDA и SCL не перепутали?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jun 21 2014, 08:55
|
Местный
  
Группа: Свой
Сообщений: 480
Регистрация: 21-11-04
Пользователь №: 1 188

|
Цитата(smalcom @ Jun 21 2014, 11:28)  Однако вселенная любит пошутить. Дык вселенная здесь не при чем. Источник шуток наверняка располагается где-то между стулом и клавиатурой. Вас не смущает, что у 24С256 размер страницы 64 байта?
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|