|
|
  |
Траблы с контроллером IIC от Xilinx, Пока что контроллер побеждает! |
|
|
|
Feb 18 2014, 14:53
|
Знающий
   
Группа: Свой
Сообщений: 972
Регистрация: 12-04-09
Из: Москва
Пользователь №: 47 543

|
Здравствуйте, уважаемые гуру.
Имеем девайс IIC (датчик температуры), висящий на Kintex 7. Все это подключается к стандартному контроллеру IIC в XPS и Microblaze.
И вроде как все оно работает, НО. Если попробовать сделать обмен типа "прочитать температуру": 1. Записать адрес датчика температуры 2. Записать регистр датчика температуры (0 - MSB темперетары) 3. Repeated Start 4. Записать адрес датчика температуры 5. Прочитать температуру 6. Стоп
То до п. 4 включительно все нормально, а потом контроллер IIC вылетает с ошибкой "потеря арбитража". При этом, если вместо "Repeated Start" поставить "Stop", а затем "Start", то все нормально работает.
Внимание, вопрос: кто-нибудь сталкивался с подобным? Какие могут быть причины, и как бороть?
Соединение точка-точка, никаких других мастеров на этой шине нет. Датчик мастером быть не умеет и не пытается. На Чипскопе и осцилле до п. 4 включительно все выглядит как надо.
Всем заранее спасибо за помощь.
|
|
|
|
|
Feb 18 2014, 16:06
|
Участник

Группа: Свой
Сообщений: 74
Регистрация: 10-08-09
Из: Санкт-Петербург
Пользователь №: 51 826

|
Попробуйте поменять антиглитчевые задержки. Когда-то и где-то видел задержку SDA относительно SCL но в приложенной картинке этой задержки нет.
Эскизы прикрепленных изображений
|
|
|
|
|
Feb 19 2014, 06:16
|
Знающий
   
Группа: Свой
Сообщений: 572
Регистрация: 17-11-05
Из: СПб, Россия
Пользователь №: 10 965

|
Я долго бился со стандартным API, но оно меня в итоге победило (точно так же зависало в процессе). В конце концов я написал вручную две функции доступа, немного пошаманил, помухлевал и в итоге работает, хотя тут тоже есть нюансы. Код // Simple user-created API to IIC controller // http://forums.xilinx.com/t5/Embedded-Processor-System-Design/Why-the-IIC-can-t-be-stopped/td-p/295693 u32 iic_write(u32 baseaddr, u32 daddr, u32 waddr, u32 wdata) { int stat2; u32 timeout; int stat = (Xil_In32(baseaddr + 0x104)); if(stat != 0xc0) { // print("Bad stat."); Xil_Out32((baseaddr + 0x100), 0xc0|0x02); // reset tx fifo // Xil_Out32((baseaddr + 0x100), 0xc0|0x03); // enable iic } Xil_Out32((baseaddr + 0x100), 0xc0|0x00); // disable iic Xil_Out32((baseaddr + 0x100), 0xc0|0x01); // enable iic
Xil_Out32((baseaddr + 0x100), 0xc0|0x0d); // Start; Transmit Xil_Out32((baseaddr + 0x108), (0x100 | (daddr & 0xFE))); // send slave address for write Xil_Out32((baseaddr + 0x108), waddr); // send register address Xil_Out32((baseaddr + 0x108), (0x200 | (wdata & 0xFF))); // send data byte with stop bit timeout = 100; // timeout while(1) // ToDo: add timeout to avoid hang up when I2C slave is not responding (no ACK) { stat2 = Xil_In32(baseaddr + 0x104); // wait for TX FIFO empty if( ((stat2 & 0x80) ) && ((stat2 & 0x04)== 0) ) // TX FIFO empty && Bus not busy break; if (timeout == 0) { xil_printf("iic write timed out %x %x\n\r", waddr, wdata); return 0xFFFFFFFF; // data not valid } timeout--; usleep(200); } return 0; }
u32 iic_read(u32 baseaddr, u32 daddr, u32 raddr) { int stat2; u32 rdata, timeout; int stat = (Xil_In32(baseaddr + 0x104)); if(stat != 0xc0) { // print("Bad stat."); Xil_Out32((baseaddr + 0x100), 0x002); // reset tx fifo Xil_Out32((baseaddr + 0x100), 0x003); // enable iic } Xil_Out32((baseaddr + 0x100), 0x000); // disable iic Xil_Out32((baseaddr + 0x100), 0x001); // enable iic
Xil_Out32((baseaddr + 0x108), (0x100 | (daddr & 0xFE))); // send slave address for write Xil_Out32((baseaddr + 0x108), raddr); // send register address Xil_Out32((baseaddr + 0x108), (0x101 | (daddr & 0xFE))); // send slave address for read Xil_Out32((baseaddr + 0x108), 0x201); // set stop after 1 data byte timeout = 100; // timeout while(1) { stat2 = Xil_In32(baseaddr + 0x104); if ((((stat2 & 0x40) == 0x0)) || (timeout == 0)) // (RX FIFO not empty && Bus not busy) or timeout // && ((stat2 & 0x04)== 0) break; //(((Xil_In32(IIC_BASEADDR + 0x104) & 0x40) == 0x40) && (timeout != 0)) { // wait for read FIFO not empty timeout--; delay_ms(1); } rdata = Xil_In32(baseaddr + 0x10C) & 0xFF; // read data byte delay_ms(1); if (timeout == 0) { xil_printf("iic read timed out %x %x\n\r", raddr, rdata); return 0xFFFFFFFF; // data not valid } return (rdata); }
|
|
|
|
|
Feb 19 2014, 08:34
|
Знающий
   
Группа: Свой
Сообщений: 572
Регистрация: 17-11-05
Из: СПб, Россия
Пользователь №: 10 965

|
Цитата(Koluchiy @ Feb 19 2014, 12:27)  Если читать Ваши комментарии так, как они написаны, то после записи адреса регистра Вы делаете стоп. Мне надо добиться, чтобы работал Repeated start, т.е. без стопа между записью номера регистра и чтением данных. Где? Xil_Out32((baseaddr + 0x108), (0x100 | (daddr & 0xFE))); // send slave address for write Xil_Out32((baseaddr + 0x108), raddr); // send register address Вот тут идет рестарт с отправкой физического адреса устройства Xil_Out32((baseaddr + 0x108), (0x101 | (daddr & 0xFE))); // send slave address for read А теперь идет чтение (в данном случае одного байта) и после этого стоп Xil_Out32((baseaddr + 0x108), 0x201); // set stop after 1 data byte
|
|
|
|
|
Feb 19 2014, 10:30
|
Знающий
   
Группа: Свой
Сообщений: 972
Регистрация: 12-04-09
Из: Москва
Пользователь №: 47 543

|
Извиняюсь, был неправ. Да, вроде работает  . Спасибо!
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|