|
Soft I2C STM32F4Discovery+MCP4728 2 шт. на шине, Глюк при считывании адреса |
|
|
|
Dec 26 2013, 20:30
|
Группа: Участник
Сообщений: 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
|
|
|
|
|
 |
Ответов
(1 - 4)
|
Dec 26 2013, 21:52
|
Группа: Участник
Сообщений: 8
Регистрация: 10-01-05
Из: Odessa near Black Black Sea
Пользователь №: 1 871

|
Цитата(Сергей Борщ @ Dec 27 2013, 00:43)  Покажите макросы SDA_LOW, SDA_HIGH, SCL_LOW, SCL_HIGH в аттаче файл mcp4728.h CODE /** * @brief Configures the PORTC pins to interface with the MCP4728DAC and timer6 interrupts * @param None * @retval None */
void MCP4728_config(void){ GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Pin =LDAC1_PIN|LDAC2_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_25MHz; GPIO_Init(GPIO_SOFT_I2C, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = SCL_SOFT_I2C|SDA_SOFT_I2C; // external resistor 700 OHM to VCC GPIO_InitStruct.GPIO_OType = GPIO_OType_OD; // common drain to check ack and extend scl if applicable GPIO_Init(GPIO_SOFT_I2C, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = RDY_BUSY_PIN1|RDY_BUSY_PIN2; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;// inputs with the ext resistor 100kOhm to VCC GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_Init(GPIO_SOFT_I2C, &GPIO_InitStruct);
NVIC_InitStructure.NVIC_IRQChannel = TIM6_DAC_IRQn; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }
Цитата(Сергей Борщ @ Dec 27 2013, 00:43)  Покажите инициализацию ног SDA, SCL
Сообщение отредактировал belial - Dec 26 2013, 21:45
|
|
|
|
|
Dec 27 2013, 00:01
|
Группа: Участник
Сообщений: 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 импульсов вдогонку для освобождения шины, те же
Сообщение отредактировал belial - Dec 27 2013, 00:31
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|