реклама на сайте
подробности

 
 
> Soft I2C STM32F4Discovery+MCP4728 2 шт. на шине, Глюк при считывании адреса
belial
сообщение Dec 26 2013, 20:30
Сообщение #1





Группа: Участник
Сообщений: 8
Регистрация: 10-01-05
Из: Odessa near Black Black Sea
Пользователь №: 1 871



Помогите, уважаемые с затыком ,При отладке в CooCox функция чтения адреса при первом вызове отвечает правильно, при втором только если поставить брекпоинт на вызов функции, иначе отвечает как в первом вызове.Два DAC MCP4728 параллельно на SDA SCL с подтяжками по 1К к питанию. в адрес второго уже записана 1(A0).
CODE
uint8_t MCP4728_INIT(void){
/**
* @brief Process the MCP4728 init, Set the gain, Vref, etc,set the second device i2c adress if need
* @param none
* @retval status operation
*/
MCP4728_config();
LDAC1_HIGH;
LDAC2_HIGH;
SDA_HIGH;
SCL_HIGH;
delay_i2c(fs_mode_delay); //fast speed 400kHz
// check devices present
STM_EVAL_LEDToggle(LED6);
uint8_t temp =READ_ADDR(Voltage_DAC);
if(temp != 0x10) return temp; // first adress is A2,A1,A0,1,A2,A1,A0,0 (b00010000)
delay_i2c(400); // от отчаяния, все равно не работает
temp = READ_ADDR(Current_DAC);// глюк здесь,(д.б. b00110010 а читается b00010000) если точка останова стоит,считывает нормально
if(temp != 0x32) {
temp = Programm_adress(Current_DAC); // надо только для непрошитого адреса 2-го DAC
if(temp) return 0x77;
}
temp = MCP4728_programming(Voltage_DAC);
if(temp) return 0x99;
temp = MCP4728_programming(Current_DAC);
if(temp) return 0xAA;
return 0;
}


Сама функция READ_ADDR
CODE
// maximum clock rate for this command is 400 kHz.
/**
* @brief Read the MCP4728 adress bits in eeprom(d7,d6,d5) and input buffer(d3,d2,d1), d4=1,d0=0
* @param uint8_t device - individual adress onto i2c bus
* @retval received from MCP4728 adress bits
*/
uint8_t READ_ADDR(uint8_t device) {
uint8_t temp1;

//send 00,0C,before ack LDAC goes low,restart,C1,read data
SOFT_I2C_START();
Soft_I2C_send(GENERAL_CALL_ADRESS,fs_mode_delay); // no need to check ack
uint8_t ack = read_ack(fs_mode_delay);
if(ack) {exception_catch(); return ack;}
Soft_I2C_send(GENERAL_CALL_READ_ADR_BITS,fs_mode_delay);
if(device) LDAC2_LOW;// choose the right DAC
else LDAC1_LOW;
delay_i2c(fs_mode_delay); // тоже не нужно
ack = read_ack(fs_mode_delay);
if(ack) {exception_catch(); return ack;}
delay_i2c(5);
SOFT_I2C_START(); // restart condition
Soft_I2C_send(MCP4728_I2C_READ_ADR|(device<<1),fs_mode_delay);
ack = read_ack(fs_mode_delay);
if(ack){exception_catch(); return ack;}
temp1 = Soft_I2C_read(fs_mode_delay,0); // without ack from master

SOFT_I2C_STOP();
LDAC2_HIGH;
LDAC1_HIGH;
return temp1;
}


Soft_I2C_read
CODE

/**
* @brief Process the read byte from SDA line, issue the ack clock bit
* @param uint32_t delay - different delays for normal, fast and high speed mode
* @retval uint8_t data
*/
uint8_t Soft_I2C_read(uint32_t delay, uint8_t with_ack){
uint8_t temp =0;
uint8_t i=0x80;
SDA_HIGH;
while (i){
delay_i2c(delay>>1);// data setup time
SCL_HIGH;
while (CHECK_SCL==0);
delay_i2c(delay>>2);
if(SDA_ACK_SLAVE) temp |= i;
i>>=1;
SCL_LOW;
delay_i2c(delay>>2);
}
if (with_ack) SDA_LOW; // ack
else SDA_HIGH; // no ack, last data byte received
delay_i2c(delay>>1);
SCL_HIGH; // 9 pulse
delay_i2c(delay>>2);
SCL_LOW;
delay_i2c(delay>>2);
SDA_HIGH;
return temp;
}

Весь I2c софтовый , таблица синусов на 120 значений, передача данных идет на high speed(3,4MHz) , остальные операции в fast speed
datasheet здесь http://ww1.microchip.com/downloads/en/DeviceDoc/22187a.pdf
Прикрепленный файл  mcp4728.rar ( 6.16 килобайт ) Кол-во скачиваний: 69


Сообщение отредактировал belial - Dec 26 2013, 20:45
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Сергей Борщ
сообщение Dec 26 2013, 23:33
Сообщение #2


Гуру
******

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



Да, все верно - открытый коллектор. Многие ошибочно используют обычный выход.
По остальному коду:

Заметил такую особенность: вы в Soft_I2C_send() делаете проверку на отпускание SCL (while (CHECK_SCL==0); ), а в SOFT_I2C_STOP() - нет. Возможно подчиненное устройство подтормаживает и из-за этого на шине не получается стоп-условие. Также такая проверка отсутствует в Soft_I2C_read() в части чтения ack и в read_ack().

И еще: посмотрите листинг функции delay_i2c() - не заменил ли ее компилятор на один единственный BX LR. конечно там есть __IO в объявлении параметра и наверняка этот макрос содержит в себе ключевое слово volatile, но все же проверьте.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
belial
сообщение Dec 27 2013, 00:01
Сообщение #3





Группа: Участник
Сообщений: 8
Регистрация: 10-01-05
Из: Odessa near Black Black Sea
Пользователь №: 1 871



Цитата(Сергей Борщ @ Dec 27 2013, 02:33) *
Заметил такую особенность: вы в Soft_I2C_send() делаете проверку на отпускание SCL (while (CHECK_SCL==0); ), а в SOFT_I2C_STOP() - нет. Возможно подчиненное устройство подтормаживает и из-за этого на шине не получается стоп-условие. Также такая проверка отсутствует в Soft_I2C_read() в части чтения ack и в read_ack().

И еще: посмотрите листинг функции delay_i2c() - не заменил ли ее компилятор на один единственный BX LR. конечно там есть __IO в объявлении параметра и наверняка этот макрос содержит в себе ключевое слово volatile, но все же проверьте.

Добавил проверку в SOFT_I2C_STOP() и в read_ack и в Soft_I2C_read(), не помогло.....
delay занимает примерно 11 команд :
CODE
delay_i2c:
08003238: sub sp, #8
0800323a: str r0, [sp, #4]
0800323c: ldr r3, [sp, #4]
0800323e: cbz r3, 0x800324e <delay_i2c+22>
08003240: ldr r3, [sp, #4]
08003242: add.w r3, r3, #4294967295
08003246: str r3, [sp, #4]
08003248: ldr r3, [sp, #4]
0800324a: cmp r3, #0
0800324c: bne.n 0x8003240 <delay_i2c+8>
0800324e: add sp, #8
08003250: bx lr
08003252: nop

Засада все-таки в том что если поставить брекпоинт на temp = READ_ADDR(Current_DAC); считывается все нормально( вижу 0x32 осциллографом), если вообще убрать эту проверку, все работает- получил 3-фазное напряжение на выходе с возможностью изменения сдвига фаз . И операция нужна 1 раз, собственно для прописывания адреса во 2 DAC однократно, на этапе первоначального старта свежеиспеченой платки.
переписал delay_i2c: void delay_i2c(__IO uint32_t delay) { while (delay--);}
занимает 7 команд:
CODE

452 void delay_i2c(__IO uint32_t delay) { while (delay--);}
0800323c: ldr r3, [sp, #4]
0800323e: add.w r2, r3, #4294967295
08003242: str r2, [sp, #4]
08003244: cmp r3, #0
08003246: bne.n 0x800323c <delay_i2c+4>
08003248: add sp, #8
0800324a: bx lr

подправил тайминги, не помогло... даже посылал после Soft_I2C_read 9 импульсов вдогонку для освобождения шины, те же sm.gif sm.gif

Сообщение отредактировал belial - Dec 27 2013, 00:31
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st August 2025 - 16:56
Рейтинг@Mail.ru


Страница сгенерированна за 0.01375 секунд с 7
ELECTRONIX ©2004-2016